nfp: add ethtool statistics for representors

Representors may be associated with both VFs or more importantly
with physical ports.  Allow vNIC and MAC statistics to be read
with ethtool -S on representors.  In case of vNICs we reuse
the vNIC statistic helper, we just need to swap RX and TX to
give statistics the "switch perspective."

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2017-08-18 15:48:20 -07:00 committed by David S. Miller
parent ef0ec676a7
commit 899a37ade8
2 changed files with 71 additions and 4 deletions

View file

@ -180,6 +180,7 @@ static const struct nfp_et_stat nfp_mac_et_stats[] = {
};
#define NN_ET_GLOBAL_STATS_LEN ARRAY_SIZE(nfp_net_et_stats)
#define NN_ET_SWITCH_STATS_LEN 9
#define NN_ET_RVEC_GATHER_STATS 7
static void nfp_net_get_nspinfo(struct nfp_app *app, char *version)
@ -497,11 +498,24 @@ nfp_vnic_get_hw_stats_count(unsigned int rx_rings, unsigned int tx_rings)
static u8 *
nfp_vnic_get_hw_stats_strings(u8 *data, unsigned int rx_rings,
unsigned int tx_rings)
unsigned int tx_rings, bool repr)
{
int i;
int swap_off, i;
for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++)
BUILD_BUG_ON(NN_ET_GLOBAL_STATS_LEN < NN_ET_SWITCH_STATS_LEN * 2);
/* If repr is true first add SWITCH_STATS_LEN and then subtract it
* effectively swapping the RX and TX statistics (giving us the RX
* and TX from perspective of the switch).
*/
swap_off = repr * NN_ET_SWITCH_STATS_LEN;
for (i = 0; i < NN_ET_SWITCH_STATS_LEN; i++)
data = nfp_pr_et(data, nfp_net_et_stats[i + swap_off].name);
for (i = NN_ET_SWITCH_STATS_LEN; i < NN_ET_SWITCH_STATS_LEN * 2; i++)
data = nfp_pr_et(data, nfp_net_et_stats[i - swap_off].name);
for (i = NN_ET_SWITCH_STATS_LEN * 2; i < NN_ET_GLOBAL_STATS_LEN; i++)
data = nfp_pr_et(data, nfp_net_et_stats[i].name);
for (i = 0; i < tx_rings; i++) {
@ -589,7 +603,8 @@ static void nfp_net_get_strings(struct net_device *netdev,
case ETH_SS_STATS:
data = nfp_vnic_get_sw_stats_strings(netdev, data);
data = nfp_vnic_get_hw_stats_strings(data, nn->dp.num_rx_rings,
nn->dp.num_tx_rings);
nn->dp.num_tx_rings,
false);
data = nfp_mac_get_stats_strings(netdev, data);
break;
}
@ -622,6 +637,50 @@ static int nfp_net_get_sset_count(struct net_device *netdev, int sset)
}
}
static void nfp_port_get_strings(struct net_device *netdev,
u32 stringset, u8 *data)
{
struct nfp_port *port = nfp_port_from_netdev(netdev);
switch (stringset) {
case ETH_SS_STATS:
if (nfp_port_is_vnic(port))
data = nfp_vnic_get_hw_stats_strings(data, 0, 0, true);
else
data = nfp_mac_get_stats_strings(netdev, data);
break;
}
}
static void
nfp_port_get_stats(struct net_device *netdev, struct ethtool_stats *stats,
u64 *data)
{
struct nfp_port *port = nfp_port_from_netdev(netdev);
if (nfp_port_is_vnic(port))
data = nfp_vnic_get_hw_stats(data, port->vnic, 0, 0);
else
data = nfp_mac_get_stats(netdev, data);
}
static int nfp_port_get_sset_count(struct net_device *netdev, int sset)
{
struct nfp_port *port = nfp_port_from_netdev(netdev);
unsigned int count;
switch (sset) {
case ETH_SS_STATS:
if (nfp_port_is_vnic(port))
count = nfp_vnic_get_hw_stats_count(0, 0);
else
count = nfp_mac_get_stats_count(netdev);
return count;
default:
return -EOPNOTSUPP;
}
}
/* RX network flow classification (RSS, filters, etc)
*/
static u32 ethtool_flow_to_nfp_flag(u32 flow_type)
@ -1085,6 +1144,9 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
const struct ethtool_ops nfp_port_ethtool_ops = {
.get_drvinfo = nfp_app_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_strings = nfp_port_get_strings,
.get_ethtool_stats = nfp_port_get_stats,
.get_sset_count = nfp_port_get_sset_count,
.set_dump = nfp_app_set_dump,
.get_dump_flag = nfp_app_get_dump_flag,
.get_dump_data = nfp_app_get_dump_data,

View file

@ -116,6 +116,11 @@ extern const struct switchdev_ops nfp_port_switchdev_ops;
int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data);
static inline bool nfp_port_is_vnic(const struct nfp_port *port)
{
return port->type == NFP_PORT_PF_PORT || port->type == NFP_PORT_VF_PORT;
}
struct nfp_port *nfp_port_from_netdev(struct net_device *netdev);
struct nfp_port *
nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id);