1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52#include <linux/ethtool.h>
53
54#include "opa_vnic_internal.h"
55
56enum {NETDEV_STATS, VNIC_STATS};
57
58struct vnic_stats {
59 char stat_string[ETH_GSTRING_LEN];
60 struct {
61 int sizeof_stat;
62 int stat_offset;
63 };
64};
65
66#define VNIC_STAT(m) { FIELD_SIZEOF(struct opa_vnic_stats, m), \
67 offsetof(struct opa_vnic_stats, m) }
68
69static struct vnic_stats vnic_gstrings_stats[] = {
70
71 {"rx_packets", VNIC_STAT(netstats.rx_packets)},
72 {"tx_packets", VNIC_STAT(netstats.tx_packets)},
73 {"rx_bytes", VNIC_STAT(netstats.rx_bytes)},
74 {"tx_bytes", VNIC_STAT(netstats.tx_bytes)},
75 {"rx_errors", VNIC_STAT(netstats.rx_errors)},
76 {"tx_errors", VNIC_STAT(netstats.tx_errors)},
77 {"rx_dropped", VNIC_STAT(netstats.rx_dropped)},
78 {"tx_dropped", VNIC_STAT(netstats.tx_dropped)},
79
80
81 {"tx_unicast", VNIC_STAT(tx_grp.unicast)},
82 {"tx_mcastbcast", VNIC_STAT(tx_grp.mcastbcast)},
83 {"tx_untagged", VNIC_STAT(tx_grp.untagged)},
84 {"tx_vlan", VNIC_STAT(tx_grp.vlan)},
85
86 {"tx_64_size", VNIC_STAT(tx_grp.s_64)},
87 {"tx_65_127", VNIC_STAT(tx_grp.s_65_127)},
88 {"tx_128_255", VNIC_STAT(tx_grp.s_128_255)},
89 {"tx_256_511", VNIC_STAT(tx_grp.s_256_511)},
90 {"tx_512_1023", VNIC_STAT(tx_grp.s_512_1023)},
91 {"tx_1024_1518", VNIC_STAT(tx_grp.s_1024_1518)},
92 {"tx_1519_max", VNIC_STAT(tx_grp.s_1519_max)},
93
94 {"rx_unicast", VNIC_STAT(rx_grp.unicast)},
95 {"rx_mcastbcast", VNIC_STAT(rx_grp.mcastbcast)},
96 {"rx_untagged", VNIC_STAT(rx_grp.untagged)},
97 {"rx_vlan", VNIC_STAT(rx_grp.vlan)},
98
99 {"rx_64_size", VNIC_STAT(rx_grp.s_64)},
100 {"rx_65_127", VNIC_STAT(rx_grp.s_65_127)},
101 {"rx_128_255", VNIC_STAT(rx_grp.s_128_255)},
102 {"rx_256_511", VNIC_STAT(rx_grp.s_256_511)},
103 {"rx_512_1023", VNIC_STAT(rx_grp.s_512_1023)},
104 {"rx_1024_1518", VNIC_STAT(rx_grp.s_1024_1518)},
105 {"rx_1519_max", VNIC_STAT(rx_grp.s_1519_max)},
106
107
108 {"rx_fifo_errors", VNIC_STAT(netstats.rx_fifo_errors)},
109 {"rx_length_errors", VNIC_STAT(netstats.rx_length_errors)},
110
111 {"tx_fifo_errors", VNIC_STAT(netstats.tx_fifo_errors)},
112 {"tx_carrier_errors", VNIC_STAT(netstats.tx_carrier_errors)},
113
114 {"tx_dlid_zero", VNIC_STAT(tx_dlid_zero)},
115 {"tx_drop_state", VNIC_STAT(tx_drop_state)},
116 {"rx_drop_state", VNIC_STAT(rx_drop_state)},
117 {"rx_oversize", VNIC_STAT(rx_oversize)},
118 {"rx_runt", VNIC_STAT(rx_runt)},
119};
120
121#define VNIC_STATS_LEN ARRAY_SIZE(vnic_gstrings_stats)
122
123
124static void vnic_get_drvinfo(struct net_device *netdev,
125 struct ethtool_drvinfo *drvinfo)
126{
127 strlcpy(drvinfo->driver, opa_vnic_driver_name, sizeof(drvinfo->driver));
128 strlcpy(drvinfo->version, opa_vnic_driver_version,
129 sizeof(drvinfo->version));
130 strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent),
131 sizeof(drvinfo->bus_info));
132}
133
134
135static int vnic_get_sset_count(struct net_device *netdev, int sset)
136{
137 return (sset == ETH_SS_STATS) ? VNIC_STATS_LEN : -EOPNOTSUPP;
138}
139
140
141static void vnic_get_ethtool_stats(struct net_device *netdev,
142 struct ethtool_stats *stats, u64 *data)
143{
144 struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev);
145 struct opa_vnic_stats vstats;
146 int i;
147
148 memset(&vstats, 0, sizeof(vstats));
149 spin_lock(&adapter->stats_lock);
150 adapter->rn_ops->ndo_get_stats64(netdev, &vstats.netstats);
151 spin_unlock(&adapter->stats_lock);
152 for (i = 0; i < VNIC_STATS_LEN; i++) {
153 char *p = (char *)&vstats + vnic_gstrings_stats[i].stat_offset;
154
155 data[i] = (vnic_gstrings_stats[i].sizeof_stat ==
156 sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
157 }
158}
159
160
161static void vnic_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
162{
163 int i;
164
165 if (stringset != ETH_SS_STATS)
166 return;
167
168 for (i = 0; i < VNIC_STATS_LEN; i++)
169 memcpy(data + i * ETH_GSTRING_LEN,
170 vnic_gstrings_stats[i].stat_string,
171 ETH_GSTRING_LEN);
172}
173
174
175static const struct ethtool_ops opa_vnic_ethtool_ops = {
176 .get_drvinfo = vnic_get_drvinfo,
177 .get_link = ethtool_op_get_link,
178 .get_strings = vnic_get_strings,
179 .get_sset_count = vnic_get_sset_count,
180 .get_ethtool_stats = vnic_get_ethtool_stats,
181};
182
183
184void opa_vnic_set_ethtool_ops(struct net_device *netdev)
185{
186 netdev->ethtool_ops = &opa_vnic_ethtool_ops;
187}
188