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