net/bnxt: fix VLAN antispoof configuration code
authorAjit Khaparde <ajit.khaparde@broadcom.com>
Fri, 21 Jul 2017 03:22:31 +0000 (22:22 -0500)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 31 Jul 2017 17:58:41 +0000 (19:58 +0200)
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 <stephen.hurd@broadcom.com>
Signed-off-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
drivers/net/bnxt/bnxt.h
drivers/net/bnxt/bnxt_hwrm.c
drivers/net/bnxt/bnxt_hwrm.h
drivers/net/bnxt/hsi_struct_def_dpdk.h
drivers/net/bnxt/rte_pmd_bnxt.c

index ec1aad9..405d94d 100644 (file)
@@ -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;
index 231f06b..a82cc81 100644 (file)
@@ -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);
                        }
                }
index dd0999a..51cd0dd 100644 (file)
@@ -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,
index 1eb8d33..cb8660a 100644 (file)
 #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
index ec5855d..c1876f8 100644 (file)
@@ -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;