Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfp: add support for TLV device stats

Device stats are currently hard coded in the PCI BAR0 layout.
Add a ability to read them from the TLV area instead.
Names for the stats are maintained by the driver, and their
meaning documented. This allows us to more easily add and
remove device stats.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jakub Kicinski and committed by
David S. Miller
ca866ee8 5000b28b

+242 -7
+116
Documentation/networking/device_drivers/netronome/nfp.rst
··· 131 131 abi_drv_load_ifc 132 132 Defines a list of PF devices allowed to load FW on the device. 133 133 This variable is not currently user configurable. 134 + 135 + Statistics 136 + ========== 137 + 138 + Following device statistics are available through the ``ethtool -S`` interface: 139 + 140 + .. flat-table:: NFP device statistics 141 + :header-rows: 1 142 + :widths: 3 1 11 143 + 144 + * - Name 145 + - ID 146 + - Meaning 147 + 148 + * - dev_rx_discards 149 + - 1 150 + - Packet can be discarded on the RX path for one of the following reasons: 151 + 152 + * The NIC is not in promisc mode, and the destination MAC address 153 + doesn't match the interfaces' MAC address. 154 + * The received packet is larger than the max buffer size on the host. 155 + I.e. it exceeds the Layer 3 MRU. 156 + * There is no freelist descriptor available on the host for the packet. 157 + It is likely that the NIC couldn't cache one in time. 158 + * A BPF program discarded the packet. 159 + * The datapath drop action was executed. 160 + * The MAC discarded the packet due to lack of ingress buffer space 161 + on the NIC. 162 + 163 + * - dev_rx_errors 164 + - 2 165 + - A packet can be counted (and dropped) as RX error for the following 166 + reasons: 167 + 168 + * A problem with the VEB lookup (only when SR-IOV is used). 169 + * A physical layer problem that causes Ethernet errors, like FCS or 170 + alignment errors. The cause is usually faulty cables or SFPs. 171 + 172 + * - dev_rx_bytes 173 + - 3 174 + - Total number of bytes received. 175 + 176 + * - dev_rx_uc_bytes 177 + - 4 178 + - Unicast bytes received. 179 + 180 + * - dev_rx_mc_bytes 181 + - 5 182 + - Multicast bytes received. 183 + 184 + * - dev_rx_bc_bytes 185 + - 6 186 + - Broadcast bytes received. 187 + 188 + * - dev_rx_pkts 189 + - 7 190 + - Total number of packets received. 191 + 192 + * - dev_rx_mc_pkts 193 + - 8 194 + - Multicast packets received. 195 + 196 + * - dev_rx_bc_pkts 197 + - 9 198 + - Broadcast packets received. 199 + 200 + * - dev_tx_discards 201 + - 10 202 + - A packet can be discarded in the TX direction if the MAC is 203 + being flow controlled and the NIC runs out of TX queue space. 204 + 205 + * - dev_tx_errors 206 + - 11 207 + - A packet can be counted as TX error (and dropped) for one for the 208 + following reasons: 209 + 210 + * The packet is an LSO segment, but the Layer 3 or Layer 4 offset 211 + could not be determined. Therefore LSO could not continue. 212 + * An invalid packet descriptor was received over PCIe. 213 + * The packet Layer 3 length exceeds the device MTU. 214 + * An error on the MAC/physical layer. Usually due to faulty cables or 215 + SFPs. 216 + * A CTM buffer could not be allocated. 217 + * The packet offset was incorrect and could not be fixed by the NIC. 218 + 219 + * - dev_tx_bytes 220 + - 12 221 + - Total number of bytes transmitted. 222 + 223 + * - dev_tx_uc_bytes 224 + - 13 225 + - Unicast bytes transmitted. 226 + 227 + * - dev_tx_mc_bytes 228 + - 14 229 + - Multicast bytes transmitted. 230 + 231 + * - dev_tx_bc_bytes 232 + - 15 233 + - Broadcast bytes transmitted. 234 + 235 + * - dev_tx_pkts 236 + - 16 237 + - Total number of packets transmitted. 238 + 239 + * - dev_tx_mc_pkts 240 + - 17 241 + - Multicast packets transmitted. 242 + 243 + * - dev_tx_bc_pkts 244 + - 18 245 + - Broadcast packets transmitted. 246 + 247 + Note that statistics unknown to the driver will be displayed as 248 + ``dev_unknown_stat$ID``, where ``$ID`` refers to the second column 249 + above.
+9
drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
··· 114 114 caps->crypto_ops = readl(data); 115 115 caps->crypto_enable_off = data - ctrl_mem + 16; 116 116 break; 117 + case NFP_NET_CFG_TLV_TYPE_VNIC_STATS: 118 + if ((data - ctrl_mem) % 8) { 119 + dev_warn(dev, "VNIC STATS TLV misaligned, ignoring offset:%u len:%u\n", 120 + offset, length); 121 + break; 122 + } 123 + caps->vnic_stats_off = data - ctrl_mem; 124 + caps->vnic_stats_cnt = length / 10; 125 + break; 117 126 default: 118 127 if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr)) 119 128 break;
+16
drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
··· 479 479 * 8 words, bitmaps of supported and enabled crypto operations. 480 480 * First 16B (4 words) contains a bitmap of supported crypto operations, 481 481 * and next 16B contain the enabled operations. 482 + * 483 + * %NFP_NET_CFG_TLV_TYPE_VNIC_STATS: 484 + * Variable, per-vNIC statistics, data should be 8B aligned (FW should insert 485 + * zero-length RESERVED TLV to pad). 486 + * TLV data has two sections. First is an array of statistics' IDs (2B each). 487 + * Second 8B statistics themselves. Statistics are 8B aligned, meaning there 488 + * may be a padding between sections. 489 + * Number of statistics can be determined as floor(tlv.length / (2 + 8)). 490 + * This TLV overwrites %NFP_NET_CFG_STATS_* values (statistics in this TLV 491 + * duplicate the old ones, so driver should be careful not to unnecessarily 492 + * render both). 482 493 */ 483 494 #define NFP_NET_CFG_TLV_TYPE_UNKNOWN 0 484 495 #define NFP_NET_CFG_TLV_TYPE_RESERVED 1 ··· 501 490 #define NFP_NET_CFG_TLV_TYPE_REPR_CAP 7 502 491 #define NFP_NET_CFG_TLV_TYPE_MBOX_CMSG_TYPES 10 503 492 #define NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS 11 /* see crypto/fw.h */ 493 + #define NFP_NET_CFG_TLV_TYPE_VNIC_STATS 12 504 494 505 495 struct device; 506 496 ··· 514 502 * @mbox_cmsg_types: cmsgs which can be passed through the mailbox 515 503 * @crypto_ops: supported crypto operations 516 504 * @crypto_enable_off: offset of crypto ops enable region 505 + * @vnic_stats_off: offset of vNIC stats area 506 + * @vnic_stats_cnt: number of vNIC stats 517 507 */ 518 508 struct nfp_net_tlv_caps { 519 509 u32 me_freq_mhz; ··· 525 511 u32 mbox_cmsg_types; 526 512 u32 crypto_ops; 527 513 unsigned int crypto_enable_off; 514 + unsigned int vnic_stats_off; 515 + unsigned int vnic_stats_cnt; 528 516 }; 529 517 530 518 int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
+101 -7
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
··· 148 148 { "tx_pause_frames_class7", NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS7, }, 149 149 }; 150 150 151 + static const char nfp_tlv_stat_names[][ETH_GSTRING_LEN] = { 152 + [1] = "dev_rx_discards", 153 + [2] = "dev_rx_errors", 154 + [3] = "dev_rx_bytes", 155 + [4] = "dev_rx_uc_bytes", 156 + [5] = "dev_rx_mc_bytes", 157 + [6] = "dev_rx_bc_bytes", 158 + [7] = "dev_rx_pkts", 159 + [8] = "dev_rx_mc_pkts", 160 + [9] = "dev_rx_bc_pkts", 161 + 162 + [10] = "dev_tx_discards", 163 + [11] = "dev_tx_errors", 164 + [12] = "dev_tx_bytes", 165 + [13] = "dev_tx_uc_bytes", 166 + [14] = "dev_tx_mc_bytes", 167 + [15] = "dev_tx_bc_bytes", 168 + [16] = "dev_tx_pkts", 169 + [17] = "dev_tx_mc_pkts", 170 + [18] = "dev_tx_bc_pkts", 171 + }; 172 + 151 173 #define NN_ET_GLOBAL_STATS_LEN ARRAY_SIZE(nfp_net_et_stats) 152 174 #define NN_ET_SWITCH_STATS_LEN 9 153 175 #define NN_RVEC_GATHER_STATS 13 ··· 582 560 return data; 583 561 } 584 562 563 + static unsigned int nfp_vnic_get_tlv_stats_count(struct nfp_net *nn) 564 + { 565 + return nn->tlv_caps.vnic_stats_cnt + nn->max_r_vecs * 4; 566 + } 567 + 568 + static u8 *nfp_vnic_get_tlv_stats_strings(struct nfp_net *nn, u8 *data) 569 + { 570 + unsigned int i, id; 571 + u8 __iomem *mem; 572 + u64 id_word = 0; 573 + 574 + mem = nn->dp.ctrl_bar + nn->tlv_caps.vnic_stats_off; 575 + for (i = 0; i < nn->tlv_caps.vnic_stats_cnt; i++) { 576 + if (!(i % 4)) 577 + id_word = readq(mem + i * 2); 578 + 579 + id = (u16)id_word; 580 + id_word >>= 16; 581 + 582 + if (id < ARRAY_SIZE(nfp_tlv_stat_names) && 583 + nfp_tlv_stat_names[id][0]) { 584 + memcpy(data, nfp_tlv_stat_names[id], ETH_GSTRING_LEN); 585 + data += ETH_GSTRING_LEN; 586 + } else { 587 + data = nfp_pr_et(data, "dev_unknown_stat%u", id); 588 + } 589 + } 590 + 591 + for (i = 0; i < nn->max_r_vecs; i++) { 592 + data = nfp_pr_et(data, "rxq_%u_pkts", i); 593 + data = nfp_pr_et(data, "rxq_%u_bytes", i); 594 + data = nfp_pr_et(data, "txq_%u_pkts", i); 595 + data = nfp_pr_et(data, "txq_%u_bytes", i); 596 + } 597 + 598 + return data; 599 + } 600 + 601 + static u64 *nfp_vnic_get_tlv_stats(struct nfp_net *nn, u64 *data) 602 + { 603 + u8 __iomem *mem; 604 + unsigned int i; 605 + 606 + mem = nn->dp.ctrl_bar + nn->tlv_caps.vnic_stats_off; 607 + mem += roundup(2 * nn->tlv_caps.vnic_stats_cnt, 8); 608 + for (i = 0; i < nn->tlv_caps.vnic_stats_cnt; i++) 609 + *data++ = readq(mem + i * 8); 610 + 611 + mem = nn->dp.ctrl_bar; 612 + for (i = 0; i < nn->max_r_vecs; i++) { 613 + *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i)); 614 + *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i) + 8); 615 + *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i)); 616 + *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i) + 8); 617 + } 618 + 619 + return data; 620 + } 621 + 585 622 static unsigned int nfp_mac_get_stats_count(struct net_device *netdev) 586 623 { 587 624 struct nfp_port *port; ··· 690 609 switch (stringset) { 691 610 case ETH_SS_STATS: 692 611 data = nfp_vnic_get_sw_stats_strings(netdev, data); 693 - data = nfp_vnic_get_hw_stats_strings(data, nn->max_r_vecs, 694 - false); 612 + if (!nn->tlv_caps.vnic_stats_off) 613 + data = nfp_vnic_get_hw_stats_strings(data, 614 + nn->max_r_vecs, 615 + false); 616 + else 617 + data = nfp_vnic_get_tlv_stats_strings(nn, data); 695 618 data = nfp_mac_get_stats_strings(netdev, data); 696 619 data = nfp_app_port_get_stats_strings(nn->port, data); 697 620 break; ··· 709 624 struct nfp_net *nn = netdev_priv(netdev); 710 625 711 626 data = nfp_vnic_get_sw_stats(netdev, data); 712 - data = nfp_vnic_get_hw_stats(data, nn->dp.ctrl_bar, nn->max_r_vecs); 627 + if (!nn->tlv_caps.vnic_stats_off) 628 + data = nfp_vnic_get_hw_stats(data, nn->dp.ctrl_bar, 629 + nn->max_r_vecs); 630 + else 631 + data = nfp_vnic_get_tlv_stats(nn, data); 713 632 data = nfp_mac_get_stats(netdev, data); 714 633 data = nfp_app_port_get_stats(nn->port, data); 715 634 } ··· 721 632 static int nfp_net_get_sset_count(struct net_device *netdev, int sset) 722 633 { 723 634 struct nfp_net *nn = netdev_priv(netdev); 635 + unsigned int cnt; 724 636 725 637 switch (sset) { 726 638 case ETH_SS_STATS: 727 - return nfp_vnic_get_sw_stats_count(netdev) + 728 - nfp_vnic_get_hw_stats_count(nn->max_r_vecs) + 729 - nfp_mac_get_stats_count(netdev) + 730 - nfp_app_port_get_stats_count(nn->port); 639 + cnt = nfp_vnic_get_sw_stats_count(netdev); 640 + if (!nn->tlv_caps.vnic_stats_off) 641 + cnt += nfp_vnic_get_hw_stats_count(nn->max_r_vecs); 642 + else 643 + cnt += nfp_vnic_get_tlv_stats_count(nn); 644 + cnt += nfp_mac_get_stats_count(netdev); 645 + cnt += nfp_app_port_get_stats_count(nn->port); 646 + return cnt; 731 647 default: 732 648 return -EOPNOTSUPP; 733 649 }