|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ |
| 3 | + |
1 | 4 | #include <linux/ethtool.h> |
2 | 5 | #include <linux/netdevice.h> |
3 | 6 | #include <linux/pci.h> |
|
6 | 9 | #include "fbnic_netdev.h" |
7 | 10 | #include "fbnic_tlv.h" |
8 | 11 |
|
| 12 | +struct fbnic_stat { |
| 13 | + u8 string[ETH_GSTRING_LEN]; |
| 14 | + unsigned int size; |
| 15 | + unsigned int offset; |
| 16 | +}; |
| 17 | + |
| 18 | +#define FBNIC_STAT_FIELDS(type, name, stat) { \ |
| 19 | + .string = name, \ |
| 20 | + .size = sizeof_field(struct type, stat), \ |
| 21 | + .offset = offsetof(struct type, stat), \ |
| 22 | +} |
| 23 | + |
| 24 | +/* Hardware statistics not captured in rtnl_link_stats */ |
| 25 | +#define FBNIC_HW_STAT(name, stat) \ |
| 26 | + FBNIC_STAT_FIELDS(fbnic_hw_stats, name, stat) |
| 27 | + |
| 28 | +static const struct fbnic_stat fbnic_gstrings_hw_stats[] = { |
| 29 | + /* RPC */ |
| 30 | + FBNIC_HW_STAT("rpc_unkn_etype", rpc.unkn_etype), |
| 31 | + FBNIC_HW_STAT("rpc_unkn_ext_hdr", rpc.unkn_ext_hdr), |
| 32 | + FBNIC_HW_STAT("rpc_ipv4_frag", rpc.ipv4_frag), |
| 33 | + FBNIC_HW_STAT("rpc_ipv6_frag", rpc.ipv6_frag), |
| 34 | + FBNIC_HW_STAT("rpc_ipv4_esp", rpc.ipv4_esp), |
| 35 | + FBNIC_HW_STAT("rpc_ipv6_esp", rpc.ipv6_esp), |
| 36 | + FBNIC_HW_STAT("rpc_tcp_opt_err", rpc.tcp_opt_err), |
| 37 | + FBNIC_HW_STAT("rpc_out_of_hdr_err", rpc.out_of_hdr_err), |
| 38 | +}; |
| 39 | + |
| 40 | +#define FBNIC_HW_FIXED_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_stats) |
| 41 | +#define FBNIC_HW_STATS_LEN FBNIC_HW_FIXED_STATS_LEN |
| 42 | + |
9 | 43 | static int |
10 | 44 | fbnic_get_ts_info(struct net_device *netdev, |
11 | 45 | struct kernel_ethtool_ts_info *tsinfo) |
@@ -51,6 +85,43 @@ static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter) |
51 | 85 | *stat = counter->value; |
52 | 86 | } |
53 | 87 |
|
| 88 | +static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data) |
| 89 | +{ |
| 90 | + int i; |
| 91 | + |
| 92 | + switch (sset) { |
| 93 | + case ETH_SS_STATS: |
| 94 | + for (i = 0; i < FBNIC_HW_STATS_LEN; i++) |
| 95 | + ethtool_puts(&data, fbnic_gstrings_hw_stats[i].string); |
| 96 | + break; |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +static int fbnic_get_sset_count(struct net_device *dev, int sset) |
| 101 | +{ |
| 102 | + switch (sset) { |
| 103 | + case ETH_SS_STATS: |
| 104 | + return FBNIC_HW_STATS_LEN; |
| 105 | + default: |
| 106 | + return -EOPNOTSUPP; |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +static void fbnic_get_ethtool_stats(struct net_device *dev, |
| 111 | + struct ethtool_stats *stats, u64 *data) |
| 112 | +{ |
| 113 | + struct fbnic_net *fbn = netdev_priv(dev); |
| 114 | + const struct fbnic_stat *stat; |
| 115 | + int i; |
| 116 | + |
| 117 | + fbnic_get_hw_stats(fbn->fbd); |
| 118 | + |
| 119 | + for (i = 0; i < FBNIC_HW_STATS_LEN; i++) { |
| 120 | + stat = &fbnic_gstrings_hw_stats[i]; |
| 121 | + data[i] = *(u64 *)((u8 *)&fbn->fbd->hw_stats + stat->offset); |
| 122 | + } |
| 123 | +} |
| 124 | + |
54 | 125 | static void |
55 | 126 | fbnic_get_eth_mac_stats(struct net_device *netdev, |
56 | 127 | struct ethtool_eth_mac_stats *eth_mac_stats) |
@@ -135,6 +206,9 @@ static const struct ethtool_ops fbnic_ethtool_ops = { |
135 | 206 | .get_drvinfo = fbnic_get_drvinfo, |
136 | 207 | .get_regs_len = fbnic_get_regs_len, |
137 | 208 | .get_regs = fbnic_get_regs, |
| 209 | + .get_strings = fbnic_get_strings, |
| 210 | + .get_ethtool_stats = fbnic_get_ethtool_stats, |
| 211 | + .get_sset_count = fbnic_get_sset_count, |
138 | 212 | .get_ts_info = fbnic_get_ts_info, |
139 | 213 | .get_ts_stats = fbnic_get_ts_stats, |
140 | 214 | .get_eth_mac_stats = fbnic_get_eth_mac_stats, |
|
0 commit comments