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); 570