From: Arkadiusz Grubba <arkadiusz.gru...@intel.com> This change introduces the ability to display extended (enhanced) statistics for PF interfaces.
The patch introduces new arrays defined for these extra stats (in i40e_ethtool.c file) and enhances/extends ethtool ops functions intended for dealing with PF stats (i.e.: i40e_get_stats_count(), i40e_get_ethtool_stats(), i40e_get_stat_strings() ). There have also been introduced the new build flag named "I40E_PF_EXTRA_STATS_OFF" to exclude from the driver code all code snippets associated with these extra stats. Signed-off-by: Arkadiusz Grubba <arkadiusz.gru...@intel.com> Tested-by: Andrew Bowers <andrewx.bow...@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirs...@intel.com> --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 41e1240acaea..c814c756b4bb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -389,6 +389,7 @@ static const struct i40e_stats i40e_gstrings_pfc_stats[] = { #define I40E_GLOBAL_STATS_LEN ARRAY_SIZE(i40e_gstrings_stats) +/* Length (number) of PF core stats only (i.e. without queues / extra stats): */ #define I40E_PF_STATS_LEN (I40E_GLOBAL_STATS_LEN + \ I40E_PFC_STATS_LEN + \ I40E_VEB_STATS_LEN + \ @@ -397,6 +398,44 @@ static const struct i40e_stats i40e_gstrings_pfc_stats[] = { /* Length of stats for a single queue */ #define I40E_QUEUE_STATS_LEN ARRAY_SIZE(i40e_gstrings_queue_stats) +#define I40E_STATS_NAME_VFID_EXTRA "vf___." +#define I40E_STATS_NAME_VFID_EXTRA_LEN (sizeof(I40E_STATS_NAME_VFID_EXTRA) - 1) + +static struct i40e_stats i40e_gstrings_eth_stats_extra[] = { + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "rx_bytes", eth_stats.rx_bytes), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "rx_unicast", eth_stats.rx_unicast), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "rx_multicast", eth_stats.rx_multicast), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "rx_broadcast", eth_stats.rx_broadcast), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "rx_discards", eth_stats.rx_discards), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "rx_unknown_protocol", eth_stats.rx_unknown_protocol), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "tx_bytes", eth_stats.tx_bytes), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "tx_unicast", eth_stats.tx_unicast), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "tx_multicast", eth_stats.tx_multicast), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "tx_broadcast", eth_stats.tx_broadcast), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "tx_discards", eth_stats.tx_discards), + I40E_VSI_STAT(I40E_STATS_NAME_VFID_EXTRA + "tx_errors", eth_stats.tx_errors), +}; + +#define I40E_STATS_EXTRA_COUNT 128 /* as for now only I40E_MAX_VF_COUNT */ +/* Following length value does not include the length values for queues stats */ +#define I40E_STATS_EXTRA_LEN ARRAY_SIZE(i40e_gstrings_eth_stats_extra) +/* Length (number) of PF extra stats only (i.e. without core stats / queues): */ +#define I40E_PF_STATS_EXTRA_LEN (I40E_STATS_EXTRA_COUNT * I40E_STATS_EXTRA_LEN) +/* Length (number) of enhanced/all PF stats (i.e. core with extra stats): */ +#define I40E_PF_STATS_ENHANCE_LEN (I40E_PF_STATS_LEN + I40E_PF_STATS_EXTRA_LEN) + enum i40e_ethtool_test_id { I40E_ETH_TEST_REG = 0, I40E_ETH_TEST_EEPROM, @@ -2190,6 +2229,9 @@ static int i40e_get_stats_count(struct net_device *netdev) */ stats_len += I40E_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues; + if (vsi == pf->vsi[pf->lan_vsi] && pf->hw.partition_id == 1) + stats_len += I40E_PF_STATS_EXTRA_LEN; + return stats_len; } @@ -2258,6 +2300,10 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; struct i40e_veb *veb = NULL; + unsigned int vsi_idx; + unsigned int vf_idx; + unsigned int vf_id; + bool is_vf_valid; unsigned int i; bool veb_stats; u64 *p = data; @@ -2307,11 +2353,109 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, i40e_add_ethtool_stats(&data, &pfc, i40e_gstrings_pfc_stats); } + /* As for now, we only process the SRIOV type VSIs (as extra stats to + * PF core stats) which are correlated with VF LAN VSI (hence below, + * in this for-loop instruction block, only VF's LAN VSIs are currently + * processed). + */ + for (vf_id = 0; vf_id < pf->num_alloc_vfs; vf_id++) { + is_vf_valid = true; + for (vf_idx = 0; vf_idx < pf->num_alloc_vfs; vf_idx++) + if (pf->vf[vf_idx].vf_id == vf_id) + break; + if (vf_idx >= pf->num_alloc_vfs) { + dev_info(&pf->pdev->dev, + "In the PF's array, there is no VF instance with VF_ID identifier %d or it is not set/initialized correctly yet\n", + vf_id); + is_vf_valid = false; + goto check_vf; + } + vsi_idx = pf->vf[vf_idx].lan_vsi_idx; + + vsi = pf->vsi[vsi_idx]; + if (!vsi) { + /* It means empty field in the PF VSI array... */ + dev_info(&pf->pdev->dev, + "No LAN VSI instance referenced by VF %d or it is not set/initialized correctly yet\n", + vf_id); + is_vf_valid = false; + goto check_vf; + } + if (vsi->vf_id != vf_id) { + dev_info(&pf->pdev->dev, + "In the PF's array, there is incorrectly set/initialized LAN VSI or reference to it from VF %d is not set/initialized correctly yet\n", + vf_id); + is_vf_valid = false; + goto check_vf; + } + if (vsi->vf_id != pf->vf[vf_idx].vf_id || + !i40e_find_vsi_from_id(pf, pf->vf[vsi->vf_id].lan_vsi_id)) { + /* Disjointed identifiers or broken references VF-VSI */ + dev_warn(&pf->pdev->dev, + "SRIOV LAN VSI (index %d in PF VSI array) with invalid VF Identifier %d (referenced by VF %d, ordered as %d in VF array)\n", + vsi_idx, pf->vsi[vsi_idx]->vf_id, + pf->vf[vf_idx].vf_id, vf_idx); + is_vf_valid = false; + } +check_vf: + if (!is_vf_valid) { + i40e_add_ethtool_stats(&data, NULL, + i40e_gstrings_eth_stats_extra); + } else { + i40e_update_eth_stats(vsi); + i40e_add_ethtool_stats(&data, vsi, + i40e_gstrings_eth_stats_extra); + } + } + for (; vf_id < I40E_STATS_EXTRA_COUNT; vf_id++) + i40e_add_ethtool_stats(&data, NULL, + i40e_gstrings_eth_stats_extra); + check_data_pointer: WARN_ONCE(data - p != i40e_get_stats_count(netdev), "ethtool stats count mismatch!"); } +/** + * __i40e_update_vfid_in_stats_strings - print VF num to stats names + * @stats_extra: array of stats structs with stats name strings + * @strings_num: number of stats name strings in array above (length) + * @vf_id: VF number to update stats name strings with + * + * Helper function to i40e_get_stat_strings() in case of extra stats. + **/ +static inline void +__i40e_update_vfid_in_stats_strings(struct i40e_stats stats_extra[], + int strings_num, int vf_id) +{ + int i; + + for (i = 0; i < strings_num; i++) { + snprintf(stats_extra[i].stat_string, + I40E_STATS_NAME_VFID_EXTRA_LEN, "vf%03d", vf_id); + stats_extra[i].stat_string[I40E_STATS_NAME_VFID_EXTRA_LEN - + 1] = '.'; + } +} + +/** + * i40e_update_vfid_in_stats - print VF num to stat names + * @stats_extra: array of stats structs with stats name strings + * @vf_id: VF number to update stats name strings with + * + * Helper macro to i40e_get_stat_strings() to ease use of + * __i40e_update_vfid_in_stats_strings() function due to extra stats. + * + * Macro to ease the use of __i40e_update_vfid_in_stats_strings by taking + * a static constant stats array and passing the ARRAY_SIZE(). This avoids typos + * by ensuring that we pass the size associated with the given stats array. + * + * The parameter @stats_extra is evaluated twice, so parameters with side + * effects should be avoided. + **/ +#define i40e_update_vfid_in_stats(stats_extra, vf_id) \ +__i40e_update_vfid_in_stats_strings(stats_extra, ARRAY_SIZE(stats_extra), vf_id) + /** * i40e_get_stat_strings - copy stat strings into supplied buffer * @netdev: the netdev to collect strings for @@ -2354,6 +2498,11 @@ static void i40e_get_stat_strings(struct net_device *netdev, u8 *data) for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) i40e_add_stat_strings(&data, i40e_gstrings_pfc_stats, i); + for (i = 0; i < I40E_STATS_EXTRA_COUNT; i++) { + i40e_update_vfid_in_stats(i40e_gstrings_eth_stats_extra, i); + i40e_add_stat_strings(&data, i40e_gstrings_eth_stats_extra); + } + check_data_pointer: WARN_ONCE(data - p != i40e_get_stats_count(netdev) * ETH_GSTRING_LEN, "stat strings count mismatch!"); -- 2.21.0