net/qede: fix VLAN filters
authorHarish Patil <harish.patil@qlogic.com>
Wed, 19 Oct 2016 04:11:34 +0000 (21:11 -0700)
committerBruce Richardson <bruce.richardson@intel.com>
Wed, 26 Oct 2016 17:42:22 +0000 (19:42 +0200)
 - fix to prevent duplicate VLAN filters

librte_ether does not keep track of VLAN filters
configured, so it becomes driver's responsibility to
keep track of it and prevent duplicate filter
programming. The fix is to use a singly linked
list for tracking the entries and there by prevent
duplicates.

 - fix num vlan filters

Fix num vlan filter when filling Ethernet device information.

Fixes: 2ea6f76aff40 ("qede: add core driver")

Signed-off-by: Harish Patil <harish.patil@qlogic.com>
drivers/net/qede/qede_eth_if.h
drivers/net/qede/qede_ethdev.c
drivers/net/qede/qede_ethdev.h
drivers/net/qede/qede_main.c

index 7840a37..5a7fdc9 100644 (file)
@@ -46,7 +46,7 @@ struct qed_dev_eth_info {
        uint8_t num_tc;
 
        struct ether_addr port_mac;
-       uint8_t num_vlan_filters;
+       uint16_t num_vlan_filters;
        uint32_t num_mac_addrs;
 };
 
