aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-10-17 13:24:23 -0400
committerStephen Hemminger <shemminger@osdl.org>2006-10-17 13:24:23 -0400
commita052b52f4b6b77503af2647dc0c7415939d8232a (patch)
treee62c42a7d2dfaceb7ddbd86e5fc8c5e444ecb77a /drivers/net/sky2.c
parent52c89cac6781dea0ee2426821cd3effae1a925d3 (diff)
sky2: accept multicast pause frames
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>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index c19338351780..67ecd66f26d6 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2850,6 +2850,14 @@ static int sky2_set_mac_address(struct net_device *dev, void *p)
2850 return 0; 2850 return 0;
2851} 2851}
2852 2852
2853static void inline sky2_add_filter(u8 filter[8], const u8 *addr)
2854{
2855 u32 bit;
2856
2857 bit = ether_crc(ETH_ALEN, addr) & 63;
2858 filter[bit >> 3] |= 1 << (bit & 7);
2859}
2860
2853static void sky2_set_multicast(struct net_device *dev) 2861static void sky2_set_multicast(struct net_device *dev)
2854{ 2862{
2855 struct sky2_port *sky2 = netdev_priv(dev); 2863 struct sky2_port *sky2 = netdev_priv(dev);
@@ -2858,7 +2866,10 @@ static void sky2_set_multicast(struct net_device *dev)
2858 struct dev_mc_list *list = dev->mc_list; 2866 struct dev_mc_list *list = dev->mc_list;
2859 u16 reg; 2867 u16 reg;
2860 u8 filter[8]; 2868 u8 filter[8];
2869 int rx_pause;
2870 static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
2861 2871
2872 rx_pause = (sky2->flow_status == FC_RX || sky2->flow_status == FC_BOTH);
2862 memset(filter, 0, sizeof(filter)); 2873 memset(filter, 0, sizeof(filter));
2863 2874
2864 reg = gma_read16(hw, port, GM_RX_CTRL); 2875 reg = gma_read16(hw, port, GM_RX_CTRL);
@@ -2866,18 +2877,19 @@ static void sky2_set_multicast(struct net_device *dev)
2866 2877
2867 if (dev->flags & IFF_PROMISC) /* promiscuous */ 2878 if (dev->flags & IFF_PROMISC) /* promiscuous */
2868 reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); 2879 reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
2869 else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 16) /* all multicast */ 2880 else if (dev->flags & IFF_ALLMULTI)
2870 memset(filter, 0xff, sizeof(filter)); 2881 memset(filter, 0xff, sizeof(filter));
2871 else if (dev->mc_count == 0) /* no multicast */ 2882 else if (dev->mc_count == 0 && !rx_pause)
2872 reg &= ~GM_RXCR_MCF_ENA; 2883 reg &= ~GM_RXCR_MCF_ENA;
2873 else { 2884 else {
2874 int i; 2885 int i;
2875 reg |= GM_RXCR_MCF_ENA; 2886 reg |= GM_RXCR_MCF_ENA;
2876 2887
2877 for (i = 0; list && i < dev->mc_count; i++, list = list->next) { 2888 if (rx_pause)
2878 u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; 2889 sky2_add_filter(filter, pause_mc_addr);
2879 filter[bit / 8] |= 1 << (bit % 8); 2890
2880 } 2891 for (i = 0; list && i < dev->mc_count; i++, list = list->next)
2892 sky2_add_filter(filter, list->dmi_addr);
2881 } 2893 }
2882 2894
2883 gma_write16(hw, port, GM_MC_ADDR_H1, 2895 gma_write16(hw, port, GM_MC_ADDR_H1,