summaryrefslogtreecommitdiff
path: root/drivers/net/bnx2x/bnx2x_init_ops.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bnx2x/bnx2x_init_ops.h')
-rw-r--r--drivers/net/bnx2x/bnx2x_init_ops.h338
1 files changed, 338 insertions, 0 deletions
diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h
index 2b1363a6fe78..aae7fea00622 100644
--- a/drivers/net/bnx2x/bnx2x_init_ops.h
+++ b/drivers/net/bnx2x/bnx2x_init_ops.h
@@ -151,6 +151,15 @@ static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data,
bnx2x_init_ind_wr(bp, addr, data, len);
}
+static void bnx2x_wr_64(struct bnx2x *bp, u32 reg, u32 val_lo, u32 val_hi)
+{
+ u32 wb_write[2];
+
+ wb_write[0] = val_lo;
+ wb_write[1] = val_hi;
+ REG_WR_DMAE_LEN(bp, reg, wb_write, 2);
+}
+
static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, u32 len, u32 blob_off)
{
const u8 *data = NULL;
@@ -503,4 +512,333 @@ static void bnx2x_init_pxp_arb(struct bnx2x *bp, int r_order, int w_order)
}
}
+/****************************************************************************
+* ILT management
+****************************************************************************/
+/*
+ * This codes hides the low level HW interaction for ILT management and
+ * configuration. The API consists of a shadow ILT table which is set by the
+ * driver and a set of routines to use it to configure the HW.
+ *
+ */
+
+/* ILT HW init operations */
+
+/* ILT memory management operations */
+#define ILT_MEMOP_ALLOC 0
+#define ILT_MEMOP_FREE 1
+
+/* the phys address is shifted right 12 bits and has an added
+ * 1=valid bit added to the 53rd bit
+ * then since this is a wide register(TM)
+ * we split it into two 32 bit writes
+ */
+#define ILT_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF))
+#define ILT_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44)))
+#define ILT_RANGE(f, l) (((l) << 10) | f)
+
+static int bnx2x_ilt_line_mem_op(struct bnx2x *bp, struct ilt_line *line,
+ u32 size, u8 memop)
+{
+ if (memop == ILT_MEMOP_FREE) {
+ BNX2X_ILT_FREE(line->page, line->page_mapping, line->size);
+ return 0;
+ }
+ BNX2X_ILT_ZALLOC(line->page, &line->page_mapping, size);
+ if (!line->page)
+ return -1;
+ line->size = size;
+ return 0;
+}
+
+
+static int bnx2x_ilt_client_mem_op(struct bnx2x *bp, int cli_num, u8 memop)
+{
+ int i, rc;
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ struct ilt_client_info *ilt_cli = &ilt->clients[cli_num];
+
+ if (!ilt || !ilt->lines)
+ return -1;
+
+ if (ilt_cli->flags & (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM))
+ return 0;
+
+ for (rc = 0, i = ilt_cli->start; i <= ilt_cli->end && !rc; i++) {
+ rc = bnx2x_ilt_line_mem_op(bp, &ilt->lines[i],
+ ilt_cli->page_size, memop);
+ }
+ return rc;
+}
+
+int bnx2x_ilt_mem_op(struct bnx2x *bp, u8 memop)
+{
+ int rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_CDU, memop);
+ if (!rc)
+ rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_QM, memop);
+ if (!rc)
+ rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_SRC, memop);
+ if (!rc)
+ rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_TM, memop);
+
+ return rc;
+}
+
+static void bnx2x_ilt_line_wr(struct bnx2x *bp, int abs_idx,
+ dma_addr_t page_mapping)
+{
+ u32 reg;
+
+ if (CHIP_IS_E1(bp))
+ reg = PXP2_REG_RQ_ONCHIP_AT + abs_idx*8;
+ else
+ reg = PXP2_REG_RQ_ONCHIP_AT_B0 + abs_idx*8;
+
+ bnx2x_wr_64(bp, reg, ILT_ADDR1(page_mapping), ILT_ADDR2(page_mapping));
+}
+
+static void bnx2x_ilt_line_init_op(struct bnx2x *bp, struct bnx2x_ilt *ilt,
+ int idx, u8 initop)
+{
+ dma_addr_t null_mapping;
+ int abs_idx = ilt->start_line + idx;
+
+
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ bnx2x_ilt_line_wr(bp, abs_idx, ilt->lines[idx].page_mapping);
+ break;
+ case INITOP_CLEAR:
+ null_mapping = 0;
+ bnx2x_ilt_line_wr(bp, abs_idx, null_mapping);
+ break;
+ }
+}
+
+void bnx2x_ilt_boundry_init_op(struct bnx2x *bp,
+ struct ilt_client_info *ilt_cli,
+ u32 ilt_start, u8 initop)
+{
+ u32 start_reg = 0;
+ u32 end_reg = 0;
+
+ /* The boundary is either SET or INIT,
+ CLEAR => SET and for now SET ~~ INIT */
+
+ /* find the appropriate regs */
+ if (CHIP_IS_E1(bp)) {
+ switch (ilt_cli->client_num) {
+ case ILT_CLIENT_CDU:
+ start_reg = PXP2_REG_PSWRQ_CDU0_L2P;
+ break;
+ case ILT_CLIENT_QM:
+ start_reg = PXP2_REG_PSWRQ_QM0_L2P;
+ break;
+ case ILT_CLIENT_SRC:
+ start_reg = PXP2_REG_PSWRQ_SRC0_L2P;
+ break;
+ case ILT_CLIENT_TM:
+ start_reg = PXP2_REG_PSWRQ_TM0_L2P;
+ break;
+ }
+ REG_WR(bp, start_reg + BP_FUNC(bp)*4,
+ ILT_RANGE((ilt_start + ilt_cli->start),
+ (ilt_start + ilt_cli->end)));
+ } else {
+ switch (ilt_cli->client_num) {
+ case ILT_CLIENT_CDU:
+ start_reg = PXP2_REG_RQ_CDU_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_CDU_LAST_ILT;
+ break;
+ case ILT_CLIENT_QM:
+ start_reg = PXP2_REG_RQ_QM_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_QM_LAST_ILT;
+ break;
+ case ILT_CLIENT_SRC:
+ start_reg = PXP2_REG_RQ_SRC_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_SRC_LAST_ILT;
+ break;
+ case ILT_CLIENT_TM:
+ start_reg = PXP2_REG_RQ_TM_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_TM_LAST_ILT;
+ break;
+ }
+ REG_WR(bp, start_reg, (ilt_start + ilt_cli->start));
+ REG_WR(bp, end_reg, (ilt_start + ilt_cli->end));
+ }
+}
+
+void bnx2x_ilt_client_init_op_ilt(struct bnx2x *bp, struct bnx2x_ilt *ilt,
+ struct ilt_client_info *ilt_cli, u8 initop)
+{
+ int i;
+
+ if (ilt_cli->flags & ILT_CLIENT_SKIP_INIT)
+ return;
+
+ for (i = ilt_cli->start; i <= ilt_cli->end; i++)
+ bnx2x_ilt_line_init_op(bp, ilt, i, initop);
+
+ /* init/clear the ILT boundries */
+ bnx2x_ilt_boundry_init_op(bp, ilt_cli, ilt->start_line, initop);
+}
+
+void bnx2x_ilt_client_init_op(struct bnx2x *bp,
+ struct ilt_client_info *ilt_cli, u8 initop)
+{
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+
+ bnx2x_ilt_client_init_op_ilt(bp, ilt, ilt_cli, initop);
+}
+
+static void bnx2x_ilt_client_id_init_op(struct bnx2x *bp,
+ int cli_num, u8 initop)
+{
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ struct ilt_client_info *ilt_cli = &ilt->clients[cli_num];
+
+ bnx2x_ilt_client_init_op(bp, ilt_cli, initop);
+}
+
+void bnx2x_ilt_init_op(struct bnx2x *bp, u8 initop)
+{
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_CDU, initop);
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_QM, initop);
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_SRC, initop);
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_TM, initop);
+}
+
+static void bnx2x_ilt_init_client_psz(struct bnx2x *bp, int cli_num,
+ u32 psz_reg, u8 initop)
+{
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ struct ilt_client_info *ilt_cli = &ilt->clients[cli_num];
+
+ if (ilt_cli->flags & ILT_CLIENT_SKIP_INIT)
+ return;
+
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ REG_WR(bp, psz_reg, ILOG2(ilt_cli->page_size >> 12));
+ break;
+ case INITOP_CLEAR:
+ break;
+ }
+}
+
+/*
+ * called during init common stage, ilt clients should be initialized
+ * prioir to calling this function
+ */
+void bnx2x_ilt_init_page_size(struct bnx2x *bp, u8 initop)
+{
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_CDU,
+ PXP2_REG_RQ_CDU_P_SIZE, initop);
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_QM,
+ PXP2_REG_RQ_QM_P_SIZE, initop);
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_SRC,
+ PXP2_REG_RQ_SRC_P_SIZE, initop);
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_TM,
+ PXP2_REG_RQ_TM_P_SIZE, initop);
+}
+
+/****************************************************************************
+* QM initializations
+****************************************************************************/
+#define QM_QUEUES_PER_FUNC 16 /* E1 has 32, but only 16 are used */
+#define QM_INIT_MIN_CID_COUNT 31
+#define QM_INIT(cid_cnt) (cid_cnt > QM_INIT_MIN_CID_COUNT)
+
+/* called during init port stage */
+void bnx2x_qm_init_cid_count(struct bnx2x *bp, int qm_cid_count,
+ u8 initop)
+{
+ int port = BP_PORT(bp);
+
+ if (QM_INIT(qm_cid_count)) {
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ REG_WR(bp, QM_REG_CONNNUM_0 + port*4,
+ qm_cid_count/16 - 1);
+ break;
+ case INITOP_CLEAR:
+ break;
+ }
+ }
+}
+
+static void bnx2x_qm_set_ptr_table(struct bnx2x *bp, int qm_cid_count)
+{
+ int i;
+ u32 wb_data[2];
+
+ wb_data[0] = wb_data[1] = 0;
+
+ for (i = 0; i < 4 * QM_QUEUES_PER_FUNC; i++) {
+ REG_WR(bp, QM_REG_BASEADDR + i*4,
+ qm_cid_count * 4 * (i % QM_QUEUES_PER_FUNC));
+ bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8,
+ wb_data, 2);
+
+ if (CHIP_IS_E1H(bp)) {
+ REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4,
+ qm_cid_count * 4 * (i % QM_QUEUES_PER_FUNC));
+ bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8,
+ wb_data, 2);
+ }
+ }
+}
+
+/* called during init common stage */
+void bnx2x_qm_init_ptr_table(struct bnx2x *bp, int qm_cid_count,
+ u8 initop)
+{
+ if (!QM_INIT(qm_cid_count))
+ return;
+
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ bnx2x_qm_set_ptr_table(bp, qm_cid_count);
+ break;
+ case INITOP_CLEAR:
+ break;
+ }
+}
+
+/****************************************************************************
+* SRC initializations
+****************************************************************************/
+
+/* called during init func stage */
+void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2,
+ dma_addr_t t2_mapping, int src_cid_count)
+{
+ int i;
+ int port = BP_PORT(bp);
+
+ /* Initialize T2 */
+ for (i = 0; i < src_cid_count-1; i++)
+ t2[i].next = (u64)(t2_mapping + (i+1)*sizeof(struct src_ent));
+
+ /* tell the searcher where the T2 table is */
+ REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, src_cid_count);
+
+ bnx2x_wr_64(bp, SRC_REG_FIRSTFREE0 + port*16,
+ U64_LO(t2_mapping), U64_HI(t2_mapping));
+
+ bnx2x_wr_64(bp, SRC_REG_LASTFREE0 + port*16,
+ U64_LO((u64)t2_mapping +
+ (src_cid_count-1) * sizeof(struct src_ent)),
+ U64_HI((u64)t2_mapping +
+ (src_cid_count-1) * sizeof(struct src_ent)));
+}
+
#endif /* BNX2X_INIT_OPS_H */