index f7cc313..b97e3be 100644 (file)
@@ -406,10 +406,11 @@ static int qede_vlan_filter_set(struct rte_eth_dev *eth_dev,
        struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
        struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
        struct qed_dev_eth_info *dev_info = &qdev->dev_info;
+       struct qede_vlan_entry *tmp = NULL;
+       struct qede_vlan_entry *vlan;
        int rc;
 
-       if (vlan_id != 0 &&
-           qdev->configured_vlans == dev_info->num_vlan_filters) {
+       if (qdev->configured_vlans == dev_info->num_vlan_filters) {
                DP_NOTICE(edev, false, "Reached max VLAN filter limit"
                                     " enabling accept_any_vlan\n");
                qede_config_accept_any_vlan(qdev, true);
@@ -417,28 +418,66 @@ static int qede_vlan_filter_set(struct rte_eth_dev *eth_dev,
        }
 
        if (on) {
+               SLIST_FOREACH(tmp, &qdev->vlan_list_head, list) {
+                       if (tmp->vid == vlan_id) {
+                               DP_ERR(edev, "VLAN %u already configured\n",
+                                      vlan_id);
+                               return -EEXIST;
+                       }
+               }
+
+               vlan = rte_malloc(NULL, sizeof(struct qede_vlan_entry),
+                                 RTE_CACHE_LINE_SIZE);
+
+               if (!vlan) {
+                       DP_ERR(edev, "Did not allocate memory for VLAN\n");
+                       return -ENOMEM;
+               }
+
                rc = qede_set_ucast_rx_vlan(qdev, QED_FILTER_XCAST_TYPE_ADD,
                                            vlan_id);
-               if (rc)
+               if (rc) {
                        DP_ERR(edev, "Failed to add VLAN %u rc %d\n", vlan_id,
                               rc);
-               else
-                       if (vlan_id != 0)
-                               qdev->configured_vlans++;
+                       rte_free(vlan);
+               } else {
+                       vlan->vid = vlan_id;
+                       SLIST_INSERT_HEAD(&qdev->vlan_list_head, vlan, list);
+                       qdev->configured_vlans++;
+                       DP_INFO(edev, "VLAN %u added, configured_vlans %u\n",
+                               vlan_id, qdev->configured_vlans);
+               }
        } else {
+               SLIST_FOREACH(tmp, &qdev->vlan_list_head, list) {
+                       if (tmp->vid == vlan_id)
+                               break;
+               }
+
+               if (!tmp) {
+                       if (qdev->configured_vlans == 0) {
+                               DP_INFO(edev,
+                                       "No VLAN filters configured yet\n");
+                               return 0;
+                       }
+
+                       DP_ERR(edev, "VLAN %u not configured\n", vlan_id);
+                       return -EINVAL;
+               }
+
+               SLIST_REMOVE(&qdev->vlan_list_head, tmp, qede_vlan_entry, list);
+
                rc = qede_set_ucast_rx_vlan(qdev, QED_FILTER_XCAST_TYPE_DEL,
                                            vlan_id);
-               if (rc)
+               if (rc) {
                        DP_ERR(edev, "Failed to delete VLAN %u rc %d\n",
                               vlan_id, rc);
-               else
-                       if (vlan_id != 0)
-                               qdev->configured_vlans--;
+               } else {
+                       qdev->configured_vlans--;
+                       DP_INFO(edev, "VLAN %u removed configured_vlans %u\n",
+                               vlan_id, qdev->configured_vlans);
+               }
        }
 
-       DP_INFO(edev, "vlan_id %u on %u rc %d configured_vlans %u\n",
-                       vlan_id, on, rc, qdev->configured_vlans);
-
        return rc;
 }
 
@@ -517,6 +556,8 @@ static int qede_dev_configure(struct rte_eth_dev *eth_dev)
                DP_INFO(edev, "IP/UDP/TCP checksum offload is always enabled "
                              "in hw\n");
 
+       SLIST_INIT(&qdev->vlan_list_head);
+
        /* Check for the port restart case */
        if (qdev->state != QEDE_DEV_INIT) {
                rc = qdev->ops->vport_stop(edev, 0);
index f2e908c..ed2d41c 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef _QEDE_ETHDEV_H_
 #define _QEDE_ETHDEV_H_
 
+#include <sys/queue.h>
+
 #include <rte_ether.h>
 #include <rte_ethdev.h>
 #include <rte_dev.h>
@@ -116,6 +118,11 @@ enum qede_dev_state {
        QEDE_DEV_STOP, /* Deactivate vport and stop traffic */
 };
 
+struct qede_vlan_entry {
+       SLIST_ENTRY(qede_vlan_entry) list;
+       uint16_t vid;
+};
+
 /*
  *  Structure to store private data for each port.
  */
@@ -136,16 +143,10 @@ struct qede_dev {
        uint16_t num_queues;
        uint8_t fp_num_tx;
        uint8_t fp_num_rx;
-
        enum qede_dev_state state;
-
-       /* Vlans */
-       osal_list_t vlan_list;
+       SLIST_HEAD(vlan_list_head, qede_vlan_entry)vlan_list_head;
        uint16_t configured_vlans;
-       uint16_t non_configured_vlans;
        bool accept_any_vlan;
-       uint16_t vxlan_dst_port;
-
        struct ether_addr primary_mac;
        bool handle_hw_err;
        char drv_ver[QED_DRV_VER_STR_SIZE];
index 60655b7..c83893d 100644 (file)
@@ -391,12 +391,18 @@ qed_fill_eth_dev_info(struct ecore_dev *edev, struct qed_dev_eth_info *info)
        info->num_tc = 1 /* @@@TBD aelior MULTI_COS */;
 
        if (IS_PF(edev)) {
+               int max_vf_vlan_filters = 0;
+
                info->num_queues = 0;
                for_each_hwfn(edev, i)
                        info->num_queues +=
                        FEAT_NUM(&edev->hwfns[i], ECORE_PF_L2_QUE);
 
-               info->num_vlan_filters = RESC_NUM(&edev->hwfns[0], ECORE_VLAN);
+               if (edev->p_iov_info)
+                       max_vf_vlan_filters = edev->p_iov_info->total_vfs *
+                                             ECORE_ETH_VF_NUM_VLAN_FILTERS;
+               info->num_vlan_filters = RESC_NUM(&edev->hwfns[0], ECORE_VLAN) -
+                                        max_vf_vlan_filters;
 
                rte_memcpy(&info->port_mac, &edev->hwfns[0].hw_info.hw_mac_addr,
                           ETHER_ADDR_LEN);
@@ -404,7 +410,7 @@ qed_fill_eth_dev_info(struct ecore_dev *edev, struct qed_dev_eth_info *info)
                ecore_vf_get_num_rxqs(&edev->hwfns[0], &info->num_queues);
 
                ecore_vf_get_num_vlan_filters(&edev->hwfns[0],
-                                             &info->num_vlan_filters);
+                                             (u8 *)&info->num_vlan_filters);
 
                ecore_vf_get_port_mac(&edev->hwfns[0],
                                      (uint8_t *)&info->port_mac);