diff options
Diffstat (limited to 'drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c')
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 593 |
1 files changed, 403 insertions, 190 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 6e31355c3567..07969f06df10 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -59,82 +59,129 @@ enum nfp_dump_diag { NFP_DUMP_NSP_DIAG = 0, }; -/* Support for stats. Returns netdev, driver, and device stats */ -enum { NETDEV_ET_STATS, NFP_NET_DRV_ET_STATS, NFP_NET_DEV_ET_STATS }; -struct _nfp_net_et_stats { +struct nfp_et_stat { char name[ETH_GSTRING_LEN]; - int type; - int sz; int off; }; -#define NN_ET_NETDEV_STAT(m) NETDEV_ET_STATS, \ - FIELD_SIZEOF(struct net_device_stats, m), \ - offsetof(struct net_device_stats, m) -/* For stats in the control BAR (other than Q stats) */ -#define NN_ET_DEV_STAT(m) NFP_NET_DEV_ET_STATS, \ - sizeof(u64), \ - (m) -static const struct _nfp_net_et_stats nfp_net_et_stats[] = { - /* netdev stats */ - {"rx_packets", NN_ET_NETDEV_STAT(rx_packets)}, - {"tx_packets", NN_ET_NETDEV_STAT(tx_packets)}, - {"rx_bytes", NN_ET_NETDEV_STAT(rx_bytes)}, - {"tx_bytes", NN_ET_NETDEV_STAT(tx_bytes)}, - {"rx_errors", NN_ET_NETDEV_STAT(rx_errors)}, - {"tx_errors", NN_ET_NETDEV_STAT(tx_errors)}, - {"rx_dropped", NN_ET_NETDEV_STAT(rx_dropped)}, - {"tx_dropped", NN_ET_NETDEV_STAT(tx_dropped)}, - {"multicast", NN_ET_NETDEV_STAT(multicast)}, - {"collisions", NN_ET_NETDEV_STAT(collisions)}, - {"rx_over_errors", NN_ET_NETDEV_STAT(rx_over_errors)}, - {"rx_crc_errors", NN_ET_NETDEV_STAT(rx_crc_errors)}, - {"rx_frame_errors", NN_ET_NETDEV_STAT(rx_frame_errors)}, - {"rx_fifo_errors", NN_ET_NETDEV_STAT(rx_fifo_errors)}, - {"rx_missed_errors", NN_ET_NETDEV_STAT(rx_missed_errors)}, - {"tx_aborted_errors", NN_ET_NETDEV_STAT(tx_aborted_errors)}, - {"tx_carrier_errors", NN_ET_NETDEV_STAT(tx_carrier_errors)}, - {"tx_fifo_errors", NN_ET_NETDEV_STAT(tx_fifo_errors)}, +static const struct nfp_et_stat nfp_net_et_stats[] = { /* Stats from the device */ - {"dev_rx_discards", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_DISCARDS)}, - {"dev_rx_errors", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_ERRORS)}, - {"dev_rx_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_OCTETS)}, - {"dev_rx_uc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_UC_OCTETS)}, - {"dev_rx_mc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_MC_OCTETS)}, - {"dev_rx_bc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_BC_OCTETS)}, - {"dev_rx_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_FRAMES)}, - {"dev_rx_mc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_MC_FRAMES)}, - {"dev_rx_bc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_BC_FRAMES)}, - - {"dev_tx_discards", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_DISCARDS)}, - {"dev_tx_errors", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_ERRORS)}, - {"dev_tx_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_OCTETS)}, - {"dev_tx_uc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_UC_OCTETS)}, - {"dev_tx_mc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_MC_OCTETS)}, - {"dev_tx_bc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_BC_OCTETS)}, - {"dev_tx_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_FRAMES)}, - {"dev_tx_mc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_MC_FRAMES)}, - {"dev_tx_bc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_BC_FRAMES)}, - - {"bpf_pass_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP0_FRAMES)}, - {"bpf_pass_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP0_BYTES)}, + { "dev_rx_discards", NFP_NET_CFG_STATS_RX_DISCARDS }, + { "dev_rx_errors", NFP_NET_CFG_STATS_RX_ERRORS }, + { "dev_rx_bytes", NFP_NET_CFG_STATS_RX_OCTETS }, + { "dev_rx_uc_bytes", NFP_NET_CFG_STATS_RX_UC_OCTETS }, + { "dev_rx_mc_bytes", NFP_NET_CFG_STATS_RX_MC_OCTETS }, + { "dev_rx_bc_bytes", NFP_NET_CFG_STATS_RX_BC_OCTETS }, + { "dev_rx_pkts", NFP_NET_CFG_STATS_RX_FRAMES }, + { "dev_rx_mc_pkts", NFP_NET_CFG_STATS_RX_MC_FRAMES }, + { "dev_rx_bc_pkts", NFP_NET_CFG_STATS_RX_BC_FRAMES }, + + { "dev_tx_discards", NFP_NET_CFG_STATS_TX_DISCARDS }, + { "dev_tx_errors", NFP_NET_CFG_STATS_TX_ERRORS }, + { "dev_tx_bytes", NFP_NET_CFG_STATS_TX_OCTETS }, + { "dev_tx_uc_bytes", NFP_NET_CFG_STATS_TX_UC_OCTETS }, + { "dev_tx_mc_bytes", NFP_NET_CFG_STATS_TX_MC_OCTETS }, + { "dev_tx_bc_bytes", NFP_NET_CFG_STATS_TX_BC_OCTETS }, + { "dev_tx_pkts", NFP_NET_CFG_STATS_TX_FRAMES }, + { "dev_tx_mc_pkts", NFP_NET_CFG_STATS_TX_MC_FRAMES }, + { "dev_tx_bc_pkts", NFP_NET_CFG_STATS_TX_BC_FRAMES }, + + { "bpf_pass_pkts", NFP_NET_CFG_STATS_APP0_FRAMES }, + { "bpf_pass_bytes", NFP_NET_CFG_STATS_APP0_BYTES }, /* see comments in outro functions in nfp_bpf_jit.c to find out * how different BPF modes use app-specific counters */ - {"bpf_app1_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP1_FRAMES)}, - {"bpf_app1_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP1_BYTES)}, - {"bpf_app2_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP2_FRAMES)}, - {"bpf_app2_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP2_BYTES)}, - {"bpf_app3_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP3_FRAMES)}, - {"bpf_app3_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_APP3_BYTES)}, + { "bpf_app1_pkts", NFP_NET_CFG_STATS_APP1_FRAMES }, + { "bpf_app1_bytes", NFP_NET_CFG_STATS_APP1_BYTES }, + { "bpf_app2_pkts", NFP_NET_CFG_STATS_APP2_FRAMES }, + { "bpf_app2_bytes", NFP_NET_CFG_STATS_APP2_BYTES }, + { "bpf_app3_pkts", NFP_NET_CFG_STATS_APP3_FRAMES }, + { "bpf_app3_bytes", NFP_NET_CFG_STATS_APP3_BYTES }, +}; + +static const struct nfp_et_stat nfp_mac_et_stats[] = { + { "rx_octets", NFP_MAC_STATS_RX_IN_OCTETS, }, + { "rx_frame_too_long_errors", + NFP_MAC_STATS_RX_FRAME_TOO_LONG_ERRORS, }, + { "rx_range_length_errors", NFP_MAC_STATS_RX_RANGE_LENGTH_ERRORS, }, + { "rx_vlan_reveive_ok", NFP_MAC_STATS_RX_VLAN_REVEIVE_OK, }, + { "rx_errors", NFP_MAC_STATS_RX_IN_ERRORS, }, + { "rx_broadcast_pkts", NFP_MAC_STATS_RX_IN_BROADCAST_PKTS, }, + { "rx_drop_events", NFP_MAC_STATS_RX_DROP_EVENTS, }, + { "rx_alignment_errors", NFP_MAC_STATS_RX_ALIGNMENT_ERRORS, }, + { "rx_pause_mac_ctrl_frames", + NFP_MAC_STATS_RX_PAUSE_MAC_CTRL_FRAMES, }, + { "rx_frames_received_ok", NFP_MAC_STATS_RX_FRAMES_RECEIVED_OK, }, + { "rx_frame_check_sequence_errors", + NFP_MAC_STATS_RX_FRAME_CHECK_SEQUENCE_ERRORS, }, + { "rx_unicast_pkts", NFP_MAC_STATS_RX_UNICAST_PKTS, }, + { "rx_multicast_pkts", NFP_MAC_STATS_RX_MULTICAST_PKTS, }, + { "rx_pkts", NFP_MAC_STATS_RX_PKTS, }, + { "rx_undersize_pkts", NFP_MAC_STATS_RX_UNDERSIZE_PKTS, }, + { "rx_pkts_64_octets", NFP_MAC_STATS_RX_PKTS_64_OCTETS, }, + { "rx_pkts_65_to_127_octets", + NFP_MAC_STATS_RX_PKTS_65_TO_127_OCTETS, }, + { "rx_pkts_128_to_255_octets", + NFP_MAC_STATS_RX_PKTS_128_TO_255_OCTETS, }, + { "rx_pkts_256_to_511_octets", + NFP_MAC_STATS_RX_PKTS_256_TO_511_OCTETS, }, + { "rx_pkts_512_to_1023_octets", + NFP_MAC_STATS_RX_PKTS_512_TO_1023_OCTETS, }, + { "rx_pkts_1024_to_1518_octets", + NFP_MAC_STATS_RX_PKTS_1024_TO_1518_OCTETS, }, + { "rx_pkts_1519_to_max_octets", + NFP_MAC_STATS_RX_PKTS_1519_TO_MAX_OCTETS, }, + { "rx_jabbers", NFP_MAC_STATS_RX_JABBERS, }, + { "rx_fragments", NFP_MAC_STATS_RX_FRAGMENTS, }, + { "rx_oversize_pkts", NFP_MAC_STATS_RX_OVERSIZE_PKTS, }, + { "rx_pause_frames_class0", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS0, }, + { "rx_pause_frames_class1", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS1, }, + { "rx_pause_frames_class2", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS2, }, + { "rx_pause_frames_class3", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS3, }, + { "rx_pause_frames_class4", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS4, }, + { "rx_pause_frames_class5", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS5, }, + { "rx_pause_frames_class6", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS6, }, + { "rx_pause_frames_class7", NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS7, }, + { "rx_mac_ctrl_frames_received", + NFP_MAC_STATS_RX_MAC_CTRL_FRAMES_RECEIVED, }, + { "rx_mac_head_drop", NFP_MAC_STATS_RX_MAC_HEAD_DROP, }, + { "tx_queue_drop", NFP_MAC_STATS_TX_QUEUE_DROP, }, + { "tx_octets", NFP_MAC_STATS_TX_OUT_OCTETS, }, + { "tx_vlan_transmitted_ok", NFP_MAC_STATS_TX_VLAN_TRANSMITTED_OK, }, + { "tx_errors", NFP_MAC_STATS_TX_OUT_ERRORS, }, + { "tx_broadcast_pkts", NFP_MAC_STATS_TX_BROADCAST_PKTS, }, + { "tx_pause_mac_ctrl_frames", + NFP_MAC_STATS_TX_PAUSE_MAC_CTRL_FRAMES, }, + { "tx_frames_transmitted_ok", + NFP_MAC_STATS_TX_FRAMES_TRANSMITTED_OK, }, + { "tx_unicast_pkts", NFP_MAC_STATS_TX_UNICAST_PKTS, }, + { "tx_multicast_pkts", NFP_MAC_STATS_TX_MULTICAST_PKTS, }, + { "tx_pkts_64_octets", NFP_MAC_STATS_TX_PKTS_64_OCTETS, }, + { "tx_pkts_65_to_127_octets", + NFP_MAC_STATS_TX_PKTS_65_TO_127_OCTETS, }, + { "tx_pkts_128_to_255_octets", + NFP_MAC_STATS_TX_PKTS_128_TO_255_OCTETS, }, + { "tx_pkts_256_to_511_octets", + NFP_MAC_STATS_TX_PKTS_256_TO_511_OCTETS, }, + { "tx_pkts_512_to_1023_octets", + NFP_MAC_STATS_TX_PKTS_512_TO_1023_OCTETS, }, + { "tx_pkts_1024_to_1518_octets", + NFP_MAC_STATS_TX_PKTS_1024_TO_1518_OCTETS, }, + { "tx_pkts_1519_to_max_octets", + NFP_MAC_STATS_TX_PKTS_1519_TO_MAX_OCTETS, }, + { "tx_pause_frames_class0", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS0, }, + { "tx_pause_frames_class1", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS1, }, + { "tx_pause_frames_class2", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS2, }, + { "tx_pause_frames_class3", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS3, }, + { "tx_pause_frames_class4", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS4, }, + { "tx_pause_frames_class5", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS5, }, + { "tx_pause_frames_class6", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS6, }, + { "tx_pause_frames_class7", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS7, }, }; #define NN_ET_GLOBAL_STATS_LEN ARRAY_SIZE(nfp_net_et_stats) -#define NN_ET_RVEC_STATS_LEN (nn->dp.num_r_vecs * 3) +#define NN_ET_SWITCH_STATS_LEN 9 #define NN_ET_RVEC_GATHER_STATS 7 -#define NN_ET_QUEUE_STATS_LEN ((nn->dp.num_tx_rings + nn->dp.num_rx_rings) * 2) -#define NN_ET_STATS_LEN (NN_ET_GLOBAL_STATS_LEN + NN_ET_RVEC_GATHER_STATS + \ - NN_ET_RVEC_STATS_LEN + NN_ET_QUEUE_STATS_LEN) static void nfp_net_get_nspinfo(struct nfp_app *app, char *version) { @@ -147,34 +194,53 @@ static void nfp_net_get_nspinfo(struct nfp_app *app, char *version) if (IS_ERR(nsp)) return; - snprintf(version, ETHTOOL_FWVERS_LEN, "sp:%hu.%hu", + snprintf(version, ETHTOOL_FWVERS_LEN, "%hu.%hu", nfp_nsp_get_abi_ver_major(nsp), nfp_nsp_get_abi_ver_minor(nsp)); nfp_nsp_close(nsp); } -static void nfp_net_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) +static void +nfp_get_drvinfo(struct nfp_app *app, struct pci_dev *pdev, + const char *vnic_version, struct ethtool_drvinfo *drvinfo) { char nsp_version[ETHTOOL_FWVERS_LEN] = {}; - struct nfp_net *nn = netdev_priv(netdev); - strlcpy(drvinfo->driver, nn->pdev->driver->name, - sizeof(drvinfo->driver)); + strlcpy(drvinfo->driver, pdev->driver->name, sizeof(drvinfo->driver)); strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version)); - nfp_net_get_nspinfo(nn->app, nsp_version); + nfp_net_get_nspinfo(app, nsp_version); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), - "%d.%d.%d.%d %s %s %s", + "%s %s %s %s", vnic_version, nsp_version, + nfp_app_mip_name(app), nfp_app_name(app)); +} + +static void +nfp_net_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) +{ + char vnic_version[ETHTOOL_FWVERS_LEN] = {}; + struct nfp_net *nn = netdev_priv(netdev); + + snprintf(vnic_version, sizeof(vnic_version), "%d.%d.%d.%d", nn->fw_ver.resv, nn->fw_ver.class, - nn->fw_ver.major, nn->fw_ver.minor, nsp_version, - nfp_app_mip_name(nn->app), nfp_app_name(nn->app)); + nn->fw_ver.major, nn->fw_ver.minor); strlcpy(drvinfo->bus_info, pci_name(nn->pdev), sizeof(drvinfo->bus_info)); - drvinfo->n_stats = NN_ET_STATS_LEN; - drvinfo->regdump_len = NFP_NET_CFG_BAR_SZ; + nfp_get_drvinfo(nn->app, nn->pdev, vnic_version, drvinfo); +} + +static void +nfp_app_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) +{ + struct nfp_app *app; + + app = nfp_app_from_netdev(netdev); + if (!app) + return; + + nfp_get_drvinfo(app, app->pdev, "*", drvinfo); } /** @@ -346,132 +412,270 @@ static int nfp_net_set_ringparam(struct net_device *netdev, return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt); } -static void nfp_net_get_strings(struct net_device *netdev, - u32 stringset, u8 *data) +static __printf(2, 3) u8 *nfp_pr_et(u8 *data, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vsnprintf(data, ETH_GSTRING_LEN, fmt, args); + va_end(args); + + return data + ETH_GSTRING_LEN; +} + +static unsigned int nfp_vnic_get_sw_stats_count(struct net_device *netdev) +{ + struct nfp_net *nn = netdev_priv(netdev); + + return NN_ET_RVEC_GATHER_STATS + nn->dp.num_r_vecs * 3; +} + +static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data) { struct nfp_net *nn = netdev_priv(netdev); - u8 *p = data; int i; - switch (stringset) { - case ETH_SS_STATS: - for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++) { - memcpy(p, nfp_net_et_stats[i].name, ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < nn->dp.num_r_vecs; i++) { - sprintf(p, "rvec_%u_rx_pkts", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rvec_%u_tx_pkts", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rvec_%u_tx_busy", i); - p += ETH_GSTRING_LEN; - } - strncpy(p, "hw_rx_csum_ok", ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - strncpy(p, "hw_rx_csum_inner_ok", ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - strncpy(p, "hw_rx_csum_err", ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - strncpy(p, "hw_tx_csum", ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - strncpy(p, "hw_tx_inner_csum", ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - strncpy(p, "tx_gather", ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - strncpy(p, "tx_lso", ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - for (i = 0; i < nn->dp.num_tx_rings; i++) { - sprintf(p, "txq_%u_pkts", i); - p += ETH_GSTRING_LEN; - sprintf(p, "txq_%u_bytes", i); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < nn->dp.num_rx_rings; i++) { - sprintf(p, "rxq_%u_pkts", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rxq_%u_bytes", i); - p += ETH_GSTRING_LEN; - } - break; + for (i = 0; i < nn->dp.num_r_vecs; i++) { + data = nfp_pr_et(data, "rvec_%u_rx_pkts", i); + data = nfp_pr_et(data, "rvec_%u_tx_pkts", i); + data = nfp_pr_et(data, "rvec_%u_tx_busy", i); } + + data = nfp_pr_et(data, "hw_rx_csum_ok"); + data = nfp_pr_et(data, "hw_rx_csum_inner_ok"); + data = nfp_pr_et(data, "hw_rx_csum_err"); + data = nfp_pr_et(data, "hw_tx_csum"); + data = nfp_pr_et(data, "hw_tx_inner_csum"); + data = nfp_pr_et(data, "tx_gather"); + data = nfp_pr_et(data, "tx_lso"); + + return data; } -static void nfp_net_get_stats(struct net_device *netdev, - struct ethtool_stats *stats, u64 *data) +static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) { u64 gathered_stats[NN_ET_RVEC_GATHER_STATS] = {}; struct nfp_net *nn = netdev_priv(netdev); - struct rtnl_link_stats64 *netdev_stats; - struct rtnl_link_stats64 temp = {}; u64 tmp[NN_ET_RVEC_GATHER_STATS]; - u8 __iomem *io_p; - int i, j, k; - u8 *p; - - netdev_stats = dev_get_stats(netdev, &temp); - - for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++) { - switch (nfp_net_et_stats[i].type) { - case NETDEV_ET_STATS: - p = (char *)netdev_stats + nfp_net_et_stats[i].off; - data[i] = nfp_net_et_stats[i].sz == sizeof(u64) ? - *(u64 *)p : *(u32 *)p; - break; - - case NFP_NET_DEV_ET_STATS: - io_p = nn->dp.ctrl_bar + nfp_net_et_stats[i].off; - data[i] = readq(io_p); - break; - } - } - for (j = 0; j < nn->dp.num_r_vecs; j++) { + unsigned int i, j; + + for (i = 0; i < nn->dp.num_r_vecs; i++) { unsigned int start; do { - start = u64_stats_fetch_begin(&nn->r_vecs[j].rx_sync); - data[i++] = nn->r_vecs[j].rx_pkts; - tmp[0] = nn->r_vecs[j].hw_csum_rx_ok; - tmp[1] = nn->r_vecs[j].hw_csum_rx_inner_ok; - tmp[2] = nn->r_vecs[j].hw_csum_rx_error; - } while (u64_stats_fetch_retry(&nn->r_vecs[j].rx_sync, start)); + start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync); + *data++ = nn->r_vecs[i].rx_pkts; + tmp[0] = nn->r_vecs[i].hw_csum_rx_ok; + tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok; + tmp[2] = nn->r_vecs[i].hw_csum_rx_error; + } while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start)); do { - start = u64_stats_fetch_begin(&nn->r_vecs[j].tx_sync); - data[i++] = nn->r_vecs[j].tx_pkts; - data[i++] = nn->r_vecs[j].tx_busy; - tmp[3] = nn->r_vecs[j].hw_csum_tx; - tmp[4] = nn->r_vecs[j].hw_csum_tx_inner; - tmp[5] = nn->r_vecs[j].tx_gather; - tmp[6] = nn->r_vecs[j].tx_lso; - } while (u64_stats_fetch_retry(&nn->r_vecs[j].tx_sync, start)); - - for (k = 0; k < NN_ET_RVEC_GATHER_STATS; k++) - gathered_stats[k] += tmp[k]; + start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync); + *data++ = nn->r_vecs[i].tx_pkts; + *data++ = nn->r_vecs[i].tx_busy; + tmp[3] = nn->r_vecs[i].hw_csum_tx; + tmp[4] = nn->r_vecs[i].hw_csum_tx_inner; + tmp[5] = nn->r_vecs[i].tx_gather; + tmp[6] = nn->r_vecs[i].tx_lso; + } while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start)); + + for (j = 0; j < NN_ET_RVEC_GATHER_STATS; j++) + gathered_stats[j] += tmp[j]; } + for (j = 0; j < NN_ET_RVEC_GATHER_STATS; j++) - data[i++] = gathered_stats[j]; - for (j = 0; j < nn->dp.num_tx_rings; j++) { - io_p = nn->dp.ctrl_bar + NFP_NET_CFG_TXR_STATS(j); - data[i++] = readq(io_p); - io_p = nn->dp.ctrl_bar + NFP_NET_CFG_TXR_STATS(j) + 8; - data[i++] = readq(io_p); + *data++ = gathered_stats[j]; + + return data; +} + +static unsigned int +nfp_vnic_get_hw_stats_count(unsigned int rx_rings, unsigned int tx_rings) +{ + return NN_ET_GLOBAL_STATS_LEN + (rx_rings + tx_rings) * 2; +} + +static u8 * +nfp_vnic_get_hw_stats_strings(u8 *data, unsigned int rx_rings, + unsigned int tx_rings, bool repr) +{ + int swap_off, 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++) { + data = nfp_pr_et(data, "txq_%u_pkts", i); + data = nfp_pr_et(data, "txq_%u_bytes", i); + } + + for (i = 0; i < rx_rings; i++) { + data = nfp_pr_et(data, "rxq_%u_pkts", i); + data = nfp_pr_et(data, "rxq_%u_bytes", i); + } + + return data; +} + +static u64 * +nfp_vnic_get_hw_stats(u64 *data, u8 __iomem *mem, + unsigned int rx_rings, unsigned int tx_rings) +{ + unsigned int i; + + for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++) + *data++ = readq(mem + nfp_net_et_stats[i].off); + + for (i = 0; i < tx_rings; i++) { + *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i)); + *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i) + 8); + } + + for (i = 0; i < rx_rings; i++) { + *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i)); + *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i) + 8); } - for (j = 0; j < nn->dp.num_rx_rings; j++) { - io_p = nn->dp.ctrl_bar + NFP_NET_CFG_RXR_STATS(j); - data[i++] = readq(io_p); - io_p = nn->dp.ctrl_bar + NFP_NET_CFG_RXR_STATS(j) + 8; - data[i++] = readq(io_p); + + return data; +} + +static unsigned int nfp_mac_get_stats_count(struct net_device *netdev) +{ + struct nfp_port *port; + + port = nfp_port_from_netdev(netdev); + if (!__nfp_port_get_eth_port(port) || !port->eth_stats) + return 0; + + return ARRAY_SIZE(nfp_mac_et_stats); +} + +static u8 *nfp_mac_get_stats_strings(struct net_device *netdev, u8 *data) +{ + struct nfp_port *port; + unsigned int i; + + port = nfp_port_from_netdev(netdev); + if (!__nfp_port_get_eth_port(port) || !port->eth_stats) + return data; + + for (i = 0; i < ARRAY_SIZE(nfp_mac_et_stats); i++) + data = nfp_pr_et(data, "mac.%s", nfp_mac_et_stats[i].name); + + return data; +} + +static u64 *nfp_mac_get_stats(struct net_device *netdev, u64 *data) +{ + struct nfp_port *port; + unsigned int i; + + port = nfp_port_from_netdev(netdev); + if (!__nfp_port_get_eth_port(port) || !port->eth_stats) + return data; + + for (i = 0; i < ARRAY_SIZE(nfp_mac_et_stats); i++) + *data++ = readq(port->eth_stats + nfp_mac_et_stats[i].off); + + return data; +} + +static void nfp_net_get_strings(struct net_device *netdev, + u32 stringset, u8 *data) +{ + struct nfp_net *nn = netdev_priv(netdev); + + switch (stringset) { + 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, + false); + data = nfp_mac_get_stats_strings(netdev, data); + break; } } +static void +nfp_net_get_stats(struct net_device *netdev, struct ethtool_stats *stats, + u64 *data) +{ + struct nfp_net *nn = netdev_priv(netdev); + + data = nfp_vnic_get_sw_stats(netdev, data); + data = nfp_vnic_get_hw_stats(data, nn->dp.ctrl_bar, + nn->dp.num_rx_rings, nn->dp.num_tx_rings); + data = nfp_mac_get_stats(netdev, data); +} + static int nfp_net_get_sset_count(struct net_device *netdev, int sset) { struct nfp_net *nn = netdev_priv(netdev); switch (sset) { case ETH_SS_STATS: - return NN_ET_STATS_LEN; + return nfp_vnic_get_sw_stats_count(netdev) + + nfp_vnic_get_hw_stats_count(nn->dp.num_rx_rings, + nn->dp.num_tx_rings) + + nfp_mac_get_stats_count(netdev); + default: + return -EOPNOTSUPP; + } +} + +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; } @@ -708,18 +912,18 @@ static int nfp_net_get_coalesce(struct net_device *netdev, /* Other debug dumps */ static int -nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) +nfp_dump_nsp_diag(struct nfp_app *app, struct ethtool_dump *dump, void *buffer) { struct nfp_resource *res; int ret; - if (!nn->app) + if (!app) return -EOPNOTSUPP; dump->version = 1; dump->flag = NFP_DUMP_NSP_DIAG; - res = nfp_resource_acquire(nn->app->cpp, NFP_RESOURCE_NSP_DIAG); + res = nfp_resource_acquire(app->cpp, NFP_RESOURCE_NSP_DIAG); if (IS_ERR(res)) return PTR_ERR(res); @@ -729,7 +933,7 @@ nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) goto exit_release; } - ret = nfp_cpp_read(nn->app->cpp, nfp_resource_cpp_id(res), + ret = nfp_cpp_read(app->cpp, nfp_resource_cpp_id(res), nfp_resource_address(res), buffer, dump->len); if (ret != dump->len) @@ -746,32 +950,30 @@ exit_release: return ret; } -static int nfp_net_set_dump(struct net_device *netdev, struct ethtool_dump *val) +static int nfp_app_set_dump(struct net_device *netdev, struct ethtool_dump *val) { - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_app *app = nfp_app_from_netdev(netdev); - if (!nn->app) + if (!app) return -EOPNOTSUPP; if (val->flag != NFP_DUMP_NSP_DIAG) return -EINVAL; - nn->ethtool_dump_flag = val->flag; - return 0; } static int -nfp_net_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) +nfp_app_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) { - return nfp_dump_nsp_diag(netdev_priv(netdev), dump, NULL); + return nfp_dump_nsp_diag(nfp_app_from_netdev(netdev), dump, NULL); } static int -nfp_net_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, +nfp_app_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, void *buffer) { - return nfp_dump_nsp_diag(netdev_priv(netdev), dump, buffer); + return nfp_dump_nsp_diag(nfp_app_from_netdev(netdev), dump, buffer); } static int nfp_net_set_coalesce(struct net_device *netdev, @@ -928,9 +1130,9 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .set_rxfh = nfp_net_set_rxfh, .get_regs_len = nfp_net_get_regs_len, .get_regs = nfp_net_get_regs, - .set_dump = nfp_net_set_dump, - .get_dump_flag = nfp_net_get_dump_flag, - .get_dump_data = nfp_net_get_dump_data, + .set_dump = nfp_app_set_dump, + .get_dump_flag = nfp_app_get_dump_flag, + .get_dump_data = nfp_app_get_dump_data, .get_coalesce = nfp_net_get_coalesce, .set_coalesce = nfp_net_set_coalesce, .get_channels = nfp_net_get_channels, @@ -939,6 +1141,17 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .set_link_ksettings = nfp_net_set_link_ksettings, }; +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, +}; + void nfp_net_set_ethtool_ops(struct net_device *netdev) { netdev->ethtool_ops = &nfp_net_ethtool_ops; |