fm10k: add helper functions to set strings and data for ethtool stats
[cascardo/linux.git] / drivers / net / ethernet / intel / fm10k / fm10k_ethtool.c
index 2f6a05b..f331966 100644 (file)
@@ -121,13 +121,22 @@ static const struct fm10k_stats fm10k_gstrings_mbx_stats[] = {
        FM10K_MBX_STAT("mbx_rx_mbmem_pushed", rx_mbmem_pushed),
 };
 
+#define FM10K_QUEUE_STAT(_name, _stat) { \
+       .stat_string = _name, \
+       .sizeof_stat = FIELD_SIZEOF(struct fm10k_ring, _stat), \
+       .stat_offset = offsetof(struct fm10k_ring, _stat) \
+}
+
+static const struct fm10k_stats fm10k_gstrings_queue_stats[] = {
+       FM10K_QUEUE_STAT("packets", stats.packets),
+       FM10K_QUEUE_STAT("bytes", stats.bytes),
+};
+
 #define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats)
 #define FM10K_DEBUG_STATS_LEN ARRAY_SIZE(fm10k_gstrings_debug_stats)
 #define FM10K_PF_STATS_LEN ARRAY_SIZE(fm10k_gstrings_pf_stats)
 #define FM10K_MBX_STATS_LEN ARRAY_SIZE(fm10k_gstrings_mbx_stats)
-
-#define FM10K_QUEUE_STATS_LEN(_n) \
-       ((_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64)))
+#define FM10K_QUEUE_STATS_LEN ARRAY_SIZE(fm10k_gstrings_queue_stats)
 
 #define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \
                                FM10K_NETDEV_STATS_LEN + \
@@ -153,69 +162,66 @@ static const char fm10k_prv_flags[FM10K_PRV_FLAG_LEN][ETH_GSTRING_LEN] = {
        "debug-statistics",
 };
 
+static void fm10k_add_stat_strings(char **p, const char *prefix,
+                                  const struct fm10k_stats stats[],
+                                  const unsigned int size)
+{
+       unsigned int i;
+
+       for (i = 0; i < size; i++) {
+               snprintf(*p, ETH_GSTRING_LEN, "%s%s",
+                        prefix, stats[i].stat_string);
+               *p += ETH_GSTRING_LEN;
+       }
+}
+
 static void fm10k_get_stat_strings(struct net_device *dev, u8 *data)
 {
        struct fm10k_intfc *interface = netdev_priv(dev);
        struct fm10k_iov_data *iov_data = interface->iov_data;
        char *p = (char *)data;
        unsigned int i;
-       unsigned int j;
 
-       for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) {
-               memcpy(p, fm10k_gstrings_net_stats[i].stat_string,
-                      ETH_GSTRING_LEN);
-               p += ETH_GSTRING_LEN;
-       }
+       fm10k_add_stat_strings(&p, "", fm10k_gstrings_net_stats,
+                              FM10K_NETDEV_STATS_LEN);
 
-       for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) {
-               memcpy(p, fm10k_gstrings_global_stats[i].stat_string,
-                      ETH_GSTRING_LEN);
-               p += ETH_GSTRING_LEN;
-       }
+       fm10k_add_stat_strings(&p, "", fm10k_gstrings_global_stats,
+                              FM10K_GLOBAL_STATS_LEN);
 
-       if (interface->flags & FM10K_FLAG_DEBUG_STATS) {
-               for (i = 0; i < FM10K_DEBUG_STATS_LEN; i++) {
-                       memcpy(p, fm10k_gstrings_debug_stats[i].stat_string,
-                              ETH_GSTRING_LEN);
-                       p += ETH_GSTRING_LEN;
-               }
-       }
+       if (interface->flags & FM10K_FLAG_DEBUG_STATS)
+               fm10k_add_stat_strings(&p, "", fm10k_gstrings_debug_stats,
+                                      FM10K_DEBUG_STATS_LEN);
 
-       for (i = 0; i < FM10K_MBX_STATS_LEN; i++) {
-               memcpy(p, fm10k_gstrings_mbx_stats[i].stat_string,
-                      ETH_GSTRING_LEN);
-               p += ETH_GSTRING_LEN;
-       }
+       fm10k_add_stat_strings(&p, "", fm10k_gstrings_mbx_stats,
+                              FM10K_MBX_STATS_LEN);
 
