drivers: use PCI registration macro
[dpdk.git] / drivers / net / i40e / i40e_ethdev.c
index 401abfb..56bd2c6 100644 (file)
@@ -31,7 +31,6 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/queue.h>
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
@@ -51,6 +50,7 @@
 #include <rte_alarm.h>
 #include <rte_dev.h>
 #include <rte_eth_ctrl.h>
+#include <rte_tailq.h>
 
 #include "i40e_logs.h"
 #include "base/i40e_prototype.h"
@@ -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 */
@@ -437,8 +440,6 @@ static int i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
 static int i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
                                          uint16_t queue_id);
 
-static int i40e_get_reg_length(struct rte_eth_dev *dev);
-
 static int i40e_get_regs(struct rte_eth_dev *dev,
                         struct rte_dev_reg_info *regs);
 
@@ -453,9 +454,28 @@ static void i40e_set_default_mac_addr(struct rte_eth_dev *dev,
 static int i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
 
 static const struct rte_pci_id pci_id_i40e_map[] = {
-#define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
-#include "rte_pci_dev_ids.h"
-{ .vendor_id = 0, /* sentinel */ },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QEMU) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_20G_KR2) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_20G_KR2_A) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_A0) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_I_X722) },
+       { .vendor_id = 0, /* sentinel */ },
 };
 
 static const struct eth_dev_ops i40e_eth_dev_ops = {
@@ -521,7 +541,6 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
        .timesync_adjust_time         = i40e_timesync_adjust_time,
        .timesync_read_time           = i40e_timesync_read_time,
        .timesync_write_time          = i40e_timesync_write_time,
-       .get_reg_length               = i40e_get_reg_length,
        .get_reg                      = i40e_get_regs,
        .get_eeprom_length            = i40e_get_eeprom_length,
        .get_eeprom                   = i40e_get_eeprom,
@@ -648,6 +667,8 @@ static struct eth_driver rte_i40e_pmd = {
                .id_table = pci_id_i40e_map,
                .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
                        RTE_PCI_DRV_DETACHABLE,
+               .probe = rte_eth_dev_pci_probe,
+               .remove = rte_eth_dev_pci_remove,
        },
        .eth_dev_init = eth_i40e_dev_init,
        .eth_dev_uninit = eth_i40e_dev_uninit,
@@ -682,27 +703,8 @@ rte_i40e_dev_atomic_write_link_status(struct rte_eth_dev *dev,
        return 0;
 }
 
-/*
- * Driver initialization routine.
- * Invoked once at EAL init time.
- * Register itself as the [Poll Mode] Driver of PCI IXGBE devices.
- */
-static int
-rte_i40e_pmd_init(const char *name __rte_unused,
-                 const char *params __rte_unused)
-{
-       PMD_INIT_FUNC_TRACE();
-       rte_eth_driver_register(&rte_i40e_pmd);
-
-       return 0;
-}
-
-static struct rte_driver rte_i40e_driver = {
-       .type = PMD_PDEV,
-       .init = rte_i40e_pmd_init,
-};
-
-PMD_REGISTER_DRIVER(rte_i40e_driver);
+DRIVER_REGISTER_PCI(net_i40e, rte_i40e_pmd.pci_drv);
+DRIVER_REGISTER_PCI_TABLE(net_i40e, pci_id_i40e_map);
 
 /*
  * Initialize registers for flexible payload, which should be set by NVM.
@@ -757,6 +759,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 +1007,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);
 
@@ -2271,7 +2430,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++;
        }
 
@@ -2280,7 +2438,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++;
        }
 
@@ -2290,7 +2447,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++;
                }
        }
@@ -2301,7 +2457,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++;
                }
        }
@@ -2330,7 +2485,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++;
@@ -2338,7 +2492,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++;
@@ -2346,7 +2499,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 +
@@ -2357,7 +2509,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 +
@@ -2459,10 +2610,10 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 
        if (i40e_is_40G_device(hw->device_id))
                /* For XL710 */
-               dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G;
+               dev_info->speed_capa = ETH_LINK_SPEED_40G;
        else
                /* For X710 */
-               dev_info->speed_capa = ETH_LINK_SPEED_10G | ETH_LINK_SPEED_40G;
+               dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G;
 }
 
 static int
