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