From eb8e81ad0d2ec50480882269da682d20a573a8cd Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Wed, 29 Mar 2017 13:36:56 -0700 Subject: [PATCH] net/qede/base: multi-Txq support on same queue-zone for VFs A step toward having multi-Txq support on same queue-zone for VFs. This change takes care of: - VFs assume a single CID per-queue, where queue X receives CID X. Switch to a model similar to that of PF - I.e., Use different CIDs for Rx/Tx, and use mapping to acquire/release those. Each VF currently will have 32 CIDs available for it [for its possible 16 Rx & 16 Tx queues]. - To retain the same interface for PFs/VFs when initializing queues, the base driver would have to retain a unique number per-each queue that would be communicated in some extended TLV [current TLV interface allows the PF to send only the queue-id]. The new TLV isn't part of the current change but base driver would now start adding such unique keys internally to queue_cids. This would also force us to start having alloc/setup/free for L2 [we've refrained from doing so until now] The limit would be no-more than 64 queues per qzone [This could be changed if needed, but hopefully no one needs so many queues] - In IOV, Add infrastructure for up to 64 qids per-qzone, although at the moment hard-code '0' for Rx and '1' for Tx [Since VF still isn't communicating via new TLV which index to associate with a given queue in its queue-zone]. Signed-off-by: Rasesh Mody --- drivers/net/qede/base/ecore.h | 4 + drivers/net/qede/base/ecore_cxt.c | 230 +++++++++++---- drivers/net/qede/base/ecore_cxt.h | 53 +++- drivers/net/qede/base/ecore_cxt_api.h | 13 - drivers/net/qede/base/ecore_dev.c | 24 +- drivers/net/qede/base/ecore_l2.c | 248 +++++++++++++++-- drivers/net/qede/base/ecore_l2.h | 46 ++- drivers/net/qede/base/ecore_sriov.c | 387 ++++++++++++++++++-------- drivers/net/qede/base/ecore_sriov.h | 17 +- drivers/net/qede/base/ecore_vf.c | 6 + drivers/net/qede/base/ecore_vf_api.h | 9 + 11 files changed, 794 insertions(+), 243 deletions(-) diff --git a/drivers/net/qede/base/ecore.h b/drivers/net/qede/base/ecore.h index 7379b3ff25..fab8193b93 100644 --- a/drivers/net/qede/base/ecore.h +++ b/drivers/net/qede/base/ecore.h @@ -200,6 +200,7 @@ struct ecore_cxt_mngr; struct ecore_dma_mem; struct ecore_sb_sp_info; struct ecore_ll2_info; +struct ecore_l2_info; struct ecore_igu_info; struct ecore_mcp_info; struct ecore_dcbx_info; @@ -598,6 +599,9 @@ struct ecore_hwfn { /* If one of the following is set then EDPM shouldn't be used */ u8 dcbx_no_edpm; u8 db_bar_no_edpm; + + /* L2-related */ + struct ecore_l2_info *p_l2_info; }; #ifndef __EXTRACT__LINUX__ diff --git a/drivers/net/qede/base/ecore_cxt.c b/drivers/net/qede/base/ecore_cxt.c index 691d63827d..f7b56728f8 100644 --- a/drivers/net/qede/base/ecore_cxt.c +++ b/drivers/net/qede/base/ecore_cxt.c @@ -8,6 +8,7 @@ #include "bcm_osal.h" #include "reg_addr.h" +#include "common_hsi.h" #include "ecore_hsi_common.h" #include "ecore_hsi_eth.h" #include "ecore_rt_defs.h" @@ -101,7 +102,6 @@ struct ecore_tid_seg { struct ecore_conn_type_cfg { u32 cid_count; - u32 cid_start; u32 cids_per_vf; struct ecore_tid_seg tid_seg[TASK_SEGMENTS]; }; @@ -197,6 +197,9 @@ struct ecore_cxt_mngr { /* Acquired CIDs */ struct ecore_cid_acquired_map acquired[MAX_CONN_TYPES]; + /* TBD - do we want this allocated to reserve space? */ + struct ecore_cid_acquired_map + acquired_vf[MAX_CONN_TYPES][COMMON_MAX_NUM_VFS]; /* ILT shadow table */ struct ecore_dma_mem *ilt_shadow; @@ -1015,44 +1018,75 @@ ilt_shadow_fail: static void ecore_cid_map_free(struct ecore_hwfn *p_hwfn) { struct ecore_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - u32 type; + u32 type, vf; for (type = 0; type < MAX_CONN_TYPES; type++) { OSAL_FREE(p_hwfn->p_dev, p_mngr->acquired[type].cid_map); p_mngr->acquired[type].max_count = 0; p_mngr->acquired[type].start_cid = 0; + + for (vf = 0; vf < COMMON_MAX_NUM_VFS; vf++) { + OSAL_FREE(p_hwfn->p_dev, + p_mngr->acquired_vf[type][vf].cid_map); + p_mngr->acquired_vf[type][vf].max_count = 0; + p_mngr->acquired_vf[type][vf].start_cid = 0; + } } } +static enum _ecore_status_t +ecore_cid_map_alloc_single(struct ecore_hwfn *p_hwfn, u32 type, + u32 cid_start, u32 cid_count, + struct ecore_cid_acquired_map *p_map) +{ + u32 size; + + if (!cid_count) + return ECORE_SUCCESS; + + size = MAP_WORD_SIZE * DIV_ROUND_UP(cid_count, BITS_PER_MAP_WORD); + p_map->cid_map = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, size); + if (p_map->cid_map == OSAL_NULL) + return ECORE_NOMEM; + + p_map->max_count = cid_count; + p_map->start_cid = cid_start; + + DP_VERBOSE(p_hwfn, ECORE_MSG_CXT, + "Type %08x start: %08x count %08x\n", + type, p_map->start_cid, p_map->max_count); + + return ECORE_SUCCESS; +} + static enum _ecore_status_t ecore_cid_map_alloc(struct ecore_hwfn *p_hwfn) { struct ecore_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - u32 start_cid = 0; - u32 type; + u32 start_cid = 0, vf_start_cid = 0; + u32 type, vf; for (type = 0; type < MAX_CONN_TYPES; type++) { - u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; - u32 size; - - if (cid_cnt == 0) - continue; + struct ecore_conn_type_cfg *p_cfg = &p_mngr->conn_cfg[type]; + struct ecore_cid_acquired_map *p_map; - size = MAP_WORD_SIZE * DIV_ROUND_UP(cid_cnt, BITS_PER_MAP_WORD); - p_mngr->acquired[type].cid_map = OSAL_ZALLOC(p_hwfn->p_dev, - GFP_KERNEL, size); - if (!p_mngr->acquired[type].cid_map) + /* Handle PF maps */ + p_map = &p_mngr->acquired[type]; + if (ecore_cid_map_alloc_single(p_hwfn, type, start_cid, + p_cfg->cid_count, p_map)) goto cid_map_fail; - p_mngr->acquired[type].max_count = cid_cnt; - p_mngr->acquired[type].start_cid = start_cid; - - p_hwfn->p_cxt_mngr->conn_cfg[type].cid_start = start_cid; + /* Handle VF maps */ + for (vf = 0; vf < COMMON_MAX_NUM_VFS; vf++) { + p_map = &p_mngr->acquired_vf[type][vf]; + if (ecore_cid_map_alloc_single(p_hwfn, type, + vf_start_cid, + p_cfg->cids_per_vf, + p_map)) + goto cid_map_fail; + } - DP_VERBOSE(p_hwfn, ECORE_MSG_CXT, - "Type %08x start: %08x count %08x\n", - type, p_mngr->acquired[type].start_cid, - p_mngr->acquired[type].max_count); - start_cid += cid_cnt; + start_cid += p_cfg->cid_count; + vf_start_cid += p_cfg->cids_per_vf; } return ECORE_SUCCESS; @@ -1171,18 +1205,34 @@ void ecore_cxt_mngr_free(struct ecore_hwfn *p_hwfn) void ecore_cxt_mngr_setup(struct ecore_hwfn *p_hwfn) { struct ecore_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct ecore_cid_acquired_map *p_map; + struct ecore_conn_type_cfg *p_cfg; int type; + u32 len; /* Reset acquired cids */ for (type = 0; type < MAX_CONN_TYPES; type++) { - u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; - u32 i; + u32 vf; + + p_cfg = &p_mngr->conn_cfg[type]; + if (p_cfg->cid_count) { + p_map = &p_mngr->acquired[type]; + len = DIV_ROUND_UP(p_map->max_count, + BITS_PER_MAP_WORD) * + MAP_WORD_SIZE; + OSAL_MEM_ZERO(p_map->cid_map, len); + } - if (cid_cnt == 0) + if (!p_cfg->cids_per_vf) continue; - for (i = 0; i < DIV_ROUND_UP(cid_cnt, BITS_PER_MAP_WORD); i++) - p_mngr->acquired[type].cid_map[i] = 0; + for (vf = 0; vf < COMMON_MAX_NUM_VFS; vf++) { + p_map = &p_mngr->acquired_vf[type][vf]; + len = DIV_ROUND_UP(p_map->max_count, + BITS_PER_MAP_WORD) * + MAP_WORD_SIZE; + OSAL_MEM_ZERO(p_map->cid_map, len); + } } } @@ -1723,93 +1773,150 @@ void ecore_cxt_hw_init_pf(struct ecore_hwfn *p_hwfn) ecore_prs_init_pf(p_hwfn); } -enum _ecore_status_t ecore_cxt_acquire_cid(struct ecore_hwfn *p_hwfn, - enum protocol_type type, u32 *p_cid) +enum _ecore_status_t _ecore_cxt_acquire_cid(struct ecore_hwfn *p_hwfn, + enum protocol_type type, + u32 *p_cid, u8 vfid) { struct ecore_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct ecore_cid_acquired_map *p_map; u32 rel_cid; - if (type >= MAX_CONN_TYPES || !p_mngr->acquired[type].cid_map) { + if (type >= MAX_CONN_TYPES) { DP_NOTICE(p_hwfn, true, "Invalid protocol type %d", type); return ECORE_INVAL; } - rel_cid = OSAL_FIND_FIRST_ZERO_BIT(p_mngr->acquired[type].cid_map, - p_mngr->acquired[type].max_count); + if (vfid >= COMMON_MAX_NUM_VFS && vfid != ECORE_CXT_PF_CID) { + DP_NOTICE(p_hwfn, true, "VF [%02x] is out of range\n", vfid); + return ECORE_INVAL; + } + + /* Determine the right map to take this CID from */ + if (vfid == ECORE_CXT_PF_CID) + p_map = &p_mngr->acquired[type]; + else + p_map = &p_mngr->acquired_vf[type][vfid]; - if (rel_cid >= p_mngr->acquired[type].max_count) { + if (p_map->cid_map == OSAL_NULL) { + DP_NOTICE(p_hwfn, true, "Invalid protocol type %d", type); + return ECORE_INVAL; + } + + rel_cid = OSAL_FIND_FIRST_ZERO_BIT(p_map->cid_map, + p_map->max_count); + + if (rel_cid >= p_map->max_count) { DP_NOTICE(p_hwfn, false, "no CID available for protocol %d\n", type); return ECORE_NORESOURCES; } - OSAL_SET_BIT(rel_cid, p_mngr->acquired[type].cid_map); + OSAL_SET_BIT(rel_cid, p_map->cid_map); - *p_cid = rel_cid + p_mngr->acquired[type].start_cid; + *p_cid = rel_cid + p_map->start_cid; + + DP_VERBOSE(p_hwfn, ECORE_MSG_CXT, + "Acquired cid 0x%08x [rel. %08x] vfid %02x type %d\n", + *p_cid, rel_cid, vfid, type); return ECORE_SUCCESS; } +enum _ecore_status_t ecore_cxt_acquire_cid(struct ecore_hwfn *p_hwfn, + enum protocol_type type, + u32 *p_cid) +{ + return _ecore_cxt_acquire_cid(p_hwfn, type, p_cid, ECORE_CXT_PF_CID); +} + static bool ecore_cxt_test_cid_acquired(struct ecore_hwfn *p_hwfn, - u32 cid, enum protocol_type *p_type) + u32 cid, u8 vfid, + enum protocol_type *p_type, + struct ecore_cid_acquired_map **pp_map) { struct ecore_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - struct ecore_cid_acquired_map *p_map; - enum protocol_type p; u32 rel_cid; /* Iterate over protocols and find matching cid range */ - for (p = 0; p < MAX_CONN_TYPES; p++) { - p_map = &p_mngr->acquired[p]; + for (*p_type = 0; *p_type < MAX_CONN_TYPES; (*p_type)++) { + if (vfid == ECORE_CXT_PF_CID) + *pp_map = &p_mngr->acquired[*p_type]; + else + *pp_map = &p_mngr->acquired_vf[*p_type][vfid]; - if (!p_map->cid_map) + if (!((*pp_map)->cid_map)) continue; - if (cid >= p_map->start_cid && - cid < p_map->start_cid + p_map->max_count) { + if (cid >= (*pp_map)->start_cid && + cid < (*pp_map)->start_cid + (*pp_map)->max_count) { break; } } - *p_type = p; - - if (p == MAX_CONN_TYPES) { - DP_NOTICE(p_hwfn, true, "Invalid CID %d", cid); - return false; + if (*p_type == MAX_CONN_TYPES) { + DP_NOTICE(p_hwfn, true, "Invalid CID %d vfid %02x", cid, vfid); + goto fail; } - rel_cid = cid - p_map->start_cid; - if (!OSAL_TEST_BIT(rel_cid, p_map->cid_map)) { - DP_NOTICE(p_hwfn, true, "CID %d not acquired", cid); - return false; + + rel_cid = cid - (*pp_map)->start_cid; + if (!OSAL_TEST_BIT(rel_cid, (*pp_map)->cid_map)) { + DP_NOTICE(p_hwfn, true, + "CID %d [vifd %02x] not acquired", cid, vfid); + goto fail; } + return true; +fail: + *p_type = MAX_CONN_TYPES; + *pp_map = OSAL_NULL; + return false; } -void ecore_cxt_release_cid(struct ecore_hwfn *p_hwfn, u32 cid) +void _ecore_cxt_release_cid(struct ecore_hwfn *p_hwfn, u32 cid, u8 vfid) { - struct ecore_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct ecore_cid_acquired_map *p_map = OSAL_NULL; enum protocol_type type; bool b_acquired; u32 rel_cid; + if (vfid != ECORE_CXT_PF_CID && vfid > COMMON_MAX_NUM_VFS) { + DP_NOTICE(p_hwfn, true, + "Trying to return incorrect CID belonging to VF %02x\n", + vfid); + return; + } + /* Test acquired and find matching per-protocol map */ - b_acquired = ecore_cxt_test_cid_acquired(p_hwfn, cid, &type); + b_acquired = ecore_cxt_test_cid_acquired(p_hwfn, cid, vfid, + &type, &p_map); if (!b_acquired) return; - rel_cid = cid - p_mngr->acquired[type].start_cid; - OSAL_CLEAR_BIT(rel_cid, p_mngr->acquired[type].cid_map); + rel_cid = cid - p_map->start_cid; + OSAL_CLEAR_BIT(rel_cid, p_map->cid_map); + + DP_VERBOSE(p_hwfn, ECORE_MSG_CXT, + "Released CID 0x%08x [rel. %08x] vfid %02x type %d\n", + cid, rel_cid, vfid, type); +} + +void ecore_cxt_release_cid(struct ecore_hwfn *p_hwfn, u32 cid) +{ + _ecore_cxt_release_cid(p_hwfn, cid, ECORE_CXT_PF_CID); } enum _ecore_status_t ecore_cxt_get_cid_info(struct ecore_hwfn *p_hwfn, struct ecore_cxt_info *p_info) { struct ecore_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct ecore_cid_acquired_map *p_map = OSAL_NULL; u32 conn_cxt_size, hw_p_size, cxts_per_p, line; enum protocol_type type; bool b_acquired; /* Test acquired and find matching per-protocol map */ - b_acquired = ecore_cxt_test_cid_acquired(p_hwfn, p_info->iid, &type); + b_acquired = ecore_cxt_test_cid_acquired(p_hwfn, p_info->iid, + ECORE_CXT_PF_CID, + &type, &p_map); if (!b_acquired) return ECORE_INVAL; @@ -1865,9 +1972,14 @@ enum _ecore_status_t ecore_cxt_set_pf_params(struct ecore_hwfn *p_hwfn) struct ecore_eth_pf_params *p_params = &p_hwfn->pf_params.eth_pf_params; + /* TODO - we probably want to add VF number to the PF + * params; + * As of now, allocates 16 * 2 per-VF [to retain regular + * functionality]. + */ ecore_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH, - p_params->num_cons, 1); /* FIXME VF count... */ + p_params->num_cons, 32); break; } diff --git a/drivers/net/qede/base/ecore_cxt.h b/drivers/net/qede/base/ecore_cxt.h index 5379d7bcde..1128051a1b 100644 --- a/drivers/net/qede/base/ecore_cxt.h +++ b/drivers/net/qede/base/ecore_cxt.h @@ -130,14 +130,53 @@ void ecore_qm_init_pf(struct ecore_hwfn *p_hwfn); enum _ecore_status_t ecore_qm_reconf(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt); +#define ECORE_CXT_PF_CID (0xff) + +/** + * @brief ecore_cxt_release - Release a cid + * + * @param p_hwfn + * @param cid + */ +void ecore_cxt_release_cid(struct ecore_hwfn *p_hwfn, u32 cid); + /** -* @brief ecore_cxt_release - Release a cid -* -* @param p_hwfn -* @param cid -*/ -void ecore_cxt_release_cid(struct ecore_hwfn *p_hwfn, - u32 cid); + * @brief ecore_cxt_release - Release a cid belonging to a vf-queue + * + * @param p_hwfn + * @param cid + * @param vfid - engine relative index. ECORE_CXT_PF_CID if belongs to PF + */ +void _ecore_cxt_release_cid(struct ecore_hwfn *p_hwfn, + u32 cid, u8 vfid); + +/** + * @brief ecore_cxt_acquire - Acquire a new cid of a specific protocol type + * + * @param p_hwfn + * @param type + * @param p_cid + * + * @return enum _ecore_status_t + */ +enum _ecore_status_t ecore_cxt_acquire_cid(struct ecore_hwfn *p_hwfn, + enum protocol_type type, + u32 *p_cid); + +/** + * @brief _ecore_cxt_acquire - Acquire a new cid of a specific protocol type + * for a vf-queue + * + * @param p_hwfn + * @param type + * @param p_cid + * @param vfid - engine relative index. ECORE_CXT_PF_CID if belongs to PF + * + * @return enum _ecore_status_t + */ +enum _ecore_status_t _ecore_cxt_acquire_cid(struct ecore_hwfn *p_hwfn, + enum protocol_type type, + u32 *p_cid, u8 vfid); /** * @brief ecore_cxt_get_tid_mem_info - function checks if the diff --git a/drivers/net/qede/base/ecore_cxt_api.h b/drivers/net/qede/base/ecore_cxt_api.h index 6a50412a61..f154e0dc88 100644 --- a/drivers/net/qede/base/ecore_cxt_api.h +++ b/drivers/net/qede/base/ecore_cxt_api.h @@ -25,19 +25,6 @@ struct ecore_tid_mem { u8 *blocks[MAX_TID_BLOCKS]; /* 4K */ }; -/** -* @brief ecore_cxt_acquire - Acquire a new cid of a specific protocol type -* -* @param p_hwfn -* @param type -* @param p_cid -* -* @return enum _ecore_status_t -*/ -enum _ecore_status_t ecore_cxt_acquire_cid(struct ecore_hwfn *p_hwfn, - enum protocol_type type, - u32 *p_cid); - /** * @brief ecoreo_cid_get_cxt_info - Returns the context info for a specific cid * diff --git a/drivers/net/qede/base/ecore_dev.c b/drivers/net/qede/base/ecore_dev.c index e58405861b..2a621f7879 100644 --- a/drivers/net/qede/base/ecore_dev.c +++ b/drivers/net/qede/base/ecore_dev.c @@ -146,8 +146,11 @@ void ecore_resc_free(struct ecore_dev *p_dev) { int i; - if (IS_VF(p_dev)) + if (IS_VF(p_dev)) { + for_each_hwfn(p_dev, i) + ecore_l2_free(&p_dev->hwfns[i]); return; + } OSAL_FREE(p_dev, p_dev->fw_data); @@ -163,6 +166,7 @@ void ecore_resc_free(struct ecore_dev *p_dev) ecore_consq_free(p_hwfn); ecore_int_free(p_hwfn); ecore_iov_free(p_hwfn); + ecore_l2_free(p_hwfn); ecore_dmae_info_free(p_hwfn); ecore_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info); /* @@@TBD Flush work-queue ? */ @@ -839,8 +843,14 @@ enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev) enum _ecore_status_t rc = ECORE_SUCCESS; int i; - if (IS_VF(p_dev)) + if (IS_VF(p_dev)) { + for_each_hwfn(p_dev, i) { + rc = ecore_l2_alloc(&p_dev->hwfns[i]); + if (rc != ECORE_SUCCESS) + return rc; + } return rc; + } p_dev->fw_data = OSAL_ZALLOC(p_dev, GFP_KERNEL, sizeof(*p_dev->fw_data)); @@ -961,6 +971,10 @@ enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev) if (rc) goto alloc_err; + rc = ecore_l2_alloc(p_hwfn); + if (rc != ECORE_SUCCESS) + goto alloc_err; + /* DMA info initialization */ rc = ecore_dmae_info_alloc(p_hwfn); if (rc) { @@ -999,8 +1013,11 @@ void ecore_resc_setup(struct ecore_dev *p_dev) { int i; - if (IS_VF(p_dev)) + if (IS_VF(p_dev)) { + for_each_hwfn(p_dev, i) + ecore_l2_setup(&p_dev->hwfns[i]); return; + } for_each_hwfn(p_dev, i) { struct ecore_hwfn *p_hwfn = &p_dev->hwfns[i]; @@ -1018,6 +1035,7 @@ void ecore_resc_setup(struct ecore_dev *p_dev) ecore_int_setup(p_hwfn, p_hwfn->p_main_ptt); + ecore_l2_setup(p_hwfn); ecore_iov_setup(p_hwfn, p_hwfn->p_main_ptt); } } diff --git a/drivers/net/qede/base/ecore_l2.c b/drivers/net/qede/base/ecore_l2.c index 4d26e19979..adb5e47073 100644 --- a/drivers/net/qede/base/ecore_l2.c +++ b/drivers/net/qede/base/ecore_l2.c @@ -29,24 +29,172 @@ #define ECORE_MAX_SGES_NUM 16 #define CRC32_POLY 0x1edc6f41 +struct ecore_l2_info { + u32 queues; + unsigned long **pp_qid_usage; + + /* The lock is meant to synchronize access to the qid usage */ + osal_mutex_t lock; +}; + +enum _ecore_status_t ecore_l2_alloc(struct ecore_hwfn *p_hwfn) +{ + struct ecore_l2_info *p_l2_info; + unsigned long **pp_qids; + u32 i; + + if (!ECORE_IS_L2_PERSONALITY(p_hwfn)) + return ECORE_SUCCESS; + + p_l2_info = OSAL_VZALLOC(p_hwfn->p_dev, sizeof(*p_l2_info)); + if (!p_l2_info) + return ECORE_NOMEM; + p_hwfn->p_l2_info = p_l2_info; + + if (IS_PF(p_hwfn->p_dev)) { + p_l2_info->queues = RESC_NUM(p_hwfn, ECORE_L2_QUEUE); + } else { + u8 rx = 0, tx = 0; + + ecore_vf_get_num_rxqs(p_hwfn, &rx); + ecore_vf_get_num_txqs(p_hwfn, &tx); + + p_l2_info->queues = (u32)OSAL_MAX_T(u8, rx, tx); + } + + pp_qids = OSAL_VZALLOC(p_hwfn->p_dev, + sizeof(unsigned long *) * + p_l2_info->queues); + if (pp_qids == OSAL_NULL) + return ECORE_NOMEM; + p_l2_info->pp_qid_usage = pp_qids; + + for (i = 0; i < p_l2_info->queues; i++) { + pp_qids[i] = OSAL_VZALLOC(p_hwfn->p_dev, + MAX_QUEUES_PER_QZONE / 8); + if (pp_qids[i] == OSAL_NULL) + return ECORE_NOMEM; + } + +#ifdef CONFIG_ECORE_LOCK_ALLOC + OSAL_MUTEX_ALLOC(p_hwfn, &p_l2_info->lock); +#endif + + return ECORE_SUCCESS; +} + +void ecore_l2_setup(struct ecore_hwfn *p_hwfn) +{ + if (!ECORE_IS_L2_PERSONALITY(p_hwfn)) + return; + + OSAL_MUTEX_INIT(&p_hwfn->p_l2_info->lock); +} + +void ecore_l2_free(struct ecore_hwfn *p_hwfn) +{ + u32 i; + + if (!ECORE_IS_L2_PERSONALITY(p_hwfn)) + return; + + if (p_hwfn->p_l2_info == OSAL_NULL) + return; + + if (p_hwfn->p_l2_info->pp_qid_usage == OSAL_NULL) + goto out_l2_info; + + /* Free until hit first uninitialized entry */ + for (i = 0; i < p_hwfn->p_l2_info->queues; i++) { + if (p_hwfn->p_l2_info->pp_qid_usage[i] == OSAL_NULL) + break; + OSAL_VFREE(p_hwfn->p_dev, + p_hwfn->p_l2_info->pp_qid_usage[i]); + } + +#ifdef CONFIG_ECORE_LOCK_ALLOC + /* Lock is last to initialize, if everything else was */ + if (i == p_hwfn->p_l2_info->queues) + OSAL_MUTEX_DEALLOC(&p_hwfn->p_l2_info->lock); +#endif + + OSAL_VFREE(p_hwfn->p_dev, p_hwfn->p_l2_info->pp_qid_usage); + +out_l2_info: + OSAL_VFREE(p_hwfn->p_dev, p_hwfn->p_l2_info); + p_hwfn->p_l2_info = OSAL_NULL; +} + +/* TODO - we'll need locking around these... */ +static bool ecore_eth_queue_qid_usage_add(struct ecore_hwfn *p_hwfn, + struct ecore_queue_cid *p_cid) +{ + struct ecore_l2_info *p_l2_info = p_hwfn->p_l2_info; + u16 queue_id = p_cid->rel.queue_id; + bool b_rc = true; + u8 first; + + OSAL_MUTEX_ACQUIRE(&p_l2_info->lock); + + if (queue_id > p_l2_info->queues) { + DP_NOTICE(p_hwfn, true, + "Requested to increase usage for qzone %04x out of %08x\n", + queue_id, p_l2_info->queues); + b_rc = false; + goto out; + } + + first = (u8)OSAL_FIND_FIRST_ZERO_BIT(p_l2_info->pp_qid_usage[queue_id], + MAX_QUEUES_PER_QZONE); + if (first >= MAX_QUEUES_PER_QZONE) { + b_rc = false; + goto out; + } + + OSAL_SET_BIT(first, p_l2_info->pp_qid_usage[queue_id]); + p_cid->qid_usage_idx = first; + +out: + OSAL_MUTEX_RELEASE(&p_l2_info->lock); + return b_rc; +} + +static void ecore_eth_queue_qid_usage_del(struct ecore_hwfn *p_hwfn, + struct ecore_queue_cid *p_cid) +{ + OSAL_MUTEX_ACQUIRE(&p_hwfn->p_l2_info->lock); + + OSAL_CLEAR_BIT(p_cid->qid_usage_idx, + p_hwfn->p_l2_info->pp_qid_usage[p_cid->rel.queue_id]); + + OSAL_MUTEX_RELEASE(&p_hwfn->p_l2_info->lock); +} + void ecore_eth_queue_cid_release(struct ecore_hwfn *p_hwfn, struct ecore_queue_cid *p_cid) { + /* For VF-queues, stuff is a bit complicated as: + * - They always maintain the qid_usage on their own. + * - In legacy mode, they also maintain their CIDs. + */ + /* VFs' CIDs are 0-based in PF-view, and uninitialized on VF */ - if (!p_cid->is_vf && IS_PF(p_hwfn->p_dev)) - ecore_cxt_release_cid(p_hwfn, p_cid->cid); + if (IS_PF(p_hwfn->p_dev) && !p_cid->b_legacy_vf) + _ecore_cxt_release_cid(p_hwfn, p_cid->cid, p_cid->vfid); + if (!p_cid->b_legacy_vf) + ecore_eth_queue_qid_usage_del(p_hwfn, p_cid); OSAL_VFREE(p_hwfn->p_dev, p_cid); } /* The internal is only meant to be directly called by PFs initializeing CIDs * for their VFs. */ -struct ecore_queue_cid * +static struct ecore_queue_cid * _ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, - u16 opaque_fid, u32 cid, u8 vf_qid, - struct ecore_queue_start_common_params *p_params) + u16 opaque_fid, u32 cid, + struct ecore_queue_start_common_params *p_params, + struct ecore_queue_cid_vf_params *p_vf_params) { - bool b_is_same = (p_hwfn->hw_info.opaque_fid == opaque_fid); struct ecore_queue_cid *p_cid; enum _ecore_status_t rc; @@ -56,13 +204,22 @@ _ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, p_cid->opaque_fid = opaque_fid; p_cid->cid = cid; - p_cid->vf_qid = vf_qid; p_cid->rel = *p_params; p_cid->p_owner = p_hwfn; + /* Fill-in bits related to VFs' queues if information was provided */ + if (p_vf_params != OSAL_NULL) { + p_cid->vfid = p_vf_params->vfid; + p_cid->vf_qid = p_vf_params->vf_qid; + p_cid->b_legacy_vf = p_vf_params->b_legacy; + } else { + p_cid->vfid = ECORE_QUEUE_CID_PF; + } + /* Don't try calculating the absolute indices for VFs */ if (IS_VF(p_hwfn->p_dev)) { p_cid->abs = p_cid->rel; + goto out; } @@ -82,7 +239,7 @@ _ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, /* In case of a PF configuring its VF's queues, the stats-id is already * absolute [since there's a single index that's suitable per-VF]. */ - if (b_is_same) { + if (p_cid->vfid == ECORE_QUEUE_CID_PF) { rc = ecore_fw_vport(p_hwfn, p_cid->rel.stats_id, &p_cid->abs.stats_id); if (rc != ECORE_SUCCESS) @@ -95,17 +252,23 @@ _ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, p_cid->abs.sb = p_cid->rel.sb; p_cid->abs.sb_idx = p_cid->rel.sb_idx; - /* This is tricky - we're actually interested in whehter this is a PF - * entry meant for the VF. - */ - if (!b_is_same) - p_cid->is_vf = true; out: + /* VF-images have provided the qid_usage_idx on their own. + * Otherwise, we need to allocate a unique one. + */ + if (!p_vf_params) { + if (!ecore_eth_queue_qid_usage_add(p_hwfn, p_cid)) + goto fail; + } else { + p_cid->qid_usage_idx = p_vf_params->qid_usage_idx; + } + DP_VERBOSE(p_hwfn, ECORE_MSG_SP, - "opaque_fid: %04x CID %08x vport %02x [%02x] qzone %04x [%04x] stats %02x [%02x] SB %04x PI %02x\n", + "opaque_fid: %04x CID %08x vport %02x [%02x] qzone %04x.%02x [%04x] stats %02x [%02x] SB %04x PI %02x\n", p_cid->opaque_fid, p_cid->cid, p_cid->rel.vport_id, p_cid->abs.vport_id, - p_cid->rel.queue_id, p_cid->abs.queue_id, + p_cid->rel.queue_id, p_cid->qid_usage_idx, + p_cid->abs.queue_id, p_cid->rel.stats_id, p_cid->abs.stats_id, p_cid->abs.sb, p_cid->abs.sb_idx); @@ -116,33 +279,56 @@ fail: return OSAL_NULL; } -static struct ecore_queue_cid * -ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, - u16 opaque_fid, - struct ecore_queue_start_common_params *p_params) +struct ecore_queue_cid * +ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, u16 opaque_fid, + struct ecore_queue_start_common_params *p_params, + struct ecore_queue_cid_vf_params *p_vf_params) { struct ecore_queue_cid *p_cid; + u8 vfid = ECORE_CXT_PF_CID; + bool b_legacy_vf = false; u32 cid = 0; + /* In case of legacy VFs, The CID can be derived from the additional + * VF parameters - the VF assumes queue X uses CID X, so we can simply + * use the vf_qid for this purpose as well. + */ + if (p_vf_params) { + vfid = p_vf_params->vfid; + + if (p_vf_params->b_legacy) { + b_legacy_vf = true; + cid = p_vf_params->vf_qid; + } + } + /* Get a unique firmware CID for this queue, in case it's a PF. * VF's don't need a CID as the queue configuration will be done * by PF. */ - if (IS_PF(p_hwfn->p_dev)) { - if (ecore_cxt_acquire_cid(p_hwfn, PROTOCOLID_ETH, - &cid) != ECORE_SUCCESS) { + if (IS_PF(p_hwfn->p_dev) && !b_legacy_vf) { + if (_ecore_cxt_acquire_cid(p_hwfn, PROTOCOLID_ETH, + &cid, vfid) != ECORE_SUCCESS) { DP_NOTICE(p_hwfn, true, "Failed to acquire cid\n"); return OSAL_NULL; } } - p_cid = _ecore_eth_queue_to_cid(p_hwfn, opaque_fid, cid, 0, p_params); - if ((p_cid == OSAL_NULL) && IS_PF(p_hwfn->p_dev)) - ecore_cxt_release_cid(p_hwfn, cid); + p_cid = _ecore_eth_queue_to_cid(p_hwfn, opaque_fid, cid, + p_params, p_vf_params); + if ((p_cid == OSAL_NULL) && IS_PF(p_hwfn->p_dev) && !b_legacy_vf) + _ecore_cxt_release_cid(p_hwfn, cid, vfid); return p_cid; } +static struct ecore_queue_cid * +ecore_eth_queue_to_cid_pf(struct ecore_hwfn *p_hwfn, u16 opaque_fid, + struct ecore_queue_start_common_params *p_params) +{ + return ecore_eth_queue_to_cid(p_hwfn, opaque_fid, p_params, OSAL_NULL); +} + enum _ecore_status_t ecore_sp_eth_vport_start(struct ecore_hwfn *p_hwfn, struct ecore_sp_vport_start_params *p_params) @@ -741,7 +927,7 @@ ecore_eth_rxq_start_ramrod(struct ecore_hwfn *p_hwfn, p_ramrod->num_of_pbl_pages = OSAL_CPU_TO_LE16(cqe_pbl_size); DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, cqe_pbl_addr); - if (p_cid->is_vf) { + if (p_cid->vfid != ECORE_QUEUE_CID_PF) { p_ramrod->vf_rx_prod_index = p_cid->vf_qid; DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "Queue%s is meant for VF rxq[%02x]\n", @@ -793,7 +979,7 @@ ecore_eth_rx_queue_start(struct ecore_hwfn *p_hwfn, enum _ecore_status_t rc; /* Allocate a CID for the queue */ - p_cid = ecore_eth_queue_to_cid(p_hwfn, opaque_fid, p_params); + p_cid = ecore_eth_queue_to_cid_pf(p_hwfn, opaque_fid, p_params); if (p_cid == OSAL_NULL) return ECORE_NOMEM; @@ -905,9 +1091,11 @@ ecore_eth_pf_rx_queue_stop(struct ecore_hwfn *p_hwfn, /* Cleaning the queue requires the completion to arrive there. * In addition, VFs require the answer to come as eqe to PF. */ - p_ramrod->complete_cqe_flg = (!p_cid->is_vf && !b_eq_completion_only) || + p_ramrod->complete_cqe_flg = ((p_cid->vfid == ECORE_QUEUE_CID_PF) && + !b_eq_completion_only) || b_cqe_completion; - p_ramrod->complete_event_flg = p_cid->is_vf || b_eq_completion_only; + p_ramrod->complete_event_flg = (p_cid->vfid != ECORE_QUEUE_CID_PF) || + b_eq_completion_only; return ecore_spq_post(p_hwfn, p_ent, OSAL_NULL); } @@ -1007,7 +1195,7 @@ ecore_eth_tx_queue_start(struct ecore_hwfn *p_hwfn, u16 opaque_fid, struct ecore_queue_cid *p_cid; enum _ecore_status_t rc; - p_cid = ecore_eth_queue_to_cid(p_hwfn, opaque_fid, p_params); + p_cid = ecore_eth_queue_to_cid_pf(p_hwfn, opaque_fid, p_params); if (p_cid == OSAL_NULL) return ECORE_INVAL; diff --git a/drivers/net/qede/base/ecore_l2.h b/drivers/net/qede/base/ecore_l2.h index 4b0ccb4cdc..3f86eac119 100644 --- a/drivers/net/qede/base/ecore_l2.h +++ b/drivers/net/qede/base/ecore_l2.h @@ -15,6 +15,34 @@ #include "ecore_spq.h" #include "ecore_l2_api.h" +#define MAX_QUEUES_PER_QZONE (sizeof(unsigned long) * 8) +#define ECORE_QUEUE_CID_PF (0xff) + +/* Additional parameters required for initialization of the queue_cid + * and are relevant only for a PF initializing one for its VFs. + */ +struct ecore_queue_cid_vf_params { + /* Should match the VF's relative index */ + u8 vfid; + + /* 0-based queue index. Should reflect the relative qzone the + * VF thinks is associated with it [in its range]. + */ + u8 vf_qid; + + /* Indicates a VF is legacy, making it differ in several things: + * - Producers would be placed in a different place. + * - Makes assumptions regarding the CIDs. + */ + bool b_legacy; + + /* For VFs, this index arrives via TLV to diffrentiate between + * different queues opened on the same qzone, and is passed + * [where the PF would have allocated it internally for its own]. + */ + u8 qid_usage_idx; +}; + struct ecore_queue_cid { /* 'Relative' is a relative term ;-). Usually the indices [not counting * SBs] would be PF-relative, but there are some cases where that isn't @@ -31,22 +59,32 @@ struct ecore_queue_cid { * Notice this is relevant on the *PF* queue-cid of its VF's queues, * and not on the VF itself. */ - bool is_vf; + u8 vfid; u8 vf_qid; + /* We need an additional index to diffrentiate between queues opened + * for same queue-zone, as VFs would have to communicate the info + * to the PF [otherwise PF has no way to diffrentiate]. + */ + u8 qid_usage_idx; + /* Legacy VFs might have Rx producer located elsewhere */ bool b_legacy_vf; struct ecore_hwfn *p_owner; }; +enum _ecore_status_t ecore_l2_alloc(struct ecore_hwfn *p_hwfn); +void ecore_l2_setup(struct ecore_hwfn *p_hwfn); +void ecore_l2_free(struct ecore_hwfn *p_hwfn); + void ecore_eth_queue_cid_release(struct ecore_hwfn *p_hwfn, struct ecore_queue_cid *p_cid); struct ecore_queue_cid * -_ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, - u16 opaque_fid, u32 cid, u8 vf_qid, - struct ecore_queue_start_common_params *p_params); +ecore_eth_queue_to_cid(struct ecore_hwfn *p_hwfn, u16 opaque_fid, + struct ecore_queue_start_common_params *p_params, + struct ecore_queue_cid_vf_params *p_vf_params); enum _ecore_status_t ecore_sp_eth_vport_start(struct ecore_hwfn *p_hwfn, diff --git a/drivers/net/qede/base/ecore_sriov.c b/drivers/net/qede/base/ecore_sriov.c index 532c492c40..39d3e88b93 100644 --- a/drivers/net/qede/base/ecore_sriov.c +++ b/drivers/net/qede/base/ecore_sriov.c @@ -192,28 +192,90 @@ struct ecore_vf_info *ecore_iov_get_vf_info(struct ecore_hwfn *p_hwfn, return vf; } +static struct ecore_queue_cid * +ecore_iov_get_vf_rx_queue_cid(struct ecore_hwfn *p_hwfn, + struct ecore_vf_info *p_vf, + struct ecore_vf_queue *p_queue) +{ + int i; + + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + if (p_queue->cids[i].p_cid && + !p_queue->cids[i].b_is_tx) + return p_queue->cids[i].p_cid; + } + + return OSAL_NULL; +} + +enum ecore_iov_validate_q_mode { + ECORE_IOV_VALIDATE_Q_NA, + ECORE_IOV_VALIDATE_Q_ENABLE, + ECORE_IOV_VALIDATE_Q_DISABLE, +}; + +static bool ecore_iov_validate_queue_mode(struct ecore_hwfn *p_hwfn, + struct ecore_vf_info *p_vf, + u16 qid, + enum ecore_iov_validate_q_mode mode, + bool b_is_tx) +{ + int i; + + if (mode == ECORE_IOV_VALIDATE_Q_NA) + return true; + + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + struct ecore_vf_queue_cid *p_qcid; + + p_qcid = &p_vf->vf_queues[qid].cids[i]; + + if (p_qcid->p_cid == OSAL_NULL) + continue; + + if (p_qcid->b_is_tx != b_is_tx) + continue; + + /* Found. It's enabled. */ + return (mode == ECORE_IOV_VALIDATE_Q_ENABLE); + } + + /* In case we haven't found any valid cid, then its disabled */ + return (mode == ECORE_IOV_VALIDATE_Q_DISABLE); +} + static bool ecore_iov_validate_rxq(struct ecore_hwfn *p_hwfn, struct ecore_vf_info *p_vf, - u16 rx_qid) + u16 rx_qid, + enum ecore_iov_validate_q_mode mode) { - if (rx_qid >= p_vf->num_rxqs) + if (rx_qid >= p_vf->num_rxqs) { DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, "VF[0x%02x] - can't touch Rx queue[%04x];" " Only 0x%04x are allocated\n", p_vf->abs_vf_id, rx_qid, p_vf->num_rxqs); - return rx_qid < p_vf->num_rxqs; + return false; + } + + return ecore_iov_validate_queue_mode(p_hwfn, p_vf, rx_qid, + mode, false); } static bool ecore_iov_validate_txq(struct ecore_hwfn *p_hwfn, struct ecore_vf_info *p_vf, - u16 tx_qid) + u16 tx_qid, + enum ecore_iov_validate_q_mode mode) { - if (tx_qid >= p_vf->num_txqs) + if (tx_qid >= p_vf->num_txqs) { DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, "VF[0x%02x] - can't touch Tx queue[%04x];" " Only 0x%04x are allocated\n", p_vf->abs_vf_id, tx_qid, p_vf->num_txqs); - return tx_qid < p_vf->num_txqs; + return false; + } + + return ecore_iov_validate_queue_mode(p_hwfn, p_vf, tx_qid, + mode, true); } static bool ecore_iov_validate_sb(struct ecore_hwfn *p_hwfn, @@ -234,13 +296,16 @@ static bool ecore_iov_validate_sb(struct ecore_hwfn *p_hwfn, return false; } +/* Is there at least 1 queue open? */ static bool ecore_iov_validate_active_rxq(struct ecore_hwfn *p_hwfn, struct ecore_vf_info *p_vf) { u8 i; for (i = 0; i < p_vf->num_rxqs; i++) - if (p_vf->vf_queues[i].p_rx_cid) + if (ecore_iov_validate_queue_mode(p_hwfn, p_vf, i, + ECORE_IOV_VALIDATE_Q_ENABLE, + false)) return true; return false; @@ -251,8 +316,10 @@ static bool ecore_iov_validate_active_txq(struct ecore_hwfn *p_hwfn, { u8 i; - for (i = 0; i < p_vf->num_rxqs; i++) - if (p_vf->vf_queues[i].p_tx_cid) + for (i = 0; i < p_vf->num_txqs; i++) + if (ecore_iov_validate_queue_mode(p_hwfn, p_vf, i, + ECORE_IOV_VALIDATE_Q_ENABLE, + true)) return true; return false; @@ -1095,19 +1162,15 @@ ecore_iov_init_hw_for_vf(struct ecore_hwfn *p_hwfn, vf->num_txqs = num_of_vf_available_chains; for (i = 0; i < vf->num_rxqs; i++) { - struct ecore_vf_q_info *p_queue = &vf->vf_queues[i]; + struct ecore_vf_queue *p_queue = &vf->vf_queues[i]; p_queue->fw_rx_qid = p_params->req_rx_queue[i]; p_queue->fw_tx_qid = p_params->req_tx_queue[i]; - /* CIDs are per-VF, so no problem having them 0-based. */ - p_queue->fw_cid = i; - DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, - "VF[%d] - Q[%d] SB %04x, qid [Rx %04x Tx %04x] CID %04x\n", + "VF[%d] - Q[%d] SB %04x, qid [Rx %04x Tx %04x]\n", vf->relative_vf_id, i, vf->igu_sbs[i], - p_queue->fw_rx_qid, p_queue->fw_tx_qid, - p_queue->fw_cid); + p_queue->fw_rx_qid, p_queue->fw_tx_qid); } /* Update the link configuration in bulletin. @@ -1443,7 +1506,7 @@ struct ecore_public_vf_info static void ecore_iov_vf_cleanup(struct ecore_hwfn *p_hwfn, struct ecore_vf_info *p_vf) { - u32 i; + u32 i, j; p_vf->vf_bulletin = 0; p_vf->vport_instance = 0; p_vf->configured_features = 0; @@ -1455,18 +1518,15 @@ static void ecore_iov_vf_cleanup(struct ecore_hwfn *p_hwfn, p_vf->num_active_rxqs = 0; for (i = 0; i < ECORE_MAX_VF_CHAINS_PER_PF; i++) { - struct ecore_vf_q_info *p_queue = &p_vf->vf_queues[i]; + struct ecore_vf_queue *p_queue = &p_vf->vf_queues[i]; - if (p_queue->p_rx_cid) { - ecore_eth_queue_cid_release(p_hwfn, - p_queue->p_rx_cid); - p_queue->p_rx_cid = OSAL_NULL; - } + for (j = 0; j < MAX_QUEUES_PER_QZONE; j++) { + if (!p_queue->cids[j].p_cid) + continue; - if (p_queue->p_tx_cid) { ecore_eth_queue_cid_release(p_hwfn, - p_queue->p_tx_cid); - p_queue->p_tx_cid = OSAL_NULL; + p_queue->cids[j].p_cid); + p_queue->cids[j].p_cid = OSAL_NULL; } } @@ -1481,7 +1541,7 @@ static u8 ecore_iov_vf_mbx_acquire_resc(struct ecore_hwfn *p_hwfn, struct vf_pf_resc_request *p_req, struct pf_vf_resc *p_resp) { - int i; + u8 i; /* Queue related information */ p_resp->num_rxqs = p_vf->num_rxqs; @@ -1502,7 +1562,7 @@ static u8 ecore_iov_vf_mbx_acquire_resc(struct ecore_hwfn *p_hwfn, for (i = 0; i < p_resp->num_rxqs; i++) { ecore_fw_l2_queue(p_hwfn, p_vf->vf_queues[i].fw_rx_qid, (u16 *)&p_resp->hw_qid[i]); - p_resp->cid[i] = p_vf->vf_queues[i].fw_cid; + p_resp->cid[i] = i; } /* Filter related information */ @@ -1905,9 +1965,12 @@ ecore_iov_configure_vport_forced(struct ecore_hwfn *p_hwfn, /* Update all the Rx queues */ for (i = 0; i < ECORE_MAX_VF_CHAINS_PER_PF; i++) { - struct ecore_queue_cid *p_cid; + struct ecore_vf_queue *p_queue = &p_vf->vf_queues[i]; + struct ecore_queue_cid *p_cid = OSAL_NULL; - p_cid = p_vf->vf_queues[i].p_rx_cid; + /* There can be at most 1 Rx queue on qzone. Find it */ + p_cid = ecore_iov_get_vf_rx_queue_cid(p_hwfn, p_vf, + p_queue); if (p_cid == OSAL_NULL) continue; @@ -2113,19 +2176,32 @@ static void ecore_iov_vf_mbx_start_rxq(struct ecore_hwfn *p_hwfn, struct ecore_vf_info *vf) { struct ecore_queue_start_common_params params; + struct ecore_queue_cid_vf_params vf_params; struct ecore_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; - struct ecore_vf_q_info *p_queue; + struct ecore_vf_queue *p_queue; struct vfpf_start_rxq_tlv *req; + struct ecore_queue_cid *p_cid; bool b_legacy_vf = false; + u8 qid_usage_idx; enum _ecore_status_t rc; req = &mbx->req_virt->start_rxq; - if (!ecore_iov_validate_rxq(p_hwfn, vf, req->rx_qid) || + if (!ecore_iov_validate_rxq(p_hwfn, vf, req->rx_qid, + ECORE_IOV_VALIDATE_Q_DISABLE) || !ecore_iov_validate_sb(p_hwfn, vf, req->hw_sb)) goto out; + /* Legacy VFs made assumptions on the CID their queues connected to, + * assuming queue X used CID X. + * TODO - need to validate that there was no official release post + * the current legacy scheme that still made that assumption. + */ + if (vf->acquire.vfdev_info.eth_fp_hsi_minor == + ETH_HSI_VER_NO_PKT_LEN_TUNN) + b_legacy_vf = true; + /* Acquire a new queue-cid */ p_queue = &vf->vf_queues[req->rx_qid]; @@ -2136,39 +2212,42 @@ static void ecore_iov_vf_mbx_start_rxq(struct ecore_hwfn *p_hwfn, params.sb = req->hw_sb; params.sb_idx = req->sb_index; - p_queue->p_rx_cid = _ecore_eth_queue_to_cid(p_hwfn, - vf->opaque_fid, - p_queue->fw_cid, - (u8)req->rx_qid, - ¶ms); - if (p_queue->p_rx_cid == OSAL_NULL) + /* TODO - set qid_usage_idx according to extended TLV. For now, use + * '0' for Rx. + */ + qid_usage_idx = 0; + + OSAL_MEM_ZERO(&vf_params, sizeof(vf_params)); + vf_params.vfid = vf->relative_vf_id; + vf_params.vf_qid = (u8)req->rx_qid; + vf_params.b_legacy = b_legacy_vf; + vf_params.qid_usage_idx = qid_usage_idx; + + p_cid = ecore_eth_queue_to_cid(p_hwfn, vf->opaque_fid, + ¶ms, &vf_params); + if (p_cid == OSAL_NULL) goto out; /* Legacy VFs have their Producers in a different location, which they * calculate on their own and clean the producer prior to this. */ - if (vf->acquire.vfdev_info.eth_fp_hsi_minor == - ETH_HSI_VER_NO_PKT_LEN_TUNN) - b_legacy_vf = true; - else + if (!b_legacy_vf) REG_WR(p_hwfn, GTT_BAR0_MAP_REG_MSDM_RAM + MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id, req->rx_qid), 0); - p_queue->p_rx_cid->b_legacy_vf = b_legacy_vf; - - rc = ecore_eth_rxq_start_ramrod(p_hwfn, - p_queue->p_rx_cid, + rc = ecore_eth_rxq_start_ramrod(p_hwfn, p_cid, req->bd_max_bytes, req->rxq_addr, req->cqe_pbl_addr, req->cqe_pbl_size); if (rc != ECORE_SUCCESS) { status = PFVF_STATUS_FAILURE; - ecore_eth_queue_cid_release(p_hwfn, p_queue->p_rx_cid); - p_queue->p_rx_cid = OSAL_NULL; + ecore_eth_queue_cid_release(p_hwfn, p_cid); } else { + p_queue->cids[qid_usage_idx].p_cid = p_cid; + p_queue->cids[qid_usage_idx].b_is_tx = false; status = PFVF_STATUS_SUCCESS; vf->num_active_rxqs++; } @@ -2331,6 +2410,7 @@ send_resp: static void ecore_iov_vf_mbx_start_txq_resp(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, struct ecore_vf_info *p_vf, + u32 cid, u8 status) { struct ecore_iov_vf_mbx *mbx = &p_vf->vf_mbx; @@ -2359,12 +2439,8 @@ static void ecore_iov_vf_mbx_start_txq_resp(struct ecore_hwfn *p_hwfn, sizeof(struct channel_list_end_tlv)); /* Update the TLV with the response */ - if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) { - u16 qid = mbx->req_virt->start_txq.tx_qid; - - p_tlv->offset = DB_ADDR_VF(p_vf->vf_queues[qid].fw_cid, - DQ_DEMS_LEGACY); - } + if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) + p_tlv->offset = DB_ADDR_VF(cid, DQ_DEMS_LEGACY); ecore_iov_send_response(p_hwfn, p_ptt, p_vf, length, status); } @@ -2374,20 +2450,34 @@ static void ecore_iov_vf_mbx_start_txq(struct ecore_hwfn *p_hwfn, struct ecore_vf_info *vf) { struct ecore_queue_start_common_params params; + struct ecore_queue_cid_vf_params vf_params; struct ecore_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; - struct ecore_vf_q_info *p_queue; + struct ecore_vf_queue *p_queue; struct vfpf_start_txq_tlv *req; + struct ecore_queue_cid *p_cid; + bool b_legacy_vf = false; + u8 qid_usage_idx; + u32 cid = 0; enum _ecore_status_t rc; u16 pq; OSAL_MEMSET(¶ms, 0, sizeof(params)); req = &mbx->req_virt->start_txq; - if (!ecore_iov_validate_txq(p_hwfn, vf, req->tx_qid) || + if (!ecore_iov_validate_txq(p_hwfn, vf, req->tx_qid, + ECORE_IOV_VALIDATE_Q_NA) || !ecore_iov_validate_sb(p_hwfn, vf, req->hw_sb)) goto out; + /* In case this is a legacy VF - need to know to use the right cids. + * TODO - need to validate that there was no official release post + * the current legacy scheme that still made that assumption. + */ + if (vf->acquire.vfdev_info.eth_fp_hsi_minor == + ETH_HSI_VER_NO_PKT_LEN_TUNN) + b_legacy_vf = true; + /* Acquire a new queue-cid */ p_queue = &vf->vf_queues[req->tx_qid]; @@ -2397,29 +2487,42 @@ static void ecore_iov_vf_mbx_start_txq(struct ecore_hwfn *p_hwfn, params.sb = req->hw_sb; params.sb_idx = req->sb_index; - p_queue->p_tx_cid = _ecore_eth_queue_to_cid(p_hwfn, - vf->opaque_fid, - p_queue->fw_cid, - (u8)req->tx_qid, - ¶ms); - if (p_queue->p_tx_cid == OSAL_NULL) + /* TODO - set qid_usage_idx according to extended TLV. For now, use + * '1' for Tx. + */ + qid_usage_idx = 1; + + if (p_queue->cids[qid_usage_idx].p_cid) + goto out; + + OSAL_MEM_ZERO(&vf_params, sizeof(vf_params)); + vf_params.vfid = vf->relative_vf_id; + vf_params.vf_qid = (u8)req->tx_qid; + vf_params.b_legacy = b_legacy_vf; + vf_params.qid_usage_idx = qid_usage_idx; + + p_cid = ecore_eth_queue_to_cid(p_hwfn, vf->opaque_fid, + ¶ms, &vf_params); + if (p_cid == OSAL_NULL) goto out; pq = ecore_get_cm_pq_idx_vf(p_hwfn, vf->relative_vf_id); - rc = ecore_eth_txq_start_ramrod(p_hwfn, p_queue->p_tx_cid, + rc = ecore_eth_txq_start_ramrod(p_hwfn, p_cid, req->pbl_addr, req->pbl_size, pq); if (rc != ECORE_SUCCESS) { status = PFVF_STATUS_FAILURE; - ecore_eth_queue_cid_release(p_hwfn, - p_queue->p_tx_cid); - p_queue->p_tx_cid = OSAL_NULL; + ecore_eth_queue_cid_release(p_hwfn, p_cid); } else { status = PFVF_STATUS_SUCCESS; + p_queue->cids[qid_usage_idx].p_cid = p_cid; + p_queue->cids[qid_usage_idx].b_is_tx = true; + cid = p_cid->cid; } out: - ecore_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, status); + ecore_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, + cid, status); } static enum _ecore_status_t ecore_iov_vf_stop_rxqs(struct ecore_hwfn *p_hwfn, @@ -2428,26 +2531,38 @@ static enum _ecore_status_t ecore_iov_vf_stop_rxqs(struct ecore_hwfn *p_hwfn, u8 num_rxqs, bool cqe_completion) { - struct ecore_vf_q_info *p_queue; enum _ecore_status_t rc = ECORE_SUCCESS; - int qid; + int qid, i; + /* TODO - improve validation [wrap around] */ if (rxq_id + num_rxqs > OSAL_ARRAY_SIZE(vf->vf_queues)) return ECORE_INVAL; for (qid = rxq_id; qid < rxq_id + num_rxqs; qid++) { - p_queue = &vf->vf_queues[qid]; - - if (!p_queue->p_rx_cid) + struct ecore_vf_queue *p_queue = &vf->vf_queues[qid]; + struct ecore_queue_cid **pp_cid = OSAL_NULL; + + /* There can be at most a single Rx per qzone. Find it */ + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + if (p_queue->cids[i].p_cid && + !p_queue->cids[i].b_is_tx) { + pp_cid = &p_queue->cids[i].p_cid; + break; + } + } + if (pp_cid == OSAL_NULL) { + DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, + "Ignoring VF[%02x] request of closing Rx queue %04x - closed\n", + vf->relative_vf_id, qid); continue; + } - rc = ecore_eth_rx_queue_stop(p_hwfn, - p_queue->p_rx_cid, + rc = ecore_eth_rx_queue_stop(p_hwfn, *pp_cid, false, cqe_completion); if (rc != ECORE_SUCCESS) return rc; - vf->vf_queues[qid].p_rx_cid = OSAL_NULL; + *pp_cid = OSAL_NULL; vf->num_active_rxqs--; } @@ -2459,24 +2574,33 @@ static enum _ecore_status_t ecore_iov_vf_stop_txqs(struct ecore_hwfn *p_hwfn, u16 txq_id, u8 num_txqs) { enum _ecore_status_t rc = ECORE_SUCCESS; - struct ecore_vf_q_info *p_queue; - int qid; + struct ecore_vf_queue *p_queue; + int qid, j; - if (txq_id + num_txqs > OSAL_ARRAY_SIZE(vf->vf_queues)) + if (!ecore_iov_validate_txq(p_hwfn, vf, txq_id, + ECORE_IOV_VALIDATE_Q_NA) || + !ecore_iov_validate_txq(p_hwfn, vf, txq_id + num_txqs, + ECORE_IOV_VALIDATE_Q_NA)) return ECORE_INVAL; for (qid = txq_id; qid < txq_id + num_txqs; qid++) { p_queue = &vf->vf_queues[qid]; - if (!p_queue->p_tx_cid) - continue; + for (j = 0; j < MAX_QUEUES_PER_QZONE; j++) { + if (p_queue->cids[j].p_cid == OSAL_NULL) + continue; - rc = ecore_eth_tx_queue_stop(p_hwfn, - p_queue->p_tx_cid); - if (rc != ECORE_SUCCESS) - return rc; + if (!p_queue->cids[j].b_is_tx) + continue; + + rc = ecore_eth_tx_queue_stop(p_hwfn, + p_queue->cids[j].p_cid); + if (rc != ECORE_SUCCESS) + return rc; - p_queue->p_tx_cid = OSAL_NULL; + p_queue->cids[j].p_cid = OSAL_NULL; + } } + return rc; } @@ -2538,33 +2662,32 @@ static void ecore_iov_vf_mbx_update_rxqs(struct ecore_hwfn *p_hwfn, u8 status = PFVF_STATUS_FAILURE; u8 complete_event_flg; u8 complete_cqe_flg; - u16 qid; enum _ecore_status_t rc; - u8 i; + u16 i; req = &mbx->req_virt->update_rxq; complete_cqe_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_CQE_FLAG); complete_event_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_EVENT_FLAG); - /* Validaute inputs */ - if (req->num_rxqs + req->rx_qid > ECORE_MAX_VF_CHAINS_PER_PF || - !ecore_iov_validate_rxq(p_hwfn, vf, req->rx_qid)) { - DP_INFO(p_hwfn, "VF[%d]: Incorrect Rxqs [%04x, %02x]\n", - vf->relative_vf_id, req->rx_qid, req->num_rxqs); - goto out; + /* Validate inputs */ + for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) { + if (!ecore_iov_validate_rxq(p_hwfn, vf, i, + ECORE_IOV_VALIDATE_Q_ENABLE)) { + DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, + "VF[%d]: Incorrect Rxqs [%04x, %02x]\n", + vf->relative_vf_id, req->rx_qid, + req->num_rxqs); + goto out; + } } for (i = 0; i < req->num_rxqs; i++) { - qid = req->rx_qid + i; - - if (!vf->vf_queues[qid].p_rx_cid) { - DP_INFO(p_hwfn, - "VF[%d] rx_qid = %d isn`t active!\n", - vf->relative_vf_id, qid); - goto out; - } + struct ecore_vf_queue *p_queue; + u16 qid = req->rx_qid + i; - handlers[i] = vf->vf_queues[qid].p_rx_cid; + p_queue = &vf->vf_queues[qid]; + handlers[i] = ecore_iov_get_vf_rx_queue_cid(p_hwfn, vf, + p_queue); } rc = ecore_sp_eth_rx_queues_update(p_hwfn, (void **)&handlers, @@ -2796,8 +2919,11 @@ ecore_iov_vp_update_rss_param(struct ecore_hwfn *p_hwfn, (1 << p_rss_tlv->rss_table_size_log)); for (i = 0; i < table_size; i++) { + struct ecore_queue_cid *p_cid; + q_idx = p_rss_tlv->rss_ind_table[i]; - if (!ecore_iov_validate_rxq(p_hwfn, vf, q_idx)) { + if (!ecore_iov_validate_rxq(p_hwfn, vf, q_idx, + ECORE_IOV_VALIDATE_Q_ENABLE)) { DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, "VF[%d]: Omitting RSS due to wrong queue %04x\n", vf->relative_vf_id, q_idx); @@ -2805,15 +2931,9 @@ ecore_iov_vp_update_rss_param(struct ecore_hwfn *p_hwfn, goto out; } - if (!vf->vf_queues[q_idx].p_rx_cid) { - DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, - "VF[%d]: Omitting RSS due to inactive queue %08x\n", - vf->relative_vf_id, q_idx); - b_reject = true; - goto out; - } - - p_rss->rss_ind_table[i] = vf->vf_queues[q_idx].p_rx_cid; + p_cid = ecore_iov_get_vf_rx_queue_cid(p_hwfn, vf, + &vf->vf_queues[q_idx]); + p_rss->rss_ind_table[i] = p_cid; } p_data->rss_params = p_rss; @@ -3272,22 +3392,26 @@ static void ecore_iov_vf_pf_set_coalesce(struct ecore_hwfn *p_hwfn, u8 status = PFVF_STATUS_FAILURE; struct ecore_queue_cid *p_cid; u16 rx_coal, tx_coal; - u16 qid; + u16 qid; + int i; req = &mbx->req_virt->update_coalesce; rx_coal = req->rx_coal; tx_coal = req->tx_coal; qid = req->qid; - p_cid = vf->vf_queues[qid].p_rx_cid; - if (!ecore_iov_validate_rxq(p_hwfn, vf, qid)) { + if (!ecore_iov_validate_rxq(p_hwfn, vf, qid, + ECORE_IOV_VALIDATE_Q_ENABLE) && + rx_coal) { DP_ERR(p_hwfn, "VF[%d]: Invalid Rx queue_id = %d\n", vf->abs_vf_id, qid); goto out; } - if (!ecore_iov_validate_txq(p_hwfn, vf, qid)) { + if (!ecore_iov_validate_txq(p_hwfn, vf, qid, + ECORE_IOV_VALIDATE_Q_ENABLE) && + tx_coal) { DP_ERR(p_hwfn, "VF[%d]: Invalid Tx queue_id = %d\n", vf->abs_vf_id, qid); goto out; @@ -3296,7 +3420,11 @@ static void ecore_iov_vf_pf_set_coalesce(struct ecore_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, "VF[%d]: Setting coalesce for VF rx_coal = %d, tx_coal = %d at queue = %d\n", vf->abs_vf_id, rx_coal, tx_coal, qid); + if (rx_coal) { + p_cid = ecore_iov_get_vf_rx_queue_cid(p_hwfn, vf, + &vf->vf_queues[qid]); + rc = ecore_set_rxq_coalesce(p_hwfn, p_ptt, rx_coal, p_cid); if (rc != ECORE_SUCCESS) { DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, @@ -3305,13 +3433,28 @@ static void ecore_iov_vf_pf_set_coalesce(struct ecore_hwfn *p_hwfn, goto out; } } + + /* TODO - in future, it might be possible to pass this in a per-cid + * granularity. For now, do this for all Tx queues. + */ if (tx_coal) { - rc = ecore_set_txq_coalesce(p_hwfn, p_ptt, tx_coal, p_cid); - if (rc != ECORE_SUCCESS) { - DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, - "VF[%d]: Unable to set tx queue = %d coalesce\n", - vf->abs_vf_id, vf->vf_queues[qid].fw_tx_qid); - goto out; + struct ecore_vf_queue *p_queue = &vf->vf_queues[qid]; + + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + if (p_queue->cids[i].p_cid == OSAL_NULL) + continue; + + if (!p_queue->cids[i].b_is_tx) + continue; + + rc = ecore_set_txq_coalesce(p_hwfn, p_ptt, tx_coal, + p_queue->cids[i].p_cid); + if (rc != ECORE_SUCCESS) { + DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, + "VF[%d]: Unable to set tx queue coalesce\n", + vf->abs_vf_id); + goto out; + } } } diff --git a/drivers/net/qede/base/ecore_sriov.h b/drivers/net/qede/base/ecore_sriov.h index 66e927108b..3c2f58bd89 100644 --- a/drivers/net/qede/base/ecore_sriov.h +++ b/drivers/net/qede/base/ecore_sriov.h @@ -13,6 +13,7 @@ #include "ecore_vfpf_if.h" #include "ecore_iov_api.h" #include "ecore_hsi_common.h" +#include "ecore_l2.h" #define ECORE_ETH_MAX_VF_NUM_VLAN_FILTERS \ (E4_MAX_NUM_VFS * ECORE_ETH_VF_NUM_VLAN_FILTERS) @@ -62,12 +63,18 @@ struct ecore_iov_vf_mbx { */ }; -struct ecore_vf_q_info { +struct ecore_vf_queue_cid { + bool b_is_tx; + struct ecore_queue_cid *p_cid; +}; + +/* Describes a qzone associated with the VF */ +struct ecore_vf_queue { + /* Input from upper-layer, mapping relateive queue to queue-zone */ u16 fw_rx_qid; - struct ecore_queue_cid *p_rx_cid; u16 fw_tx_qid; - struct ecore_queue_cid *p_tx_cid; - u8 fw_cid; + + struct ecore_vf_queue_cid cids[MAX_QUEUES_PER_QZONE]; }; enum vf_state { @@ -127,7 +134,7 @@ struct ecore_vf_info { u8 num_mac_filters; u8 num_vlan_filters; - struct ecore_vf_q_info vf_queues[ECORE_MAX_VF_CHAINS_PER_PF]; + struct ecore_vf_queue vf_queues[ECORE_MAX_VF_CHAINS_PER_PF]; u16 igu_sbs[ECORE_MAX_VF_CHAINS_PER_PF]; /* TODO - Only windows is using it - should be removed */ diff --git a/drivers/net/qede/base/ecore_vf.c b/drivers/net/qede/base/ecore_vf.c index 8ce9340f9c..ac72681bf9 100644 --- a/drivers/net/qede/base/ecore_vf.c +++ b/drivers/net/qede/base/ecore_vf.c @@ -1582,6 +1582,12 @@ void ecore_vf_get_num_rxqs(struct ecore_hwfn *p_hwfn, u8 *num_rxqs) *num_rxqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_rxqs; } +void ecore_vf_get_num_txqs(struct ecore_hwfn *p_hwfn, + u8 *num_txqs) +{ + *num_txqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_txqs; +} + void ecore_vf_get_port_mac(struct ecore_hwfn *p_hwfn, u8 *port_mac) { OSAL_MEMCPY(port_mac, diff --git a/drivers/net/qede/base/ecore_vf_api.h b/drivers/net/qede/base/ecore_vf_api.h index a6e5f32a7e..be3a326b45 100644 --- a/drivers/net/qede/base/ecore_vf_api.h +++ b/drivers/net/qede/base/ecore_vf_api.h @@ -60,6 +60,15 @@ void ecore_vf_get_link_caps(struct ecore_hwfn *p_hwfn, void ecore_vf_get_num_rxqs(struct ecore_hwfn *p_hwfn, u8 *num_rxqs); +/** + * @brief Get number of Rx queues allocated for VF by ecore + * + * @param p_hwfn + * @param num_txqs - allocated RX queues + */ +void ecore_vf_get_num_txqs(struct ecore_hwfn *p_hwfn, + u8 *num_txqs); + /** * @brief Get port mac address for VF * -- 2.20.1