drivers: update registration macro usage
[dpdk.git] / drivers / net / i40e / i40e_ethdev.c
index c1fb89a..47b9b6b 100644 (file)
@@ -63,6 +63,9 @@
 #include "i40e_pf.h"
 #include "i40e_regs.h"
 
+#define ETH_I40E_FLOATING_VEB_ARG      "enable_floating_veb"
+#define ETH_I40E_FLOATING_VEB_LIST_ARG "floating_veb_list"
+
 #define I40E_CLEAR_PXE_WAIT_MS     200
 
 /* Maximun number of capability elements */
@@ -702,7 +705,8 @@ static struct rte_driver rte_i40e_driver = {
        .init = rte_i40e_pmd_init,
 };
 
-PMD_REGISTER_DRIVER(rte_i40e_driver);
+PMD_REGISTER_DRIVER(rte_i40e_driver, i40e);
+DRIVER_REGISTER_PCI_TABLE(i40e, pci_id_i40e_map);
 
 /*
  * Initialize registers for flexible payload, which should be set by NVM.
@@ -757,6 +761,161 @@ i40e_add_tx_flow_control_drop_filter(struct i40e_pf *pf)
                                  " frames from VSIs.");
 }
 
+static int
+floating_veb_list_handler(__rte_unused const char *key,
+                         const char *floating_veb_value,
+                         void *opaque)
+{
+       int idx = 0;
+       unsigned int count = 0;
+       char *end = NULL;
+       int min, max;
+       bool *vf_floating_veb = opaque;
+
+       while (isblank(*floating_veb_value))
+               floating_veb_value++;
+
+       /* Reset floating VEB configuration for VFs */
+       for (idx = 0; idx < I40E_MAX_VF; idx++)
+               vf_floating_veb[idx] = false;
+
+       min = I40E_MAX_VF;
+       do {
+               while (isblank(*floating_veb_value))
+                       floating_veb_value++;
+               if (*floating_veb_value == '\0')
+                       return -1;
+               errno = 0;
+               idx = strtoul(floating_veb_value, &end, 10);
+               if (errno || end == NULL)
+                       return -1;
+               while (isblank(*end))
+                       end++;
+               if (*end == '-') {
+                       min = idx;
+               } else if ((*end == ';') || (*end == '\0')) {
+                       max = idx;
+                       if (min == I40E_MAX_VF)
+                               min = idx;
+                       if (max >= I40E_MAX_VF)
+                               max = I40E_MAX_VF - 1;
+                       for (idx = min; idx <= max; idx++) {
+                               vf_floating_veb[idx] = true;
+                               count++;
+                       }
+                       min = I40E_MAX_VF;
+               } else {
+                       return -1;
+               }
+               floating_veb_value = end + 1;
+       } while (*end != '\0');
+
+       if (count == 0)
+               return -1;
+
+       return 0;
+}
+
+static void
+config_vf_floating_veb(struct rte_devargs *devargs,
+                      uint16_t floating_veb,
+                      bool *vf_floating_veb)
+{
+       struct rte_kvargs *kvlist;
+       int i;
+       const char *floating_veb_list = ETH_I40E_FLOATING_VEB_LIST_ARG;
+
+       if (!floating_veb)
+               return;
+       /* All the VFs attach to the floating VEB by default
+        * when the floating VEB is enabled.
+        */
+       for (i = 0; i < I40E_MAX_VF; i++)
+               vf_floating_veb[i] = true;
+
+       if (devargs == NULL)
+               return;
+
+       kvlist = rte_kvargs_parse(devargs->args, NULL);
+       if (kvlist == NULL)
+               return;
+
+       if (!rte_kvargs_count(kvlist, floating_veb_list)) {
+               rte_kvargs_free(kvlist);
+               return;
+       }
+       /* When the floating_veb_list parameter exists, all the VFs
+        * will attach to the legacy VEB firstly, then configure VFs
+        * to the floating VEB according to the floating_veb_list.
+        */
+       if (rte_kvargs_process(kvlist, floating_veb_list,
+                              floating_veb_list_handler,
+                              vf_floating_veb) < 0) {
+               rte_kvargs_free(kvlist);
+               return;
+       }
+       rte_kvargs_free(kvlist);
+}
+
+static int
+i40e_check_floating_handler(__rte_unused const char *key,
+                           const char *value,
+                           __rte_unused void *opaque)
+{
+       if (strcmp(value, "1"))
+               return -1;
+
+       return 0;
+}
+
+static int
+is_floating_veb_supported(struct rte_devargs *devargs)
+{
+       struct rte_kvargs *kvlist;
+       const char *floating_veb_key = ETH_I40E_FLOATING_VEB_ARG;
+
+       if (devargs == NULL)
+               return 0;
+
+       kvlist = rte_kvargs_parse(devargs->args, NULL);
+       if (kvlist == NULL)
+               return 0;
+
+       if (!rte_kvargs_count(kvlist, floating_veb_key)) {
+               rte_kvargs_free(kvlist);
+               return 0;
+       }
+       /* Floating VEB is enabled when there's key-value:
+        * enable_floating_veb=1
+        */
+       if (rte_kvargs_process(kvlist, floating_veb_key,
+                              i40e_check_floating_handler, NULL) < 0) {
+               rte_kvargs_free(kvlist);
+               return 0;
+       }
+       rte_kvargs_free(kvlist);
+
+       return 1;
+}
+
+static void
+config_floating_veb(struct rte_eth_dev *dev)
+{
+       struct rte_pci_device *pci_dev = dev->pci_dev;
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       memset(pf->floating_veb_list, 0, sizeof(pf->floating_veb_list));
+
+       if (hw->aq.fw_maj_ver >= FLOATING_VEB_SUPPORTED_FW_MAJ) {
+               pf->floating_veb = is_floating_veb_supported(pci_dev->devargs);
+               config_vf_floating_veb(pci_dev->devargs, pf->floating_veb,
+                                      pf->floating_veb_list);
+       } else {
+               pf->floating_veb = false;
+       }
+}
+
 static int
 eth_i40e_dev_init(struct rte_eth_dev *dev)
 {
@@ -850,6 +1009,8 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                     ((hw->nvm.version >> 4) & 0xff),
                     (hw->nvm.version & 0xf), hw->nvm.eetrack);
 
