|
17 | 17 | #include <linux/mdio.h>
|
18 | 18 | #include <linux/module.h>
|
19 | 19 | #include <linux/phy.h>
|
| 20 | +#include <linux/ethtool.h> |
20 | 21 |
|
21 | 22 | #define MII_BCM_CHANNEL_WIDTH 0x2000
|
22 | 23 | #define BCM_CL45VEN_EEE_ADV 0x3c
|
@@ -317,6 +318,75 @@ int bcm_phy_downshift_set(struct phy_device *phydev, u8 count)
|
317 | 318 | }
|
318 | 319 | EXPORT_SYMBOL_GPL(bcm_phy_downshift_set);
|
319 | 320 |
|
| 321 | +struct bcm_phy_hw_stat { |
| 322 | + const char *string; |
| 323 | + u8 reg; |
| 324 | + u8 shift; |
| 325 | + u8 bits; |
| 326 | +}; |
| 327 | + |
| 328 | +/* Counters freeze at either 0xffff or 0xff, better than nothing */ |
| 329 | +static const struct bcm_phy_hw_stat bcm_phy_hw_stats[] = { |
| 330 | + { "phy_receive_errors", MII_BRCM_CORE_BASE12, 0, 16 }, |
| 331 | + { "phy_serdes_ber_errors", MII_BRCM_CORE_BASE13, 8, 8 }, |
| 332 | + { "phy_false_carrier_sense_errors", MII_BRCM_CORE_BASE13, 0, 8 }, |
| 333 | + { "phy_local_rcvr_nok", MII_BRCM_CORE_BASE14, 8, 8 }, |
| 334 | + { "phy_remote_rcv_nok", MII_BRCM_CORE_BASE14, 0, 8 }, |
| 335 | +}; |
| 336 | + |
| 337 | +int bcm_phy_get_sset_count(struct phy_device *phydev) |
| 338 | +{ |
| 339 | + return ARRAY_SIZE(bcm_phy_hw_stats); |
| 340 | +} |
| 341 | +EXPORT_SYMBOL_GPL(bcm_phy_get_sset_count); |
| 342 | + |
| 343 | +void bcm_phy_get_strings(struct phy_device *phydev, u8 *data) |
| 344 | +{ |
| 345 | + unsigned int i; |
| 346 | + |
| 347 | + for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++) |
| 348 | + memcpy(data + i * ETH_GSTRING_LEN, |
| 349 | + bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN); |
| 350 | +} |
| 351 | +EXPORT_SYMBOL_GPL(bcm_phy_get_strings); |
| 352 | + |
| 353 | +#ifndef UINT64_MAX |
| 354 | +#define UINT64_MAX (u64)(~((u64)0)) |
| 355 | +#endif |
| 356 | + |
| 357 | +/* Caller is supposed to provide appropriate storage for the library code to |
| 358 | + * access the shadow copy |
| 359 | + */ |
| 360 | +static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow, |
| 361 | + unsigned int i) |
| 362 | +{ |
| 363 | + struct bcm_phy_hw_stat stat = bcm_phy_hw_stats[i]; |
| 364 | + int val; |
| 365 | + u64 ret; |
| 366 | + |
| 367 | + val = phy_read(phydev, stat.reg); |
| 368 | + if (val < 0) { |
| 369 | + ret = UINT64_MAX; |
| 370 | + } else { |
| 371 | + val >>= stat.shift; |
| 372 | + val = val & ((1 << stat.bits) - 1); |
| 373 | + shadow[i] += val; |
| 374 | + ret = shadow[i]; |
| 375 | + } |
| 376 | + |
| 377 | + return ret; |
| 378 | +} |
| 379 | + |
| 380 | +void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow, |
| 381 | + struct ethtool_stats *stats, u64 *data) |
| 382 | +{ |
| 383 | + unsigned int i; |
| 384 | + |
| 385 | + for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++) |
| 386 | + data[i] = bcm_phy_get_stat(phydev, shadow, i); |
| 387 | +} |
| 388 | +EXPORT_SYMBOL_GPL(bcm_phy_get_stats); |
| 389 | + |
320 | 390 | MODULE_DESCRIPTION("Broadcom PHY Library");
|
321 | 391 | MODULE_LICENSE("GPL v2");
|
322 | 392 | MODULE_AUTHOR("Broadcom Corporation");
|
0 commit comments