Merge tag 'perf-tools-fixes-for-v6.4-1-2023-05-20' of git://git.kernel.org/pub/scm...
[linux-block.git] / net / ethtool / stats.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include "netlink.h"
4 #include "common.h"
5 #include "bitset.h"
6
7 struct stats_req_info {
8         struct ethnl_req_info           base;
9         DECLARE_BITMAP(stat_mask, __ETHTOOL_STATS_CNT);
10         enum ethtool_mac_stats_src      src;
11 };
12
13 #define STATS_REQINFO(__req_base) \
14         container_of(__req_base, struct stats_req_info, base)
15
16 struct stats_reply_data {
17         struct ethnl_reply_data         base;
18         struct_group(stats,
19                 struct ethtool_eth_phy_stats    phy_stats;
20                 struct ethtool_eth_mac_stats    mac_stats;
21                 struct ethtool_eth_ctrl_stats   ctrl_stats;
22                 struct ethtool_rmon_stats       rmon_stats;
23         );
24         const struct ethtool_rmon_hist_range    *rmon_ranges;
25 };
26
27 #define STATS_REPDATA(__reply_base) \
28         container_of(__reply_base, struct stats_reply_data, base)
29
30 const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = {
31         [ETHTOOL_STATS_ETH_PHY]                 = "eth-phy",
32         [ETHTOOL_STATS_ETH_MAC]                 = "eth-mac",
33         [ETHTOOL_STATS_ETH_CTRL]                = "eth-ctrl",
34         [ETHTOOL_STATS_RMON]                    = "rmon",
35 };
36
37 const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
38         [ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR]     = "SymbolErrorDuringCarrier",
39 };
40
41 const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN] = {
42         [ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT]      = "FramesTransmittedOK",
43         [ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL]  = "SingleCollisionFrames",
44         [ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL]   = "MultipleCollisionFrames",
45         [ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT]      = "FramesReceivedOK",
46         [ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR]     = "FrameCheckSequenceErrors",
47         [ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR]   = "AlignmentErrors",
48         [ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES]    = "OctetsTransmittedOK",
49         [ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER]    = "FramesWithDeferredXmissions",
50         [ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL]   = "LateCollisions",
51         [ETHTOOL_A_STATS_ETH_MAC_11_XS_COL]     = "FramesAbortedDueToXSColls",
52         [ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR] = "FramesLostDueToIntMACXmitError",
53         [ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR]     = "CarrierSenseErrors",
54         [ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES]   = "OctetsReceivedOK",
55         [ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR] = "FramesLostDueToIntMACRcvError",
56         [ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST]   = "MulticastFramesXmittedOK",
57         [ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST]   = "BroadcastFramesXmittedOK",
58         [ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER]   = "FramesWithExcessiveDeferral",
59         [ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST]   = "MulticastFramesReceivedOK",
60         [ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST]   = "BroadcastFramesReceivedOK",
61         [ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR] = "InRangeLengthErrors",
62         [ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN]    = "OutOfRangeLengthField",
63         [ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR]       = "FrameTooLongErrors",
64 };
65
66 const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN] = {
67         [ETHTOOL_A_STATS_ETH_CTRL_3_TX]         = "MACControlFramesTransmitted",
68         [ETHTOOL_A_STATS_ETH_CTRL_4_RX]         = "MACControlFramesReceived",
69         [ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP]   = "UnsupportedOpcodesReceived",
70 };
71
72 const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN] = {
73         [ETHTOOL_A_STATS_RMON_UNDERSIZE]        = "etherStatsUndersizePkts",
74         [ETHTOOL_A_STATS_RMON_OVERSIZE]         = "etherStatsOversizePkts",
75         [ETHTOOL_A_STATS_RMON_FRAG]             = "etherStatsFragments",
76         [ETHTOOL_A_STATS_RMON_JABBER]           = "etherStatsJabbers",
77 };
78
79 const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_SRC + 1] = {
80         [ETHTOOL_A_STATS_HEADER]        =
81                 NLA_POLICY_NESTED(ethnl_header_policy),
82         [ETHTOOL_A_STATS_GROUPS]        = { .type = NLA_NESTED },
83         [ETHTOOL_A_STATS_SRC]           =
84                 NLA_POLICY_MAX(NLA_U32, ETHTOOL_MAC_STATS_SRC_PMAC),
85 };
86
87 static int stats_parse_request(struct ethnl_req_info *req_base,
88                                struct nlattr **tb,
89                                struct netlink_ext_ack *extack)
90 {
91         enum ethtool_mac_stats_src src = ETHTOOL_MAC_STATS_SRC_AGGREGATE;
92         struct stats_req_info *req_info = STATS_REQINFO(req_base);
93         bool mod = false;
94         int err;
95
96         err = ethnl_update_bitset(req_info->stat_mask, __ETHTOOL_STATS_CNT,
97                                   tb[ETHTOOL_A_STATS_GROUPS], stats_std_names,
98                                   extack, &mod);
99         if (err)
100                 return err;
101
102         if (!mod) {
103                 NL_SET_ERR_MSG(extack, "no stats requested");
104                 return -EINVAL;
105         }
106
107         if (tb[ETHTOOL_A_STATS_SRC])
108                 src = nla_get_u32(tb[ETHTOOL_A_STATS_SRC]);
109
110         req_info->src = src;
111
112         return 0;
113 }
114
115 static int stats_prepare_data(const struct ethnl_req_info *req_base,
116                               struct ethnl_reply_data *reply_base,
117                               struct genl_info *info)
118 {
119         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
120         struct netlink_ext_ack *extack = info ? info->extack : NULL;
121         struct stats_reply_data *data = STATS_REPDATA(reply_base);
122         enum ethtool_mac_stats_src src = req_info->src;
123         struct net_device *dev = reply_base->dev;
124         int ret;
125
126         ret = ethnl_ops_begin(dev);
127         if (ret < 0)
128                 return ret;
129
130         if ((src == ETHTOOL_MAC_STATS_SRC_EMAC ||
131              src == ETHTOOL_MAC_STATS_SRC_PMAC) &&
132             !__ethtool_dev_mm_supported(dev)) {
133                 NL_SET_ERR_MSG_MOD(extack,
134                                    "Device does not support MAC merge layer");
135                 ethnl_ops_complete(dev);
136                 return -EOPNOTSUPP;
137         }
138
139         /* Mark all stats as unset (see ETHTOOL_STAT_NOT_SET) to prevent them
140          * from being reported to user space in case driver did not set them.
141          */
142         memset(&data->stats, 0xff, sizeof(data->stats));
143
144         data->phy_stats.src = src;
145         data->mac_stats.src = src;
146         data->ctrl_stats.src = src;
147         data->rmon_stats.src = src;
148
149         if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
150             dev->ethtool_ops->get_eth_phy_stats)
151                 dev->ethtool_ops->get_eth_phy_stats(dev, &data->phy_stats);
152         if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask) &&
153             dev->ethtool_ops->get_eth_mac_stats)
154                 dev->ethtool_ops->get_eth_mac_stats(dev, &data->mac_stats);
155         if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&
156             dev->ethtool_ops->get_eth_ctrl_stats)
157                 dev->ethtool_ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);
158         if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask) &&
159             dev->ethtool_ops->get_rmon_stats)
160                 dev->ethtool_ops->get_rmon_stats(dev, &data->rmon_stats,
161                                                  &data->rmon_ranges);
162
163         ethnl_ops_complete(dev);
164         return 0;
165 }
166
167 static int stats_reply_size(const struct ethnl_req_info *req_base,
168                             const struct ethnl_reply_data *reply_base)
169 {
170         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
171         unsigned int n_grps = 0, n_stats = 0;
172         int len = 0;
173
174         len += nla_total_size(sizeof(u32)); /* _STATS_SRC */
175
176         if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) {
177                 n_stats += sizeof(struct ethtool_eth_phy_stats) / sizeof(u64);
178                 n_grps++;
179         }
180         if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask)) {
181                 n_stats += sizeof(struct ethtool_eth_mac_stats) / sizeof(u64);
182                 n_grps++;
183         }
184         if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask)) {
185                 n_stats += sizeof(struct ethtool_eth_ctrl_stats) / sizeof(u64);
186                 n_grps++;
187         }
188         if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask)) {
189                 n_stats += sizeof(struct ethtool_rmon_stats) / sizeof(u64);
190                 n_grps++;
191                 /* Above includes the space for _A_STATS_GRP_HIST_VALs */
192
193                 len += (nla_total_size(0) +     /* _A_STATS_GRP_HIST */
194                         nla_total_size(4) +     /* _A_STATS_GRP_HIST_BKT_LOW */
195                         nla_total_size(4)) *    /* _A_STATS_GRP_HIST_BKT_HI */
196                         ETHTOOL_RMON_HIST_MAX * 2;
197         }
198
199         len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
200                          nla_total_size(4) + /* _A_STATS_GRP_ID */
201                          nla_total_size(4)); /* _A_STATS_GRP_SS_ID */
202         len += n_stats * (nla_total_size(0) + /* _A_STATS_GRP_STAT */
203                           nla_total_size_64bit(sizeof(u64)));
204
205         return len;
206 }
207
208 static int stat_put(struct sk_buff *skb, u16 attrtype, u64 val)
209 {
210         struct nlattr *nest;
211         int ret;
212
213         if (val == ETHTOOL_STAT_NOT_SET)
214                 return 0;
215
216         /* We want to start stats attr types from 0, so we don't have a type
217          * for pad inside ETHTOOL_A_STATS_GRP_STAT. Pad things on the outside
218          * of ETHTOOL_A_STATS_GRP_STAT. Since we're one nest away from the
219          * actual attr we're 4B off - nla_need_padding_for_64bit() & co.
220          * can't be used.
221          */
222 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
223         if (!IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8))
224                 if (!nla_reserve(skb, ETHTOOL_A_STATS_GRP_PAD, 0))
225                         return -EMSGSIZE;
226 #endif
227
228         nest = nla_nest_start(skb, ETHTOOL_A_STATS_GRP_STAT);
229         if (!nest)
230                 return -EMSGSIZE;
231
232         ret = nla_put_u64_64bit(skb, attrtype, val, -1 /* not used */);
233         if (ret) {
234                 nla_nest_cancel(skb, nest);
235                 return ret;
236         }
237
238         nla_nest_end(skb, nest);
239         return 0;
240 }
241
242 static int stats_put_phy_stats(struct sk_buff *skb,
243                                const struct stats_reply_data *data)
244 {
245         if (stat_put(skb, ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR,
246                      data->phy_stats.SymbolErrorDuringCarrier))
247                 return -EMSGSIZE;
248         return 0;
249 }
250
251 static int stats_put_mac_stats(struct sk_buff *skb,
252                                const struct stats_reply_data *data)
253 {
254         if (stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT,
255                      data->mac_stats.FramesTransmittedOK) ||
256             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL,
257                      data->mac_stats.SingleCollisionFrames) ||
258             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL,
259                      data->mac_stats.MultipleCollisionFrames) ||
260             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT,
261                      data->mac_stats.FramesReceivedOK) ||
262             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR,
263                      data->mac_stats.FrameCheckSequenceErrors) ||
264             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR,
265                      data->mac_stats.AlignmentErrors) ||
266             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES,
267                      data->mac_stats.OctetsTransmittedOK) ||
268             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER,
269                      data->mac_stats.FramesWithDeferredXmissions) ||
270             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL,
271                      data->mac_stats.LateCollisions) ||
272             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_11_XS_COL,
273                      data->mac_stats.FramesAbortedDueToXSColls) ||
274             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR,
275                      data->mac_stats.FramesLostDueToIntMACXmitError) ||
276             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR,
277                      data->mac_stats.CarrierSenseErrors) ||
278             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES,
279                      data->mac_stats.OctetsReceivedOK) ||
280             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR,
281                      data->mac_stats.FramesLostDueToIntMACRcvError) ||
282             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST,
283                      data->mac_stats.MulticastFramesXmittedOK) ||
284             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST,
285                      data->mac_stats.BroadcastFramesXmittedOK) ||
286             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER,
287                      data->mac_stats.FramesWithExcessiveDeferral) ||
288             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST,
289                      data->mac_stats.MulticastFramesReceivedOK) ||
290             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST,
291                      data->mac_stats.BroadcastFramesReceivedOK) ||
292             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR,
293                      data->mac_stats.InRangeLengthErrors) ||
294             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN,
295                      data->mac_stats.OutOfRangeLengthField) ||
296             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR,
297                      data->mac_stats.FrameTooLongErrors))
298                 return -EMSGSIZE;
299         return 0;
300 }
301
302 static int stats_put_ctrl_stats(struct sk_buff *skb,
303                                 const struct stats_reply_data *data)
304 {
305         if (stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_3_TX,
306                      data->ctrl_stats.MACControlFramesTransmitted) ||
307             stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_4_RX,
308                      data->ctrl_stats.MACControlFramesReceived) ||
309             stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP,
310                      data->ctrl_stats.UnsupportedOpcodesReceived))
311                 return -EMSGSIZE;
312         return 0;
313 }
314
315 static int stats_put_rmon_hist(struct sk_buff *skb, u32 attr, const u64 *hist,
316                                const struct ethtool_rmon_hist_range *ranges)
317 {
318         struct nlattr *nest;
319         int i;
320
321         if (!ranges)
322                 return 0;
323
324         for (i = 0; i < ETHTOOL_RMON_HIST_MAX; i++) {
325                 if (!ranges[i].low && !ranges[i].high)
326                         break;
327                 if (hist[i] == ETHTOOL_STAT_NOT_SET)
328                         continue;
329
330                 nest = nla_nest_start(skb, attr);
331                 if (!nest)
332                         return -EMSGSIZE;
333
334                 if (nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_LOW,
335                                 ranges[i].low) ||
336                     nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_HI,
337                                 ranges[i].high) ||
338                     nla_put_u64_64bit(skb, ETHTOOL_A_STATS_GRP_HIST_VAL,
339                                       hist[i], ETHTOOL_A_STATS_GRP_PAD))
340                         goto err_cancel_hist;
341
342                 nla_nest_end(skb, nest);
343         }
344
345         return 0;
346
347 err_cancel_hist:
348         nla_nest_cancel(skb, nest);
349         return -EMSGSIZE;
350 }
351
352 static int stats_put_rmon_stats(struct sk_buff *skb,
353                                 const struct stats_reply_data *data)
354 {
355         if (stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_RX,
356                                 data->rmon_stats.hist, data->rmon_ranges) ||
357             stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_TX,
358                                 data->rmon_stats.hist_tx, data->rmon_ranges))
359                 return -EMSGSIZE;
360
361         if (stat_put(skb, ETHTOOL_A_STATS_RMON_UNDERSIZE,
362                      data->rmon_stats.undersize_pkts) ||
363             stat_put(skb, ETHTOOL_A_STATS_RMON_OVERSIZE,
364                      data->rmon_stats.oversize_pkts) ||
365             stat_put(skb, ETHTOOL_A_STATS_RMON_FRAG,
366                      data->rmon_stats.fragments) ||
367             stat_put(skb, ETHTOOL_A_STATS_RMON_JABBER,
368                      data->rmon_stats.jabbers))
369                 return -EMSGSIZE;
370
371         return 0;
372 }
373
374 static int stats_put_stats(struct sk_buff *skb,
375                            const struct stats_reply_data *data,
376                            u32 id, u32 ss_id,
377                            int (*cb)(struct sk_buff *skb,
378                                      const struct stats_reply_data *data))
379 {
380         struct nlattr *nest;
381
382         nest = nla_nest_start(skb, ETHTOOL_A_STATS_GRP);
383         if (!nest)
384                 return -EMSGSIZE;
385
386         if (nla_put_u32(skb, ETHTOOL_A_STATS_GRP_ID, id) ||
387             nla_put_u32(skb, ETHTOOL_A_STATS_GRP_SS_ID, ss_id))
388                 goto err_cancel;
389
390         if (cb(skb, data))
391                 goto err_cancel;
392
393         nla_nest_end(skb, nest);
394         return 0;
395
396 err_cancel:
397         nla_nest_cancel(skb, nest);
398         return -EMSGSIZE;
399 }
400
401 static int stats_fill_reply(struct sk_buff *skb,
402                             const struct ethnl_req_info *req_base,
403                             const struct ethnl_reply_data *reply_base)
404 {
405         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
406         const struct stats_reply_data *data = STATS_REPDATA(reply_base);
407         int ret = 0;
408
409         if (nla_put_u32(skb, ETHTOOL_A_STATS_SRC, req_info->src))
410                 return -EMSGSIZE;
411
412         if (!ret && test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask))
413                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_PHY,
414                                       ETH_SS_STATS_ETH_PHY,
415                                       stats_put_phy_stats);
416         if (!ret && test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask))
417                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_MAC,
418                                       ETH_SS_STATS_ETH_MAC,
419                                       stats_put_mac_stats);
420         if (!ret && test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask))
421                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,
422                                       ETH_SS_STATS_ETH_CTRL,
423                                       stats_put_ctrl_stats);
424         if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
425                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
426                                       ETH_SS_STATS_RMON, stats_put_rmon_stats);
427
428         return ret;
429 }
430
431 const struct ethnl_request_ops ethnl_stats_request_ops = {
432         .request_cmd            = ETHTOOL_MSG_STATS_GET,
433         .reply_cmd              = ETHTOOL_MSG_STATS_GET_REPLY,
434         .hdr_attr               = ETHTOOL_A_STATS_HEADER,
435         .req_info_size          = sizeof(struct stats_req_info),
436         .reply_data_size        = sizeof(struct stats_reply_data),
437
438         .parse_request          = stats_parse_request,
439         .prepare_data           = stats_prepare_data,
440         .reply_size             = stats_reply_size,
441         .fill_reply             = stats_fill_reply,
442 };
443
444 static u64 ethtool_stats_sum(u64 a, u64 b)
445 {
446         if (a == ETHTOOL_STAT_NOT_SET)
447                 return b;
448         if (b == ETHTOOL_STAT_NOT_SET)
449                 return a;
450         return a + b;
451 }
452
453 /* Avoid modifying the aggregation procedure every time a new counter is added
454  * by treating the structures as an array of u64 statistics.
455  */
456 static void ethtool_aggregate_stats(void *aggr_stats, const void *emac_stats,
457                                     const void *pmac_stats, size_t stats_size,
458                                     size_t stats_offset)
459 {
460         size_t num_stats = stats_size / sizeof(u64);
461         const u64 *s1 = emac_stats + stats_offset;
462         const u64 *s2 = pmac_stats + stats_offset;
463         u64 *s = aggr_stats + stats_offset;
464         int i;
465
466         for (i = 0; i < num_stats; i++)
467                 s[i] = ethtool_stats_sum(s1[i], s2[i]);
468 }
469
470 void ethtool_aggregate_mac_stats(struct net_device *dev,
471                                  struct ethtool_eth_mac_stats *mac_stats)
472 {
473         const struct ethtool_ops *ops = dev->ethtool_ops;
474         struct ethtool_eth_mac_stats pmac, emac;
475
476         memset(&emac, 0xff, sizeof(emac));
477         memset(&pmac, 0xff, sizeof(pmac));
478         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
479         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
480
481         ops->get_eth_mac_stats(dev, &emac);
482         ops->get_eth_mac_stats(dev, &pmac);
483
484         ethtool_aggregate_stats(mac_stats, &emac, &pmac,
485                                 sizeof(mac_stats->stats),
486                                 offsetof(struct ethtool_eth_mac_stats, stats));
487 }
488 EXPORT_SYMBOL(ethtool_aggregate_mac_stats);
489
490 void ethtool_aggregate_phy_stats(struct net_device *dev,
491                                  struct ethtool_eth_phy_stats *phy_stats)
492 {
493         const struct ethtool_ops *ops = dev->ethtool_ops;
494         struct ethtool_eth_phy_stats pmac, emac;
495
496         memset(&emac, 0xff, sizeof(emac));
497         memset(&pmac, 0xff, sizeof(pmac));
498         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
499         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
500
501         ops->get_eth_phy_stats(dev, &emac);
502         ops->get_eth_phy_stats(dev, &pmac);
503
504         ethtool_aggregate_stats(phy_stats, &emac, &pmac,
505                                 sizeof(phy_stats->stats),
506                                 offsetof(struct ethtool_eth_phy_stats, stats));
507 }
508 EXPORT_SYMBOL(ethtool_aggregate_phy_stats);
509
510 void ethtool_aggregate_ctrl_stats(struct net_device *dev,
511                                   struct ethtool_eth_ctrl_stats *ctrl_stats)
512 {
513         const struct ethtool_ops *ops = dev->ethtool_ops;
514         struct ethtool_eth_ctrl_stats pmac, emac;
515
516         memset(&emac, 0xff, sizeof(emac));
517         memset(&pmac, 0xff, sizeof(pmac));
518         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
519         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
520
521         ops->get_eth_ctrl_stats(dev, &emac);
522         ops->get_eth_ctrl_stats(dev, &pmac);
523
524         ethtool_aggregate_stats(ctrl_stats, &emac, &pmac,
525                                 sizeof(ctrl_stats->stats),
526                                 offsetof(struct ethtool_eth_ctrl_stats, stats));
527 }
528 EXPORT_SYMBOL(ethtool_aggregate_ctrl_stats);
529
530 void ethtool_aggregate_pause_stats(struct net_device *dev,
531                                    struct ethtool_pause_stats *pause_stats)
532 {
533         const struct ethtool_ops *ops = dev->ethtool_ops;
534         struct ethtool_pause_stats pmac, emac;
535
536         memset(&emac, 0xff, sizeof(emac));
537         memset(&pmac, 0xff, sizeof(pmac));
538         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
539         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
540
541         ops->get_pause_stats(dev, &emac);
542         ops->get_pause_stats(dev, &pmac);
543
544         ethtool_aggregate_stats(pause_stats, &emac, &pmac,
545                                 sizeof(pause_stats->stats),
546                                 offsetof(struct ethtool_pause_stats, stats));
547 }
548 EXPORT_SYMBOL(ethtool_aggregate_pause_stats);
549
550 void ethtool_aggregate_rmon_stats(struct net_device *dev,
551                                   struct ethtool_rmon_stats *rmon_stats)
552 {
553         const struct ethtool_ops *ops = dev->ethtool_ops;
554         const struct ethtool_rmon_hist_range *dummy;
555         struct ethtool_rmon_stats pmac, emac;
556
557         memset(&emac, 0xff, sizeof(emac));
558         memset(&pmac, 0xff, sizeof(pmac));
559         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
560         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
561
562         ops->get_rmon_stats(dev, &emac, &dummy);
563         ops->get_rmon_stats(dev, &pmac, &dummy);
564
565         ethtool_aggregate_stats(rmon_stats, &emac, &pmac,
566                                 sizeof(rmon_stats->stats),
567                                 offsetof(struct ethtool_rmon_stats, stats));
568 }
569 EXPORT_SYMBOL(ethtool_aggregate_rmon_stats);