+       /* Need the special FW version to support floating VEB */
+       config_floating_veb(dev);
        /* Clear PXE mode */
        i40e_clear_pxe_mode(hw);
 
@@ -927,12 +1088,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                             "VLAN ether type");
                goto err_setup_pf_switch;
        }
-       ret = i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_INNER, ETHER_TYPE_VLAN);
-       if (ret != I40E_SUCCESS) {
-               PMD_INIT_LOG(ERR, "Failed to set the default outer "
-                            "VLAN ether type");
-               goto err_setup_pf_switch;
-       }
 
        /* PF setup, which includes VSI setup */
        ret = i40e_pf_setup(pf);
@@ -2277,7 +2432,6 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
                snprintf(xstats_names[count].name,
                         sizeof(xstats_names[count].name),
                         "%s", rte_i40e_stats_strings[i].name);
-               xstats_names[count].id = count;
                count++;
        }
 
@@ -2286,7 +2440,6 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
                snprintf(xstats_names[count].name,
                        sizeof(xstats_names[count].name),
                         "%s", rte_i40e_hw_port_strings[i].name);
-               xstats_names[count].id = count;
                count++;
        }
 
@@ -2296,7 +2449,6 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
                                 sizeof(xstats_names[count].name),
                                 "rx_priority%u_%s", prio,
                                 rte_i40e_rxq_prio_strings[i].name);
-                       xstats_names[count].id = count;
                        count++;
                }
        }
@@ -2307,7 +2459,6 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
                                 sizeof(xstats_names[count].name),
                                 "tx_priority%u_%s", prio,
                                 rte_i40e_txq_prio_strings[i].name);
-                       xstats_names[count].id = count;
                        count++;
                }
        }