-       if (interface->hw.mac.type != fm10k_mac_vf) {
-               for (i = 0; i < FM10K_PF_STATS_LEN; i++) {
-                       memcpy(p, fm10k_gstrings_pf_stats[i].stat_string,
-                              ETH_GSTRING_LEN);
-                       p += ETH_GSTRING_LEN;
-               }
-       }
+       if (interface->hw.mac.type != fm10k_mac_vf)
+               fm10k_add_stat_strings(&p, "", fm10k_gstrings_pf_stats,
+                                      FM10K_PF_STATS_LEN);
 
        if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) {
                for (i = 0; i < iov_data->num_vfs; i++) {
-                       for (j = 0; j < FM10K_MBX_STATS_LEN; j++) {
-                               snprintf(p,
-                                        ETH_GSTRING_LEN,
-                                        "vf_%u_%s", i,
-                                        fm10k_gstrings_mbx_stats[j].stat_string);
-                               p += ETH_GSTRING_LEN;
-                       }
+                       char prefix[ETH_GSTRING_LEN];
+
+                       snprintf(prefix, ETH_GSTRING_LEN, "vf_%u_", i);
+                       fm10k_add_stat_strings(&p, prefix,
+                                              fm10k_gstrings_mbx_stats,
+                                              FM10K_MBX_STATS_LEN);
                }
        }
 
        for (i = 0; i < interface->hw.mac.max_queues; i++) {
-               snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_packets", i);
-               p += ETH_GSTRING_LEN;
-               snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_bytes", i);
-               p += ETH_GSTRING_LEN;
-               snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_packets", i);
-               p += ETH_GSTRING_LEN;
-               snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_bytes", i);
-               p += ETH_GSTRING_LEN;
+               char prefix[ETH_GSTRING_LEN];
+
+               snprintf(prefix, ETH_GSTRING_LEN, "tx_queue_%u_", i);
+               fm10k_add_stat_strings(&p, prefix,
+                                      fm10k_gstrings_queue_stats,
+                                      FM10K_QUEUE_STATS_LEN);
+
+               snprintf(prefix, ETH_GSTRING_LEN, "rx_queue_%u_", i);
+               fm10k_add_stat_strings(&p, prefix,
+                                      fm10k_gstrings_queue_stats,
+                                      FM10K_QUEUE_STATS_LEN);
        }
 }
 
@@ -250,7 +256,7 @@ static int fm10k_get_sset_count(struct net_device *dev, int sset)
        case ETH_SS_TEST:
                return FM10K_TEST_LEN;
        case ETH_SS_STATS:
-               stats_len += FM10K_QUEUE_STATS_LEN(hw->mac.max_queues);
+               stats_len += hw->mac.max_queues * 2 * FM10K_QUEUE_STATS_LEN;
 
                if (hw->mac.type != fm10k_mac_vf)
                        stats_len += FM10K_PF_STATS_LEN;
@@ -271,55 +277,72 @@ static int fm10k_get_sset_count(struct net_device *dev, int sset)
        }
 }
 
