@@ -477,6 +592,128 @@ static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port,
dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret);
}
+#define AR9331_STATS_ADD(_stats, _raw, _reg) \
+{ \
+ u64_stats_add(&_stats->_reg, _raw._reg); \
+}
+
+static void ar9331_read_stats(struct ar9331_sw_port *port)
+{
+ struct ar9331_sw_stats *stats = &port->stats;
+ struct ar9331_sw_priv *priv = port->priv;
+ struct ar9331_sw_stats_raw raw;
+ int ret;
+
+ /* Do the slowest part first, to avoid needles 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 */
+
+ u64_stats_update_begin(&stats->syncp);
+
+ AR9331_STATS_ADD(stats, raw, rxgoodbyte);
+ AR9331_STATS_ADD(stats, raw, rxbroad);
+ AR9331_STATS_ADD(stats, raw, rxpause);
+ AR9331_STATS_ADD(stats, raw, rxmulti);
+ AR9331_STATS_ADD(stats, raw, rxfcserr);
+ AR9331_STATS_ADD(stats, raw, rxalignerr);
+ AR9331_STATS_ADD(stats, raw, rxrunt);
+ AR9331_STATS_ADD(stats, raw, rxfragment);
+ AR9331_STATS_ADD(stats, raw, rx64byte);
+ AR9331_STATS_ADD(stats, raw, rx128byte);
+ AR9331_STATS_ADD(stats, raw, rx256byte);
+ AR9331_STATS_ADD(stats, raw, rx512byte);
+ AR9331_STATS_ADD(stats, raw, rx1024byte);
+ AR9331_STATS_ADD(stats, raw, rx1518byte);
+ AR9331_STATS_ADD(stats, raw, rxmaxbyte);
+ AR9331_STATS_ADD(stats, raw, rxtoolong);
+ AR9331_STATS_ADD(stats, raw, rxbadbyte);
+ AR9331_STATS_ADD(stats, raw, rxoverflow);
+ AR9331_STATS_ADD(stats, raw, filtered);
+ AR9331_STATS_ADD(stats, raw, txbroad);
+ AR9331_STATS_ADD(stats, raw, txpause);
+ AR9331_STATS_ADD(stats, raw, txmulti);
+ AR9331_STATS_ADD(stats, raw, txunderrun);
+ AR9331_STATS_ADD(stats, raw, tx64byte);
+ AR9331_STATS_ADD(stats, raw, tx128byte);
+ AR9331_STATS_ADD(stats, raw, tx256byte);
+ AR9331_STATS_ADD(stats, raw, tx512byte);
+ AR9331_STATS_ADD(stats, raw, tx1024byte);
+ AR9331_STATS_ADD(stats, raw, tx1518byte);
+ AR9331_STATS_ADD(stats, raw, txmaxbyte);
+ AR9331_STATS_ADD(stats, raw, txoversize);
+ AR9331_STATS_ADD(stats, raw, txbyte);
+ AR9331_STATS_ADD(stats, raw, txcollision);
+ AR9331_STATS_ADD(stats, raw, txabortcol);
+ AR9331_STATS_ADD(stats, raw, txmulticol);
+ AR9331_STATS_ADD(stats, raw, txsinglecol);
+ AR9331_STATS_ADD(stats, raw, txexcdefer);
+ AR9331_STATS_ADD(stats, raw, txdefer);
+ AR9331_STATS_ADD(stats, raw, txlatecol);
+
+ u64_stats_update_end(&stats->syncp);
+}
+
+static void ar9331_stats_update(struct ar9331_sw_port *port,
+ struct rtnl_link_stats64 *stats)
+{
+ struct ar9331_sw_stats *s = &port->stats;
+
+ stats->rx_packets = u64_stats_read(&s->rx64byte) +
+ u64_stats_read(&s->rx128byte) + u64_stats_read(&s->rx256byte) +
+ u64_stats_read(&s->rx512byte) + u64_stats_read(&s->rx1024byte) +
+ u64_stats_read(&s->rx1518byte) + u64_stats_read(&s->rxmaxbyte);
+ stats->tx_packets = u64_stats_read(&s->tx64byte) +
+ u64_stats_read(&s->tx128byte) + u64_stats_read(&s->tx256byte) +
+ u64_stats_read(&s->tx512byte) + u64_stats_read(&s->tx1024byte) +
+ u64_stats_read(&s->tx1518byte) + u64_stats_read(&s->txmaxbyte);
+ stats->rx_bytes = u64_stats_read(&s->rxgoodbyte);
+ stats->tx_bytes = u64_stats_read(&s->txbyte);
+ stats->rx_errors = u64_stats_read(&s->rxfcserr) +
+ u64_stats_read(&s->rxalignerr) + u64_stats_read(&s->rxrunt) +
+ u64_stats_read(&s->rxfragment) + u64_stats_read(&s->rxoverflow);
+ stats->tx_errors = u64_stats_read(&s->txoversize);
+ stats->multicast = u64_stats_read(&s->rxmulti);
+ stats->collisions = u64_stats_read(&s->txcollision);
+ stats->rx_length_errors = u64_stats_read(&s->rxrunt) +
+ u64_stats_read(&s->rxfragment) + u64_stats_read(&s->rxtoolong);
+ stats->rx_crc_errors = u64_stats_read(&s->rxfcserr) +
+ u64_stats_read(&s->rxalignerr) + u64_stats_read(&s->rxfragment);
+ stats->rx_frame_errors = u64_stats_read(&s->rxalignerr);
+ stats->rx_missed_errors = u64_stats_read(&s->rxoverflow);
+ stats->tx_aborted_errors = u64_stats_read(&s->txabortcol);
+ stats->tx_fifo_errors = u64_stats_read(&s->txunderrun);
+ stats->tx_window_errors = u64_stats_read(&s->txlatecol);
+ stats->rx_nohandler = u64_stats_read(&s->filtered);
+}
+
+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];
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&p->stats.syncp);
+ ar9331_stats_update(p, s);
+ } while (u64_stats_fetch_retry(&p->stats.syncp, start));
+}
+
static const struct dsa_switch_ops ar9331_sw_ops = {
.get_tag_protocol = ar9331_sw_get_tag_protocol,
.setup = ar9331_sw_setup,