Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-dsa-add-stats64-support'

Oleksij Rempel says:

====================
net: dsa: add stats64 support

changes v8:
- stats.no_handler should not be assigned from HW stats

changes v7:
- move raw.filtered from rx_errors to rx_dropped counter

changes v6:
- move stats64 callback to ethtool section
- ar9331: diff. fixes
- ar9331: move stats calculation to the worker
- ar9331: extend rx/tx error counters
- use spin lock instead of u64_stats*

changes v5:
- read all stats in one regmap_bulk_read() request
- protect stats with u64_stats* helpers.

changes v4:
- do no read MIBs withing stats64 call
- change polling frequency to 0.3Hz

changes v3:
- fix wrong multiplication
- cancel port workers on remove

changes v2:
- use stats64 instead of get_ethtool_stats
- add worked to poll for the stats
====================

Link: https://lore.kernel.org/r/20210111104658.21930-1-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+178 -3
+162 -1
drivers/net/dsa/qca/ar9331.c
··· 101 101 AR9331_SW_PORT_STATUS_RX_FLOW_EN | AR9331_SW_PORT_STATUS_TX_FLOW_EN | \ 102 102 AR9331_SW_PORT_STATUS_SPEED_M) 103 103 104 + /* MIB registers */ 105 + #define AR9331_MIB_COUNTER(x) (0x20000 + ((x) * 0x100)) 106 + 104 107 /* Phy bypass mode 105 108 * ------------------------------------------------------------------------ 106 109 * Bit: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 | ··· 157 154 #define AR9331_SW_MDIO_POLL_SLEEP_US 1 158 155 #define AR9331_SW_MDIO_POLL_TIMEOUT_US 20 159 156 157 + /* The interval should be small enough to avoid overflow of 32bit MIBs */ 158 + /* 159 + * FIXME: until we can read MIBs from stats64 call directly (i.e. sleep 160 + * there), we have to poll stats more frequently then it is actually needed. 161 + * For overflow protection, normally, 100 sec interval should have been OK. 162 + */ 163 + #define STATS_INTERVAL_JIFFIES (3 * HZ) 164 + 165 + struct ar9331_sw_stats_raw { 166 + u32 rxbroad; /* 0x00 */ 167 + u32 rxpause; /* 0x04 */ 168 + u32 rxmulti; /* 0x08 */ 169 + u32 rxfcserr; /* 0x0c */ 170 + u32 rxalignerr; /* 0x10 */ 171 + u32 rxrunt; /* 0x14 */ 172 + u32 rxfragment; /* 0x18 */ 173 + u32 rx64byte; /* 0x1c */ 174 + u32 rx128byte; /* 0x20 */ 175 + u32 rx256byte; /* 0x24 */ 176 + u32 rx512byte; /* 0x28 */ 177 + u32 rx1024byte; /* 0x2c */ 178 + u32 rx1518byte; /* 0x30 */ 179 + u32 rxmaxbyte; /* 0x34 */ 180 + u32 rxtoolong; /* 0x38 */ 181 + u32 rxgoodbyte; /* 0x3c */ 182 + u32 rxgoodbyte_hi; 183 + u32 rxbadbyte; /* 0x44 */ 184 + u32 rxbadbyte_hi; 185 + u32 rxoverflow; /* 0x4c */ 186 + u32 filtered; /* 0x50 */ 187 + u32 txbroad; /* 0x54 */ 188 + u32 txpause; /* 0x58 */ 189 + u32 txmulti; /* 0x5c */ 190 + u32 txunderrun; /* 0x60 */ 191 + u32 tx64byte; /* 0x64 */ 192 + u32 tx128byte; /* 0x68 */ 193 + u32 tx256byte; /* 0x6c */ 194 + u32 tx512byte; /* 0x70 */ 195 + u32 tx1024byte; /* 0x74 */ 196 + u32 tx1518byte; /* 0x78 */ 197 + u32 txmaxbyte; /* 0x7c */ 198 + u32 txoversize; /* 0x80 */ 199 + u32 txbyte; /* 0x84 */ 200 + u32 txbyte_hi; 201 + u32 txcollision; /* 0x8c */ 202 + u32 txabortcol; /* 0x90 */ 203 + u32 txmulticol; /* 0x94 */ 204 + u32 txsinglecol; /* 0x98 */ 205 + u32 txexcdefer; /* 0x9c */ 206 + u32 txdefer; /* 0xa0 */ 207 + u32 txlatecol; /* 0xa4 */ 208 + }; 209 + 210 + struct ar9331_sw_port { 211 + int idx; 212 + struct delayed_work mib_read; 213 + struct rtnl_link_stats64 stats; 214 + struct spinlock stats_lock; 215 + }; 216 + 160 217 struct ar9331_sw_priv { 161 218 struct device *dev; 162 219 struct dsa_switch ds; ··· 228 165 struct mii_bus *sbus; /* mdio slave */ 229 166 struct regmap *regmap; 230 167 struct reset_control *sw_reset; 168 + struct ar9331_sw_port port[AR9331_SW_PORTS]; 231 169 }; 170 + 171 + static struct ar9331_sw_priv *ar9331_sw_port_to_priv(struct ar9331_sw_port *port) 172 + { 173 + struct ar9331_sw_port *p = port - port->idx; 174 + 175 + return (struct ar9331_sw_priv *)((void *)p - 176 + offsetof(struct ar9331_sw_priv, port)); 177 + } 232 178 233 179 /* Warning: switch reset will reset last AR9331_SW_MDIO_PHY_MODE_PAGE request 234 180 * If some kind of optimization is used, the request should be repeated. ··· 496 424 phy_interface_t interface) 497 425 { 498 426 struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; 427 + struct ar9331_sw_port *p = &priv->port[port]; 499 428 struct regmap *regmap = priv->regmap; 500 429 int ret; 501 430 ··· 504 431 AR9331_SW_PORT_STATUS_MAC_MASK, 0); 505 432 if (ret) 506 433 dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); 434 + 435 + cancel_delayed_work_sync(&p->mib_read); 507 436 } 508 437 509 438 static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, ··· 516 441 bool tx_pause, bool rx_pause) 517 442 { 518 443 struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; 444 + struct ar9331_sw_port *p = &priv->port[port]; 519 445 struct regmap *regmap = priv->regmap; 520 446 u32 val; 521 447 int ret; 448 + 449 + schedule_delayed_work(&p->mib_read, 0); 522 450 523 451 val = AR9331_SW_PORT_STATUS_MAC_MASK; 524 452 switch (speed) { ··· 555 477 dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); 556 478 } 557 479 480 + static void ar9331_read_stats(struct ar9331_sw_port *port) 481 + { 482 + struct ar9331_sw_priv *priv = ar9331_sw_port_to_priv(port); 483 + struct rtnl_link_stats64 *stats = &port->stats; 484 + struct ar9331_sw_stats_raw raw; 485 + int ret; 486 + 487 + /* Do the slowest part first, to avoid needless locking for long time */ 488 + ret = regmap_bulk_read(priv->regmap, AR9331_MIB_COUNTER(port->idx), 489 + &raw, sizeof(raw) / sizeof(u32)); 490 + if (ret) { 491 + dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); 492 + return; 493 + } 494 + /* All MIB counters are cleared automatically on read */ 495 + 496 + spin_lock(&port->stats_lock); 497 + 498 + stats->rx_bytes += raw.rxgoodbyte; 499 + stats->tx_bytes += raw.txbyte; 500 + 501 + stats->rx_packets += raw.rx64byte + raw.rx128byte + raw.rx256byte + 502 + raw.rx512byte + raw.rx1024byte + raw.rx1518byte + raw.rxmaxbyte; 503 + stats->tx_packets += raw.tx64byte + raw.tx128byte + raw.tx256byte + 504 + raw.tx512byte + raw.tx1024byte + raw.tx1518byte + raw.txmaxbyte; 505 + 506 + stats->rx_length_errors += raw.rxrunt + raw.rxfragment + raw.rxtoolong; 507 + stats->rx_crc_errors += raw.rxfcserr; 508 + stats->rx_frame_errors += raw.rxalignerr; 509 + stats->rx_missed_errors += raw.rxoverflow; 510 + stats->rx_dropped += raw.filtered; 511 + stats->rx_errors += raw.rxfcserr + raw.rxalignerr + raw.rxrunt + 512 + raw.rxfragment + raw.rxoverflow + raw.rxtoolong; 513 + 514 + stats->tx_window_errors += raw.txlatecol; 515 + stats->tx_fifo_errors += raw.txunderrun; 516 + stats->tx_aborted_errors += raw.txabortcol; 517 + stats->tx_errors += raw.txoversize + raw.txabortcol + raw.txunderrun + 518 + raw.txlatecol; 519 + 520 + stats->multicast += raw.rxmulti; 521 + stats->collisions += raw.txcollision; 522 + 523 + spin_unlock(&port->stats_lock); 524 + } 525 + 526 + static void ar9331_do_stats_poll(struct work_struct *work) 527 + { 528 + struct ar9331_sw_port *port = container_of(work, struct ar9331_sw_port, 529 + mib_read.work); 530 + 531 + ar9331_read_stats(port); 532 + 533 + schedule_delayed_work(&port->mib_read, STATS_INTERVAL_JIFFIES); 534 + } 535 + 536 + static void ar9331_get_stats64(struct dsa_switch *ds, int port, 537 + struct rtnl_link_stats64 *s) 538 + { 539 + struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; 540 + struct ar9331_sw_port *p = &priv->port[port]; 541 + 542 + spin_lock(&p->stats_lock); 543 + memcpy(s, &p->stats, sizeof(*s)); 544 + spin_unlock(&p->stats_lock); 545 + } 546 + 558 547 static const struct dsa_switch_ops ar9331_sw_ops = { 559 548 .get_tag_protocol = ar9331_sw_get_tag_protocol, 560 549 .setup = ar9331_sw_setup, ··· 630 485 .phylink_mac_config = ar9331_sw_phylink_mac_config, 631 486 .phylink_mac_link_down = ar9331_sw_phylink_mac_link_down, 632 487 .phylink_mac_link_up = ar9331_sw_phylink_mac_link_up, 488 + .get_stats64 = ar9331_get_stats64, 633 489 }; 634 490 635 491 static irqreturn_t ar9331_sw_irq(int irq, void *data) ··· 942 796 { 943 797 struct ar9331_sw_priv *priv; 944 798 struct dsa_switch *ds; 945 - int ret; 799 + int ret, i; 946 800 947 801 priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); 948 802 if (!priv) ··· 977 831 ds->ops = &priv->ops; 978 832 dev_set_drvdata(&mdiodev->dev, priv); 979 833 834 + for (i = 0; i < ARRAY_SIZE(priv->port); i++) { 835 + struct ar9331_sw_port *port = &priv->port[i]; 836 + 837 + port->idx = i; 838 + spin_lock_init(&port->stats_lock); 839 + INIT_DELAYED_WORK(&port->mib_read, ar9331_do_stats_poll); 840 + } 841 + 980 842 ret = dsa_register_switch(ds); 981 843 if (ret) 982 844 goto err_remove_irq; ··· 1000 846 static void ar9331_sw_remove(struct mdio_device *mdiodev) 1001 847 { 1002 848 struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev); 849 + unsigned int i; 850 + 851 + for (i = 0; i < ARRAY_SIZE(priv->port); i++) { 852 + struct ar9331_sw_port *port = &priv->port[i]; 853 + 854 + cancel_delayed_work_sync(&port->mib_read); 855 + } 1003 856 1004 857 irq_domain_remove(priv->irqdomain); 1005 858 mdiobus_unregister(priv->mbus);
+3 -1
include/net/dsa.h
··· 482 482 void (*phylink_fixed_state)(struct dsa_switch *ds, int port, 483 483 struct phylink_link_state *state); 484 484 /* 485 - * ethtool hardware statistics. 485 + * Port statistics counters. 486 486 */ 487 487 void (*get_strings)(struct dsa_switch *ds, int port, 488 488 u32 stringset, uint8_t *data); ··· 491 491 int (*get_sset_count)(struct dsa_switch *ds, int port, int sset); 492 492 void (*get_ethtool_phy_stats)(struct dsa_switch *ds, 493 493 int port, uint64_t *data); 494 + void (*get_stats64)(struct dsa_switch *ds, int port, 495 + struct rtnl_link_stats64 *s); 494 496 495 497 /* 496 498 * ethtool Wake-on-LAN
+13 -1
net/dsa/slave.c
··· 1569 1569 return dp->ds->devlink ? &dp->devlink_port : NULL; 1570 1570 } 1571 1571 1572 + static void dsa_slave_get_stats64(struct net_device *dev, 1573 + struct rtnl_link_stats64 *s) 1574 + { 1575 + struct dsa_port *dp = dsa_slave_to_port(dev); 1576 + struct dsa_switch *ds = dp->ds; 1577 + 1578 + if (ds->ops->get_stats64) 1579 + ds->ops->get_stats64(ds, dp->index, s); 1580 + else 1581 + dev_get_tstats64(dev, s); 1582 + } 1583 + 1572 1584 static const struct net_device_ops dsa_slave_netdev_ops = { 1573 1585 .ndo_open = dsa_slave_open, 1574 1586 .ndo_stop = dsa_slave_close, ··· 1600 1588 #endif 1601 1589 .ndo_get_phys_port_name = dsa_slave_get_phys_port_name, 1602 1590 .ndo_setup_tc = dsa_slave_setup_tc, 1603 - .ndo_get_stats64 = dev_get_tstats64, 1591 + .ndo_get_stats64 = dsa_slave_get_stats64, 1604 1592 .ndo_get_port_parent_id = dsa_slave_get_port_parent_id, 1605 1593 .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid, 1606 1594 .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,