Hi Tristan > +static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, > + u64 *cnt) > +{ > + u32 data; > + int timeout; > + struct ksz_port *p = &dev->ports[port]; > + > + /* retain the flush/freeze bit */ > + data = p->freeze ? MIB_COUNTER_FLUSH_FREEZE : 0; > + data |= MIB_COUNTER_READ; > + data |= (addr << MIB_COUNTER_INDEX_S); > + ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); > + > + timeout = 1000; > + do { > + ksz_pread32(dev, port, REG_PORT_MIB_CTRL_STAT__4, > + &data); > + usleep_range(1, 10); > + if (!(data & MIB_COUNTER_READ)) > + break; > + } while (timeout-- > 0);
Could you use readx_poll_timeout() here? > +void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf) > +{ > + struct ksz_device *dev = ds->priv; > + struct ksz_port_mib *mib; > + > + mib = &dev->ports[port].mib; > + > + /* freeze MIB counters if supported */ > + if (dev->dev_ops->freeze_mib) > + dev->dev_ops->freeze_mib(dev, port, true); > + mutex_lock(&mib->cnt_mutex); > + port_r_cnt(dev, port); > + mutex_unlock(&mib->cnt_mutex); > + if (dev->dev_ops->freeze_mib) > + dev->dev_ops->freeze_mib(dev, port, false); Should the freeze be protected by the mutex as well? > + memcpy(buf, mib->counters, dev->mib_cnt * sizeof(u64)); I wonder if this memcpy should also be protected by the mutex. As soon as the mutex is dropped, the scheduled work could start updating mib->counters in non-atomic ways? > +} > + > int ksz_port_bridge_join(struct dsa_switch *ds, int port, > struct net_device *br) > { > @@ -255,6 +349,7 @@ int ksz_enable_port(struct dsa_switch *ds, int port, > struct phy_device *phy) > /* setup slave port */ > dev->dev_ops->port_setup(dev, port, false); > dev->dev_ops->phy_setup(dev, port, phy); > + dev->dev_ops->port_init_cnt(dev, port); This is probably not the correct place to do this. MIB counters should not be cleared by an ifdown/ifup cycle. They should only be cleared when the driver is probed.