Loading drivers/net/dsa/qca/ar9331.c +162 −1 Original line number Diff line number Diff line Loading @@ -101,6 +101,9 @@ AR9331_SW_PORT_STATUS_RX_FLOW_EN | AR9331_SW_PORT_STATUS_TX_FLOW_EN | \ AR9331_SW_PORT_STATUS_SPEED_M) /* MIB registers */ #define AR9331_MIB_COUNTER(x) (0x20000 + ((x) * 0x100)) /* Phy bypass mode * ------------------------------------------------------------------------ * Bit: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 | Loading Loading @@ -154,6 +157,66 @@ #define AR9331_SW_MDIO_POLL_SLEEP_US 1 #define AR9331_SW_MDIO_POLL_TIMEOUT_US 20 /* The interval should be small enough to avoid overflow of 32bit MIBs */ /* * FIXME: until we can read MIBs from stats64 call directly (i.e. sleep * there), we have to poll stats more frequently then it is actually needed. * For overflow protection, normally, 100 sec interval should have been OK. */ #define STATS_INTERVAL_JIFFIES (3 * HZ) struct ar9331_sw_stats_raw { u32 rxbroad; /* 0x00 */ u32 rxpause; /* 0x04 */ u32 rxmulti; /* 0x08 */ u32 rxfcserr; /* 0x0c */ u32 rxalignerr; /* 0x10 */ u32 rxrunt; /* 0x14 */ u32 rxfragment; /* 0x18 */ u32 rx64byte; /* 0x1c */ u32 rx128byte; /* 0x20 */ u32 rx256byte; /* 0x24 */ u32 rx512byte; /* 0x28 */ u32 rx1024byte; /* 0x2c */ u32 rx1518byte; /* 0x30 */ u32 rxmaxbyte; /* 0x34 */ u32 rxtoolong; /* 0x38 */ u32 rxgoodbyte; /* 0x3c */ u32 rxgoodbyte_hi; u32 rxbadbyte; /* 0x44 */ u32 rxbadbyte_hi; u32 rxoverflow; /* 0x4c */ u32 filtered; /* 0x50 */ u32 txbroad; /* 0x54 */ u32 txpause; /* 0x58 */ u32 txmulti; /* 0x5c */ u32 txunderrun; /* 0x60 */ u32 tx64byte; /* 0x64 */ u32 tx128byte; /* 0x68 */ u32 tx256byte; /* 0x6c */ u32 tx512byte; /* 0x70 */ u32 tx1024byte; /* 0x74 */ u32 tx1518byte; /* 0x78 */ u32 txmaxbyte; /* 0x7c */ u32 txoversize; /* 0x80 */ u32 txbyte; /* 0x84 */ u32 txbyte_hi; u32 txcollision; /* 0x8c */ u32 txabortcol; /* 0x90 */ u32 txmulticol; /* 0x94 */ u32 txsinglecol; /* 0x98 */ u32 txexcdefer; /* 0x9c */ u32 txdefer; /* 0xa0 */ u32 txlatecol; /* 0xa4 */ }; struct ar9331_sw_port { int idx; struct delayed_work mib_read; struct rtnl_link_stats64 stats; struct spinlock stats_lock; }; struct ar9331_sw_priv { struct device *dev; struct dsa_switch ds; Loading @@ -165,8 +228,17 @@ struct ar9331_sw_priv { struct mii_bus *sbus; /* mdio slave */ struct regmap *regmap; struct reset_control *sw_reset; struct ar9331_sw_port port[AR9331_SW_PORTS]; }; static struct ar9331_sw_priv *ar9331_sw_port_to_priv(struct ar9331_sw_port *port) { struct ar9331_sw_port *p = port - port->idx; return (struct ar9331_sw_priv *)((void *)p - offsetof(struct ar9331_sw_priv, port)); } /* Warning: switch reset will reset last AR9331_SW_MDIO_PHY_MODE_PAGE request * If some kind of optimization is used, the request should be repeated. */ Loading Loading @@ -424,6 +496,7 @@ static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port, phy_interface_t interface) { struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; struct ar9331_sw_port *p = &priv->port[port]; struct regmap *regmap = priv->regmap; int ret; Loading @@ -431,6 +504,8 @@ static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port, AR9331_SW_PORT_STATUS_MAC_MASK, 0); if (ret) dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); cancel_delayed_work_sync(&p->mib_read); } static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, Loading @@ -441,10 +516,13 @@ static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, bool tx_pause, bool rx_pause) { struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; struct ar9331_sw_port *p = &priv->port[port]; struct regmap *regmap = priv->regmap; u32 val; int ret; schedule_delayed_work(&p->mib_read, 0); val = AR9331_SW_PORT_STATUS_MAC_MASK; switch (speed) { case SPEED_1000: Loading Loading @@ -477,6 +555,73 @@ static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); } static void ar9331_read_stats(struct ar9331_sw_port *port) { struct ar9331_sw_priv *priv = ar9331_sw_port_to_priv(port); struct rtnl_link_stats64 *stats = &port->stats; struct ar9331_sw_stats_raw raw; int ret; /* Do the slowest part first, to avoid needless locking for long time */ ret = regmap_bulk_read(priv->regmap, AR9331_MIB_COUNTER(port->idx), &raw, sizeof(raw) / sizeof(u32)); if (ret) { dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); return; } /* All MIB counters are cleared automatically on read */ spin_lock(&port->stats_lock); stats->rx_bytes += raw.rxgoodbyte; stats->tx_bytes += raw.txbyte; stats->rx_packets += raw.rx64byte + raw.rx128byte + raw.rx256byte + raw.rx512byte + raw.rx1024byte + raw.rx1518byte + raw.rxmaxbyte; stats->tx_packets += raw.tx64byte + raw.tx128byte + raw.tx256byte + raw.tx512byte + raw.tx1024byte + raw.tx1518byte + raw.txmaxbyte; stats->rx_length_errors += raw.rxrunt + raw.rxfragment + raw.rxtoolong; stats->rx_crc_errors += raw.rxfcserr; stats->rx_frame_errors += raw.rxalignerr; stats->rx_missed_errors += raw.rxoverflow; stats->rx_dropped += raw.filtered; stats->rx_errors += raw.rxfcserr + raw.rxalignerr + raw.rxrunt + raw.rxfragment + raw.rxoverflow + raw.rxtoolong; stats->tx_window_errors += raw.txlatecol; stats->tx_fifo_errors += raw.txunderrun; stats->tx_aborted_errors += raw.txabortcol; stats->tx_errors += raw.txoversize + raw.txabortcol + raw.txunderrun + raw.txlatecol; stats->multicast += raw.rxmulti; stats->collisions += raw.txcollision; spin_unlock(&port->stats_lock); } static void ar9331_do_stats_poll(struct work_struct *work) { struct ar9331_sw_port *port = container_of(work, struct ar9331_sw_port, mib_read.work); ar9331_read_stats(port); schedule_delayed_work(&port->mib_read, STATS_INTERVAL_JIFFIES); } static void ar9331_get_stats64(struct dsa_switch *ds, int port, struct rtnl_link_stats64 *s) { struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; struct ar9331_sw_port *p = &priv->port[port]; spin_lock(&p->stats_lock); memcpy(s, &p->stats, sizeof(*s)); spin_unlock(&p->stats_lock); } static const struct dsa_switch_ops ar9331_sw_ops = { .get_tag_protocol = ar9331_sw_get_tag_protocol, .setup = ar9331_sw_setup, Loading @@ -485,6 +630,7 @@ static const struct dsa_switch_ops ar9331_sw_ops = { .phylink_mac_config = ar9331_sw_phylink_mac_config, .phylink_mac_link_down = ar9331_sw_phylink_mac_link_down, .phylink_mac_link_up = ar9331_sw_phylink_mac_link_up, .get_stats64 = ar9331_get_stats64, }; static irqreturn_t ar9331_sw_irq(int irq, void *data) Loading Loading @@ -796,7 +942,7 @@ static int ar9331_sw_probe(struct mdio_device *mdiodev) { struct ar9331_sw_priv *priv; struct dsa_switch *ds; int ret; int ret, i; priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) Loading Loading @@ -831,6 +977,14 @@ static int ar9331_sw_probe(struct mdio_device *mdiodev) ds->ops = &priv->ops; dev_set_drvdata(&mdiodev->dev, priv); for (i = 0; i < ARRAY_SIZE(priv->port); i++) { struct ar9331_sw_port *port = &priv->port[i]; port->idx = i; spin_lock_init(&port->stats_lock); INIT_DELAYED_WORK(&port->mib_read, ar9331_do_stats_poll); } ret = dsa_register_switch(ds); if (ret) goto err_remove_irq; Loading @@ -846,6 +1000,13 @@ static int ar9331_sw_probe(struct mdio_device *mdiodev) static void ar9331_sw_remove(struct mdio_device *mdiodev) { struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev); unsigned int i; for (i = 0; i < ARRAY_SIZE(priv->port); i++) { struct ar9331_sw_port *port = &priv->port[i]; cancel_delayed_work_sync(&port->mib_read); } irq_domain_remove(priv->irqdomain); mdiobus_unregister(priv->mbus); Loading Loading
drivers/net/dsa/qca/ar9331.c +162 −1 Original line number Diff line number Diff line Loading @@ -101,6 +101,9 @@ AR9331_SW_PORT_STATUS_RX_FLOW_EN | AR9331_SW_PORT_STATUS_TX_FLOW_EN | \ AR9331_SW_PORT_STATUS_SPEED_M) /* MIB registers */ #define AR9331_MIB_COUNTER(x) (0x20000 + ((x) * 0x100)) /* Phy bypass mode * ------------------------------------------------------------------------ * Bit: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 | Loading Loading @@ -154,6 +157,66 @@ #define AR9331_SW_MDIO_POLL_SLEEP_US 1 #define AR9331_SW_MDIO_POLL_TIMEOUT_US 20 /* The interval should be small enough to avoid overflow of 32bit MIBs */ /* * FIXME: until we can read MIBs from stats64 call directly (i.e. sleep * there), we have to poll stats more frequently then it is actually needed. * For overflow protection, normally, 100 sec interval should have been OK. */ #define STATS_INTERVAL_JIFFIES (3 * HZ) struct ar9331_sw_stats_raw { u32 rxbroad; /* 0x00 */ u32 rxpause; /* 0x04 */ u32 rxmulti; /* 0x08 */ u32 rxfcserr; /* 0x0c */ u32 rxalignerr; /* 0x10 */ u32 rxrunt; /* 0x14 */ u32 rxfragment; /* 0x18 */ u32 rx64byte; /* 0x1c */ u32 rx128byte; /* 0x20 */ u32 rx256byte; /* 0x24 */ u32 rx512byte; /* 0x28 */ u32 rx1024byte; /* 0x2c */ u32 rx1518byte; /* 0x30 */ u32 rxmaxbyte; /* 0x34 */ u32 rxtoolong; /* 0x38 */ u32 rxgoodbyte; /* 0x3c */ u32 rxgoodbyte_hi; u32 rxbadbyte; /* 0x44 */ u32 rxbadbyte_hi; u32 rxoverflow; /* 0x4c */ u32 filtered; /* 0x50 */ u32 txbroad; /* 0x54 */ u32 txpause; /* 0x58 */ u32 txmulti; /* 0x5c */ u32 txunderrun; /* 0x60 */ u32 tx64byte; /* 0x64 */ u32 tx128byte; /* 0x68 */ u32 tx256byte; /* 0x6c */ u32 tx512byte; /* 0x70 */ u32 tx1024byte; /* 0x74 */ u32 tx1518byte; /* 0x78 */ u32 txmaxbyte; /* 0x7c */ u32 txoversize; /* 0x80 */ u32 txbyte; /* 0x84 */ u32 txbyte_hi; u32 txcollision; /* 0x8c */ u32 txabortcol; /* 0x90 */ u32 txmulticol; /* 0x94 */ u32 txsinglecol; /* 0x98 */ u32 txexcdefer; /* 0x9c */ u32 txdefer; /* 0xa0 */ u32 txlatecol; /* 0xa4 */ }; struct ar9331_sw_port { int idx; struct delayed_work mib_read; struct rtnl_link_stats64 stats; struct spinlock stats_lock; }; struct ar9331_sw_priv { struct device *dev; struct dsa_switch ds; Loading @@ -165,8 +228,17 @@ struct ar9331_sw_priv { struct mii_bus *sbus; /* mdio slave */ struct regmap *regmap; struct reset_control *sw_reset; struct ar9331_sw_port port[AR9331_SW_PORTS]; }; static struct ar9331_sw_priv *ar9331_sw_port_to_priv(struct ar9331_sw_port *port) { struct ar9331_sw_port *p = port - port->idx; return (struct ar9331_sw_priv *)((void *)p - offsetof(struct ar9331_sw_priv, port)); } /* Warning: switch reset will reset last AR9331_SW_MDIO_PHY_MODE_PAGE request * If some kind of optimization is used, the request should be repeated. */ Loading Loading @@ -424,6 +496,7 @@ static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port, phy_interface_t interface) { struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; struct ar9331_sw_port *p = &priv->port[port]; struct regmap *regmap = priv->regmap; int ret; Loading @@ -431,6 +504,8 @@ static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port, AR9331_SW_PORT_STATUS_MAC_MASK, 0); if (ret) dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); cancel_delayed_work_sync(&p->mib_read); } static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, Loading @@ -441,10 +516,13 @@ static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, bool tx_pause, bool rx_pause) { struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; struct ar9331_sw_port *p = &priv->port[port]; struct regmap *regmap = priv->regmap; u32 val; int ret; schedule_delayed_work(&p->mib_read, 0); val = AR9331_SW_PORT_STATUS_MAC_MASK; switch (speed) { case SPEED_1000: Loading Loading @@ -477,6 +555,73 @@ static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); } static void ar9331_read_stats(struct ar9331_sw_port *port) { struct ar9331_sw_priv *priv = ar9331_sw_port_to_priv(port); struct rtnl_link_stats64 *stats = &port->stats; struct ar9331_sw_stats_raw raw; int ret; /* Do the slowest part first, to avoid needless locking for long time */ ret = regmap_bulk_read(priv->regmap, AR9331_MIB_COUNTER(port->idx), &raw, sizeof(raw) / sizeof(u32)); if (ret) { dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); return; } /* All MIB counters are cleared automatically on read */ spin_lock(&port->stats_lock); stats->rx_bytes += raw.rxgoodbyte; stats->tx_bytes += raw.txbyte; stats->rx_packets += raw.rx64byte + raw.rx128byte + raw.rx256byte + raw.rx512byte + raw.rx1024byte + raw.rx1518byte + raw.rxmaxbyte; stats->tx_packets += raw.tx64byte + raw.tx128byte + raw.tx256byte + raw.tx512byte + raw.tx1024byte + raw.tx1518byte + raw.txmaxbyte; stats->rx_length_errors += raw.rxrunt + raw.rxfragment + raw.rxtoolong; stats->rx_crc_errors += raw.rxfcserr; stats->rx_frame_errors += raw.rxalignerr; stats->rx_missed_errors += raw.rxoverflow; stats->rx_dropped += raw.filtered; stats->rx_errors += raw.rxfcserr + raw.rxalignerr + raw.rxrunt + raw.rxfragment + raw.rxoverflow + raw.rxtoolong; stats->tx_window_errors += raw.txlatecol; stats->tx_fifo_errors += raw.txunderrun; stats->tx_aborted_errors += raw.txabortcol; stats->tx_errors += raw.txoversize + raw.txabortcol + raw.txunderrun + raw.txlatecol; stats->multicast += raw.rxmulti; stats->collisions += raw.txcollision; spin_unlock(&port->stats_lock); } static void ar9331_do_stats_poll(struct work_struct *work) { struct ar9331_sw_port *port = container_of(work, struct ar9331_sw_port, mib_read.work); ar9331_read_stats(port); schedule_delayed_work(&port->mib_read, STATS_INTERVAL_JIFFIES); } static void ar9331_get_stats64(struct dsa_switch *ds, int port, struct rtnl_link_stats64 *s) { struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; struct ar9331_sw_port *p = &priv->port[port]; spin_lock(&p->stats_lock); memcpy(s, &p->stats, sizeof(*s)); spin_unlock(&p->stats_lock); } static const struct dsa_switch_ops ar9331_sw_ops = { .get_tag_protocol = ar9331_sw_get_tag_protocol, .setup = ar9331_sw_setup, Loading @@ -485,6 +630,7 @@ static const struct dsa_switch_ops ar9331_sw_ops = { .phylink_mac_config = ar9331_sw_phylink_mac_config, .phylink_mac_link_down = ar9331_sw_phylink_mac_link_down, .phylink_mac_link_up = ar9331_sw_phylink_mac_link_up, .get_stats64 = ar9331_get_stats64, }; static irqreturn_t ar9331_sw_irq(int irq, void *data) Loading Loading @@ -796,7 +942,7 @@ static int ar9331_sw_probe(struct mdio_device *mdiodev) { struct ar9331_sw_priv *priv; struct dsa_switch *ds; int ret; int ret, i; priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) Loading Loading @@ -831,6 +977,14 @@ static int ar9331_sw_probe(struct mdio_device *mdiodev) ds->ops = &priv->ops; dev_set_drvdata(&mdiodev->dev, priv); for (i = 0; i < ARRAY_SIZE(priv->port); i++) { struct ar9331_sw_port *port = &priv->port[i]; port->idx = i; spin_lock_init(&port->stats_lock); INIT_DELAYED_WORK(&port->mib_read, ar9331_do_stats_poll); } ret = dsa_register_switch(ds); if (ret) goto err_remove_irq; Loading @@ -846,6 +1000,13 @@ static int ar9331_sw_probe(struct mdio_device *mdiodev) static void ar9331_sw_remove(struct mdio_device *mdiodev) { struct ar9331_sw_priv *priv = dev_get_drvdata(&mdiodev->dev); unsigned int i; for (i = 0; i < ARRAY_SIZE(priv->port); i++) { struct ar9331_sw_port *port = &priv->port[i]; cancel_delayed_work_sync(&port->mib_read); } irq_domain_remove(priv->irqdomain); mdiobus_unregister(priv->mbus); Loading