sky2: accept multicast pause frames
authorStephen Hemminger <shemminger@osdl.org>
Tue, 17 Oct 2006 17:24:23 +0000 (10:24 -0700)
committerStephen Hemminger <shemminger@osdl.org>
Tue, 17 Oct 2006 17:24:23 +0000 (10:24 -0700)
When using flow control, the PHY needs to accept multicast pause frames.
Without this fix, these frames were getting discarded by the PHY before
doing any flow control.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
drivers/net/sky2.c

index c193383..67ecd66 100644 (file)
@@ -2850,6 +2850,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);
@@ -2858,7 +2866,10 @@ static void sky2_set_multicast(struct net_device *dev)
        struct dev_mc_list *list = dev->mc_list;
        u16 reg;
        u8 filter[8];
+       int rx_pause;
+       static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
 
+       rx_pause = (sky2->flow_status == FC_RX || sky2->flow_status == FC_BOTH);
        memset(filter, 0, sizeof(filter));
 
        reg = gma_read16(hw, port, GM_RX_CTRL);
@@ -2866,18 +2877,19 @@ static void sky2_set_multicast(struct net_device *dev)
 
        if (dev->flags & IFF_PROMISC)   /* promiscuous */
                reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
-       else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 16)     /* all multicast */
+       else if (dev->flags & IFF_ALLMULTI)
                memset(filter, 0xff, sizeof(filter));
-       else if (dev->mc_count == 0)    /* no multicast */
+       else if (dev->mc_count == 0 && !rx_pause)
                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)
+                       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,