+static void fm10k_add_ethtool_stats(u64 **data, void *pointer,
+                                   const struct fm10k_stats stats[],
+                                   const unsigned int size)
+{
+       unsigned int i;
+       char *p;
+
+       if (!pointer) {
+               /* memory is not zero allocated so we have to clear it */
+               for (i = 0; i < size; i++)
+                       *((*data)++) = 0;
+               return;
+       }
+
+       for (i = 0; i < size; i++) {
+               p = (char *)pointer + stats[i].stat_offset;
+
+               switch (stats[i].sizeof_stat) {
+               case sizeof(u64):
+                       *((*data)++) = *(u64 *)p;
+                       break;
+               case sizeof(u32):
+                       *((*data)++) = *(u32 *)p;
+                       break;
+               case sizeof(u16):
+                       *((*data)++) = *(u16 *)p;
+                       break;
+               case sizeof(u8):
+                       *((*data)++) = *(u8 *)p;
+                       break;
+               default:
+                       *((*data)++) = 0;
+               }
+       }
+}
+
 static void fm10k_get_ethtool_stats(struct net_device *netdev,
                                    struct ethtool_stats __always_unused *stats,
                                    u64 *data)
 {
-       const int stat_count = sizeof(struct fm10k_queue_stats) / sizeof(u64);
        struct fm10k_intfc *interface = netdev_priv(netdev);
        struct fm10k_iov_data *iov_data = interface->iov_data;
        struct net_device_stats *net_stats = &netdev->stats;
-       char *p;
-       int i, j;
+       int i;
 
        fm10k_update_stats(interface);
 
-       for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) {
-               p = (char *)net_stats + fm10k_gstrings_net_stats[i].stat_offset;
-               *(data++) = (fm10k_gstrings_net_stats[i].sizeof_stat ==
-                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-       }
+       fm10k_add_ethtool_stats(&data, net_stats, fm10k_gstrings_net_stats,
+                               FM10K_NETDEV_STATS_LEN);
 
-       for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) {
-               p = (char *)interface +
-                   fm10k_gstrings_global_stats[i].stat_offset;
-               *(data++) = (fm10k_gstrings_global_stats[i].sizeof_stat ==
-                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-       }
+       fm10k_add_ethtool_stats(&data, interface, fm10k_gstrings_global_stats,
+                               FM10K_GLOBAL_STATS_LEN);
 
-       if (interface->flags & FM10K_FLAG_DEBUG_STATS) {
-               for (i = 0; i < FM10K_DEBUG_STATS_LEN; i++) {
-                       p = (char *)interface +
-                               fm10k_gstrings_debug_stats[i].stat_offset;
-                       *(data++) = (fm10k_gstrings_debug_stats[i].sizeof_stat ==
-                                    sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-               }
-       }
+       if (interface->flags & FM10K_FLAG_DEBUG_STATS)
+               fm10k_add_ethtool_stats(&data, interface,
+                                       fm10k_gstrings_debug_stats,
+                                       FM10K_DEBUG_STATS_LEN);
 
-       for (i = 0; i < FM10K_MBX_STATS_LEN; i++) {
-               p = (char *)&interface->hw.mbx +
-                       fm10k_gstrings_mbx_stats[i].stat_offset;
-               *(data++) = (fm10k_gstrings_mbx_stats[i].sizeof_stat ==
-                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-       }
+       fm10k_add_ethtool_stats(&data, &interface->hw.mbx,
+                               fm10k_gstrings_mbx_stats,
+                               FM10K_MBX_STATS_LEN);
 
        if (interface->hw.mac.type != fm10k_mac_vf) {
-               for (i = 0; i < FM10K_PF_STATS_LEN; i++) {
-                       p = (char *)interface +
-                           fm10k_gstrings_pf_stats[i].stat_offset;
-                       *(data++) = (fm10k_gstrings_pf_stats[i].sizeof_stat ==
-                                    sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-               }
+               fm10k_add_ethtool_stats(&data, interface,
+                                       fm10k_gstrings_pf_stats,
+                                       FM10K_PF_STATS_LEN);
        }
 
        if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) {
@@ -328,36 +351,24 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev,
 
                        vf_info = &iov_data->vf_info[i];
 
-                       /* skip stats if we don't have a vf info */
-                       if (!vf_info) {
-                               data += FM10K_MBX_STATS_LEN;
-                               continue;
-                       }
-
-                       for (j = 0; j < FM10K_MBX_STATS_LEN; j++) {
-                               p = (char *)&vf_info->mbx +
-                                       fm10k_gstrings_mbx_stats[j].stat_offset;
-                               *(data++) = (fm10k_gstrings_mbx_stats[j].sizeof_stat ==
-                                            sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-                       }
+                       fm10k_add_ethtool_stats(&data, &vf_info->mbx,
+                                               fm10k_gstrings_mbx_stats,
+                                               FM10K_MBX_STATS_LEN);
                }
        }
 
        for (i = 0; i < interface->hw.mac.max_queues; i++) {
                struct fm10k_ring *ring;
-               u64 *queue_stat;
 
                ring = interface->tx_ring[i];
-               if (ring)
-                       queue_stat = (u64 *)&ring->stats;
-               for (j = 0; j < stat_count; j++)
-                       *(data++) = ring ? queue_stat[j] : 0;
+               fm10k_add_ethtool_stats(&data, ring,
+                                       fm10k_gstrings_queue_stats,
+                                       FM10K_QUEUE_STATS_LEN);
 
                ring = interface->rx_ring[i];
-               if (ring)
-                       queue_stat = (u64 *)&ring->stats;
-               for (j = 0; j < stat_count; j++)
-                       *(data++) = ring ? queue_stat[j] : 0;
+               fm10k_add_ethtool_stats(&data, ring,
+                                       fm10k_gstrings_queue_stats,
+                                       FM10K_QUEUE_STATS_LEN);
        }
 }
 
@@ -425,7 +436,7 @@ static void fm10k_get_regs(struct net_device *netdev,
        u32 *buff = p;
        u16 i;
 
-       regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
+       regs->version = BIT(24) | (hw->revision_id << 16) | hw->device_id;
 
        switch (hw->mac.type) {
        case fm10k_mac_pf:
@@ -935,15 +946,15 @@ static int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data)
        struct fm10k_mbx_info *mbx = &hw->mbx;
        u32 attr_flag, test_msg[6];
        unsigned long timeout;
-       int err;
+       int err = -EINVAL;
 
        /* For now this is a VF only feature */
        if (hw->mac.type != fm10k_mac_vf)
                return 0;
 
        /* loop through both nested and unnested attribute types */
-       for (attr_flag = (1 << FM10K_TEST_MSG_UNSET);
-            attr_flag < (1 << (2 * FM10K_TEST_MSG_NESTED));
+       for (attr_flag = BIT(FM10K_TEST_MSG_UNSET);
+            attr_flag < BIT(2 * FM10K_TEST_MSG_NESTED);
             attr_flag += attr_flag) {
                /* generate message to be tested */
                fm10k_tlv_msg_test_create(test_msg, attr_flag);
@@ -1005,7 +1016,7 @@ static u32 fm10k_get_priv_flags(struct net_device *netdev)
        u32 priv_flags = 0;
 
        if (interface->flags & FM10K_FLAG_DEBUG_STATS)
-               priv_flags |= 1 << FM10K_PRV_FLAG_DEBUG_STATS;
+               priv_flags |= BIT(FM10K_PRV_FLAG_DEBUG_STATS);
 
        return priv_flags;
 }
@@ -1014,10 +1025,10 @@ static int fm10k_set_priv_flags(struct net_device *netdev, u32 priv_flags)
 {
        struct fm10k_intfc *interface = netdev_priv(netdev);
 
-       if (priv_flags >= (1 << FM10K_PRV_FLAG_LEN))
+       if (priv_flags >= BIT(FM10K_PRV_FLAG_LEN))
                return -EINVAL;
 
-       if (priv_flags & (1 << FM10K_PRV_FLAG_DEBUG_STATS))
+       if (priv_flags & BIT(FM10K_PRV_FLAG_DEBUG_STATS))
                interface->flags |= FM10K_FLAG_DEBUG_STATS;
        else
                interface->flags &= ~FM10K_FLAG_DEBUG_STATS;
@@ -1025,11 +1036,31 @@ static int fm10k_set_priv_flags(struct net_device *netdev, u32 priv_flags)
        return 0;
 }
 
-static u32 fm10k_get_reta_size(struct net_device __always_unused *netdev)
+u32 fm10k_get_reta_size(struct net_device __always_unused *netdev)
 {
        return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG;
 }
 
+void fm10k_write_reta(struct fm10k_intfc *interface, const u32 *indir)
+{
+       struct fm10k_hw *hw = &interface->hw;
+       int i;
+
+       /* record entries to reta table */
+       for (i = 0; i < FM10K_RETA_SIZE; i++, indir += 4) {
+               u32 reta = indir[0] |
+                          (indir[1] << 8) |
+                          (indir[2] << 16) |
+                          (indir[3] << 24);
+
+               if (interface->reta[i] == reta)
+                       continue;
+
+               interface->reta[i] = reta;
+               fm10k_write_reg(hw, FM10K_RETA(0, i), reta);
+       }
+}
+
 static int fm10k_get_reta(struct net_device *netdev, u32 *indir)
 {
        struct fm10k_intfc *interface = netdev_priv(netdev);
@@ -1053,7 +1084,6 @@ static int fm10k_get_reta(struct net_device *netdev, u32 *indir)
 static int fm10k_set_reta(struct net_device *netdev, const u32 *indir)
 {
        struct fm10k_intfc *interface = netdev_priv(netdev);
-       struct fm10k_hw *hw = &interface->hw;
        int i;
        u16 rss_i;
 
@@ -1068,19 +1098,7 @@ static int fm10k_set_reta(struct net_device *netdev, const u32 *indir)
                return -EINVAL;
        }
 
-       /* record entries to reta table */
-       for (i = 0; i < FM10K_RETA_SIZE; i++, indir += 4) {
-               u32 reta = indir[0] |
-                          (indir[1] << 8) |
-                          (indir[2] << 16) |
-                          (indir[3] << 24);
-
-               if (interface->reta[i] == reta)
-                       continue;
-
-               interface->reta[i] = reta;
-               fm10k_write_reg(hw, FM10K_RETA(0, i), reta);
-       }
+       fm10k_write_reta(interface, indir);
 
        return 0;
 }
@@ -1145,7 +1163,7 @@ static unsigned int fm10k_max_channels(struct net_device *dev)
 
        /* For QoS report channels per traffic class */
        if (tcs > 1)
-               max_combined = 1 << (fls(max_combined / tcs) - 1);
+               max_combined = BIT((fls(max_combined / tcs) - 1));
 
        return max_combined;
 }
@@ -1210,11 +1228,9 @@ static int fm10k_get_ts_info(struct net_device *dev,
        else
                info->phc_index = -1;
 
-       info->tx_types = (1 << HWTSTAMP_TX_OFF) |
-                        (1 << HWTSTAMP_TX_ON);
+       info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
 
-       info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
-                          (1 << HWTSTAMP_FILTER_ALL);
+       info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
 
        return 0;
 }