Add callback and update the code to use the rx_mode snapshot and deferred write model
Signed-off-by: I Viswanath <[email protected]> --- This is a very weird driver in that it calls pcnet32_load_multicast to set up the mc filter registers instead of the set_rx_mode callback in ndo_open. I can't find a single other driver that does that. Apart from that, I don't think it makes sense for the (now) write_rx_mode callback to call netif_wake_queue(). Correct me if I am wrong here. drivers/net/ethernet/amd/pcnet32.c | 57 ++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index 9eaefa0f5e80..8bb0bb3da789 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -314,8 +314,9 @@ static void pcnet32_tx_timeout(struct net_device *dev, unsigned int txqueue); static irqreturn_t pcnet32_interrupt(int, void *); static int pcnet32_close(struct net_device *); static struct net_device_stats *pcnet32_get_stats(struct net_device *); -static void pcnet32_load_multicast(struct net_device *dev); +static void pcnet32_load_multicast(struct net_device *dev, bool is_open); static void pcnet32_set_multicast_list(struct net_device *); +static void pcnet32_write_multicast_list(struct net_device *); static int pcnet32_ioctl(struct net_device *, struct ifreq *, int); static void pcnet32_watchdog(struct timer_list *); static int mdio_read(struct net_device *dev, int phy_id, int reg_num); @@ -1580,6 +1581,7 @@ static const struct net_device_ops pcnet32_netdev_ops = { .ndo_tx_timeout = pcnet32_tx_timeout, .ndo_get_stats = pcnet32_get_stats, .ndo_set_rx_mode = pcnet32_set_multicast_list, + .ndo_write_rx_mode = pcnet32_write_multicast_list, .ndo_eth_ioctl = pcnet32_ioctl, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -2264,7 +2266,7 @@ static int pcnet32_open(struct net_device *dev) lp->init_block->mode = cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7); - pcnet32_load_multicast(dev); + pcnet32_load_multicast(dev, true); if (pcnet32_init_ring(dev)) { rc = -ENOMEM; @@ -2680,18 +2682,26 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) } /* taken from the sunlance driver, which it took from the depca driver */ -static void pcnet32_load_multicast(struct net_device *dev) +static void pcnet32_load_multicast(struct net_device *dev, bool is_open) { struct pcnet32_private *lp = netdev_priv(dev); volatile struct pcnet32_init_block *ib = lp->init_block; volatile __le16 *mcast_table = (__le16 *)ib->filter; struct netdev_hw_addr *ha; + char *ha_addr; + bool allmulti; unsigned long ioaddr = dev->base_addr; - int i; + int i, ni; u32 crc; + if (is_open) + allmulti = dev->flags & IFF_ALLMULTI; + else + allmulti = netif_rx_mode_get_cfg(dev, + NETIF_RX_MODE_CFG_ALLMULTI); + /* set all multicast bits */ - if (dev->flags & IFF_ALLMULTI) { + if (allmulti) { ib->filter[0] = cpu_to_le32(~0U); ib->filter[1] = cpu_to_le32(~0U); lp->a->write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff); @@ -2705,20 +2715,40 @@ static void pcnet32_load_multicast(struct net_device *dev) ib->filter[1] = 0; /* Add addresses */ - netdev_for_each_mc_addr(ha, dev) { - crc = ether_crc_le(6, ha->addr); - crc = crc >> 26; - mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf)); - } + if (is_open) + netdev_for_each_mc_addr(ha, dev) { + crc = ether_crc_le(6, ha->addr); + crc = crc >> 26; + mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf)); + } + else + netif_rx_mode_for_each_mc_addr(ha_addr, dev, ni) { + crc = ether_crc_le(6, ha_addr); + crc = crc >> 26; + mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf)); + } + for (i = 0; i < 4; i++) lp->a->write_csr(ioaddr, PCNET32_MC_FILTER + i, le16_to_cpu(mcast_table[i])); } +static void pcnet32_set_multicast_list(struct net_device *dev) +{ + bool allmulti = !!(dev->flags & IFF_ALLMULTI); + bool promisc = !!(dev->flags & IFF_PROMISC); + + netif_rx_mode_set_flag(dev, NETIF_RX_MODE_UC_SKIP, true); + netif_rx_mode_set_flag(dev, NETIF_RX_MODE_MC_SKIP, promisc | allmulti); + + netif_rx_mode_set_cfg(dev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti); + netif_rx_mode_set_cfg(dev, NETIF_RX_MODE_CFG_PROMISC, promisc); +} + /* * Set or clear the multicast filter for this adaptor. */ -static void pcnet32_set_multicast_list(struct net_device *dev) +static void pcnet32_write_multicast_list(struct net_device *dev) { unsigned long ioaddr = dev->base_addr, flags; struct pcnet32_private *lp = netdev_priv(dev); @@ -2727,7 +2757,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); suspended = pcnet32_suspend(dev, &flags, 0); csr15 = lp->a->read_csr(ioaddr, CSR15); - if (dev->flags & IFF_PROMISC) { + if (netif_rx_mode_get_cfg(dev, NETIF_RX_MODE_CFG_PROMISC)) { /* Log any net taps. */ netif_info(lp, hw, dev, "Promiscuous mode enabled\n"); lp->init_block->mode = @@ -2738,7 +2768,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev) lp->init_block->mode = cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a->write_csr(ioaddr, CSR15, csr15 & 0x7fff); - pcnet32_load_multicast(dev); + pcnet32_load_multicast(dev, false); } if (suspended) { @@ -2746,7 +2776,6 @@ static void pcnet32_set_multicast_list(struct net_device *dev) } else { lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); pcnet32_restart(dev, CSR0_NORMAL); - netif_wake_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); -- 2.47.3
