diff options
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 24 |
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 | ||
2853 | static 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 | |||
2853 | static void sky2_set_multicast(struct net_device *dev) | 2861 | static 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, |