Implement the ndo_set_rx_mode_async callback and update the driver to use the snapshot/commit model for RX mode update. Signed-off-by: I Viswanath --- There are no calls to netif_set_rx_mode in pcnet32 drivers/net/ethernet/amd/pcnet32.c | 65 ++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index 911808ab13a7..d5ad96985d68 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_set_multicast_list_async(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_set_rx_mode_async = pcnet32_set_multicast_list_async, .ndo_eth_ioctl = pcnet32_ioctl, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -2260,7 +2262,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; @@ -2676,18 +2678,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_get_rx_mode_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); @@ -2701,20 +2711,41 @@ 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_set_rx_mode_flag(dev, NETIF_RX_MODE_UC_SKIP, true); + netif_set_rx_mode_flag(dev, NETIF_RX_MODE_MC_SKIP, promisc | allmulti); + + netif_set_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti); + netif_set_rx_mode_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_set_multicast_list_async(struct net_device *dev) { unsigned long ioaddr = dev->base_addr, flags; struct pcnet32_private *lp = netdev_priv(dev); @@ -2723,7 +2754,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_get_rx_mode_cfg(dev, NETIF_RX_MODE_CFG_PROMISC)) { /* Log any net taps. */ netif_info(lp, hw, dev, "Promiscuous mode enabled\n"); lp->init_block->mode = @@ -2734,7 +2765,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) { @@ -2922,6 +2953,7 @@ static int __maybe_unused pcnet32_pm_suspend(struct device *device_d) pcnet32_close(dev); } + netif_disable_async_ops(dev); return 0; } @@ -2929,6 +2961,7 @@ static int __maybe_unused pcnet32_pm_resume(struct device *device_d) { struct net_device *dev = dev_get_drvdata(device_d); + netif_enable_async_ops(dev); if (netif_running(dev)) { pcnet32_open(dev); netif_device_attach(dev); @@ -2937,6 +2970,13 @@ static int __maybe_unused pcnet32_pm_resume(struct device *device_d) return 0; } +static void pcnet32_shutdown(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + netif_disable_async_ops(dev); +} + static void pcnet32_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -2964,6 +3004,7 @@ static struct pci_driver pcnet32_driver = { .driver = { .pm = &pcnet32_pm_ops, }, + .shutdown = pcnet32_shutdown, }; /* An additional parameter that may be passed in... */ -- 2.47.3