diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-02-26 01:51:40 +0100 |
---|---|---|
committer | Adrian Bunk <bunk@stusta.de> | 2007-02-26 01:51:40 +0100 |
commit | c3208ec9d5dd6d925693ab8cf99bfdaf80d1b0c0 (patch) | |
tree | 8d15434ccc8ea4323c23a7f366e59631ae050e9b | |
parent | 6d33b0b0227977ccc7201bf223e0314b3db93e0a (diff) |
sky2: allow multicast pause frames
The 802 standard allows pause frames to be either unicast or multicast.
Switches seem to send unicast frames, but on a direct link, other boards send
multicast pause. Unless the filter bit is set, these pause frames get
dropped.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
-rw-r--r-- | drivers/net/sky2.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f0b19259319..a173e377580 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2686,6 +2686,14 @@ static int sky2_set_mac_address(struct net_device *dev, void *p) return 0; } +static void inline sky2_add_filter(u8 filter[8], const u8 *addr) +{ + u32 bit; + + bit = ether_crc(ETH_ALEN, addr) & 63; + filter[bit >> 3] |= 1 << (bit & 7); +} + static void sky2_set_multicast(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); @@ -2694,6 +2702,7 @@ static void sky2_set_multicast(struct net_device *dev) struct dev_mc_list *list = dev->mc_list; u16 reg; u8 filter[8]; + static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 }; memset(filter, 0, sizeof(filter)); @@ -2704,16 +2713,17 @@ static void sky2_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 16) /* all multicast */ memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0) /* no multicast */ + else if (dev->mc_count == 0 && !sky2->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 (sky2->rx_pause) + sky2_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < dev->mc_count; i++, list = list->next) + sky2_add_filter(filter, list->dmi_addr); } gma_write16(hw, port, GM_MC_ADDR_H1, |