From 6aebde8dc767088a3171b864755f26ceae2f8bc7 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Mon, 27 Jan 2020 15:26:08 +0200 Subject: qed: FW 8.42.2.0 Expose new registers and change windows This patch contains register initialization related changes. - Modifications to the runtime offsets - these are defines used by the driver or firmware functions to set values that are used by the initialization functions to set device register values. - Global window values changes to provide different device register ranges. - Additional device registers addresses were added to the register file, used in later stages. Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c') diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index d6430dfebd83..2307f8842c9e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -44,9 +44,9 @@ #define CDU_VALIDATION_DEFAULT_CFG 61 static u16 con_region_offsets[3][NUM_OF_CONNECTION_TYPES_E4] = { - {400, 336, 352, 304, 304, 384, 416, 352}, /* region 3 offsets */ - {528, 496, 416, 448, 448, 512, 544, 480}, /* region 4 offsets */ - {608, 544, 496, 512, 576, 592, 624, 560} /* region 5 offsets */ + {400, 336, 352, 368, 304, 384, 416, 352}, /* region 3 offsets */ + {528, 496, 416, 512, 448, 512, 544, 480}, /* region 4 offsets */ + {608, 544, 496, 576, 576, 592, 624, 560} /* region 5 offsets */ }; static u16 task_region_offsets[1][NUM_OF_CONNECTION_TYPES_E4] = { @@ -228,9 +228,6 @@ static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, bool pf_rl_en) STORE_RT_REG(p_hwfn, QM_REG_RLPFVOQENABLE_RT_OFFSET, (u32)voq_bit_mask); - if (num_ext_voqs >= 32) - STORE_RT_REG(p_hwfn, QM_REG_RLPFVOQENABLE_MSB_RT_OFFSET, - (u32)(voq_bit_mask >> 32)); /* Write RL period */ STORE_RT_REG(p_hwfn, -- cgit v1.2.3-59-g8ed1b From 92fae6fb231f66ce0e71ed348e788180c1a603f9 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Mon, 27 Jan 2020 15:26:09 +0200 Subject: qed: FW 8.42.2.0 Queue Manager changes This patch contains changes in initialization and usage of the QM blocks. Instead of setting a rate limiter per vport the rate limiters are now a global resource and set independentaly. The patch also contains a field name change: vport_wfq which is part of vport_params was renamed to wfq as the vport prefix is redundant. Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 1 - drivers/net/ethernet/qlogic/qed/qed_dev.c | 21 +- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 41 ++-- .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 238 ++++++++++----------- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 8 +- 5 files changed, 149 insertions(+), 160 deletions(-) (limited to 'drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c') diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 8e1bdf58b9e7..5ebafbc379db 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -1522,7 +1522,6 @@ void qed_qm_init_pf(struct qed_hwfn *p_hwfn, params.num_vports = qm_info->num_vports; params.pf_wfq = qm_info->pf_wfq; params.pf_rl = qm_info->pf_rl; - params.link_speed = p_link->speed; params.pq_params = qm_info->qm_pq_params; params.vport_params = qm_info->qm_vport_params; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index a1ebc2b1ca0b..249fcc3dc138 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1571,7 +1571,7 @@ static void qed_init_qm_vport_params(struct qed_hwfn *p_hwfn) /* all vports participate in weighted fair queueing */ for (i = 0; i < qed_init_qm_get_num_vports(p_hwfn); i++) - qm_info->qm_vport_params[i].vport_wfq = 1; + qm_info->qm_vport_params[i].wfq = 1; } /* initialize qm port params */ @@ -2034,9 +2034,8 @@ static void qed_dp_init_qm_params(struct qed_hwfn *p_hwfn) vport = &(qm_info->qm_vport_params[i]); DP_VERBOSE(p_hwfn, NETIF_MSG_HW, - "vport idx %d, vport_rl %d, wfq %d, first_tx_pq_id [ ", - qm_info->start_vport + i, - vport->vport_rl, vport->vport_wfq); + "vport idx %d, wfq %d, first_tx_pq_id [ ", + qm_info->start_vport + i, vport->wfq); for (tc = 0; tc < NUM_OF_TCS; tc++) DP_VERBOSE(p_hwfn, NETIF_MSG_HW, @@ -2049,11 +2048,11 @@ static void qed_dp_init_qm_params(struct qed_hwfn *p_hwfn) pq = &(qm_info->qm_pq_params[i]); DP_VERBOSE(p_hwfn, NETIF_MSG_HW, - "pq idx %d, port %d, vport_id %d, tc %d, wrr_grp %d, rl_valid %d\n", + "pq idx %d, port %d, vport_id %d, tc %d, wrr_grp %d, rl_valid %d rl_id %d\n", qm_info->start_pq + i, pq->port_id, pq->vport_id, - pq->tc_id, pq->wrr_group, pq->rl_valid); + pq->tc_id, pq->wrr_group, pq->rl_valid, pq->rl_id); } } @@ -2623,7 +2622,7 @@ static int qed_hw_init_common(struct qed_hwfn *p_hwfn, params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port; params.pf_rl_en = qm_info->pf_rl_en; params.pf_wfq_en = qm_info->pf_wfq_en; - params.vport_rl_en = qm_info->vport_rl_en; + params.global_rl_en = qm_info->vport_rl_en; params.vport_wfq_en = qm_info->vport_wfq_en; params.port_params = qm_info->qm_port_params; @@ -5087,11 +5086,11 @@ static void qed_configure_wfq_for_all_vports(struct qed_hwfn *p_hwfn, for (i = 0; i < p_hwfn->qm_info.num_vports; i++) { u32 wfq_speed = p_hwfn->qm_info.wfq_data[i].min_speed; - vport_params[i].vport_wfq = (wfq_speed * QED_WFQ_UNIT) / + vport_params[i].wfq = (wfq_speed * QED_WFQ_UNIT) / min_pf_rate; qed_init_vport_wfq(p_hwfn, p_ptt, vport_params[i].first_tx_pq_id, - vport_params[i].vport_wfq); + vport_params[i].wfq); } } @@ -5102,7 +5101,7 @@ static void qed_init_wfq_default_param(struct qed_hwfn *p_hwfn, int i; for (i = 0; i < p_hwfn->qm_info.num_vports; i++) - p_hwfn->qm_info.qm_vport_params[i].vport_wfq = 1; + p_hwfn->qm_info.qm_vport_params[i].wfq = 1; } static void qed_disable_wfq_for_all_vports(struct qed_hwfn *p_hwfn, @@ -5118,7 +5117,7 @@ static void qed_disable_wfq_for_all_vports(struct qed_hwfn *p_hwfn, qed_init_wfq_default_param(p_hwfn, min_pf_rate); qed_init_vport_wfq(p_hwfn, p_ptt, vport_params[i].first_tx_pq_id, - vport_params[i].vport_wfq); + vport_params[i].wfq); } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index efabe0ca5cbe..5ac68ec01a04 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -2630,13 +2630,18 @@ struct init_nig_pri_tc_map_req { struct init_nig_pri_tc_map_entry pri[NUM_OF_VLAN_PRIORITIES]; }; +/* QM per global RL init parameters */ +struct init_qm_global_rl_params { + u32 rate_limit; +}; + /* QM per-port init parameters */ struct init_qm_port_params { - u8 active; - u8 active_phys_tcs; + u16 active_phys_tcs; u16 num_pbf_cmd_lines; u16 num_btb_blocks; - u16 reserved; + u8 active; + u8 reserved; }; /* QM per-PQ init parameters */ @@ -2645,15 +2650,14 @@ struct init_qm_pq_params { u8 tc_id; u8 wrr_group; u8 rl_valid; + u16 rl_id; u8 port_id; - u8 reserved0; - u16 reserved1; + u8 reserved; }; /* QM per-vport init parameters */ struct init_qm_vport_params { - u32 vport_rl; - u16 vport_wfq; + u16 wfq; u16 first_tx_pq_id[NUM_OF_TCS]; }; @@ -3982,7 +3986,7 @@ struct qed_qm_common_rt_init_params { u8 max_phys_tcs_per_port; bool pf_rl_en; bool pf_wfq_en; - bool vport_rl_en; + bool global_rl_en; bool vport_wfq_en; struct init_qm_port_params *port_params; }; @@ -4001,11 +4005,10 @@ struct qed_qm_pf_rt_init_params { u16 start_pq; u16 num_pf_pqs; u16 num_vf_pqs; - u8 start_vport; - u8 num_vports; + u16 start_vport; + u16 num_vports; u16 pf_wfq; u32 pf_rl; - u32 link_speed; struct init_qm_pq_params *pq_params; struct init_qm_vport_params *vport_params; }; @@ -4054,22 +4057,22 @@ int qed_init_pf_rl(struct qed_hwfn *p_hwfn, */ int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u16 first_tx_pq_id[NUM_OF_TCS], u16 vport_wfq); + u16 first_tx_pq_id[NUM_OF_TCS], u16 wfq); /** - * @brief qed_init_vport_rl - Initializes the rate limit of the specified VPORT + * @brief qed_init_global_rl - Initializes the rate limit of the specified + * rate limiter * * @param p_hwfn * @param p_ptt - ptt window used for writing the registers - * @param vport_id - VPORT ID - * @param vport_rl - rate limit in Mb/sec units - * @param link_speed - link speed in Mbps. + * @param rl_id - RL ID + * @param rate_limit - rate limit in Mb/sec units * * @return 0 on success, -1 on error. */ -int qed_init_vport_rl(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 vport_id, u32 vport_rl, u32 link_speed); +int qed_init_global_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 rl_id, u32 rate_limit); /** * @brief qed_send_qm_stop_cmd Sends a stop command to the QM diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index 2307f8842c9e..965529b1a9c5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -61,6 +61,9 @@ static u16 task_region_offsets[1][NUM_OF_CONNECTION_TYPES_E4] = { 0x100) - 1 : 0) #define QM_INVALID_PQ_ID 0xffff +/* Max link speed (in Mbps) */ +#define QM_MAX_LINK_SPEED 100000 + /* Feature enable */ #define QM_BYPASS_EN 1 #define QM_BYTE_CRD_EN 1 @@ -128,8 +131,6 @@ static u16 task_region_offsets[1][NUM_OF_CONNECTION_TYPES_E4] = { /* Pure LB CmdQ lines (+spare) */ #define PBF_CMDQ_PURE_LB_LINES 150 -#define PBF_CMDQ_LINES_E5_RSVD_RATIO 8 - #define PBF_CMDQ_LINES_RT_OFFSET(ext_voq) \ (PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET + \ (ext_voq) * (PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET - \ @@ -140,6 +141,9 @@ static u16 task_region_offsets[1][NUM_OF_CONNECTION_TYPES_E4] = { (ext_voq) * (PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET - \ PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET)) +/* Returns the VOQ line credit for the specified number of PBF command lines. + * PBF lines are specified in 256b units. + */ #define QM_VOQ_LINE_CRD(pbf_cmd_lines) \ ((((pbf_cmd_lines) - 4) * 2) | QM_LINE_CRD_REG_SIGN_BIT) @@ -178,14 +182,14 @@ static u16 task_region_offsets[1][NUM_OF_CONNECTION_TYPES_E4] = { cmd ## _ ## field, \ value) -#define QM_INIT_TX_PQ_MAP(p_hwfn, map, chip, pq_id, rl_valid, vp_pq_id, rl_id, \ +#define QM_INIT_TX_PQ_MAP(p_hwfn, map, chip, pq_id, vp_pq_id, rl_valid, rl_id, \ ext_voq, wrr) \ do { \ typeof(map) __map; \ memset(&__map, 0, sizeof(__map)); \ SET_FIELD(__map.reg, QM_RF_PQ_MAP_ ## chip ## _PQ_VALID, 1); \ SET_FIELD(__map.reg, QM_RF_PQ_MAP_ ## chip ## _RL_VALID, \ - rl_valid); \ + rl_valid ? 1 : 0);\ SET_FIELD(__map.reg, QM_RF_PQ_MAP_ ## chip ## _VP_PQ_ID, \ vp_pq_id); \ SET_FIELD(__map.reg, QM_RF_PQ_MAP_ ## chip ## _RL_ID, rl_id); \ @@ -200,9 +204,12 @@ static u16 task_region_offsets[1][NUM_OF_CONNECTION_TYPES_E4] = { #define WRITE_PQ_INFO_TO_RAM 1 #define PQ_INFO_ELEMENT(vp, pf, tc, port, rl_valid, rl) \ (((vp) << 0) | ((pf) << 12) | ((tc) << 16) | ((port) << 20) | \ - ((rl_valid) << 22) | ((rl) << 24)) + ((rl_valid ? 1 : 0) << 22) | (((rl) & 255) << 24) | \ + (((rl) >> 8) << 9)) + #define PQ_INFO_RAM_GRC_ADDRESS(pq_id) \ - (XSEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + 21776 + (pq_id) * 4) + XSEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + \ + XSTORM_PQ_INFO_OFFSET(pq_id) /******************** INTERNAL IMPLEMENTATION *********************/ @@ -256,12 +263,12 @@ static void qed_enable_pf_wfq(struct qed_hwfn *p_hwfn, bool pf_wfq_en) QM_WFQ_UPPER_BOUND); } -/* Prepare VPORT RL enable/disable runtime init values */ -static void qed_enable_vport_rl(struct qed_hwfn *p_hwfn, bool vport_rl_en) +/* Prepare global RL enable/disable runtime init values */ +static void qed_enable_global_rl(struct qed_hwfn *p_hwfn, bool global_rl_en) { STORE_RT_REG(p_hwfn, QM_REG_RLGLBLENABLE_RT_OFFSET, - vport_rl_en ? 1 : 0); - if (vport_rl_en) { + global_rl_en ? 1 : 0); + if (global_rl_en) { /* Write RL period (use timer 0 only) */ STORE_RT_REG(p_hwfn, QM_REG_RLGLBLPERIOD_0_RT_OFFSET, @@ -328,8 +335,7 @@ static void qed_cmdq_lines_rt_init( continue; /* Find number of command queue lines to divide between the - * active physical TCs. In E5, 1/8 of the lines are reserved. - * the lines for pure LB TC are subtracted. + * active physical TCs. */ phys_lines = port_params[port_id].num_pbf_cmd_lines; phys_lines -= PBF_CMDQ_PURE_LB_LINES; @@ -358,11 +364,30 @@ static void qed_cmdq_lines_rt_init( ext_voq = qed_get_ext_voq(p_hwfn, port_id, PURE_LB_TC, max_phys_tcs_per_port); - qed_cmdq_lines_voq_rt_init(p_hwfn, - ext_voq, PBF_CMDQ_PURE_LB_LINES); + qed_cmdq_lines_voq_rt_init(p_hwfn, ext_voq, + PBF_CMDQ_PURE_LB_LINES); } } +/* Prepare runtime init values to allocate guaranteed BTB blocks for the + * specified port. The guaranteed BTB space is divided between the TCs as + * follows (shared space Is currently not used): + * 1. Parameters: + * B - BTB blocks for this port + * C - Number of physical TCs for this port + * 2. Calculation: + * a. 38 blocks (9700B jumbo frame) are allocated for global per port + * headroom. + * b. B = B - 38 (remainder after global headroom allocation). + * c. MAX(38,B/(C+0.7)) blocks are allocated for the pure LB VOQ. + * d. B = B - MAX(38, B/(C+0.7)) (remainder after pure LB allocation). + * e. B/C blocks are allocated for each physical TC. + * Assumptions: + * - MTU is up to 9700 bytes (38 blocks) + * - All TCs are considered symmetrical (same rate and packet size) + * - No optimization for lossy TC (all are considered lossless). Shared space + * is not enabled and allocated for each TC. + */ static void qed_btb_blocks_rt_init( struct qed_hwfn *p_hwfn, u8 max_ports_per_engine, @@ -421,6 +446,34 @@ static void qed_btb_blocks_rt_init( } } +/* Prepare runtime init values for the specified RL. + * Set max link speed (100Gbps) per rate limiter. + * Return -1 on error. + */ +static int qed_global_rl_rt_init(struct qed_hwfn *p_hwfn) +{ + u32 upper_bound = QM_VP_RL_UPPER_BOUND(QM_MAX_LINK_SPEED) | + (u32)QM_RL_CRD_REG_SIGN_BIT; + u32 inc_val; + u16 rl_id; + + /* Go over all global RLs */ + for (rl_id = 0; rl_id < MAX_QM_GLOBAL_RLS; rl_id++) { + inc_val = QM_RL_INC_VAL(QM_MAX_LINK_SPEED); + + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLCRD_RT_OFFSET + rl_id, + (u32)QM_RL_CRD_REG_SIGN_BIT); + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLUPPERBOUND_RT_OFFSET + rl_id, + upper_bound); + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLINCVAL_RT_OFFSET + rl_id, inc_val); + } + + return 0; +} + /* Prepare Tx PQ mapping runtime init values for the specified PF */ static void qed_tx_pq_map_rt_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -457,18 +510,17 @@ static void qed_tx_pq_map_rt_init(struct qed_hwfn *p_hwfn, /* Go over all Tx PQs */ for (i = 0, pq_id = p_params->start_pq; i < num_pqs; i++, pq_id++) { - u8 ext_voq, vport_id_in_pf, tc_id = pq_params[i].tc_id; - u32 max_qm_global_rls = MAX_QM_GLOBAL_RLS; + u16 *p_first_tx_pq_id, vport_id_in_pf; struct qm_rf_pq_map_e4 tx_pq_map; - bool is_vf_pq, rl_valid; - u16 *p_first_tx_pq_id; + u8 tc_id = pq_params[i].tc_id; + bool is_vf_pq; + u8 ext_voq; ext_voq = qed_get_ext_voq(p_hwfn, pq_params[i].port_id, tc_id, p_params->max_phys_tcs_per_port); is_vf_pq = (i >= p_params->num_pf_pqs); - rl_valid = pq_params[i].rl_valid > 0; /* Update first Tx PQ of VPORT/TC */ vport_id_in_pf = pq_params[i].vport_id - p_params->start_vport; @@ -489,21 +541,14 @@ static void qed_tx_pq_map_rt_init(struct qed_hwfn *p_hwfn, map_val); } - /* Check RL ID */ - if (rl_valid && pq_params[i].vport_id >= max_qm_global_rls) { - DP_NOTICE(p_hwfn, - "Invalid VPORT ID for rate limiter configuration\n"); - rl_valid = false; - } - /* Prepare PQ map entry */ QM_INIT_TX_PQ_MAP(p_hwfn, tx_pq_map, E4, pq_id, - rl_valid ? 1 : 0, *p_first_tx_pq_id, - rl_valid ? pq_params[i].vport_id : 0, + pq_params[i].rl_valid, + pq_params[i].rl_id, ext_voq, pq_params[i].wrr_group); /* Set PQ base address */ @@ -526,9 +571,8 @@ static void qed_tx_pq_map_rt_init(struct qed_hwfn *p_hwfn, p_params->pf_id, tc_id, pq_params[i].port_id, - rl_valid ? 1 : 0, - rl_valid ? - pq_params[i].vport_id : 0); + pq_params[i].rl_valid, + pq_params[i].rl_id); qed_wr(p_hwfn, p_ptt, PQ_INFO_RAM_GRC_ADDRESS(pq_id), pq_info); } @@ -666,19 +710,19 @@ static int qed_pf_rl_rt_init(struct qed_hwfn *p_hwfn, u8 pf_id, u32 pf_rl) * Return -1 on error. */ static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn, - u8 num_vports, + u16 num_vports, struct init_qm_vport_params *vport_params) { - u16 vport_pq_id; + u16 vport_pq_id, i; u32 inc_val; - u8 tc, i; + u8 tc; /* Go over all PF VPORTs */ for (i = 0; i < num_vports; i++) { - if (!vport_params[i].vport_wfq) + if (!vport_params[i].wfq) continue; - inc_val = QM_WFQ_INC_VAL(vport_params[i].vport_wfq); + inc_val = QM_WFQ_INC_VAL(vport_params[i].wfq); if (inc_val > QM_WFQ_MAX_INC_VAL) { DP_NOTICE(p_hwfn, "Invalid VPORT WFQ weight configuration\n"); @@ -703,48 +747,6 @@ static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn, return 0; } -/* Prepare VPORT RL runtime init values for the specified VPORTs. - * Return -1 on error. - */ -static int qed_vport_rl_rt_init(struct qed_hwfn *p_hwfn, - u8 start_vport, - u8 num_vports, - u32 link_speed, - struct init_qm_vport_params *vport_params) -{ - u8 i, vport_id; - u32 inc_val; - - if (start_vport + num_vports >= MAX_QM_GLOBAL_RLS) { - DP_NOTICE(p_hwfn, - "Invalid VPORT ID for rate limiter configuration\n"); - return -1; - } - - /* Go over all PF VPORTs */ - for (i = 0, vport_id = start_vport; i < num_vports; i++, vport_id++) { - inc_val = QM_RL_INC_VAL(vport_params[i].vport_rl ? - vport_params[i].vport_rl : - link_speed); - if (inc_val > QM_VP_RL_MAX_INC_VAL(link_speed)) { - DP_NOTICE(p_hwfn, - "Invalid VPORT rate-limit configuration\n"); - return -1; - } - - STORE_RT_REG(p_hwfn, QM_REG_RLGLBLCRD_RT_OFFSET + vport_id, - (u32)QM_RL_CRD_REG_SIGN_BIT); - STORE_RT_REG(p_hwfn, - QM_REG_RLGLBLUPPERBOUND_RT_OFFSET + vport_id, - QM_VP_RL_UPPER_BOUND(link_speed) | - (u32)QM_RL_CRD_REG_SIGN_BIT); - STORE_RT_REG(p_hwfn, QM_REG_RLGLBLINCVAL_RT_OFFSET + vport_id, - inc_val); - } - - return 0; -} - static bool qed_poll_on_qm_cmd_ready(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { @@ -796,23 +798,20 @@ u32 qed_qm_pf_mem_size(u32 num_pf_cids, int qed_qm_common_rt_init(struct qed_hwfn *p_hwfn, struct qed_qm_common_rt_init_params *p_params) { - /* Init AFullOprtnstcCrdMask */ - u32 mask = (QM_OPPOR_LINE_VOQ_DEF << - QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_SHIFT) | - (QM_BYTE_CRD_EN << QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_SHIFT) | - (p_params->pf_wfq_en << - QM_RF_OPPORTUNISTIC_MASK_PFWFQ_SHIFT) | - (p_params->vport_wfq_en << - QM_RF_OPPORTUNISTIC_MASK_VPWFQ_SHIFT) | - (p_params->pf_rl_en << - QM_RF_OPPORTUNISTIC_MASK_PFRL_SHIFT) | - (p_params->vport_rl_en << - QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_SHIFT) | - (QM_OPPOR_FW_STOP_DEF << - QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_SHIFT) | - (QM_OPPOR_PQ_EMPTY_DEF << - QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_SHIFT); + u32 mask = 0; + /* Init AFullOprtnstcCrdMask */ + SET_FIELD(mask, QM_RF_OPPORTUNISTIC_MASK_LINEVOQ, + QM_OPPOR_LINE_VOQ_DEF); + SET_FIELD(mask, QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ, QM_BYTE_CRD_EN); + SET_FIELD(mask, QM_RF_OPPORTUNISTIC_MASK_PFWFQ, p_params->pf_wfq_en); + SET_FIELD(mask, QM_RF_OPPORTUNISTIC_MASK_VPWFQ, p_params->vport_wfq_en); + SET_FIELD(mask, QM_RF_OPPORTUNISTIC_MASK_PFRL, p_params->pf_rl_en); + SET_FIELD(mask, QM_RF_OPPORTUNISTIC_MASK_VPQCNRL, + p_params->global_rl_en); + SET_FIELD(mask, QM_RF_OPPORTUNISTIC_MASK_FWPAUSE, QM_OPPOR_FW_STOP_DEF); + SET_FIELD(mask, + QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY, QM_OPPOR_PQ_EMPTY_DEF); STORE_RT_REG(p_hwfn, QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET, mask); /* Enable/disable PF RL */ @@ -821,8 +820,8 @@ int qed_qm_common_rt_init(struct qed_hwfn *p_hwfn, /* Enable/disable PF WFQ */ qed_enable_pf_wfq(p_hwfn, p_params->pf_wfq_en); - /* Enable/disable VPORT RL */ - qed_enable_vport_rl(p_hwfn, p_params->vport_rl_en); + /* Enable/disable global RL */ + qed_enable_global_rl(p_hwfn, p_params->global_rl_en); /* Enable/disable VPORT WFQ */ qed_enable_vport_wfq(p_hwfn, p_params->vport_wfq_en); @@ -839,6 +838,8 @@ int qed_qm_common_rt_init(struct qed_hwfn *p_hwfn, p_params->max_phys_tcs_per_port, p_params->port_params); + qed_global_rl_rt_init(p_hwfn); + return 0; } @@ -850,7 +851,9 @@ int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, u32 other_mem_size_4kb = QM_PQ_MEM_4KB(p_params->num_pf_cids + p_params->num_tids) * QM_OTHER_PQS_PER_PF; - u8 tc, i; + u16 i; + u8 tc; + /* Clear first Tx PQ ID array for each VPORT */ for (i = 0; i < p_params->num_vports; i++) @@ -875,16 +878,10 @@ int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, if (qed_pf_rl_rt_init(p_hwfn, p_params->pf_id, p_params->pf_rl)) return -1; - /* Set VPORT WFQ */ + /* Init VPORT WFQ */ if (qed_vp_wfq_rt_init(p_hwfn, p_params->num_vports, vport_params)) return -1; - /* Set VPORT RL */ - if (qed_vport_rl_rt_init(p_hwfn, p_params->start_vport, - p_params->num_vports, p_params->link_speed, - vport_params)) - return -1; - return 0; } @@ -922,18 +919,19 @@ int qed_init_pf_rl(struct qed_hwfn *p_hwfn, int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u16 first_tx_pq_id[NUM_OF_TCS], u16 vport_wfq) + u16 first_tx_pq_id[NUM_OF_TCS], u16 wfq) { u16 vport_pq_id; u32 inc_val; u8 tc; - inc_val = QM_WFQ_INC_VAL(vport_wfq); + inc_val = QM_WFQ_INC_VAL(wfq); if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid VPORT WFQ weight configuration\n"); + DP_NOTICE(p_hwfn, "Invalid VPORT WFQ configuration.\n"); return -1; } + /* A VPORT can have several VPORT PQ IDs for various TCs */ for (tc = 0; tc < NUM_OF_TCS; tc++) { vport_pq_id = first_tx_pq_id[tc]; if (vport_pq_id != QM_INVALID_PQ_ID) @@ -945,28 +943,20 @@ int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, return 0; } -int qed_init_vport_rl(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 vport_id, u32 vport_rl, u32 link_speed) +int qed_init_global_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u16 rl_id, u32 rate_limit) { - u32 inc_val, max_qm_global_rls = MAX_QM_GLOBAL_RLS; - - if (vport_id >= max_qm_global_rls) { - DP_NOTICE(p_hwfn, - "Invalid VPORT ID for rate limiter configuration\n"); - return -1; - } + u32 inc_val; - inc_val = QM_RL_INC_VAL(vport_rl ? vport_rl : link_speed); - if (inc_val > QM_VP_RL_MAX_INC_VAL(link_speed)) { - DP_NOTICE(p_hwfn, "Invalid VPORT rate-limit configuration\n"); + inc_val = QM_RL_INC_VAL(rate_limit); + if (inc_val > QM_VP_RL_MAX_INC_VAL(rate_limit)) { + DP_NOTICE(p_hwfn, "Invalid rate limit configuration.\n"); return -1; } - qed_wr(p_hwfn, - p_ptt, - QM_REG_RLGLBLCRD + vport_id * 4, (u32)QM_RL_CRD_REG_SIGN_BIT); - qed_wr(p_hwfn, p_ptt, QM_REG_RLGLBLINCVAL + vport_id * 4, inc_val); + qed_wr(p_hwfn, p_ptt, + QM_REG_RLGLBLCRD + rl_id * 4, (u32)QM_RL_CRD_REG_SIGN_BIT); + qed_wr(p_hwfn, p_ptt, QM_REG_RLGLBLINCVAL + rl_id * 4, inc_val); return 0; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index dcb5c917f373..fe4b740de14c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -4354,9 +4354,9 @@ qed_iov_bulletin_get_forced_vlan(struct qed_hwfn *p_hwfn, u16 rel_vf_id) static int qed_iov_configure_tx_rate(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, int vfid, int val) { - struct qed_mcp_link_state *p_link; struct qed_vf_info *vf; u8 abs_vp_id = 0; + u16 rl_id; int rc; vf = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); @@ -4367,10 +4367,8 @@ static int qed_iov_configure_tx_rate(struct qed_hwfn *p_hwfn, if (rc) return rc; - p_link = &QED_LEADING_HWFN(p_hwfn->cdev)->mcp_info->link_output; - - return qed_init_vport_rl(p_hwfn, p_ptt, abs_vp_id, (u32)val, - p_link->speed); + rl_id = abs_vp_id; /* The "rl_id" is set as the "vport_id" */ + return qed_init_global_rl(p_hwfn, p_ptt, rl_id, (u32)val); } static int -- cgit v1.2.3-59-g8ed1b From 63ddca3052ce2397ffd71899390d552cd40ddb6f Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Mon, 27 Jan 2020 15:26:10 +0200 Subject: qed: FW 8.42.2.0 Parser offsets modified Convert storm ram line to regpair rather than two distinct u32 to better represent the u64 width of the ram. Convert some defines to be hex instead of negative values these values also changed by FW from previous value. Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 51 +++++++++++----------- 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c') diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index 965529b1a9c5..40b8a52dbfa3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -1000,7 +1000,6 @@ bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, return true; } - #define SET_TUNNEL_TYPE_ENABLE_BIT(var, offset, enable) \ do { \ typeof(var) *__p_var = &(var); \ @@ -1008,8 +1007,9 @@ bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, *__p_var = (*__p_var & ~BIT(__offset)) | \ ((enable) ? BIT(__offset) : 0); \ } while (0) -#define PRS_ETH_TUNN_OUTPUT_FORMAT -188897008 -#define PRS_ETH_OUTPUT_FORMAT -46832 + +#define PRS_ETH_TUNN_OUTPUT_FORMAT 0xF4DAB910 +#define PRS_ETH_OUTPUT_FORMAT 0xFFFF4910 void qed_set_vxlan_dest_port(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 dest_port) @@ -1153,8 +1153,8 @@ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn, ip_geneve_enable ? 1 : 0); } -#define PRS_ETH_VXLAN_NO_L2_ENABLE_OFFSET 4 -#define PRS_ETH_VXLAN_NO_L2_OUTPUT_FORMAT -927094512 +#define PRS_ETH_VXLAN_NO_L2_ENABLE_OFFSET 3 +#define PRS_ETH_VXLAN_NO_L2_OUTPUT_FORMAT -925189872 void qed_set_vxlan_no_l2_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool enable) @@ -1219,7 +1219,8 @@ void qed_gft_config(struct qed_hwfn *p_hwfn, bool udp, bool ipv4, bool ipv6, enum gft_profile_type profile_type) { - u32 reg_val, cam_line, ram_line_lo, ram_line_hi, search_non_ip_as_gft; + u32 reg_val, cam_line, search_non_ip_as_gft; + struct regpair ram_line = { }; if (!ipv6 && !ipv4) DP_NOTICE(p_hwfn, @@ -1285,35 +1286,33 @@ void qed_gft_config(struct qed_hwfn *p_hwfn, qed_rd(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id); /* Write line to RAM - compare to filter 4 tuple */ - ram_line_lo = 0; - ram_line_hi = 0; /* Search no IP as GFT */ search_non_ip_as_gft = 0; /* Tunnel type */ - SET_FIELD(ram_line_lo, GFT_RAM_LINE_TUNNEL_DST_PORT, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_TUNNEL_DST_PORT, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL, 1); if (profile_type == GFT_PROFILE_TYPE_4_TUPLE) { - SET_FIELD(ram_line_hi, GFT_RAM_LINE_DST_IP, 1); - SET_FIELD(ram_line_hi, GFT_RAM_LINE_SRC_IP, 1); - SET_FIELD(ram_line_hi, GFT_RAM_LINE_OVER_IP_PROTOCOL, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_ETHERTYPE, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_SRC_PORT, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_DST_PORT, 1); + SET_FIELD(ram_line.hi, GFT_RAM_LINE_DST_IP, 1); + SET_FIELD(ram_line.hi, GFT_RAM_LINE_SRC_IP, 1); + SET_FIELD(ram_line.hi, GFT_RAM_LINE_OVER_IP_PROTOCOL, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_ETHERTYPE, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_SRC_PORT, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_DST_PORT, 1); } else if (profile_type == GFT_PROFILE_TYPE_L4_DST_PORT) { - SET_FIELD(ram_line_hi, GFT_RAM_LINE_OVER_IP_PROTOCOL, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_ETHERTYPE, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_DST_PORT, 1); + SET_FIELD(ram_line.hi, GFT_RAM_LINE_OVER_IP_PROTOCOL, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_ETHERTYPE, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_DST_PORT, 1); } else if (profile_type == GFT_PROFILE_TYPE_IP_DST_ADDR) { - SET_FIELD(ram_line_hi, GFT_RAM_LINE_DST_IP, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_ETHERTYPE, 1); + SET_FIELD(ram_line.hi, GFT_RAM_LINE_DST_IP, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_ETHERTYPE, 1); } else if (profile_type == GFT_PROFILE_TYPE_IP_SRC_ADDR) { - SET_FIELD(ram_line_hi, GFT_RAM_LINE_SRC_IP, 1); - SET_FIELD(ram_line_lo, GFT_RAM_LINE_ETHERTYPE, 1); + SET_FIELD(ram_line.hi, GFT_RAM_LINE_SRC_IP, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_ETHERTYPE, 1); } else if (profile_type == GFT_PROFILE_TYPE_TUNNEL_TYPE) { - SET_FIELD(ram_line_lo, GFT_RAM_LINE_TUNNEL_ETHERTYPE, 1); + SET_FIELD(ram_line.lo, GFT_RAM_LINE_TUNNEL_ETHERTYPE, 1); /* Allow tunneled traffic without inner IP */ search_non_ip_as_gft = 1; @@ -1324,11 +1323,11 @@ void qed_gft_config(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id, - ram_line_lo); + ram_line.lo); qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id + REG_SIZE, - ram_line_hi); + ram_line.hi); /* Set default profile so that no filter match will happen */ qed_wr(p_hwfn, -- cgit v1.2.3-59-g8ed1b From 804c5702fc583afbdb6860f79e9d4058570ccc43 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Mon, 27 Jan 2020 15:26:11 +0200 Subject: qed: Use dmae to write to widebus registers in fw_funcs There are several wide-bus registers written to by the fw_funcs that require using the dmae for atomicity. Therefore using the dmae channel functionality was added to the fw_funcs file, since the code is very similar to the previously used code, the structures used were moved to qed_hsi. Due to FW conventions, the names of the flags in the struct changed. Since this required slight modification in the places that set the flags the code was modified to use GET/SET FIELD macros. Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 24 ------ drivers/net/ethernet/qlogic/qed/qed_hsi.h | 41 ++++++++++- drivers/net/ethernet/qlogic/qed/qed_hw.c | 67 ++++++++--------- .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 86 ++++++++++++++++------ drivers/net/ethernet/qlogic/qed/qed_init_ops.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 11 +-- 7 files changed, 142 insertions(+), 91 deletions(-) (limited to 'drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 249fcc3dc138..479d98e6187a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -907,7 +907,7 @@ qed_llh_access_filter(struct qed_hwfn *p_hwfn, /* Filter value */ addr = NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * filter_idx * 0x4; - params.flags = QED_DMAE_FLAG_PF_DST; + SET_FIELD(params.flags, QED_DMAE_PARAMS_DST_PF_VALID, 0x1); params.dst_pfid = pfid; rc = qed_dmae_host2grc(p_hwfn, p_ptt, diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h index 47376d4d071f..eb4808b3bf67 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -230,30 +230,6 @@ enum qed_dmae_address_type_t { QED_DMAE_ADDRESS_GRC }; -/* value of flags If QED_DMAE_FLAG_RW_REPL_SRC flag is set and the - * source is a block of length DMAE_MAX_RW_SIZE and the - * destination is larger, the source block will be duplicated as - * many times as required to fill the destination block. This is - * used mostly to write a zeroed buffer to destination address - * using DMA - */ -#define QED_DMAE_FLAG_RW_REPL_SRC 0x00000001 -#define QED_DMAE_FLAG_VF_SRC 0x00000002 -#define QED_DMAE_FLAG_VF_DST 0x00000004 -#define QED_DMAE_FLAG_COMPLETION_DST 0x00000008 -#define QED_DMAE_FLAG_PORT 0x00000010 -#define QED_DMAE_FLAG_PF_SRC 0x00000020 -#define QED_DMAE_FLAG_PF_DST 0x00000040 - -struct qed_dmae_params { - u32 flags; /* consists of QED_DMAE_FLAG_* values */ - u8 src_vfid; - u8 dst_vfid; - u8 port_id; - u8 src_pfid; - u8 dst_pfid; -}; - /** * @brief qed_dmae_host2grc - copy data from source addr to * dmae registers using the given ptt diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 5ac68ec01a04..cced2ce365de 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -1435,7 +1435,11 @@ struct dmae_cmd { __le16 crc16; __le16 crc16_c; __le16 crc10; - __le16 reserved; + __le16 error_bit_reserved; +#define DMAE_CMD_ERROR_BIT_MASK 0x1 +#define DMAE_CMD_ERROR_BIT_SHIFT 0 +#define DMAE_CMD_RESERVED_MASK 0x7FFF +#define DMAE_CMD_RESERVED_SHIFT 1 __le16 xsum16; __le16 xsum8; }; @@ -1566,6 +1570,41 @@ struct e4_ystorm_core_conn_ag_ctx { __le32 reg3; }; +/* DMAE parameters */ +struct qed_dmae_params { + u32 flags; +/* If QED_DMAE_PARAMS_RW_REPL_SRC flag is set and the + * source is a block of length DMAE_MAX_RW_SIZE and the + * destination is larger, the source block will be duplicated as + * many times as required to fill the destination block. This is + * used mostly to write a zeroed buffer to destination address + * using DMA + */ +#define QED_DMAE_PARAMS_RW_REPL_SRC_MASK 0x1 +#define QED_DMAE_PARAMS_RW_REPL_SRC_SHIFT 0 +#define QED_DMAE_PARAMS_SRC_VF_VALID_MASK 0x1 +#define QED_DMAE_PARAMS_SRC_VF_VALID_SHIFT 1 +#define QED_DMAE_PARAMS_DST_VF_VALID_MASK 0x1 +#define QED_DMAE_PARAMS_DST_VF_VALID_SHIFT 2 +#define QED_DMAE_PARAMS_COMPLETION_DST_MASK 0x1 +#define QED_DMAE_PARAMS_COMPLETION_DST_SHIFT 3 +#define QED_DMAE_PARAMS_PORT_VALID_MASK 0x1 +#define QED_DMAE_PARAMS_PORT_VALID_SHIFT 4 +#define QED_DMAE_PARAMS_SRC_PF_VALID_MASK 0x1 +#define QED_DMAE_PARAMS_SRC_PF_VALID_SHIFT 5 +#define QED_DMAE_PARAMS_DST_PF_VALID_MASK 0x1 +#define QED_DMAE_PARAMS_DST_PF_VALID_SHIFT 6 +#define QED_DMAE_PARAMS_RESERVED_MASK 0x1FFFFFF +#define QED_DMAE_PARAMS_RESERVED_SHIFT 7 + u8 src_vfid; + u8 dst_vfid; + u8 port_id; + u8 src_pfid; + u8 dst_pfid; + u8 reserved1; + __le16 reserved2; +}; + /* IGU cleanup command */ struct igu_cleanup { __le32 sb_id_and_flags; diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c index a4de9e3ef72c..4ab8cfaf63d1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -393,7 +393,7 @@ u32 qed_vfid_to_concrete(struct qed_hwfn *p_hwfn, u8 vfid) /* DMAE */ #define QED_DMAE_FLAGS_IS_SET(params, flag) \ - ((params) != NULL && ((params)->flags & QED_DMAE_FLAG_##flag)) + ((params) != NULL && GET_FIELD((params)->flags, QED_DMAE_PARAMS_##flag)) static void qed_dmae_opcode(struct qed_hwfn *p_hwfn, const u8 is_src_type_grc, @@ -408,62 +408,55 @@ static void qed_dmae_opcode(struct qed_hwfn *p_hwfn, * 0- The source is the PCIe * 1- The source is the GRC. */ - opcode |= (is_src_type_grc ? DMAE_CMD_SRC_MASK_GRC - : DMAE_CMD_SRC_MASK_PCIE) << - DMAE_CMD_SRC_SHIFT; - src_pfid = QED_DMAE_FLAGS_IS_SET(p_params, PF_SRC) ? - p_params->src_pfid : p_hwfn->rel_pf_id; - opcode |= ((src_pfid & DMAE_CMD_SRC_PF_ID_MASK) << - DMAE_CMD_SRC_PF_ID_SHIFT); + SET_FIELD(opcode, DMAE_CMD_SRC, + (is_src_type_grc ? dmae_cmd_src_grc : dmae_cmd_src_pcie)); + src_pfid = QED_DMAE_FLAGS_IS_SET(p_params, SRC_PF_VALID) ? + p_params->src_pfid : p_hwfn->rel_pf_id; + SET_FIELD(opcode, DMAE_CMD_SRC_PF_ID, src_pfid); /* The destination of the DMA can be: 0-None 1-PCIe 2-GRC 3-None */ - opcode |= (is_dst_type_grc ? DMAE_CMD_DST_MASK_GRC - : DMAE_CMD_DST_MASK_PCIE) << - DMAE_CMD_DST_SHIFT; - dst_pfid = QED_DMAE_FLAGS_IS_SET(p_params, PF_DST) ? - p_params->dst_pfid : p_hwfn->rel_pf_id; - opcode |= ((dst_pfid & DMAE_CMD_DST_PF_ID_MASK) << - DMAE_CMD_DST_PF_ID_SHIFT); + SET_FIELD(opcode, DMAE_CMD_DST, + (is_dst_type_grc ? dmae_cmd_dst_grc : dmae_cmd_dst_pcie)); + dst_pfid = QED_DMAE_FLAGS_IS_SET(p_params, DST_PF_VALID) ? + p_params->dst_pfid : p_hwfn->rel_pf_id; + SET_FIELD(opcode, DMAE_CMD_DST_PF_ID, dst_pfid); + /* Whether to write a completion word to the completion destination: * 0-Do not write a completion word * 1-Write the completion word */ - opcode |= (DMAE_CMD_COMP_WORD_EN_MASK << DMAE_CMD_COMP_WORD_EN_SHIFT); - opcode |= (DMAE_CMD_SRC_ADDR_RESET_MASK << - DMAE_CMD_SRC_ADDR_RESET_SHIFT); + SET_FIELD(opcode, DMAE_CMD_COMP_WORD_EN, 1); + SET_FIELD(opcode, DMAE_CMD_SRC_ADDR_RESET, 1); if (QED_DMAE_FLAGS_IS_SET(p_params, COMPLETION_DST)) - opcode |= (1 << DMAE_CMD_COMP_FUNC_SHIFT); + SET_FIELD(opcode, DMAE_CMD_COMP_FUNC, 1); - opcode |= (DMAE_CMD_ENDIANITY << DMAE_CMD_ENDIANITY_MODE_SHIFT); + /* swapping mode 3 - big endian */ + SET_FIELD(opcode, DMAE_CMD_ENDIANITY_MODE, DMAE_CMD_ENDIANITY); - port_id = (QED_DMAE_FLAGS_IS_SET(p_params, PORT)) ? - p_params->port_id : p_hwfn->port_id; - opcode |= (port_id << DMAE_CMD_PORT_ID_SHIFT); + port_id = (QED_DMAE_FLAGS_IS_SET(p_params, PORT_VALID)) ? + p_params->port_id : p_hwfn->port_id; + SET_FIELD(opcode, DMAE_CMD_PORT_ID, port_id); /* reset source address in next go */ - opcode |= (DMAE_CMD_SRC_ADDR_RESET_MASK << - DMAE_CMD_SRC_ADDR_RESET_SHIFT); + SET_FIELD(opcode, DMAE_CMD_SRC_ADDR_RESET, 1); /* reset dest address in next go */ - opcode |= (DMAE_CMD_DST_ADDR_RESET_MASK << - DMAE_CMD_DST_ADDR_RESET_SHIFT); + SET_FIELD(opcode, DMAE_CMD_DST_ADDR_RESET, 1); /* SRC/DST VFID: all 1's - pf, otherwise VF id */ - if (QED_DMAE_FLAGS_IS_SET(p_params, VF_SRC)) { - opcode |= 1 << DMAE_CMD_SRC_VF_ID_VALID_SHIFT; - opcode_b |= p_params->src_vfid << DMAE_CMD_SRC_VF_ID_SHIFT; + if (QED_DMAE_FLAGS_IS_SET(p_params, SRC_VF_VALID)) { + SET_FIELD(opcode, DMAE_CMD_SRC_VF_ID_VALID, 1); + SET_FIELD(opcode_b, DMAE_CMD_SRC_VF_ID, p_params->src_vfid); } else { - opcode_b |= DMAE_CMD_SRC_VF_ID_MASK << - DMAE_CMD_SRC_VF_ID_SHIFT; + SET_FIELD(opcode_b, DMAE_CMD_SRC_VF_ID, 0xFF); } - - if (QED_DMAE_FLAGS_IS_SET(p_params, VF_DST)) { - opcode |= 1 << DMAE_CMD_DST_VF_ID_VALID_SHIFT; - opcode_b |= p_params->dst_vfid << DMAE_CMD_DST_VF_ID_SHIFT; + if (QED_DMAE_FLAGS_IS_SET(p_params, DST_VF_VALID)) { + SET_FIELD(opcode, DMAE_CMD_DST_VF_ID_VALID, 1); + SET_FIELD(opcode_b, DMAE_CMD_DST_VF_ID, p_params->dst_vfid); } else { - opcode_b |= DMAE_CMD_DST_VF_ID_MASK << DMAE_CMD_DST_VF_ID_SHIFT; + SET_FIELD(opcode_b, DMAE_CMD_DST_VF_ID, 0xFF); } p_hwfn->dmae_info.p_dmae_cmd->opcode = cpu_to_le32(opcode); diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index 40b8a52dbfa3..6fdf9ab98685 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -1011,6 +1011,56 @@ bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, #define PRS_ETH_TUNN_OUTPUT_FORMAT 0xF4DAB910 #define PRS_ETH_OUTPUT_FORMAT 0xFFFF4910 +#define ARR_REG_WR(dev, ptt, addr, arr, arr_size) \ + do { \ + u32 i; \ + \ + for (i = 0; i < (arr_size); i++) \ + qed_wr(dev, ptt, \ + ((addr) + (4 * i)), \ + ((u32 *)&(arr))[i]); \ + } while (0) + +/** + * @brief qed_dmae_to_grc - is an internal function - writes from host to + * wide-bus registers (split registers are not supported yet) + * + * @param p_hwfn - HW device data + * @param p_ptt - ptt window used for writing the registers. + * @param p_data - pointer to source data. + * @param addr - Destination register address. + * @param len_in_dwords - data length in DWARDS (u32) + */ +static int qed_dmae_to_grc(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *p_data, u32 addr, u32 len_in_dwords) +{ + struct qed_dmae_params params = {}; + int rc; + + if (!p_data) + return -1; + + /* Set DMAE params */ + SET_FIELD(params.flags, QED_DMAE_PARAMS_COMPLETION_DST, 1); + + /* Execute DMAE command */ + rc = qed_dmae_host2grc(p_hwfn, p_ptt, + (u64)(uintptr_t)(p_data), + addr, len_in_dwords, ¶ms); + + /* If not read using DMAE, read using GRC */ + if (rc) { + DP_VERBOSE(p_hwfn, + QED_MSG_DEBUG, + "Failed writing to chip using DMAE, using GRC instead\n"); + /* write to registers using GRC */ + ARR_REG_WR(p_hwfn, p_ptt, addr, p_data, len_in_dwords); + } + + return len_in_dwords; +} + void qed_set_vxlan_dest_port(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 dest_port) { @@ -1195,6 +1245,8 @@ void qed_set_vxlan_no_l2_enable(struct qed_hwfn *p_hwfn, void qed_gft_disable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 pf_id) { + struct regpair ram_line = { }; + /* Disable gft search for PF */ qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_GFT, 0); @@ -1204,12 +1256,9 @@ void qed_gft_disable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 pf_id) qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id, 0); /* Zero ramline */ - qed_wr(p_hwfn, - p_ptt, PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id, 0); - qed_wr(p_hwfn, - p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id + REG_SIZE, - 0); + qed_dmae_to_grc(p_hwfn, p_ptt, (u32 *)&ram_line, + PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id, + sizeof(ram_line) / REG_SIZE); } void qed_gft_config(struct qed_hwfn *p_hwfn, @@ -1320,24 +1369,17 @@ void qed_gft_config(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_NON_IP_AS_GFT, search_non_ip_as_gft); - qed_wr(p_hwfn, - p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id, - ram_line.lo); - qed_wr(p_hwfn, - p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id + REG_SIZE, - ram_line.hi); + qed_dmae_to_grc(p_hwfn, p_ptt, (u32 *)&ram_line, + PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id, + sizeof(ram_line) / REG_SIZE); /* Set default profile so that no filter match will happen */ - qed_wr(p_hwfn, - p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * - PRS_GFT_CAM_LINES_NO_MATCH, 0xffffffff); - qed_wr(p_hwfn, - p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * - PRS_GFT_CAM_LINES_NO_MATCH + REG_SIZE, 0x3ff); + ram_line.lo = 0xffffffff; + ram_line.hi = 0x3ff; + qed_dmae_to_grc(p_hwfn, p_ptt, (u32 *)&ram_line, + PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * + PRS_GFT_CAM_LINES_NO_MATCH, + sizeof(ram_line) / REG_SIZE); /* Enable gft search */ qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_GFT, 1); diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c index ef22a3596295..31222b3e3936 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -215,7 +215,7 @@ static int qed_init_fill_dmae(struct qed_hwfn *p_hwfn, * 3. p_hwfb->temp_data, * 4. fill_count */ - params.flags = QED_DMAE_FLAG_RW_REPL_SRC; + SET_FIELD(params.flags, QED_DMAE_PARAMS_RW_REPL_SRC, 0x1); return qed_dmae_host2grc(p_hwfn, p_ptt, (uintptr_t)(&zero_buffer[0]), addr, fill_count, ¶ms); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index fe4b740de14c..66876af814c4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -352,7 +352,7 @@ static int qed_iov_post_vf_bulletin(struct qed_hwfn *p_hwfn, /* propagate bulletin board via dmae to vm memory */ memset(¶ms, 0, sizeof(params)); - params.flags = QED_DMAE_FLAG_VF_DST; + SET_FIELD(params.flags, QED_DMAE_PARAMS_DST_VF_VALID, 0x1); params.dst_vfid = p_vf->abs_vf_id; return qed_dmae_host2host(p_hwfn, p_ptt, p_vf->bulletin.phys, p_vf->vf_bulletin, p_vf->bulletin.size / 4, @@ -1225,8 +1225,8 @@ static void qed_iov_send_response(struct qed_hwfn *p_hwfn, eng_vf_id = p_vf->abs_vf_id; - memset(¶ms, 0, sizeof(struct qed_dmae_params)); - params.flags = QED_DMAE_FLAG_VF_DST; + memset(¶ms, 0, sizeof(params)); + SET_FIELD(params.flags, QED_DMAE_PARAMS_DST_VF_VALID, 0x1); params.dst_vfid = eng_vf_id; qed_dmae_host2host(p_hwfn, p_ptt, mbx->reply_phys + sizeof(u64), @@ -4103,8 +4103,9 @@ static int qed_iov_copy_vf_msg(struct qed_hwfn *p_hwfn, struct qed_ptt *ptt, if (!vf_info) return -EINVAL; - memset(¶ms, 0, sizeof(struct qed_dmae_params)); - params.flags = QED_DMAE_FLAG_VF_SRC | QED_DMAE_FLAG_COMPLETION_DST; + memset(¶ms, 0, sizeof(params)); + SET_FIELD(params.flags, QED_DMAE_PARAMS_SRC_VF_VALID, 0x1); + SET_FIELD(params.flags, QED_DMAE_PARAMS_COMPLETION_DST, 0x1); params.src_vfid = vf_info->abs_vf_id; if (qed_dmae_host2host(p_hwfn, ptt, -- cgit v1.2.3-59-g8ed1b From 30d5f85895fad1b3fec34b86cb779d4f56f85e32 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Mon, 27 Jan 2020 15:26:16 +0200 Subject: qed: FW 8.42.2.0 Add fw overlay feature This feature enables the FW to page out FW code when required Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 3 + drivers/net/ethernet/qlogic/qed/qed_dev.c | 18 ++- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 58 +++++++++ .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 141 +++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_init_ops.c | 5 + 5 files changed, 224 insertions(+), 1 deletion(-) (limited to 'drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index cfbfe7441ecb..fedb1ab0b223 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -462,6 +462,8 @@ struct qed_fw_data { const u8 *modes_tree_buf; union init_op *init_ops; const u32 *arr_data; + const u32 *fw_overlays; + u32 fw_overlays_len; u32 init_ops_size; }; @@ -686,6 +688,7 @@ struct qed_hwfn { /* Nvm images number and attributes */ struct qed_nvm_image_info nvm_info; + struct phys_mem_desc *fw_overlay_mem; struct qed_ptt *p_arfs_ptt; struct qed_simd_fp_handler simd_proto_handler[64]; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index e3e0376c13d6..df97810b09b9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1412,6 +1412,7 @@ void qed_resc_free(struct qed_dev *cdev) qed_dmae_info_free(p_hwfn); qed_dcbx_info_free(p_hwfn); qed_dbg_user_data_free(p_hwfn); + qed_fw_overlay_mem_free(p_hwfn, p_hwfn->fw_overlay_mem); /* Destroy doorbell recovery mechanism */ qed_db_recovery_teardown(p_hwfn); @@ -2893,6 +2894,8 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, if (rc) return rc; + qed_fw_overlay_init_ram(p_hwfn, p_ptt, p_hwfn->fw_overlay_mem); + /* Pure runtime initializations - directly to the HW */ qed_int_igu_init_pure_rt(p_hwfn, p_ptt, true, true); @@ -3002,8 +3005,10 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) u32 load_code, resp, param, drv_mb_param; bool b_default_mtu = true; struct qed_hwfn *p_hwfn; - int rc = 0, i; + const u32 *fw_overlays; + u32 fw_overlays_len; u16 ether_type; + int rc = 0, i; if ((p_params->int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); @@ -3104,6 +3109,17 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) */ qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt); + fw_overlays = cdev->fw_data->fw_overlays; + fw_overlays_len = cdev->fw_data->fw_overlays_len; + p_hwfn->fw_overlay_mem = + qed_fw_overlay_mem_alloc(p_hwfn, fw_overlays, + fw_overlays_len); + if (!p_hwfn->fw_overlay_mem) { + DP_NOTICE(p_hwfn, + "Failed to allocate fw overlay memory\n"); + goto load_err; + } + switch (load_code) { case FW_MSG_CODE_DRV_LOAD_ENGINE: rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt, diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 06b94508115a..67c048415d3b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -1843,6 +1843,19 @@ struct sdm_op_gen { #define SDM_OP_GEN_RESERVED_SHIFT 20 }; +/* Physical memory descriptor */ +struct phys_mem_desc { + dma_addr_t phys_addr; + void *virt_addr; + u32 size; /* In bytes */ +}; + +/* Virtual memory descriptor */ +struct virt_mem_desc { + void *ptr; + u32 size; /* In bytes */ +}; + /****************************************/ /* Debug Tools HSI constants and macros */ /****************************************/ @@ -2872,6 +2885,15 @@ enum bin_init_buffer_type { MAX_BIN_INIT_BUFFER_TYPE }; +/* FW overlay buffer header */ +struct fw_overlay_buf_hdr { + u32 data; +#define FW_OVERLAY_BUF_HDR_STORM_ID_MASK 0xFF +#define FW_OVERLAY_BUF_HDR_STORM_ID_SHIFT 0 +#define FW_OVERLAY_BUF_HDR_BUF_SIZE_MASK 0xFFFFFF +#define FW_OVERLAY_BUF_HDR_BUF_SIZE_SHIFT 8 +}; + /* init array header: raw */ struct init_array_raw_hdr { u32 data; @@ -4345,6 +4367,42 @@ void qed_memset_task_ctx(void *p_ctx_mem, u32 ctx_size, u8 ctx_type); void qed_set_rdma_error_level(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u8 assert_level[NUM_STORMS]); +/** + * @brief qed_fw_overlay_mem_alloc - Allocates and fills the FW overlay memory. + * + * @param p_hwfn - HW device data + * @param fw_overlay_in_buf - the input FW overlay buffer. + * @param buf_size - the size of the input FW overlay buffer in bytes. + * must be aligned to dwords. + * @param fw_overlay_out_mem - OUT: a pointer to the allocated overlays memory. + * + * @return a pointer to the allocated overlays memory, + * or NULL in case of failures. + */ +struct phys_mem_desc * +qed_fw_overlay_mem_alloc(struct qed_hwfn *p_hwfn, + const u32 * const fw_overlay_in_buf, + u32 buf_size_in_bytes); + +/** + * @brief qed_fw_overlay_init_ram - Initializes the FW overlay RAM. + * + * @param p_hwfn - HW device data. + * @param p_ptt - ptt window used for writing the registers. + * @param fw_overlay_mem - the allocated FW overlay memory. + */ +void qed_fw_overlay_init_ram(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct phys_mem_desc *fw_overlay_mem); + +/** + * @brief qed_fw_overlay_mem_free - Frees the FW overlay memory. + * + * @param p_hwfn - HW device data. + * @param fw_overlay_mem - the allocated FW overlay memory to free. + */ +void qed_fw_overlay_mem_free(struct qed_hwfn *p_hwfn, + struct phys_mem_desc *fw_overlay_mem); /* Ystorm flow control mode. Use enum fw_flow_ctrl_mode */ #define YSTORM_FLOW_CONTROL_MODE_OFFSET (IRO[0].base) diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index 6fdf9ab98685..2f1049b0b93a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -1572,3 +1572,144 @@ void qed_set_rdma_error_level(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, ram_addr, assert_level[storm_id]); } } + +#define PHYS_ADDR_DWORDS DIV_ROUND_UP(sizeof(dma_addr_t), 4) +#define OVERLAY_HDR_SIZE_DWORDS (sizeof(struct fw_overlay_buf_hdr) / 4) + +static u32 qed_get_overlay_addr_ram_addr(struct qed_hwfn *p_hwfn, u8 storm_id) +{ + switch (storm_id) { + case 0: + return TSEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + + TSTORM_OVERLAY_BUF_ADDR_OFFSET; + case 1: + return MSEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + + MSTORM_OVERLAY_BUF_ADDR_OFFSET; + case 2: + return USEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + + USTORM_OVERLAY_BUF_ADDR_OFFSET; + case 3: + return XSEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + + XSTORM_OVERLAY_BUF_ADDR_OFFSET; + case 4: + return YSEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + + YSTORM_OVERLAY_BUF_ADDR_OFFSET; + case 5: + return PSEM_REG_FAST_MEMORY + SEM_FAST_REG_INT_RAM + + PSTORM_OVERLAY_BUF_ADDR_OFFSET; + + default: + return 0; + } +} + +struct phys_mem_desc *qed_fw_overlay_mem_alloc(struct qed_hwfn *p_hwfn, + const u32 * const + fw_overlay_in_buf, + u32 buf_size_in_bytes) +{ + u32 buf_size = buf_size_in_bytes / sizeof(u32), buf_offset = 0; + struct phys_mem_desc *allocated_mem; + + if (!buf_size) + return NULL; + + allocated_mem = kcalloc(NUM_STORMS, sizeof(struct phys_mem_desc), + GFP_KERNEL); + if (!allocated_mem) + return NULL; + + memset(allocated_mem, 0, NUM_STORMS * sizeof(struct phys_mem_desc)); + + /* For each Storm, set physical address in RAM */ + while (buf_offset < buf_size) { + struct phys_mem_desc *storm_mem_desc; + struct fw_overlay_buf_hdr *hdr; + u32 storm_buf_size; + u8 storm_id; + + hdr = + (struct fw_overlay_buf_hdr *)&fw_overlay_in_buf[buf_offset]; + storm_buf_size = GET_FIELD(hdr->data, + FW_OVERLAY_BUF_HDR_BUF_SIZE); + storm_id = GET_FIELD(hdr->data, FW_OVERLAY_BUF_HDR_STORM_ID); + storm_mem_desc = allocated_mem + storm_id; + storm_mem_desc->size = storm_buf_size * sizeof(u32); + + /* Allocate physical memory for Storm's overlays buffer */ + storm_mem_desc->virt_addr = + dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + storm_mem_desc->size, + &storm_mem_desc->phys_addr, GFP_KERNEL); + if (!storm_mem_desc->virt_addr) + break; + + /* Skip overlays buffer header */ + buf_offset += OVERLAY_HDR_SIZE_DWORDS; + + /* Copy Storm's overlays buffer to allocated memory */ + memcpy(storm_mem_desc->virt_addr, + &fw_overlay_in_buf[buf_offset], storm_mem_desc->size); + + /* Advance to next Storm */ + buf_offset += storm_buf_size; + } + + /* If memory allocation has failed, free all allocated memory */ + if (buf_offset < buf_size) { + qed_fw_overlay_mem_free(p_hwfn, allocated_mem); + return NULL; + } + + return allocated_mem; +} + +void qed_fw_overlay_init_ram(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct phys_mem_desc *fw_overlay_mem) +{ + u8 storm_id; + + for (storm_id = 0; storm_id < NUM_STORMS; storm_id++) { + struct phys_mem_desc *storm_mem_desc = + (struct phys_mem_desc *)fw_overlay_mem + storm_id; + u32 ram_addr, i; + + /* Skip Storms with no FW overlays */ + if (!storm_mem_desc->virt_addr) + continue; + + /* Calculate overlay RAM GRC address of current PF */ + ram_addr = qed_get_overlay_addr_ram_addr(p_hwfn, storm_id) + + sizeof(dma_addr_t) * p_hwfn->rel_pf_id; + + /* Write Storm's overlay physical address to RAM */ + for (i = 0; i < PHYS_ADDR_DWORDS; i++, ram_addr += sizeof(u32)) + qed_wr(p_hwfn, p_ptt, ram_addr, + ((u32 *)&storm_mem_desc->phys_addr)[i]); + } +} + +void qed_fw_overlay_mem_free(struct qed_hwfn *p_hwfn, + struct phys_mem_desc *fw_overlay_mem) +{ + u8 storm_id; + + if (!fw_overlay_mem) + return; + + for (storm_id = 0; storm_id < NUM_STORMS; storm_id++) { + struct phys_mem_desc *storm_mem_desc = + (struct phys_mem_desc *)fw_overlay_mem + storm_id; + + /* Free Storm's physical memory */ + if (storm_mem_desc->virt_addr) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + storm_mem_desc->size, + storm_mem_desc->virt_addr, + storm_mem_desc->phys_addr); + } + + /* Free allocated virtual memory */ + kfree(fw_overlay_mem); +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c index 5ca117a8734a..36f998c89e74 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -589,5 +589,10 @@ int qed_init_fw_data(struct qed_dev *cdev, const u8 *data) len = buf_hdr[BIN_BUF_INIT_CMD].length; fw->init_ops_size = len / sizeof(struct init_raw_op); + offset = buf_hdr[BIN_BUF_INIT_OVERLAYS].offset; + fw->fw_overlays = (u32 *)(data + offset); + len = buf_hdr[BIN_BUF_INIT_OVERLAYS].length; + fw->fw_overlays_len = len; + return 0; } -- cgit v1.2.3-59-g8ed1b