@@ -2336,7 +2487,6 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
        /* Get stats from i40e_eth_stats struct */
        for (i = 0; i < I40E_NB_ETH_XSTATS; i++) {
-               xstats[count].id = count;
                xstats[count].value = *(uint64_t *)(((char *)&hw_stats->eth) +
                        rte_i40e_stats_strings[i].offset);
                count++;
@@ -2344,7 +2494,6 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
        /* Get individiual stats from i40e_hw_port struct */
        for (i = 0; i < I40E_NB_HW_PORT_XSTATS; i++) {
-               xstats[count].id = count;
                xstats[count].value = *(uint64_t *)(((char *)hw_stats) +
                        rte_i40e_hw_port_strings[i].offset);
                count++;
@@ -2352,7 +2501,6 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
        for (i = 0; i < I40E_NB_RXQ_PRIO_XSTATS; i++) {
                for (prio = 0; prio < 8; prio++) {
-                       xstats[count].id = count;
                        xstats[count].value =
                                *(uint64_t *)(((char *)hw_stats) +
                                rte_i40e_rxq_prio_strings[i].offset +
@@ -2363,7 +2511,6 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 
        for (i = 0; i < I40E_NB_TXQ_PRIO_XSTATS; i++) {
                for (prio = 0; prio < 8; prio++) {
-                       xstats[count].id = count;
                        xstats[count].value =
                                *(uint64_t *)(((char *)hw_stats) +
                                rte_i40e_txq_prio_strings[i].offset +
@@ -2493,13 +2640,24 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
        uint64_t reg_r = 0, reg_w = 0;
        uint16_t reg_id = 0;
        int ret = 0;
+       int qinq = dev->data->dev_conf.rxmode.hw_vlan_extend;
 
        switch (vlan_type) {
        case ETH_VLAN_TYPE_OUTER:
-               reg_id = 2;
+               if (qinq)
+                       reg_id = 2;
+               else
+                       reg_id = 3;
                break;
        case ETH_VLAN_TYPE_INNER:
-               reg_id = 3;
+               if (qinq)
+                       reg_id = 3;
+               else {
+                       ret = -EINVAL;
+                       PMD_DRV_LOG(ERR,
+                               "Unsupported vlan type in single vlan.\n");
+                       return ret;
+               }
                break;
        default:
                ret = -EINVAL;
@@ -2561,8 +2719,14 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
        }
 
        if (mask & ETH_VLAN_EXTEND_MASK) {
-               if (dev->data->dev_conf.rxmode.hw_vlan_extend)
+               if (dev->data->dev_conf.rxmode.hw_vlan_extend) {
                        i40e_vsi_config_double_vlan(vsi, TRUE);
+                       /* Set global registers with default ether type value */
+                       i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_OUTER,
+                                          ETHER_TYPE_VLAN);
+                       i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_INNER,
+                                          ETHER_TYPE_VLAN);
+               }
                else
                        i40e_vsi_config_double_vlan(vsi, FALSE);
        }
@@ -3819,21 +3983,27 @@ i40e_veb_release(struct i40e_veb *veb)
        struct i40e_vsi *vsi;
        struct i40e_hw *hw;
 
-       if (veb == NULL || veb->associate_vsi == NULL)
+       if (veb == NULL)
                return -EINVAL;
 
        if (!TAILQ_EMPTY(&veb->head)) {
                PMD_DRV_LOG(ERR, "VEB still has VSI attached, can't remove");
                return -EACCES;
        }
+       /* associate_vsi field is NULL for floating VEB */
+       if (veb->associate_vsi != NULL) {
+               vsi = veb->associate_vsi;
+               hw = I40E_VSI_TO_HW(vsi);
 
-       vsi = veb->associate_vsi;
-       hw = I40E_VSI_TO_HW(vsi);
+               vsi->uplink_seid = veb->uplink_seid;
+               vsi->veb = NULL;
+       } else {
+               veb->associate_pf->main_vsi->floating_veb = NULL;
+               hw = I40E_VSI_TO_HW(veb->associate_pf->main_vsi);
+       }
 
-       vsi->uplink_seid = veb->uplink_seid;
        i40e_aq_delete_element(hw, veb->seid, NULL);
        rte_free(veb);
-       vsi->veb = NULL;
        return I40E_SUCCESS;
 }
 
@@ -3845,9 +4015,9 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
        int ret;
        struct i40e_hw *hw;
 
-       if (NULL == pf || vsi == NULL) {
-               PMD_DRV_LOG(ERR, "veb setup failed, "
-                           "associated VSI shouldn't null");
+       if (pf == NULL) {
+               PMD_DRV_LOG(ERR,
+                           "veb setup failed, associated PF shouldn't null");
                return NULL;
        }
        hw = I40E_PF_TO_HW(pf);
@@ -3859,11 +4029,19 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
        }
 
        veb->associate_vsi = vsi;
+       veb->associate_pf = pf;
        TAILQ_INIT(&veb->head);
-       veb->uplink_seid = vsi->uplink_seid;
+       veb->uplink_seid = vsi ? vsi->uplink_seid : 0;
 
-       ret = i40e_aq_add_veb(hw, veb->uplink_seid, vsi->seid,
-               I40E_DEFAULT_TCMAP, false, &veb->seid, false, NULL);
+       /* create floating veb if vsi is NULL */
+       if (vsi != NULL) {
+               ret = i40e_aq_add_veb(hw, veb->uplink_seid, vsi->seid,
+                                     I40E_DEFAULT_TCMAP, false,
+                                     &veb->seid, false, NULL);
+       } else {
+               ret = i40e_aq_add_veb(hw, 0, 0, I40E_DEFAULT_TCMAP,
+                                     true, &veb->seid, false, NULL);
+       }
 
        if (ret != I40E_SUCCESS) {
                PMD_DRV_LOG(ERR, "Add veb failed, aq_err: %d",
@@ -3879,10 +4057,10 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
                            hw->aq.asq_last_status);
                goto fail;
        }
-
        /* Get VEB bandwidth, to be implemented */
        /* Now associated vsi binding to the VEB, set uplink to this VEB */
-       vsi->uplink_seid = veb->seid;
+       if (vsi)
+               vsi->uplink_seid = veb->seid;
 
        return veb;
 fail:
@@ -3898,6 +4076,7 @@ i40e_vsi_release(struct i40e_vsi *vsi)
        struct i40e_vsi_list *vsi_list;
        int ret;
        struct i40e_mac_filter *f;
+       uint16_t user_param = vsi->user_param;
 
        if (!vsi)
                return I40E_SUCCESS;
@@ -3915,12 +4094,22 @@ i40e_vsi_release(struct i40e_vsi *vsi)
                i40e_veb_release(vsi->veb);
        }
 
+       if (vsi->floating_veb) {
+               TAILQ_FOREACH(vsi_list, &vsi->floating_veb->head, list) {
+                       if (i40e_vsi_release(vsi_list->vsi) != I40E_SUCCESS)
+                               return -1;
+                       TAILQ_REMOVE(&vsi->floating_veb->head, vsi_list, list);
+               }
+       }
+
        /* Remove all macvlan filters of the VSI */
        i40e_vsi_remove_all_macvlan_filter(vsi);
        TAILQ_FOREACH(f, &vsi->mac_list, next)
                rte_free(f);
 
-       if (vsi->type != I40E_VSI_MAIN) {
+       if (vsi->type != I40E_VSI_MAIN &&
+           ((vsi->type != I40E_VSI_SRIOV) ||
+           !pf->floating_veb_list[user_param])) {
                /* Remove vsi from parent's sibling list */
                if (vsi->parent_vsi == NULL || vsi->parent_vsi->veb == NULL) {
                        PMD_DRV_LOG(ERR, "VSI's parent VSI is NULL");
@@ -3934,6 +4123,24 @@ i40e_vsi_release(struct i40e_vsi *vsi)
                if (ret != I40E_SUCCESS)
                        PMD_DRV_LOG(ERR, "Failed to delete element");
        }
+
+       if ((vsi->type == I40E_VSI_SRIOV) &&
+           pf->floating_veb_list[user_param]) {
+               /* Remove vsi from parent's sibling list */
+               if (vsi->parent_vsi == NULL ||
+                   vsi->parent_vsi->floating_veb == NULL) {
+                       PMD_DRV_LOG(ERR, "VSI's parent VSI is NULL");
+                       return I40E_ERR_PARAM;
+               }
+               TAILQ_REMOVE(&vsi->parent_vsi->floating_veb->head,
+                            &vsi->sib_vsi_list, list);
+
+               /* Remove all switch element of the VSI */
+               ret = i40e_aq_delete_element(hw, vsi->seid, NULL);
+               if (ret != I40E_SUCCESS)
+                       PMD_DRV_LOG(ERR, "Failed to delete element");
+       }
+
        i40e_res_pool_free(&pf->qp_pool, vsi->base_queue);
 
        if (vsi->type != I40E_VSI_SRIOV)
@@ -4102,7 +4309,8 @@ i40e_vsi_setup(struct i40e_pf *pf,
        struct ether_addr broadcast =
                {.addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
 
-       if (type != I40E_VSI_MAIN && uplink_vsi == NULL) {
+       if (type != I40E_VSI_MAIN && type != I40E_VSI_SRIOV &&
+           uplink_vsi == NULL) {
                PMD_DRV_LOG(ERR, "VSI setup failed, "
                            "VSI link shouldn't be NULL");
                return NULL;
@@ -4114,11 +4322,18 @@ i40e_vsi_setup(struct i40e_pf *pf,
                return NULL;
        }
 
-       /* If uplink vsi didn't setup VEB, create one first */
-       if (type != I40E_VSI_MAIN && uplink_vsi->veb == NULL) {
+       /* two situations
+        * 1.type is not MAIN and uplink vsi is not NULL
+        * If uplink vsi didn't setup VEB, create one first under veb field
+        * 2.type is SRIOV and the uplink is NULL
+        * If floating VEB is NULL, create one veb under floating veb field
+        */
+
+       if (type != I40E_VSI_MAIN && uplink_vsi != NULL &&
+           uplink_vsi->veb == NULL) {
                uplink_vsi->veb = i40e_veb_setup(pf, uplink_vsi);
 
-               if (NULL == uplink_vsi->veb) {
+               if (uplink_vsi->veb == NULL) {
                        PMD_DRV_LOG(ERR, "VEB setup failed");
                        return NULL;
                }
@@ -4126,6 +4341,16 @@ i40e_vsi_setup(struct i40e_pf *pf,
                i40e_enable_pf_lb(pf);
        }
 
+       if (type == I40E_VSI_SRIOV && uplink_vsi == NULL &&
+           pf->main_vsi->floating_veb == NULL) {
+               pf->main_vsi->floating_veb = i40e_veb_setup(pf, uplink_vsi);
+
+               if (pf->main_vsi->floating_veb == NULL) {
+                       PMD_DRV_LOG(ERR, "VEB setup failed");
+                       return NULL;
+               }
+       }
+
        vsi = rte_zmalloc("i40e_vsi", sizeof(struct i40e_vsi), 0);
        if (!vsi) {
                PMD_DRV_LOG(ERR, "Failed to allocate memory for vsi");
@@ -4135,7 +4360,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
        vsi->type = type;
        vsi->adapter = I40E_PF_TO_ADAPTER(pf);
        vsi->max_macaddrs = I40E_NUM_MACADDR_MAX;
-       vsi->parent_vsi = uplink_vsi;
+       vsi->parent_vsi = uplink_vsi ? uplink_vsi : pf->main_vsi;
        vsi->user_param = user_param;
        /* Allocate queues */
        switch (vsi->type) {
@@ -4289,7 +4514,10 @@ i40e_vsi_setup(struct i40e_pf *pf,
                 * For other VSI, the uplink_seid equals to uplink VSI's
                 * uplink_seid since they share same VEB
                 */
-               vsi->uplink_seid = uplink_vsi->uplink_seid;
+               if (uplink_vsi == NULL)
+                       vsi->uplink_seid = pf->main_vsi->floating_veb->seid;
+               else
+                       vsi->uplink_seid = uplink_vsi->uplink_seid;
                ctxt.pf_num = hw->pf_id;
                ctxt.vf_num = hw->func_caps.vf_base_id + user_param;
                ctxt.uplink_seid = vsi->uplink_seid;
@@ -4397,8 +4625,13 @@ i40e_vsi_setup(struct i40e_pf *pf,
                vsi->seid = ctxt.seid;
                vsi->vsi_id = ctxt.vsi_number;
                vsi->sib_vsi_list.vsi = vsi;
-               TAILQ_INSERT_TAIL(&uplink_vsi->veb->head,
-                               &vsi->sib_vsi_list, list);
+               if (vsi->type == I40E_VSI_SRIOV && uplink_vsi == NULL) {
+                       TAILQ_INSERT_TAIL(&pf->main_vsi->floating_veb->head,
+                                         &vsi->sib_vsi_list, list);
+               } else {
+                       TAILQ_INSERT_TAIL(&uplink_vsi->veb->head,
+                                         &vsi->sib_vsi_list, list);
+               }
        }
 
        /* MAC/VLAN configuration */