diff options
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r-- | drivers/net/skge.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c3d2e0a2c4e6..f59f37aaccec 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2767,6 +2767,17 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu) return err; } +static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 }; + +static void genesis_add_filter(u8 filter[8], const u8 *addr) +{ + u32 crc, bit; + + crc = ether_crc_le(ETH_ALEN, addr); + bit = ~crc & 0x3f; + filter[bit/8] |= 1 << (bit%8); +} + static void genesis_set_multicast(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); @@ -2788,24 +2799,33 @@ static void genesis_set_multicast(struct net_device *dev) memset(filter, 0xff, sizeof(filter)); else { memset(filter, 0, sizeof(filter)); - for (i = 0; list && i < count; i++, list = list->next) { - u32 crc, bit; - crc = ether_crc_le(ETH_ALEN, list->dmi_addr); - bit = ~crc & 0x3f; - filter[bit/8] |= 1 << (bit%8); - } + + if (skge->flow_status == FLOW_STAT_REM_SEND + || skge->flow_status == FLOW_STAT_SYMMETRIC) + genesis_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < count; i++, list = list->next) + genesis_add_filter(filter, list->dmi_addr); } xm_write32(hw, port, XM_MODE, mode); xm_outhash(hw, port, XM_HSM, filter); } +static void yukon_add_filter(u8 filter[8], const u8 *addr) +{ + u32 bit = ether_crc(ETH_ALEN, addr) & 0x3f; + filter[bit/8] |= 1 << (bit%8); +} + static void yukon_set_multicast(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; int port = skge->port; struct dev_mc_list *list = dev->mc_list; + int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND + || skge->flow_status == FLOW_STAT_SYMMETRIC); u16 reg; u8 filter[8]; @@ -2818,16 +2838,17 @@ static void yukon_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if (dev->flags & IFF_ALLMULTI) /* all multicast */ memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0) /* no multicast */ + else if (dev->mc_count == 0 && !rx_pause)/* no multicast */ reg &= ~GM_RXCR_MCF_ENA; else { int i; reg |= GM_RXCR_MCF_ENA; - for (i = 0; list && i < dev->mc_count; i++, list = list->next) { - u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; - filter[bit/8] |= 1 << (bit%8); - } + if (rx_pause) + yukon_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < dev->mc_count; i++, list = list->next) + yukon_add_filter(filter, list->dmi_addr); } |