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