|
@@ -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,
|