net/sfc: add kvarg control for MAC statistics update period
authorIvan Malov <ivan.malov@oktetlabs.ru>
Thu, 9 Mar 2017 17:22:59 +0000 (17:22 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 4 Apr 2017 16:59:40 +0000 (18:59 +0200)
The patch is to make MAC statistics update interval tunable
by means of 'stats_update_period_ms' kvarg parameter making
it possible to use values different from 1000 ms in case of
SFN8xxx boards provided that firmware version is 6.2.1.1033

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andrew Lee <alee@solarflare.com>
doc/guides/nics/sfc_efx.rst
drivers/net/sfc/sfc.h
drivers/net/sfc/sfc_ethdev.c
drivers/net/sfc/sfc_kvargs.c
drivers/net/sfc/sfc_kvargs.h
drivers/net/sfc/sfc_port.c

index 8229d7d..c02e1be 100644 (file)
@@ -242,3 +242,12 @@ boolean parameters value.
   Enable extra logging of the communication with the NIC's management CPU.
   The logging is done using RTE_LOG() with INFO level and PMD type.
   The format is consumed by the Solarflare netlogdecode cross-platform tool.
+
+- ``stats_update_period_ms`` [long] (default **1000**)
+
+  Adjust period in milliseconds to update port hardware statistics.
+  The accepted range is 0 to 65535. The value of **0** may be used
+  to disable periodic statistics update. One should note that it's
+  only possible to set an arbitrary value on SFN8xxx provided that
+  firmware version is 6.2.1.1033 or higher, otherwise any positive
+  value will select a fixed update period of **1000** milliseconds
index 6aeeda5..ca39df0 100644 (file)
@@ -160,6 +160,8 @@ struct sfc_port {
        uint64_t                        *mac_stats_buf;
        efsys_mem_t                     mac_stats_dma_mem;
        boolean_t                       mac_stats_reset_pending;
+       uint16_t                        mac_stats_update_period_ms;
+       uint32_t                        mac_stats_update_generation;
 
        uint32_t                mac_stats_mask[EFX_MAC_STATS_MASK_NPAGES];
 };
index e84731a..834ec67 100644 (file)
@@ -1436,5 +1436,6 @@ RTE_PMD_REGISTER_PCI_TABLE(net_sfc_efx, pci_id_sfc_efx_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_sfc_efx, "* igb_uio | uio_pci_generic | vfio");
 RTE_PMD_REGISTER_PARAM_STRING(net_sfc_efx,
        SFC_KVARG_PERF_PROFILE "=" SFC_KVARG_VALUES_PERF_PROFILE " "
+       SFC_KVARG_STATS_UPDATE_PERIOD_MS "=<long> "
        SFC_KVARG_MCDI_LOGGING "=" SFC_KVARG_VALUES_BOOL " "
        SFC_KVARG_DEBUG_INIT "=" SFC_KVARG_VALUES_BOOL);
index 227a8db..60a7ac1 100644 (file)
@@ -42,6 +42,7 @@ sfc_kvargs_parse(struct sfc_adapter *sa)
        struct rte_eth_dev *eth_dev = (sa)->eth_dev;
        struct rte_devargs *devargs = eth_dev->device->devargs;
        const char **params = (const char *[]){
+               SFC_KVARG_STATS_UPDATE_PERIOD_MS,
                SFC_KVARG_DEBUG_INIT,
                SFC_KVARG_MCDI_LOGGING,
                SFC_KVARG_PERF_PROFILE,
@@ -110,3 +111,22 @@ sfc_kvarg_bool_handler(__rte_unused const char *key,
 
        return 0;
 }
+
+int
+sfc_kvarg_long_handler(__rte_unused const char *key,
+                      const char *value_str, void *opaque)
+{
+       long value;
+       char *endptr;
+
+       if (!value_str || !opaque)
+               return -EINVAL;
+
+       value = strtol(value_str, &endptr, 0);
+       if (endptr == value_str)
+               return -EINVAL;
+
+       *(long *)opaque = value;
+
+       return 0;
+}
index 2fea9c7..6c6003a 100644 (file)
@@ -52,6 +52,8 @@ extern "C" {
            SFC_KVARG_PERF_PROFILE_THROUGHPUT "|" \
            SFC_KVARG_PERF_PROFILE_LOW_LATENCY "]"
 
+#define SFC_KVARG_STATS_UPDATE_PERIOD_MS       "stats_update_period_ms"
+
 struct sfc_adapter;
 
 int sfc_kvargs_parse(struct sfc_adapter *sa);
@@ -63,6 +65,9 @@ int sfc_kvargs_process(struct sfc_adapter *sa, const char *key_match,
 int sfc_kvarg_bool_handler(const char *key, const char *value_str,
                           void *opaque);
 
+int sfc_kvarg_long_handler(const char *key, const char *value_str,
+                          void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
index e77848d..be75480 100644 (file)
 
 #include "sfc.h"
 #include "sfc_log.h"
+#include "sfc_kvargs.h"
+
+/** Default MAC statistics update period is 1 second */
+#define SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF     MS_PER_S
+
+/** The number of microseconds to sleep on attempt to get statistics update */
+#define SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US 10
+
+/** The number of attempts to await arrival of freshly generated statistics */
+#define SFC_MAC_STATS_UPDATE_NB_ATTEMPTS       50
 
 /**
  * Update MAC statistics in the buffer.
@@ -46,6 +56,10 @@ int
 sfc_port_update_mac_stats(struct sfc_adapter *sa)
 {
        struct sfc_port *port = &sa->port;
+       efsys_mem_t *esmp = &port->mac_stats_dma_mem;
+       uint32_t *genp = NULL;
+       uint32_t gen_old;
+       unsigned int nb_attempts = 0;
        int rc;
 
        SFC_ASSERT(rte_spinlock_is_locked(&port->mac_stats_lock));
@@ -53,10 +67,27 @@ sfc_port_update_mac_stats(struct sfc_adapter *sa)
        if (sa->state != SFC_ADAPTER_STARTED)
                return EINVAL;
 
-       rc = efx_mac_stats_update(sa->nic, &port->mac_stats_dma_mem,
-                                 port->mac_stats_buf, NULL);
-       if (rc != 0)
-               return rc;
+       /* If periodic statistics DMA'ing is off, request explicitly */
+       if (port->mac_stats_update_period_ms == 0) {
+               rc = efx_mac_stats_upload(sa->nic, esmp);
+               if (rc != 0)
+                       return rc;
+
+               genp = &port->mac_stats_update_generation;
+               gen_old = *genp;
+       }
+
+       do {
+               if (nb_attempts > 0)
+                       rte_delay_us(SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US);
+
+               rc = efx_mac_stats_update(sa->nic, esmp,
+                                         port->mac_stats_buf, genp);
+               if (rc != 0)
+                       return rc;
+
+       } while ((genp != NULL) && (*genp == gen_old) &&
+                (++nb_attempts < SFC_MAC_STATS_UPDATE_NB_ATTEMPTS));
 
        return 0;
 }
@@ -171,15 +202,22 @@ sfc_port_start(struct sfc_adapter *sa)
        efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
                               sizeof(port->mac_stats_mask));
 
-       /* Update MAC stats using periodic DMA.
-        * Common code always uses 1000ms update period, so period_ms
-        * parameter only needs to be non-zero to start updates.
-        */
-       sfc_log_init(sa, "request MAC stats DMA'ing");
-       rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
-                                   1000, B_FALSE);
-       if (rc != 0)
-               goto fail_mac_stats_periodic;
+       port->mac_stats_update_generation = 0;
+
+       if (port->mac_stats_update_period_ms != 0) {
+               /*
+                * Update MAC stats using periodic DMA;
+                * any positive update interval different from
+                * 1000 ms can be set only on SFN8xxx provided
+                * that FW version is 6.2.1.1033 or higher
+                */
+               sfc_log_init(sa, "request MAC stats DMA'ing");
+               rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
+                                           port->mac_stats_update_period_ms,
+                                           B_FALSE);
+               if (rc != 0)
+                       goto fail_mac_stats_periodic;
+       }
 
        sfc_log_init(sa, "disable MAC drain");
        rc = efx_mac_drain(sa->nic, B_FALSE);
@@ -239,6 +277,7 @@ sfc_port_init(struct sfc_adapter *sa)
 {
        const struct rte_eth_dev_data *dev_data = sa->eth_dev->data;
        struct sfc_port *port = &sa->port;
+       long kvarg_stats_update_period_ms;
        int rc;
 
        sfc_log_init(sa, "entry");
@@ -279,9 +318,30 @@ sfc_port_init(struct sfc_adapter *sa)
 
        port->mac_stats_reset_pending = B_FALSE;
 
+       kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
+
+       rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
+                               sfc_kvarg_long_handler,
+                               &kvarg_stats_update_period_ms);
+       if ((rc == 0) &&
+           ((kvarg_stats_update_period_ms < 0) ||
+            (kvarg_stats_update_period_ms > UINT16_MAX))) {
+               sfc_err(sa, "wrong '" SFC_KVARG_STATS_UPDATE_PERIOD_MS "' "
+                           "was set (%ld);", kvarg_stats_update_period_ms);
+               sfc_err(sa, "it must not be less than 0 "
+                           "or greater than %" PRIu16, UINT16_MAX);
+               rc = EINVAL;
+               goto fail_kvarg_stats_update_period_ms;
+       } else if (rc != 0) {
+               goto fail_kvarg_stats_update_period_ms;
+       }
+
+       port->mac_stats_update_period_ms = kvarg_stats_update_period_ms;
+
        sfc_log_init(sa, "done");
        return 0;
 
+fail_kvarg_stats_update_period_ms:
 fail_mac_stats_dma_alloc:
        rte_free(port->mac_stats_buf);
 fail_mac_stats_buf_alloc: