From 910242bcf521eb52b1a68414f3a434e4f513bef5 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Thu, 20 Jul 2017 22:22:31 -0500 Subject: [PATCH] net/bnxt: fix VLAN antispoof configuration code We are wrongly using a Rx side HWRM command set_rx_mask to configure VLAN anti-spoof. This being a Tx side feature, this patch tries to fix it. Since the HWRM command to do it is available only in the newer firmware versions, the patch verifies the firmware version before attempting to send the HWRM command to the firmware. Fixes: 36735a932ca7 ("net/bnxt: support set VF QOS and MAC anti spoof") Signed-off-by: Stephen Hurd Signed-off-by: Ajit Khaparde --- drivers/net/bnxt/bnxt.h | 7 ++ drivers/net/bnxt/bnxt_hwrm.c | 49 ++++++++++++++ drivers/net/bnxt/bnxt_hwrm.h | 3 + drivers/net/bnxt/hsi_struct_def_dpdk.h | 81 ++++++++++++++++++++++- drivers/net/bnxt/rte_pmd_bnxt.c | 91 ++++++++++++++++++-------- 5 files changed, 202 insertions(+), 29 deletions(-) diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h index ec1aad987d..405d94deb5 100644 --- a/drivers/net/bnxt/bnxt.h +++ b/drivers/net/bnxt/bnxt.h @@ -97,9 +97,16 @@ struct bnxt_vlan_table_entry { uint16_t vid; } __attribute__((packed)); +struct bnxt_vlan_antispoof_table_entry { + uint16_t tpid; + uint16_t vid; + uint16_t mask; +} __attribute__((packed)); + struct bnxt_child_vf_info { void *req_buf; struct bnxt_vlan_table_entry *vlan_table; + struct bnxt_vlan_antispoof_table_entry *vlan_as_table; STAILQ_HEAD(, bnxt_filter_info) filter; uint32_t func_cfg_flags; uint32_t l2_rx_mask; diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c index 231f06b1bb..a82cc819f7 100644 --- a/drivers/net/bnxt/bnxt_hwrm.c +++ b/drivers/net/bnxt/bnxt_hwrm.c @@ -282,6 +282,44 @@ int bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt *bp, return rc; } +int bnxt_hwrm_cfa_vlan_antispoof_cfg(struct bnxt *bp, uint16_t fid, + uint16_t vlan_count, + struct bnxt_vlan_antispoof_table_entry *vlan_table) +{ + int rc = 0; + struct hwrm_cfa_vlan_antispoof_cfg_input req = {.req_type = 0 }; + struct hwrm_cfa_vlan_antispoof_cfg_output *resp = + bp->hwrm_cmd_resp_addr; + + /* + * Older HWRM versions did not support this command, and the set_rx_mask + * list was used for anti-spoof. In 1.8.0, the TX path configuration was + * removed from set_rx_mask call, and this command was added. + * + * This command is also present from 1.7.8.11 and higher, + * as well as 1.7.8.0 + */ + if (bp->fw_ver < ((1 << 24) | (8 << 16))) { + if (bp->fw_ver != ((1 << 24) | (7 << 16) | (8 << 8))) { + if (bp->fw_ver < ((1 << 24) | (7 << 16) | (8 << 8) | + (11))) + return 0; + } + } + HWRM_PREP(req, CFA_VLAN_ANTISPOOF_CFG, -1, resp); + req.fid = rte_cpu_to_le_16(fid); + + req.vlan_tag_mask_tbl_addr = + rte_cpu_to_le_64(rte_mem_virt2phy(vlan_table)); + req.num_vlan_entries = rte_cpu_to_le_32((uint32_t)vlan_count); + + rc = bnxt_hwrm_send_message(bp, &req, sizeof(req)); + + HWRM_CHECK_RESULT; + + return rc; +} + int bnxt_hwrm_clear_filter(struct bnxt *bp, struct bnxt_filter_info *filter) { @@ -389,6 +427,17 @@ int bnxt_hwrm_func_qcaps(struct bnxt *bp) else rte_mem_lock_page( bp->pf.vf_info[i].vlan_table); + bp->pf.vf_info[i].vlan_as_table = + rte_zmalloc("VF VLAN AS table", + getpagesize(), + getpagesize()); + if (bp->pf.vf_info[i].vlan_as_table == NULL) + RTE_LOG(ERR, PMD, + "Alloc VLAN AS table for VF %d fail\n", + i); + else + rte_mem_lock_page( + bp->pf.vf_info[i].vlan_as_table); STAILQ_INIT(&bp->pf.vf_info[i].filter); } } diff --git a/drivers/net/bnxt/bnxt_hwrm.h b/drivers/net/bnxt/bnxt_hwrm.h index dd0999a1a3..51cd0dd42c 100644 --- a/drivers/net/bnxt/bnxt_hwrm.h +++ b/drivers/net/bnxt/bnxt_hwrm.h @@ -48,6 +48,9 @@ int bnxt_hwrm_cfa_l2_clear_rx_mask(struct bnxt *bp, int bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt *bp, struct bnxt_vnic_info *vnic, uint16_t vlan_count, struct bnxt_vlan_table_entry *vlan_table); +int bnxt_hwrm_cfa_vlan_antispoof_cfg(struct bnxt *bp, uint16_t fid, + uint16_t vlan_count, + struct bnxt_vlan_antispoof_table_entry *vlan_table); int bnxt_hwrm_clear_filter(struct bnxt *bp, struct bnxt_filter_info *filter); int bnxt_hwrm_set_filter(struct bnxt *bp, diff --git a/drivers/net/bnxt/hsi_struct_def_dpdk.h b/drivers/net/bnxt/hsi_struct_def_dpdk.h index 1eb8d33bb4..cb8660af5e 100644 --- a/drivers/net/bnxt/hsi_struct_def_dpdk.h +++ b/drivers/net/bnxt/hsi_struct_def_dpdk.h @@ -123,7 +123,7 @@ #define HWRM_CFA_L2_FILTER_CFG (UINT32_C(0x92)) #define HWRM_CFA_L2_SET_RX_MASK (UINT32_C(0x93)) /* Reserved for future use */ -#define RESERVED4 (UINT32_C(0x94)) +#define HWRM_CFA_VLAN_ANTISPOOF_CFG (UINT32_C(0x94)) #define HWRM_CFA_TUNNEL_FILTER_ALLOC (UINT32_C(0x95)) #define HWRM_CFA_TUNNEL_FILTER_FREE (UINT32_C(0x96)) #define HWRM_CFA_NTUPLE_FILTER_ALLOC (UINT32_C(0x99)) @@ -9471,6 +9471,85 @@ struct hwrm_cfa_l2_set_rx_mask_output { */ } __attribute__((packed)); +/* hwrm_cfa_vlan_antispoof_cfg */ +/* Description: Configures vlan anti-spoof filters for VF. */ +/* Input (32 bytes) */ +struct hwrm_cfa_vlan_antispoof_cfg_input { + uint16_t req_type; + /* + * This value indicates what type of request this is. The format for the + * rest of the command is determined by this field. + */ + uint16_t cmpl_ring; + /* + * This value indicates the what completion ring the request will be + * optionally completed on. If the value is -1, then no CR completion + * will be generated. Any other value must be a valid CR ring_id value + * for this function. + */ + uint16_t seq_id; + /* This value indicates the command sequence number. */ + uint16_t target_id; + /* + * Target ID of this command. 0x0 - 0xFFF8 - Used for function ids + * 0xFFF8 - 0xFFFE - Reserved for internal processors 0xFFFF - HWRM + */ + uint64_t resp_addr; + /* + * This is the host address where the response will be written when the + * request is complete. This area must be 16B aligned and must be + * cleared to zero before the request is made. + */ + uint16_t fid; + /* + * Function ID of the function that is being configured. Only valid for + * a VF FID configured by the PF. + */ + uint8_t unused_0; + uint8_t unused_1; + uint32_t num_vlan_entries; + /* Number of VLAN entries in the vlan_tag_mask_tbl. */ + uint64_t vlan_tag_mask_tbl_addr; + /* + * The vlan_tag_mask_tbl_addr is the DMA address of the VLAN antispoof + * table. Each table entry contains the 16-bit TPID (0x8100 or 0x88a8 + * only), 16-bit VLAN ID, and a 16-bit mask, all in network order to + * match hwrm_cfa_l2_set_rx_mask. For an individual VLAN entry, the mask + * value should be 0xfff for the 12-bit VLAN ID. + */ +}; + +/* Output (16 bytes) */ +struct hwrm_cfa_vlan_antispoof_cfg_output { + uint16_t error_code; + /* + * Pass/Fail or error type Note: receiver to verify the in parameters, + * and fail the call with an error when appropriate + */ + uint16_t req_type; + /* This field returns the type of original request. */ + uint16_t seq_id; + /* This field provides original sequence number of the command. */ + uint16_t resp_len; + /* + * This field is the length of the response in bytes. The last byte of + * the response is a valid flag that will read as '1' when the command + * has been completely written to memory. + */ + uint32_t unused_0; + uint8_t unused_1; + uint8_t unused_2; + uint8_t unused_3; + uint8_t valid; + /* + * This field is used in Output records to indicate that the output is + * completely written to RAM. This field should be read as '1' to + * indicate that the output has been completely written. When writing a + * command completion or response to an internal processor, the order of + * writes has to be such that this field is written last. + */ +}; + /* hwrm_tunnel_dst_port_query */ /* * Description: This function is called by a driver to query tunnel type diff --git a/drivers/net/bnxt/rte_pmd_bnxt.c b/drivers/net/bnxt/rte_pmd_bnxt.c index ec5855d41f..c1876f8816 100644 --- a/drivers/net/bnxt/rte_pmd_bnxt.c +++ b/drivers/net/bnxt/rte_pmd_bnxt.c @@ -299,8 +299,6 @@ int rte_pmd_bnxt_set_vf_vlan_anti_spoof(uint8_t port, uint16_t vf, uint8_t on) struct rte_eth_dev *dev; struct bnxt *bp; int rc; - int dflt_vnic; - struct bnxt_vnic_info vnic; RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); @@ -327,25 +325,11 @@ int rte_pmd_bnxt_set_vf_vlan_anti_spoof(uint8_t port, uint16_t vf, uint8_t on) if (!rc) { bp->pf.vf_info[vf].vlan_spoof_en = on; if (on) { - dflt_vnic = bnxt_hwrm_func_qcfg_vf_dflt_vnic_id(bp, vf); - if (dflt_vnic < 0) { - /* - * This simply indicates there's no driver - * loaded. This is not an error. - */ - RTE_LOG(INFO, PMD, - "Unable to get default VNIC for VF %d\n", - vf); - } else { - vnic.fw_vnic_id = dflt_vnic; - if (bnxt_hwrm_vnic_qcfg(bp, - &vnic, bp->pf.first_vf_id + vf) == 0) { - if (bnxt_hwrm_cfa_l2_set_rx_mask(bp, - &vnic, bp->pf.vf_info[vf].vlan_count, - bp->pf.vf_info[vf].vlan_table)) - rc = -1; - } - } + if (bnxt_hwrm_cfa_vlan_antispoof_cfg(bp, + bp->pf.first_vf_id + vf, + bp->pf.vf_info[vf].vlan_count, + bp->pf.vf_info[vf].vlan_as_table)) + rc = -1; } } else { RTE_LOG(ERR, PMD, "Failed to update VF VNIC %d.\n", vf); @@ -451,10 +435,49 @@ int rte_pmd_bnxt_set_vf_rxmode(uint8_t port, uint16_t vf, return rc; } +static int bnxt_set_vf_table(struct bnxt *bp, uint16_t vf) +{ + int rc = 0; + int dflt_vnic; + struct bnxt_vnic_info vnic; + + if (!BNXT_PF(bp)) { + RTE_LOG(ERR, PMD, + "Attempt to set VLAN table on non-PF port!\n"); + return -EINVAL; + } + + if (vf >= bp->pdev->max_vfs) + return -EINVAL; + + dflt_vnic = bnxt_hwrm_func_qcfg_vf_dflt_vnic_id(bp, vf); + if (dflt_vnic < 0) { + /* This simply indicates there's no driver loaded. + * This is not an error. + */ + RTE_LOG(ERR, PMD, "Unable to get default VNIC for VF %d\n", vf); + } else { + memset(&vnic, 0, sizeof(vnic)); + vnic.fw_vnic_id = dflt_vnic; + if (bnxt_hwrm_vnic_qcfg(bp, &vnic, + bp->pf.first_vf_id + vf) == 0) { + if (bnxt_hwrm_cfa_l2_set_rx_mask(bp, &vnic, + bp->pf.vf_info[vf].vlan_count, + bp->pf.vf_info[vf].vlan_table)) + rc = -1; + } else { + rc = -1; + } + } + + return rc; +} + int rte_pmd_bnxt_set_vf_vlan_filter(uint8_t port, uint16_t vlan, uint64_t vf_mask, uint8_t vlan_on) { struct bnxt_vlan_table_entry *ve; + struct bnxt_vlan_antispoof_table_entry *vase; struct rte_eth_dev *dev; struct bnxt *bp; uint16_t cnt; @@ -480,6 +503,10 @@ int rte_pmd_bnxt_set_vf_vlan_filter(uint8_t port, uint16_t vlan, rc = -1; continue; } + if (bp->pf.vf_info[i].vlan_as_table == NULL) { + rc = -1; + continue; + } if (vlan_on) { /* First, search for a duplicate... */ for (j = 0; j < cnt; j++) { @@ -489,13 +516,13 @@ int rte_pmd_bnxt_set_vf_vlan_filter(uint8_t port, uint16_t vlan, } if (j == cnt) { /* Now check that there's space */ - if (cnt == getpagesize() / - sizeof(struct bnxt_vlan_table_entry)) { + if (cnt == getpagesize() / sizeof(struct + bnxt_vlan_antispoof_table_entry)) { RTE_LOG(ERR, PMD, - "VF %d VLAN table is full\n", - i); + "VLAN anti-spoof table is full\n"); RTE_LOG(ERR, PMD, - "cannot add VLAN %u\n", vlan); + "VF %d cannot add VLAN %u\n", + i, vlan); rc = -1; continue; } @@ -506,6 +533,11 @@ int rte_pmd_bnxt_set_vf_vlan_filter(uint8_t port, uint16_t vlan, * And finally, add to the * end of the table */ + vase = &bp->pf.vf_info[i].vlan_as_table[cnt]; + // TODO: Hardcoded TPID + vase->tpid = rte_cpu_to_be_16(0x8100); + vase->vid = rte_cpu_to_be_16(vlan); + vase->mask = rte_cpu_to_be_16(0xfff); ve = &bp->pf.vf_info[i].vlan_table[cnt]; /* TODO: Hardcoded TPID */ ve->tpid = rte_cpu_to_be_16(0x8100); @@ -520,12 +552,15 @@ int rte_pmd_bnxt_set_vf_vlan_filter(uint8_t port, uint16_t vlan, &bp->pf.vf_info[i].vlan_table[j + 1], getpagesize() - ((j + 1) * sizeof(struct bnxt_vlan_table_entry))); + memmove(&bp->pf.vf_info[i].vlan_as_table[j], + &bp->pf.vf_info[i].vlan_as_table[j + 1], + getpagesize() - ((j + 1) * sizeof(struct + bnxt_vlan_antispoof_table_entry))); j--; cnt = --bp->pf.vf_info[i].vlan_count; } } - rte_pmd_bnxt_set_vf_vlan_anti_spoof(dev->data->port_id, i, - bp->pf.vf_info[i].vlan_spoof_en); + bnxt_set_vf_table(bp, i); } return rc; -- 2.20.1