aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/skge.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-27 07:39:04 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-27 07:39:04 -0800
commitce27002078e1e65c64395c0a3348786c974306cf (patch)
tree630eabb32368ee0d6ecceae36c550b832456df01 /drivers/net/skge.c
parent6c1586bc9356855159e5845c6e788aa6db333cb9 (diff)
parentf8dfdd5cab482a2ce4a8e2375e1512aa4829c653 (diff)
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (52 commits) netxen: do_rom_fast_write error handling natsemi: Fix detection of vanilla natsemi cards net: remove a collection of unneeded #undef REALLY_SLOW_IO stuff chelsio: Fix non-NAPI compile cxgb3 - Feed Rx free list with pages cxgb3 - Recovery from HW starvation of response queue entries. cxgb3 - Unmap offload packets when they are freed cxgb3 - FW version update cxgb3 - private ioctl cleanup cxgb3 - manage sysfs attributes per port S2IO: Restoring the mac address in s2io_reset S2IO: Avoid printing the Enhanced statistics for Xframe I card. S2IO: Making LED off during LINK_DOWN notification. S2IO: Added a loadable parameter to enable or disable vlan stripping in frame. S2IO: Optimized the delay to wait for command completion S2IO: Fixes for MSI and MSIX qla3xxx: Bumping driver version number qla3xxx: Kernic Panic on pSeries under stress conditions qla3xxx: bugfix tx reset after stress conditions. qla3xxx: Check return code from pci_map_single() in ql_release_to_lrg_buf_free_list(), ql_populate_free_queue(), ql_alloc_large_buffers(), and ql3xxx_send() ...
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r--drivers/net/skge.c47
1 files changed, 34 insertions, 13 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index c3d2e0a2c4e..eea75a401b0 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -77,13 +77,13 @@ static const struct pci_device_id skge_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) },
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T) },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, /* DGE-530T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
{ PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
{ PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) },
- { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, skge_id_table);
@@ -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);
}