@@ -2800,9 +2951,10 @@ i40e_macaddr_add(struct rte_eth_dev *dev,
        int ret;
 
        /* If VMDQ not enabled or configured, return */
-       if (pool != 0 && (!(pf->flags | I40E_FLAG_VMDQ) || !pf->nb_cfg_vmdq_vsi)) {
+       if (pool != 0 && (!(pf->flags & I40E_FLAG_VMDQ) ||
+                         !pf->nb_cfg_vmdq_vsi)) {
                PMD_DRV_LOG(ERR, "VMDQ not %s, can't set mac to pool %u",
-                       pf->flags | I40E_FLAG_VMDQ ? "configured" : "enabled",
+                       pf->flags & I40E_FLAG_VMDQ ? "configured" : "enabled",
                        pool);
                return;
        }
@@ -2853,7 +3005,7 @@ i40e_macaddr_remove(struct rte_eth_dev *dev, uint32_t index)
                                vsi = pf->main_vsi;
                        else {
                                /* No VMDQ pool enabled or configured */
-                               if (!(pf->flags | I40E_FLAG_VMDQ) ||
+                               if (!(pf->flags & I40E_FLAG_VMDQ) ||
                                        (i > pf->nb_cfg_vmdq_vsi)) {
                                        PMD_DRV_LOG(ERR, "No VMDQ pool enabled"
                                                        "/configured");
@@ -3015,13 +3167,16 @@ i40e_get_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size)
 static int
 i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size)
 {
-       struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
-       struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+       struct i40e_pf *pf;
+       struct i40e_hw *hw;
        int ret;
 
        if (!vsi || !lut)
                return -EINVAL;
 
+       pf = I40E_VSI_TO_PF(vsi);
+       hw = I40E_VSI_TO_HW(vsi);
+
        if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
                ret = i40e_aq_set_rss_lut(hw, vsi->vsi_id, TRUE,
                                          lut, lut_size);
@@ -3921,6 +4076,7 @@ i40e_vsi_release(struct i40e_vsi *vsi)
        struct i40e_pf *pf;
        struct i40e_hw *hw;
        struct i40e_vsi_list *vsi_list;
+       void *temp;
        int ret;
        struct i40e_mac_filter *f;
        uint16_t user_param = vsi->user_param;
@@ -3933,25 +4089,23 @@ i40e_vsi_release(struct i40e_vsi *vsi)
 
        /* VSI has child to attach, release child first */
        if (vsi->veb) {
-               TAILQ_FOREACH(vsi_list, &vsi->veb->head, list) {
+               TAILQ_FOREACH_SAFE(vsi_list, &vsi->veb->head, list, temp) {
                        if (i40e_vsi_release(vsi_list->vsi) != I40E_SUCCESS)
                                return -1;
-                       TAILQ_REMOVE(&vsi->veb->head, vsi_list, list);
                }
                i40e_veb_release(vsi->veb);
        }
 
        if (vsi->floating_veb) {
-               TAILQ_FOREACH(vsi_list, &vsi->floating_veb->head, list) {
+               TAILQ_FOREACH_SAFE(vsi_list, &vsi->floating_veb->head, list, temp) {
                        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)
+       TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp)
                rte_free(f);
 
        if (vsi->type != I40E_VSI_MAIN &&
@@ -4509,6 +4663,7 @@ i40e_vsi_config_vlan_filter(struct i40e_vsi *vsi, bool on)
 {
        int i, num;
        struct i40e_mac_filter *f;
+       void *temp;
        struct i40e_mac_filter_info *mac_filter;
        enum rte_mac_filter_type desired_filter;
        int ret = I40E_SUCCESS;
@@ -4533,7 +4688,7 @@ i40e_vsi_config_vlan_filter(struct i40e_vsi *vsi, bool on)
        i = 0;
 
        /* Remove all existing mac */
-       TAILQ_FOREACH(f, &vsi->mac_list, next) {
+       TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
                mac_filter[i] = f->mac_info;
                ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
                if (ret) {
@@ -6752,6 +6907,9 @@ i40e_get_hash_filter_global_config(struct i40e_hw *hw,
                mask &= ~(1UL << i);
                /* Bit set indicats the coresponding flow type is supported */
                g_cfg->valid_bit_mask[0] |= (1UL << i);
+               /* if flowtype is invalid, continue */
+               if (!I40E_VALID_FLOW(i))
+                       continue;
                pctype = i40e_flowtype_to_pctype(i);
                reg = i40e_read_rx_ctl(hw, I40E_GLQF_HSYM(pctype));
                if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
@@ -6823,6 +6981,9 @@ i40e_set_hash_filter_global_config(struct i40e_hw *hw,
                if (!(mask0 & (1UL << i)))
                        continue;
                mask0 &= ~(1UL << i);
+               /* if flowtype is invalid, continue */
+               if (!I40E_VALID_FLOW(i))
+                       continue;
                pctype = i40e_flowtype_to_pctype(i);
                reg = (g_cfg->sym_hash_enable_mask[0] & (1UL << i)) ?
                                I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
@@ -7385,13 +7546,11 @@ i40e_hash_filter_inset_select(struct i40e_hw *hw,
                return -EINVAL;
        }
 
-       pctype = i40e_flowtype_to_pctype(conf->flow_type);
-       if (pctype == 0 || pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD) {
-               PMD_DRV_LOG(ERR, "Not supported flow type (%u)",
-                           conf->flow_type);
+       if (!I40E_VALID_FLOW(conf->flow_type)) {
+               PMD_DRV_LOG(ERR, "invalid flow_type input.");
                return -EINVAL;
        }
-
+       pctype = i40e_flowtype_to_pctype(conf->flow_type);
        ret = i40e_parse_input_set(&input_set, pctype, conf->field,
                                   conf->inset_size);
        if (ret) {
@@ -7456,12 +7615,11 @@ i40e_fdir_filter_inset_select(struct i40e_pf *pf,
                return -EINVAL;
        }
 
-       pctype = i40e_flowtype_to_pctype(conf->flow_type);
-       if (pctype == 0 || pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD) {
-               PMD_DRV_LOG(ERR, "Not supported flow type (%u)",
-                           conf->flow_type);
+       if (!I40E_VALID_FLOW(conf->flow_type)) {
+               PMD_DRV_LOG(ERR, "invalid flow_type input.");
                return -EINVAL;
        }
+       pctype = i40e_flowtype_to_pctype(conf->flow_type);
        ret = i40e_parse_input_set(&input_set, pctype, conf->field,
                                   conf->inset_size);
        if (ret) {
@@ -9190,12 +9348,6 @@ i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
        return 0;
 }
 
-static int i40e_get_reg_length(__rte_unused struct rte_eth_dev *dev)
-{
-       /* Highest base addr + 32-bit word */
-       return I40E_GLGEN_STAT_CLEAR + 4;
-}
-
 static int i40e_get_regs(struct rte_eth_dev *dev,
                         struct rte_dev_reg_info *regs)
 {
@@ -9204,6 +9356,12 @@ static int i40e_get_regs(struct rte_eth_dev *dev,
        uint32_t reg_idx, arr_idx, arr_idx2, reg_offset;
        const struct i40e_reg_info *reg_info;
 
+       if (ptr_data == NULL) {
+               regs->length = I40E_GLGEN_STAT_CLEAR + 4;
+               regs->width = sizeof(uint32_t);
+               return 0;
+       }
+
        /* The first few registers have to be read using AQ operations */
        reg_idx = 0;
        while (i40e_regs_adminq[reg_idx].name) {