--- forcedeth.c.orig 2010-04-26 16:48:30.000000000 +0200 +++ forcedeth.c 2010-05-21 13:22:25.705907294 +0200 @@ -837,6 +837,11 @@ char name_rx[IFNAMSIZ + 3]; /* -rx */ char name_tx[IFNAMSIZ + 3]; /* -tx */ char name_other[IFNAMSIZ + 6]; /* -other */ + + /* current packet filter state */ + u32 cur_pff; + u32 cur_addr[2]; + u32 cur_mask[2]; }; /* @@ -3128,17 +3133,28 @@ } addr[0] |= NVREG_MCASTADDRA_FORCE; pff |= NVREG_PFF_ALWAYS; - spin_lock_irq(&np->lock); - nv_stop_rx(dev); - writel(addr[0], base + NvRegMulticastAddrA); - writel(addr[1], base + NvRegMulticastAddrB); - writel(mask[0], base + NvRegMulticastMaskA); - writel(mask[1], base + NvRegMulticastMaskB); - writel(pff, base + NvRegPacketFilterFlags); - dprintk(KERN_INFO "%s: reconfiguration for multicast lists.\n", - dev->name); - nv_start_rx(dev); - spin_unlock_irq(&np->lock); + if (np->cur_pff != (pff & ~NVREG_PFF_PAUSE_RX) + || memcmp(np->cur_addr, addr, sizeof(np->cur_addr)) != 0 + || memcmp(np->cur_mask, mask, sizeof(np->cur_mask)) != 0) + { + dprintk(KERN_INFO "%s: reconfiguration for multicast lists.\n", + dev->name); + spin_lock_irq(&np->lock); + nv_stop_rx(dev); + writel(addr[0], base + NvRegMulticastAddrA); + writel(addr[1], base + NvRegMulticastAddrB); + writel(mask[0], base + NvRegMulticastMaskA); + writel(mask[1], base + NvRegMulticastMaskB); + writel(pff, base + NvRegPacketFilterFlags); + nv_start_rx(dev); + spin_unlock_irq(&np->lock); + memcpy(np->cur_addr, addr, sizeof(np->cur_addr)); + memcpy(np->cur_mask, mask, sizeof(np->cur_mask)); + np->cur_pff = pff & ~NVREG_PFF_PAUSE_RX; + } else { + dprintk(KERN_INFO "%s: pff state unchanged - skipping reconfiguration.\n", + dev->name); + } } static void nv_update_pause(struct net_device *dev, u32 pause_flags) @@ -5369,6 +5385,12 @@ writel(NVREG_MCASTMASKB_NONE, base + NvRegMulticastMaskB); writel(0, base + NvRegPacketFilterFlags); + np->cur_pff = 0; + np->cur_addr[0] = NVREG_MCASTADDRA_FORCE; + np->cur_addr[1] = 0; + np->cur_mask[0] = NVREG_MCASTMASKA_NONE; + np->cur_mask[1] = NVREG_MCASTMASKB_NONE; + writel(0, base + NvRegTransmitterControl); writel(0, base + NvRegReceiverControl);