From cd926c7330ae76b620853533e68654a1ef0c2347 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 16 Oct 2008 22:04:07 +0200 Subject: r8169: verbose mac address init I prefer the debug information to be displayed until the issue is properly handled. Signed-off-by: Francois Romieu Cc: Edward Hsu --- drivers/net/r8169.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c821da21d8e..cd9a21581f5 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1947,11 +1947,11 @@ static void rtl_init_mac_address(struct rtl8169_private *tp, u8 cfg1; int vpd_cap; u8 mac[8]; - DECLARE_MAC_BUF(buf); cfg1 = RTL_R8(Config1); if (!(cfg1 & VPD)) { - dprintk("VPD access not enabled, enabling\n"); + if (netif_msg_probe(tp)) + dev_info(&pdev->dev, "VPD access disabled, enabling\n"); RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, cfg1 | VPD); RTL_W8(Cfg9346, Cfg9346_Lock); @@ -1969,11 +1969,19 @@ static void rtl_init_mac_address(struct rtl8169_private *tp, */ if (rtl_eeprom_read(pdev, vpd_cap, 0x000e, (__le32*)&mac[0]) < 0 || rtl_eeprom_read(pdev, vpd_cap, 0x0012, (__le32*)&mac[4]) < 0) { - dprintk("Reading MAC address from EEPROM failed\n"); + if (netif_msg_probe(tp)) { + dev_warn(&pdev->dev, + "reading MAC address from EEPROM failed\n"); + } return; } - dprintk("MAC address found in EEPROM: %s\n", print_mac(buf, mac)); + if (netif_msg_probe(tp)) { + DECLARE_MAC_BUF(buf); + + dev_info(&pdev->dev, "MAC address found in EEPROM: %s\n", + print_mac(buf, mac)); + } /* Write MAC address */ rtl_rar_set(tp, mac); -- cgit v1.2.3 From e1564ec938b759268d6e67f24b5d6f429da4a5a9 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 16 Oct 2008 22:46:13 +0200 Subject: r8169: checks against wrong mac addresse init Checking the signature of the eeprom and the validity of the MAC address should be enough to filter out the bad addresses observed so far. Contributed by Ivan Vecera and Martin Capitanio. Tested on 8102el, 8168b and 8169 for a start. Signed-off-by: Francois Romieu Cc: Edward Hsu --- drivers/net/r8169.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index cd9a21581f5..2b4e975770f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -81,6 +81,10 @@ static const int multicast_filter_limit = 32; #define RTL8169_TX_TIMEOUT (6*HZ) #define RTL8169_PHY_TIMEOUT (10*HZ) +#define RTL_EEPROM_SIG cpu_to_le32(0x8129) +#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff) +#define RTL_EEPROM_SIG_ADDR 0x0000 + /* write/read MMIO register */ #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) #define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) @@ -1944,9 +1948,10 @@ static void rtl_init_mac_address(struct rtl8169_private *tp, void __iomem *ioaddr) { struct pci_dev *pdev = tp->pci_dev; - u8 cfg1; int vpd_cap; + __le32 sig; u8 mac[8]; + u8 cfg1; cfg1 = RTL_R8(Config1); if (!(cfg1 & VPD)) { @@ -1961,7 +1966,16 @@ static void rtl_init_mac_address(struct rtl8169_private *tp, if (!vpd_cap) return; - /* MAC address is stored in EEPROM at offset 0x0e + if (rtl_eeprom_read(pdev, vpd_cap, RTL_EEPROM_SIG_ADDR, &sig) < 0) + return; + + if ((sig & RTL_EEPROM_SIG_MASK) != RTL_EEPROM_SIG) { + dev_info(&pdev->dev, "Missing EEPROM signature: %08x\n", sig); + return; + } + + /* + * MAC address is stored in EEPROM at offset 0x0e * Realtek says: "The VPD address does not have to be a DWORD-aligned * address as defined in the PCI 2.2 Specifications, but the VPD data * is always consecutive 4-byte data starting from the VPD address @@ -1983,8 +1997,8 @@ static void rtl_init_mac_address(struct rtl8169_private *tp, print_mac(buf, mac)); } - /* Write MAC address */ - rtl_rar_set(tp, mac); + if (is_valid_ether_addr(mac)) + rtl_rar_set(tp, mac); } static int __devinit -- cgit v1.2.3 From d51894f4979e941a86309f29898579cbb591514e Mon Sep 17 00:00:00 2001 From: roel kluin Date: Tue, 21 Oct 2008 01:35:34 -0400 Subject: gianfar: fix handle errors returned by platform_get_irq*() platform_get_irq*() returns on -ENXIO when the resource cannot be found, but this remains unnoticed if stored in an unsigned. Signed-off-by: Roel Kluin Signed-off-by: Jeff Garzik --- drivers/net/gianfar.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index b5bb7ae2817..64b201134fd 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -161,7 +161,7 @@ static int gfar_probe(struct platform_device *pdev) struct gfar_private *priv = NULL; struct gianfar_platform_data *einfo; struct resource *r; - int err = 0; + int err = 0, irq; DECLARE_MAC_BUF(mac); einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; @@ -187,15 +187,25 @@ static int gfar_probe(struct platform_device *pdev) /* fill out IRQ fields */ if (einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - priv->interruptTransmit = platform_get_irq_byname(pdev, "tx"); - priv->interruptReceive = platform_get_irq_byname(pdev, "rx"); - priv->interruptError = platform_get_irq_byname(pdev, "error"); - if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0) + irq = platform_get_irq_byname(pdev, "tx"); + if (irq < 0) + goto regs_fail; + priv->interruptTransmit = irq; + + irq = platform_get_irq_byname(pdev, "rx"); + if (irq < 0) + goto regs_fail; + priv->interruptReceive = irq; + + irq = platform_get_irq_byname(pdev, "error"); + if (irq < 0) goto regs_fail; + priv->interruptError = irq; } else { - priv->interruptTransmit = platform_get_irq(pdev, 0); - if (priv->interruptTransmit < 0) + irq = platform_get_irq(pdev, 0); + if (irq < 0) goto regs_fail; + priv->interruptTransmit = irq; } /* get a pointer to the register memory */ -- cgit v1.2.3 From ced1cbacc0557eda31ab59317c09f774cff865bb Mon Sep 17 00:00:00 2001 From: roel kluin Date: Tue, 21 Oct 2008 01:44:02 -0400 Subject: AX88796: ax_probe() fix irq assignment dev->irq is unsigned Signed-off-by: Roel Kluin Signed-off-by: Jeff Garzik --- drivers/net/ax88796.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 4207d6efddc..9a314d88e7b 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -838,12 +838,12 @@ static int ax_probe(struct platform_device *pdev) /* find the platform resources */ - dev->irq = platform_get_irq(pdev, 0); - if (dev->irq < 0) { + ret = platform_get_irq(pdev, 0); + if (ret < 0) { dev_err(&pdev->dev, "no IRQ specified\n"); - ret = -ENXIO; goto exit_mem; } + dev->irq = ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { -- cgit v1.2.3 From cde0d910b9185519f7f2cfe015f9039e02c2f25b Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 21 Oct 2008 00:00:29 +0900 Subject: net: Make SMC91X selectable on other MIPS boards RBTX4939 board has SMC91X chip and there can be other MIPS boards with that chip. Make SMC91X selectable on all MIPS board would be better than enumerating each boards in Kconfig. Signed-off-by: Atsushi Nemoto Cc: jeff@garzik.org Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ad301ace608..021e8f16740 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -888,7 +888,7 @@ config SMC91X select CRC32 select MII depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || \ - SOC_AU1X00 || BLACKFIN || MN10300 + MIPS || BLACKFIN || MN10300 help This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it -- cgit v1.2.3 From 051d36f3fbd013a73cb42a6762e5bf339a3732aa Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Mon, 20 Oct 2008 13:54:12 +0200 Subject: myri10ge: disable NAPI on failure to setup the interface Disable NAPI if a failure occurs when setting up the interface. Leaving it enabled could cause a BUG the next time an ifconfig up is issued. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index a9aebad5265..b1556b2e404 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.4.3-1.369" +#define MYRI10GE_VERSION_STR "1.4.3-1.371" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -2497,6 +2497,10 @@ static int myri10ge_open(struct net_device *dev) return 0; abort_with_rings: + while (slice) { + slice--; + napi_disable(&mgp->ss[slice].napi); + } for (i = 0; i < mgp->num_slices; i++) myri10ge_free_rings(&mgp->ss[i]); -- cgit v1.2.3 From d766a4eda65b80afb50a39ce15c0ca424115bc07 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 21 Oct 2008 04:36:29 +0400 Subject: SMC911x: unbreak PXA builds Currently SMC911x driver is broken on ARM/PXA builds. Unbreak such configurations. Signed-off-by: Dmitry Baryshkov Signed-off-by: Jeff Garzik --- drivers/net/smc911x.c | 2 +- drivers/net/smc911x.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 8aa7460ef0e..ec32b5d89c9 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1242,7 +1242,7 @@ smc911x_rx_dma_irq(int dma, void *data) netif_rx(skb); spin_lock_irqsave(&lp->lock, flags); - pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16; + pkts = (SMC_GET_RX_FIFO_INF(lp) & RX_FIFO_INF_RXSUSED_) >> 16; if (pkts != 0) { smc911x_rcv(dev); }else { diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index bf6240f23f5..cc7d85bdfb3 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -50,6 +50,10 @@ #define SMC_DYNAMIC_BUS_CONFIG #endif +#ifdef SMC_USE_PXA_DMA +#define SMC_USE_DMA +#endif + /* store this information for the driver.. */ struct smc911x_local { /* @@ -196,8 +200,6 @@ static inline void SMC_outsl(struct smc911x_local *lp, int reg, #ifdef SMC_USE_PXA_DMA -#define SMC_USE_DMA - /* * Define the request and free functions * These are unfortunately architecture specific as no generic allocation -- cgit v1.2.3 From 6d329af9967e7ab3f4a3d7f1e8ef87539c3a069f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 17 Oct 2008 14:18:26 -0700 Subject: cxgb3: Fix kernel crash caused by uninitialized l2t_entry.arpq Commit 147e70e6 ("cxgb3: Use SKB list interfaces instead of home-grown implementation.") causes a crash in t3_l2t_send_slow() when an iWARP connection request is received. This is because the new l2t_entry.arpq skb queue is never initialized, and therefore trying to add an skb to it causes a NULL dereference. With the old code there was no need to initialize the queues because the l2t_entry structures were zeroed, and the code used NULL to mean empty. Fix this by adding __skb_queue_head_init() when all the l2t_entry structures get allocated. Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/l2t.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index 4407ac9bb55..ff1611f90e7 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -431,6 +431,7 @@ struct l2t_data *t3_init_l2t(unsigned int l2t_capacity) for (i = 0; i < l2t_capacity; ++i) { d->l2tab[i].idx = i; d->l2tab[i].state = L2T_STATE_UNUSED; + __skb_queue_head_init(&d->l2tab[i].arpq); spin_lock_init(&d->l2tab[i].lock); atomic_set(&d->l2tab[i].refcnt, 0); } -- cgit v1.2.3 From 93fbaae188fba7c2a6e458f62e1f61439caebfc8 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Fri, 17 Oct 2008 01:40:44 +0800 Subject: netdev: DM9000: remove BLACKFIN hacking in DM9000 netdev driver remove integer casting in the read/write IO accessors, because Blackfin now provides those functions Tested-by: Javier Herrero Signed-off-by: Bryan Wu Signed-off-by: Jeff Garzik --- drivers/net/dm9000.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index f42c23f4265..5a9083e3f44 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -47,15 +47,6 @@ #define CARDNAME "dm9000" #define DRV_VERSION "1.31" -#ifdef CONFIG_BLACKFIN -#define readsb insb -#define readsw insw -#define readsl insl -#define writesb outsb -#define writesw outsw -#define writesl outsl -#endif - /* * Transmit timeout, default 5 seconds. */ -- cgit v1.2.3 From d4f12daf7ba4efc506c377a9591ecdb692641fe5 Mon Sep 17 00:00:00 2001 From: Hannes Hering Date: Thu, 16 Oct 2008 11:36:42 +0200 Subject: ehea: Fix memory hotplug support This patch implements the memory notifier to update the busmap instantly instead of rebuilding the whole map. This is necessary because walk_memory_resource provides different information than required during memory hotplug. Signed-off-by: Hannes Hering Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea.h | 2 +- drivers/net/ehea/ehea_main.c | 25 +++++---- drivers/net/ehea/ehea_qmr.c | 131 +++++++++++++++++++++++++++++++++---------- drivers/net/ehea/ehea_qmr.h | 2 + 4 files changed, 119 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 5524271eedc..82dd1a891ce 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0093" +#define DRV_VERSION "EHEA_0094" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index b70c5314f53..422fcb93e2c 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2863,7 +2863,7 @@ static void ehea_rereg_mrs(struct work_struct *work) struct ehea_adapter *adapter; mutex_lock(&dlpar_mem_lock); - ehea_info("LPAR memory enlarged - re-initializing driver"); + ehea_info("LPAR memory changed - re-initializing driver"); list_for_each_entry(adapter, &adapter_list, list) if (adapter->active_ports) { @@ -2900,13 +2900,6 @@ static void ehea_rereg_mrs(struct work_struct *work) } } - ehea_destroy_busmap(); - ret = ehea_create_busmap(); - if (ret) { - ehea_error("creating ehea busmap failed"); - goto out; - } - clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags); list_for_each_entry(adapter, &adapter_list, list) @@ -3519,9 +3512,21 @@ void ehea_crash_handler(void) static int ehea_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) { + struct memory_notify *arg = data; switch (action) { - case MEM_OFFLINE: - ehea_info("memory has been removed"); + case MEM_CANCEL_OFFLINE: + ehea_info("memory offlining canceled"); + /* Readd canceled memory block */ + case MEM_ONLINE: + ehea_info("memory is going online"); + if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages)) + return NOTIFY_BAD; + ehea_rereg_mrs(NULL); + break; + case MEM_GOING_OFFLINE: + ehea_info("memory is going offline"); + if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages)) + return NOTIFY_BAD; ehea_rereg_mrs(NULL); break; default: diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index db8a9257e68..9b61dc9865d 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -567,7 +567,7 @@ static inline int ehea_calc_index(unsigned long i, unsigned long s) static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap, int dir) { - if(!ehea_top_bmap->dir[dir]) { + if (!ehea_top_bmap->dir[dir]) { ehea_top_bmap->dir[dir] = kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL); if (!ehea_top_bmap->dir[dir]) @@ -578,7 +578,7 @@ static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap, static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir) { - if(!ehea_bmap->top[top]) { + if (!ehea_bmap->top[top]) { ehea_bmap->top[top] = kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL); if (!ehea_bmap->top[top]) @@ -587,53 +587,124 @@ static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir) return ehea_init_top_bmap(ehea_bmap->top[top], dir); } -static int ehea_create_busmap_callback(unsigned long pfn, - unsigned long nr_pages, void *arg) -{ - unsigned long i, mr_len, start_section, end_section; - start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE; - end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE); - mr_len = *(unsigned long *)arg; +static DEFINE_MUTEX(ehea_busmap_mutex); +static unsigned long ehea_mr_len; - if (!ehea_bmap) - ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); - if (!ehea_bmap) - return -ENOMEM; +#define EHEA_BUSMAP_ADD_SECT 1 +#define EHEA_BUSMAP_REM_SECT 0 - for (i = start_section; i < end_section; i++) { - int ret; - int top, dir, idx; - u64 vaddr; +static void ehea_rebuild_busmap(void) +{ + u64 vaddr = EHEA_BUSMAP_START; + int top, dir, idx; + + for (top = 0; top < EHEA_MAP_ENTRIES; top++) { + struct ehea_top_bmap *ehea_top; + int valid_dir_entries = 0; - top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); - dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); + if (!ehea_bmap->top[top]) + continue; + ehea_top = ehea_bmap->top[top]; + for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) { + struct ehea_dir_bmap *ehea_dir; + int valid_entries = 0; - ret = ehea_init_bmap(ehea_bmap, top, dir); - if(ret) - return ret; + if (!ehea_top->dir[dir]) + continue; + valid_dir_entries++; + ehea_dir = ehea_top->dir[dir]; + for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) { + if (!ehea_dir->ent[idx]) + continue; + valid_entries++; + ehea_dir->ent[idx] = vaddr; + vaddr += EHEA_SECTSIZE; + } + if (!valid_entries) { + ehea_top->dir[dir] = NULL; + kfree(ehea_dir); + } + } + if (!valid_dir_entries) { + ehea_bmap->top[top] = NULL; + kfree(ehea_top); + } + } +} - idx = i & EHEA_INDEX_MASK; - vaddr = EHEA_BUSMAP_START + mr_len + i * EHEA_SECTSIZE; +static int ehea_update_busmap(unsigned long pfn, unsigned long pgnum, int add) +{ + unsigned long i, start_section, end_section; - ehea_bmap->top[top]->dir[dir]->ent[idx] = vaddr; + if (!ehea_bmap) { + ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); + if (!ehea_bmap) + return -ENOMEM; } - mr_len += nr_pages * PAGE_SIZE; - *(unsigned long *)arg = mr_len; + start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE; + end_section = start_section + ((pgnum * PAGE_SIZE) / EHEA_SECTSIZE); + /* Mark entries as valid or invalid only; address is assigned later */ + for (i = start_section; i < end_section; i++) { + u64 flag; + int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); + int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); + int idx = i & EHEA_INDEX_MASK; + + if (add) { + int ret = ehea_init_bmap(ehea_bmap, top, dir); + if (ret) + return ret; + flag = 1; /* valid */ + ehea_mr_len += EHEA_SECTSIZE; + } else { + if (!ehea_bmap->top[top]) + continue; + if (!ehea_bmap->top[top]->dir[dir]) + continue; + flag = 0; /* invalid */ + ehea_mr_len -= EHEA_SECTSIZE; + } + ehea_bmap->top[top]->dir[dir]->ent[idx] = flag; + } + ehea_rebuild_busmap(); /* Assign contiguous addresses for mr */ return 0; } -static unsigned long ehea_mr_len; +int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages) +{ + int ret; -static DEFINE_MUTEX(ehea_busmap_mutex); + mutex_lock(&ehea_busmap_mutex); + ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); + mutex_unlock(&ehea_busmap_mutex); + return ret; +} + +int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages) +{ + int ret; + + mutex_lock(&ehea_busmap_mutex); + ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_REM_SECT); + mutex_unlock(&ehea_busmap_mutex); + return ret; +} + +static int ehea_create_busmap_callback(unsigned long pfn, + unsigned long nr_pages, void *arg) +{ + return ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); +} int ehea_create_busmap(void) { int ret; + mutex_lock(&ehea_busmap_mutex); ehea_mr_len = 0; - ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, &ehea_mr_len, + ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, NULL, ehea_create_busmap_callback); mutex_unlock(&ehea_busmap_mutex); return ret; diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index 0bb6f92fa2f..1e58dc06b7d 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h @@ -378,6 +378,8 @@ int ehea_rem_mr(struct ehea_mr *mr); void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); +int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages); +int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages); int ehea_create_busmap(void); void ehea_destroy_busmap(void); u64 ehea_map_vaddr(void *caddr); -- cgit v1.2.3 From c54106bb3856a7726a814d54aa0eb32f5419a743 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 16 Oct 2008 21:26:57 -0700 Subject: igb: fix tx data corruption with transition to L0s on 82575 The 82575 has an issue in which the DMA will go out of sync if the link partner goes into an L0s state. To prevent this we set the pci-e link partner capability bits to disable the L0s transition on the hw. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/igb/igb_main.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 93d02efa9a0..33bd7bb0aac 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -966,10 +967,11 @@ static int __devinit igb_probe(struct pci_dev *pdev, struct net_device *netdev; struct igb_adapter *adapter; struct e1000_hw *hw; + struct pci_dev *us_dev; const struct e1000_info *ei = igb_info_tbl[ent->driver_data]; unsigned long mmio_start, mmio_len; - int i, err, pci_using_dac; - u16 eeprom_data = 0; + int i, err, pci_using_dac, pos; + u16 eeprom_data = 0, state = 0; u16 eeprom_apme_mask = IGB_EEPROM_APME; u32 part_num; int bars, need_ioport; @@ -1004,6 +1006,28 @@ static int __devinit igb_probe(struct pci_dev *pdev, } } + /* 82575 requires that the pci-e link partner disable the L0s state */ + switch (pdev->device) { + case E1000_DEV_ID_82575EB_COPPER: + case E1000_DEV_ID_82575EB_FIBER_SERDES: + case E1000_DEV_ID_82575GB_QUAD_COPPER: + us_dev = pdev->bus->self; + pos = pci_find_capability(us_dev, PCI_CAP_ID_EXP); + if (pos) { + pci_read_config_word(us_dev, pos + PCI_EXP_LNKCTL, + &state); + state &= ~PCIE_LINK_STATE_L0S; + pci_write_config_word(us_dev, pos + PCI_EXP_LNKCTL, + state); + printk(KERN_INFO "Disabling ASPM L0s upstream switch " + "port %x:%x.%x\n", us_dev->bus->number, + PCI_SLOT(us_dev->devfn), + PCI_FUNC(us_dev->devfn)); + } + default: + break; + } + err = pci_request_selected_regions(pdev, bars, igb_driver_name); if (err) goto err_pci_reg; -- cgit v1.2.3 From 421e02f0e9c3335028750ee411e5534dab82efbd Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 17 Oct 2008 11:08:31 -0700 Subject: igb: add IGB_DCA instead of selecting INTEL_IOATDMA Add a bool IGB_DCA defined to y if IGB and DCA are enabled, but IGB isn't y while DCA=m. And thus remove the need to select INTEL_IOATDMA when IGB is enabled, so that non-x86 architectures can build the igb driver. Based on work/patch from Brice Goglin Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 5 +++++ drivers/net/igb/igb_main.c | 32 ++++++++++++++++---------------- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 021e8f16740..c7f020c4f14 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2003,6 +2003,11 @@ config IGB_LRO If in doubt, say N. +config IGB_DCA + bool "Enable DCA" + default y + depends on IGB && DCA && !(IGB=y && DCA=m) + source "drivers/net/ixp2000/Kconfig" config MYRI_SBUS diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 33bd7bb0aac..1f397cd9941 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -42,7 +42,7 @@ #include #include #include -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA #include #endif #include "igb.h" @@ -107,11 +107,11 @@ static irqreturn_t igb_msix_other(int irq, void *); static irqreturn_t igb_msix_rx(int irq, void *); static irqreturn_t igb_msix_tx(int irq, void *); static int igb_clean_rx_ring_msix(struct napi_struct *, int); -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA static void igb_update_rx_dca(struct igb_ring *); static void igb_update_tx_dca(struct igb_ring *); static void igb_setup_dca(struct igb_adapter *); -#endif /* CONFIG_DCA */ +#endif /* CONFIG_IGB_DCA */ static bool igb_clean_tx_irq(struct igb_ring *); static int igb_poll(struct napi_struct *, int); static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int); @@ -132,7 +132,7 @@ static int igb_suspend(struct pci_dev *, pm_message_t); static int igb_resume(struct pci_dev *); #endif static void igb_shutdown(struct pci_dev *); -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA static int igb_notify_dca(struct notifier_block *, unsigned long, void *); static struct notifier_block dca_notifier = { .notifier_call = igb_notify_dca, @@ -208,7 +208,7 @@ static int __init igb_init_module(void) global_quad_port_a = 0; ret = pci_register_driver(&igb_driver); -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA dca_register_notify(&dca_notifier); #endif return ret; @@ -224,7 +224,7 @@ module_init(igb_init_module); **/ static void __exit igb_exit_module(void) { -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA dca_unregister_notify(&dca_notifier); #endif pci_unregister_driver(&igb_driver); @@ -1261,7 +1261,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (err) goto err_register; -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA if ((adapter->flags & IGB_FLAG_HAS_DCA) && (dca_add_requester(&pdev->dev) == 0)) { adapter->flags |= IGB_FLAG_DCA_ENABLED; @@ -1335,7 +1335,7 @@ static void __devexit igb_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA struct e1000_hw *hw = &adapter->hw; #endif @@ -1347,7 +1347,7 @@ static void __devexit igb_remove(struct pci_dev *pdev) flush_scheduled_work(); -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) { dev_info(&pdev->dev, "DCA disabled\n"); dca_remove_requester(&pdev->dev); @@ -3295,7 +3295,7 @@ static irqreturn_t igb_msix_tx(int irq, void *data) struct igb_adapter *adapter = tx_ring->adapter; struct e1000_hw *hw = &adapter->hw; -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_tx_dca(tx_ring); #endif @@ -3347,14 +3347,14 @@ static irqreturn_t igb_msix_rx(int irq, void *data) if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) __netif_rx_schedule(adapter->netdev, &rx_ring->napi); -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(rx_ring); #endif return IRQ_HANDLED; } -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA static void igb_update_rx_dca(struct igb_ring *rx_ring) { u32 dca_rxctrl; @@ -3474,7 +3474,7 @@ static int igb_notify_dca(struct notifier_block *nb, unsigned long event, return ret_val ? NOTIFY_BAD : NOTIFY_DONE; } -#endif /* CONFIG_DCA */ +#endif /* CONFIG_IGB_DCA */ /** * igb_intr_msi - Interrupt Handler @@ -3553,13 +3553,13 @@ static int igb_poll(struct napi_struct *napi, int budget) int tx_clean_complete, work_done = 0; /* this poll routine only supports one tx and one rx queue */ -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_tx_dca(&adapter->tx_ring[0]); #endif tx_clean_complete = igb_clean_tx_irq(&adapter->tx_ring[0]); -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(&adapter->rx_ring[0]); #endif @@ -3587,7 +3587,7 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) struct net_device *netdev = adapter->netdev; int work_done = 0; -#ifdef CONFIG_DCA +#ifdef CONFIG_IGB_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(rx_ring); #endif -- cgit v1.2.3 From de4549cae088a74262834178b71fb25dbec2c376 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Oct 2008 18:04:27 -0700 Subject: 8139x: reduce message severity on driver overlap The 8139 drivers are a source of error messages that confuse users. Since this device can not be disambiguated by normal PCI device id's two drivers match the same info. But the module utilities seem to correctly handle this overlap, they try one driver, then if that doesn't load try the other. Therefore there is no need for a message to be logged with error level severity, just using info level instead. Can't be completely silent because user might have configure one driver and forgot the other one. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 5 ++--- drivers/net/8139too.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 85fa40a0a66..9ba1f0b4642 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1836,10 +1836,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (pdev->vendor == PCI_VENDOR_ID_REALTEK && pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->revision < 0x20) { - dev_err(&pdev->dev, - "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n", + dev_info(&pdev->dev, + "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip, use 8139too\n", pdev->vendor, pdev->device, pdev->revision); - dev_err(&pdev->dev, "Try the \"8139too\" driver instead.\n"); return -ENODEV; } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 0daf8c15e38..63f906b0489 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -946,10 +946,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, if (pdev->vendor == PCI_VENDOR_ID_REALTEK && pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->revision >= 0x20) { dev_info(&pdev->dev, - "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n", + "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip, use 8139cp\n", pdev->vendor, pdev->device, pdev->revision); - dev_info(&pdev->dev, - "Use the \"8139cp\" driver for improved performance and stability.\n"); + return -ENODEV; } if (pdev->vendor == PCI_VENDOR_ID_REALTEK && -- cgit v1.2.3 From 708f6e27c3f75166433b69174a8348308e55d073 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Mon, 20 Oct 2008 23:37:55 +0200 Subject: sis190: add identifier for Atheros AR8021 PHY Fixes http://bugzilla.kernel.org/show_bug.cgi?id=10994 Contributed by pablomme@googlemail.com, coenraad@wish.org.za and a few others. Signed-off-by: Francois Romieu Signed-off-by: Jeff Garzik --- drivers/net/sis190.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 3fe01763760..e6e3bf58a56 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -317,6 +317,7 @@ static struct mii_chip_info { unsigned int type; u32 feature; } mii_chip_table[] = { + { "Atheros PHY AR8012", { 0x004d, 0xd020 }, LAN, 0 }, { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 }, { "Broadcom PHY AC131", { 0x0143, 0xbc70 }, LAN, 0 }, { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN, 0 }, -- cgit v1.2.3 From bd2c4972fff2d621383bc2c3389a7b1ac7eca8f1 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 20 Oct 2008 18:15:17 +0100 Subject: smc911x: Allow Kconfig dependency on ARM Since more ARM platforms use this device, it is easier to add a dependency on ARM rather than individual platforms. Signed-off-by: Catalin Marinas Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c7f020c4f14..a76ca75fd4d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -960,7 +960,7 @@ config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 select MII - depends on ARCH_PXA || SUPERH + depends on ARM || SUPERH help This is a driver for SMSC's LAN911x series of Ethernet chipsets including the new LAN9115, LAN9116, LAN9117, and LAN9118. -- cgit v1.2.3 From 319edafef64406c971035c56bd68480e5a82b581 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 20 Oct 2008 18:15:30 +0100 Subject: smc911x: Add IRQ polarity configuration Platforms like ARM Ltd's RealView require the IRQ polarity bit to be set for the SMC9118 chip. This patch allows the dynamic configuration via the smc911x_platdata structure. This patch also changes the smc91x_platdata structure name to the correct smc911x_platdata in the smc911x_drv_probe() function. Signed-off-by: Catalin Marinas Signed-off-by: Jeff Garzik --- drivers/net/smc911x.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index ec32b5d89c9..2c78229ad04 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -180,7 +180,7 @@ static void PRINT_PKT(u_char *buf, int length) static void smc911x_reset(struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); - unsigned int reg, timeout=0, resets=1; + unsigned int reg, timeout=0, resets=1, irq_cfg; unsigned long flags; DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); @@ -252,7 +252,12 @@ static void smc911x_reset(struct net_device *dev) * Deassert IRQ for 1*10us for edge type interrupts * and drive IRQ pin push-pull */ - SMC_SET_IRQ_CFG(lp, (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_); + irq_cfg = (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_; +#ifdef SMC_DYNAMIC_BUS_CONFIG + if (lp->cfg.irq_polarity) + irq_cfg |= INT_CFG_IRQ_POL_; +#endif + SMC_SET_IRQ_CFG(lp, irq_cfg); /* clear anything saved */ if (lp->pending_tx_skb != NULL) { @@ -2054,7 +2059,7 @@ err_out: */ static int smc911x_drv_probe(struct platform_device *pdev) { - struct smc91x_platdata *pd = pdev->dev.platform_data; + struct smc911x_platdata *pd = pdev->dev.platform_data; struct net_device *ndev; struct resource *res; struct smc911x_local *lp; -- cgit v1.2.3 From b891a9023bc4fc639b31c234a705e7e51104cf22 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 20 Oct 2008 18:15:37 +0100 Subject: smc911x: Make the driver safer on SMP This patch extends the critical regions covered by lp->lock to make it safer on SMP. The main failure point was the smc911x_hard_start_xmit function being called from different CPUs. It was tested on the ARM SMP platforms. Signed-off-by: Catalin Marinas Signed-off-by: Jeff Garzik --- drivers/net/smc911x.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2c78229ad04..f59c7772f34 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -155,23 +155,17 @@ static void PRINT_PKT(u_char *buf, int length) /* this enables an interrupt in the interrupt mask register */ #define SMC_ENABLE_INT(lp, x) do { \ unsigned int __mask; \ - unsigned long __flags; \ - spin_lock_irqsave(&lp->lock, __flags); \ __mask = SMC_GET_INT_EN((lp)); \ __mask |= (x); \ SMC_SET_INT_EN((lp), __mask); \ - spin_unlock_irqrestore(&lp->lock, __flags); \ } while (0) /* this disables an interrupt from the interrupt mask register */ #define SMC_DISABLE_INT(lp, x) do { \ unsigned int __mask; \ - unsigned long __flags; \ - spin_lock_irqsave(&lp->lock, __flags); \ __mask = SMC_GET_INT_EN((lp)); \ __mask &= ~(x); \ SMC_SET_INT_EN((lp), __mask); \ - spin_unlock_irqrestore(&lp->lock, __flags); \ } while (0) /* @@ -279,6 +273,8 @@ static void smc911x_enable(struct net_device *dev) DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); + spin_lock_irqsave(&lp->lock, flags); + SMC_SET_MAC_ADDR(lp, dev->dev_addr); /* Enable TX */ @@ -291,12 +287,10 @@ static void smc911x_enable(struct net_device *dev) SMC_SET_FIFO_TSL(lp, 64); SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); - spin_lock_irqsave(&lp->lock, flags); SMC_GET_MAC_CR(lp, cr); cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_; SMC_SET_MAC_CR(lp, cr); SMC_SET_TX_CFG(lp, TX_CFG_TX_ON_); - spin_unlock_irqrestore(&lp->lock, flags); /* Add 2 byte padding to start of packets */ SMC_SET_RX_CFG(lp, (2<<8) & RX_CFG_RXDOFF_); @@ -305,9 +299,7 @@ static void smc911x_enable(struct net_device *dev) if (cr & MAC_CR_RXEN_) DBG(SMC_DEBUG_RX, "%s: Receiver already enabled\n", dev->name); - spin_lock_irqsave(&lp->lock, flags); SMC_SET_MAC_CR(lp, cr | MAC_CR_RXEN_); - spin_unlock_irqrestore(&lp->lock, flags); /* Interrupt on every received packet */ SMC_SET_FIFO_RSA(lp, 0x01); @@ -323,6 +315,8 @@ static void smc911x_enable(struct net_device *dev) mask|=INT_EN_RDFO_EN_; } SMC_ENABLE_INT(lp, mask); + + spin_unlock_irqrestore(&lp->lock, flags); } /* @@ -463,7 +457,6 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) struct sk_buff *skb; unsigned int cmdA, cmdB, len; unsigned char *buf; - unsigned long flags; DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __func__); BUG_ON(lp->pending_tx_skb == NULL); @@ -508,11 +501,9 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb(skb); #endif - spin_lock_irqsave(&lp->lock, flags); if (!lp->tx_throttle) { netif_wake_queue(dev); } - spin_unlock_irqrestore(&lp->lock, flags); SMC_ENABLE_INT(lp, INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_); } @@ -531,6 +522,8 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __func__); + spin_lock_irqsave(&lp->lock, flags); + BUG_ON(lp->pending_tx_skb != NULL); free = SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TDFREE_; @@ -540,12 +533,10 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (free <= SMC911X_TX_FIFO_LOW_THRESHOLD) { DBG(SMC_DEBUG_TX, "%s: Disabling data flow due to low FIFO space (%d)\n", dev->name, free); - spin_lock_irqsave(&lp->lock, flags); /* Reenable when at least 1 packet of size MTU present */ SMC_SET_FIFO_TDA(lp, (SMC911X_TX_FIFO_LOW_THRESHOLD)/64); lp->tx_throttle = 1; netif_stop_queue(dev); - spin_unlock_irqrestore(&lp->lock, flags); } /* Drop packets when we run out of space in TX FIFO @@ -561,6 +552,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->pending_tx_skb = NULL; dev->stats.tx_errors++; dev->stats.tx_dropped++; + spin_unlock_irqrestore(&lp->lock, flags); dev_kfree_skb(skb); return 0; } @@ -570,7 +562,6 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* If the DMA is already running then defer this packet Tx until * the DMA IRQ starts it */ - spin_lock_irqsave(&lp->lock, flags); if (lp->txdma_active) { DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Tx DMA running, deferring packet\n", dev->name); lp->pending_tx_skb = skb; @@ -581,11 +572,11 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name); lp->txdma_active = 1; } - spin_unlock_irqrestore(&lp->lock, flags); } #endif lp->pending_tx_skb = skb; smc911x_hardware_send_pkt(dev); + spin_unlock_irqrestore(&lp->lock, flags); return 0; } -- cgit v1.2.3 From bb0d215c8f970345746129d4c110159b099e032f Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 20 Oct 2008 10:30:26 -0700 Subject: qlge: Fix MSI/legacy single interrupt bug. The chip can issue spurious interrupts for single interrupt modes. We use disable to clear the condition and allow processing to continue. Also got rid of legacy specific code since it now needs to be done on MSI single irq also. Signed-off-by: Ron Mercer Signed-off-by: Jeff Garzik --- drivers/net/qlge/qlge.h | 5 +-- drivers/net/qlge/qlge_main.c | 89 +++++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 38116f9d416..ba2e1c5b6bc 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1375,7 +1375,6 @@ struct ql_adapter { spinlock_t adapter_lock; spinlock_t hw_lock; spinlock_t stats_lock; - spinlock_t legacy_lock; /* used for maintaining legacy intr sync */ /* PCI Bus Relative Register Addresses */ void __iomem *reg_base; @@ -1399,8 +1398,6 @@ struct ql_adapter { struct msix_entry *msi_x_entry; struct intr_context intr_context[MAX_RX_RINGS]; - int (*legacy_check) (struct ql_adapter *); - int tx_ring_count; /* One per online CPU. */ u32 rss_ring_first_cq_id;/* index of first inbound (rss) rx_ring */ u32 rss_ring_count; /* One per online CPU. */ @@ -1502,7 +1499,7 @@ void ql_mpi_work(struct work_struct *work); void ql_mpi_reset_work(struct work_struct *work); int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit); void ql_queue_asic_error(struct ql_adapter *qdev); -void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); +u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); void ql_set_ethtool_ops(struct net_device *ndev); int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data); diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 4b2caa6b7ac..b83a9c9b6a9 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -577,41 +577,53 @@ static void ql_disable_interrupts(struct ql_adapter *qdev) * incremented everytime we queue a worker and decremented everytime * a worker finishes. Once it hits zero we enable the interrupt. */ -void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr) +u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr) { - if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) + u32 var = 0; + unsigned long hw_flags = 0; + struct intr_context *ctx = qdev->intr_context + intr; + + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr)) { + /* Always enable if we're MSIX multi interrupts and + * it's not the default (zeroeth) interrupt. + */ ql_write32(qdev, INTR_EN, - qdev->intr_context[intr].intr_en_mask); - else { - if (qdev->legacy_check) - spin_lock(&qdev->legacy_lock); - if (atomic_dec_and_test(&qdev->intr_context[intr].irq_cnt)) { - QPRINTK(qdev, INTR, ERR, "Enabling interrupt %d.\n", - intr); - ql_write32(qdev, INTR_EN, - qdev->intr_context[intr].intr_en_mask); - } else { - QPRINTK(qdev, INTR, ERR, - "Skip enable, other queue(s) are active.\n"); - } - if (qdev->legacy_check) - spin_unlock(&qdev->legacy_lock); + ctx->intr_en_mask); + var = ql_read32(qdev, STS); + return var; } + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + if (atomic_dec_and_test(&ctx->irq_cnt)) { + ql_write32(qdev, INTR_EN, + ctx->intr_en_mask); + var = ql_read32(qdev, STS); + } + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return var; } static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr) { u32 var = 0; + unsigned long hw_flags; + struct intr_context *ctx; - if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) - goto exit; - else if (!atomic_read(&qdev->intr_context[intr].irq_cnt)) { + /* HW disables for us if we're MSIX multi interrupts and + * it's not the default (zeroeth) interrupt. + */ + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr)) + return 0; + + ctx = qdev->intr_context + intr; + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + if (!atomic_read(&ctx->irq_cnt)) { ql_write32(qdev, INTR_EN, - qdev->intr_context[intr].intr_dis_mask); + ctx->intr_dis_mask); var = ql_read32(qdev, STS); } - atomic_inc(&qdev->intr_context[intr].irq_cnt); -exit: + atomic_inc(&ctx->irq_cnt); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return var; } @@ -623,7 +635,9 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev) * and enables only if the result is zero. * So we precharge it here. */ - atomic_set(&qdev->intr_context[i].irq_cnt, 1); + if (unlikely(!test_bit(QL_MSIX_ENABLED, &qdev->flags) || + i == 0)) + atomic_set(&qdev->intr_context[i].irq_cnt, 1); ql_enable_completion_interrupt(qdev, i); } @@ -1725,19 +1739,6 @@ static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id) return IRQ_HANDLED; } -/* We check here to see if we're already handling a legacy - * interrupt. If we are, then it must belong to another - * chip with which we're sharing the interrupt line. - */ -int ql_legacy_check(struct ql_adapter *qdev) -{ - int err; - spin_lock(&qdev->legacy_lock); - err = atomic_read(&qdev->intr_context[0].irq_cnt); - spin_unlock(&qdev->legacy_lock); - return err; -} - /* This handles a fatal error, MPI activity, and the default * rx_ring in an MSI-X multiple vector environment. * In MSI/Legacy environment it also process the rest of @@ -1752,12 +1753,15 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) int i; int work_done = 0; - if (qdev->legacy_check && qdev->legacy_check(qdev)) { - QPRINTK(qdev, INTR, INFO, "Already busy, not our interrupt.\n"); - return IRQ_NONE; /* Not our interrupt */ + spin_lock(&qdev->hw_lock); + if (atomic_read(&qdev->intr_context[0].irq_cnt)) { + QPRINTK(qdev, INTR, DEBUG, "Shared Interrupt, Not ours!\n"); + spin_unlock(&qdev->hw_lock); + return IRQ_NONE; } + spin_unlock(&qdev->hw_lock); - var = ql_read32(qdev, STS); + var = ql_disable_completion_interrupt(qdev, intr_context->intr); /* * Check for fatal error. @@ -1823,6 +1827,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) } } } + ql_enable_completion_interrupt(qdev, intr_context->intr); return work_done ? IRQ_HANDLED : IRQ_NONE; } @@ -2701,8 +2706,6 @@ msi: } } irq_type = LEG_IRQ; - spin_lock_init(&qdev->legacy_lock); - qdev->legacy_check = ql_legacy_check; QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n"); } -- cgit v1.2.3 From bd28bdb18f1028f8f0a3f83291336529b2cb5b7a Mon Sep 17 00:00:00 2001 From: Jon Smirl Date: Sat, 18 Oct 2008 11:40:59 +0000 Subject: [netdrvr] fec_mpc52xx: Implement polling, to make netconsole work. Implement polling for 5200FEC to make netconsole work. Tested on Phytec pcm030 and Efika. Signed-off-by: Jon Smirl Signed-off-by: Jeff Garzik --- drivers/net/fec_mpc52xx.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 4e4f68304e8..aec3b97e794 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -401,6 +401,21 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d return 0; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void mpc52xx_fec_poll_controller(struct net_device *dev) +{ + struct mpc52xx_fec_priv *priv = netdev_priv(dev); + + disable_irq(priv->t_irq); + mpc52xx_fec_tx_interrupt(priv->t_irq, dev); + enable_irq(priv->t_irq); + disable_irq(priv->r_irq); + mpc52xx_fec_rx_interrupt(priv->r_irq, dev); + enable_irq(priv->r_irq); +} +#endif + + /* This handles BestComm transmit task interrupts */ static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id) @@ -926,6 +941,9 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) ndev->tx_timeout = mpc52xx_fec_tx_timeout; ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; ndev->base_addr = mem.start; +#ifdef CONFIG_NET_POLL_CONTROLLER + ndev->poll_controller = mpc52xx_fec_poll_controller; +#endif priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */ -- cgit v1.2.3 From 8bdd5b9c6bd53add260756b6673a0545fbdbba21 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 16 Oct 2008 11:02:06 -0400 Subject: ath5k: fix suspend-related oops on rmmod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a patch by Elias Oltmanns, we call ath5k_init in resume even if we didn't previously open the device. Besides starting up the device unnecessarily, this also causes an oops on rmmod because mac80211 will not invoke ath5k_stop and softirqs are left running after the module has been unloaded. Add a new state bit, ATH_STAT_STARTED, to indicate that we have been started up. Reported-by: Toralf Förster Signed-off-by: Elias Oltmanns Signed-off-by: Bob Copeland Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 27 +++++++++++++++++++-------- drivers/net/wireless/ath5k/base.h | 3 ++- 2 files changed, 21 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 9b95c4049b3..0f1d6bdd51a 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -340,9 +340,9 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) } /* Interrupt handling */ -static int ath5k_init(struct ath5k_softc *sc); +static int ath5k_init(struct ath5k_softc *sc, bool is_resume); static int ath5k_stop_locked(struct ath5k_softc *sc); -static int ath5k_stop_hw(struct ath5k_softc *sc); +static int ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend); static irqreturn_t ath5k_intr(int irq, void *dev_id); static void ath5k_tasklet_reset(unsigned long data); @@ -646,7 +646,7 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath5k_led_off(sc); - ath5k_stop_hw(sc); + ath5k_stop_hw(sc, true); free_irq(pdev->irq, sc); pci_save_state(pdev); @@ -683,7 +683,7 @@ ath5k_pci_resume(struct pci_dev *pdev) goto err_no_irq; } - err = ath5k_init(sc); + err = ath5k_init(sc, true); if (err) goto err_irq; ath5k_led_enable(sc); @@ -2200,12 +2200,17 @@ ath5k_beacon_config(struct ath5k_softc *sc) \********************/ static int -ath5k_init(struct ath5k_softc *sc) +ath5k_init(struct ath5k_softc *sc, bool is_resume) { int ret; mutex_lock(&sc->lock); + if (is_resume && !test_bit(ATH_STAT_STARTED, sc->status)) + goto out_ok; + + __clear_bit(ATH_STAT_STARTED, sc->status); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); /* @@ -2230,12 +2235,15 @@ ath5k_init(struct ath5k_softc *sc) if (ret) goto done; + __set_bit(ATH_STAT_STARTED, sc->status); + /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(sc->ah, false); mod_timer(&sc->calib_tim, round_jiffies(jiffies + msecs_to_jiffies(ath5k_calinterval * 1000))); +out_ok: ret = 0; done: mmiowb(); @@ -2290,7 +2298,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) * stop is preempted). */ static int -ath5k_stop_hw(struct ath5k_softc *sc) +ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend) { int ret; @@ -2321,6 +2329,9 @@ ath5k_stop_hw(struct ath5k_softc *sc) } } ath5k_txbuf_free(sc, sc->bbuf); + if (!is_suspend) + __clear_bit(ATH_STAT_STARTED, sc->status); + mmiowb(); mutex_unlock(&sc->lock); @@ -2718,12 +2729,12 @@ ath5k_reset_wake(struct ath5k_softc *sc) static int ath5k_start(struct ieee80211_hw *hw) { - return ath5k_init(hw->priv); + return ath5k_init(hw->priv, false); } static void ath5k_stop(struct ieee80211_hw *hw) { - ath5k_stop_hw(hw->priv); + ath5k_stop_hw(hw->priv, false); } static int ath5k_add_interface(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 9d0b728928e..06d1054ca94 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -128,11 +128,12 @@ struct ath5k_softc { size_t desc_len; /* size of TX/RX descriptors */ u16 cachelsz; /* cache line size */ - DECLARE_BITMAP(status, 4); + DECLARE_BITMAP(status, 5); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ #define ATH_STAT_PROMISC 2 #define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ +#define ATH_STAT_STARTED 4 /* opened & irqs enabled */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ unsigned int curmode; /* current phy mode */ -- cgit v1.2.3 From 70458259936e723a4ac02c85bdbaf08dc69edfbe Mon Sep 17 00:00:00 2001 From: Andrey Borzenkov Date: Fri, 10 Oct 2008 21:26:30 +0400 Subject: orinoco: reduce stack usage in firmware download path orinoco_dl_firmware and symbol_dl_mage allocate large local variables (1K); at least orinoco fails with panic or hung kernel if 4K stacks is enabled. Allocate large buffers dynamically at run time. Tested-By: Andrey Borzenkov for Agere case Signed-off-by: Andrey Borzenkov < arvidjaar@mail.ru> Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 50904771f29..e0512e49d6d 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -433,7 +433,7 @@ struct fw_info { const static struct fw_info orinoco_fw[] = { { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 } + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } }; /* Structure used to access fields in FW @@ -458,7 +458,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, int ap) { /* Plug Data Area (PDA) */ - __le16 pda[512] = { 0 }; + __le16 *pda; hermes_t *hw = &priv->hw; const struct firmware *fw_entry; @@ -467,7 +467,11 @@ orinoco_dl_firmware(struct orinoco_private *priv, const unsigned char *end; const char *firmware; struct net_device *dev = priv->ndev; - int err; + int err = 0; + + pda = kzalloc(fw->pda_size, GFP_KERNEL); + if (!pda) + return -ENOMEM; if (ap) firmware = fw->ap_fw; @@ -478,17 +482,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, dev->name, firmware); /* Read current plug data */ - err = hermes_read_pda(hw, pda, fw->pda_addr, - min_t(u16, fw->pda_size, sizeof(pda)), 0); + err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); if (err) - return err; + goto free; err = request_firmware(&fw_entry, firmware, priv->dev); if (err) { printk(KERN_ERR "%s: Cannot find firmware %s\n", dev->name, firmware); - return -ENOENT; + err = -ENOENT; + goto free; } hdr = (const struct orinoco_fw_header *) fw_entry->data; @@ -532,6 +536,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, abort: release_firmware(fw_entry); + +free: + kfree(pda); return err; } @@ -549,12 +556,12 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, int secondary) { hermes_t *hw = &priv->hw; - int ret; + int ret = 0; const unsigned char *ptr; const unsigned char *first_block; /* Plug Data Area (PDA) */ - __le16 pda[256]; + __le16 *pda = NULL; /* Binary block begins after the 0x1A marker */ ptr = image; @@ -563,28 +570,33 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, /* Read the PDA from EEPROM */ if (secondary) { - ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1); + pda = kzalloc(fw->pda_size, GFP_KERNEL); + if (!pda) + return -ENOMEM; + + ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); if (ret) - return ret; + goto free; } /* Stop the firmware, so that it can be safely rewritten */ if (priv->stop_fw) { ret = priv->stop_fw(priv, 1); if (ret) - return ret; + goto free; } /* Program the adapter with new firmware */ ret = hermes_program(hw, first_block, end); if (ret) - return ret; + goto free; /* Write the PDA to the adapter */ if (secondary) { size_t len = hermes_blocks_length(first_block); ptr = first_block + len; ret = hermes_apply_pda(hw, ptr, pda); + kfree(pda); if (ret) return ret; } @@ -608,6 +620,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, return -ENODEV; return 0; + +free: + kfree(pda); + return ret; } -- cgit v1.2.3 From 4cc683c9adbe644323e978bc63b2ab12606bb3c8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 03:30:06 +0200 Subject: p54: enable 2.4/5GHz spectrum by eeprom bits. Badness at /home/proski/src/linux-2.6/net/mac80211/rx.c:2200 NIP: c02bc850 LR: c02ab268 CTR: 00000000 REGS: ef01fcc0 TRAP: 0700 Tainted: G W (2.6.27-wl) MSR: 00029032 CR: 22004084 XER: 20000000 TASK = c1a58800[1778] 'p54pci' THREAD: ef01e000 [...] NIP [c02bc850] __ieee80211_rx+0x17c/0x638 LR [c02ab268] ieee80211_tasklet_handler+0x104/0x120 Call Trace: [ef01fd70] [c1a0c020] 0xc1a0c020 (unreliable) [ef01fdb0] [c02ab268] ieee80211_tasklet_handler+0x104/0x120 [...] the problem was that some older cards are mis-identified and didn't support 5GHz rates, while they have the right MAC & Synth chip. This patch changes the way how p54 decides if it should enable 11a channels or not. Reported-by: Pavel Roskin Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 117c7d3a52b..2d022f83774 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -306,8 +306,8 @@ static int p54_convert_rev1(struct ieee80211_hw *dev, return 0; } -static const char *p54_rf_chips[] = { "NULL", "Indigo?", "Duette", - "Frisbee", "Xbow", "Longbow" }; +static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2", + "Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; static int p54_init_xbow_synth(struct ieee80211_hw *dev); static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) @@ -319,6 +319,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) void *tmp; int err; u8 *end = (u8 *)eeprom + len; + u16 synth; DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; @@ -400,8 +401,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) tmp = entry->data; while ((u8 *)tmp < entry->data + data_len) { struct bootrec_exp_if *exp_if = tmp; - if (le16_to_cpu(exp_if->if_id) == 0xF) - priv->rxhw = le16_to_cpu(exp_if->variant) & 0x07; + if (le16_to_cpu(exp_if->if_id) == 0xf) + synth = le16_to_cpu(exp_if->variant); tmp += sizeof(struct bootrec_exp_if); } break; @@ -427,22 +428,13 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) goto err; } - switch (priv->rxhw) { - case 4: /* XBow */ + priv->rxhw = synth & 0x07; + if (priv->rxhw == 4) p54_init_xbow_synth(dev); - case 1: /* Indigo? */ - case 2: /* Duette */ - dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; - case 3: /* Frisbee */ - case 5: /* Longbow */ + if (!(synth & 0x40)) dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - break; - default: - printk(KERN_ERR "%s: unsupported RF-Chip\n", - wiphy_name(dev->wiphy)); - err = -EINVAL; - goto err; - } + if (!(synth & 0x80)) + dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { u8 perm_addr[ETH_ALEN]; -- cgit v1.2.3 From b63365a2d60268a3988285d6c3c6003d7066f93a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 23 Oct 2008 01:11:29 -0700 Subject: net: Fix disjunct computation of netdev features My change commit e2a6b85247aacc52d6ba0d9b37a99b8d1a3e0d83 net: Enable TSO if supported by at least one device didn't do what was intended because the netdev_compute_features function was designed for conjunctions. So what happened was that it would simply take the TSO status of the last constituent device. This patch extends it to support both conjunctions and disjunctions under the new name of netdev_increment_features. It also adds a new function netdev_fix_features which does the sanity checking that usually occurs upon registration. This ensures that the computation doesn't result in an illegal combination since this checking is absent when the change is initiated via ethtool. The two users of netdev_compute_features have been converted. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8e2be24f3fe..832739f38db 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1341,18 +1341,24 @@ static int bond_compute_features(struct bonding *bond) int i; features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); - features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | - NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; + features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; + + if (!bond->first_slave) + goto done; + + features &= ~NETIF_F_ONE_FOR_ALL; bond_for_each_slave(bond, slave, i) { - features = netdev_compute_features(features, - slave->dev->features); + features = netdev_increment_features(features, + slave->dev->features, + NETIF_F_ONE_FOR_ALL); if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; } +done: features |= (bond_dev->features & BOND_VLAN_FEATURES); - bond_dev->features = features; + bond_dev->features = netdev_fix_features(features, NULL); bond_dev->hard_header_len = max_hard_header_len; return 0; -- cgit v1.2.3