aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-02-26 01:51:40 +0100
committerAdrian Bunk <bunk@stusta.de>2007-02-26 01:51:40 +0100
commitc3208ec9d5dd6d925693ab8cf99bfdaf80d1b0c0 (patch)
tree8d15434ccc8ea4323c23a7f366e59631ae050e9b
parent6d33b0b0227977ccc7201bf223e0314b3db93e0a (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.c20
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,