|
@@ -2767,6 +2767,17 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
|
|
|
+
|
|
|
+static void genesis_add_filter(u8 filter[8], const u8 *addr)
|
|
|
+{
|
|
|
+ u32 crc, bit;
|
|
|
+
|
|
|
+ crc = ether_crc_le(ETH_ALEN, addr);
|
|
|
+ bit = ~crc & 0x3f;
|
|
|
+ filter[bit/8] |= 1 << (bit%8);
|
|
|
+}
|
|
|
+
|
|
|
static void genesis_set_multicast(struct net_device *dev)
|
|
|
{
|
|
|
struct skge_port *skge = netdev_priv(dev);
|
|
@@ -2788,24 +2799,33 @@ static void genesis_set_multicast(struct net_device *dev)
|
|
|
memset(filter, 0xff, sizeof(filter));
|
|
|
else {
|
|
|
memset(filter, 0, sizeof(filter));
|
|
|
- for (i = 0; list && i < count; i++, list = list->next) {
|
|
|
- u32 crc, bit;
|
|
|
- crc = ether_crc_le(ETH_ALEN, list->dmi_addr);
|
|
|
- bit = ~crc & 0x3f;
|
|
|
- filter[bit/8] |= 1 << (bit%8);
|
|
|
- }
|
|
|
+
|
|
|
+ if (skge->flow_status == FLOW_STAT_REM_SEND
|
|
|
+ || skge->flow_status == FLOW_STAT_SYMMETRIC)
|
|
|
+ genesis_add_filter(filter, pause_mc_addr);
|
|
|
+
|
|
|
+ for (i = 0; list && i < count; i++, list = list->next)
|
|
|
+ genesis_add_filter(filter, list->dmi_addr);
|
|
|
}
|
|
|
|
|
|
xm_write32(hw, port, XM_MODE, mode);
|
|
|
xm_outhash(hw, port, XM_HSM, filter);
|
|
|
}
|
|
|
|
|
|
+static void yukon_add_filter(u8 filter[8], const u8 *addr)
|
|
|
+{
|
|
|
+ u32 bit = ether_crc(ETH_ALEN, addr) & 0x3f;
|
|
|
+ filter[bit/8] |= 1 << (bit%8);
|
|
|
+}
|
|
|
+
|
|
|
static void yukon_set_multicast(struct net_device *dev)
|
|
|
{
|
|
|
struct skge_port *skge = netdev_priv(dev);
|
|
|
struct skge_hw *hw = skge->hw;
|
|
|
int port = skge->port;
|
|
|
struct dev_mc_list *list = dev->mc_list;
|
|
|
+ int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND
|
|
|
+ || skge->flow_status == FLOW_STAT_SYMMETRIC);
|
|
|
u16 reg;
|
|
|
u8 filter[8];
|
|
|
|
|
@@ -2818,16 +2838,17 @@ static void yukon_set_multicast(struct net_device *dev)
|
|
|
reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
|
|
|
else if (dev->flags & IFF_ALLMULTI) /* all multicast */
|
|
|
memset(filter, 0xff, sizeof(filter));
|
|
|
- else if (dev->mc_count == 0) /* no multicast */
|
|
|
+ else if (dev->mc_count == 0 && !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 (rx_pause)
|
|
|
+ yukon_add_filter(filter, pause_mc_addr);
|
|
|
+
|
|
|
+ for (i = 0; list && i < dev->mc_count; i++, list = list->next)
|
|
|
+ yukon_add_filter(filter, list->dmi_addr);
|
|
|
}
|
|
|
|
|
|
|