aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS7
-rw-r--r--arch/arm/mach-at91rm9200/at91rm9200.c45
-rw-r--r--arch/arm/mach-at91rm9200/generic.h8
-rw-r--r--arch/arm/mach-at91rm9200/irq.c70
-rw-r--r--arch/arm/mach-pnx4008/core.c2
-rw-r--r--arch/arm/mach-pnx4008/dma.c1
-rw-r--r--arch/arm/mach-pnx4008/irq.c22
-rw-r--r--arch/arm/mach-pnx4008/time.c8
-rw-r--r--arch/sparc64/kernel/prom.c2
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c10
-rw-r--r--arch/sparc64/kernel/time.c5
-rw-r--r--drivers/net/8139cp.c35
-rw-r--r--drivers/net/8139too.c34
-rw-r--r--drivers/net/b44.c27
-rw-r--r--drivers/net/bnx2.c30
-rw-r--r--drivers/net/cassini.c25
-rw-r--r--drivers/net/declance.c7
-rw-r--r--drivers/net/dl2k.c43
-rw-r--r--drivers/net/eepro100.c6
-rw-r--r--drivers/net/epic100.c93
-rw-r--r--drivers/net/fealnx.c36
-rw-r--r--drivers/net/gt96100eth.c3
-rw-r--r--drivers/net/gt96100eth.h2
-rw-r--r--drivers/net/hamachi.c16
-rw-r--r--drivers/net/myri10ge/myri10ge.c17
-rw-r--r--drivers/net/natsemi.c117
-rw-r--r--drivers/net/ne2k-pci.c9
-rw-r--r--drivers/net/ni5010.c52
-rw-r--r--drivers/net/ns83820.c41
-rw-r--r--drivers/net/pci-skeleton.c19
-rw-r--r--drivers/net/pcnet32.c520
-rw-r--r--drivers/net/phy/cicada.c42
-rw-r--r--drivers/net/r8169.c40
-rw-r--r--drivers/net/starfire.c123
-rw-r--r--drivers/net/sundance.c106
-rw-r--r--drivers/net/tulip/winbond-840.c29
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c27
-rw-r--r--drivers/net/via-rhine.c121
-rw-r--r--drivers/net/via-velocity.c102
-rw-r--r--drivers/net/via-velocity.h4
-rw-r--r--drivers/net/wan/Kconfig12
-rw-r--r--drivers/net/wan/Makefile1
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c31
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h24
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c7
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c2
-rw-r--r--drivers/net/wireless/zd1211rw/Kconfig19
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile11
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c1615
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h825
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h48
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.c191
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h85
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c1057
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h190
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c267
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.h45
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c151
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h82
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c308
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c279
-rw-r--r--drivers/net/wireless/zd1211rw/zd_types.h71
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1316
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h240
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.c82
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.h29
-rw-r--r--drivers/net/yellowfin.c39
-rw-r--r--drivers/scsi/ahci.c17
-rw-r--r--drivers/scsi/libata-core.c289
-rw-r--r--drivers/scsi/libata-eh.c405
-rw-r--r--drivers/scsi/libata-scsi.c124
-rw-r--r--drivers/scsi/sata_sil.c105
-rw-r--r--drivers/scsi/sata_sil24.c134
-rw-r--r--drivers/scsi/sata_vsc.c2
-rw-r--r--drivers/serial/at91_serial.c5
-rw-r--r--fs/lockd/clntproc.c26
-rw-r--r--fs/locks.c23
-rw-r--r--fs/nfs/dir.c4
-rw-r--r--fs/nfs/direct.c435
-rw-r--r--fs/nfs/nfs4proc.c74
-rw-r--r--fs/nfs/write.c20
-rw-r--r--include/asm-arm/arch-at91rm9200/irqs.h8
-rw-r--r--include/asm-sparc64/dma-mapping.h14
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/libata.h85
-rw-r--r--include/linux/nfs_xdr.h2
-rw-r--r--include/linux/pci_ids.h7
-rw-r--r--include/net/ieee80211softmac.h1
-rw-r--r--net/ieee80211/ieee80211_rx.c4
-rw-r--r--net/ieee80211/ieee80211_tx.c15
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c31
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c4
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c3
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c36
-rw-r--r--net/sunrpc/xdr.c3
99 files changed, 9068 insertions, 1751 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 5f76a4f5cd4..196a31c9752 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2039,9 +2039,10 @@ L: linux-kernel@vger.kernel.org
S: Maintained
NI5010 NETWORK DRIVER
-P: Jan-Pascal van Best and Andreas Mohr
-M: Jan-Pascal van Best <jvbest@qv3pluto.leidenuniv.nl>
-M: Andreas Mohr <100.30936@germany.net>
+P: Jan-Pascal van Best
+M: janpascal@vanbest.org
+P: Andreas Mohr
+M: andi@lisas.de
L: netdev@vger.kernel.org
S: Maintained
diff --git a/arch/arm/mach-at91rm9200/at91rm9200.c b/arch/arm/mach-at91rm9200/at91rm9200.c
index 7e1d072bdd8..0985b1c42c7 100644
--- a/arch/arm/mach-at91rm9200/at91rm9200.c
+++ b/arch/arm/mach-at91rm9200/at91rm9200.c
@@ -107,3 +107,48 @@ void __init at91rm9200_map_io(void)
iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
}
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 7, /* Advanced Interrupt Controller (FIQ) */
+ 7, /* System Peripherals */
+ 0, /* Parallel IO Controller A */
+ 0, /* Parallel IO Controller B */
+ 0, /* Parallel IO Controller C */
+ 0, /* Parallel IO Controller D */
+ 6, /* USART 0 */
+ 6, /* USART 1 */
+ 6, /* USART 2 */
+ 6, /* USART 3 */
+ 0, /* Multimedia Card Interface */
+ 4, /* USB Device Port */
+ 0, /* Two-Wire Interface */
+ 6, /* Serial Peripheral Interface */
+ 5, /* Serial Synchronous Controller 0 */
+ 5, /* Serial Synchronous Controller 1 */
+ 5, /* Serial Synchronous Controller 2 */
+ 0, /* Timer Counter 0 */
+ 0, /* Timer Counter 1 */
+ 0, /* Timer Counter 2 */
+ 0, /* Timer Counter 3 */
+ 0, /* Timer Counter 4 */
+ 0, /* Timer Counter 5 */
+ 3, /* USB Host port */
+ 3, /* Ethernet MAC */
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+ 0, /* Advanced Interrupt Controller (IRQ1) */
+ 0, /* Advanced Interrupt Controller (IRQ2) */
+ 0, /* Advanced Interrupt Controller (IRQ3) */
+ 0, /* Advanced Interrupt Controller (IRQ4) */
+ 0, /* Advanced Interrupt Controller (IRQ5) */
+ 0 /* Advanced Interrupt Controller (IRQ6) */
+};
+
+void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
+{
+ if (!priority)
+ priority = at91rm9200_default_irq_priority;
+
+ at91_aic_init(priority);
+}
diff --git a/arch/arm/mach-at91rm9200/generic.h b/arch/arm/mach-at91rm9200/generic.h
index f0d969d7d87..7979d8ab7e0 100644
--- a/arch/arm/mach-at91rm9200/generic.h
+++ b/arch/arm/mach-at91rm9200/generic.h
@@ -8,13 +8,19 @@
* published by the Free Software Foundation.
*/
-void at91_gpio_irq_setup(unsigned banks);
+ /* Interrupts */
+extern void __init at91rm9200_init_irq(unsigned int priority[]);
+extern void __init at91_aic_init(unsigned int priority[]);
+extern void __init at91_gpio_irq_setup(unsigned banks);
+ /* Timer */
struct sys_timer;
extern struct sys_timer at91rm9200_timer;
+ /* Memory Map */
extern void __init at91rm9200_map_io(void);
+ /* Clocks */
extern int __init at91_clock_init(unsigned long main_clock);
struct device;
extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);
diff --git a/arch/arm/mach-at91rm9200/irq.c b/arch/arm/mach-at91rm9200/irq.c
index dcd560dbcfb..9b091132041 100644
--- a/arch/arm/mach-at91rm9200/irq.c
+++ b/arch/arm/mach-at91rm9200/irq.c
@@ -36,58 +36,20 @@
#include "generic.h"
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller */
- 7, /* System Peripheral */
- 0, /* Parallel IO Controller A */
- 0, /* Parallel IO Controller B */
- 0, /* Parallel IO Controller C */
- 0, /* Parallel IO Controller D */
- 6, /* USART 0 */
- 6, /* USART 1 */
- 6, /* USART 2 */
- 6, /* USART 3 */
- 0, /* Multimedia Card Interface */
- 4, /* USB Device Port */
- 0, /* Two-Wire Interface */
- 6, /* Serial Peripheral Interface */
- 5, /* Serial Synchronous Controller */
- 5, /* Serial Synchronous Controller */
- 5, /* Serial Synchronous Controller */
- 0, /* Timer Counter 0 */
- 0, /* Timer Counter 1 */
- 0, /* Timer Counter 2 */
- 0, /* Timer Counter 3 */
- 0, /* Timer Counter 4 */
- 0, /* Timer Counter 5 */
- 3, /* USB Host port */
- 3, /* Ethernet MAC */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
- 0 /* Advanced Interrupt Controller */
-};
-
-static void at91rm9200_mask_irq(unsigned int irq)
+static void at91_aic_mask_irq(unsigned int irq)
{
/* Disable interrupt on AIC */
at91_sys_write(AT91_AIC_IDCR, 1 << irq);
}
-static void at91rm9200_unmask_irq(unsigned int irq)
+static void at91_aic_unmask_irq(unsigned int irq)
{
/* Enable interrupt on AIC */
at91_sys_write(AT91_AIC_IECR, 1 << irq);
}
-static int at91rm9200_irq_type(unsigned irq, unsigned type)
+static int at91_aic_set_type(unsigned irq, unsigned type)
{
unsigned int smr, srctype;
@@ -122,7 +84,7 @@ static int at91rm9200_irq_type(unsigned irq, unsigned type)
static u32 wakeups;
static u32 backups;
-static int at91rm9200_irq_set_wake(unsigned irq, unsigned value)
+static int at91_aic_set_wake(unsigned irq, unsigned value)
{
if (unlikely(irq >= 32))
return -EINVAL;
@@ -149,28 +111,24 @@ void at91_irq_resume(void)
}
#else
-#define at91rm9200_irq_set_wake NULL
+#define at91_aic_set_wake NULL
#endif
-static struct irqchip at91rm9200_irq_chip = {
- .ack = at91rm9200_mask_irq,
- .mask = at91rm9200_mask_irq,
- .unmask = at91rm9200_unmask_irq,
- .set_type = at91rm9200_irq_type,
- .set_wake = at91rm9200_irq_set_wake,
+static struct irqchip at91_aic_chip = {
+ .ack = at91_aic_mask_irq,
+ .mask = at91_aic_mask_irq,
+ .unmask = at91_aic_unmask_irq,
+ .set_type = at91_aic_set_type,
+ .set_wake = at91_aic_set_wake,
};
/*
* Initialize the AIC interrupt controller.
*/
-void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
+void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
{
unsigned int i;
- /* No priority list specified for this board -> use defaults */
- if (priority == NULL)
- priority = at91rm9200_default_irq_priority;
-
/*
* The IVR is used by macro get_irqnr_and_base to read and verify.
* The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
@@ -178,10 +136,10 @@ void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
for (i = 0; i < NR_AIC_IRQS; i++) {
/* Put irq number in Source Vector Register: */
at91_sys_write(AT91_AIC_SVR(i), i);
- /* Store the Source Mode Register as defined in table above */
+ /* Active Low interrupt, with the specified priority */
at91_sys_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
- set_irq_chip(i, &at91rm9200_irq_chip);
+ set_irq_chip(i, &at91_aic_chip);
set_irq_handler(i, do_level_IRQ);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
diff --git a/arch/arm/mach-pnx4008/core.c b/arch/arm/mach-pnx4008/core.c
index ba91daad64f..3d73c1e9375 100644
--- a/arch/arm/mach-pnx4008/core.c
+++ b/arch/arm/mach-pnx4008/core.c
@@ -27,7 +27,6 @@
#include <linux/spi/spi.h>
#include <asm/hardware.h>
-#include <asm/irq.h>
#include <asm/io.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -36,7 +35,6 @@
#include <asm/system.h>
#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
diff --git a/arch/arm/mach-pnx4008/dma.c b/arch/arm/mach-pnx4008/dma.c
index 981aa9dcded..ec01574f88a 100644
--- a/arch/arm/mach-pnx4008/dma.c
+++ b/arch/arm/mach-pnx4008/dma.c
@@ -23,7 +23,6 @@
#include <linux/clk.h>
#include <asm/system.h>
-#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/dma.h>
#include <asm/dma-mapping.h>
diff --git a/arch/arm/mach-pnx4008/irq.c b/arch/arm/mach-pnx4008/irq.c
index 9b0a8e084e9..3a4bcf3d91f 100644
--- a/arch/arm/mach-pnx4008/irq.c
+++ b/arch/arm/mach-pnx4008/irq.c
@@ -22,8 +22,8 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
+#include <linux/irq.h>
#include <asm/hardware.h>
-#include <asm/irq.h>
#include <asm/io.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -96,26 +96,24 @@ void __init pnx4008_init_irq(void)
{
unsigned int i;
- /* configure and enable IRQ 0,1,30,31 (cascade interrupts) mask all others */
+ /* configure IRQ's */
+ for (i = 0; i < NR_IRQS; i++) {
+ set_irq_flags(i, IRQF_VALID);
+ set_irq_chip(i, &pnx4008_irq_chip);
+ pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
+ }
+
+ /* configure and enable IRQ 0,1,30,31 (cascade interrupts) */
pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]);
pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]);
pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]);
pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]);
+ /* mask all others */
__raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
(1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
INTC_ER(MAIN_BASE_INT));
__raw_writel(0, INTC_ER(SIC1_BASE_INT));
__raw_writel(0, INTC_ER(SIC2_BASE_INT));
-
- /* configure all other IRQ's */
- for (i = 0; i < NR_IRQS; i++) {
- if (i == SUB2_FIQ_N || i == SUB1_FIQ_N ||
- i == SUB2_IRQ_N || i == SUB1_IRQ_N)
- continue;
- set_irq_flags(i, IRQF_VALID);
- set_irq_chip(i, &pnx4008_irq_chip);
- pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
- }
}
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 888bf6cfba8..756228ddd03 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -20,17 +20,15 @@
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/irq.h>
#include <asm/system.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/leds.h>
-#include <asm/irq.h>
-#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-
-#include <linux/time.h>
-#include <linux/timex.h>
#include <asm/errno.h>
/*! Note: all timers are UPCOUNTING */
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index fa484d4f241..99daeee4209 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -1032,7 +1032,9 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp)
static void irq_trans_init(struct device_node *dp)
{
const char *model;
+#ifdef CONFIG_PCI
int i;
+#endif
model = of_get_property(dp, "model", NULL);
if (!model)
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 4173de425f0..237524d87ca 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -124,11 +124,6 @@ EXPORT_SYMBOL(__write_lock);
EXPORT_SYMBOL(__write_unlock);
EXPORT_SYMBOL(__write_trylock);
-#if defined(CONFIG_MCOUNT)
-extern void _mcount(void);
-EXPORT_SYMBOL(_mcount);
-#endif
-
/* CPU online map and active count. */
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(phys_cpu_present_map);
@@ -136,6 +131,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
EXPORT_SYMBOL(smp_call_function);
#endif /* CONFIG_SMP */
+#if defined(CONFIG_MCOUNT)
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
+
EXPORT_SYMBOL(sparc64_get_clock_tick);
/* semaphores */
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 8dcbfbffacc..b43de647ba7 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -788,12 +788,15 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
if (!regs)
return -ENOMEM;
+#ifdef CONFIG_PCI
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = (unsigned long) regs;
- } else if (model[5] == '0' && model[6] == '2') {
+ } else
+#endif
+ if (model[5] == '0' && model[6] == '2') {
mstk48t02_regs = regs;
} else if(model[5] == '0' && model[6] == '8') {
mstk48t08_regs = regs;
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 1959654cbec..d2150baa7e3 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1836,9 +1836,10 @@ 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 && pci_rev < 0x20) {
- printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
+ dev_err(&pdev->dev,
+ "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
+ pdev->vendor, pdev->device, pci_rev);
+ dev_err(&pdev->dev, "Try the \"8139too\" driver instead.\n");
return -ENODEV;
}
@@ -1876,14 +1877,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pciaddr = pci_resource_start(pdev, 1);
if (!pciaddr) {
rc = -EIO;
- printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no MMIO resource\n");
goto err_out_res;
}
if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
rc = -EIO;
- printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
- (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
+ dev_err(&pdev->dev, "MMIO resource (%llx) too small\n",
+ (unsigned long long)pci_resource_len(pdev, 1));
goto err_out_res;
}
@@ -1897,14 +1897,15 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting.\n");
goto err_out_res;
}
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
- printk(KERN_ERR PFX "No usable consistent DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "No usable consistent DMA configuration, "
+ "aborting.\n");
goto err_out_res;
}
}
@@ -1915,9 +1916,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
regs = ioremap(pciaddr, CP_REGS_SIZE);
if (!regs) {
rc = -EIO;
- printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%llx) on pci dev %s\n",
- (unsigned long long)pci_resource_len(pdev, 1),
- (unsigned long long)pciaddr, pci_name(pdev));
+ dev_err(&pdev->dev, "Cannot map PCI MMIO (%lx@%lx)\n",
+ (unsigned long long)pci_resource_len(pdev, 1),
+ (unsigned long long)pciaddr);
goto err_out_res;
}
dev->base_addr = (unsigned long) regs;
@@ -1986,7 +1987,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
/* enable busmastering and memory-write-invalidate */
pci_set_master(pdev);
- if (cp->wol_enabled) cp_set_d3_state (cp);
+ if (cp->wol_enabled)
+ cp_set_d3_state (cp);
return 0;
@@ -2011,7 +2013,8 @@ static void cp_remove_one (struct pci_dev *pdev)
BUG_ON(!dev);
unregister_netdev(dev);
iounmap(cp->regs);
- if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
+ if (cp->wol_enabled)
+ pci_set_power_state (pdev, PCI_D0);
pci_release_regions(pdev);
pci_clear_mwi(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 717506b2b13..cd9718512d1 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -768,7 +768,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* dev and priv zeroed in alloc_etherdev */
dev = alloc_etherdev (sizeof (*tp));
if (dev == NULL) {
- printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Unable to alloc new net device\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
@@ -800,31 +800,31 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
#ifdef USE_IO_OPS
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
/* check for weird/broken PCI region reporting */
if (pio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Invalid PCI I/O region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
#else
/* make sure PCI base addr 1 is MMIO */
if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
if (mmio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Invalid PCI mem region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
#endif
- rc = pci_request_regions (pdev, "8139too");
+ rc = pci_request_regions (pdev, DRV_NAME);
if (rc)
goto err_out;
disable_dev_on_err = 1;
@@ -835,7 +835,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
#ifdef USE_IO_OPS
ioaddr = ioport_map(pio_start, pio_len);
if (!ioaddr) {
- printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map PIO, aborting\n");
rc = -EIO;
goto err_out;
}
@@ -846,7 +846,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* ioremap MMIO region */
ioaddr = pci_iomap(pdev, 1, 0);
if (ioaddr == NULL) {
- printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out;
}
@@ -860,8 +860,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* check for missing/broken hardware */
if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
- printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Chip not responding, ignoring board\n");
rc = -EIO;
goto err_out;
}
@@ -875,9 +874,10 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming RTL-8139\n");
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
tp->chipset = 0;
match:
@@ -954,9 +954,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
- printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+ dev_info(&pdev->dev,
+ "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+ pdev->vendor, pdev->device, pci_rev);
+ dev_info(&pdev->dev,
+ "Use the \"8139cp\" driver for improved performance and stability.\n");
}
i = rtl8139_init_board (pdev, &dev);
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index cd98d31dee8..bea0fc0ede2 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -2120,13 +2120,14 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device, "
+ dev_err(&pdev->dev, "Cannot enable PCI device, "
"aborting.\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find proper PCI device "
+ dev_err(&pdev->dev,
+ "Cannot find proper PCI device "
"base address, aborting.\n");
err = -ENODEV;
goto err_out_disable_pdev;
@@ -2134,8 +2135,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, DRV_MODULE_NAME);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot obtain PCI resources, aborting.\n");
goto err_out_disable_pdev;
}
@@ -2143,15 +2144,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
@@ -2160,7 +2159,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_free_res;
}
@@ -2181,8 +2180,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
bp->regs = ioremap(b44reg_base, b44reg_len);
if (bp->regs == 0UL) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
err = -ENOMEM;
goto err_out_free_dev;
}
@@ -2212,8 +2210,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = b44_get_invariants(bp);
if (err) {
- printk(KERN_ERR PFX "Problem fetching invariants of chip, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Problem fetching invariants of chip, aborting.\n");
goto err_out_iounmap;
}
@@ -2233,8 +2231,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
goto err_out_iounmap;
}
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 4f4db5ae503..64b6a72b4f6 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -5575,20 +5575,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device(pdev);
if (rc) {
- printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
goto err_out;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find PCI device base address, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot find PCI device base address, aborting.\n");
rc = -ENODEV;
goto err_out_disable;
}
rc = pci_request_regions(pdev, DRV_MODULE_NAME);
if (rc) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
goto err_out_disable;
}
@@ -5596,15 +5596,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (bp->pm_cap == 0) {
- printk(KERN_ERR PFX "Cannot find power management capability, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot find power management capability, aborting.\n");
rc = -EIO;
goto err_out_release;
}
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
if (bp->pcix_cap == 0) {
- printk(KERN_ERR PFX "Cannot find PCIX capability, aborting.\n");
+ dev_err(&pdev->dev, "Cannot find PCIX capability, aborting.\n");
rc = -EIO;
goto err_out_release;
}
@@ -5612,14 +5612,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
bp->flags |= USING_DAC_FLAG;
if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
- printk(KERN_ERR PFX "pci_set_consistent_dma_mask "
- "failed, aborting.\n");
+ dev_err(&pdev->dev,
+ "pci_set_consistent_dma_mask failed, aborting.\n");
rc = -EIO;
goto err_out_release;
}
}
else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
- printk(KERN_ERR PFX "System does not support DMA, aborting.\n");
+ dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
rc = -EIO;
goto err_out_release;
}
@@ -5639,7 +5639,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->regview = ioremap_nocache(dev->base_addr, mem_len);
if (!bp->regview) {
- printk(KERN_ERR PFX "Cannot map register space, aborting.\n");
+ dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
rc = -ENOMEM;
goto err_out_release;
}
@@ -5711,8 +5711,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
!(bp->flags & PCIX_FLAG)) {
- printk(KERN_ERR PFX "5706 A1 can only be used in a PCIX bus, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "5706 A1 can only be used in a PCIX bus, aborting.\n");
goto err_out_unmap;
}
@@ -5733,7 +5733,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
BNX2_DEV_INFO_SIGNATURE_MAGIC) {
- printk(KERN_ERR PFX "Firmware not running, aborting.\n");
+ dev_err(&pdev->dev, "Firmware not running, aborting.\n");
rc = -ENODEV;
goto err_out_unmap;
}
@@ -5895,7 +5895,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
if ((rc = register_netdev(dev))) {
- printk(KERN_ERR PFX "Cannot register net device\n");
+ dev_err(&pdev->dev, "Cannot register net device\n");
if (bp->regview)
iounmap(bp->regview);
pci_release_regions(pdev);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index d33130f6470..a31544ccb3c 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -4887,13 +4887,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find proper PCI device "
+ dev_err(&pdev->dev, "Cannot find proper PCI device "
"base address, aborting.\n");
err = -ENODEV;
goto err_out_disable_pdev;
@@ -4901,7 +4900,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*cp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_disable_pdev;
}
@@ -4910,8 +4909,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, dev->name);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
goto err_out_free_netdev;
}
pci_set_master(pdev);
@@ -4941,7 +4939,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
if (pci_write_config_byte(pdev,
PCI_CACHE_LINE_SIZE,
cas_cacheline_size)) {
- printk(KERN_ERR PFX "Could not set PCI cache "
+ dev_err(&pdev->dev, "Could not set PCI cache "
"line size\n");
goto err_write_cacheline;
}
@@ -4955,7 +4953,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_set_consistent_dma_mask(pdev,
DMA_64BIT_MASK);
if (err < 0) {
- printk(KERN_ERR PFX "Unable to obtain 64-bit DMA "
+ dev_err(&pdev->dev, "Unable to obtain 64-bit DMA "
"for consistent allocations\n");
goto err_out_free_res;
}
@@ -4963,7 +4961,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
} else {
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
+ dev_err(&pdev->dev, "No usable DMA configuration, "
"aborting.\n");
goto err_out_free_res;
}
@@ -5023,8 +5021,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
/* give us access to cassini registers */
cp->regs = pci_iomap(pdev, 0, casreg_len);
if (cp->regs == 0UL) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
goto err_out_free_res;
}
cp->casreg_len = casreg_len;
@@ -5040,8 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
&cp->block_dvma);
if (!cp->init_block) {
- printk(KERN_ERR PFX "Cannot allocate init block, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot allocate init block, aborting.\n");
goto err_out_iounmap;
}
@@ -5085,8 +5081,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_HIGHDMA;
if (register_netdev(dev)) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
goto err_out_free_consistent;
}
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 2038ca7e49c..6ad5796121c 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -703,8 +703,8 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
return IRQ_HANDLED;
}
-static irqreturn_t
-lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lance_interrupt(const int irq, void *dev_id,
+ struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct lance_private *lp = netdev_priv(dev);
@@ -1253,7 +1253,7 @@ static int __init dec_lance_init(const int type, const int slot)
return 0;
err_out_free_dev:
- kfree(dev);
+ free_netdev(dev);
err_out:
return ret;
@@ -1299,6 +1299,7 @@ static void __exit dec_lance_cleanup(void)
while (root_lance_dev) {
struct net_device *dev = root_lance_dev;
struct lance_private *lp = netdev_priv(dev);
+
unregister_netdev(dev);
#ifdef CONFIG_TC
if (lp->slot >= 0)
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 4b6ddb70f92..402961e68c8 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -9,49 +9,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
-/*
- Rev Date Description
- ==========================================================================
- 0.01 2001/05/03 Created DL2000-based linux driver
- 0.02 2001/05/21 Added VLAN and hardware checksum support.
- 1.00 2001/06/26 Added jumbo frame support.
- 1.01 2001/08/21 Added two parameters, rx_coalesce and rx_timeout.
- 1.02 2001/10/08 Supported fiber media.
- Added flow control parameters.
- 1.03 2001/10/12 Changed the default media to 1000mbps_fd for
- the fiber devices.
- 1.04 2001/11/08 Fixed Tx stopped when tx very busy.
- 1.05 2001/11/22 Fixed Tx stopped when unidirectional tx busy.
- 1.06 2001/12/13 Fixed disconnect bug at 10Mbps mode.
- Fixed tx_full flag incorrect.
- Added tx_coalesce paramter.
- 1.07 2002/01/03 Fixed miscount of RX frame error.
- 1.08 2002/01/17 Fixed the multicast bug.
- 1.09 2002/03/07 Move rx-poll-now to re-fill loop.
- Added rio_timer() to watch rx buffers.
- 1.10 2002/04/16 Fixed miscount of carrier error.
- 1.11 2002/05/23 Added ISR schedule scheme
- Fixed miscount of rx frame error for DGE-550SX.
- Fixed VLAN bug.
- 1.12 2002/06/13 Lock tx_coalesce=1 on 10/100Mbps mode.
- 1.13 2002/08/13 1. Fix disconnection (many tx:carrier/rx:frame
- errs) with some mainboards.
- 2. Use definition "DRV_NAME" "DRV_VERSION"
- "DRV_RELDATE" for flexibility.
- 1.14 2002/08/14 Support ethtool.
- 1.15 2002/08/27 Changed the default media to Auto-Negotiation
- for the fiber devices.
- 1.16 2002/09/04 More power down time for fiber devices auto-
- negotiation.
- Fix disconnect bug after ifup and ifdown.
- 1.17 2002/10/03 Fix RMON statistics overflow.
- Always use I/O mapping to access eeprom,
- avoid system freezing with some chipsets.
-*/
#define DRV_NAME "D-Link DL2000-based linux driver"
-#define DRV_VERSION "v1.17b"
-#define DRV_RELDATE "2006/03/10"
+#define DRV_VERSION "v1.18"
+#define DRV_RELDATE "2006/06/27"
#include "dl2k.h"
#include <linux/dma-mapping.h>
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 2ad32754292..e445988c92e 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -555,12 +555,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
if (!request_region(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1), "eepro100")) {
- printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
+ dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n");
goto err_out_none;
}
if (!request_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), "eepro100")) {
- printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
+ dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n");
goto err_out_free_pio_region;
}
@@ -573,7 +573,7 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
ioaddr = pci_iomap(pdev, pci_bar, 0);
if (!ioaddr) {
- printk (KERN_ERR "eepro100: cannot remap IO\n");
+ dev_err(&pdev->dev, "eepro100: cannot remap IO\n");
goto err_out_free_mmio_region;
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 9f3e09a3d88..a67650ccf08 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -19,62 +19,15 @@
Information and updates available at
http://www.scyld.com/network/epic100.html
+ [this link no longer provides anything useful -jgarzik]
---------------------------------------------------------------------
- Linux kernel-specific changes:
-
- LK1.1.2 (jgarzik):
- * Merge becker version 1.09 (4/08/2000)
-
- LK1.1.3:
- * Major bugfix to 1.09 driver (Francis Romieu)
-
- LK1.1.4 (jgarzik):
- * Merge becker test version 1.09 (5/29/2000)
-
- LK1.1.5:
- * Fix locking (jgarzik)
- * Limit 83c175 probe to ethernet-class PCI devices (rgooch)
-
- LK1.1.6:
- * Merge becker version 1.11
- * Move pci_enable_device before any PCI BAR len checks
-
- LK1.1.7:
- * { fill me in }
-
- LK1.1.8:
- * ethtool driver info support (jgarzik)
-
- LK1.1.9:
- * ethtool media get/set support (jgarzik)
-
- LK1.1.10:
- * revert MII transceiver init change (jgarzik)
-
- LK1.1.11:
- * implement ETHTOOL_[GS]SET, _NWAY_RST, _[GS]MSGLVL, _GLINK (jgarzik)
- * replace some MII-related magic numbers with constants
-
- LK1.1.12:
- * fix power-up sequence
-
- LK1.1.13:
- * revert version 1.1.12, power-up sequence "fix"
-
- LK1.1.14 (Kryzsztof Halasa):
- * fix spurious bad initializations
- * pound phy a la SMSC's app note on the subject
-
- AC1.1.14ac
- * fix power up/down for ethtool that broke in 1.11
-
*/
#define DRV_NAME "epic100"
-#define DRV_VERSION "1.11+LK1.1.14+AC1.1.14"
-#define DRV_RELDATE "June 2, 2004"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
@@ -204,19 +157,15 @@ typedef enum {
struct epic_chip_info {
const char *name;
- int io_size; /* Needed for I/O region check or ioremap(). */
int drv_flags; /* Driver use, intended as capability flags. */
};
/* indexed by chip_t */
static const struct epic_chip_info pci_id_tbl[] = {
- { "SMSC EPIC/100 83c170",
- EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
- { "SMSC EPIC/100 83c170",
- EPIC_TOTAL_SIZE, TYPE2_INTR },
- { "SMSC EPIC/C 83c175",
- EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
+ { "SMSC EPIC/100 83c170", TYPE2_INTR | NO_MII | MII_PWRDWN },
+ { "SMSC EPIC/100 83c170", TYPE2_INTR },
+ { "SMSC EPIC/C 83c175", TYPE2_INTR | MII_PWRDWN },
};
@@ -385,8 +334,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
goto out;
irq = pdev->irq;
- if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
- printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
+ if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) {
+ dev_err(&pdev->dev, "no PCI region space\n");
ret = -ENODEV;
goto err_out_disable;
}
@@ -401,7 +350,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof (*ep));
if (!dev) {
- printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
+ dev_err(&pdev->dev, "no memory for eth device\n");
goto err_out_free_res;
}
SET_MODULE_OWNER(dev);
@@ -413,7 +362,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ioaddr = pci_resource_start (pdev, 1);
ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
if (!ioaddr) {
- printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
+ dev_err(&pdev->dev, "ioremap failed\n");
goto err_out_free_netdev;
}
#endif
@@ -473,8 +422,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
if (debug > 2) {
- printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n",
- pci_name(pdev));
+ dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n");
for (i = 0; i < 64; i++)
printk(" %4.4x%s", read_eeprom(ioaddr, i),
i % 16 == 15 ? "\n" : "");
@@ -496,21 +444,23 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
int mii_status = mdio_read(dev, phy, MII_BMSR);
if (mii_status != 0xffff && mii_status != 0x0000) {
ep->phys[phy_idx++] = phy;
- printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
- "%4.4x status %4.4x.\n",
- pci_name(pdev), phy, mdio_read(dev, phy, 0), mii_status);
+ dev_info(&pdev->dev,
+ "MII transceiver #%d control "
+ "%4.4x status %4.4x.\n",
+ phy, mdio_read(dev, phy, 0), mii_status);
}
}
ep->mii_phy_cnt = phy_idx;
if (phy_idx != 0) {
phy = ep->phys[0];
ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
- printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
+ dev_info(&pdev->dev,
+ "Autonegotiation advertising %4.4x link "
"partner %4.4x.\n",
- pci_name(pdev), ep->mii.advertising, mdio_read(dev, phy, 5));
+ ep->mii.advertising, mdio_read(dev, phy, 5));
} else if ( ! (ep->chip_flags & NO_MII)) {
- printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
- pci_name(pdev));
+ dev_warn(&pdev->dev,
+ "***WARNING***: No MII transceiver found!\n");
/* Use the known PHY address of the EPII. */
ep->phys[0] = 3;
}
@@ -525,8 +475,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
/* The lower four bits are the media type. */
if (duplex) {
ep->mii.force_media = ep->mii.full_duplex = 1;
- printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n",
- pci_name(pdev));
+ dev_info(&pdev->dev, "Forced full duplex requested.\n");
}
dev->if_port = ep->default_port = option;
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index c701951dcd6..97d34fee8c1 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -124,7 +124,9 @@ MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered mult
MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
-#define MIN_REGION_SIZE 136
+enum {
+ MIN_REGION_SIZE = 136,
+};
/* A chip capabilities table, matching the entries in pci_tbl[] above. */
enum chip_capability_flags {
@@ -146,14 +148,13 @@ enum phy_type_flags {
struct chip_info {
char *chip_name;
- int io_size;
int flags;
};
-static const struct chip_info skel_netdrv_tbl[] = {
- {"100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
- {"100/10M Ethernet PCI Adapter", 136, HAS_CHIP_XCVR},
- {"1000/100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
+static const struct chip_info skel_netdrv_tbl[] __devinitdata = {
+ { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
+ { "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
+ { "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
};
/* Offsets to the Command and Status Registers. */
@@ -504,13 +505,14 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
len = pci_resource_len(pdev, bar);
if (len < MIN_REGION_SIZE) {
- printk(KERN_ERR "%s: region size %ld too small, aborting\n",
- boardname, len);
+ dev_err(&pdev->dev,
+ "region size %ld too small, aborting\n", len);
return -ENODEV;
}
i = pci_request_regions(pdev, boardname);
- if (i) return i;
+ if (i)
+ return i;
irq = pdev->irq;
@@ -576,9 +578,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy;
- printk(KERN_INFO
- "%s: MII PHY found at address %d, status "
- "0x%4.4x.\n", dev->name, phy, mii_status);
+ dev_info(&pdev->dev,
+ "MII PHY found at address %d, status "
+ "0x%4.4x.\n", phy, mii_status);
/* get phy type */
{
unsigned int data;
@@ -601,10 +603,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
}
np->mii_cnt = phy_idx;
- if (phy_idx == 0) {
- printk(KERN_WARNING "%s: MII PHY not found -- this device may "
- "not operate correctly.\n", dev->name);
- }
+ if (phy_idx == 0)
+ dev_warn(&pdev->dev,
+ "MII PHY not found -- this device may "
+ "not operate correctly.\n");
} else {
np->phys[0] = 32;
/* 89/6/23 add, (begin) */
@@ -630,7 +632,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np->mii.full_duplex = full_duplex[card_idx];
if (np->mii.full_duplex) {
- printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+ dev_info(&pdev->dev, "Media type forced to Full Duplex.\n");
/* 89/6/13 add, (begin) */
// if (np->PHYType==MarvellPHY)
if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {
diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
index 49dacc6e35a..2b4db741447 100644
--- a/drivers/net/gt96100eth.c
+++ b/drivers/net/gt96100eth.c
@@ -699,7 +699,6 @@ static int __init gt96100_probe1(struct pci_dev *pci, int port_num)
memset(gp, 0, sizeof(*gp)); // clear it
gp->port_num = port_num;
- gp->io_size = GT96100_ETH_IO_SIZE;
gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
gp->phy_addr = phy_addr;
gp->chip_rev = chip_rev;
@@ -1531,7 +1530,7 @@ static void gt96100_cleanup_module(void)
+ sizeof(gt96100_td_t) * TX_RING_SIZE,
gp->rx_ring);
free_netdev(gtif->dev);
- release_region(gtif->iobase, gp->io_size);
+ release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
}
}
}
diff --git a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h
index 2a8331938b8..3b62a87c7d7 100644
--- a/drivers/net/gt96100eth.h
+++ b/drivers/net/gt96100eth.h
@@ -331,7 +331,6 @@ struct gt96100_private {
mib_counters_t mib;
struct net_device_stats stats;
- int io_size;
int port_num; // 0 or 1
int chip_rev;
u32 port_offset;
@@ -340,7 +339,6 @@ struct gt96100_private {
u32 last_psr; // last value of the port status register
int options; /* User-settable misc. driver options. */
- int drv_flags;
struct timer_list timer;
spinlock_t lock; /* Serialise access to device */
};
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 7bcd939c6ed..409c6aab041 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -20,22 +20,15 @@
Support and updates available at
http://www.scyld.com/network/hamachi.html
+ [link no longer provides useful info -jgarzik]
or
http://www.parl.clemson.edu/~keithu/hamachi.html
-
-
- Linux kernel changelog:
-
- LK1.0.1:
- - fix lack of pci_dev<->dev association
- - ethtool support (jgarzik)
-
*/
#define DRV_NAME "hamachi"
-#define DRV_VERSION "1.01+LK1.0.1"
-#define DRV_RELDATE "5/18/2001"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
/* A few user-configurable values. */
@@ -608,7 +601,8 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
pci_set_master(pdev);
i = pci_request_regions(pdev, DRV_NAME);
- if (i) return i;
+ if (i)
+ return i;
irq = pdev->irq;
ioaddr = ioremap(base, 0x400);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 72aad42db7b..f4c8fd373b9 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -188,7 +188,6 @@ struct myri10ge_priv {
int vendor_specific_offset;
u32 devctl;
u16 msi_flags;
- u32 pm_state[16];
u32 read_dma;
u32 write_dma;
u32 read_write_dma;
@@ -1289,6 +1288,7 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
"tx_heartbeat_errors", "tx_window_errors",
/* device-specific stats */
+ "tx_boundary", "WC", "irq", "MSI",
"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
"serial_number", "tx_pkt_start", "tx_pkt_done",
"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
@@ -1327,6 +1327,10 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
data[i] = ((unsigned long *)&mgp->stats)[i];
+ data[i++] = (unsigned int)mgp->tx.boundary;
+ data[i++] = (unsigned int)(mgp->mtrr >= 0);
+ data[i++] = (unsigned int)mgp->pdev->irq;
+ data[i++] = (unsigned int)mgp->msi_enabled;
data[i++] = (unsigned int)mgp->read_dma;
data[i++] = (unsigned int)mgp->write_dma;
data[i++] = (unsigned int)mgp->read_write_dma;
@@ -2197,8 +2201,6 @@ static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
* any other device, except if forced with myri10ge_ecrc_enable > 1.
*/
-#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE 0x005d
-
static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
{
struct pci_dev *bridge = mgp->pdev->bus->self;
@@ -2737,11 +2739,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
goto abort_with_irq;
}
-
- printk(KERN_INFO "myri10ge: %s: %s IRQ %d, tx bndry %d, fw %s, WC %s\n",
- netdev->name, (mgp->msi_enabled ? "MSI" : "xPIC"),
- pdev->irq, mgp->tx.boundary, mgp->fw_name,
- (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
+ dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+ (mgp->msi_enabled ? "MSI" : "xPIC"),
+ pdev->irq, mgp->tx.boundary, mgp->fw_name,
+ (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
return 0;
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 9df2628be1e..db0475a1102 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -20,120 +20,9 @@
Support information and updates available at
http://www.scyld.com/network/netsemi.html
+ [link no longer provides useful info -jgarzik]
- Linux kernel modifications:
-
- Version 1.0.1:
- - Spinlock fixes
- - Bug fixes and better intr performance (Tjeerd)
- Version 1.0.2:
- - Now reads correct MAC address from eeprom
- Version 1.0.3:
- - Eliminate redundant priv->tx_full flag
- - Call netif_start_queue from dev->tx_timeout
- - wmb() in start_tx() to flush data
- - Update Tx locking
- - Clean up PCI enable (davej)
- Version 1.0.4:
- - Merge Donald Becker's natsemi.c version 1.07
- Version 1.0.5:
- - { fill me in }
- Version 1.0.6:
- * ethtool support (jgarzik)
- * Proper initialization of the card (which sometimes
- fails to occur and leaves the card in a non-functional
- state). (uzi)
-
- * Some documented register settings to optimize some
- of the 100Mbit autodetection circuitry in rev C cards. (uzi)
-
- * Polling of the PHY intr for stuff like link state
- change and auto- negotiation to finally work properly. (uzi)
-
- * One-liner removal of a duplicate declaration of
- netdev_error(). (uzi)
-
- Version 1.0.7: (Manfred Spraul)
- * pci dma
- * SMP locking update
- * full reset added into tx_timeout
- * correct multicast hash generation (both big and little endian)
- [copied from a natsemi driver version
- from Myrio Corporation, Greg Smith]
- * suspend/resume
-
- version 1.0.8 (Tim Hockin <thockin@sun.com>)
- * ETHTOOL_* support
- * Wake on lan support (Erik Gilling)
- * MXDMA fixes for serverworks
- * EEPROM reload
-
- version 1.0.9 (Manfred Spraul)
- * Main change: fix lack of synchronize
- netif_close/netif_suspend against a last interrupt
- or packet.
- * do not enable superflous interrupts (e.g. the
- drivers relies on TxDone - TxIntr not needed)
- * wait that the hardware has really stopped in close
- and suspend.
- * workaround for the (at least) gcc-2.95.1 compiler
- problem. Also simplifies the code a bit.
- * disable_irq() in tx_timeout - needed to protect
- against rx interrupts.
- * stop the nic before switching into silent rx mode
- for wol (required according to docu).
-
- version 1.0.10:
- * use long for ee_addr (various)
- * print pointers properly (DaveM)
- * include asm/irq.h (?)
-
- version 1.0.11:
- * check and reset if PHY errors appear (Adrian Sun)
- * WoL cleanup (Tim Hockin)
- * Magic number cleanup (Tim Hockin)
- * Don't reload EEPROM on every reset (Tim Hockin)
- * Save and restore EEPROM state across reset (Tim Hockin)
- * MDIO Cleanup (Tim Hockin)
- * Reformat register offsets/bits (jgarzik)
-
- version 1.0.12:
- * ETHTOOL_* further support (Tim Hockin)
-
- version 1.0.13:
- * ETHTOOL_[G]EEPROM support (Tim Hockin)
-
- version 1.0.13:
- * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
-
- version 1.0.14:
- * Cleanup some messages and autoneg in ethtool (Tim Hockin)
-
- version 1.0.15:
- * Get rid of cable_magic flag
- * use new (National provided) solution for cable magic issue
-
- version 1.0.16:
- * call netdev_rx() for RxErrors (Manfred Spraul)
- * formatting and cleanups
- * change options and full_duplex arrays to be zero
- initialized
- * enable only the WoL and PHY interrupts in wol mode
-
- version 1.0.17:
- * only do cable_magic on 83815 and early 83816 (Tim Hockin)
- * create a function for rx refill (Manfred Spraul)
- * combine drain_ring and init_ring (Manfred Spraul)
- * oom handling (Manfred Spraul)
- * hands_off instead of playing with netif_device_{de,a}ttach
- (Manfred Spraul)
- * be sure to write the MAC back to the chip (Manfred Spraul)
- * lengthen EEPROM timeout, and always warn about timeouts
- (Manfred Spraul)
- * comments update (Manfred)
- * do the right thing on a phy-reset (Manfred and Tim)
-
TODO:
* big endian support with CFG:BEM instead of cpu_to_le32
*/
@@ -165,8 +54,8 @@
#include <asm/uaccess.h>
#define DRV_NAME "natsemi"
-#define DRV_VERSION "1.07+LK1.0.17"
-#define DRV_RELDATE "Sep 27, 2002"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
#define RX_OFFSET 2
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index fa50eb88940..34bdba9eec7 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -231,12 +231,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
irq = pdev->irq;
if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
- printk (KERN_ERR PFX "no I/O resource at PCI BAR #0\n");
+ dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
return -ENODEV;
}
if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
- printk (KERN_ERR PFX "I/O resource 0x%x @ 0x%lx busy\n",
+ dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
NE_IO_EXTENT, ioaddr);
return -EBUSY;
}
@@ -263,7 +263,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
/* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
dev = alloc_ei_netdev();
if (!dev) {
- printk (KERN_ERR PFX "cannot allocate ethernet device\n");
+ dev_err(&pdev->dev, "cannot allocate ethernet device\n");
goto err_out_free_res;
}
SET_MODULE_OWNER(dev);
@@ -281,7 +281,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
/* Limit wait: '2' avoids jiffy roll-over. */
if (jiffies - reset_start_time > 2) {
- printk(KERN_ERR PFX "Card failure (no reset ack).\n");
+ dev_err(&pdev->dev,
+ "Card failure (no reset ack).\n");
goto err_out_free_netdev;
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index a68bf474f6e..d4be207d321 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -1,17 +1,12 @@
/* ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
*
- * Copyright 1996,1997 Jan-Pascal van Best and Andreas Mohr.
+ * Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* The authors may be reached as:
- * jvbest@wi.leidenuniv.nl a.mohr@mailto.de
- * or by snail mail as
- * Jan-Pascal van Best Andreas Mohr
- * Klikspaanweg 58-4 Stauferstr. 6
- * 2324 LZ Leiden D-71272 Renningen
- * The Netherlands Germany
+ * janpascal@vanbest.org andi@lisas.de
*
* Sources:
* Donald Becker's "skeleton.c"
@@ -27,8 +22,9 @@
* 970503 v0.93: Fixed auto-irq failure on warm reboot (JB)
* 970623 v1.00: First kernel version (AM)
* 970814 v1.01: Added detection of onboard receive buffer size (AM)
+ * 060611 v1.02: slight cleanup: email addresses, driver modernization.
* Bugs:
- * - None known...
+ * - not SMP-safe (no locking of I/O accesses)
* - Note that you have to patch ifconfig for the new /proc/net/dev
* format. It gives incorrect stats otherwise.
*
@@ -39,7 +35,7 @@
* Complete merge with Andreas' driver
* Implement ring buffers (Is this useful? You can't squeeze
* too many packet in a 2k buffer!)
- * Implement DMA (Again, is this useful? Some docs says DMA is
+ * Implement DMA (Again, is this useful? Some docs say DMA is
* slower than programmed I/O)
*
* Compile with:
@@ -47,7 +43,7 @@
* -DMODULE -c ni5010.c
*
* Insert with e.g.:
- * insmod ni5010.o io=0x300 irq=5
+ * insmod ni5010.ko io=0x300 irq=5
*/
#include <linux/module.h>
@@ -69,15 +65,15 @@
#include "ni5010.h"
-static const char *boardname = "NI5010";
-static char *version =
- "ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n";
+static const char boardname[] = "NI5010";
+static char version[] __initdata =
+ "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
/* bufsize_rcv == 0 means autoprobing */
static unsigned int bufsize_rcv;
-#define jumpered_interrupts /* IRQ line jumpered on board */
-#undef jumpered_dma /* No DMA used */
+#define JUMPERED_INTERRUPTS /* IRQ line jumpered on board */
+#undef JUMPERED_DMA /* No DMA used */
#undef FULL_IODETECT /* Only detect in portlist */
#ifndef FULL_IODETECT
@@ -281,7 +277,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
if (dev->irq == 0xff)
;
else if (dev->irq < 2) {
@@ -305,7 +301,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
} else if (dev->irq == 2) {
dev->irq = 9;
}
-#endif /* jumpered_irq */
+#endif /* JUMPERED_INTERRUPTS */
PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
/* DMA is not supported (yet?), so no use detecting it */
@@ -334,7 +330,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
outw(0, IE_GP); /* Point GP at start of packet */
outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */
}
- printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
+ printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
memset(dev->priv, 0, sizeof(struct ni5010_local));
dev->open = ni5010_open;
@@ -354,11 +350,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
outb(0xff, EDLC_XCLR); /* Kill all pending xmt interrupts */
printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
- if (dev->dma) printk(" & DMA %d", dev->dma);
+ if (dev->dma)
+ printk(" & DMA %d", dev->dma);
printk(".\n");
-
- printk(KERN_INFO "Join the NI5010 driver development team!\n");
- printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n");
return 0;
out:
release_region(dev->base_addr, NI5010_IO_EXTENT);
@@ -371,7 +365,7 @@ out:
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
+ * there is a non-reboot way to recover if something goes wrong.
*/
static int ni5010_open(struct net_device *dev)
@@ -390,13 +384,13 @@ static int ni5010_open(struct net_device *dev)
* Always allocate the DMA channel after the IRQ,
* and clean up on failure.
*/
-#ifdef jumpered_dma
+#ifdef JUMPERED_DMA
if (request_dma(dev->dma, cardname)) {
printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
free_irq(dev->irq, NULL);
return -EAGAIN;
}
-#endif /* jumpered_dma */
+#endif /* JUMPERED_DMA */
PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
/* Reset the hardware here. Don't forget to set the station address. */
@@ -633,7 +627,7 @@ static int ni5010_close(struct net_device *dev)
int ioaddr = dev->base_addr;
PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
free_irq(dev->irq, NULL);
#endif
/* Put card in held-RESET state */
@@ -771,7 +765,7 @@ module_param(irq, int, 0);
MODULE_PARM_DESC(io, "ni5010 I/O base address");
MODULE_PARM_DESC(irq, "ni5010 IRQ number");
-int init_module(void)
+static int __init ni5010_init_module(void)
{
PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
/*
@@ -792,13 +786,15 @@ int init_module(void)
return 0;
}
-void cleanup_module(void)
+static void __exit ni5010_cleanup_module(void)
{
PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
unregister_netdev(dev_ni5010);
release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
free_netdev(dev_ni5010);
}
+module_init(ni5010_init_module);
+module_exit(ni5010_cleanup_module);
#endif /* MODULE */
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 70429108c40..0e76859c90a 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -803,7 +803,7 @@ static int ns83820_setup_rx(struct net_device *ndev)
writel(dev->IMR_cache, dev->base + IMR);
writel(1, dev->base + IER);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock(&dev->misc_lock);
kick_rx(ndev);
@@ -1012,8 +1012,6 @@ static void do_tx_done(struct net_device *ndev)
struct ns83820 *dev = PRIV(ndev);
u32 cmdsts, tx_done_idx, *desc;
- spin_lock_irq(&dev->tx_lock);
-
dprintk("do_tx_done(%p)\n", ndev);
tx_done_idx = dev->tx_done_idx;
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1069,7 +1067,6 @@ static void do_tx_done(struct net_device *ndev)
netif_start_queue(ndev);
netif_wake_queue(ndev);
}
- spin_unlock_irq(&dev->tx_lock);
}
static void ns83820_cleanup_tx(struct ns83820 *dev)
@@ -1281,11 +1278,13 @@ static struct ethtool_ops ops = {
.get_link = ns83820_get_link
};
+/* this function is called in irq context from the ISR */
static void ns83820_mib_isr(struct ns83820 *dev)
{
- spin_lock(&dev->misc_lock);
+ unsigned long flags;
+ spin_lock_irqsave(&dev->misc_lock, flags);
ns83820_update_stats(dev);
- spin_unlock(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
static void ns83820_do_isr(struct net_device *ndev, u32 isr);
@@ -1307,6 +1306,8 @@ static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs)
static void ns83820_do_isr(struct net_device *ndev, u32 isr)
{
struct ns83820 *dev = PRIV(ndev);
+ unsigned long flags;
+
#ifdef DEBUG
if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
Dprintk("odd isr? 0x%08x\n", isr);
@@ -1321,10 +1322,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
if ((ISR_RXDESC | ISR_RXOK) & isr) {
prefetch(dev->rx_info.next_rx_desc);
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
tasklet_schedule(&dev->rx_tasklet);
//rx_irq(ndev);
@@ -1370,16 +1371,18 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
* work has accumulated
*/
if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
+ spin_lock_irqsave(&dev->tx_lock, flags);
do_tx_done(ndev);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
/* Disable TxOk if there are no outstanding tx packets.
*/
if ((dev->tx_done_idx == dev->tx_free_idx) &&
(dev->IMR_cache & ISR_TXOK)) {
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache &= ~ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
}
@@ -1390,10 +1393,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
* nature are expected, we must enable TxOk.
*/
if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache |= ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
/* MIB interrupt: one of the statistics counters is about to overflow */
@@ -1455,7 +1458,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
u32 tx_done_idx, *desc;
unsigned long flags;
- local_irq_save(flags);
+ spin_lock_irqsave(&dev->tx_lock, flags);
tx_done_idx = dev->tx_done_idx;
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1482,7 +1485,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
ndev->name,
tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
}
static void ns83820_tx_watch(unsigned long data)
@@ -1832,7 +1835,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
} else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
using_dac = 0;
} else {
- printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");
+ dev_warn(&pci_dev->dev, "pci_set_dma_mask failed!\n");
return -ENODEV;
}
@@ -1855,7 +1858,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
err = pci_enable_device(pci_dev);
if (err) {
- printk(KERN_INFO "ns83820: pci_enable_dev failed: %d\n", err);
+ dev_info(&pci_dev->dev, "pci_enable_dev failed: %d\n", err);
goto out_free;
}
@@ -1884,8 +1887,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED,
DRV_NAME, ndev);
if (err) {
- printk(KERN_INFO "ns83820: unable to register irq %d\n",
- pci_dev->irq);
+ dev_info(&pci_dev->dev, "unable to register irq %d, err %d\n",
+ pci_dev->irq, err);
goto out_disable;
}
@@ -1899,7 +1902,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
rtnl_lock();
err = dev_alloc_name(ndev, ndev->name);
if (err < 0) {
- printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err);
+ dev_info(&pci_dev->dev, "unable to get netdev name: %d\n", err);
goto out_free_irq;
}
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 3388ee1313e..e0e29396404 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -601,7 +601,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* dev zeroed in alloc_etherdev */
dev = alloc_etherdev (sizeof (*tp));
if (dev == NULL) {
- printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
DPRINTK ("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
@@ -631,14 +631,14 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
+ dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
/* make sure PCI base addr 1 is MMIO */
if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
@@ -646,12 +646,12 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* check for weird/broken PCI region reporting */
if ((pio_len < NETDRV_MIN_IO_SIZE) ||
(mmio_len < NETDRV_MIN_IO_SIZE)) {
- printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+ dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
- rc = pci_request_regions (pdev, "pci-skeleton");
+ rc = pci_request_regions (pdev, MODNAME);
if (rc)
goto err_out;
@@ -663,7 +663,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* ioremap MMIO region */
ioaddr = ioremap (mmio_start, mmio_len);
if (ioaddr == NULL) {
- printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
@@ -699,9 +699,10 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pci_name(pdev), NETDRV_R32 (TxConfig));
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming RTL-8139\n");
+ dev_printk (KERN_DEBUG, &pdev->dev, "TxConfig = 0x%lx\n",
+ NETDRV_R32 (TxConfig));
tp->chipset = 0;
match:
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index d768f3d1ac2..4daafe30335 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -58,18 +58,15 @@ static const char *const version =
* PCI device identifiers for "new style" Linux PCI Device Drivers
*/
static struct pci_device_id pcnet32_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
/*
* Adapters that were sold with IBM's RS/6000 or pSeries hardware have
* the incorrect vendor id.
*/
- { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE),
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, },
{ } /* terminate list */
};
@@ -188,6 +185,23 @@ static int homepna[MAX_UNITS];
#define PCNET32_TOTAL_SIZE 0x20
+#define CSR0 0
+#define CSR0_INIT 0x1
+#define CSR0_START 0x2
+#define CSR0_STOP 0x4
+#define CSR0_TXPOLL 0x8
+#define CSR0_INTEN 0x40
+#define CSR0_IDON 0x0100
+#define CSR0_NORMAL (CSR0_START | CSR0_INTEN)
+#define PCNET32_INIT_LOW 1
+#define PCNET32_INIT_HIGH 2
+#define CSR3 3
+#define CSR4 4
+#define CSR5 5
+#define CSR5_SUSPEND 0x0001
+#define CSR15 15
+#define PCNET32_MC_FILTER 8
+
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
@@ -277,7 +291,6 @@ struct pcnet32_private {
u32 phymask;
};
-static void pcnet32_probe_vlbus(void);
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
static int pcnet32_probe1(unsigned long, int, struct pci_dev *);
static int pcnet32_open(struct net_device *);
@@ -419,6 +432,238 @@ static struct pcnet32_access pcnet32_dwio = {
.reset = pcnet32_dwio_reset
};
+static void pcnet32_netif_stop(struct net_device *dev)
+{
+ dev->trans_start = jiffies;
+ netif_poll_disable(dev);
+ netif_tx_disable(dev);
+}
+
+static void pcnet32_netif_start(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ netif_poll_enable(dev);
+}
+
+/*
+ * Allocate space for the new sized tx ring.
+ * Free old resources
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_tx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_tx_head *new_tx_ring;
+ struct sk_buff **new_skb_list;
+
+ pcnet32_purge_tx_ring(dev);
+
+ new_tx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_tx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_tx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ kfree(lp->tx_skbuff);
+ kfree(lp->tx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ lp->tx_ring_size, lp->tx_ring,
+ lp->tx_ring_dma_addr);
+
+ lp->tx_ring_size = (1 << size);
+ lp->tx_mod_mask = lp->tx_ring_size - 1;
+ lp->tx_len_bits = (size << 12);
+ lp->tx_ring = new_tx_ring;
+ lp->tx_ring_dma_addr = new_ring_dma_addr;
+ lp->tx_dma_addr = new_dma_addr_list;
+ lp->tx_skbuff = new_skb_list;
+ return;
+
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_tx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ new_tx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+/*
+ * Allocate space for the new sized rx ring.
+ * Re-use old receive buffers.
+ * alloc extra buffers
+ * free unneeded buffers
+ * free unneeded buffers
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_rx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_rx_head *new_rx_ring;
+ struct sk_buff **new_skb_list;
+ int new, overlap;
+
+ new_rx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_rx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_rx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ /* first copy the current receive buffers */
+ overlap = min(size, lp->rx_ring_size);
+ for (new = 0; new < overlap; new++) {
+ new_rx_ring[new] = lp->rx_ring[new];
+ new_dma_addr_list[new] = lp->rx_dma_addr[new];
+ new_skb_list[new] = lp->rx_skbuff[new];
+ }
+ /* now allocate any new buffers needed */
+ for (; new < size; new++ ) {
+ struct sk_buff *rx_skbuff;
+ new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ);
+ if (!(rx_skbuff = new_skb_list[new])) {
+ /* keep the original lists and buffers */
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
+ dev->name);
+ goto free_all_new;
+ }
+ skb_reserve(rx_skbuff, 2);
+
+ new_dma_addr_list[new] =
+ pci_map_single(lp->pci_dev, rx_skbuff->data,
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
+ new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ new_rx_ring[new].status = le16_to_cpu(0x8000);
+ }
+ /* and free any unneeded buffers */
+ for (; new < lp->rx_ring_size; new++) {
+ if (lp->rx_skbuff[new]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(lp->rx_skbuff[new]);
+ }
+ }
+
+ kfree(lp->rx_skbuff);
+ kfree(lp->rx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ lp->rx_ring_size, lp->rx_ring,
+ lp->rx_ring_dma_addr);
+
+ lp->rx_ring_size = (1 << size);
+ lp->rx_mod_mask = lp->rx_ring_size - 1;
+ lp->rx_len_bits = (size << 4);
+ lp->rx_ring = new_rx_ring;
+ lp->rx_ring_dma_addr = new_ring_dma_addr;
+ lp->rx_dma_addr = new_dma_addr_list;
+ lp->rx_skbuff = new_skb_list;
+ return;
+
+ free_all_new:
+ for (; --new >= lp->rx_ring_size; ) {
+ if (new_skb_list[new]) {
+ pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(new_skb_list[new]);
+ }
+ }
+ kfree(new_skb_list);
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_rx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ new_rx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+static void pcnet32_purge_rx_ring(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int i;
+
+ /* free all allocated skbuffs */
+ for (i = 0; i < lp->rx_ring_size; i++) {
+ lp->rx_ring[i].status = 0; /* CPU owns buffer */
+ wmb(); /* Make sure adapter sees owner change */
+ if (lp->rx_skbuff[i]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(lp->rx_skbuff[i]);
+ }
+ lp->rx_skbuff[i] = NULL;
+ lp->rx_dma_addr[i] = 0;
+ }
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
@@ -519,10 +764,10 @@ static void pcnet32_get_ringparam(struct net_device *dev,
{
struct pcnet32_private *lp = dev->priv;
- ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
- ering->tx_pending = lp->tx_ring_size - 1;
- ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
- ering->rx_pending = lp->rx_ring_size - 1;
+ ering->tx_max_pending = TX_MAX_RING_SIZE;
+ ering->tx_pending = lp->tx_ring_size;
+ ering->rx_max_pending = RX_MAX_RING_SIZE;
+ ering->rx_pending = lp->rx_ring_size;
}
static int pcnet32_set_ringparam(struct net_device *dev,
@@ -530,56 +775,53 @@ static int pcnet32_set_ringparam(struct net_device *dev,
{
struct pcnet32_private *lp = dev->priv;
unsigned long flags;
+ unsigned int size;
+ ulong ioaddr = dev->base_addr;
int i;
if (ering->rx_mini_pending || ering->rx_jumbo_pending)
return -EINVAL;
if (netif_running(dev))
- pcnet32_close(dev);
+ pcnet32_netif_stop(dev);
spin_lock_irqsave(&lp->lock, flags);
- pcnet32_free_ring(dev);
- lp->tx_ring_size =
- min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
- lp->rx_ring_size =
- min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
/* set the minimum ring size to 4, to allow the loopback test to work
* unchanged.
*/
for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
- if (lp->tx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->tx_ring_size = (1 << i);
- lp->tx_mod_mask = lp->tx_ring_size - 1;
- lp->tx_len_bits = (i << 12);
-
+ if ((1 << i) != lp->tx_ring_size)
+ pcnet32_realloc_tx_ring(dev, lp, i);
+
+ size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
- if (lp->rx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->rx_ring_size = (1 << i);
- lp->rx_mod_mask = lp->rx_ring_size - 1;
- lp->rx_len_bits = (i << 4);
+ if ((1 << i) != lp->rx_ring_size)
+ pcnet32_realloc_rx_ring(dev, lp, i);
+
+ dev->weight = lp->rx_ring_size / 2;
- if (pcnet32_alloc_ring(dev, dev->name)) {
- pcnet32_free_ring(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- return -ENOMEM;
+ if (netif_running(dev)) {
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, CSR0_NORMAL);
}
spin_unlock_irqrestore(&lp->lock, flags);
- if (pcnet32_debug & NETIF_MSG_DRV)
- printk(KERN_INFO PFX
+ if (netif_msg_drv(lp))
+ printk(KERN_INFO
"%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
lp->rx_ring_size, lp->tx_ring_size);
- if (netif_running(dev))
- pcnet32_open(dev);
-
return 0;
}
@@ -633,29 +875,27 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
unsigned long flags;
unsigned long ticks;
- *data1 = 1; /* status of test, default to fail */
rc = 1; /* default to fail */
if (netif_running(dev))
pcnet32_close(dev);
spin_lock_irqsave(&lp->lock, flags);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
/* Reset the PCNET32 */
lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915);
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
- lp->init_block.mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
- lp->init_block.filter[0] = 0;
- lp->init_block.filter[1] = 0;
-
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
/* Initialize Transmit buffers. */
size = data_len + 15;
@@ -697,14 +937,15 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
- x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
- x = x | 0x0002;
- a->write_bcr(ioaddr, 32, x);
+ x = a->read_bcr(ioaddr, 32); /* set internal loopback in BCR32 */
+ a->write_bcr(ioaddr, 32, x | 0x0002);
- lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
+ /* set int loopback in CSR15 */
+ x = a->read_csr(ioaddr, CSR15) & 0xfffc;
+ lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
teststatus = le16_to_cpu(0x8000);
- lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
for (x = 0; x < numbuffs; x++) {
@@ -712,7 +953,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
rmb();
while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
+ msleep(1);
spin_lock_irqsave(&lp->lock, flags);
rmb();
ticks++;
@@ -725,7 +966,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
@@ -758,25 +999,24 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
x++;
}
- if (!rc) {
- *data1 = 0;
- }
clean_up:
+ *data1 = rc;
pcnet32_purge_tx_ring(dev);
- x = a->read_csr(ioaddr, 15) & 0xFFFF;
- a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
- x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
- x = x & ~0x0002;
- a->write_bcr(ioaddr, 32, x);
+ x = a->read_csr(ioaddr, CSR15);
+ a->write_csr(ioaddr, CSR15, (x & ~0x0044)); /* reset bits 6 and 2 */
- spin_unlock_irqrestore(&lp->lock, flags);
+ x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
+ a->write_bcr(ioaddr, 32, (x & ~0x0002));
if (netif_running(dev)) {
+ spin_unlock_irqrestore(&lp->lock, flags);
pcnet32_open(dev);
} else {
+ pcnet32_purge_rx_ring(dev);
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ spin_unlock_irqrestore(&lp->lock, flags);
}
return (rc);
@@ -839,6 +1079,43 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
return 0;
}
+/*
+ * lp->lock must be held.
+ */
+static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
+ int can_sleep)
+{
+ int csr5;
+ struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_access *a = &lp->a;
+ ulong ioaddr = dev->base_addr;
+ int ticks;
+
+ /* set SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
+
+ /* poll waiting for bit to be set */
+ ticks = 0;
+ while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
+ spin_unlock_irqrestore(&lp->lock, *flags);
+ if (can_sleep)
+ msleep(1);
+ else
+ mdelay(1);
+ spin_lock_irqsave(&lp->lock, *flags);
+ ticks++;
+ if (ticks > 200) {
+ if (netif_msg_hw(lp))
+ printk(KERN_DEBUG
+ "%s: Error getting into suspend!\n",
+ dev->name);
+ return 0;
+ }
+ }
+ return 1;
+}
+
#define PCNET32_REGS_PER_PHY 32
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
@@ -857,32 +1134,13 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
struct pcnet32_private *lp = dev->priv;
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
- int ticks;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- csr0 = a->read_csr(ioaddr, 0);
- if (!(csr0 & 0x0004)) { /* If not stopped */
- /* set SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0001);
-
- /* poll waiting for bit to be set */
- ticks = 0;
- while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
- spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
- spin_lock_irqsave(&lp->lock, flags);
- ticks++;
- if (ticks > 200) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Error getting into suspend!\n",
- dev->name);
- break;
- }
- }
- }
+ csr0 = a->read_csr(ioaddr, CSR0);
+ if (!(csr0 & CSR0_STOP)) /* If not stopped */
+ pcnet32_suspend(dev, &flags, 1);
/* read address PROM */
for (i = 0; i < 16; i += 2)
@@ -919,9 +1177,12 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
}
- if (!(csr0 & 0x0004)) { /* If not stopped */
+ if (!(csr0 & CSR0_STOP)) { /* If not stopped */
+ int csr5;
+
/* clear SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0000);
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -952,7 +1213,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = {
/* only probes for non-PCI devices, the rest are handled by
* pci_register_driver via pcnet32_probe_pci */
-static void __devinit pcnet32_probe_vlbus(void)
+static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist)
{
unsigned int *port, ioaddr;
@@ -1436,7 +1697,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
lp->tx_ring_size,
&lp->tx_ring_dma_addr);
if (lp->tx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
@@ -1448,52 +1709,48 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
lp->rx_ring_size,
&lp->rx_ring_dma_addr);
if (lp->rx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
return -ENOMEM;
}
- lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size,
+ lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->tx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size);
- lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size,
+ lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->rx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size);
- lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size,
+ lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->tx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size);
- lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size,
+ lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->rx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
return 0;
}
@@ -1757,16 +2014,7 @@ static int pcnet32_open(struct net_device *dev)
err_free_ring:
/* free any allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
/*
* Switch back to 16bit mode to avoid problems with dumb
@@ -2348,7 +2596,6 @@ static int pcnet32_close(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
- int i;
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@@ -2379,31 +2626,8 @@ static int pcnet32_close(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
- /* free all allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- wmb(); /* Make sure adapter sees owner change */
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
-
- for (i = 0; i < lp->tx_ring_size; i++) {
- lp->tx_ring[i].status = 0; /* CPU owns buffer */
- wmb(); /* Make sure adapter sees owner change */
- if (lp->tx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
- lp->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(lp->tx_skbuff[i]);
- }
- lp->tx_skbuff[i] = NULL;
- lp->tx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
+ pcnet32_purge_tx_ring(dev);
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2433,6 +2657,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
volatile struct pcnet32_init_block *ib = &lp->init_block;
volatile u16 *mcast_table = (u16 *) & ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
+ unsigned long ioaddr = dev->base_addr;
char *addrs;
int i;
u32 crc;
@@ -2441,6 +2666,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI) {
ib->filter[0] = 0xffffffff;
ib->filter[1] = 0xffffffff;
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
return;
}
/* clear the multicast filter */
@@ -2462,6 +2691,9 @@ static void pcnet32_load_multicast(struct net_device *dev)
le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
(1 << (crc & 0xf)));
}
+ for (i = 0; i < 4; i++)
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
+ le16_to_cpu(mcast_table[i]));
return;
}
@@ -2472,8 +2704,11 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr, flags;
struct pcnet32_private *lp = dev->priv;
+ int csr15, suspended;
spin_lock_irqsave(&lp->lock, flags);
+ suspended = pcnet32_suspend(dev, &flags, 0);
+ csr15 = lp->a.read_csr(ioaddr, CSR15);
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
if (netif_msg_hw(lp))
@@ -2482,15 +2717,24 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
lp->init_block.mode =
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
lp->init_block.mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
- pcnet32_restart(dev, 0x0042); /* Resume normal operation */
- netif_wake_queue(dev);
+ if (suspended) {
+ int csr5;
+ /* clear SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = lp->a.read_csr(ioaddr, CSR5);
+ lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
+ } else {
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ pcnet32_restart(dev, CSR0_NORMAL);
+ netif_wake_queue(dev);
+ }
spin_unlock_irqrestore(&lp->lock, flags);
}
@@ -2730,7 +2974,7 @@ static int __init pcnet32_init_module(void)
/* should we find any remaining VLbus devices ? */
if (pcnet32vlb)
- pcnet32_probe_vlbus();
+ pcnet32_probe_vlbus(pcnet32_portlist);
if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index 3efb715c28d..ae60e6e4107 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -103,7 +103,22 @@ static int cis820x_config_intr(struct phy_device *phydev)
return err;
}
-/* Cicada 820x */
+/* Cicada 8201, a.k.a Vitesse VSC8201 */
+static struct phy_driver cis8201_driver = {
+ .phy_id = 0x000fc410,
+ .name = "Cicada Cis8201",
+ .phy_id_mask = 0x000ffff0,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &cis820x_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &cis820x_ack_interrupt,
+ .config_intr = &cis820x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+/* Cicada 8204 */
static struct phy_driver cis8204_driver = {
.phy_id = 0x000fc440,
.name = "Cicada Cis8204",
@@ -118,15 +133,30 @@ static struct phy_driver cis8204_driver = {
.driver = { .owner = THIS_MODULE,},
};
-static int __init cis8204_init(void)
+static int __init cicada_init(void)
{
- return phy_driver_register(&cis8204_driver);
+ int ret;
+
+ ret = phy_driver_register(&cis8204_driver);
+ if (ret)
+ goto err1;
+
+ ret = phy_driver_register(&cis8201_driver);
+ if (ret)
+ goto err2;
+ return 0;
+
+err2:
+ phy_driver_unregister(&cis8204_driver);
+err1:
+ return ret;
}
-static void __exit cis8204_exit(void)
+static void __exit cicada_exit(void)
{
phy_driver_unregister(&cis8204_driver);
+ phy_driver_unregister(&cis8201_driver);
}
-module_init(cis8204_init);
-module_exit(cis8204_exit);
+module_init(cicada_init);
+module_exit(cicada_exit);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 16a0ef1b136..4c2f575faad 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1406,7 +1406,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
dev = alloc_etherdev(sizeof (*tp));
if (dev == NULL) {
if (netif_msg_drv(&debug))
- printk(KERN_ERR PFX "unable to alloc new ethernet\n");
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
goto err_out;
}
@@ -1418,10 +1418,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pci_enable_device(pdev);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX "%s: enable failure\n",
- pci_name(pdev));
- }
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "enable failure\n");
goto err_out_free_dev;
}
@@ -1437,37 +1435,32 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
} else {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"PowerManagement capability not found.\n");
- }
}
/* make sure PCI base addr 1 is MMIO */
if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"region #1 not an MMIO resource, aborting\n");
- }
rc = -ENODEV;
goto err_out_mwi;
}
/* check for weird/broken PCI region reporting */
if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"Invalid PCI region size(s), aborting\n");
- }
rc = -ENODEV;
goto err_out_mwi;
}
rc = pci_request_regions(pdev, MODULENAME);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX "%s: could not request regions.\n",
- pci_name(pdev));
- }
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "could not request regions.\n");
goto err_out_mwi;
}
@@ -1480,10 +1473,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
} else {
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"DMA configuration failed.\n");
- }
goto err_out_free_res;
}
}
@@ -1494,7 +1486,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
if (ioaddr == NULL) {
if (netif_msg_probe(tp))
- printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
@@ -1526,9 +1518,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
if (i < 0) {
/* Unknown chip: assume array element #0, original RTL-8169 */
if (netif_msg_probe(tp)) {
- printk(KERN_DEBUG PFX "PCI device %s: "
+ dev_printk(KERN_DEBUG, &pdev->dev,
"unknown chip version, assuming %s\n",
- pci_name(pdev), rtl_chip_info[0].name);
+ rtl_chip_info[0].name);
}
i++;
}
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index ed1f59901ff..c0a62b00ffc 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -22,129 +22,13 @@
Support and updates available at
http://www.scyld.com/network/starfire.html
+ [link no longer provides useful info -jgarzik]
- -----------------------------------------------------------
-
- Linux kernel-specific changes:
-
- LK1.1.1 (jgarzik):
- - Use PCI driver interface
- - Fix MOD_xxx races
- - softnet fixups
-
- LK1.1.2 (jgarzik):
- - Merge Becker version 0.15
-
- LK1.1.3 (Andrew Morton)
- - Timer cleanups
-
- LK1.1.4 (jgarzik):
- - Merge Becker version 1.03
-
- LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
- - Support hardware Rx/Tx checksumming
- - Use the GFP firmware taken from Adaptec's Netware driver
-
- LK1.2.2 (Ion Badulescu)
- - Backported to 2.2.x
-
- LK1.2.3 (Ion Badulescu)
- - Fix the flaky mdio interface
- - More compat clean-ups
-
- LK1.2.4 (Ion Badulescu)
- - More 2.2.x initialization fixes
-
- LK1.2.5 (Ion Badulescu)
- - Several fixes from Manfred Spraul
-
- LK1.2.6 (Ion Badulescu)
- - Fixed ifup/ifdown/ifup problem in 2.4.x
-
- LK1.2.7 (Ion Badulescu)
- - Removed unused code
- - Made more functions static and __init
-
- LK1.2.8 (Ion Badulescu)
- - Quell bogus error messages, inform about the Tx threshold
- - Removed #ifdef CONFIG_PCI, this driver is PCI only
-
- LK1.2.9 (Ion Badulescu)
- - Merged Jeff Garzik's changes from 2.4.4-pre5
- - Added 2.2.x compatibility stuff required by the above changes
-
- LK1.2.9a (Ion Badulescu)
- - More updates from Jeff Garzik
-
- LK1.3.0 (Ion Badulescu)
- - Merged zerocopy support
-
- LK1.3.1 (Ion Badulescu)
- - Added ethtool support
- - Added GPIO (media change) interrupt support
-
- LK1.3.2 (Ion Badulescu)
- - Fixed 2.2.x compatibility issues introduced in 1.3.1
- - Fixed ethtool ioctl returning uninitialized memory
-
- LK1.3.3 (Ion Badulescu)
- - Initialize the TxMode register properly
- - Don't dereference dev->priv after freeing it
-
- LK1.3.4 (Ion Badulescu)
- - Fixed initialization timing problems
- - Fixed interrupt mask definitions
-
- LK1.3.5 (jgarzik)
- - ethtool NWAY_RST, GLINK, [GS]MSGLVL support
-
- LK1.3.6:
- - Sparc64 support and fixes (Ion Badulescu)
- - Better stats and error handling (Ion Badulescu)
- - Use new pci_set_mwi() PCI API function (jgarzik)
-
- LK1.3.7 (Ion Badulescu)
- - minimal implementation of tx_timeout()
- - correctly shutdown the Rx/Tx engines in netdev_close()
- - added calls to netif_carrier_on/off
- (patch from Stefan Rompf <srompf@isg.de>)
- - VLAN support
-
- LK1.3.8 (Ion Badulescu)
- - adjust DMA burst size on sparc64
- - 64-bit support
- - reworked zerocopy support for 64-bit buffers
- - working and usable interrupt mitigation/latency
- - reduced Tx interrupt frequency for lower interrupt overhead
-
- LK1.3.9 (Ion Badulescu)
- - bugfix for mcast filter
- - enable the right kind of Tx interrupts (TxDMADone, not TxDone)
-
- LK1.4.0 (Ion Badulescu)
- - NAPI support
-
- LK1.4.1 (Ion Badulescu)
- - flush PCI posting buffers after disabling Rx interrupts
- - put the chip to a D3 slumber on driver unload
- - added config option to enable/disable NAPI
-
- LK1.4.2 (Ion Badulescu)
- - finally added firmware (GPL'ed by Adaptec)
- - removed compatibility code for 2.2.x
-
- LK1.4.2.1 (Ion Badulescu)
- - fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM
- - added 32-bit padding to outgoing skb's, removed previous workaround
-
-TODO: - fix forced speed/duplexing code (broken a long time ago, when
- somebody converted the driver to use the generic MII code)
- - fix VLAN support
*/
#define DRV_NAME "starfire"
-#define DRV_VERSION "1.03+LK1.4.2.1"
-#define DRV_RELDATE "October 3, 2005"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -846,7 +730,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
goto err_out_free_netdev;
}
- /* ioremap is borken in Linux-2.2.x/sparc64 */
base = ioremap(ioaddr, io_size);
if (!base) {
printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 643fceae3db..ac17377b3e9 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -16,91 +16,13 @@
Support and updates available at
http://www.scyld.com/network/sundance.html
+ [link no longer provides useful info -jgarzik]
-
- Version LK1.01a (jgarzik):
- - Replace some MII-related magic numbers with constants
-
- Version LK1.02 (D-Link):
- - Add new board to PCI ID list
- - Fix multicast bug
-
- Version LK1.03 (D-Link):
- - New Rx scheme, reduce Rx congestion
- - Option to disable flow control
-
- Version LK1.04 (D-Link):
- - Tx timeout recovery
- - More support for ethtool.
-
- Version LK1.04a:
- - Remove unused/constant members from struct pci_id_info
- (which then allows removal of 'drv_flags' from private struct)
- (jgarzik)
- - If no phy is found, fail to load that board (jgarzik)
- - Always start phy id scan at id 1 to avoid problems (Donald Becker)
- - Autodetect where mii_preable_required is needed,
- default to not needed. (Donald Becker)
-
- Version LK1.04b:
- - Remove mii_preamble_required module parameter (Donald Becker)
- - Add per-interface mii_preamble_required (setting is autodetected)
- (Donald Becker)
- - Remove unnecessary cast from void pointer (jgarzik)
- - Re-align comments in private struct (jgarzik)
-
- Version LK1.04c (jgarzik):
- - Support bitmapped message levels (NETIF_MSG_xxx), and the
- two ethtool ioctls that get/set them
- - Don't hand-code MII ethtool support, use standard API/lib
-
- Version LK1.04d:
- - Merge from Donald Becker's sundance.c: (Jason Lunz)
- * proper support for variably-sized MTUs
- * default to PIO, to fix chip bugs
- - Add missing unregister_netdev (Jason Lunz)
- - Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
- - Better rx buf size calculation (Donald Becker)
-
- Version LK1.05 (D-Link):
- - Fix DFE-580TX packet drop issue (for DL10050C)
- - Fix reset_tx logic
-
- Version LK1.06 (D-Link):
- - Fix crash while unloading driver
-
- Versin LK1.06b (D-Link):
- - New tx scheme, adaptive tx_coalesce
-
- Version LK1.07 (D-Link):
- - Fix tx bugs in big-endian machines
- - Remove unused max_interrupt_work module parameter, the new
- NAPI-like rx scheme doesn't need it.
- - Remove redundancy get_stats() in intr_handler(), those
- I/O access could affect performance in ARM-based system
- - Add Linux software VLAN support
-
- Version LK1.08 (Philippe De Muyter phdm@macqel.be):
- - Fix bug of custom mac address
- (StationAddr register only accept word write)
-
- Version LK1.09 (D-Link):
- - Fix the flowctrl bug.
- - Set Pause bit in MII ANAR if flow control enabled.
-
- Version LK1.09a (ICPlus):
- - Add the delay time in reading the contents of EEPROM
-
- Version LK1.10 (Philippe De Muyter phdm@macqel.be):
- - Make 'unblock interface after Tx underrun' work
-
- Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com):
- - Add support for IC Plus Corporation IP100A chipset
*/
#define DRV_NAME "sundance"
-#define DRV_VERSION "1.01+LK1.11"
-#define DRV_RELDATE "14-Jun-2006"
+#define DRV_VERSION "1.1"
+#define DRV_RELDATE "27-Jun-2006"
/* The user-configurable values.
@@ -282,15 +204,15 @@ IVc. Errata
#define USE_IO_OPS 1
#endif
-static struct pci_device_id sundance_pci_tbl[] = {
- {0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
- {0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
- {0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
- {0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
- {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
- {0,}
+static const struct pci_device_id sundance_pci_tbl[] = {
+ { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
+ { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
+ { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
+ { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 },
+ { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+ { }
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -301,7 +223,7 @@ enum {
struct pci_id_info {
const char *name;
};
-static const struct pci_id_info pci_id_tbl[] = {
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
{"D-Link DFE-550TX FAST Ethernet Adapter"},
{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
{"D-Link DFE-580TX 4 port Server Adapter"},
@@ -309,7 +231,7 @@ static const struct pci_id_info pci_id_tbl[] = {
{"D-Link DL10050-based FAST Ethernet Adapter"},
{"Sundance Technology Alta"},
{"IC Plus Corporation IP100A FAST Ethernet Adapter"},
- {NULL,}, /* 0 terminated list. */
+ { } /* terminate list. */
};
/* This driver was written to use PCI memory space, however x86-oriented
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index b4c0d101a7d..7f414815cc6 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -224,24 +224,21 @@ static const struct pci_device_id w840_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
+enum {
+ netdev_res_size = 128, /* size of PCI BAR resource */
+};
+
struct pci_id_info {
const char *name;
- struct match_info {
- int pci, pci_mask, subsystem, subsystem_mask;
- int revision, revision_mask; /* Only 8 bits. */
- } id;
- int io_size; /* Needed for I/O region check or ioremap(). */
- int drv_flags; /* Driver use, intended as capability flags. */
+ int drv_flags; /* Driver use, intended as capability flags. */
};
-static struct pci_id_info pci_id_tbl[] = {
- {"Winbond W89c840", /* Sometime a Level-One switch card. */
- { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
- 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
- {"Winbond W89c840", { 0x08401050, 0xffffffff, },
- 128, CanHaveMII | HasBrokenTx},
- {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
- 128, CanHaveMII | HasBrokenTx},
- {NULL,}, /* 0 terminated list. */
+
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
+ { /* Sometime a Level-One switch card. */
+ "Winbond W89c840", CanHaveMII | HasBrokenTx | FDXOnNoMII},
+ { "Winbond W89c840", CanHaveMII | HasBrokenTx},
+ { "Compex RL100-ATX", CanHaveMII | HasBrokenTx},
+ { } /* terminate list. */
};
/* This driver was written to use PCI memory space, however some x86 systems
@@ -399,7 +396,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
#ifdef USE_IO_OPS
bar = 0;
#endif
- ioaddr = pci_iomap(pdev, bar, pci_id_tbl[chip_idx].io_size);
+ ioaddr = pci_iomap(pdev, bar, netdev_res_size);
if (!ioaddr)
goto err_out_free_res;
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index 091ebb7a62f..17ca7dc42e6 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -10,26 +10,11 @@
410 Severn Ave., Suite 210
Annapolis MD 21403
- -----------------------------------------------------------
-
- Linux kernel-specific changes:
-
- LK1.0 (Ion Badulescu)
- - Major cleanup
- - Use 2.4 PCI API
- - Support ethtool
- - Rewrite perfect filter/hash code
- - Use interrupts for media changes
-
- LK1.1 (Ion Badulescu)
- - Disallow negotiation of unsupported full-duplex modes
*/
#define DRV_NAME "xircom_tulip_cb"
-#define DRV_VERSION "0.91+LK1.1"
-#define DRV_RELDATE "October 11, 2001"
-
-#define CARDBUS 1
+#define DRV_VERSION "0.92"
+#define DRV_RELDATE "June 27, 2006"
/* A few user-configurable values. */
@@ -306,10 +291,10 @@ struct xircom_private {
struct xircom_tx_desc tx_ring[TX_RING_SIZE];
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
-#ifdef CARDBUS
+
/* The X3201-3 requires 4-byte aligned tx bufs */
struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
-#endif
+
/* The addresses of receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)]; /* Pseudo-Tx frame to init address table. */
@@ -908,10 +893,8 @@ static void xircom_init_ring(struct net_device *dev)
tp->tx_skbuff[i] = NULL;
tp->tx_ring[i].status = 0;
tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
-#ifdef CARDBUS
if (tp->chip_id == X3201_3)
tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
-#endif /* CARDBUS */
}
tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
}
@@ -931,12 +914,10 @@ xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->cur_tx % TX_RING_SIZE;
tp->tx_skbuff[entry] = skb;
-#ifdef CARDBUS
if (tp->chip_id == X3201_3) {
memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
} else
-#endif
tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 98b6f3207d3..d3d0ec97031 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -25,117 +25,13 @@
version. He may or may not be interested in bug reports on this
code. You can find his versions at:
http://www.scyld.com/network/via-rhine.html
-
-
- Linux kernel version history:
-
- LK1.1.0:
- - Jeff Garzik: softnet 'n stuff
-
- LK1.1.1:
- - Justin Guyett: softnet and locking fixes
- - Jeff Garzik: use PCI interface
-
- LK1.1.2:
- - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
-
- LK1.1.3:
- - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c
- code) update "Theory of Operation" with
- softnet/locking changes
- - Dave Miller: PCI DMA and endian fixups
- - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
-
- LK1.1.4:
- - Urban Widmark: fix gcc 2.95.2 problem and
- remove writel's to fixed address 0x7c
-
- LK1.1.5:
- - Urban Widmark: mdio locking, bounce buffer changes
- merges from Beckers 1.05 version
- added netif_running_on/off support
-
- LK1.1.6:
- - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio)
- set netif_running_on/off on startup, del_timer_sync
-
- LK1.1.7:
- - Manfred Spraul: added reset into tx_timeout
-
- LK1.1.9:
- - Urban Widmark: merges from Beckers 1.10 version
- (media selection + eeprom reload)
- - David Vrabel: merges from D-Link "1.11" version
- (disable WOL and PME on startup)
-
- LK1.1.10:
- - Manfred Spraul: use "singlecopy" for unaligned buffers
- don't allocate bounce buffers for !ReqTxAlign cards
-
- LK1.1.11:
- - David Woodhouse: Set dev->base_addr before the first time we call
- wait_for_reset(). It's a lot happier that way.
- Free np->tx_bufs only if we actually allocated it.
-
- LK1.1.12:
- - Martin Eriksson: Allow Memory-Mapped IO to be enabled.
-
- LK1.1.13 (jgarzik):
- - Add ethtool support
- - Replace some MII-related magic numbers with constants
-
- LK1.1.14 (Ivan G.):
- - fixes comments for Rhine-III
- - removes W_MAX_TIMEOUT (unused)
- - adds HasDavicomPhy for Rhine-I (basis: linuxfet driver; my card
- is R-I and has Davicom chip, flag is referenced in kernel driver)
- - sends chip_id as a parameter to wait_for_reset since np is not
- initialized on first call
- - changes mmio "else if (chip_id==VT6102)" to "else" so it will work
- for Rhine-III's (documentation says same bit is correct)
- - transmit frame queue message is off by one - fixed
- - adds IntrNormalSummary to "Something Wicked" exclusion list
- so normal interrupts will not trigger the message (src: Donald Becker)
- (Roger Luethi)
- - show confused chip where to continue after Tx error
- - location of collision counter is chip specific
- - allow selecting backoff algorithm (module parameter)
-
- LK1.1.15 (jgarzik):
- - Use new MII lib helper generic_mii_ioctl
-
- LK1.1.16 (Roger Luethi)
- - Etherleak fix
- - Handle Tx buffer underrun
- - Fix bugs in full duplex handling
- - New reset code uses "force reset" cmd on Rhine-II
- - Various clean ups
-
- LK1.1.17 (Roger Luethi)
- - Fix race in via_rhine_start_tx()
- - On errors, wait for Tx engine to turn off before scavenging
- - Handle Tx descriptor write-back race on Rhine-II
- - Force flushing for PCI posted writes
- - More reset code changes
-
- LK1.1.18 (Roger Luethi)
- - No filtering multicast in promisc mode (Edward Peng)
- - Fix for Rhine-I Tx timeouts
-
- LK1.1.19 (Roger Luethi)
- - Increase Tx threshold for unspecified errors
-
- LK1.2.0-2.6 (Roger Luethi)
- - Massive clean-up
- - Rewrite PHY, media handling (remove options, full_duplex, backoff)
- - Fix Tx engine race for good
- - Craig Brind: Zero padded aligned buffers for short packets.
+ [link no longer provides useful info -jgarzik]
*/
#define DRV_NAME "via-rhine"
-#define DRV_VERSION "1.2.0-2.6"
-#define DRV_RELDATE "June-10-2004"
+#define DRV_VERSION "1.4.0"
+#define DRV_RELDATE "June-27-2006"
/* A few user-configurable values.
@@ -356,12 +252,11 @@ enum rhine_quirks {
/* Beware of PCI posted writes */
#define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0)
-static struct pci_device_id rhine_pci_tbl[] =
-{
- {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT86C100A */
- {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6102 */
- {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* 6105{,L,LOM} */
- {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6105M */
+static const struct pci_device_id rhine_pci_tbl[] = {
+ { 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, }, /* VT86C100A */
+ { 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6102 */
+ { 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, }, /* 6105{,L,LOM} */
+ { 0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6105M */
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index ba2972ba375..f5b0078eb4a 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -229,7 +229,8 @@ static int rx_copybreak = 200;
module_param(rx_copybreak, int, 0644);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
+static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
+ const struct velocity_info_tbl *info);
static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
static void velocity_print_info(struct velocity_info *vptr);
static int velocity_open(struct net_device *dev);
@@ -294,9 +295,9 @@ static void velocity_unregister_notifier(void)
* Internal board variants. At the moment we have only one
*/
-static struct velocity_info_tbl chip_info_table[] = {
- {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL},
- {0, NULL}
+static const struct velocity_info_tbl chip_info_table[] __devinitdata = {
+ {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
+ { }
};
/*
@@ -304,10 +305,9 @@ static struct velocity_info_tbl chip_info_table[] = {
* device driver. Used for hotplug autoloading.
*/
-static struct pci_device_id velocity_id_table[] __devinitdata = {
- {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table},
- {0, }
+static const struct pci_device_id velocity_id_table[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
+ { }
};
MODULE_DEVICE_TABLE(pci, velocity_id_table);
@@ -341,7 +341,7 @@ static char __devinit *get_chip_name(enum chip_type chip_id)
static void __devexit velocity_remove1(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
#ifdef CONFIG_PM
unsigned long flags;
@@ -686,21 +686,23 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
static int first = 1;
struct net_device *dev;
int i;
- struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
+ const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
struct velocity_info *vptr;
struct mac_regs __iomem * regs;
int ret = -ENOMEM;
+ /* FIXME: this driver, like almost all other ethernet drivers,
+ * can support more than MAX_UNITS.
+ */
if (velocity_nics >= MAX_UNITS) {
- printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n",
- velocity_nics);
+ dev_notice(&pdev->dev, "already found %d NICs.\n",
+ velocity_nics);
return -ENODEV;
}
dev = alloc_etherdev(sizeof(struct velocity_info));
-
- if (dev == NULL) {
- printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n");
+ if (!dev) {
+ dev_err(&pdev->dev, "allocate net device failed.\n");
goto out;
}
@@ -708,7 +710,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- vptr = dev->priv;
+ vptr = netdev_priv(dev);
if (first) {
@@ -731,17 +733,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
ret = velocity_get_pci_info(vptr, pdev);
if (ret < 0) {
- printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+ /* error message already printed */
goto err_disable;
}
ret = pci_request_regions(pdev, VELOCITY_NAME);
if (ret < 0) {
- printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+ dev_err(&pdev->dev, "No PCI resources.\n");
goto err_disable;
}
- regs = ioremap(vptr->memaddr, vptr->io_size);
+ regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
if (regs == NULL) {
ret = -EIO;
goto err_release_res;
@@ -859,13 +861,14 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
* discovered.
*/
-static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+ struct velocity_info *vptr,
+ const struct velocity_info_tbl *info)
{
memset(vptr, 0, sizeof(struct velocity_info));
vptr->pdev = pdev;
vptr->chip_id = info->chip_id;
- vptr->io_size = info->io_size;
vptr->num_txq = info->txqueue;
vptr->multicast_limit = MCAM_SIZE;
spin_lock_init(&vptr->lock);
@@ -883,8 +886,7 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i
static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
{
-
- if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
+ if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
return -EIO;
pci_set_master(pdev);
@@ -892,24 +894,20 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
vptr->ioaddr = pci_resource_start(pdev, 0);
vptr->memaddr = pci_resource_start(pdev, 1);
- if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO))
- {
- printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n",
- pci_name(pdev));
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #0 is not an I/O resource, aborting.\n");
return -EINVAL;
}
- if((pci_resource_flags(pdev, 1) & IORESOURCE_IO))
- {
- printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n",
- pci_name(pdev));
+ if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #1 is an I/O resource, aborting.\n");
return -EINVAL;
}
- if(pci_resource_len(pdev, 1) < 256)
- {
- printk(KERN_ERR "%s: region #1 is too small.\n",
- pci_name(pdev));
+ if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+ dev_err(&pdev->dev, "region #1 is too small.\n");
return -EINVAL;
}
vptr->pdev = pdev;
@@ -1728,7 +1726,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
static int velocity_open(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int ret;
vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
@@ -1785,7 +1783,7 @@ err_free_desc_rings:
static int velocity_change_mtu(struct net_device *dev, int new_mtu)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
unsigned long flags;
int oldmtu = dev->mtu;
int ret = 0;
@@ -1861,7 +1859,7 @@ static void velocity_shutdown(struct velocity_info *vptr)
static int velocity_close(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
netif_stop_queue(dev);
velocity_shutdown(vptr);
@@ -1894,7 +1892,7 @@ static int velocity_close(struct net_device *dev)
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int qnum = 0;
struct tx_desc *td_ptr;
struct velocity_td_info *tdinfo;
@@ -2049,7 +2047,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = dev_instance;
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
u32 isr_status;
int max_count = 0;
@@ -2104,7 +2102,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
static void velocity_set_multi(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
u8 rx_mode;
int i;
@@ -2153,7 +2151,7 @@ static void velocity_set_multi(struct net_device *dev)
static struct net_device_stats *velocity_get_stats(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
/* If the hardware is down, don't touch MII */
if(!netif_running(dev))
@@ -2196,7 +2194,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int ret;
/* If we are asked for information and the device is power
@@ -2825,7 +2823,7 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
static int velocity_ethtool_up(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D0);
return 0;
@@ -2841,14 +2839,14 @@ static int velocity_ethtool_up(struct net_device *dev)
static void velocity_ethtool_down(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D3hot);
}
static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
u32 status;
status = check_connection_type(vptr->mac_regs);
@@ -2873,7 +2871,7 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
u32 curr_status;
u32 new_status = 0;
int ret = 0;
@@ -2896,14 +2894,14 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
static u32 velocity_get_link(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 0 : 1;
}
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
strcpy(info->driver, VELOCITY_NAME);
strcpy(info->version, VELOCITY_VERSION);
strcpy(info->bus_info, pci_name(vptr->pdev));
@@ -2911,7 +2909,7 @@ static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
wol->wolopts |= WAKE_MAGIC;
/*
@@ -2927,7 +2925,7 @@ static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_woli
static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
return -EFAULT;
@@ -2992,7 +2990,7 @@ static struct ethtool_ops velocity_ethtool_ops = {
static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
unsigned long flags;
struct mii_ioctl_data *miidata = if_mii(ifr);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index f1b2640ebdc..496c3d59744 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -31,6 +31,8 @@
#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
#define VELOCITY_VERSION "1.13"
+#define VELOCITY_IO_SIZE 256
+
#define PKT_BUF_SZ 1540
#define MAX_UNITS 8
@@ -1191,7 +1193,6 @@ enum chip_type {
struct velocity_info_tbl {
enum chip_type chip_id;
char *name;
- int io_size;
int txqueue;
u32 flags;
};
@@ -1751,7 +1752,6 @@ struct velocity_info {
struct mac_regs __iomem * mac_regs;
unsigned long memaddr;
unsigned long ioaddr;
- u32 io_size;
u8 rev_id;
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index b5328b0ff92..54b8e492ef9 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -134,18 +134,6 @@ config SEALEVEL_4021
The driver will be compiled as a module: the
module will be called sealevel.
-config SYNCLINK_SYNCPPP
- tristate "SyncLink HDLC/SYNCPPP support"
- depends on WAN
- help
- Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
-
- Normally the SyncLink WAN driver works with the main PPP driver
- <file:drivers/net/ppp_generic.c> and pppd program.
- HDLC/SYNCPPP support allows use of the Cisco HDLC/PPP driver
- <file:drivers/net/wan/syncppp.c>. The SyncLink WAN driver (in
- character devices) must also be enabled.
-
# Generic HDLC
config HDLC
tristate "Generic HDLC layer"
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 823c6d5ab90..316ca6869d5 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -28,7 +28,6 @@ obj-$(CONFIG_COSA) += syncppp.o cosa.o
obj-$(CONFIG_FARSYNC) += syncppp.o farsync.o
obj-$(CONFIG_DSCC4) += dscc4.o
obj-$(CONFIG_LANMEDIA) += syncppp.o
-obj-$(CONFIG_SYNCLINK_SYNCPPP) += syncppp.o
obj-$(CONFIG_X25_ASY) += x25_asy.o
obj-$(CONFIG_LANMEDIA) += lmc/
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 30ec235e693..fa9d2c4edc9 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -550,6 +550,7 @@ config USB_ZD1201
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/zd1211rw/Kconfig"
# yes, this works even when no drivers are selected
config NET_WIRELESS
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 512603de309..c613af17a15 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/
obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_BCM43XX) += bcm43xx/
+obj-$(CONFIG_ZD1211RW) += zd1211rw/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index d8f5600578b..e1c5a939bca 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1885,6 +1885,15 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
spin_lock(&bcm->irq_lock);
+ /* Only accept IRQs, if we are initialized properly.
+ * This avoids an RX race while initializing.
+ * We should probably not enable IRQs before we are initialized
+ * completely, but some careful work is needed to fix this. I think it
+ * is best to stay with this cheap workaround for now... .
+ */
+ if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
+ goto out;
+
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
/* irq not for us (shared irq) */
@@ -1906,19 +1915,11 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
bcm43xx_interrupt_ack(bcm, reason);
- /* Only accept IRQs, if we are initialized properly.
- * This avoids an RX race while initializing.
- * We should probably not enable IRQs before we are initialized
- * completely, but some careful work is needed to fix this. I think it
- * is best to stay with this cheap workaround for now... .
- */
- if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
- /* disable all IRQs. They are enabled again in the bottom half. */
- bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- /* save the reason code and call our bottom half. */
- bcm->irq_reason = reason;
- tasklet_schedule(&bcm->isr_tasklet);
- }
+ /* disable all IRQs. They are enabled again in the bottom half. */
+ bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ /* save the reason code and call our bottom half. */
+ bcm->irq_reason = reason;
+ tasklet_schedule(&bcm->isr_tasklet);
out:
mmiowb();
@@ -3698,6 +3699,10 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
secinfo->encrypt = sec->encrypt;
dprintk(", .encrypt = %d", sec->encrypt);
}
+ if (sec->flags & SEC_AUTH_MODE) {
+ secinfo->auth_mode = sec->auth_mode;
+ dprintk(", .auth_mode = %d\n", sec->auth_mode);
+ }
dprintk("\n");
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
!bcm->ieee->host_encrypt) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 30a202b258b..116493671f8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -112,30 +112,6 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
return bcm43xx_channel_to_freq_bg(channel);
}
-/* Lightweight function to check if a channel number is valid.
- * Note that this does _NOT_ check for geographical restrictions!
- */
-static inline
-int bcm43xx_is_valid_channel_a(u8 channel)
-{
- return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
- && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel_bg(u8 channel)
-{
- return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
- && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
- u8 channel)
-{
- if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
- return bcm43xx_is_valid_channel_a(channel);
- return bcm43xx_is_valid_channel_bg(channel);
-}
-
void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index af5c0bff169..bb9c484d7e1 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
u16 r8, tmp;
u16 freq;
+ if (!ieee80211_is_valid_channel(bcm->ieee, channel))
+ return -EINVAL;
if ((radio->manufact == 0x17F) &&
(radio->version == 0x2060) &&
(radio->revision == 1)) {
- if (channel > 200)
- return -EINVAL;
freq = channel2freq_a(channel);
r8 = bcm43xx_radio_read16(bcm, 0x0008);
@@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
TODO(); //TODO: TSSI2dbm workaround
bcm43xx_phy_xmitpower(bcm);//FIXME correct?
} else {
- if ((channel < 1) || (channel > 14))
- return -EINVAL;
-
if (synthetic_pu_workaround)
bcm43xx_synth_pu_workaround(bcm, channel);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index c35cb3a0777..5c36e29efff 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -119,7 +119,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
freq = data->freq.m;
}
- if (!bcm43xx_is_valid_channel(bcm, channel))
+ if (!ieee80211_is_valid_channel(bcm->ieee, channel))
goto out_unlock;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
//ieee80211softmac_disassoc(softmac, $REASON);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index d8ece28c079..6dbd855b364 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
u16 control = 0;
u16 wsec_rate = 0;
u16 encrypt_frame;
+ const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
+ const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
/* Now construct the TX header. */
memset(txhdr, 0, sizeof(*txhdr));
- bitrate = bcm->softmac->txrates.default_rate;
+ bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
+ is_multicast_ether_addr(wireless_header->addr1), is_mgt);
ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index 49860fa61c3..6dfa041be66 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -66,10 +66,12 @@ static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+ PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
PLXDEV(0x1385, 0x4100, "Netgear MA301"),
PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+ PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
new file mode 100644
index 00000000000..66ed55bc546
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -0,0 +1,19 @@
+config ZD1211RW
+ tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
+ depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
+ chip, present in many USB-wireless adapters.
+
+ Device firmware is required alongside this driver. You can download the
+ firmware distribution from http://zd1211.ath.cx/get-firmware
+
+config ZD1211RW_DEBUG
+ bool "ZyDAS ZD1211 debugging"
+ depends on ZD1211RW
+ ---help---
+ ZD1211 debugging messages. Choosing Y will result in additional debug
+ messages being saved to your kernel logs, which may help debug any
+ problems.
+
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
new file mode 100644
index 00000000000..500314fc74d
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_ZD1211RW) += zd1211rw.o
+
+zd1211rw-objs := zd_chip.o zd_ieee80211.o \
+ zd_mac.o zd_netdev.o \
+ zd_rf_al2230.o zd_rf_rf2959.o \
+ zd_rf.o zd_usb.o zd_util.o
+
+ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
new file mode 100644
index 00000000000..efc9c4bd826
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -0,0 +1,1615 @@
+/* zd_chip.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* This file implements all the hardware specific functions for the ZD1211
+ * and ZD1211B chips. Support for the ZD1211B was possible after Timothy
+ * Legge sent me a ZD1211B device. Thank you Tim. -- Uli
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+void zd_chip_init(struct zd_chip *chip,
+ struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ memset(chip, 0, sizeof(*chip));
+ mutex_init(&chip->mutex);
+ zd_usb_init(&chip->usb, netdev, intf);
+ zd_rf_init(&chip->rf);
+}
+
+void zd_chip_clear(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_clear(&chip->usb);
+ zd_rf_clear(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ mutex_destroy(&chip->mutex);
+ memset(chip, 0, sizeof(*chip));
+}
+
+static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%02x-%02x-%02x",
+ addr[0], addr[1], addr[2]);
+}
+
+/* Prints an identifier line, which will support debugging. */
+static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
+{
+ int i = 0;
+
+ i = scnprintf(buffer, size, "zd1211%s chip ",
+ chip->is_zd1211b ? "b" : "");
+ i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " ");
+ i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " ");
+ i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c", chip->pa_type,
+ chip->patch_cck_gain ? 'g' : '-',
+ chip->patch_cr157 ? '7' : '-',
+ chip->patch_6m_band_edge ? '6' : '-');
+ return i;
+}
+
+static void print_id(struct zd_chip *chip)
+{
+ char buffer[80];
+
+ scnprint_id(chip, buffer, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ dev_info(zd_chip_dev(chip), "%s\n", buffer);
+}
+
+/* Read a variable number of 32-bit values. Parameter count is not allowed to
+ * exceed USB_MAX_IOREAD32_COUNT.
+ */
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr,
+ unsigned int count)
+{
+ int r;
+ int i;
+ zd_addr_t *a16 = (zd_addr_t *)NULL;
+ u16 *v16;
+ unsigned int count16;
+
+ if (count > USB_MAX_IOREAD32_COUNT)
+ return -EINVAL;
+
+ /* Allocate a single memory block for values and addresses. */
+ count16 = 2*count;
+ a16 = (zd_addr_t *)kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
+ GFP_NOFS);
+ if (!a16) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error ENOMEM in allocation of a16\n");
+ r = -ENOMEM;
+ goto out;
+ }
+ v16 = (u16 *)(a16 + count16);
+
+ for (i = 0; i < count; i++) {
+ int j = 2*i;
+ /* We read the high word always first. */
+ a16[j] = zd_inc_word(addr[i]);
+ a16[j+1] = addr[i];
+ }
+
+ r = zd_ioread16v_locked(chip, v16, a16, count16);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error: zd_ioread16v_locked. Error number %d\n", r);
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ int j = 2*i;
+ values[i] = (v16[j] << 16) | v16[j+1];
+ }
+
+out:
+ kfree((void *)a16);
+ return r;
+}
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count)
+{
+ int i, j, r;
+ struct zd_ioreq16 *ioreqs16;
+ unsigned int count16;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+
+ if (count == 0)
+ return 0;
+ if (count > USB_MAX_IOWRITE32_COUNT)
+ return -EINVAL;
+
+ /* Allocate a single memory block for values and addresses. */
+ count16 = 2*count;
+ ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+ if (!ioreqs16) {
+ r = -ENOMEM;
+ dev_dbg_f(zd_chip_dev(chip),
+ "error %d in ioreqs16 allocation\n", r);
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ j = 2*i;
+ /* We write the high word always first. */
+ ioreqs16[j].value = ioreqs[i].value >> 16;
+ ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr);
+ ioreqs16[j+1].value = ioreqs[i].value;
+ ioreqs16[j+1].addr = ioreqs[i].addr;
+ }
+
+ r = zd_usb_iowrite16v(&chip->usb, ioreqs16, count16);
+#ifdef DEBUG
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error %d in zd_usb_write16v\n", r);
+ }
+#endif /* DEBUG */
+out:
+ kfree(ioreqs16);
+ return r;
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+ const struct zd_ioreq16 *ioreqs, unsigned int count)
+{
+ int r;
+ unsigned int i, j, t, max;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ for (i = 0; i < count; i += j + t) {
+ t = 0;
+ max = count-i;
+ if (max > USB_MAX_IOWRITE16_COUNT)
+ max = USB_MAX_IOWRITE16_COUNT;
+ for (j = 0; j < max; j++) {
+ if (!ioreqs[i+j].addr) {
+ t = 1;
+ break;
+ }
+ }
+
+ r = zd_usb_iowrite16v(&chip->usb, &ioreqs[i], j);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error zd_usb_iowrite16v. Error number %d\n",
+ r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+/* Writes a variable number of 32 bit registers. The functions will split
+ * that in several USB requests. A split can be forced by inserting an IO
+ * request with an zero address field.
+ */
+int zd_iowrite32a_locked(struct zd_chip *chip,
+ const struct zd_ioreq32 *ioreqs, unsigned int count)
+{
+ int r;
+ unsigned int i, j, t, max;
+
+ for (i = 0; i < count; i += j + t) {
+ t = 0;
+ max = count-i;
+ if (max > USB_MAX_IOWRITE32_COUNT)
+ max = USB_MAX_IOWRITE32_COUNT;
+ for (j = 0; j < max; j++) {
+ if (!ioreqs[i+j].addr) {
+ t = 1;
+ break;
+ }
+ }
+
+ r = _zd_iowrite32v_locked(chip, &ioreqs[i], j);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error _zd_iowrite32v_locked."
+ " Error number %d\n", r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+ u32 *values, unsigned int count)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32v_locked(chip, values, addresses, count);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32a_locked(chip, ioreqs, count);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int read_pod(struct zd_chip *chip, u8 *rf_type)
+{
+ int r;
+ u32 value;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &value, E2P_POD);
+ if (r)
+ goto error;
+ dev_dbg_f(zd_chip_dev(chip), "E2P_POD %#010x\n", value);
+
+ /* FIXME: AL2230 handling (Bit 7 in POD) */
+ *rf_type = value & 0x0f;
+ chip->pa_type = (value >> 16) & 0x0f;
+ chip->patch_cck_gain = (value >> 8) & 0x1;
+ chip->patch_cr157 = (value >> 13) & 0x1;
+ chip->patch_6m_band_edge = (value >> 21) & 0x1;
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
+ "patch 6M %d\n",
+ zd_rf_name(*rf_type), *rf_type,
+ chip->pa_type, chip->patch_cck_gain,
+ chip->patch_cr157, chip->patch_6m_band_edge);
+ return 0;
+error:
+ *rf_type = 0;
+ chip->pa_type = 0;
+ chip->patch_cck_gain = 0;
+ chip->patch_cr157 = 0;
+ chip->patch_6m_band_edge = 0;
+ return r;
+}
+
+static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr,
+ const zd_addr_t *addr)
+{
+ int r;
+ u32 parts[2];
+
+ r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error: couldn't read e2p macs. Error number %d\n", r);
+ return r;
+ }
+
+ mac_addr[0] = parts[0];
+ mac_addr[1] = parts[0] >> 8;
+ mac_addr[2] = parts[0] >> 16;
+ mac_addr[3] = parts[0] >> 24;
+ mac_addr[4] = parts[1];
+ mac_addr[5] = parts[1] >> 8;
+
+ return 0;
+}
+
+static int read_e2p_mac_addr(struct zd_chip *chip)
+{
+ static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 };
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr);
+}
+
+/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and
+ * CR_MAC_ADDR_P2 must be overwritten
+ */
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ mutex_lock(&chip->mutex);
+ memcpy(mac_addr, chip->e2p_mac, ETH_ALEN);
+ mutex_unlock(&chip->mutex);
+}
+
+static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 };
+ return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr);
+}
+
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ mutex_lock(&chip->mutex);
+ r = read_mac_addr(chip, mac_addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
+{
+ int r;
+ struct zd_ioreq32 reqs[2] = {
+ [0] = { .addr = CR_MAC_ADDR_P1 },
+ [1] = { .addr = CR_MAC_ADDR_P2 },
+ };
+
+ reqs[0].value = (mac_addr[3] << 24)
+ | (mac_addr[2] << 16)
+ | (mac_addr[1] << 8)
+ | mac_addr[0];
+ reqs[1].value = (mac_addr[5] << 8)
+ | mac_addr[4];
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr));
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+#ifdef DEBUG
+ {
+ u8 tmp[ETH_ALEN];
+ read_mac_addr(chip, tmp);
+ }
+#endif /* DEBUG */
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain)
+{
+ int r;
+ u32 value;
+
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32_locked(chip, &value, E2P_SUBID);
+ mutex_unlock(&chip->mutex);
+ if (r)
+ return r;
+
+ *regdomain = value >> 16;
+ dev_dbg_f(zd_chip_dev(chip), "regdomain: %#04x\n", *regdomain);
+
+ return 0;
+}
+
+static int read_values(struct zd_chip *chip, u8 *values, size_t count,
+ zd_addr_t e2p_addr, u32 guard)
+{
+ int r;
+ int i;
+ u32 v;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ for (i = 0;;) {
+ r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+ if (r)
+ return r;
+ v -= guard;
+ if (i+4 < count) {
+ values[i++] = v;
+ values[i++] = v >> 8;
+ values[i++] = v >> 16;
+ values[i++] = v >> 24;
+ continue;
+ }
+ for (;i < count; i++)
+ values[i] = v >> (8*(i%3));
+ return 0;
+ }
+}
+
+static int read_pwr_cal_values(struct zd_chip *chip)
+{
+ return read_values(chip, chip->pwr_cal_values,
+ E2P_CHANNEL_COUNT, E2P_PWR_CAL_VALUE1,
+ 0);
+}
+
+static int read_pwr_int_values(struct zd_chip *chip)
+{
+ return read_values(chip, chip->pwr_int_values,
+ E2P_CHANNEL_COUNT, E2P_PWR_INT_VALUE1,
+ E2P_PWR_INT_GUARD);
+}
+
+static int read_ofdm_cal_values(struct zd_chip *chip)
+{
+ int r;
+ int i;
+ static const zd_addr_t addresses[] = {
+ E2P_36M_CAL_VALUE1,
+ E2P_48M_CAL_VALUE1,
+ E2P_54M_CAL_VALUE1,
+ };
+
+ for (i = 0; i < 3; i++) {
+ r = read_values(chip, chip->ofdm_cal_values[i],
+ E2P_CHANNEL_COUNT, addresses[i], 0);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static int read_cal_int_tables(struct zd_chip *chip)
+{
+ int r;
+
+ r = read_pwr_cal_values(chip);
+ if (r)
+ return r;
+ r = read_pwr_int_values(chip);
+ if (r)
+ return r;
+ r = read_ofdm_cal_values(chip);
+ if (r)
+ return r;
+ return 0;
+}
+
+/* phy means physical registers */
+int zd_chip_lock_phy_regs(struct zd_chip *chip)
+{
+ int r;
+ u32 tmp;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+ if (r) {
+ dev_err(zd_chip_dev(chip), "error ioread32(CR_REG1): %d\n", r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS);
+ tmp &= ~UNLOCK_PHY_REGS;
+
+ r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+ if (r)
+ dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+ return r;
+}
+
+int zd_chip_unlock_phy_regs(struct zd_chip *chip)
+{
+ int r;
+ u32 tmp;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+ if (r) {
+ dev_err(zd_chip_dev(chip),
+ "error ioread32(CR_REG1): %d\n", r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS);
+ tmp |= UNLOCK_PHY_REGS;
+
+ r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+ if (r)
+ dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+ return r;
+}
+
+/* CR157 can be optionally patched by the EEPROM */
+static int patch_cr157(struct zd_chip *chip)
+{
+ int r;
+ u32 value;
+
+ if (!chip->patch_cr157)
+ return 0;
+
+ r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+ if (r)
+ return r;
+
+ dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8);
+ return zd_iowrite32_locked(chip, value >> 8, CR157);
+}
+
+/*
+ * 6M band edge can be optionally overwritten for certain RF's
+ * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
+ * bit (for AL2230, AL2230S)
+ */
+static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+{
+ struct zd_ioreq16 ioreqs[] = {
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR47, 0x1e },
+ };
+
+ if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
+ return 0;
+
+ /* FIXME: Channel 11 is not the edge for all regulatory domains. */
+ if (channel == 1 || channel == 11)
+ ioreqs[0].value = 0x12;
+
+ dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211_hw_reset_phy(struct zd_chip *chip)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 },
+ { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 },
+ { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f },
+ { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d },
+ { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a },
+ { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c },
+ { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 },
+ { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 },
+ { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b },
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
+ { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
+ { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff },
+ { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
+ { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
+ { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
+ { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
+ { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
+ { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
+ { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 },
+ { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 },
+ { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 },
+ { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 },
+ { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 },
+ { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff },
+ { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 },
+ { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 },
+ { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 },
+ { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a },
+ { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 },
+ { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e },
+ { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+ { },
+ { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 },
+ { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 },
+ { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 },
+ { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 },
+ { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C },
+ { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 },
+ { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 },
+ { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 },
+ { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 },
+ { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+ { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 },
+ { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+ { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+ { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
+ { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
+ { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
+ { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
+ { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
+ { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
+ { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
+ { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
+ { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
+ { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+ /* Note: CR204 must lead the CR203 */
+ { CR204, 0x7d },
+ { },
+ { CR203, 0x30 },
+ };
+
+ int r, t;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ goto unlock;
+
+ r = patch_cr157(chip);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ return r;
+}
+
+static int zd1211b_hw_reset_phy(struct zd_chip *chip)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 },
+ { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 },
+ { CR10, 0x81 },
+ /* power control { { CR11, 1 << 6 }, */
+ { CR11, 0x00 },
+ { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 },
+ { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e },
+ { CR18, 0x0a }, { CR19, 0x48 },
+ { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
+ { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 },
+ { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 },
+ { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 },
+ { CR30, 0x49 }, /* jointly decoder, no ASIC */
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
+ { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
+ { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff },
+ { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
+ { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
+ { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
+ { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
+ { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
+ { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
+ { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 },
+ { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
+ { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 },
+ { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 },
+ { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 },
+ { CR94, 0x01 },
+ { CR95, 0x20 }, /* ZD1211B */
+ { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 },
+ { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 },
+ { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+ { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 },
+ { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 },
+ { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+ { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+ { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e },
+ { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 },
+ { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 },
+ { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c },
+ { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 },
+ { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
+ { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
+ { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe },
+ { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+ { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+ { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+ { CR170, 0xba }, { CR171, 0xba },
+ /* Note: CR204 must lead the CR203 */
+ { CR204, 0x7d },
+ {},
+ { CR203, 0x30 },
+ };
+
+ int r, t;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ goto unlock;
+
+ r = patch_cr157(chip);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ return r;
+}
+
+static int hw_reset_phy(struct zd_chip *chip)
+{
+ return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) :
+ zd1211_hw_reset_phy(chip);
+}
+
+static int zd1211_hw_init_hmac(struct zd_chip *chip)
+{
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
+ { CR_ZD1211_RETRY_MAX, 0x2 },
+ { CR_SNIFFER_ON, 0 },
+ { CR_RX_FILTER, AP_RX_FILTER },
+ { CR_GROUP_HASH_P1, 0x00 },
+ { CR_GROUP_HASH_P2, 0x80000000 },
+ { CR_REG1, 0xa4 },
+ { CR_ADDA_PWR_DWN, 0x7f },
+ { CR_BCN_PLCP_CFG, 0x00f00401 },
+ { CR_PHY_DELAY, 0x00 },
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+ { CR_IFS_VALUE, 0x547c032 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+ { CR_RX_THRESHOLD, 0x000c0640 },
+ { CR_AFTER_PNP, 0x1 },
+ { CR_WEP_PROTECT, 0x114 },
+ };
+
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+#ifdef DEBUG
+ if (r) {
+ dev_err(zd_chip_dev(chip),
+ "error in zd_iowrite32a_locked. Error number %d\n", r);
+ }
+#endif /* DEBUG */
+ return r;
+}
+
+static int zd1211b_hw_init_hmac(struct zd_chip *chip)
+{
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
+ { CR_ZD1211B_RETRY_MAX, 0x02020202 },
+ { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f },
+ { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f },
+ { CR_ZD1211B_TX_PWR_CTL2, 0x003f001f },
+ { CR_ZD1211B_TX_PWR_CTL1, 0x001f000f },
+ { CR_ZD1211B_AIFS_CTL1, 0x00280028 },
+ { CR_ZD1211B_AIFS_CTL2, 0x008C003C },
+ { CR_ZD1211B_TXOP, 0x01800824 },
+ { CR_SNIFFER_ON, 0 },
+ { CR_RX_FILTER, AP_RX_FILTER },
+ { CR_GROUP_HASH_P1, 0x00 },
+ { CR_GROUP_HASH_P2, 0x80000000 },
+ { CR_REG1, 0xa4 },
+ { CR_ADDA_PWR_DWN, 0x7f },
+ { CR_BCN_PLCP_CFG, 0x00f00401 },
+ { CR_PHY_DELAY, 0x00 },
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+ { CR_IFS_VALUE, 0x547c032 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+ { CR_RX_THRESHOLD, 0x000c0640 },
+ { CR_AFTER_PNP, 0x1 },
+ { CR_WEP_PROTECT, 0x114 },
+ };
+
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error in zd_iowrite32a_locked. Error number %d\n", r);
+ }
+ return r;
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+ return chip->is_zd1211b ?
+ zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
+}
+
+struct aw_pt_bi {
+ u32 atim_wnd_period;
+ u32 pre_tbtt;
+ u32 beacon_interval;
+};
+
+static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+ int r;
+ static const zd_addr_t aw_pt_bi_addr[] =
+ { CR_ATIM_WND_PERIOD, CR_PRE_TBTT, CR_BCN_INTERVAL };
+ u32 values[3];
+
+ r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr,
+ ARRAY_SIZE(aw_pt_bi_addr));
+ if (r) {
+ memset(s, 0, sizeof(*s));
+ return r;
+ }
+
+ s->atim_wnd_period = values[0];
+ s->pre_tbtt = values[1];
+ s->beacon_interval = values[2];
+ dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n",
+ s->atim_wnd_period, s->pre_tbtt, s->beacon_interval);
+ return 0;
+}
+
+static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+ struct zd_ioreq32 reqs[3];
+
+ if (s->beacon_interval <= 5)
+ s->beacon_interval = 5;
+ if (s->pre_tbtt < 4 || s->pre_tbtt >= s->beacon_interval)
+ s->pre_tbtt = s->beacon_interval - 1;
+ if (s->atim_wnd_period >= s->pre_tbtt)
+ s->atim_wnd_period = s->pre_tbtt - 1;
+
+ reqs[0].addr = CR_ATIM_WND_PERIOD;
+ reqs[0].value = s->atim_wnd_period;
+ reqs[1].addr = CR_PRE_TBTT;
+ reqs[1].value = s->pre_tbtt;
+ reqs[2].addr = CR_BCN_INTERVAL;
+ reqs[2].value = s->beacon_interval;
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt,
+ s->beacon_interval);
+ return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+}
+
+
+static int set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+ int r;
+ struct aw_pt_bi s;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = get_aw_pt_bi(chip, &s);
+ if (r)
+ return r;
+ s.beacon_interval = interval;
+ return set_aw_pt_bi(chip, &s);
+}
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = set_beacon_interval(chip, interval);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int hw_init(struct zd_chip *chip)
+{
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = hw_reset_phy(chip);
+ if (r)
+ return r;
+
+ r = hw_init_hmac(chip);
+ if (r)
+ return r;
+ r = set_beacon_interval(chip, 100);
+ if (r)
+ return r;
+ return 0;
+}
+
+#ifdef DEBUG
+static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
+ const char *addr_string)
+{
+ int r;
+ u32 value;
+
+ r = zd_ioread32_locked(chip, &value, addr);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error reading %s. Error number %d\n", addr_string, r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "%s %#010x\n",
+ addr_string, (unsigned int)value);
+ return 0;
+}
+
+static int test_init(struct zd_chip *chip)
+{
+ int r;
+
+ r = dump_cr(chip, CR_AFTER_PNP, "CR_AFTER_PNP");
+ if (r)
+ return r;
+ r = dump_cr(chip, CR_GPI_EN, "CR_GPI_EN");
+ if (r)
+ return r;
+ return dump_cr(chip, CR_INTERRUPT, "CR_INTERRUPT");
+}
+
+static void dump_fw_registers(struct zd_chip *chip)
+{
+ static const zd_addr_t addr[4] = {
+ FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
+ FW_LINK_STATUS
+ };
+
+ int r;
+ u16 values[4];
+
+ r = zd_ioread16v_locked(chip, values, (const zd_addr_t*)addr,
+ ARRAY_SIZE(addr));
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip), "error %d zd_ioread16v_locked\n",
+ r);
+ return;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "FW_FIRMWARE_VER %#06hx\n", values[0]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_USB_SPEED %#06hx\n", values[1]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_FIX_TX_RATE %#06hx\n", values[2]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_LINK_STATUS %#06hx\n", values[3]);
+}
+#endif /* DEBUG */
+
+static int print_fw_version(struct zd_chip *chip)
+{
+ int r;
+ u16 version;
+
+ r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+ if (r)
+ return r;
+
+ dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version);
+ return 0;
+}
+
+static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
+{
+ u32 rates;
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ /* This sets the mandatory rates, which only depend from the standard
+ * that the device is supporting. Until further notice we should try
+ * to support 802.11g also for full speed USB.
+ */
+ switch (std) {
+ case IEEE80211B:
+ rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
+ break;
+ case IEEE80211G:
+ rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
+ CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL);
+}
+
+int zd_chip_enable_hwint(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, HWINT_ENABLED, CR_INTERRUPT);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int disable_hwint(struct zd_chip *chip)
+{
+ return zd_iowrite32_locked(chip, HWINT_DISABLED, CR_INTERRUPT);
+}
+
+int zd_chip_disable_hwint(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = disable_hwint(chip);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
+{
+ int r;
+ u8 rf_type;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ mutex_lock(&chip->mutex);
+ chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0;
+
+#ifdef DEBUG
+ r = test_init(chip);
+ if (r)
+ goto out;
+#endif
+ r = zd_iowrite32_locked(chip, 1, CR_AFTER_PNP);
+ if (r)
+ goto out;
+
+ r = zd_usb_init_hw(&chip->usb);
+ if (r)
+ goto out;
+
+ /* GPI is always disabled, also in the other driver.
+ */
+ r = zd_iowrite32_locked(chip, 0, CR_GPI_EN);
+ if (r)
+ goto out;
+ r = zd_iowrite32_locked(chip, CWIN_SIZE, CR_CWMIN_CWMAX);
+ if (r)
+ goto out;
+ /* Currently we support IEEE 802.11g for full and high speed USB.
+ * It might be discussed, whether we should suppport pure b mode for
+ * full speed USB.
+ */
+ r = set_mandatory_rates(chip, IEEE80211G);
+ if (r)
+ goto out;
+ /* Disabling interrupts is certainly a smart thing here.
+ */
+ r = disable_hwint(chip);
+ if (r)
+ goto out;
+ r = read_pod(chip, &rf_type);
+ if (r)
+ goto out;
+ r = hw_init(chip);
+ if (r)
+ goto out;
+ r = zd_rf_init_hw(&chip->rf, rf_type);
+ if (r)
+ goto out;
+
+ r = print_fw_version(chip);
+ if (r)
+ goto out;
+
+#ifdef DEBUG
+ dump_fw_registers(chip);
+ r = test_init(chip);
+ if (r)
+ goto out;
+#endif /* DEBUG */
+
+ r = read_e2p_mac_addr(chip);
+ if (r)
+ goto out;
+
+ r = read_cal_int_tables(chip);
+ if (r)
+ goto out;
+
+ print_id(chip);
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int update_pwr_int(struct zd_chip *chip, u8 channel)
+{
+ u8 value = chip->pwr_int_values[channel - 1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
+ channel, value);
+ return zd_iowrite32_locked(chip, value, CR31);
+}
+
+static int update_pwr_cal(struct zd_chip *chip, u8 channel)
+{
+ u8 value = chip->pwr_cal_values[channel-1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
+ channel, value);
+ return zd_iowrite32_locked(chip, value, CR68);
+}
+
+static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
+{
+ struct zd_ioreq32 ioreqs[3];
+
+ ioreqs[0].addr = CR67;
+ ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
+ ioreqs[1].addr = CR66;
+ ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1];
+ ioreqs[2].addr = CR65;
+ ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
+ channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int update_channel_integration_and_calibration(struct zd_chip *chip,
+ u8 channel)
+{
+ int r;
+
+ r = update_pwr_int(chip, channel);
+ if (r)
+ return r;
+ if (chip->is_zd1211b) {
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR69, 0x28 },
+ {},
+ { CR69, 0x2a },
+ };
+
+ r = update_ofdm_cal(chip, channel);
+ if (r)
+ return r;
+ r = update_pwr_cal(chip, channel);
+ if (r)
+ return r;
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+/* The CCK baseband gain can be optionally patched by the EEPROM */
+static int patch_cck_gain(struct zd_chip *chip)
+{
+ int r;
+ u32 value;
+
+ if (!chip->patch_cck_gain)
+ return 0;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+ if (r)
+ return r;
+ dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
+ return zd_iowrite32_locked(chip, value & 0xff, CR47);
+}
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
+{
+ int r, t;
+
+ mutex_lock(&chip->mutex);
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+ r = zd_rf_set_channel(&chip->rf, channel);
+ if (r)
+ goto unlock;
+ r = update_channel_integration_and_calibration(chip, channel);
+ if (r)
+ goto unlock;
+ r = patch_cck_gain(chip);
+ if (r)
+ goto unlock;
+ r = patch_6m_band_edge(chip, channel);
+ if (r)
+ goto unlock;
+ r = zd_iowrite32_locked(chip, 0, CR_CONFIG_PHILIPS);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+u8 zd_chip_get_channel(struct zd_chip *chip)
+{
+ u8 channel;
+
+ mutex_lock(&chip->mutex);
+ channel = chip->rf.channel;
+ mutex_unlock(&chip->mutex);
+ return channel;
+}
+
+static u16 led_mask(int led)
+{
+ switch (led) {
+ case 1:
+ return LED1;
+ case 2:
+ return LED2;
+ default:
+ return 0;
+ }
+}
+
+static int read_led_reg(struct zd_chip *chip, u16 *status)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_ioread16_locked(chip, status, CR_LED);
+}
+
+static int write_led_reg(struct zd_chip *chip, u16 status)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_iowrite16_locked(chip, status, CR_LED);
+}
+
+int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status)
+{
+ int r, ret;
+ u16 mask = led_mask(led);
+ u16 reg;
+
+ if (!mask)
+ return -EINVAL;
+ mutex_lock(&chip->mutex);
+ r = read_led_reg(chip, &reg);
+ if (r)
+ return r;
+ switch (status) {
+ case LED_STATUS:
+ return (reg & mask) ? LED_ON : LED_OFF;
+ case LED_OFF:
+ reg &= ~mask;
+ ret = LED_OFF;
+ break;
+ case LED_FLIP:
+ reg ^= mask;
+ ret = (reg&mask) ? LED_ON : LED_OFF;
+ break;
+ case LED_ON:
+ reg |= mask;
+ ret = LED_ON;
+ break;
+ default:
+ return -EINVAL;
+ }
+ r = write_led_reg(chip, reg);
+ if (r) {
+ ret = r;
+ goto out;
+ }
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_led_flip(struct zd_chip *chip, int led,
+ const unsigned int *phases_msecs, unsigned int count)
+{
+ int i, r;
+ enum led_status status;
+
+ r = zd_chip_led_status(chip, led, LED_STATUS);
+ if (r)
+ return r;
+ status = r;
+ for (i = 0; i < count; i++) {
+ r = zd_chip_led_status(chip, led, LED_FLIP);
+ if (r < 0)
+ goto out;
+ msleep(phases_msecs[i]);
+ }
+
+out:
+ zd_chip_led_status(chip, led, status);
+ return r;
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
+{
+ int r;
+
+ if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+{
+ static const u16 constants[] = {
+ 715, 655, 585, 540, 470, 410, 360, 315,
+ 270, 235, 205, 175, 150, 125, 105, 85,
+ 65, 50, 40, 25, 15
+ };
+
+ int i;
+ u32 x;
+
+ /* It seems that their quality parameter is somehow per signal
+ * and is now transferred per bit.
+ */
+ switch (rate) {
+ case ZD_OFDM_RATE_6M:
+ case ZD_OFDM_RATE_12M:
+ case ZD_OFDM_RATE_24M:
+ size *= 2;
+ break;
+ case ZD_OFDM_RATE_9M:
+ case ZD_OFDM_RATE_18M:
+ case ZD_OFDM_RATE_36M:
+ case ZD_OFDM_RATE_54M:
+ size *= 4;
+ size /= 3;
+ break;
+ case ZD_OFDM_RATE_48M:
+ size *= 3;
+ size /= 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ x = (10000 * status_quality)/size;
+ for (i = 0; i < ARRAY_SIZE(constants); i++) {
+ if (x > constants[i])
+ break;
+ }
+
+ return i;
+}
+
+static unsigned int log10times100(unsigned int x)
+{
+ static const u8 log10[] = {
+ 0,
+ 0, 30, 47, 60, 69, 77, 84, 90, 95, 100,
+ 104, 107, 111, 114, 117, 120, 123, 125, 127, 130,
+ 132, 134, 136, 138, 139, 141, 143, 144, 146, 147,
+ 149, 150, 151, 153, 154, 155, 156, 157, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 168, 169, 169,
+ 170, 171, 172, 173, 174, 174, 175, 176, 177, 177,
+ 178, 179, 179, 180, 181, 181, 182, 183, 183, 184,
+ 185, 185, 186, 186, 187, 188, 188, 189, 189, 190,
+ 190, 191, 191, 192, 192, 193, 193, 194, 194, 195,
+ 195, 196, 196, 197, 197, 198, 198, 199, 199, 200,
+ 200, 200, 201, 201, 202, 202, 202, 203, 203, 204,
+ 204, 204, 205, 205, 206, 206, 206, 207, 207, 207,
+ 208, 208, 208, 209, 209, 210, 210, 210, 211, 211,
+ 211, 212, 212, 212, 213, 213, 213, 213, 214, 214,
+ 214, 215, 215, 215, 216, 216, 216, 217, 217, 217,
+ 217, 218, 218, 218, 219, 219, 219, 219, 220, 220,
+ 220, 220, 221, 221, 221, 222, 222, 222, 222, 223,
+ 223, 223, 223, 224, 224, 224, 224,
+ };
+
+ return x < ARRAY_SIZE(log10) ? log10[x] : 225;
+}
+
+enum {
+ MAX_CCK_EVM_DB = 45,
+};
+
+static int cck_evm_db(u8 status_quality)
+{
+ return (20 * log10times100(status_quality)) / 100;
+}
+
+static int cck_snr_db(u8 status_quality)
+{
+ int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality);
+ ZD_ASSERT(r >= 0);
+ return r;
+}
+
+static int rx_qual_db(const void *rx_frame, unsigned int size,
+ const struct rx_status *status)
+{
+ return (status->frame_status&ZD_RX_OFDM) ?
+ ofdm_qual_db(status->signal_quality_ofdm,
+ zd_ofdm_plcp_header_rate(rx_frame),
+ size) :
+ cck_snr_db(status->signal_quality_cck);
+}
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+ const struct rx_status *status)
+{
+ int r = rx_qual_db(rx_frame, size, status);
+ if (r < 0)
+ r = 0;
+ r = (r * 100) / 14;
+ if (r > 100)
+ r = 100;
+ return r;
+}
+
+u8 zd_rx_strength_percent(u8 rssi)
+{
+ int r = (rssi*100) / 30;
+ if (r > 100)
+ r = 100;
+ return (u8) r;
+}
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
+{
+ static const u16 ofdm_rates[] = {
+ [ZD_OFDM_RATE_6M] = 60,
+ [ZD_OFDM_RATE_9M] = 90,
+ [ZD_OFDM_RATE_12M] = 120,
+ [ZD_OFDM_RATE_18M] = 180,
+ [ZD_OFDM_RATE_24M] = 240,
+ [ZD_OFDM_RATE_36M] = 360,
+ [ZD_OFDM_RATE_48M] = 480,
+ [ZD_OFDM_RATE_54M] = 540,
+ };
+ u16 rate;
+ if (status->frame_status & ZD_RX_OFDM) {
+ u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
+ rate = ofdm_rates[ofdm_rate & 0xf];
+ } else {
+ u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
+ switch (cck_rate) {
+ case ZD_CCK_SIGNAL_1M:
+ rate = 10;
+ break;
+ case ZD_CCK_SIGNAL_2M:
+ rate = 20;
+ break;
+ case ZD_CCK_SIGNAL_5M5:
+ rate = 55;
+ break;
+ case ZD_CCK_SIGNAL_11M:
+ rate = 110;
+ break;
+ default:
+ rate = 0;
+ }
+ }
+
+ return rate;
+}
+
+int zd_chip_switch_radio_on(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_switch_radio_on(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_switch_radio_off(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_switch_radio_off(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_enable_int(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_usb_enable_int(&chip->usb);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+void zd_chip_disable_int(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_disable_int(&chip->usb);
+ mutex_unlock(&chip->mutex);
+}
+
+int zd_chip_enable_rx(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_usb_enable_rx(&chip->usb);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+void zd_chip_disable_rx(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_disable_rx(&chip->usb);
+ mutex_unlock(&chip->mutex);
+}
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count, u8 bits)
+{
+ int r;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ r = zd_rfwrite_locked(chip, values[i], bits);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
new file mode 100644
index 00000000000..805121093ab
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -0,0 +1,825 @@
+/* zd_chip.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_CHIP_H
+#define _ZD_CHIP_H
+
+#include "zd_types.h"
+#include "zd_rf.h"
+#include "zd_usb.h"
+
+/* Header for the Media Access Controller (MAC) and the Baseband Processor
+ * (BBP). It appears that the ZD1211 wraps the old ZD1205 with USB glue and
+ * adds a processor for handling the USB protocol.
+ */
+
+/* 8-bit hardware registers */
+#define CR0 CTL_REG(0x0000)
+#define CR1 CTL_REG(0x0004)
+#define CR2 CTL_REG(0x0008)
+#define CR3 CTL_REG(0x000C)
+
+#define CR5 CTL_REG(0x0010)
+/* bit 5: if set short preamble used
+ * bit 6: filter band - Japan channel 14 on, else off
+ */
+#define CR6 CTL_REG(0x0014)
+#define CR7 CTL_REG(0x0018)
+#define CR8 CTL_REG(0x001C)
+
+#define CR4 CTL_REG(0x0020)
+
+#define CR9 CTL_REG(0x0024)
+/* bit 2: antenna switch (together with CR10) */
+#define CR10 CTL_REG(0x0028)
+/* bit 1: antenna switch (together with CR9)
+ * RF2959 controls with CR11 radion on and off
+ */
+#define CR11 CTL_REG(0x002C)
+/* bit 6: TX power control for OFDM
+ * RF2959 controls with CR10 radio on and off
+ */
+#define CR12 CTL_REG(0x0030)
+#define CR13 CTL_REG(0x0034)
+#define CR14 CTL_REG(0x0038)
+#define CR15 CTL_REG(0x003C)
+#define CR16 CTL_REG(0x0040)
+#define CR17 CTL_REG(0x0044)
+#define CR18 CTL_REG(0x0048)
+#define CR19 CTL_REG(0x004C)
+#define CR20 CTL_REG(0x0050)
+#define CR21 CTL_REG(0x0054)
+#define CR22 CTL_REG(0x0058)
+#define CR23 CTL_REG(0x005C)
+#define CR24 CTL_REG(0x0060) /* CCA threshold */
+#define CR25 CTL_REG(0x0064)
+#define CR26 CTL_REG(0x0068)
+#define CR27 CTL_REG(0x006C)
+#define CR28 CTL_REG(0x0070)
+#define CR29 CTL_REG(0x0074)
+#define CR30 CTL_REG(0x0078)
+#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */
+#define CR32 CTL_REG(0x0080)
+#define CR33 CTL_REG(0x0084)
+#define CR34 CTL_REG(0x0088)
+#define CR35 CTL_REG(0x008C)
+#define CR36 CTL_REG(0x0090)
+#define CR37 CTL_REG(0x0094)
+#define CR38 CTL_REG(0x0098)
+#define CR39 CTL_REG(0x009C)
+#define CR40 CTL_REG(0x00A0)
+#define CR41 CTL_REG(0x00A4)
+#define CR42 CTL_REG(0x00A8)
+#define CR43 CTL_REG(0x00AC)
+#define CR44 CTL_REG(0x00B0)
+#define CR45 CTL_REG(0x00B4)
+#define CR46 CTL_REG(0x00B8)
+#define CR47 CTL_REG(0x00BC) /* CCK baseband gain
+ * (patch value might be in EEPROM)
+ */
+#define CR48 CTL_REG(0x00C0)
+#define CR49 CTL_REG(0x00C4)
+#define CR50 CTL_REG(0x00C8)
+#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */
+#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */
+#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */
+#define CR54 CTL_REG(0x00D8)
+#define CR55 CTL_REG(0x00DC)
+#define CR56 CTL_REG(0x00E0)
+#define CR57 CTL_REG(0x00E4)
+#define CR58 CTL_REG(0x00E8)
+#define CR59 CTL_REG(0x00EC)
+#define CR60 CTL_REG(0x00F0)
+#define CR61 CTL_REG(0x00F4)
+#define CR62 CTL_REG(0x00F8)
+#define CR63 CTL_REG(0x00FC)
+#define CR64 CTL_REG(0x0100)
+#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */
+#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */
+#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */
+#define CR68 CTL_REG(0x0110) /* CCK calibration */
+#define CR69 CTL_REG(0x0114)
+#define CR70 CTL_REG(0x0118)
+#define CR71 CTL_REG(0x011C)
+#define CR72 CTL_REG(0x0120)
+#define CR73 CTL_REG(0x0124)
+#define CR74 CTL_REG(0x0128)
+#define CR75 CTL_REG(0x012C)
+#define CR76 CTL_REG(0x0130)
+#define CR77 CTL_REG(0x0134)
+#define CR78 CTL_REG(0x0138)
+#define CR79 CTL_REG(0x013C)
+#define CR80 CTL_REG(0x0140)
+#define CR81 CTL_REG(0x0144)
+#define CR82 CTL_REG(0x0148)
+#define CR83 CTL_REG(0x014C)
+#define CR84 CTL_REG(0x0150)
+#define CR85 CTL_REG(0x0154)
+#define CR86 CTL_REG(0x0158)
+#define CR87 CTL_REG(0x015C)
+#define CR88 CTL_REG(0x0160)
+#define CR89 CTL_REG(0x0164)
+#define CR90 CTL_REG(0x0168)
+#define CR91 CTL_REG(0x016C)
+#define CR92 CTL_REG(0x0170)
+#define CR93 CTL_REG(0x0174)
+#define CR94 CTL_REG(0x0178)
+#define CR95 CTL_REG(0x017C)
+#define CR96 CTL_REG(0x0180)
+#define CR97 CTL_REG(0x0184)
+#define CR98 CTL_REG(0x0188)
+#define CR99 CTL_REG(0x018C)
+#define CR100 CTL_REG(0x0190)
+#define CR101 CTL_REG(0x0194)
+#define CR102 CTL_REG(0x0198)
+#define CR103 CTL_REG(0x019C)
+#define CR104 CTL_REG(0x01A0)
+#define CR105 CTL_REG(0x01A4)
+#define CR106 CTL_REG(0x01A8)
+#define CR107 CTL_REG(0x01AC)
+#define CR108 CTL_REG(0x01B0)
+#define CR109 CTL_REG(0x01B4)
+#define CR110 CTL_REG(0x01B8)
+#define CR111 CTL_REG(0x01BC)
+#define CR112 CTL_REG(0x01C0)
+#define CR113 CTL_REG(0x01C4)
+#define CR114 CTL_REG(0x01C8)
+#define CR115 CTL_REG(0x01CC)
+#define CR116 CTL_REG(0x01D0)
+#define CR117 CTL_REG(0x01D4)
+#define CR118 CTL_REG(0x01D8)
+#define CR119 CTL_REG(0x01DC)
+#define CR120 CTL_REG(0x01E0)
+#define CR121 CTL_REG(0x01E4)
+#define CR122 CTL_REG(0x01E8)
+#define CR123 CTL_REG(0x01EC)
+#define CR124 CTL_REG(0x01F0)
+#define CR125 CTL_REG(0x01F4)
+#define CR126 CTL_REG(0x01F8)
+#define CR127 CTL_REG(0x01FC)
+#define CR128 CTL_REG(0x0200)
+#define CR129 CTL_REG(0x0204)
+#define CR130 CTL_REG(0x0208)
+#define CR131 CTL_REG(0x020C)
+#define CR132 CTL_REG(0x0210)
+#define CR133 CTL_REG(0x0214)
+#define CR134 CTL_REG(0x0218)
+#define CR135 CTL_REG(0x021C)
+#define CR136 CTL_REG(0x0220)
+#define CR137 CTL_REG(0x0224)
+#define CR138 CTL_REG(0x0228)
+#define CR139 CTL_REG(0x022C)
+#define CR140 CTL_REG(0x0230)
+#define CR141 CTL_REG(0x0234)
+#define CR142 CTL_REG(0x0238)
+#define CR143 CTL_REG(0x023C)
+#define CR144 CTL_REG(0x0240)
+#define CR145 CTL_REG(0x0244)
+#define CR146 CTL_REG(0x0248)
+#define CR147 CTL_REG(0x024C)
+#define CR148 CTL_REG(0x0250)
+#define CR149 CTL_REG(0x0254)
+#define CR150 CTL_REG(0x0258)
+#define CR151 CTL_REG(0x025C)
+#define CR152 CTL_REG(0x0260)
+#define CR153 CTL_REG(0x0264)
+#define CR154 CTL_REG(0x0268)
+#define CR155 CTL_REG(0x026C)
+#define CR156 CTL_REG(0x0270)
+#define CR157 CTL_REG(0x0274)
+#define CR158 CTL_REG(0x0278)
+#define CR159 CTL_REG(0x027C)
+#define CR160 CTL_REG(0x0280)
+#define CR161 CTL_REG(0x0284)
+#define CR162 CTL_REG(0x0288)
+#define CR163 CTL_REG(0x028C)
+#define CR164 CTL_REG(0x0290)
+#define CR165 CTL_REG(0x0294)
+#define CR166 CTL_REG(0x0298)
+#define CR167 CTL_REG(0x029C)
+#define CR168 CTL_REG(0x02A0)
+#define CR169 CTL_REG(0x02A4)
+#define CR170 CTL_REG(0x02A8)
+#define CR171 CTL_REG(0x02AC)
+#define CR172 CTL_REG(0x02B0)
+#define CR173 CTL_REG(0x02B4)
+#define CR174 CTL_REG(0x02B8)
+#define CR175 CTL_REG(0x02BC)
+#define CR176 CTL_REG(0x02C0)
+#define CR177 CTL_REG(0x02C4)
+#define CR178 CTL_REG(0x02C8)
+#define CR179 CTL_REG(0x02CC)
+#define CR180 CTL_REG(0x02D0)
+#define CR181 CTL_REG(0x02D4)
+#define CR182 CTL_REG(0x02D8)
+#define CR183 CTL_REG(0x02DC)
+#define CR184 CTL_REG(0x02E0)
+#define CR185 CTL_REG(0x02E4)
+#define CR186 CTL_REG(0x02E8)
+#define CR187 CTL_REG(0x02EC)
+#define CR188 CTL_REG(0x02F0)
+#define CR189 CTL_REG(0x02F4)
+#define CR190 CTL_REG(0x02F8)
+#define CR191 CTL_REG(0x02FC)
+#define CR192 CTL_REG(0x0300)
+#define CR193 CTL_REG(0x0304)
+#define CR194 CTL_REG(0x0308)
+#define CR195 CTL_REG(0x030C)
+#define CR196 CTL_REG(0x0310)
+#define CR197 CTL_REG(0x0314)
+#define CR198 CTL_REG(0x0318)
+#define CR199 CTL_REG(0x031C)
+#define CR200 CTL_REG(0x0320)
+#define CR201 CTL_REG(0x0324)
+#define CR202 CTL_REG(0x0328)
+#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */
+#define CR204 CTL_REG(0x0330)
+#define CR205 CTL_REG(0x0334)
+#define CR206 CTL_REG(0x0338)
+#define CR207 CTL_REG(0x033C)
+#define CR208 CTL_REG(0x0340)
+#define CR209 CTL_REG(0x0344)
+#define CR210 CTL_REG(0x0348)
+#define CR211 CTL_REG(0x034C)
+#define CR212 CTL_REG(0x0350)
+#define CR213 CTL_REG(0x0354)
+#define CR214 CTL_REG(0x0358)
+#define CR215 CTL_REG(0x035C)
+#define CR216 CTL_REG(0x0360)
+#define CR217 CTL_REG(0x0364)
+#define CR218 CTL_REG(0x0368)
+#define CR219 CTL_REG(0x036C)
+#define CR220 CTL_REG(0x0370)
+#define CR221 CTL_REG(0x0374)
+#define CR222 CTL_REG(0x0378)
+#define CR223 CTL_REG(0x037C)
+#define CR224 CTL_REG(0x0380)
+#define CR225 CTL_REG(0x0384)
+#define CR226 CTL_REG(0x0388)
+#define CR227 CTL_REG(0x038C)
+#define CR228 CTL_REG(0x0390)
+#define CR229 CTL_REG(0x0394)
+#define CR230 CTL_REG(0x0398)
+#define CR231 CTL_REG(0x039C)
+#define CR232 CTL_REG(0x03A0)
+#define CR233 CTL_REG(0x03A4)
+#define CR234 CTL_REG(0x03A8)
+#define CR235 CTL_REG(0x03AC)
+#define CR236 CTL_REG(0x03B0)
+
+#define CR240 CTL_REG(0x03C0)
+/* bit 7: host-controlled RF register writes
+ * CR241-CR245: for hardware controlled writing of RF bits, not needed for
+ * USB
+ */
+#define CR241 CTL_REG(0x03C4)
+#define CR242 CTL_REG(0x03C8)
+#define CR243 CTL_REG(0x03CC)
+#define CR244 CTL_REG(0x03D0)
+#define CR245 CTL_REG(0x03D4)
+
+#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of
+ * Airoha RFs AL2230 and AL7230B
+ */
+#define CR252 CTL_REG(0x03F0)
+#define CR253 CTL_REG(0x03F4)
+#define CR254 CTL_REG(0x03F8)
+#define CR255 CTL_REG(0x03FC)
+
+#define CR_MAX_PHY_REG 255
+
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+ * driver.
+ */
+
+#define CR_RF_IF_CLK CTL_REG(0x0400)
+#define CR_RF_IF_DATA CTL_REG(0x0404)
+#define CR_PE1_PE2 CTL_REG(0x0408)
+#define CR_PE2_DLY CTL_REG(0x040C)
+#define CR_LE1 CTL_REG(0x0410)
+#define CR_LE2 CTL_REG(0x0414)
+/* Seems to enable/disable GPI (General Purpose IO?) */
+#define CR_GPI_EN CTL_REG(0x0418)
+#define CR_RADIO_PD CTL_REG(0x042C)
+#define CR_RF2948_PD CTL_REG(0x042C)
+#define CR_ENABLE_PS_MANUAL_AGC CTL_REG(0x043C)
+#define CR_CONFIG_PHILIPS CTL_REG(0x0440)
+#define CR_SA2400_SER_AP CTL_REG(0x0444)
+#define CR_I2C_WRITE CTL_REG(0x0444)
+#define CR_SA2400_SER_RP CTL_REG(0x0448)
+#define CR_RADIO_PE CTL_REG(0x0458)
+#define CR_RST_BUS_MASTER CTL_REG(0x045C)
+#define CR_RFCFG CTL_REG(0x0464)
+#define CR_HSTSCHG CTL_REG(0x046C)
+#define CR_PHY_ON CTL_REG(0x0474)
+#define CR_RX_DELAY CTL_REG(0x0478)
+#define CR_RX_PE_DELAY CTL_REG(0x047C)
+#define CR_GPIO_1 CTL_REG(0x0490)
+#define CR_GPIO_2 CTL_REG(0x0494)
+#define CR_EncryBufMux CTL_REG(0x04A8)
+#define CR_PS_CTRL CTL_REG(0x0500)
+#define CR_ADDA_PWR_DWN CTL_REG(0x0504)
+#define CR_ADDA_MBIAS_WARMTIME CTL_REG(0x0508)
+#define CR_MAC_PS_STATE CTL_REG(0x050C)
+
+#define CR_INTERRUPT CTL_REG(0x0510)
+#define INT_TX_COMPLETE 0x00000001
+#define INT_RX_COMPLETE 0x00000002
+#define INT_RETRY_FAIL 0x00000004
+#define INT_WAKEUP 0x00000008
+#define INT_DTIM_NOTIFY 0x00000020
+#define INT_CFG_NEXT_BCN 0x00000040
+#define INT_BUS_ABORT 0x00000080
+#define INT_TX_FIFO_READY 0x00000100
+#define INT_UART 0x00000200
+#define INT_TX_COMPLETE_EN 0x00010000
+#define INT_RX_COMPLETE_EN 0x00020000
+#define INT_RETRY_FAIL_EN 0x00040000
+#define INT_WAKEUP_EN 0x00080000
+#define INT_DTIM_NOTIFY_EN 0x00200000
+#define INT_CFG_NEXT_BCN_EN 0x00400000
+#define INT_BUS_ABORT_EN 0x00800000
+#define INT_TX_FIFO_READY_EN 0x01000000
+#define INT_UART_EN 0x02000000
+
+#define CR_TSF_LOW_PART CTL_REG(0x0514)
+#define CR_TSF_HIGH_PART CTL_REG(0x0518)
+
+/* Following three values are in time units (1024us)
+ * Following condition must be met:
+ * atim < tbtt < bcn
+ */
+#define CR_ATIM_WND_PERIOD CTL_REG(0x051C)
+#define CR_BCN_INTERVAL CTL_REG(0x0520)
+#define CR_PRE_TBTT CTL_REG(0x0524)
+/* in units of TU(1024us) */
+
+/* for UART support */
+#define CR_UART_RBR_THR_DLL CTL_REG(0x0540)
+#define CR_UART_DLM_IER CTL_REG(0x0544)
+#define CR_UART_IIR_FCR CTL_REG(0x0548)
+#define CR_UART_LCR CTL_REG(0x054c)
+#define CR_UART_MCR CTL_REG(0x0550)
+#define CR_UART_LSR CTL_REG(0x0554)
+#define CR_UART_MSR CTL_REG(0x0558)
+#define CR_UART_ECR CTL_REG(0x055c)
+#define CR_UART_STATUS CTL_REG(0x0560)
+
+#define CR_PCI_TX_ADDR_P1 CTL_REG(0x0600)
+#define CR_PCI_TX_AddR_P2 CTL_REG(0x0604)
+#define CR_PCI_RX_AddR_P1 CTL_REG(0x0608)
+#define CR_PCI_RX_AddR_P2 CTL_REG(0x060C)
+
+/* must be overwritten if custom MAC address will be used */
+#define CR_MAC_ADDR_P1 CTL_REG(0x0610)
+#define CR_MAC_ADDR_P2 CTL_REG(0x0614)
+#define CR_BSSID_P1 CTL_REG(0x0618)
+#define CR_BSSID_P2 CTL_REG(0x061C)
+#define CR_BCN_PLCP_CFG CTL_REG(0x0620)
+#define CR_GROUP_HASH_P1 CTL_REG(0x0624)
+#define CR_GROUP_HASH_P2 CTL_REG(0x0628)
+#define CR_RX_TIMEOUT CTL_REG(0x062C)
+
+/* Basic rates supported by the BSS. When producing ACK or CTS messages, the
+ * device will use a rate in this table that is less than or equal to the rate
+ * of the incoming frame which prompted the response */
+#define CR_BASIC_RATE_TBL CTL_REG(0x0630)
+#define CR_RATE_1M 0x0001 /* 802.11b */
+#define CR_RATE_2M 0x0002 /* 802.11b */
+#define CR_RATE_5_5M 0x0004 /* 802.11b */
+#define CR_RATE_11M 0x0008 /* 802.11b */
+#define CR_RATE_6M 0x0100 /* 802.11g */
+#define CR_RATE_9M 0x0200 /* 802.11g */
+#define CR_RATE_12M 0x0400 /* 802.11g */
+#define CR_RATE_18M 0x0800 /* 802.11g */
+#define CR_RATE_24M 0x1000 /* 802.11g */
+#define CR_RATE_36M 0x2000 /* 802.11g */
+#define CR_RATE_48M 0x4000 /* 802.11g */
+#define CR_RATE_54M 0x8000 /* 802.11g */
+#define CR_RATES_80211G 0xff00
+#define CR_RATES_80211B 0x000f
+
+/* Mandatory rates required in the BSS. When producing ACK or CTS messages, if
+ * the device could not find an appropriate rate in CR_BASIC_RATE_TBL, it will
+ * look for a rate in this table that is less than or equal to the rate of
+ * the incoming frame. */
+#define CR_MANDATORY_RATE_TBL CTL_REG(0x0634)
+#define CR_RTS_CTS_RATE CTL_REG(0x0638)
+
+#define CR_WEP_PROTECT CTL_REG(0x063C)
+#define CR_RX_THRESHOLD CTL_REG(0x0640)
+
+/* register for controlling the LEDS */
+#define CR_LED CTL_REG(0x0644)
+/* masks for controlling LEDs */
+#define LED1 0x0100
+#define LED2 0x0200
+
+/* Seems to indicate that the configuration is over.
+ */
+#define CR_AFTER_PNP CTL_REG(0x0648)
+#define CR_ACK_TIME_80211 CTL_REG(0x0658)
+
+#define CR_RX_OFFSET CTL_REG(0x065c)
+
+#define CR_PHY_DELAY CTL_REG(0x066C)
+#define CR_BCN_FIFO CTL_REG(0x0670)
+#define CR_SNIFFER_ON CTL_REG(0x0674)
+
+#define CR_ENCRYPTION_TYPE CTL_REG(0x0678)
+#define NO_WEP 0
+#define WEP64 1
+#define WEP128 5
+#define WEP256 6
+#define ENC_SNIFFER 8
+
+#define CR_ZD1211_RETRY_MAX CTL_REG(0x067C)
+
+#define CR_REG1 CTL_REG(0x0680)
+/* Setting the bit UNLOCK_PHY_REGS disallows the write access to physical
+ * registers, so one could argue it is a LOCK bit. But calling it
+ * LOCK_PHY_REGS makes it confusing.
+ */
+#define UNLOCK_PHY_REGS 0x0080
+
+#define CR_DEVICE_STATE CTL_REG(0x0684)
+#define CR_UNDERRUN_CNT CTL_REG(0x0688)
+
+#define CR_RX_FILTER CTL_REG(0x068c)
+#define RX_FILTER_ASSOC_RESPONSE 0x0002
+#define RX_FILTER_PROBE_RESPONSE 0x0020
+#define RX_FILTER_BEACON 0x0100
+#define RX_FILTER_AUTH 0x0800
+/* Sniff modus sets filter to 0xfffff */
+
+#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
+#define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694)
+#define CR_IFS_VALUE CTL_REG(0x0698)
+#define CR_RX_TIME_OUT CTL_REG(0x069C)
+#define CR_TOTAL_RX_FRM CTL_REG(0x06A0)
+#define CR_CRC32_CNT CTL_REG(0x06A4)
+#define CR_CRC16_CNT CTL_REG(0x06A8)
+#define CR_DECRYPTION_ERR_UNI CTL_REG(0x06AC)
+#define CR_RX_FIFO_OVERRUN CTL_REG(0x06B0)
+
+#define CR_DECRYPTION_ERR_MUL CTL_REG(0x06BC)
+
+#define CR_NAV_CNT CTL_REG(0x06C4)
+#define CR_NAV_CCA CTL_REG(0x06C8)
+#define CR_RETRY_CNT CTL_REG(0x06CC)
+
+#define CR_READ_TCB_ADDR CTL_REG(0x06E8)
+#define CR_READ_RFD_ADDR CTL_REG(0x06EC)
+#define CR_CWMIN_CWMAX CTL_REG(0x06F0)
+#define CR_TOTAL_TX_FRM CTL_REG(0x06F4)
+
+/* CAM: Continuous Access Mode (power management) */
+#define CR_CAM_MODE CTL_REG(0x0700)
+#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
+#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
+#define CR_CAM_ADDRESS CTL_REG(0x070C)
+#define CR_CAM_DATA CTL_REG(0x0710)
+
+#define CR_ROMDIR CTL_REG(0x0714)
+
+#define CR_DECRY_ERR_FLG_LOW CTL_REG(0x0714)
+#define CR_DECRY_ERR_FLG_HIGH CTL_REG(0x0718)
+
+#define CR_WEPKEY0 CTL_REG(0x0720)
+#define CR_WEPKEY1 CTL_REG(0x0724)
+#define CR_WEPKEY2 CTL_REG(0x0728)
+#define CR_WEPKEY3 CTL_REG(0x072C)
+#define CR_WEPKEY4 CTL_REG(0x0730)
+#define CR_WEPKEY5 CTL_REG(0x0734)
+#define CR_WEPKEY6 CTL_REG(0x0738)
+#define CR_WEPKEY7 CTL_REG(0x073C)
+#define CR_WEPKEY8 CTL_REG(0x0740)
+#define CR_WEPKEY9 CTL_REG(0x0744)
+#define CR_WEPKEY10 CTL_REG(0x0748)
+#define CR_WEPKEY11 CTL_REG(0x074C)
+#define CR_WEPKEY12 CTL_REG(0x0750)
+#define CR_WEPKEY13 CTL_REG(0x0754)
+#define CR_WEPKEY14 CTL_REG(0x0758)
+#define CR_WEPKEY15 CTL_REG(0x075c)
+#define CR_TKIP_MODE CTL_REG(0x0760)
+
+#define CR_EEPROM_PROTECT0 CTL_REG(0x0758)
+#define CR_EEPROM_PROTECT1 CTL_REG(0x075C)
+
+#define CR_DBG_FIFO_RD CTL_REG(0x0800)
+#define CR_DBG_SELECT CTL_REG(0x0804)
+#define CR_FIFO_Length CTL_REG(0x0808)
+
+
+#define CR_RSSI_MGC CTL_REG(0x0810)
+
+#define CR_PON CTL_REG(0x0818)
+#define CR_RX_ON CTL_REG(0x081C)
+#define CR_TX_ON CTL_REG(0x0820)
+#define CR_CHIP_EN CTL_REG(0x0824)
+#define CR_LO_SW CTL_REG(0x0828)
+#define CR_TXRX_SW CTL_REG(0x082C)
+#define CR_S_MD CTL_REG(0x0830)
+
+#define CR_USB_DEBUG_PORT CTL_REG(0x0888)
+
+#define CR_ZD1211B_TX_PWR_CTL1 CTL_REG(0x0b00)
+#define CR_ZD1211B_TX_PWR_CTL2 CTL_REG(0x0b04)
+#define CR_ZD1211B_TX_PWR_CTL3 CTL_REG(0x0b08)
+#define CR_ZD1211B_TX_PWR_CTL4 CTL_REG(0x0b0c)
+#define CR_ZD1211B_AIFS_CTL1 CTL_REG(0x0b10)
+#define CR_ZD1211B_AIFS_CTL2 CTL_REG(0x0b14)
+#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
+#define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28)
+
+#define AP_RX_FILTER 0x0400feff
+#define STA_RX_FILTER 0x0000ffff
+
+#define CWIN_SIZE 0x007f043f
+
+
+#define HWINT_ENABLED 0x004f0000
+#define HWINT_DISABLED 0
+
+#define E2P_PWR_INT_GUARD 8
+#define E2P_CHANNEL_COUNT 14
+
+/* If you compare this addresses with the ZYDAS orignal driver, please notify
+ * that we use word mapping for the EEPROM.
+ */
+
+/*
+ * Upper 16 bit contains the regulatory domain.
+ */
+#define E2P_SUBID E2P_REG(0x00)
+#define E2P_POD E2P_REG(0x02)
+#define E2P_MAC_ADDR_P1 E2P_REG(0x04)
+#define E2P_MAC_ADDR_P2 E2P_REG(0x06)
+#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08)
+#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a)
+#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c)
+#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e)
+#define E2P_PWR_INT_VALUE1 E2P_REG(0x10)
+#define E2P_PWR_INT_VALUE2 E2P_REG(0x12)
+#define E2P_PWR_INT_VALUE3 E2P_REG(0x14)
+#define E2P_PWR_INT_VALUE4 E2P_REG(0x16)
+
+/* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
+ * also only 11 channels. */
+#define E2P_ALLOWED_CHANNEL E2P_REG(0x18)
+
+#define E2P_PHY_REG E2P_REG(0x1a)
+#define E2P_DEVICE_VER E2P_REG(0x20)
+#define E2P_36M_CAL_VALUE1 E2P_REG(0x28)
+#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a)
+#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c)
+#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e)
+#define E2P_11A_INT_VALUE1 E2P_REG(0x30)
+#define E2P_11A_INT_VALUE2 E2P_REG(0x32)
+#define E2P_11A_INT_VALUE3 E2P_REG(0x34)
+#define E2P_11A_INT_VALUE4 E2P_REG(0x36)
+#define E2P_48M_CAL_VALUE1 E2P_REG(0x38)
+#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a)
+#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c)
+#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e)
+#define E2P_48M_INT_VALUE1 E2P_REG(0x40)
+#define E2P_48M_INT_VALUE2 E2P_REG(0x42)
+#define E2P_48M_INT_VALUE3 E2P_REG(0x44)
+#define E2P_48M_INT_VALUE4 E2P_REG(0x46)
+#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */
+#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a)
+#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c)
+#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e)
+#define E2P_54M_INT_VALUE1 E2P_REG(0x50)
+#define E2P_54M_INT_VALUE2 E2P_REG(0x52)
+#define E2P_54M_INT_VALUE3 E2P_REG(0x54)
+#define E2P_54M_INT_VALUE4 E2P_REG(0x56)
+
+/* All 16 bit values */
+#define FW_FIRMWARE_VER FW_REG(0)
+/* non-zero if USB high speed connection */
+#define FW_USB_SPEED FW_REG(1)
+#define FW_FIX_TX_RATE FW_REG(2)
+/* Seems to be able to control LEDs over the firmware */
+#define FW_LINK_STATUS FW_REG(3)
+#define FW_SOFT_RESET FW_REG(4)
+#define FW_FLASH_CHK FW_REG(5)
+
+enum {
+ CR_BASE_OFFSET = 0x9000,
+ FW_START_OFFSET = 0xee00,
+ FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d,
+ EEPROM_START_OFFSET = 0xf800,
+ EEPROM_SIZE = 0x800, /* words */
+ LOAD_CODE_SIZE = 0xe, /* words */
+ LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
+ EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+ E2P_BASE_OFFSET = EEPROM_START_OFFSET +
+ EEPROM_REGS_OFFSET,
+};
+
+#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d)
+
+enum {
+ /* indices for ofdm_cal_values */
+ OFDM_36M_INDEX = 0,
+ OFDM_48M_INDEX = 1,
+ OFDM_54M_INDEX = 2,
+};
+
+struct zd_chip {
+ struct zd_usb usb;
+ struct zd_rf rf;
+ struct mutex mutex;
+ u8 e2p_mac[ETH_ALEN];
+ /* EepSetPoint in the vendor driver */
+ u8 pwr_cal_values[E2P_CHANNEL_COUNT];
+ /* integration values in the vendor driver */
+ u8 pwr_int_values[E2P_CHANNEL_COUNT];
+ /* SetPointOFDM in the vendor driver */
+ u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
+ u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
+ is_zd1211b:1;
+};
+
+static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
+{
+ return container_of(usb, struct zd_chip, usb);
+}
+
+static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf)
+{
+ return container_of(rf, struct zd_chip, rf);
+}
+
+#define zd_chip_dev(chip) (&(chip)->usb.intf->dev)
+
+void zd_chip_init(struct zd_chip *chip,
+ struct net_device *netdev,
+ struct usb_interface *intf);
+void zd_chip_clear(struct zd_chip *chip);
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type);
+int zd_chip_reset(struct zd_chip *chip);
+
+static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values,
+ const zd_addr_t *addresses,
+ unsigned int count)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_ioread16v(&chip->usb, values, addresses, count);
+}
+
+static inline int zd_ioread16_locked(struct zd_chip *chip, u16 *value,
+ const zd_addr_t addr)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_ioread16(&chip->usb, value, addr);
+}
+
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values,
+ const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_ioread32_locked(struct zd_chip *chip, u32 *value,
+ const zd_addr_t addr)
+{
+ return zd_ioread32v_locked(chip, value, (const zd_addr_t *)&addr, 1);
+}
+
+static inline int zd_iowrite16_locked(struct zd_chip *chip, u16 value,
+ zd_addr_t addr)
+{
+ struct zd_ioreq16 ioreq;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ ioreq.addr = addr;
+ ioreq.value = value;
+
+ return zd_usb_iowrite16v(&chip->usb, &ioreq, 1);
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+ const struct zd_ioreq16 *ioreqs, unsigned int count);
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count);
+
+static inline int zd_iowrite32_locked(struct zd_chip *chip, u32 value,
+ zd_addr_t addr)
+{
+ struct zd_ioreq32 ioreq;
+
+ ioreq.addr = addr;
+ ioreq.value = value;
+
+ return _zd_iowrite32v_locked(chip, &ioreq, 1);
+}
+
+int zd_iowrite32a_locked(struct zd_chip *chip,
+ const struct zd_ioreq32 *ioreqs, unsigned int count);
+
+static inline int zd_rfwrite_locked(struct zd_chip *chip, u32 value, u8 bits)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_rfwrite(&chip->usb, value, bits);
+}
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count, u8 bits);
+
+/* Locking functions for reading and writing registers.
+ * The different parameters are intentional.
+ */
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value);
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value);
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value);
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value);
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+ u32 *values, unsigned int count);
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count);
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel);
+static inline u8 _zd_chip_get_channel(struct zd_chip *chip)
+{
+ return chip->rf.channel;
+}
+u8 zd_chip_get_channel(struct zd_chip *chip);
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain);
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr);
+int zd_chip_switch_radio_on(struct zd_chip *chip);
+int zd_chip_switch_radio_off(struct zd_chip *chip);
+int zd_chip_enable_int(struct zd_chip *chip);
+void zd_chip_disable_int(struct zd_chip *chip);
+int zd_chip_enable_rx(struct zd_chip *chip);
+void zd_chip_disable_rx(struct zd_chip *chip);
+int zd_chip_enable_hwint(struct zd_chip *chip);
+int zd_chip_disable_hwint(struct zd_chip *chip);
+
+static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type)
+{
+ return zd_ioread32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_set_encryption_type(struct zd_chip *chip, u32 type)
+{
+ return zd_iowrite32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates)
+{
+ return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates);
+
+static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
+{
+ return zd_iowrite32(chip, CR_RX_FILTER, filter);
+}
+
+int zd_chip_lock_phy_regs(struct zd_chip *chip);
+int zd_chip_unlock_phy_regs(struct zd_chip *chip);
+
+enum led_status {
+ LED_OFF = 0,
+ LED_ON = 1,
+ LED_FLIP = 2,
+ LED_STATUS = 3,
+};
+
+int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status);
+int zd_chip_led_flip(struct zd_chip *chip, int led,
+ const unsigned int *phases_msecs, unsigned int count);
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
+
+static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval)
+{
+ return zd_ioread32(chip, CR_BCN_INTERVAL, interval);
+}
+
+struct rx_status;
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+ const struct rx_status *status);
+u8 zd_rx_strength_percent(u8 rssi);
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
+
+#endif /* _ZD_CHIP_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
new file mode 100644
index 00000000000..465906812fc
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -0,0 +1,48 @@
+/* zd_def.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_DEF_H
+#define _ZD_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/stringify.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#define dev_printk_f(level, dev, fmt, args...) \
+ dev_printk(level, dev, "%s() " fmt, __func__, ##args)
+
+#ifdef DEBUG
+# define dev_dbg_f(dev, fmt, args...) \
+ dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
+#else
+# define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
+#endif /* DEBUG */
+
+#ifdef DEBUG
+# define ZD_ASSERT(x) \
+do { \
+ if (!(x)) { \
+ pr_debug("%s:%d ASSERT %s VIOLATED!\n", \
+ __FILE__, __LINE__, __stringify(x)); \
+ } \
+} while (0)
+#else
+# define ZD_ASSERT(x) do { } while (0)
+#endif
+
+#endif /* _ZD_DEF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
new file mode 100644
index 00000000000..66905f7b61f
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
@@ -0,0 +1,191 @@
+/* zd_ieee80211.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * A lot of this code is generic and should be moved into the upper layers
+ * at some point.
+ */
+
+#include <linux/errno.h>
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+
+static const struct channel_range channel_ranges[] = {
+ [0] = { 0, 0},
+ [ZD_REGDOMAIN_FCC] = { 1, 12},
+ [ZD_REGDOMAIN_IC] = { 1, 12},
+ [ZD_REGDOMAIN_ETSI] = { 1, 14},
+ [ZD_REGDOMAIN_JAPAN] = { 1, 14},
+ [ZD_REGDOMAIN_SPAIN] = { 1, 14},
+ [ZD_REGDOMAIN_FRANCE] = { 1, 14},
+ [ZD_REGDOMAIN_JAPAN_ADD] = {14, 15},
+};
+
+const struct channel_range *zd_channel_range(u8 regdomain)
+{
+ if (regdomain >= ARRAY_SIZE(channel_ranges))
+ regdomain = 0;
+ return &channel_ranges[regdomain];
+}
+
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
+{
+ const struct channel_range *range = zd_channel_range(regdomain);
+ return range->start <= channel && channel < range->end;
+}
+
+int zd_regdomain_supported(u8 regdomain)
+{
+ const struct channel_range *range = zd_channel_range(regdomain);
+ return range->start != 0;
+}
+
+/* Stores channel frequencies in MHz. */
+static const u16 channel_frequencies[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
+ 2452, 2457, 2462, 2467, 2472, 2484,
+};
+
+#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
+
+static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
+{
+ u32 factor;
+
+ freq->e = 0;
+ if (mhz >= 1000000000U) {
+ pr_debug("zd1211 mhz %u to large\n", mhz);
+ freq->m = 0;
+ return -EINVAL;
+ }
+
+ factor = 1000;
+ while (mhz >= factor) {
+
+ freq->e += 1;
+ factor *= 10;
+ }
+
+ factor /= 1000U;
+ freq->m = mhz * (1000000U/factor) + hz/factor;
+
+ return 0;
+}
+
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
+{
+ if (channel > NUM_CHANNELS) {
+ freq->m = 0;
+ freq->e = 0;
+ return -EINVAL;
+ }
+ if (!channel) {
+ freq->m = 0;
+ freq->e = 0;
+ return -EINVAL;
+ }
+ return compute_freq(freq, channel_frequencies[channel-1], 0);
+}
+
+static int freq_to_mhz(const struct iw_freq *freq)
+{
+ u32 factor;
+ int e;
+
+ /* Such high frequencies are not supported. */
+ if (freq->e > 6)
+ return -EINVAL;
+
+ factor = 1;
+ for (e = freq->e; e > 0; --e) {
+ factor *= 10;
+ }
+ factor = 1000000U / factor;
+
+ if (freq->m % factor) {
+ return -EINVAL;
+ }
+
+ return freq->m / factor;
+}
+
+int zd_find_channel(u8 *channel, const struct iw_freq *freq)
+{
+ int i, r;
+ u32 mhz;
+
+ if (!(freq->flags & IW_FREQ_FIXED))
+ return 0;
+
+ if (freq->m < 1000) {
+ if (freq->m > NUM_CHANNELS || freq->m == 0)
+ return -EINVAL;
+ *channel = freq->m;
+ return 1;
+ }
+
+ r = freq_to_mhz(freq);
+ if (r < 0)
+ return r;
+ mhz = r;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (mhz == channel_frequencies[i]) {
+ *channel = i+1;
+ return 1;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
+{
+ struct ieee80211_geo geo;
+ const struct channel_range *range;
+ int i;
+ u8 channel;
+
+ dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+ "regdomain %#04x\n", regdomain);
+
+ range = zd_channel_range(regdomain);
+ if (range->start == 0) {
+ dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+ "zd1211 regdomain %#04x not supported\n",
+ regdomain);
+ return -EINVAL;
+ }
+
+ memset(&geo, 0, sizeof(geo));
+
+ for (i = 0, channel = range->start; channel < range->end; channel++) {
+ struct ieee80211_channel *chan = &geo.bg[i++];
+ chan->freq = channel_frequencies[channel - 1];
+ chan->channel = channel;
+ }
+
+ geo.bg_channels = i;
+ memcpy(geo.name, "XX ", 4);
+ ieee80211_set_geo(ieee, &geo);
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
new file mode 100644
index 00000000000..36329890dfe
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -0,0 +1,85 @@
+#ifndef _ZD_IEEE80211_H
+#define _ZD_IEEE80211_H
+
+#include <net/ieee80211.h>
+#include "zd_types.h"
+
+/* Additional definitions from the standards.
+ */
+
+#define ZD_REGDOMAIN_FCC 0x10
+#define ZD_REGDOMAIN_IC 0x20
+#define ZD_REGDOMAIN_ETSI 0x30
+#define ZD_REGDOMAIN_SPAIN 0x31
+#define ZD_REGDOMAIN_FRANCE 0x32
+#define ZD_REGDOMAIN_JAPAN_ADD 0x40
+#define ZD_REGDOMAIN_JAPAN 0x41
+
+enum {
+ MIN_CHANNEL24 = 1,
+ MAX_CHANNEL24 = 14,
+};
+
+struct channel_range {
+ u8 start;
+ u8 end; /* exclusive (channel must be less than end) */
+};
+
+struct iw_freq;
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain);
+
+const struct channel_range *zd_channel_range(u8 regdomain);
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel);
+int zd_regdomain_supported(u8 regdomain);
+
+/* for 2.4 GHz band */
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel);
+int zd_find_channel(u8 *channel, const struct iw_freq *freq);
+
+#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
+
+struct ofdm_plcp_header {
+ u8 prefix[3];
+ __le16 service;
+} __attribute__((packed));
+
+static inline u8 zd_ofdm_plcp_header_rate(
+ const struct ofdm_plcp_header *header)
+{
+ return header->prefix[0] & 0xf;
+}
+
+#define ZD_OFDM_RATE_6M 0xb
+#define ZD_OFDM_RATE_9M 0xf
+#define ZD_OFDM_RATE_12M 0xa
+#define ZD_OFDM_RATE_18M 0xe
+#define ZD_OFDM_RATE_24M 0x9
+#define ZD_OFDM_RATE_36M 0xd
+#define ZD_OFDM_RATE_48M 0x8
+#define ZD_OFDM_RATE_54M 0xc
+
+struct cck_plcp_header {
+ u8 signal;
+ u8 service;
+ __le16 length;
+ __le16 crc16;
+} __attribute__((packed));
+
+static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+{
+ return header->signal;
+}
+
+#define ZD_CCK_SIGNAL_1M 0x0a
+#define ZD_CCK_SIGNAL_2M 0x14
+#define ZD_CCK_SIGNAL_5M5 0x37
+#define ZD_CCK_SIGNAL_11M 0x6e
+
+enum ieee80211_std {
+ IEEE80211B = 0x01,
+ IEEE80211A = 0x02,
+ IEEE80211G = 0x04,
+};
+
+#endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
new file mode 100644
index 00000000000..3bdc54d128d
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -0,0 +1,1057 @@
+/* zd_mac.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/usb.h>
+#include <linux/jiffies.h>
+#include <net/ieee80211_radiotap.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+#include "zd_netdev.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+static void ieee_init(struct ieee80211_device *ieee);
+static void softmac_init(struct ieee80211softmac_device *sm);
+
+int zd_mac_init(struct zd_mac *mac,
+ struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+
+ memset(mac, 0, sizeof(*mac));
+ spin_lock_init(&mac->lock);
+ mac->netdev = netdev;
+
+ ieee_init(ieee);
+ softmac_init(ieee80211_priv(netdev));
+ zd_chip_init(&mac->chip, netdev, intf);
+ return 0;
+}
+
+static int reset_channel(struct zd_mac *mac)
+{
+ int r;
+ unsigned long flags;
+ const struct channel_range *range;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ range = zd_channel_range(mac->regdomain);
+ if (!range->start) {
+ r = -EINVAL;
+ goto out;
+ }
+ mac->requested_channel = range->start;
+ r = 0;
+out:
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return r;
+}
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type)
+{
+ int r;
+ struct zd_chip *chip = &mac->chip;
+ u8 addr[ETH_ALEN];
+ u8 default_regdomain;
+
+ r = zd_chip_enable_int(chip);
+ if (r)
+ goto out;
+ r = zd_chip_init_hw(chip, device_type);
+ if (r)
+ goto disable_int;
+
+ zd_get_e2p_mac_addr(chip, addr);
+ r = zd_write_mac_addr(chip, addr);
+ if (r)
+ goto disable_int;
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_read_regdomain(chip, &default_regdomain);
+ if (r)
+ goto disable_int;
+ if (!zd_regdomain_supported(default_regdomain)) {
+ dev_dbg_f(zd_mac_dev(mac),
+ "Regulatory Domain %#04x is not supported.\n",
+ default_regdomain);
+ r = -EINVAL;
+ goto disable_int;
+ }
+ spin_lock_irq(&mac->lock);
+ mac->regdomain = mac->default_regdomain = default_regdomain;
+ spin_unlock_irq(&mac->lock);
+ r = reset_channel(mac);
+ if (r)
+ goto disable_int;
+
+ r = zd_set_encryption_type(chip, NO_WEP);
+ if (r)
+ goto disable_int;
+
+ r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain);
+ if (r)
+ goto disable_int;
+
+ r = 0;
+disable_int:
+ zd_chip_disable_int(chip);
+out:
+ return r;
+}
+
+void zd_mac_clear(struct zd_mac *mac)
+{
+ /* Aquire the lock. */
+ spin_lock(&mac->lock);
+ spin_unlock(&mac->lock);
+ zd_chip_clear(&mac->chip);
+ memset(mac, 0, sizeof(*mac));
+}
+
+static int reset_mode(struct zd_mac *mac)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct zd_ioreq32 ioreqs[3] = {
+ { CR_RX_FILTER, RX_FILTER_BEACON|RX_FILTER_PROBE_RESPONSE|
+ RX_FILTER_AUTH|RX_FILTER_ASSOC_RESPONSE },
+ { CR_SNIFFER_ON, 0U },
+ { CR_ENCRYPTION_TYPE, NO_WEP },
+ };
+
+ if (ieee->iw_mode == IW_MODE_MONITOR) {
+ ioreqs[0].value = 0xffffffff;
+ ioreqs[1].value = 0x1;
+ ioreqs[2].value = ENC_SNIFFER;
+ }
+
+ return zd_iowrite32a(&mac->chip, ioreqs, 3);
+}
+
+int zd_mac_open(struct net_device *netdev)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+ int r;
+
+ r = zd_chip_enable_int(chip);
+ if (r < 0)
+ goto out;
+
+ r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
+ if (r < 0)
+ goto disable_int;
+ r = reset_mode(mac);
+ if (r)
+ goto disable_int;
+ r = zd_chip_switch_radio_on(chip);
+ if (r < 0)
+ goto disable_int;
+ r = zd_chip_set_channel(chip, mac->requested_channel);
+ if (r < 0)
+ goto disable_radio;
+ r = zd_chip_enable_rx(chip);
+ if (r < 0)
+ goto disable_radio;
+ r = zd_chip_enable_hwint(chip);
+ if (r < 0)
+ goto disable_rx;
+
+ ieee80211softmac_start(netdev);
+ return 0;
+disable_rx:
+ zd_chip_disable_rx(chip);
+disable_radio:
+ zd_chip_switch_radio_off(chip);
+disable_int:
+ zd_chip_disable_int(chip);
+out:
+ return r;
+}
+
+int zd_mac_stop(struct net_device *netdev)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+
+ netif_stop_queue(netdev);
+
+ /*
+ * The order here deliberately is a little different from the open()
+ * method, since we need to make sure there is no opportunity for RX
+ * frames to be processed by softmac after we have stopped it.
+ */
+
+ zd_chip_disable_rx(chip);
+ ieee80211softmac_stop(netdev);
+
+ zd_chip_disable_hwint(chip);
+ zd_chip_switch_radio_off(chip);
+ zd_chip_disable_int(chip);
+
+ return 0;
+}
+
+int zd_mac_set_mac_address(struct net_device *netdev, void *p)
+{
+ int r;
+ unsigned long flags;
+ struct sockaddr *addr = p;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ dev_dbg_f(zd_mac_dev(mac),
+ "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+
+ r = zd_write_mac_addr(chip, addr->sa_data);
+ if (r)
+ return r;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
+ spin_unlock_irqrestore(&mac->lock, flags);
+
+ return 0;
+}
+
+int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
+{
+ int r;
+ u8 channel;
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ if (regdomain == 0) {
+ regdomain = mac->default_regdomain;
+ }
+ if (!zd_regdomain_supported(regdomain)) {
+ spin_unlock_irq(&mac->lock);
+ return -EINVAL;
+ }
+ mac->regdomain = regdomain;
+ channel = mac->requested_channel;
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain);
+ if (r)
+ return r;
+ if (!zd_regdomain_supports_channel(regdomain, channel)) {
+ r = reset_channel(mac);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+u8 zd_mac_get_regdomain(struct zd_mac *mac)
+{
+ unsigned long flags;
+ u8 regdomain;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ regdomain = mac->regdomain;
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return regdomain;
+}
+
+static void set_channel(struct net_device *netdev, u8 channel)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+
+ dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel);
+
+ zd_chip_set_channel(&mac->chip, channel);
+}
+
+/* TODO: Should not work in Managed mode. */
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel)
+{
+ unsigned long lock_flags;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ if (ieee->iw_mode == IW_MODE_INFRA)
+ return -EPERM;
+
+ spin_lock_irqsave(&mac->lock, lock_flags);
+ if (!zd_regdomain_supports_channel(mac->regdomain, channel)) {
+ spin_unlock_irqrestore(&mac->lock, lock_flags);
+ return -EINVAL;
+ }
+ mac->requested_channel = channel;
+ spin_unlock_irqrestore(&mac->lock, lock_flags);
+ if (netif_running(mac->netdev))
+ return zd_chip_set_channel(&mac->chip, channel);
+ else
+ return 0;
+}
+
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ *channel = zd_chip_get_channel(&mac->chip);
+ if (ieee->iw_mode != IW_MODE_INFRA) {
+ spin_lock_irq(&mac->lock);
+ *flags = *channel == mac->requested_channel ?
+ MAC_FIXED_CHANNEL : 0;
+ spin_unlock(&mac->lock);
+ } else {
+ *flags = 0;
+ }
+ dev_dbg_f(zd_mac_dev(mac), "channel %u flags %u\n", *channel, *flags);
+ return 0;
+}
+
+/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
+static u8 cs_typed_rate(u8 cs_rate)
+{
+ static const u8 typed_rates[16] = {
+ [ZD_CS_CCK_RATE_1M] = ZD_CS_CCK|ZD_CS_CCK_RATE_1M,
+ [ZD_CS_CCK_RATE_2M] = ZD_CS_CCK|ZD_CS_CCK_RATE_2M,
+ [ZD_CS_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CS_CCK_RATE_5_5M,
+ [ZD_CS_CCK_RATE_11M] = ZD_CS_CCK|ZD_CS_CCK_RATE_11M,
+ [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
+ [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
+ [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
+ [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
+ [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
+ [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
+ [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
+ [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
+ };
+
+ ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
+ return typed_rates[cs_rate & ZD_CS_RATE_MASK];
+}
+
+/* Fallback to lowest rate, if rate is unknown. */
+static u8 rate_to_cs_rate(u8 rate)
+{
+ switch (rate) {
+ case IEEE80211_CCK_RATE_2MB:
+ return ZD_CS_CCK_RATE_2M;
+ case IEEE80211_CCK_RATE_5MB:
+ return ZD_CS_CCK_RATE_5_5M;
+ case IEEE80211_CCK_RATE_11MB:
+ return ZD_CS_CCK_RATE_11M;
+ case IEEE80211_OFDM_RATE_6MB:
+ return ZD_OFDM_RATE_6M;
+ case IEEE80211_OFDM_RATE_9MB:
+ return ZD_OFDM_RATE_9M;
+ case IEEE80211_OFDM_RATE_12MB:
+ return ZD_OFDM_RATE_12M;
+ case IEEE80211_OFDM_RATE_18MB:
+ return ZD_OFDM_RATE_18M;
+ case IEEE80211_OFDM_RATE_24MB:
+ return ZD_OFDM_RATE_24M;
+ case IEEE80211_OFDM_RATE_36MB:
+ return ZD_OFDM_RATE_36M;
+ case IEEE80211_OFDM_RATE_48MB:
+ return ZD_OFDM_RATE_48M;
+ case IEEE80211_OFDM_RATE_54MB:
+ return ZD_OFDM_RATE_54M;
+ }
+ return ZD_CS_CCK_RATE_1M;
+}
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
+{
+ struct ieee80211_device *ieee;
+
+ switch (mode) {
+ case IW_MODE_AUTO:
+ case IW_MODE_ADHOC:
+ case IW_MODE_INFRA:
+ mac->netdev->type = ARPHRD_ETHER;
+ break;
+ case IW_MODE_MONITOR:
+ mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
+ break;
+ default:
+ dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode);
+ return -EINVAL;
+ }
+
+ ieee = zd_mac_to_ieee80211(mac);
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&ieee->lock);
+ ieee->iw_mode = mode;
+ spin_unlock_irq(&ieee->lock);
+
+ if (netif_running(mac->netdev))
+ return reset_mode(mac);
+
+ return 0;
+}
+
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode)
+{
+ unsigned long flags;
+ struct ieee80211_device *ieee;
+
+ ieee = zd_mac_to_ieee80211(mac);
+ spin_lock_irqsave(&ieee->lock, flags);
+ *mode = ieee->iw_mode;
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ return 0;
+}
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
+{
+ int i;
+ const struct channel_range *channel_range;
+ u8 regdomain;
+
+ memset(range, 0, sizeof(*range));
+
+ /* FIXME: Not so important and depends on the mode. For 802.11g
+ * usually this value is used. It seems to be that Bit/s number is
+ * given here.
+ */
+ range->throughput = 27 * 1000 * 1000;
+
+ range->max_qual.qual = 100;
+ range->max_qual.level = 100;
+
+ /* FIXME: Needs still to be tuned. */
+ range->avg_qual.qual = 71;
+ range->avg_qual.level = 80;
+
+ /* FIXME: depends on standard? */
+ range->min_rts = 256;
+ range->max_rts = 2346;
+
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->max_encoding_tokens = WEP_KEYS;
+ range->num_encoding_sizes = 2;
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = WEP_KEY_LEN;
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 20;
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ regdomain = mac->regdomain;
+ spin_unlock_irq(&mac->lock);
+ channel_range = zd_channel_range(regdomain);
+
+ range->num_channels = channel_range->end - channel_range->start;
+ range->old_num_channels = range->num_channels;
+ range->num_frequency = range->num_channels;
+ range->old_num_frequency = range->num_frequency;
+
+ for (i = 0; i < range->num_frequency; i++) {
+ struct iw_freq *freq = &range->freq[i];
+ freq->i = channel_range->start + i;
+ zd_channel_to_freq(freq, freq->i);
+ }
+
+ return 0;
+}
+
+static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length)
+{
+ static const u8 rate_divisor[] = {
+ [ZD_CS_CCK_RATE_1M] = 1,
+ [ZD_CS_CCK_RATE_2M] = 2,
+ [ZD_CS_CCK_RATE_5_5M] = 11, /* bits must be doubled */
+ [ZD_CS_CCK_RATE_11M] = 11,
+ [ZD_OFDM_RATE_6M] = 6,
+ [ZD_OFDM_RATE_9M] = 9,
+ [ZD_OFDM_RATE_12M] = 12,
+ [ZD_OFDM_RATE_18M] = 18,
+ [ZD_OFDM_RATE_24M] = 24,
+ [ZD_OFDM_RATE_36M] = 36,
+ [ZD_OFDM_RATE_48M] = 48,
+ [ZD_OFDM_RATE_54M] = 54,
+ };
+
+ u32 bits = (u32)tx_length * 8;
+ u32 divisor;
+
+ divisor = rate_divisor[cs_rate];
+ if (divisor == 0)
+ return -EINVAL;
+
+ switch (cs_rate) {
+ case ZD_CS_CCK_RATE_5_5M:
+ bits = (2*bits) + 10; /* round up to the next integer */
+ break;
+ case ZD_CS_CCK_RATE_11M:
+ if (service) {
+ u32 t = bits % 11;
+ *service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+ if (0 < t && t <= 3) {
+ *service |= ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+ }
+ }
+ bits += 10; /* round up to the next integer */
+ break;
+ }
+
+ return bits/divisor;
+}
+
+enum {
+ R2M_SHORT_PREAMBLE = 0x01,
+ R2M_11A = 0x02,
+};
+
+static u8 cs_rate_to_modulation(u8 cs_rate, int flags)
+{
+ u8 modulation;
+
+ modulation = cs_typed_rate(cs_rate);
+ if (flags & R2M_SHORT_PREAMBLE) {
+ switch (ZD_CS_RATE(modulation)) {
+ case ZD_CS_CCK_RATE_2M:
+ case ZD_CS_CCK_RATE_5_5M:
+ case ZD_CS_CCK_RATE_11M:
+ modulation |= ZD_CS_CCK_PREA_SHORT;
+ return modulation;
+ }
+ }
+ if (flags & R2M_11A) {
+ if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
+ modulation |= ZD_CS_OFDM_MODE_11A;
+ }
+ return modulation;
+}
+
+static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
+ u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
+ u8 rate, cs_rate;
+ int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
+
+ /* FIXME: 802.11a? short preamble? */
+ rate = ieee80211softmac_suggest_txrate(softmac,
+ is_multicast_ether_addr(hdr->addr1), is_mgt);
+
+ cs_rate = rate_to_cs_rate(rate);
+ cs->modulation = cs_rate_to_modulation(cs_rate, 0);
+}
+
+static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
+ struct ieee80211_hdr_4addr *header)
+{
+ unsigned int tx_length = le16_to_cpu(cs->tx_length);
+ u16 fctl = le16_to_cpu(header->frame_ctl);
+ u16 ftype = WLAN_FC_GET_TYPE(fctl);
+ u16 stype = WLAN_FC_GET_STYPE(fctl);
+
+ /*
+ * CONTROL:
+ * - start at 0x00
+ * - if fragment 0, enable bit 0
+ * - if backoff needed, enable bit 0
+ * - if burst (backoff not needed) disable bit 0
+ * - if multicast, enable bit 1
+ * - if PS-POLL frame, enable bit 2
+ * - if in INDEPENDENT_BSS mode and zd1205_DestPowerSave, then enable
+ * bit 4 (FIXME: wtf)
+ * - if frag_len > RTS threshold, set bit 5 as long if it isnt
+ * multicast or mgt
+ * - if bit 5 is set, and we are in OFDM mode, unset bit 5 and set bit
+ * 7
+ */
+
+ cs->control = 0;
+
+ /* First fragment */
+ if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0)
+ cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
+
+ /* Multicast */
+ if (is_multicast_ether_addr(header->addr1))
+ cs->control |= ZD_CS_MULTICAST;
+
+ /* PS-POLL */
+ if (stype == IEEE80211_STYPE_PSPOLL)
+ cs->control |= ZD_CS_PS_POLL_FRAME;
+
+ if (!is_multicast_ether_addr(header->addr1) &&
+ ftype != IEEE80211_FTYPE_MGMT &&
+ tx_length > zd_netdev_ieee80211(mac->netdev)->rts)
+ {
+ /* FIXME: check the logic */
+ if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM) {
+ /* 802.11g */
+ cs->control |= ZD_CS_SELF_CTS;
+ } else { /* 802.11b */
+ cs->control |= ZD_CS_RTS;
+ }
+ }
+
+ /* FIXME: Management frame? */
+}
+
+static int fill_ctrlset(struct zd_mac *mac,
+ struct ieee80211_txb *txb,
+ int frag_num)
+{
+ int r;
+ struct sk_buff *skb = txb->fragments[frag_num];
+ struct ieee80211_hdr_4addr *hdr =
+ (struct ieee80211_hdr_4addr *) skb->data;
+ unsigned int frag_len = skb->len + IEEE80211_FCS_LEN;
+ unsigned int next_frag_len;
+ unsigned int packet_length;
+ struct zd_ctrlset *cs = (struct zd_ctrlset *)
+ skb_push(skb, sizeof(struct zd_ctrlset));
+
+ if (frag_num+1 < txb->nr_frags) {
+ next_frag_len = txb->fragments[frag_num+1]->len +
+ IEEE80211_FCS_LEN;
+ } else {
+ next_frag_len = 0;
+ }
+ ZD_ASSERT(frag_len <= 0xffff);
+ ZD_ASSERT(next_frag_len <= 0xffff);
+
+ cs_set_modulation(mac, cs, hdr);
+
+ cs->tx_length = cpu_to_le16(frag_len);
+
+ cs_set_control(mac, cs, hdr);
+
+ packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
+ ZD_ASSERT(packet_length <= 0xffff);
+ /* ZD1211B: Computing the length difference this way, gives us
+ * flexibility to compute the packet length.
+ */
+ cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ?
+ packet_length - frag_len : packet_length);
+
+ /*
+ * CURRENT LENGTH:
+ * - transmit frame length in microseconds
+ * - seems to be derived from frame length
+ * - see Cal_Us_Service() in zdinlinef.h
+ * - if macp->bTxBurstEnable is enabled, then multiply by 4
+ * - bTxBurstEnable is never set in the vendor driver
+ *
+ * SERVICE:
+ * - "for PLCP configuration"
+ * - always 0 except in some situations at 802.11b 11M
+ * - see line 53 of zdinlinef.h
+ */
+ cs->service = 0;
+ r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+ le16_to_cpu(cs->tx_length));
+ if (r < 0)
+ return r;
+ cs->current_length = cpu_to_le16(r);
+
+ if (next_frag_len == 0) {
+ cs->next_frame_length = 0;
+ } else {
+ r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+ next_frag_len);
+ if (r < 0)
+ return r;
+ cs->next_frame_length = cpu_to_le16(r);
+ }
+
+ return 0;
+}
+
+static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
+{
+ int i, r;
+
+ for (i = 0; i < txb->nr_frags; i++) {
+ struct sk_buff *skb = txb->fragments[i];
+
+ r = fill_ctrlset(mac, txb, i);
+ if (r)
+ return r;
+ r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
+ if (r)
+ return r;
+ }
+
+ /* FIXME: shouldn't this be handled by the upper layers? */
+ mac->netdev->trans_start = jiffies;
+
+ ieee80211_txb_free(txb);
+ return 0;
+}
+
+struct zd_rt_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ u8 rt_flags;
+ u16 rt_channel;
+ u16 rt_chbitmask;
+ u16 rt_rate;
+};
+
+static void fill_rt_header(void *buffer, struct zd_mac *mac,
+ const struct ieee80211_rx_stats *stats,
+ const struct rx_status *status)
+{
+ struct zd_rt_hdr *hdr = buffer;
+
+ hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ hdr->rt_hdr.it_pad = 0;
+ hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr));
+ hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_RATE));
+
+ hdr->rt_flags = 0;
+ if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256))
+ hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ /* FIXME: 802.11a */
+ hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz(
+ _zd_chip_get_channel(&mac->chip)));
+ hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ |
+ ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) ==
+ ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK));
+
+ hdr->rt_rate = stats->rate / 5;
+}
+
+/* Returns 1 if the data packet is for us and 0 otherwise. */
+static int is_data_packet_for_us(struct ieee80211_device *ieee,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ struct net_device *netdev = ieee->dev;
+ u16 fc = le16_to_cpu(hdr->frame_ctl);
+
+ ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA);
+
+ switch (ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
+ memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+ return 0;
+ break;
+ case IW_MODE_AUTO:
+ case IW_MODE_INFRA:
+ if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
+ IEEE80211_FCTL_FROMDS ||
+ memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+ return 0;
+ break;
+ default:
+ ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR);
+ return 0;
+ }
+
+ return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+ is_multicast_ether_addr(hdr->addr1) ||
+ (netdev->flags & IFF_PROMISC);
+}
+
+/* Filters receiving packets. If it returns 1 send it to ieee80211_rx, if 0
+ * return. If an error is detected -EINVAL is returned. ieee80211_rx_mgt() is
+ * called here.
+ *
+ * It has been based on ieee80211_rx_any.
+ */
+static int filter_rx(struct ieee80211_device *ieee,
+ const u8 *buffer, unsigned int length,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ieee80211_hdr_4addr *hdr;
+ u16 fc;
+
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ return 1;
+
+ hdr = (struct ieee80211_hdr_4addr *)buffer;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ if ((fc & IEEE80211_FCTL_VERS) != 0)
+ return -EINVAL;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case IEEE80211_FTYPE_MGMT:
+ if (length < sizeof(struct ieee80211_hdr_3addr))
+ return -EINVAL;
+ ieee80211_rx_mgt(ieee, hdr, stats);
+ return 0;
+ case IEEE80211_FTYPE_CTL:
+ /* Ignore invalid short buffers */
+ return 0;
+ case IEEE80211_FTYPE_DATA:
+ if (length < sizeof(struct ieee80211_hdr_3addr))
+ return -EINVAL;
+ return is_data_packet_for_us(ieee, hdr);
+ }
+
+ return -EINVAL;
+}
+
+static void update_qual_rssi(struct zd_mac *mac, u8 qual_percent, u8 rssi)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ mac->qual_average = (7 * mac->qual_average + qual_percent) / 8;
+ mac->rssi_average = (7 * mac->rssi_average + rssi) / 8;
+ spin_unlock_irqrestore(&mac->lock, flags);
+}
+
+static int fill_rx_stats(struct ieee80211_rx_stats *stats,
+ const struct rx_status **pstatus,
+ struct zd_mac *mac,
+ const u8 *buffer, unsigned int length)
+{
+ const struct rx_status *status;
+
+ *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+ if (status->frame_status & ZD_RX_ERROR) {
+ /* FIXME: update? */
+ return -EINVAL;
+ }
+ memset(stats, 0, sizeof(struct ieee80211_rx_stats));
+ stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
+ + sizeof(struct rx_status));
+ /* FIXME: 802.11a */
+ stats->freq = IEEE80211_24GHZ_BAND;
+ stats->received_channel = _zd_chip_get_channel(&mac->chip);
+ stats->rssi = zd_rx_strength_percent(status->signal_strength);
+ stats->signal = zd_rx_qual_percent(buffer,
+ length - sizeof(struct rx_status),
+ status);
+ stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL;
+ stats->rate = zd_rx_rate(buffer, status);
+ if (stats->rate)
+ stats->mask |= IEEE80211_STATMASK_RATE;
+
+ update_qual_rssi(mac, stats->signal, stats->rssi);
+ return 0;
+}
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+ int r;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct ieee80211_rx_stats stats;
+ const struct rx_status *status;
+ struct sk_buff *skb;
+
+ if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+ IEEE80211_FCS_LEN + sizeof(struct rx_status))
+ return -EINVAL;
+
+ r = fill_rx_stats(&stats, &status, mac, buffer, length);
+ if (r)
+ return r;
+
+ length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
+ sizeof(struct rx_status);
+ buffer += ZD_PLCP_HEADER_SIZE;
+
+ r = filter_rx(ieee, buffer, length, &stats);
+ if (r <= 0)
+ return r;
+
+ skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+ if (!skb)
+ return -ENOMEM;
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+ &stats, status);
+ memcpy(skb_put(skb, length), buffer, length);
+
+ r = ieee80211_rx(ieee, skb, &stats);
+ if (!r) {
+ ZD_ASSERT(in_irq());
+ dev_kfree_skb_irq(skb);
+ }
+ return 0;
+}
+
+static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev,
+ int pri)
+{
+ return zd_mac_tx(zd_netdev_mac(netdev), txb, pri);
+}
+
+static void set_security(struct net_device *netdev,
+ struct ieee80211_security *sec)
+{
+ struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+ struct ieee80211_security *secinfo = &ieee->sec;
+ int keyidx;
+
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+
+ for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
+ if (sec->flags & (1<<keyidx)) {
+ secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
+ secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
+ memcpy(secinfo->keys[keyidx], sec->keys[keyidx],
+ SCM_KEY_LEN);
+ }
+
+ if (sec->flags & SEC_ACTIVE_KEY) {
+ secinfo->active_key = sec->active_key;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .active_key = %d\n", sec->active_key);
+ }
+ if (sec->flags & SEC_UNICAST_GROUP) {
+ secinfo->unicast_uses_group = sec->unicast_uses_group;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .unicast_uses_group = %d\n",
+ sec->unicast_uses_group);
+ }
+ if (sec->flags & SEC_LEVEL) {
+ secinfo->level = sec->level;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .level = %d\n", sec->level);
+ }
+ if (sec->flags & SEC_ENABLED) {
+ secinfo->enabled = sec->enabled;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .enabled = %d\n", sec->enabled);
+ }
+ if (sec->flags & SEC_ENCRYPT) {
+ secinfo->encrypt = sec->encrypt;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .encrypt = %d\n", sec->encrypt);
+ }
+ if (sec->flags & SEC_AUTH_MODE) {
+ secinfo->auth_mode = sec->auth_mode;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .auth_mode = %d\n", sec->auth_mode);
+ }
+}
+
+static void ieee_init(struct ieee80211_device *ieee)
+{
+ ieee->mode = IEEE_B | IEEE_G;
+ ieee->freq_band = IEEE80211_24GHZ_BAND;
+ ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION;
+ ieee->tx_headroom = sizeof(struct zd_ctrlset);
+ ieee->set_security = set_security;
+ ieee->hard_start_xmit = netdev_tx;
+
+ /* Software encryption/decryption for now */
+ ieee->host_build_iv = 0;
+ ieee->host_encrypt = 1;
+ ieee->host_decrypt = 1;
+
+ /* FIXME: default to managed mode, until ieee80211 and zd1211rw can
+ * correctly support AUTO */
+ ieee->iw_mode = IW_MODE_INFRA;
+}
+
+static void softmac_init(struct ieee80211softmac_device *sm)
+{
+ sm->set_channel = set_channel;
+}
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev)
+{
+ struct zd_mac *mac = zd_netdev_mac(ndev);
+ struct iw_statistics *iw_stats = &mac->iw_stats;
+
+ memset(iw_stats, 0, sizeof(struct iw_statistics));
+ /* We are not setting the status, because ieee->state is not updated
+ * at all and this driver doesn't track authentication state.
+ */
+ spin_lock_irq(&mac->lock);
+ iw_stats->qual.qual = mac->qual_average;
+ iw_stats->qual.level = mac->rssi_average;
+ iw_stats->qual.updated = IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED|
+ IW_QUAL_NOISE_INVALID;
+ spin_unlock_irq(&mac->lock);
+ /* TODO: update counter */
+ return iw_stats;
+}
+
+#ifdef DEBUG
+static const char* decryption_types[] = {
+ [ZD_RX_NO_WEP] = "none",
+ [ZD_RX_WEP64] = "WEP64",
+ [ZD_RX_TKIP] = "TKIP",
+ [ZD_RX_AES] = "AES",
+ [ZD_RX_WEP128] = "WEP128",
+ [ZD_RX_WEP256] = "WEP256",
+};
+
+static const char *decryption_type_string(u8 type)
+{
+ const char *s;
+
+ if (type < ARRAY_SIZE(decryption_types)) {
+ s = decryption_types[type];
+ } else {
+ s = NULL;
+ }
+ return s ? s : "unknown";
+}
+
+static int is_ofdm(u8 frame_status)
+{
+ return (frame_status & ZD_RX_OFDM);
+}
+
+void zd_dump_rx_status(const struct rx_status *status)
+{
+ const char* modulation;
+ u8 quality;
+
+ if (is_ofdm(status->frame_status)) {
+ modulation = "ofdm";
+ quality = status->signal_quality_ofdm;
+ } else {
+ modulation = "cck";
+ quality = status->signal_quality_cck;
+ }
+ pr_debug("rx status %s strength %#04x qual %#04x decryption %s\n",
+ modulation, status->signal_strength, quality,
+ decryption_type_string(status->decryption_type));
+ if (status->frame_status & ZD_RX_ERROR) {
+ pr_debug("rx error %s%s%s%s%s%s\n",
+ (status->frame_status & ZD_RX_TIMEOUT_ERROR) ?
+ "timeout " : "",
+ (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) ?
+ "fifo " : "",
+ (status->frame_status & ZD_RX_DECRYPTION_ERROR) ?
+ "decryption " : "",
+ (status->frame_status & ZD_RX_CRC32_ERROR) ?
+ "crc32 " : "",
+ (status->frame_status & ZD_RX_NO_ADDR1_MATCH_ERROR) ?
+ "addr1 " : "",
+ (status->frame_status & ZD_RX_CRC16_ERROR) ?
+ "crc16" : "");
+ }
+}
+#endif /* DEBUG */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
new file mode 100644
index 00000000000..71e382c589e
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -0,0 +1,190 @@
+/* zd_mac.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_MAC_H
+#define _ZD_MAC_H
+
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+
+#include "zd_chip.h"
+#include "zd_netdev.h"
+
+struct zd_ctrlset {
+ u8 modulation;
+ __le16 tx_length;
+ u8 control;
+ /* stores only the difference to tx_length on ZD1211B */
+ __le16 packet_length;
+ __le16 current_length;
+ u8 service;
+ __le16 next_frame_length;
+} __attribute__((packed));
+
+#define ZD_CS_RESERVED_SIZE 25
+
+/* zd_crtlset field modulation */
+#define ZD_CS_RATE_MASK 0x0f
+#define ZD_CS_TYPE_MASK 0x10
+#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
+#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
+
+#define ZD_CS_CCK 0x00
+#define ZD_CS_OFDM 0x10
+
+#define ZD_CS_CCK_RATE_1M 0x00
+#define ZD_CS_CCK_RATE_2M 0x01
+#define ZD_CS_CCK_RATE_5_5M 0x02
+#define ZD_CS_CCK_RATE_11M 0x03
+/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+ */
+
+/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
+#define ZD_CS_CCK_PREA_LONG 0x00
+#define ZD_CS_CCK_PREA_SHORT 0x20
+#define ZD_CS_OFDM_MODE_11G 0x00
+#define ZD_CS_OFDM_MODE_11A 0x20
+
+/* zd_ctrlset control field */
+#define ZD_CS_NEED_RANDOM_BACKOFF 0x01
+#define ZD_CS_MULTICAST 0x02
+
+#define ZD_CS_FRAME_TYPE_MASK 0x0c
+#define ZD_CS_DATA_FRAME 0x00
+#define ZD_CS_PS_POLL_FRAME 0x04
+#define ZD_CS_MANAGEMENT_FRAME 0x08
+#define ZD_CS_NO_SEQUENCE_CTL_FRAME 0x0c
+
+#define ZD_CS_WAKE_DESTINATION 0x10
+#define ZD_CS_RTS 0x20
+#define ZD_CS_ENCRYPT 0x40
+#define ZD_CS_SELF_CTS 0x80
+
+/* Incoming frames are prepended by a PLCP header */
+#define ZD_PLCP_HEADER_SIZE 5
+
+struct rx_length_info {
+ __le16 length[3];
+ __le16 tag;
+} __attribute__((packed));
+
+#define RX_LENGTH_INFO_TAG 0x697e
+
+struct rx_status {
+ /* rssi */
+ u8 signal_strength;
+ u8 signal_quality_cck;
+ u8 signal_quality_ofdm;
+ u8 decryption_type;
+ u8 frame_status;
+} __attribute__((packed));
+
+/* rx_status field decryption_type */
+#define ZD_RX_NO_WEP 0
+#define ZD_RX_WEP64 1
+#define ZD_RX_TKIP 2
+#define ZD_RX_AES 4
+#define ZD_RX_WEP128 5
+#define ZD_RX_WEP256 6
+
+/* rx_status field frame_status */
+#define ZD_RX_FRAME_MODULATION_MASK 0x01
+#define ZD_RX_CCK 0x00
+#define ZD_RX_OFDM 0x01
+
+#define ZD_RX_TIMEOUT_ERROR 0x02
+#define ZD_RX_FIFO_OVERRUN_ERROR 0x04
+#define ZD_RX_DECRYPTION_ERROR 0x08
+#define ZD_RX_CRC32_ERROR 0x10
+#define ZD_RX_NO_ADDR1_MATCH_ERROR 0x20
+#define ZD_RX_CRC16_ERROR 0x40
+#define ZD_RX_ERROR 0x80
+
+enum mac_flags {
+ MAC_FIXED_CHANNEL = 0x01,
+};
+
+struct zd_mac {
+ struct net_device *netdev;
+ struct zd_chip chip;
+ spinlock_t lock;
+ /* Unlocked reading possible */
+ struct iw_statistics iw_stats;
+ u8 qual_average;
+ u8 rssi_average;
+ u8 regdomain;
+ u8 default_regdomain;
+ u8 requested_channel;
+};
+
+static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
+{
+ return zd_netdev_ieee80211(mac->netdev);
+}
+
+static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev)
+{
+ return ieee80211softmac_priv(netdev);
+}
+
+static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
+{
+ return container_of(chip, struct zd_mac, chip);
+}
+
+static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb)
+{
+ return zd_chip_to_mac(zd_usb_to_chip(usb));
+}
+
+#define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip))
+
+int zd_mac_init(struct zd_mac *mac,
+ struct net_device *netdev,
+ struct usb_interface *intf);
+void zd_mac_clear(struct zd_mac *mac);
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type);
+
+int zd_mac_open(struct net_device *netdev);
+int zd_mac_stop(struct net_device *netdev);
+int zd_mac_set_mac_address(struct net_device *dev, void *p);
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
+
+int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
+u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
+
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel);
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags);
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode);
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode);
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range);
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev);
+
+#ifdef DEBUG
+void zd_dump_rx_status(const struct rx_status *status);
+#else
+#define zd_dump_rx_status(status)
+#endif /* DEBUG */
+
+#endif /* _ZD_MAC_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
new file mode 100644
index 00000000000..9df232c2c86
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -0,0 +1,267 @@
+/* zd_netdev.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+#include <net/ieee80211softmac_wx.h>
+#include <net/iw_handler.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+
+/* Region 0 means reset regdomain to default. */
+static int zd_set_regdomain(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ const u8 *regdomain = (u8 *)req;
+ return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain);
+}
+
+static int zd_get_regdomain(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ u8 *regdomain = (u8 *)req;
+ if (!regdomain)
+ return -EINVAL;
+ *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev));
+ return 0;
+}
+
+static const struct iw_priv_args zd_priv_args[] = {
+ {
+ .cmd = ZD_PRIV_SET_REGDOMAIN,
+ .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ .name = "set_regdomain",
+ },
+ {
+ .cmd = ZD_PRIV_GET_REGDOMAIN,
+ .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ .name = "get_regdomain",
+ },
+};
+
+#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV]
+
+static const iw_handler zd_priv_handler[] = {
+ PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain,
+ PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain,
+};
+
+static int iw_get_name(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ /* FIXME: check whether 802.11a will also supported, add also
+ * zd1211B, if we support it.
+ */
+ strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
+ return 0;
+}
+
+static int iw_set_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ int r;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct iw_freq *freq = &req->freq;
+ u8 channel;
+
+ r = zd_find_channel(&channel, freq);
+ if (r < 0)
+ return r;
+ r = zd_mac_request_channel(mac, channel);
+ return r;
+}
+
+static int iw_get_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ int r;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct iw_freq *freq = &req->freq;
+ u8 channel;
+ u8 flags;
+
+ r = zd_mac_get_channel(mac, &channel, &flags);
+ if (r)
+ return r;
+
+ freq->flags = (flags & MAC_FIXED_CHANNEL) ?
+ IW_FREQ_FIXED : IW_FREQ_AUTO;
+ dev_dbg_f(zd_mac_dev(mac), "channel %s\n",
+ (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto");
+ return zd_channel_to_freq(freq, channel);
+}
+
+static int iw_set_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
+}
+
+static int iw_get_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
+}
+
+static int iw_get_range(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ struct iw_range *range = (struct iw_range *)extra;
+
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+ req->data.length = sizeof(*range);
+ return zd_mac_get_range(zd_netdev_mac(netdev), range);
+}
+
+static int iw_set_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_get_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_set_encodeext(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_get_encodeext(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+#define WX(x) [(x)-SIOCIWFIRST]
+
+static const iw_handler zd_standard_iw_handlers[] = {
+ WX(SIOCGIWNAME) = iw_get_name,
+ WX(SIOCSIWFREQ) = iw_set_freq,
+ WX(SIOCGIWFREQ) = iw_get_freq,
+ WX(SIOCSIWMODE) = iw_set_mode,
+ WX(SIOCGIWMODE) = iw_get_mode,
+ WX(SIOCGIWRANGE) = iw_get_range,
+ WX(SIOCSIWENCODE) = iw_set_encode,
+ WX(SIOCGIWENCODE) = iw_get_encode,
+ WX(SIOCSIWENCODEEXT) = iw_set_encodeext,
+ WX(SIOCGIWENCODEEXT) = iw_get_encodeext,
+ WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
+ WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
+ WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
+ WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
+ WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
+ WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
+ WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
+ WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
+ WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
+ WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
+ WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
+ WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
+ WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme,
+};
+
+static const struct iw_handler_def iw_handler_def = {
+ .standard = zd_standard_iw_handlers,
+ .num_standard = ARRAY_SIZE(zd_standard_iw_handlers),
+ .private = zd_priv_handler,
+ .num_private = ARRAY_SIZE(zd_priv_handler),
+ .private_args = zd_priv_args,
+ .num_private_args = ARRAY_SIZE(zd_priv_args),
+ .get_wireless_stats = zd_mac_get_wireless_stats,
+};
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf)
+{
+ int r;
+ struct net_device *netdev;
+ struct zd_mac *mac;
+
+ netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
+ if (!netdev) {
+ dev_dbg_f(&intf->dev, "out of memory\n");
+ return NULL;
+ }
+
+ mac = zd_netdev_mac(netdev);
+ r = zd_mac_init(mac, netdev, intf);
+ if (r) {
+ usb_set_intfdata(intf, NULL);
+ free_ieee80211(netdev);
+ return NULL;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
+ dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
+
+ netdev->open = zd_mac_open;
+ netdev->stop = zd_mac_stop;
+ /* netdev->get_stats = */
+ /* netdev->set_multicast_list = */
+ netdev->set_mac_address = zd_mac_set_mac_address;
+ netdev->wireless_handlers = &iw_handler_def;
+ /* netdev->ethtool_ops = */
+
+ return netdev;
+}
+
+void zd_netdev_free(struct net_device *netdev)
+{
+ if (!netdev)
+ return;
+
+ zd_mac_clear(zd_netdev_mac(netdev));
+ free_ieee80211(netdev);
+}
+
+void zd_netdev_disconnect(struct net_device *netdev)
+{
+ unregister_netdev(netdev);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.h b/drivers/net/wireless/zd1211rw/zd_netdev.h
new file mode 100644
index 00000000000..374a957073c
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.h
@@ -0,0 +1,45 @@
+/* zd_netdev.h: Header for net device related functions.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_NETDEV_H
+#define _ZD_NETDEV_H
+
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <net/ieee80211.h>
+
+#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV)
+#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1)
+
+static inline struct ieee80211_device *zd_netdev_ieee80211(
+ struct net_device *ndev)
+{
+ return netdev_priv(ndev);
+}
+
+static inline struct net_device *zd_ieee80211_to_netdev(
+ struct ieee80211_device *ieee)
+{
+ return ieee->dev;
+}
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf);
+void zd_netdev_free(struct net_device *netdev);
+
+void zd_netdev_disconnect(struct net_device *netdev);
+
+#endif /* _ZD_NETDEV_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
new file mode 100644
index 00000000000..d3770d2c61b
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -0,0 +1,151 @@
+/* zd_rf.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include "zd_def.h"
+#include "zd_rf.h"
+#include "zd_ieee80211.h"
+#include "zd_chip.h"
+
+static const char *rfs[] = {
+ [0] = "unknown RF0",
+ [1] = "unknown RF1",
+ [UW2451_RF] = "UW2451_RF",
+ [UCHIP_RF] = "UCHIP_RF",
+ [AL2230_RF] = "AL2230_RF",
+ [AL7230B_RF] = "AL7230B_RF",
+ [THETA_RF] = "THETA_RF",
+ [AL2210_RF] = "AL2210_RF",
+ [MAXIM_NEW_RF] = "MAXIM_NEW_RF",
+ [UW2453_RF] = "UW2453_RF",
+ [AL2230S_RF] = "AL2230S_RF",
+ [RALINK_RF] = "RALINK_RF",
+ [INTERSIL_RF] = "INTERSIL_RF",
+ [RF2959_RF] = "RF2959_RF",
+ [MAXIM_NEW2_RF] = "MAXIM_NEW2_RF",
+ [PHILIPS_RF] = "PHILIPS_RF",
+};
+
+const char *zd_rf_name(u8 type)
+{
+ if (type & 0xf0)
+ type = 0;
+ return rfs[type];
+}
+
+void zd_rf_init(struct zd_rf *rf)
+{
+ memset(rf, 0, sizeof(*rf));
+}
+
+void zd_rf_clear(struct zd_rf *rf)
+{
+ memset(rf, 0, sizeof(*rf));
+}
+
+int zd_rf_init_hw(struct zd_rf *rf, u8 type)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ switch (type) {
+ case RF2959_RF:
+ r = zd_rf_init_rf2959(rf);
+ if (r)
+ return r;
+ break;
+ case AL2230_RF:
+ r = zd_rf_init_al2230(rf);
+ if (r)
+ return r;
+ break;
+ default:
+ dev_err(zd_chip_dev(chip),
+ "RF %s %#x is not supported\n", zd_rf_name(type), type);
+ rf->type = 0;
+ return -ENODEV;
+ }
+
+ rf->type = type;
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->init_hw(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%s", zd_rf_name(rf->type));
+}
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+
+ ZD_ASSERT(mutex_is_locked(&zd_rf_to_chip(rf)->mutex));
+ if (channel < MIN_CHANNEL24)
+ return -EINVAL;
+ if (channel > MAX_CHANNEL24)
+ return -EINVAL;
+ dev_dbg_f(zd_chip_dev(zd_rf_to_chip(rf)), "channel: %d\n", channel);
+
+ r = rf->set_channel(rf, channel);
+ if (r >= 0)
+ rf->channel = channel;
+ return r;
+}
+
+int zd_switch_radio_on(struct zd_rf *rf)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->switch_radio_on(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
+
+int zd_switch_radio_off(struct zd_rf *rf)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ /* TODO: move phy regs handling to zd_chip */
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->switch_radio_off(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
new file mode 100644
index 00000000000..ea30f693fcc
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -0,0 +1,82 @@
+/* zd_rf.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_RF_H
+#define _ZD_RF_H
+
+#include "zd_types.h"
+
+#define UW2451_RF 0x2
+#define UCHIP_RF 0x3
+#define AL2230_RF 0x4
+#define AL7230B_RF 0x5 /* a,b,g */
+#define THETA_RF 0x6
+#define AL2210_RF 0x7
+#define MAXIM_NEW_RF 0x8
+#define UW2453_RF 0x9
+#define AL2230S_RF 0xa
+#define RALINK_RF 0xb
+#define INTERSIL_RF 0xc
+#define RF2959_RF 0xd
+#define MAXIM_NEW2_RF 0xe
+#define PHILIPS_RF 0xf
+
+#define RF_CHANNEL(ch) [(ch)-1]
+
+/* Provides functions of the RF transceiver. */
+
+enum {
+ RF_REG_BITS = 6,
+ RF_VALUE_BITS = 18,
+ RF_RV_BITS = RF_REG_BITS + RF_VALUE_BITS,
+};
+
+struct zd_rf {
+ u8 type;
+
+ u8 channel;
+ /*
+ * Whether this RF should patch the 6M band edge
+ * (assuming E2P_POD agrees)
+ */
+ u8 patch_6m_band_edge:1;
+
+ /* RF-specific functions */
+ int (*init_hw)(struct zd_rf *rf);
+ int (*set_channel)(struct zd_rf *rf, u8 channel);
+ int (*switch_radio_on)(struct zd_rf *rf);
+ int (*switch_radio_off)(struct zd_rf *rf);
+};
+
+const char *zd_rf_name(u8 type);
+void zd_rf_init(struct zd_rf *rf);
+void zd_rf_clear(struct zd_rf *rf);
+int zd_rf_init_hw(struct zd_rf *rf, u8 type);
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size);
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
+
+int zd_switch_radio_on(struct zd_rf *rf);
+int zd_switch_radio_off(struct zd_rf *rf);
+
+/* Functions for individual RF chips */
+
+int zd_rf_init_rf2959(struct zd_rf *rf);
+int zd_rf_init_al2230(struct zd_rf *rf);
+
+#endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
new file mode 100644
index 00000000000..0948b25f660
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -0,0 +1,308 @@
+/* zd_rf_al2230.c: Functions for the AL2230 RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 al2230_table[][3] = {
+ RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
+ RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
+ RF_CHANNEL( 4) = { 0x03e790, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 5) = { 0x03f7a0, 0x033331, 0x00000d, },
+ RF_CHANNEL( 6) = { 0x03f7a0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 7) = { 0x03e7a0, 0x033331, 0x00000d, },
+ RF_CHANNEL( 8) = { 0x03e7a0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 9) = { 0x03f7b0, 0x033331, 0x00000d, },
+ RF_CHANNEL(10) = { 0x03f7b0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL(11) = { 0x03e7b0, 0x033331, 0x00000d, },
+ RF_CHANNEL(12) = { 0x03e7b0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL(13) = { 0x03f7c0, 0x033331, 0x00000d, },
+ RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
+};
+
+static int zd1211_al2230_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
+ { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
+ { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a },
+ { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b },
+ { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 },
+ /* for newest (3rd cut) AL2300 */
+ { CR17, 0x28 },
+ { CR26, 0x93 }, { CR34, 0x30 },
+ /* for newest (3rd cut) AL2300 */
+ { CR35, 0x3e },
+ { CR41, 0x24 }, { CR44, 0x32 },
+ /* for newest (3rd cut) AL2300 */
+ { CR46, 0x96 },
+ { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
+ { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
+ { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 },
+ { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 },
+ { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 },
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ /* for newest (3rd cut) AL2300 */
+ { CR115, 0x24 },
+ { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc },
+ { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 },
+ { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff },
+ { CR253, 0xff },
+
+ /* These following happen separately in the vendor driver */
+ { },
+
+ /* shdnb(PLL_ON)=0 */
+ { CR251, 0x2f },
+ /* shdnb(PLL_ON)=1 */
+ { CR251, 0x3f },
+ { CR138, 0x28 }, { CR203, 0x06 },
+ };
+
+ static const u32 rv[] = {
+ /* Channel 1 */
+ 0x03f790,
+ 0x033331,
+ 0x00000d,
+
+ 0x0b3331,
+ 0x03b812,
+ 0x00fff3,
+ 0x000da4,
+ 0x0f4dc5, /* fix freq shift, 0x04edc5 */
+ 0x0805b6,
+ 0x011687,
+ 0x000688,
+ 0x0403b9, /* external control TX power (CR31) */
+ 0x00dbba,
+ 0x00099b,
+ 0x0bdffc,
+ 0x00000d,
+ 0x00500f,
+
+ /* These writes happen separately in the vendor driver */
+ 0x00d00f,
+ 0x004c0f,
+ 0x00540f,
+ 0x00700f,
+ 0x00500f,
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int zd1211b_al2230_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs1[] = {
+ { CR10, 0x89 }, { CR15, 0x20 },
+ { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */
+ { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
+ { CR28, 0x3e }, { CR29, 0x00 },
+ { CR33, 0x28 }, /* 5621 */
+ { CR34, 0x30 },
+ { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */
+ { CR41, 0x24 }, { CR44, 0x32 },
+ { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */
+ { CR47, 0x1e },
+
+ /* ZD1211B 05.06.10 */
+ { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
+ { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
+ { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
+ { CR69, 0x28 },
+
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR87, 0x0a }, { CR89, 0x04 },
+ { CR91, 0x00 }, /* 5621 */
+ { CR92, 0x0a },
+ { CR98, 0x8d }, /* 4804, for 1212 new algorithm */
+ { CR99, 0x00 }, /* 5621 */
+ { CR101, 0x13 }, { CR102, 0x27 },
+ { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
+ { CR107, 0x2a },
+ { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+ { CR110, 0x1f }, /* 4804, for 1212 new algorithm */
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */
+ { CR116, 0x24 },
+ { CR117, 0xfa }, /* for 1211b */
+ { CR118, 0xfa }, /* for 1211b */
+ { CR119, 0x10 },
+ { CR120, 0x4f },
+ { CR121, 0x6c }, /* for 1211b */
+ { CR122, 0xfc }, /* E0->FC at 4902 */
+ { CR123, 0x57 }, /* 5623 */
+ { CR125, 0xad }, /* 4804, for 1212 new algorithm */
+ { CR126, 0x6c }, /* 5614 */
+ { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+ { CR137, 0x50 }, /* 5614 */
+ { CR138, 0xa8 },
+ { CR144, 0xac }, /* 5621 */
+ { CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
+ };
+
+ static const u32 rv1[] = {
+ /* channel 1 */
+ 0x03f790,
+ 0x033331,
+ 0x00000d,
+
+ 0x0b3331,
+ 0x03b812,
+ 0x00fff3,
+ 0x0005a4,
+ 0x0f4dc5, /* fix freq shift 0x044dc5 */
+ 0x0805b6,
+ 0x0146c7,
+ 0x000688,
+ 0x0403b9, /* External control TX power (CR31) */
+ 0x00dbba,
+ 0x00099b,
+ 0x0bdffc,
+ 0x00000d,
+ 0x00580f,
+ };
+
+ static const struct zd_ioreq16 ioreqs2[] = {
+ { CR47, 0x1e }, { CR_RFCFG, 0x03 },
+ };
+
+ static const u32 rv2[] = {
+ 0x00880f,
+ 0x00080f,
+ };
+
+ static const struct zd_ioreq16 ioreqs3[] = {
+ { CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
+ };
+
+ static const u32 rv3[] = {
+ 0x00d80f,
+ 0x00780f,
+ 0x00580f,
+ };
+
+ static const struct zd_ioreq16 ioreqs4[] = {
+ { CR138, 0x28 }, { CR203, 0x06 },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
+ if (r)
+ return r;
+ r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+ if (r)
+ return r;
+ r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+ if (r)
+ return r;
+ r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
+ if (r)
+ return r;
+ return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
+}
+
+static int al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ const u32 *rv = al2230_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR138, 0x28 },
+ { CR203, 0x06 },
+ };
+
+ r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS);
+ if (r)
+ return r;
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x3f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x7f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al2230_switch_radio_off(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x04 },
+ { CR251, 0x2f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al2230(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ rf->set_channel = al2230_set_channel;
+ rf->switch_radio_off = al2230_switch_radio_off;
+ if (chip->is_zd1211b) {
+ rf->init_hw = zd1211b_al2230_init_hw;
+ rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
+ } else {
+ rf->init_hw = zd1211_al2230_init_hw;
+ rf->switch_radio_on = zd1211_al2230_switch_radio_on;
+ }
+ rf->patch_6m_band_edge = 1;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
new file mode 100644
index 00000000000..58247271cc2
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -0,0 +1,279 @@
+/* zd_rf_rfmd.c: Functions for the RFMD RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static u32 rf2959_table[][2] = {
+ RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
+ RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
+ RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
+ RF_CHANNEL( 4) = { 0x1819a9, 0x1e6666 },
+ RF_CHANNEL( 5) = { 0x1819b9, 0x1e6666 },
+ RF_CHANNEL( 6) = { 0x1819c9, 0x1e6666 },
+ RF_CHANNEL( 7) = { 0x1819d9, 0x1e6666 },
+ RF_CHANNEL( 8) = { 0x1819e9, 0x1e6666 },
+ RF_CHANNEL( 9) = { 0x1819f9, 0x1e6666 },
+ RF_CHANNEL(10) = { 0x181a09, 0x1e6666 },
+ RF_CHANNEL(11) = { 0x181a19, 0x1e6666 },
+ RF_CHANNEL(12) = { 0x181a29, 0x1e6666 },
+ RF_CHANNEL(13) = { 0x181a39, 0x1e6666 },
+ RF_CHANNEL(14) = { 0x181a60, 0x1c0000 },
+};
+
+#if 0
+static int bits(u32 rw, int from, int to)
+{
+ rw &= ~(0xffffffffU << (to+1));
+ rw >>= from;
+ return rw;
+}
+
+static int bit(u32 rw, int bit)
+{
+ return bits(rw, bit, bit);
+}
+
+static void dump_regwrite(u32 rw)
+{
+ int reg = bits(rw, 18, 22);
+ int rw_flag = bits(rw, 23, 23);
+ PDEBUG("rf2959 %#010x reg %d rw %d", rw, reg, rw_flag);
+
+ switch (reg) {
+ case 0:
+ PDEBUG("reg0 CFG1 ref_sel %d hybernate %d rf_vco_reg_en %d"
+ " if_vco_reg_en %d if_vga_en %d",
+ bits(rw, 14, 15), bit(rw, 3), bit(rw, 2), bit(rw, 1),
+ bit(rw, 0));
+ break;
+ case 1:
+ PDEBUG("reg1 IFPLL1 pll_en1 %d kv_en1 %d vtc_en1 %d lpf1 %d"
+ " cpl1 %d pdp1 %d autocal_en1 %d ld_en1 %d ifloopr %d"
+ " ifloopc %d dac1 %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+ bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+ bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0, 3));
+ break;
+ case 2:
+ PDEBUG("reg2 IFPLL2 n1 %d num1 %d",
+ bits(rw, 6, 17), bits(rw, 0, 5));
+ break;
+ case 3:
+ PDEBUG("reg3 IFPLL3 num %d", bits(rw, 0, 17));
+ break;
+ case 4:
+ PDEBUG("reg4 IFPLL4 dn1 %#04x ct_def1 %d kv_def1 %d",
+ bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+ break;
+ case 5:
+ PDEBUG("reg5 RFPLL1 pll_en %d kv_en %d vtc_en %d lpf %d cpl %d"
+ " pdp %d autocal_en %d ld_en %d rfloopr %d rfloopc %d"
+ " dac %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+ bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+ bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0,3));
+ break;
+ case 6:
+ PDEBUG("reg6 RFPLL2 n %d num %d",
+ bits(rw, 6, 17), bits(rw, 0, 5));
+ break;
+ case 7:
+ PDEBUG("reg7 RFPLL3 num2 %d", bits(rw, 0, 17));
+ break;
+ case 8:
+ PDEBUG("reg8 RFPLL4 dn %#06x ct_def %d kv_def %d",
+ bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+ break;
+ case 9:
+ PDEBUG("reg9 CAL1 tvco %d tlock %d m_ct_value %d ld_window %d",
+ bits(rw, 13, 17), bits(rw, 8, 12), bits(rw, 3, 7),
+ bits(rw, 0, 2));
+ break;
+ case 10:
+ PDEBUG("reg10 TXRX1 rxdcfbbyps %d pcontrol %d txvgc %d"
+ " rxlpfbw %d txlpfbw %d txdiffmode %d txenmode %d"
+ " intbiasen %d tybypass %d",
+ bit(rw, 17), bits(rw, 15, 16), bits(rw, 10, 14),
+ bits(rw, 7, 9), bits(rw, 4, 6), bit(rw, 3), bit(rw, 2),
+ bit(rw, 1), bit(rw, 0));
+ break;
+ case 11:
+ PDEBUG("reg11 PCNT1 mid_bias %d p_desired %d pc_offset %d"
+ " tx_delay %d",
+ bits(rw, 15, 17), bits(rw, 9, 14), bits(rw, 3, 8),
+ bits(rw, 0, 2));
+ break;
+ case 12:
+ PDEBUG("reg12 PCNT2 max_power %d mid_power %d min_power %d",
+ bits(rw, 12, 17), bits(rw, 6, 11), bits(rw, 0, 5));
+ break;
+ case 13:
+ PDEBUG("reg13 VCOT1 rfpll vco comp %d ifpll vco comp %d"
+ " lobias %d if_biasbuf %d if_biasvco %d rf_biasbuf %d"
+ " rf_biasvco %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15),
+ bits(rw, 8, 9), bits(rw, 5, 7), bits(rw, 3, 4),
+ bits(rw, 0, 2));
+ break;
+ case 14:
+ PDEBUG("reg14 IQCAL rx_acal %d rx_pcal %d"
+ " tx_acal %d tx_pcal %d",
+ bits(rw, 13, 17), bits(rw, 9, 12), bits(rw, 4, 8),
+ bits(rw, 0, 3));
+ break;
+ }
+}
+#endif /* 0 */
+
+static int rf2959_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 },
+ { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 },
+ { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E },
+ { CR23, 0x48 },
+ /* normal size for cca threshold */
+ { CR24, 0x14 },
+ /* { CR24, 0x20 }, */
+ { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 },
+ { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 },
+ { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 },
+ { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E },
+ { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 },
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
+ { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A },
+ { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 },
+ /* { CR91, 0x18 }, */
+ /* should solve continous CTS frame problems */
+ { CR91, 0x00 },
+ { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 },
+ { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 },
+ { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 },
+ { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 },
+ { CR104, 0x18 }, { CR105, 0x12 },
+ /* normal size */
+ { CR106, 0x1a },
+ /* { CR106, 0x22 }, */
+ { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 },
+ { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 },
+ { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 },
+ { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 },
+ { CR119, 0x16 },
+ /* no TX continuation */
+ { CR122, 0x00 },
+ /* { CR122, 0xff }, */
+ { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 },
+ { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB },
+ { CR170, 0xBB },
+ };
+
+ static const u32 rv[] = {
+ 0x000007, /* REG0(CFG1) */
+ 0x07dd43, /* REG1(IFPLL1) */
+ 0x080959, /* REG2(IFPLL2) */
+ 0x0e6666,
+ 0x116a57, /* REG4 */
+ 0x17dd43, /* REG5 */
+ 0x1819f9, /* REG6 */
+ 0x1e6666,
+ 0x214554,
+ 0x25e7fa,
+ 0x27fffa,
+ /* The Zydas driver somehow forgets to set this value. It's
+ * only set for Japan. We are using internal power control
+ * for now.
+ */
+ 0x294128, /* internal power */
+ /* 0x28252c, */ /* External control TX power */
+ /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */
+ 0x2c0000,
+ 0x300000,
+ 0x340000, /* REG13(0xD) */
+ 0x381e0f, /* REG14(0xE) */
+ /* Bogus, RF2959's data sheet doesn't know register 27, which is
+ * actually referenced here. The commented 0x11 is 17.
+ */
+ 0x6c180f, /* REG27(0x11) */
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+}
+
+static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int i, r;
+ u32 *rv = rf2959_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ for (i = 0; i < 2; i++) {
+ r = zd_rfwrite_locked(chip, rv[i], RF_RV_BITS);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static int rf2959_switch_radio_on(struct zd_rf *rf)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR10, 0x89 },
+ { CR11, 0x00 },
+ };
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int rf2959_switch_radio_off(struct zd_rf *rf)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR10, 0x15 },
+ { CR11, 0x81 },
+ };
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_rf2959(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ if (chip->is_zd1211b) {
+ dev_err(zd_chip_dev(chip),
+ "RF2959 is currently not supported for ZD1211B"
+ " devices\n");
+ return -ENODEV;
+ }
+ rf->init_hw = rf2959_init_hw;
+ rf->set_channel = rf2959_set_channel;
+ rf->switch_radio_on = rf2959_switch_radio_on;
+ rf->switch_radio_off = rf2959_switch_radio_off;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
new file mode 100644
index 00000000000..0155a1584ed
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_types.h
@@ -0,0 +1,71 @@
+/* zd_types.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_TYPES_H
+#define _ZD_TYPES_H
+
+#include <linux/types.h>
+
+/* We have three register spaces mapped into the overall USB address space of
+ * 64K words (16-bit values). There is the control register space of
+ * double-word registers, the eeprom register space and the firmware register
+ * space. The control register space is byte mapped, the others are word
+ * mapped.
+ *
+ * For that reason, we are using byte offsets for control registers and word
+ * offsets for everything else.
+ */
+
+typedef u32 __nocast zd_addr_t;
+
+enum {
+ ADDR_BASE_MASK = 0xff000000,
+ ADDR_OFFSET_MASK = 0x0000ffff,
+ ADDR_ZERO_MASK = 0x00ff0000,
+ NULL_BASE = 0x00000000,
+ USB_BASE = 0x01000000,
+ CR_BASE = 0x02000000,
+ CR_MAX_OFFSET = 0x0b30,
+ E2P_BASE = 0x03000000,
+ E2P_MAX_OFFSET = 0x007e,
+ FW_BASE = 0x04000000,
+ FW_MAX_OFFSET = 0x0005,
+};
+
+#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
+#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
+
+#define ZD_ADDR(base, offset) \
+ ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
+
+#define ZD_NULL_ADDR ((zd_addr_t)0)
+#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */
+#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */
+#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */
+#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */
+
+static inline zd_addr_t zd_inc_word(zd_addr_t addr)
+{
+ u32 base = ZD_ADDR_BASE(addr);
+ u32 offset = ZD_OFFSET(addr);
+
+ offset += base == CR_BASE ? 2 : 1;
+
+ return base | offset;
+}
+
+#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
new file mode 100644
index 00000000000..ce1cb2c6aa8
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -0,0 +1,1316 @@
+/* zd_usb.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/unaligned.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_usb.h"
+#include "zd_util.h"
+
+static struct usb_device_id usb_ids[] = {
+ /* ZD1211 */
+ { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ /* ZD1211B */
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ {}
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB driver for devices with the ZD1211 chip.");
+MODULE_AUTHOR("Ulrich Kunitz");
+MODULE_AUTHOR("Daniel Drake");
+MODULE_VERSION("1.0");
+MODULE_DEVICE_TABLE(usb, usb_ids);
+
+#define FW_ZD1211_PREFIX "zd1211/zd1211_"
+#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
+
+/* register address handling */
+
+#ifdef DEBUG
+static int check_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+ u32 base = ZD_ADDR_BASE(addr);
+ u32 offset = ZD_OFFSET(addr);
+
+ if ((u32)addr & ADDR_ZERO_MASK)
+ goto invalid_address;
+ switch (base) {
+ case USB_BASE:
+ break;
+ case CR_BASE:
+ if (offset > CR_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "CR offset %#010x larger than"
+ " CR_MAX_OFFSET %#10x\n",
+ offset, CR_MAX_OFFSET);
+ goto invalid_address;
+ }
+ if (offset & 1) {
+ dev_dbg(zd_usb_dev(usb),
+ "CR offset %#010x is not a multiple of 2\n",
+ offset);
+ goto invalid_address;
+ }
+ break;
+ case E2P_BASE:
+ if (offset > E2P_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "E2P offset %#010x larger than"
+ " E2P_MAX_OFFSET %#010x\n",
+ offset, E2P_MAX_OFFSET);
+ goto invalid_address;
+ }
+ break;
+ case FW_BASE:
+ if (!usb->fw_base_offset) {
+ dev_dbg(zd_usb_dev(usb),
+ "ERROR: fw base offset has not been set\n");
+ return -EAGAIN;
+ }
+ if (offset > FW_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "FW offset %#10x is larger than"
+ " FW_MAX_OFFSET %#010x\n",
+ offset, FW_MAX_OFFSET);
+ goto invalid_address;
+ }
+ break;
+ default:
+ dev_dbg(zd_usb_dev(usb),
+ "address has unsupported base %#010x\n", addr);
+ goto invalid_address;
+ }
+
+ return 0;
+invalid_address:
+ dev_dbg(zd_usb_dev(usb),
+ "ERROR: invalid address: %#010x\n", addr);
+ return -EINVAL;
+}
+#endif /* DEBUG */
+
+static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+ u32 base;
+ u16 offset;
+
+ base = ZD_ADDR_BASE(addr);
+ offset = ZD_OFFSET(addr);
+
+ ZD_ASSERT(check_addr(usb, addr) == 0);
+
+ switch (base) {
+ case CR_BASE:
+ offset += CR_BASE_OFFSET;
+ break;
+ case E2P_BASE:
+ offset += E2P_BASE_OFFSET;
+ break;
+ case FW_BASE:
+ offset += usb->fw_base_offset;
+ break;
+ }
+
+ return offset;
+}
+
+/* USB device initialization */
+
+static int request_fw_file(
+ const struct firmware **fw, const char *name, struct device *device)
+{
+ int r;
+
+ dev_dbg_f(device, "fw name %s\n", name);
+
+ r = request_firmware(fw, name, device);
+ if (r)
+ dev_err(device,
+ "Could not load firmware file %s. Error number %d\n",
+ name, r);
+ return r;
+}
+
+static inline u16 get_bcdDevice(const struct usb_device *udev)
+{
+ return le16_to_cpu(udev->descriptor.bcdDevice);
+}
+
+enum upload_code_flags {
+ REBOOT = 1,
+};
+
+/* Ensures that MAX_TRANSFER_SIZE is even. */
+#define MAX_TRANSFER_SIZE (USB_MAX_TRANSFER_SIZE & ~1)
+
+static int upload_code(struct usb_device *udev,
+ const u8 *data, size_t size, u16 code_offset, int flags)
+{
+ u8 *p;
+ int r;
+
+ /* USB request blocks need "kmalloced" buffers.
+ */
+ p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL);
+ if (!p) {
+ dev_err(&udev->dev, "out of memory\n");
+ r = -ENOMEM;
+ goto error;
+ }
+
+ size &= ~1;
+ while (size > 0) {
+ size_t transfer_size = size <= MAX_TRANSFER_SIZE ?
+ size : MAX_TRANSFER_SIZE;
+
+ dev_dbg_f(&udev->dev, "transfer size %zu\n", transfer_size);
+
+ memcpy(p, data, transfer_size);
+ r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_FIRMWARE_DOWNLOAD,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ code_offset, 0, p, transfer_size, 1000 /* ms */);
+ if (r < 0) {
+ dev_err(&udev->dev,
+ "USB control request for firmware upload"
+ " failed. Error number %d\n", r);
+ goto error;
+ }
+ transfer_size = r & ~1;
+
+ size -= transfer_size;
+ data += transfer_size;
+ code_offset += transfer_size/sizeof(u16);
+ }
+
+ if (flags & REBOOT) {
+ u8 ret;
+
+ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_REQ_FIRMWARE_CONFIRM,
+ USB_DIR_IN | USB_TYPE_VENDOR,
+ 0, 0, &ret, sizeof(ret), 5000 /* ms */);
+ if (r != sizeof(ret)) {
+ dev_err(&udev->dev,
+ "control request firmeware confirmation failed."
+ " Return value %d\n", r);
+ if (r >= 0)
+ r = -ENODEV;
+ goto error;
+ }
+ if (ret & 0x80) {
+ dev_err(&udev->dev,
+ "Internal error while downloading."
+ " Firmware confirm return value %#04x\n",
+ (unsigned int)ret);
+ r = -ENODEV;
+ goto error;
+ }
+ dev_dbg_f(&udev->dev, "firmware confirm return value %#04x\n",
+ (unsigned int)ret);
+ }
+
+ r = 0;
+error:
+ kfree(p);
+ return r;
+}
+
+static u16 get_word(const void *data, u16 offset)
+{
+ const __le16 *p = data;
+ return le16_to_cpu(p[offset]);
+}
+
+static char *get_fw_name(char *buffer, size_t size, u8 device_type,
+ const char* postfix)
+{
+ scnprintf(buffer, size, "%s%s",
+ device_type == DEVICE_ZD1211B ?
+ FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX,
+ postfix);
+ return buffer;
+}
+
+static int upload_firmware(struct usb_device *udev, u8 device_type)
+{
+ int r;
+ u16 fw_bcdDevice;
+ u16 bcdDevice;
+ const struct firmware *ub_fw = NULL;
+ const struct firmware *uph_fw = NULL;
+ char fw_name[128];
+
+ bcdDevice = get_bcdDevice(udev);
+
+ r = request_fw_file(&ub_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "ub"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+
+ /* FIXME: do we have any reason to perform the kludge that the vendor
+ * driver does when there is a version mismatch? (their driver uploads
+ * different firmwares and stuff)
+ */
+ if (fw_bcdDevice != bcdDevice) {
+ dev_info(&udev->dev,
+ "firmware device id %#06x and actual device id "
+ "%#06x differ, continuing anyway\n",
+ fw_bcdDevice, bcdDevice);
+ } else {
+ dev_dbg_f(&udev->dev,
+ "firmware device id %#06x is equal to the "
+ "actual device id\n", fw_bcdDevice);
+ }
+
+
+ r = request_fw_file(&uph_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
+ REBOOT);
+ if (r) {
+ dev_err(&udev->dev,
+ "Could not upload firmware code uph. Error number %d\n",
+ r);
+ }
+
+ /* FALL-THROUGH */
+error:
+ release_firmware(ub_fw);
+ release_firmware(uph_fw);
+ return r;
+}
+
+static void disable_read_regs_int(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ ZD_ASSERT(in_interrupt());
+ spin_lock(&intr->lock);
+ intr->read_regs_enabled = 0;
+ spin_unlock(&intr->lock);
+}
+
+#define urb_dev(urb) (&(urb)->dev->dev)
+
+static inline void handle_regs_int(struct urb *urb)
+{
+ struct zd_usb *usb = urb->context;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ int len;
+
+ ZD_ASSERT(in_interrupt());
+ spin_lock(&intr->lock);
+
+ if (intr->read_regs_enabled) {
+ intr->read_regs.length = len = urb->actual_length;
+
+ if (len > sizeof(intr->read_regs.buffer))
+ len = sizeof(intr->read_regs.buffer);
+ memcpy(intr->read_regs.buffer, urb->transfer_buffer, len);
+ intr->read_regs_enabled = 0;
+ complete(&intr->read_regs.completion);
+ goto out;
+ }
+
+ dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
+out:
+ spin_unlock(&intr->lock);
+}
+
+static inline void handle_retry_failed_int(struct urb *urb)
+{
+ dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
+}
+
+
+static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ int r;
+ struct usb_int_header *hdr;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ goto kfree;
+ case -EPIPE:
+ usb_clear_halt(urb->dev, EP_INT_IN);
+ /* FALL-THROUGH */
+ default:
+ goto resubmit;
+ }
+
+ if (urb->actual_length < sizeof(hdr)) {
+ dev_dbg_f(urb_dev(urb), "error: urb %p to small\n", urb);
+ goto resubmit;
+ }
+
+ hdr = urb->transfer_buffer;
+ if (hdr->type != USB_INT_TYPE) {
+ dev_dbg_f(urb_dev(urb), "error: urb %p wrong type\n", urb);
+ goto resubmit;
+ }
+
+ switch (hdr->id) {
+ case USB_INT_ID_REGS:
+ handle_regs_int(urb);
+ break;
+ case USB_INT_ID_RETRY_FAILED:
+ handle_retry_failed_int(urb);
+ break;
+ default:
+ dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
+ (unsigned int)hdr->id);
+ goto resubmit;
+ }
+
+resubmit:
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r) {
+ dev_dbg_f(urb_dev(urb), "resubmit urb %p\n", urb);
+ goto kfree;
+ }
+ return;
+kfree:
+ kfree(urb->transfer_buffer);
+}
+
+static inline int int_urb_interval(struct usb_device *udev)
+{
+ switch (udev->speed) {
+ case USB_SPEED_HIGH:
+ return 4;
+ case USB_SPEED_LOW:
+ return 10;
+ case USB_SPEED_FULL:
+ default:
+ return 1;
+ }
+}
+
+static inline int usb_int_enabled(struct zd_usb *usb)
+{
+ unsigned long flags;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct urb *urb;
+
+ spin_lock_irqsave(&intr->lock, flags);
+ urb = intr->urb;
+ spin_unlock_irqrestore(&intr->lock, flags);
+ return urb != NULL;
+}
+
+int zd_usb_enable_int(struct zd_usb *usb)
+{
+ int r;
+ struct usb_device *udev;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ void *transfer_buffer = NULL;
+ struct urb *urb;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ urb = usb_alloc_urb(0, GFP_NOFS);
+ if (!urb) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&intr->lock);
+ if (intr->urb) {
+ spin_unlock_irq(&intr->lock);
+ r = 0;
+ goto error_free_urb;
+ }
+ intr->urb = urb;
+ spin_unlock_irq(&intr->lock);
+
+ /* TODO: make it a DMA buffer */
+ r = -ENOMEM;
+ transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+ if (!transfer_buffer) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "couldn't allocate transfer_buffer\n");
+ goto error_set_urb_null;
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
+ transfer_buffer, USB_MAX_EP_INT_BUFFER,
+ int_urb_complete, usb,
+ intr->interval);
+
+ dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
+ r = usb_submit_urb(urb, GFP_NOFS);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "Couldn't submit urb. Error number %d\n", r);
+ goto error;
+ }
+
+ return 0;
+error:
+ kfree(transfer_buffer);
+error_set_urb_null:
+ spin_lock_irq(&intr->lock);
+ intr->urb = NULL;
+ spin_unlock_irq(&intr->lock);
+error_free_urb:
+ usb_free_urb(urb);
+out:
+ return r;
+}
+
+void zd_usb_disable_int(struct zd_usb *usb)
+{
+ unsigned long flags;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct urb *urb;
+
+ spin_lock_irqsave(&intr->lock, flags);
+ urb = intr->urb;
+ if (!urb) {
+ spin_unlock_irqrestore(&intr->lock, flags);
+ return;
+ }
+ intr->urb = NULL;
+ spin_unlock_irqrestore(&intr->lock, flags);
+
+ usb_kill_urb(urb);
+ dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb);
+ usb_free_urb(urb);
+}
+
+static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
+ unsigned int length)
+{
+ int i;
+ struct zd_mac *mac = zd_usb_to_mac(usb);
+ const struct rx_length_info *length_info;
+
+ if (length < sizeof(struct rx_length_info)) {
+ /* It's not a complete packet anyhow. */
+ return;
+ }
+ length_info = (struct rx_length_info *)
+ (buffer + length - sizeof(struct rx_length_info));
+
+ /* It might be that three frames are merged into a single URB
+ * transaction. We have to check for the length info tag.
+ *
+ * While testing we discovered that length_info might be unaligned,
+ * because if USB transactions are merged, the last packet will not
+ * be padded. Unaligned access might also happen if the length_info
+ * structure is not present.
+ */
+ if (get_unaligned(&length_info->tag) == RX_LENGTH_INFO_TAG) {
+ unsigned int l, k, n;
+ for (i = 0, l = 0;; i++) {
+ k = le16_to_cpu(get_unaligned(
+ &length_info->length[i]));
+ n = l+k;
+ if (n > length)
+ return;
+ zd_mac_rx(mac, buffer+l, k);
+ if (i >= 2)
+ return;
+ l = (n+3) & ~3;
+ }
+ } else {
+ zd_mac_rx(mac, buffer, length);
+ }
+}
+
+static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ struct zd_usb *usb;
+ struct zd_usb_rx *rx;
+ const u8 *buffer;
+ unsigned int length;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ return;
+ case -EPIPE:
+ usb_clear_halt(urb->dev, EP_DATA_IN);
+ /* FALL-THROUGH */
+ default:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ goto resubmit;
+ }
+
+ buffer = urb->transfer_buffer;
+ length = urb->actual_length;
+ usb = urb->context;
+ rx = &usb->rx;
+
+ if (length%rx->usb_packet_size > rx->usb_packet_size-4) {
+ /* If there is an old first fragment, we don't care. */
+ dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
+ ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
+ spin_lock(&rx->lock);
+ memcpy(rx->fragment, buffer, length);
+ rx->fragment_length = length;
+ spin_unlock(&rx->lock);
+ goto resubmit;
+ }
+
+ spin_lock(&rx->lock);
+ if (rx->fragment_length > 0) {
+ /* We are on a second fragment, we believe */
+ ZD_ASSERT(length + rx->fragment_length <=
+ ARRAY_SIZE(rx->fragment));
+ dev_dbg_f(urb_dev(urb), "*** second fragment ***\n");
+ memcpy(rx->fragment+rx->fragment_length, buffer, length);
+ handle_rx_packet(usb, rx->fragment,
+ rx->fragment_length + length);
+ rx->fragment_length = 0;
+ spin_unlock(&rx->lock);
+ } else {
+ spin_unlock(&rx->lock);
+ handle_rx_packet(usb, buffer, length);
+ }
+
+resubmit:
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+struct urb *alloc_urb(struct zd_usb *usb)
+{
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+ struct urb *urb;
+ void *buffer;
+
+ urb = usb_alloc_urb(0, GFP_NOFS);
+ if (!urb)
+ return NULL;
+ buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+ &urb->transfer_dma);
+ if (!buffer) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
+ buffer, USB_MAX_RX_SIZE,
+ rx_urb_complete, usb);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ return urb;
+}
+
+void free_urb(struct urb *urb)
+{
+ if (!urb)
+ return;
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+}
+
+int zd_usb_enable_rx(struct zd_usb *usb)
+{
+ int i, r;
+ struct zd_usb_rx *rx = &usb->rx;
+ struct urb **urbs;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ r = -ENOMEM;
+ urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+ if (!urbs)
+ goto error;
+ for (i = 0; i < URBS_COUNT; i++) {
+ urbs[i] = alloc_urb(usb);
+ if (!urbs[i])
+ goto error;
+ }
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&rx->lock);
+ if (rx->urbs) {
+ spin_unlock_irq(&rx->lock);
+ r = 0;
+ goto error;
+ }
+ rx->urbs = urbs;
+ rx->urbs_count = URBS_COUNT;
+ spin_unlock_irq(&rx->lock);
+
+ for (i = 0; i < URBS_COUNT; i++) {
+ r = usb_submit_urb(urbs[i], GFP_NOFS);
+ if (r)
+ goto error_submit;
+ }
+
+ return 0;
+error_submit:
+ for (i = 0; i < URBS_COUNT; i++) {
+ usb_kill_urb(urbs[i]);
+ }
+ spin_lock_irq(&rx->lock);
+ rx->urbs = NULL;
+ rx->urbs_count = 0;
+ spin_unlock_irq(&rx->lock);
+error:
+ if (urbs) {
+ for (i = 0; i < URBS_COUNT; i++)
+ free_urb(urbs[i]);
+ }
+ return r;
+}
+
+void zd_usb_disable_rx(struct zd_usb *usb)
+{
+ int i;
+ unsigned long flags;
+ struct urb **urbs;
+ unsigned int count;
+ struct zd_usb_rx *rx = &usb->rx;
+
+ spin_lock_irqsave(&rx->lock, flags);
+ urbs = rx->urbs;
+ count = rx->urbs_count;
+ spin_unlock_irqrestore(&rx->lock, flags);
+ if (!urbs)
+ return;
+
+ for (i = 0; i < count; i++) {
+ usb_kill_urb(urbs[i]);
+ free_urb(urbs[i]);
+ }
+ kfree(urbs);
+
+ spin_lock_irqsave(&rx->lock, flags);
+ rx->urbs = NULL;
+ rx->urbs_count = 0;
+ spin_unlock_irqrestore(&rx->lock, flags);
+}
+
+static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ int r;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ break;
+ case -EPIPE:
+ usb_clear_halt(urb->dev, EP_DATA_OUT);
+ /* FALL-THROUGH */
+ default:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ goto resubmit;
+ }
+free_urb:
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ return;
+resubmit:
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r) {
+ dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r);
+ goto free_urb;
+ }
+}
+
+/* Puts the frame on the USB endpoint. It doesn't wait for
+ * completion. The frame must contain the control set.
+ */
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length)
+{
+ int r;
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+ struct urb *urb;
+ void *buffer;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buffer) {
+ r = -ENOMEM;
+ goto error_free_urb;
+ }
+ memcpy(buffer, frame, length);
+
+ usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
+ buffer, length, tx_urb_complete, NULL);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r)
+ goto error;
+ return 0;
+error:
+ usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,
+ urb->transfer_dma);
+error_free_urb:
+ usb_free_urb(urb);
+out:
+ return r;
+}
+
+static inline void init_usb_interrupt(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock_init(&intr->lock);
+ intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
+ init_completion(&intr->read_regs.completion);
+ intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+}
+
+static inline void init_usb_rx(struct zd_usb *usb)
+{
+ struct zd_usb_rx *rx = &usb->rx;
+ spin_lock_init(&rx->lock);
+ if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) {
+ rx->usb_packet_size = 512;
+ } else {
+ rx->usb_packet_size = 64;
+ }
+ ZD_ASSERT(rx->fragment_length == 0);
+}
+
+static inline void init_usb_tx(struct zd_usb *usb)
+{
+ /* FIXME: at this point we will allocate a fixed number of urb's for
+ * use in a cyclic scheme */
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ memset(usb, 0, sizeof(*usb));
+ usb->intf = usb_get_intf(intf);
+ usb_set_intfdata(usb->intf, netdev);
+ init_usb_interrupt(usb);
+ init_usb_tx(usb);
+ init_usb_rx(usb);
+}
+
+int zd_usb_init_hw(struct zd_usb *usb)
+{
+ int r;
+ struct zd_chip *chip = zd_usb_to_chip(usb);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread16_locked(chip, &usb->fw_base_offset,
+ USB_REG((u16)FW_BASE_ADDR_OFFSET));
+ if (r)
+ return r;
+ dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
+ usb->fw_base_offset);
+
+ return 0;
+}
+
+void zd_usb_clear(struct zd_usb *usb)
+{
+ usb_set_intfdata(usb->intf, NULL);
+ usb_put_intf(usb->intf);
+ memset(usb, 0, sizeof(*usb));
+ /* FIXME: usb_interrupt, usb_tx, usb_rx? */
+}
+
+static const char *speed(enum usb_device_speed speed)
+{
+ switch (speed) {
+ case USB_SPEED_LOW:
+ return "low";
+ case USB_SPEED_FULL:
+ return "full";
+ case USB_SPEED_HIGH:
+ return "high";
+ default:
+ return "unknown speed";
+ }
+}
+
+static int scnprint_id(struct usb_device *udev, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ get_bcdDevice(udev),
+ speed(udev->speed));
+}
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size)
+{
+ struct usb_device *udev = interface_to_usbdev(usb->intf);
+ return scnprint_id(udev, buffer, size);
+}
+
+#ifdef DEBUG
+static void print_id(struct usb_device *udev)
+{
+ char buffer[40];
+
+ scnprint_id(udev, buffer, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ dev_dbg_f(&udev->dev, "%s\n", buffer);
+}
+#else
+#define print_id(udev) do { } while (0)
+#endif
+
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int r;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct net_device *netdev = NULL;
+
+ print_id(udev);
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ break;
+ default:
+ dev_dbg_f(&intf->dev, "Unknown USB speed\n");
+ r = -ENODEV;
+ goto error;
+ }
+
+ netdev = zd_netdev_alloc(intf);
+ if (netdev == NULL) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ r = upload_firmware(udev, id->driver_info);
+ if (r) {
+ dev_err(&intf->dev,
+ "couldn't load firmware. Error number %d\n", r);
+ goto error;
+ }
+
+ r = usb_reset_configuration(udev);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't reset configuration. Error number %d\n", r);
+ goto error;
+ }
+
+ /* At this point the interrupt endpoint is not generally enabled. We
+ * save the USB bandwidth until the network device is opened. But
+ * notify that the initialization of the MAC will require the
+ * interrupts to be temporary enabled.
+ */
+ r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't initialize mac. Error number %d\n", r);
+ goto error;
+ }
+
+ r = register_netdev(netdev);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't register netdev. Error number %d\n", r);
+ goto error;
+ }
+
+ dev_dbg_f(&intf->dev, "successful\n");
+ dev_info(&intf->dev,"%s\n", netdev->name);
+ return 0;
+error:
+ usb_reset_device(interface_to_usbdev(intf));
+ zd_netdev_free(netdev);
+ return r;
+}
+
+static void disconnect(struct usb_interface *intf)
+{
+ struct net_device *netdev = zd_intf_to_netdev(intf);
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_usb *usb = &mac->chip.usb;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ zd_netdev_disconnect(netdev);
+
+ /* Just in case something has gone wrong! */
+ zd_usb_disable_rx(usb);
+ zd_usb_disable_int(usb);
+
+ /* If the disconnect has been caused by a removal of the
+ * driver module, the reset allows reloading of the driver. If the
+ * reset will not be executed here, the upload of the firmware in the
+ * probe function caused by the reloading of the driver will fail.
+ */
+ usb_reset_device(interface_to_usbdev(intf));
+
+ /* If somebody still waits on this lock now, this is an error. */
+ zd_netdev_free(netdev);
+ dev_dbg(&intf->dev, "disconnected\n");
+}
+
+static struct usb_driver driver = {
+ .name = "zd1211rw",
+ .id_table = usb_ids,
+ .probe = probe,
+ .disconnect = disconnect,
+};
+
+static int __init usb_init(void)
+{
+ int r;
+
+ pr_debug("usb_init()\n");
+
+ r = usb_register(&driver);
+ if (r) {
+ printk(KERN_ERR "usb_register() failed. Error number %d\n", r);
+ return r;
+ }
+
+ pr_debug("zd1211rw initialized\n");
+ return 0;
+}
+
+static void __exit usb_exit(void)
+{
+ pr_debug("usb_exit()\n");
+ usb_deregister(&driver);
+}
+
+module_init(usb_init);
+module_exit(usb_exit);
+
+static int usb_int_regs_length(unsigned int count)
+{
+ return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);
+}
+
+static void prepare_read_regs_int(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock(&intr->lock);
+ intr->read_regs_enabled = 1;
+ INIT_COMPLETION(intr->read_regs.completion);
+ spin_unlock(&intr->lock);
+}
+
+static int get_results(struct zd_usb *usb, u16 *values,
+ struct usb_req_read_regs *req, unsigned int count)
+{
+ int r;
+ int i;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct read_regs_int *rr = &intr->read_regs;
+ struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;
+
+ spin_lock(&intr->lock);
+
+ r = -EIO;
+ /* The created block size seems to be larger than expected.
+ * However results appear to be correct.
+ */
+ if (rr->length < usb_int_regs_length(count)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: actual length %d less than expected %d\n",
+ rr->length, usb_int_regs_length(count));
+ goto error_unlock;
+ }
+ if (rr->length > sizeof(rr->buffer)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: actual length %d exceeds buffer size %zu\n",
+ rr->length, sizeof(rr->buffer));
+ goto error_unlock;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct reg_data *rd = &regs->regs[i];
+ if (rd->addr != req->addr[i]) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "rd[%d] addr %#06hx expected %#06hx\n", i,
+ le16_to_cpu(rd->addr),
+ le16_to_cpu(req->addr[i]));
+ goto error_unlock;
+ }
+ values[i] = le16_to_cpu(rd->value);
+ }
+
+ r = 0;
+error_unlock:
+ spin_unlock(&intr->lock);
+ return r;
+}
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+ const zd_addr_t *addresses, unsigned int count)
+{
+ int r;
+ int i, req_len, actual_req_len;
+ struct usb_device *udev;
+ struct usb_req_read_regs *req = NULL;
+ unsigned long timeout;
+
+ if (count < 1) {
+ dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n");
+ return -EINVAL;
+ }
+ if (count > USB_MAX_IOREAD16_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: count %u exceeds possible max %u\n",
+ count, USB_MAX_IOREAD16_COUNT);
+ return -EINVAL;
+ }
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+ if (!usb_int_enabled(usb)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: usb interrupt not enabled\n");
+ return -EWOULDBLOCK;
+ }
+
+ req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+ req->id = cpu_to_le16(USB_REQ_READ_REGS);
+ for (i = 0; i < count; i++)
+ req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+
+ udev = zd_usb_to_usbdev(usb);
+ prepare_read_regs_int(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto error;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()\n"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto error;
+ }
+
+ timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ disable_read_regs_int(usb);
+ dev_dbg_f(zd_usb_dev(usb), "read timed out\n");
+ r = -ETIMEDOUT;
+ goto error;
+ }
+
+ r = get_results(usb, values, req, count);
+error:
+ kfree(req);
+ return r;
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+ unsigned int count)
+{
+ int r;
+ struct usb_device *udev;
+ struct usb_req_write_regs *req = NULL;
+ int i, req_len, actual_req_len;
+
+ if (count == 0)
+ return 0;
+ if (count > USB_MAX_IOWRITE16_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: count %u exceeds possible max %u\n",
+ count, USB_MAX_IOWRITE16_COUNT);
+ return -EINVAL;
+ }
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+
+ req_len = sizeof(struct usb_req_write_regs) +
+ count * sizeof(struct reg_data);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+
+ req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
+ for (i = 0; i < count; i++) {
+ struct reg_data *rw = &req->reg_writes[i];
+ rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+ rw->value = cpu_to_le16(ioreqs[i].value);
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto error;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg()"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto error;
+ }
+
+ /* FALL-THROUGH with r == 0 */
+error:
+ kfree(req);
+ return r;
+}
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
+{
+ int r;
+ struct usb_device *udev;
+ struct usb_req_rfwrite *req = NULL;
+ int i, req_len, actual_req_len;
+ u16 bit_value_template;
+
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+ if (bits < USB_MIN_RFWRITE_BIT_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: bits %d are smaller than"
+ " USB_MIN_RFWRITE_BIT_COUNT %d\n",
+ bits, USB_MIN_RFWRITE_BIT_COUNT);
+ return -EINVAL;
+ }
+ if (bits > USB_MAX_RFWRITE_BIT_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n",
+ bits, USB_MAX_RFWRITE_BIT_COUNT);
+ return -EINVAL;
+ }
+#ifdef DEBUG
+ if (value & (~0UL << bits)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: value %#09x has bits >= %d set\n",
+ value, bits);
+ return -EINVAL;
+ }
+#endif /* DEBUG */
+
+ dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);
+
+ r = zd_usb_ioread16(usb, &bit_value_template, CR203);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error %d: Couldn't read CR203\n", r);
+ goto out;
+ }
+ bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
+
+ req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+
+ req->id = cpu_to_le16(USB_REQ_WRITE_RF);
+ /* 1: 3683a, but not used in ZYDAS driver */
+ req->value = cpu_to_le16(2);
+ req->bits = cpu_to_le16(bits);
+
+ for (i = 0; i < bits; i++) {
+ u16 bv = bit_value_template;
+ if (value & (1 << (bits-1-i)))
+ bv |= RF_DATA;
+ req->bit_values[i] = cpu_to_le16(bv);
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto out;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto out;
+ }
+
+ /* FALL-THROUGH with r == 0 */
+out:
+ kfree(req);
+ return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
new file mode 100644
index 00000000000..d6420283bd5
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -0,0 +1,240 @@
+/* zd_usb.h: Header for USB interface implemented by ZD1211 chip
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_USB_H
+#define _ZD_USB_H
+
+#include <linux/completion.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+
+#include "zd_def.h"
+#include "zd_types.h"
+
+enum devicetype {
+ DEVICE_ZD1211 = 0,
+ DEVICE_ZD1211B = 1,
+};
+
+enum endpoints {
+ EP_CTRL = 0,
+ EP_DATA_OUT = 1,
+ EP_DATA_IN = 2,
+ EP_INT_IN = 3,
+ EP_REGS_OUT = 4,
+};
+
+enum {
+ USB_MAX_TRANSFER_SIZE = 4096, /* bytes */
+ /* FIXME: The original driver uses this value. We have to check,
+ * whether the MAX_TRANSFER_SIZE is sufficient and this needs only be
+ * used if one combined frame is split over two USB transactions.
+ */
+ USB_MAX_RX_SIZE = 4800, /* bytes */
+ USB_MAX_IOWRITE16_COUNT = 15,
+ USB_MAX_IOWRITE32_COUNT = USB_MAX_IOWRITE16_COUNT/2,
+ USB_MAX_IOREAD16_COUNT = 15,
+ USB_MAX_IOREAD32_COUNT = USB_MAX_IOREAD16_COUNT/2,
+ USB_MIN_RFWRITE_BIT_COUNT = 16,
+ USB_MAX_RFWRITE_BIT_COUNT = 28,
+ USB_MAX_EP_INT_BUFFER = 64,
+ USB_ZD1211B_BCD_DEVICE = 0x4810,
+};
+
+enum control_requests {
+ USB_REQ_WRITE_REGS = 0x21,
+ USB_REQ_READ_REGS = 0x22,
+ USB_REQ_WRITE_RF = 0x23,
+ USB_REQ_PROG_FLASH = 0x24,
+ USB_REQ_EEPROM_START = 0x0128, /* ? request is a byte */
+ USB_REQ_EEPROM_MID = 0x28,
+ USB_REQ_EEPROM_END = 0x0228, /* ? request is a byte */
+ USB_REQ_FIRMWARE_DOWNLOAD = 0x30,
+ USB_REQ_FIRMWARE_CONFIRM = 0x31,
+ USB_REQ_FIRMWARE_READ_DATA = 0x32,
+};
+
+struct usb_req_read_regs {
+ __le16 id;
+ __le16 addr[0];
+} __attribute__((packed));
+
+struct reg_data {
+ __le16 addr;
+ __le16 value;
+} __attribute__((packed));
+
+struct usb_req_write_regs {
+ __le16 id;
+ struct reg_data reg_writes[0];
+} __attribute__((packed));
+
+enum {
+ RF_IF_LE = 0x02,
+ RF_CLK = 0x04,
+ RF_DATA = 0x08,
+};
+
+struct usb_req_rfwrite {
+ __le16 id;
+ __le16 value;
+ /* 1: 3683a */
+ /* 2: other (default) */
+ __le16 bits;
+ /* RF2595: 24 */
+ __le16 bit_values[0];
+ /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
+} __attribute__((packed));
+
+/* USB interrupt */
+
+enum usb_int_id {
+ USB_INT_TYPE = 0x01,
+ USB_INT_ID_REGS = 0x90,
+ USB_INT_ID_RETRY_FAILED = 0xa0,
+};
+
+enum usb_int_flags {
+ USB_INT_READ_REGS_EN = 0x01,
+};
+
+struct usb_int_header {
+ u8 type; /* must always be 1 */
+ u8 id;
+} __attribute__((packed));
+
+struct usb_int_regs {
+ struct usb_int_header hdr;
+ struct reg_data regs[0];
+} __attribute__((packed));
+
+struct usb_int_retry_fail {
+ struct usb_int_header hdr;
+ u8 new_rate;
+ u8 _dummy;
+ u8 addr[ETH_ALEN];
+ u8 ibss_wakeup_dest;
+} __attribute__((packed));
+
+struct read_regs_int {
+ struct completion completion;
+ /* Stores the USB int structure and contains the USB address of the
+ * first requested register before request.
+ */
+ u8 buffer[USB_MAX_EP_INT_BUFFER];
+ int length;
+ __le16 cr_int_addr;
+};
+
+struct zd_ioreq16 {
+ zd_addr_t addr;
+ u16 value;
+};
+
+struct zd_ioreq32 {
+ zd_addr_t addr;
+ u32 value;
+};
+
+struct zd_usb_interrupt {
+ struct read_regs_int read_regs;
+ spinlock_t lock;
+ struct urb *urb;
+ int interval;
+ u8 read_regs_enabled:1;
+};
+
+static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)
+{
+ return (struct usb_int_regs *)intr->read_regs.buffer;
+}
+
+#define URBS_COUNT 5
+
+struct zd_usb_rx {
+ spinlock_t lock;
+ u8 fragment[2*USB_MAX_RX_SIZE];
+ unsigned int fragment_length;
+ unsigned int usb_packet_size;
+ struct urb **urbs;
+ int urbs_count;
+};
+
+struct zd_usb_tx {
+ spinlock_t lock;
+};
+
+/* Contains the usb parts. The structure doesn't require a lock, because intf
+ * and fw_base_offset, will not be changed after initialization.
+ */
+struct zd_usb {
+ struct zd_usb_interrupt intr;
+ struct zd_usb_rx rx;
+ struct zd_usb_tx tx;
+ struct usb_interface *intf;
+ u16 fw_base_offset;
+};
+
+#define zd_usb_dev(usb) (&usb->intf->dev)
+
+static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb)
+{
+ return interface_to_usbdev(usb->intf);
+}
+
+static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf)
+{
+ return usb_get_intfdata(intf);
+}
+
+static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb)
+{
+ return zd_intf_to_netdev(usb->intf);
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+ struct usb_interface *intf);
+int zd_usb_init_hw(struct zd_usb *usb);
+void zd_usb_clear(struct zd_usb *usb);
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size);
+
+int zd_usb_enable_int(struct zd_usb *usb);
+void zd_usb_disable_int(struct zd_usb *usb);
+
+int zd_usb_enable_rx(struct zd_usb *usb);
+void zd_usb_disable_rx(struct zd_usb *usb);
+
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length);
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+ const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_usb_ioread16(struct zd_usb *usb, u16 *value,
+ const zd_addr_t addr)
+{
+ return zd_usb_ioread16v(usb, value, (const zd_addr_t *)&addr, 1);
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+ unsigned int count);
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
+
+#endif /* _ZD_USB_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c
new file mode 100644
index 00000000000..d20036c15d1
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_util.c
@@ -0,0 +1,82 @@
+/* zd_util.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Utility program
+ */
+
+#include "zd_def.h"
+#include "zd_util.h"
+
+#ifdef DEBUG
+static char hex(u8 v)
+{
+ v &= 0xf;
+ return (v < 10 ? '0' : 'a' - 10) + v;
+}
+
+static char hex_print(u8 c)
+{
+ return (0x20 <= c && c < 0x7f) ? c : '.';
+}
+
+static void dump_line(const u8 *bytes, size_t size)
+{
+ char c;
+ size_t i;
+
+ size = size <= 8 ? size : 8;
+ printk(KERN_DEBUG "zd1211 %p ", bytes);
+ for (i = 0; i < 8; i++) {
+ switch (i) {
+ case 1:
+ case 5:
+ c = '.';
+ break;
+ case 3:
+ c = ':';
+ break;
+ default:
+ c = ' ';
+ }
+ if (i < size) {
+ printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
+ } else {
+ printk(" %c", c);
+ }
+ }
+
+ for (i = 0; i < size; i++)
+ printk("%c", hex_print(bytes[i]));
+ printk("\n");
+}
+
+void zd_hexdump(const void *bytes, size_t size)
+{
+ size_t i = 0;
+
+ do {
+ dump_line((u8 *)bytes + i, size-i);
+ i += 8;
+ } while (i < size);
+}
+#endif /* DEBUG */
+
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
+{
+ if (buffer_size < tail_size)
+ return NULL;
+ return (u8 *)buffer + (buffer_size - tail_size);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h
new file mode 100644
index 00000000000..ce26f7adea9
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_util.h
@@ -0,0 +1,29 @@
+/* zd_util.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_UTIL_H
+#define _ZD_UTIL_H
+
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
+
+#ifdef DEBUG
+void zd_hexdump(const void *bytes, size_t size);
+#else
+#define zd_hexdump(bytes, size)
+#endif /* DEBUG */
+
+#endif /* _ZD_UTIL_H */
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index bbbf7e274a2..8459a18254a 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -19,37 +19,13 @@
Support and updates available at
http://www.scyld.com/network/yellowfin.html
+ [link no longer provides useful info -jgarzik]
-
- Linux kernel changelog:
- -----------------------
-
- LK1.1.1 (jgarzik): Port to 2.4 kernel
-
- LK1.1.2 (jgarzik):
- * Merge in becker version 1.05
-
- LK1.1.3 (jgarzik):
- * Various cleanups
- * Update yellowfin_timer to correctly calculate duplex.
- (suggested by Manfred Spraul)
-
- LK1.1.4 (val@nmt.edu):
- * Fix three endian-ness bugs
- * Support dual function SYM53C885E ethernet chip
-
- LK1.1.5 (val@nmt.edu):
- * Fix forced full-duplex bug I introduced
-
- LK1.1.6 (val@nmt.edu):
- * Only print warning on truly "oversized" packets
- * Fix theoretical bug on gigabit cards - return to 1.1.3 behavior
-
*/
#define DRV_NAME "yellowfin"
-#define DRV_VERSION "1.05+LK1.1.6"
-#define DRV_RELDATE "Feb 11, 2002"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "Jun 27, 2006"
#define PFX DRV_NAME ": "
@@ -239,8 +215,11 @@ enum capability_flags {
HasMACAddrBug=32, /* Only on early revs. */
DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
};
+
/* The PCI I/O space extent. */
-#define YELLOWFIN_SIZE 0x100
+enum {
+ YELLOWFIN_SIZE = 0x100,
+};
struct pci_id_info {
const char *name;
@@ -248,16 +227,14 @@ struct pci_id_info {
int pci, pci_mask, subsystem, subsystem_mask;
int revision, revision_mask; /* Only 8 bits. */
} id;
- int io_size; /* Needed for I/O region check or ioremap(). */
int drv_flags; /* Driver use, intended as capability flags. */
};
static const struct pci_id_info pci_id_tbl[] = {
{"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
- YELLOWFIN_SIZE,
FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
- YELLOWFIN_SIZE, HasMII | DontUseEeprom },
+ HasMII | DontUseEeprom },
{ }
};
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 15f6cd4279b..77e7202a0eb 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -1052,7 +1052,7 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap)
{
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
ahci_start_engine(ap);
@@ -1323,6 +1323,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* JMicron-specific fixup: make sure we're in AHCI mode */
+ /* This is protected from races with ata_jmicron by the pci probe
+ locking */
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
+ /* AHCI enable, AHCI on function 0 */
+ pci_write_config_byte(pdev, 0x41, 0xa1);
+ /* Function 1 is the PATA controller */
+ if (PCI_FUNC(pdev->devfn))
+ return -ENODEV;
+ }
+
rc = pci_enable_device(pdev);
if (rc)
return rc;
@@ -1378,10 +1389,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (have_msi)
hpriv->flags |= AHCI_FLAG_MSI;
- /* JMicron-specific fixup: make sure we're in AHCI mode */
- if (pdev->vendor == 0x197b)
- pci_write_config_byte(pdev, 0x41, 0xa1);
-
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1c960ac1617..386e5f21e19 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -61,9 +61,9 @@
#include "libata.h"
/* debounce timing parameters in msecs { interval, duration, timeout } */
-const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
-const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
-const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };
+const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
+const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
+const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
@@ -907,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
{
int rc;
- if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+ if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
return;
PREPARE_WORK(&ap->port_task, fn, data);
@@ -938,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap)
DPRINTK("ENTER\n");
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+ ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
@@ -957,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap)
}
spin_lock_irqsave(ap->lock, flags);
- ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+ ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
if (ata_msg_ctl(ap))
@@ -1009,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_lock_irqsave(ap->lock, flags);
/* no internal command while frozen */
- if (ap->flags & ATA_FLAG_FROZEN) {
+ if (ap->pflags & ATA_PFLAG_FROZEN) {
spin_unlock_irqrestore(ap->lock, flags);
return AC_ERR_SYSTEM;
}
@@ -1325,6 +1325,19 @@ static void ata_dev_config_ncq(struct ata_device *dev,
snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
}
+static void ata_set_port_max_cmd_len(struct ata_port *ap)
+{
+ int i;
+
+ if (ap->host) {
+ ap->host->max_cmd_len = 0;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ap->host->max_cmd_len = max_t(unsigned int,
+ ap->host->max_cmd_len,
+ ap->device[i].cdb_len);
+ }
+}
+
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@@ -1344,7 +1357,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
struct ata_port *ap = dev->ap;
const u16 *id = dev->id;
unsigned int xfer_mask;
- int i, rc;
+ int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
ata_dev_printk(dev, KERN_INFO,
@@ -1404,7 +1417,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
/* print device info to dmesg */
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: %s %s\n",
ata_id_major_version(id),
@@ -1427,7 +1440,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: CHS %u/%u/%u\n",
ata_id_major_version(id),
@@ -1439,7 +1452,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
if (dev->id[59] & 0x100) {
dev->multi_count = dev->id[59] & 0xff;
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
"ata%u: dev %u multi count %u\n",
ap->id, dev->devno, dev->multi_count);
@@ -1468,21 +1481,17 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
ata_mode_string(xfer_mask),
cdb_intr_string);
}
- ap->host->max_cmd_len = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->host->max_cmd_len = max_t(unsigned int,
- ap->host->max_cmd_len,
- ap->device[i].cdb_len);
+ ata_set_port_max_cmd_len(ap);
/* limit bridge transfers to udma5, 200 sectors */
if (ata_dev_knobble(dev)) {
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
"applying bridge limits\n");
dev->udma_mask &= ATA_UDMA5;
@@ -2137,7 +2146,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* return error code and failing device on failure.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- if (ata_dev_enabled(&ap->device[i])) {
+ if (ata_dev_ready(&ap->device[i])) {
ap->ops->set_mode(ap);
break;
}
@@ -2203,7 +2212,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
dev = &ap->device[i];
- if (!ata_dev_enabled(dev))
+ /* don't udpate suspended devices' xfer mode */
+ if (!ata_dev_ready(dev))
continue;
rc = ata_dev_set_mode(dev);
@@ -2579,7 +2589,7 @@ static void ata_wait_spinup(struct ata_port *ap)
/* first, debounce phy if SATA */
if (ap->cbl == ATA_CBL_SATA) {
- rc = sata_phy_debounce(ap, sata_deb_timing_eh);
+ rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
/* if debounced successfully and offline, no need to wait */
if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
@@ -2615,16 +2625,17 @@ static void ata_wait_spinup(struct ata_port *ap)
int ata_std_prereset(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
- const unsigned long *timing;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
- /* hotplug? */
- if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
- if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
- ehc->i.action |= ATA_EH_HARDRESET;
- if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
- ata_wait_spinup(ap);
- }
+ /* handle link resume & hotplug spinup */
+ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+ (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
+ (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
+ ata_wait_spinup(ap);
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
@@ -2632,11 +2643,6 @@ int ata_std_prereset(struct ata_port *ap)
/* if SATA, resume phy */
if (ap->cbl == ATA_CBL_SATA) {
- if (ap->flags & ATA_FLAG_LOADING)
- timing = sata_deb_timing_boot;
- else
- timing = sata_deb_timing_eh;
-
rc = sata_phy_resume(ap, timing);
if (rc && rc != -EOPNOTSUPP) {
/* phy resume failed */
@@ -2724,6 +2730,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
*/
int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
u32 scontrol;
int rc;
@@ -2761,7 +2769,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
msleep(1);
/* bring phy back */
- sata_phy_resume(ap, sata_deb_timing_eh);
+ sata_phy_resume(ap, timing);
/* TODO: phy layer with polling, timeouts, etc. */
if (ata_port_offline(ap)) {
@@ -4285,7 +4293,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
unsigned int i;
/* no command while frozen */
- if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+ if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
/* the last tag is reserved for internal command. */
@@ -4407,7 +4415,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* taken care of.
*/
if (ap->ops->error_handler) {
- WARN_ON(ap->flags & ATA_FLAG_FROZEN);
+ WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
@@ -5001,86 +5009,120 @@ int ata_flush_cache(struct ata_device *dev)
return 0;
}
-static int ata_standby_drive(struct ata_device *dev)
+static int ata_host_set_request_pm(struct ata_host_set *host_set,
+ pm_message_t mesg, unsigned int action,
+ unsigned int ehi_flags, int wait)
{
- unsigned int err_mask;
+ unsigned long flags;
+ int i, rc;
- err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
- if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
- "(err_mask=0x%x)\n", err_mask);
- return -EIO;
- }
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
- return 0;
-}
+ /* Previous resume operation might still be in
+ * progress. Wait for PM_PENDING to clear.
+ */
+ if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ }
-static int ata_start_drive(struct ata_device *dev)
-{
- unsigned int err_mask;
+ /* request PM ops to EH */
+ spin_lock_irqsave(ap->lock, flags);
- err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
- if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to start drive "
- "(err_mask=0x%x)\n", err_mask);
- return -EIO;
+ ap->pm_mesg = mesg;
+ if (wait) {
+ rc = 0;
+ ap->pm_result = &rc;
+ }
+
+ ap->pflags |= ATA_PFLAG_PM_PENDING;
+ ap->eh_info.action |= action;
+ ap->eh_info.flags |= ehi_flags;
+
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait and check result */
+ if (wait) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ if (rc)
+ return rc;
+ }
}
return 0;
}
/**
- * ata_device_resume - wakeup a previously suspended devices
- * @dev: the device to resume
+ * ata_host_set_suspend - suspend host_set
+ * @host_set: host_set to suspend
+ * @mesg: PM message
*
- * Kick the drive back into action, by sending it an idle immediate
- * command and making sure its transfer mode matches between drive
- * and host.
+ * Suspend @host_set. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and waits for EH
+ * to finish.
*
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-int ata_device_resume(struct ata_device *dev)
+int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
{
- struct ata_port *ap = dev->ap;
+ int i, j, rc;
- if (ap->flags & ATA_FLAG_SUSPENDED) {
- struct ata_device *failed_dev;
+ rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
+ if (rc)
+ goto fail;
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
- ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
+ /* EH is quiescent now. Fail if we have any ready device.
+ * This happens if hotplug occurs between completion of device
+ * suspension and here.
+ */
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
- ap->flags &= ~ATA_FLAG_SUSPENDED;
- while (ata_set_mode(ap, &failed_dev))
- ata_dev_disable(failed_dev);
+ for (j = 0; j < ATA_MAX_DEVICES; j++) {
+ struct ata_device *dev = &ap->device[j];
+
+ if (ata_dev_ready(dev)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "suspend failed, device %d "
+ "still active\n", dev->devno);
+ rc = -EBUSY;
+ goto fail;
+ }
+ }
}
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_start_drive(dev);
+ host_set->dev->power.power_state = mesg;
return 0;
+
+ fail:
+ ata_host_set_resume(host_set);
+ return rc;
}
/**
- * ata_device_suspend - prepare a device for suspend
- * @dev: the device to suspend
- * @state: target power management state
+ * ata_host_set_resume - resume host_set
+ * @host_set: host_set to resume
+ *
+ * Resume @host_set. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and returns.
+ * Note that all resume operations are performed parallely.
*
- * Flush the cache on the drive, if appropriate, then issue a
- * standbynow command.
+ * LOCKING:
+ * Kernel thread context (may sleep).
*/
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
+void ata_host_set_resume(struct ata_host_set *host_set)
{
- struct ata_port *ap = dev->ap;
-
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_flush_cache(dev);
-
- if (state.event != PM_EVENT_FREEZE)
- ata_standby_drive(dev);
- ap->flags |= ATA_FLAG_SUSPENDED;
- return 0;
+ ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET,
+ ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+ host_set->dev->power.power_state = PMSG_ON;
}
/**
@@ -5440,6 +5482,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
if (ap->ops->error_handler) {
+ struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
ata_port_probe(ap);
@@ -5447,10 +5490,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
- ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
+ ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
- ap->flags |= ATA_FLAG_LOADING;
+ ap->pflags |= ATA_PFLAG_LOADING;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
@@ -5518,7 +5562,7 @@ void ata_port_detach(struct ata_port *ap)
/* tell EH we're leaving & flush EH */
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_UNLOADING;
+ ap->pflags |= ATA_PFLAG_UNLOADING;
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
@@ -5723,20 +5767,55 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
return (tmp == bits->val) ? 1 : 0;
}
-int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state)
{
pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
- return 0;
+
+ if (state.event == PM_EVENT_SUSPEND) {
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
}
-int ata_pci_device_resume(struct pci_dev *pdev)
+void ata_pci_device_do_resume(struct pci_dev *pdev)
{
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_device(pdev);
pci_set_master(pdev);
+}
+
+int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+ int rc = 0;
+
+ rc = ata_host_set_suspend(host_set, state);
+ if (rc)
+ return rc;
+
+ if (host_set->next) {
+ rc = ata_host_set_suspend(host_set->next, state);
+ if (rc) {
+ ata_host_set_resume(host_set);
+ return rc;
+ }
+ }
+
+ ata_pci_device_do_suspend(pdev, state);
+
+ return 0;
+}
+
+int ata_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ ata_host_set_resume(host_set);
+ if (host_set->next)
+ ata_host_set_resume(host_set->next);
+
return 0;
}
#endif /* CONFIG_PCI */
@@ -5842,9 +5921,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
* Do not depend on ABI/API stability.
*/
-EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
-EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
-EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
+EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+EXPORT_SYMBOL_GPL(sata_deb_timing_long);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add);
@@ -5916,6 +5995,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
EXPORT_SYMBOL_GPL(ata_port_online);
EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_host_set_suspend);
+EXPORT_SYMBOL_GPL(ata_host_set_resume);
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
@@ -5930,14 +6011,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_resume);
EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index bf5a72aca8a..4b6aa30f4d6 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -47,6 +47,8 @@
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
+static void ata_eh_handle_port_suspend(struct ata_port *ap);
+static void ata_eh_handle_port_resume(struct ata_port *ap);
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
@@ -190,7 +192,6 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
- spinlock_t *ap_lock = ap->lock;
int i, repeat_cnt = ATA_EH_MAX_REPEAT;
unsigned long flags;
@@ -217,7 +218,7 @@ void ata_scsi_error(struct Scsi_Host *host)
struct scsi_cmnd *scmd, *tmp;
int nr_timedout = 0;
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
struct ata_queued_cmd *qc;
@@ -256,43 +257,49 @@ void ata_scsi_error(struct Scsi_Host *host)
if (nr_timedout)
__ata_port_freeze(ap);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else
- spin_unlock_wait(ap_lock);
+ spin_unlock_wait(ap->lock);
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ /* process port resume request */
+ ata_eh_handle_port_resume(ap);
+
/* fetch & clear EH info */
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
memset(&ap->eh_context, 0, sizeof(ap->eh_context));
ap->eh_context.i = ap->eh_info;
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
- ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
- ap->flags &= ~ATA_FLAG_EH_PENDING;
+ ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING;
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
- /* invoke EH. if unloading, just finish failed qcs */
- if (!(ap->flags & ATA_FLAG_UNLOADING))
+ /* invoke EH, skip if unloading or suspended */
+ if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
ap->ops->error_handler(ap);
else
ata_eh_finish(ap);
+ /* process port suspend request */
+ ata_eh_handle_port_suspend(ap);
+
/* Exception might have happend after ->error_handler
* recovered the port but before this point. Repeat
* EH in such case.
*/
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
- if (ap->flags & ATA_FLAG_EH_PENDING) {
+ if (ap->pflags & ATA_PFLAG_EH_PENDING) {
if (--repeat_cnt) {
ata_port_printk(ap, KERN_INFO,
"EH pending after completion, "
"repeating EH (cnt=%d)\n", repeat_cnt);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
@@ -302,14 +309,14 @@ void ata_scsi_error(struct Scsi_Host *host)
/* this run is complete, make sure EH info is clear */
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
- /* Clear host_eh_scheduled while holding ap_lock such
+ /* Clear host_eh_scheduled while holding ap->lock such
* that if exception occurs after this point but
* before EH completion, SCSI midlayer will
* re-initiate EH.
*/
host->host_eh_scheduled = 0;
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else {
WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
ap->ops->eng_timeout(ap);
@@ -321,24 +328,23 @@ void ata_scsi_error(struct Scsi_Host *host)
scsi_eh_flush_done_q(&ap->eh_done_q);
/* clean up */
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
- if (ap->flags & ATA_FLAG_LOADING) {
- ap->flags &= ~ATA_FLAG_LOADING;
- } else {
- if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
- queue_work(ata_aux_wq, &ap->hotplug_task);
- if (ap->flags & ATA_FLAG_RECOVERED)
- ata_port_printk(ap, KERN_INFO, "EH complete\n");
- }
+ if (ap->pflags & ATA_PFLAG_LOADING)
+ ap->pflags &= ~ATA_PFLAG_LOADING;
+ else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
+ queue_work(ata_aux_wq, &ap->hotplug_task);
+
+ if (ap->pflags & ATA_PFLAG_RECOVERED)
+ ata_port_printk(ap, KERN_INFO, "EH complete\n");
- ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
+ ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
/* tell wait_eh that we're done */
- ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
+ ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
wake_up_all(&ap->eh_wait_q);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("EXIT\n");
}
@@ -360,7 +366,7 @@ void ata_port_wait_eh(struct ata_port *ap)
retry:
spin_lock_irqsave(ap->lock, flags);
- while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
+ while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
spin_unlock_irqrestore(ap->lock, flags);
schedule();
@@ -489,7 +495,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED;
- qc->ap->flags |= ATA_FLAG_EH_PENDING;
+ qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
@@ -513,7 +519,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
{
WARN_ON(!ap->ops->error_handler);
- ap->flags |= ATA_FLAG_EH_PENDING;
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
scsi_schedule_eh(ap->host);
DPRINTK("port EH scheduled\n");
@@ -578,7 +584,7 @@ static void __ata_port_freeze(struct ata_port *ap)
if (ap->ops->freeze)
ap->ops->freeze(ap);
- ap->flags |= ATA_FLAG_FROZEN;
+ ap->pflags |= ATA_PFLAG_FROZEN;
DPRINTK("ata%u port frozen\n", ap->id);
}
@@ -646,7 +652,7 @@ void ata_eh_thaw_port(struct ata_port *ap)
spin_lock_irqsave(ap->lock, flags);
- ap->flags &= ~ATA_FLAG_FROZEN;
+ ap->pflags &= ~ATA_PFLAG_FROZEN;
if (ap->ops->thaw)
ap->ops->thaw(ap);
@@ -731,7 +737,7 @@ static void ata_eh_detach_dev(struct ata_device *dev)
if (ata_scsi_offline_dev(dev)) {
dev->flags |= ATA_DFLAG_DETACHED;
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
}
/* clear per-dev EH actions */
@@ -760,8 +766,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
unsigned long flags;
spin_lock_irqsave(ap->lock, flags);
+
ata_eh_clear_action(dev, &ap->eh_info, action);
- ap->flags |= ATA_FLAG_RECOVERED;
+
+ if (!(ap->eh_context.i.flags & ATA_EHI_QUIET))
+ ap->pflags |= ATA_PFLAG_RECOVERED;
+
spin_unlock_irqrestore(ap->lock, flags);
}
@@ -1027,7 +1037,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
int tag, rc;
/* if frozen, we can't do much */
- if (ap->flags & ATA_FLAG_FROZEN)
+ if (ap->pflags & ATA_PFLAG_FROZEN)
return;
/* is it NCQ device error? */
@@ -1275,6 +1285,9 @@ static void ata_eh_autopsy(struct ata_port *ap)
DPRINTK("ENTER\n");
+ if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
+ return;
+
/* obtain and analyze SError */
rc = sata_scr_read(ap, SCR_ERROR, &serror);
if (rc == 0) {
@@ -1327,7 +1340,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
}
/* enforce default EH actions */
- if (ap->flags & ATA_FLAG_FROZEN ||
+ if (ap->pflags & ATA_PFLAG_FROZEN ||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
action |= ATA_EH_SOFTRESET;
else if (all_err_mask)
@@ -1346,7 +1359,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
/* record autopsy result */
ehc->i.dev = failed_dev;
- ehc->i.action = action;
+ ehc->i.action |= action;
DPRINTK("EXIT\n");
}
@@ -1385,7 +1398,7 @@ static void ata_eh_report(struct ata_port *ap)
return;
frozen = "";
- if (ap->flags & ATA_FLAG_FROZEN)
+ if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
if (ehc->i.dev) {
@@ -1465,7 +1478,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
struct ata_eh_context *ehc = &ap->eh_context;
unsigned int *classes = ehc->classes;
int tries = ATA_EH_RESET_TRIES;
- int verbose = !(ap->flags & ATA_FLAG_LOADING);
+ int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
unsigned int action;
ata_reset_fn_t reset;
int i, did_followup_srst, rc;
@@ -1605,7 +1618,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
dev = &ap->device[i];
action = ata_eh_dev_action(dev);
- if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
+ if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
if (ata_port_offline(ap)) {
rc = -EIO;
break;
@@ -1636,7 +1649,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
}
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
spin_unlock_irqrestore(ap->lock, flags);
}
}
@@ -1648,6 +1661,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
+/**
+ * ata_eh_suspend - handle suspend EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle suspend EH action. Disk devices are spinned down and
+ * other types of devices are just marked suspended. Once
+ * suspended, no EH action to the device is allowed until it is
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned long flags;
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
+ continue;
+
+ WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ /* flush cache */
+ rc = ata_flush_cache(dev);
+ if (rc)
+ break;
+
+ /* spin down */
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin down (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags |= ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_done(ap, dev, ATA_EH_SUSPEND);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
+/**
+ * ata_eh_prep_resume - prep for resume EH action
+ * @ap: target host port
+ *
+ * Clear SUSPENDED in preparation for scheduled resume actions.
+ * This allows other parts of EH to access the devices being
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_prep_resume(struct ata_port *ap)
+{
+ struct ata_device *dev;
+ unsigned long flags;
+ int i;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eh_resume - handle resume EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle resume EH action. Target devices are already reset and
+ * revalidated. Spinning up is the only operation left.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ err_mask = ata_do_simple_cmd(dev,
+ ATA_CMD_IDLEIMMEDIATE);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin up (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ ata_eh_done(ap, dev, ATA_EH_RESUME);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
static int ata_port_nr_enabled(struct ata_port *ap)
{
int i, cnt = 0;
@@ -1673,7 +1844,19 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
struct ata_eh_context *ehc = &ap->eh_context;
int i;
- if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
+ /* skip if all possible devices are suspended */
+ for (i = 0; i < ata_port_max_devices(ap); i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (ata_dev_absent(dev) || ata_dev_ready(dev))
+ break;
+ }
+
+ if (i == ata_port_max_devices(ap))
+ return 1;
+
+ /* always thaw frozen port and recover failed devices */
+ if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap))
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
@@ -1744,9 +1927,12 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = 0;
/* if UNLOADING, finish immediately */
- if (ap->flags & ATA_FLAG_UNLOADING)
+ if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
+ /* prep for resume */
+ ata_eh_prep_resume(ap);
+
/* skip EH if possible. */
if (ata_eh_skip_recovery(ap))
ehc->i.action = 0;
@@ -1774,6 +1960,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (rc)
goto dev_fail;
+ /* resume devices */
+ rc = ata_eh_resume(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
/* configure transfer mode if the port has been reset */
if (ehc->i.flags & ATA_EHI_DID_RESET) {
rc = ata_set_mode(ap, &dev);
@@ -1783,6 +1974,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
}
}
+ /* suspend devices */
+ rc = ata_eh_suspend(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
goto out;
dev_fail:
@@ -1908,11 +2104,124 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
- if (!(ap->flags & ATA_FLAG_LOADING)) {
- ata_eh_autopsy(ap);
- ata_eh_report(ap);
- }
-
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
ata_eh_finish(ap);
}
+
+/**
+ * ata_eh_handle_port_suspend - perform port suspend operation
+ * @ap: port to suspend
+ *
+ * Suspend @ap.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_suspend(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ /* are we suspending? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event == PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+
+ /* suspend */
+ ata_eh_freeze_port(ap);
+
+ if (ap->ops->port_suspend)
+ rc = ap->ops->port_suspend(ap, ap->pm_mesg);
+
+ /* report result */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->pflags &= ~ATA_PFLAG_PM_PENDING;
+ if (rc == 0)
+ ap->pflags |= ATA_PFLAG_SUSPENDED;
+ else
+ ata_port_schedule_eh(ap);
+
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return;
+}
+
+/**
+ * ata_eh_handle_port_resume - perform port resume operation
+ * @ap: port to resume
+ *
+ * Resume @ap.
+ *
+ * This function also waits upto one second until all devices
+ * hanging off this port requests resume EH action. This is to
+ * prevent invoking EH and thus reset multiple times on resume.
+ *
+ * On DPM resume, where some of devices might not be resumed
+ * together, this may delay port resume upto one second, but such
+ * DPM resumes are rare and 1 sec delay isn't too bad.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_resume(struct ata_port *ap)
+{
+ unsigned long timeout;
+ unsigned long flags;
+ int i, rc = 0;
+
+ /* are we resuming? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event != PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* spurious? */
+ if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
+ goto done;
+
+ if (ap->ops->port_resume)
+ rc = ap->ops->port_resume(ap);
+
+ /* give devices time to request EH */
+ timeout = jiffies + HZ; /* 1s max */
+ while (1) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned int action = ata_eh_dev_action(dev);
+
+ if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
+ !(action & ATA_EH_RESUME))
+ break;
+ }
+
+ if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
+ break;
+ msleep(10);
+ }
+
+ done:
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 2915bca691e..7ced41ecde8 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
}
}
-int ata_scsi_device_resume(struct scsi_device *sdev)
+/**
+ * ata_scsi_device_suspend - suspend ATA device associated with sdev
+ * @sdev: the SCSI device to suspend
+ * @state: target power management state
+ *
+ * Request suspend EH action on the ATA device associated with
+ * @sdev and wait for the operation to complete.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ unsigned long flags;
+ unsigned int action;
+ int rc = 0;
+
+ if (!dev)
+ goto out;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* wait for the previous resume to complete */
+ while (dev->flags & ATA_DFLAG_SUSPENDED) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_port_wait_eh(ap);
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
+
+ /* request suspend */
+ action = ATA_EH_SUSPEND;
+ if (state.event != PM_EVENT_SUSPEND)
+ action |= ATA_EH_PM_FREEZE;
+ ap->eh_info.dev_action[dev->devno] |= action;
+ ap->eh_info.flags |= ATA_EHI_QUIET;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to do the job */
+ ata_port_wait_eh(ap);
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* If @sdev is still attached but the associated ATA device
+ * isn't suspended, the operation failed.
+ */
+ if (sdev->sdev_state != SDEV_OFFLINE &&
+ sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
+ !(dev->flags & ATA_DFLAG_SUSPENDED))
+ rc = -EIO;
- return ata_device_resume(dev);
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ if (rc == 0)
+ sdev->sdev_gendev.power.power_state = state;
+ return rc;
}
-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
+/**
+ * ata_scsi_device_resume - resume ATA device associated with sdev
+ * @sdev: the SCSI device to resume
+ *
+ * Request resume EH action on the ATA device associated with
+ * @sdev and return immediately. This enables parallel
+ * wakeup/spinup of devices.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0.
+ */
+int ata_scsi_device_resume(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned long flags;
+ unsigned int action;
+
+ if (!dev)
+ goto out;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
- return ata_device_suspend(dev, state);
+ /* request resume */
+ action = ATA_EH_RESUME;
+ if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
+ __ata_ehi_hotplugged(ehi);
+ else
+ action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
+ ehi->dev_action[dev->devno] |= action;
+
+ /* We don't want autopsy and verbose EH messages. Disable
+ * those if we're the only device on this link.
+ */
+ if (ata_port_max_devices(ap) == 1)
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+ ata_port_schedule_eh(ap);
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ sdev->sdev_gendev.power.power_state = PMSG_ON;
+ return 0;
}
/**
@@ -2930,7 +3039,7 @@ void ata_scsi_hotplug(void *data)
struct ata_port *ap = data;
int i;
- if (ap->flags & ATA_FLAG_UNLOADING) {
+ if (ap->pflags & ATA_PFLAG_UNLOADING) {
DPRINTK("ENTER/EXIT - unloading\n");
return;
}
@@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
if (dev) {
ap->eh_info.probe_mask |= 1 << dev->devno;
ap->eh_info.action |= ATA_EH_SOFTRESET;
+ ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
} else
rc = -EINVAL;
}
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 7aabb45c35e..d0a85073ebf 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -109,6 +109,7 @@ enum {
};
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil_pci_device_resume(struct pci_dev *pdev);
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = {
.id_table = sil_pci_tbl,
.probe = sil_init_one,
.remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = sil_pci_device_resume,
};
static struct scsi_host_template sil_sht = {
@@ -178,6 +181,8 @@ static struct scsi_host_template sil_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil_ops = {
@@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* during hardreset makes controllers with broken SIEN
* repeat probing needlessly.
*/
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
ata_ehi_hotplugged(&ap->eh_info);
ap->eh_info.serror |= serror;
}
@@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
}
}
+static void sil_init_controller(struct pci_dev *pdev,
+ int n_ports, unsigned long host_flags,
+ void __iomem *mmio_base)
+{
+ u8 cls;
+ u32 tmp;
+ int i;
+
+ /* Initialize FIFO PCI bus arbitration */
+ cls = sil_get_device_cache_line(pdev);
+ if (cls) {
+ cls >>= 3;
+ cls++; /* cls = (line_size/8)+1 */
+ for (i = 0; i < n_ports; i++)
+ writew(cls << 8 | cls,
+ mmio_base + sil_port[i].fifo_cfg);
+ } else
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "cache line size not set. Driver may not function\n");
+
+ /* Apply R_ERR on DMA activate FIS errata workaround */
+ if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ int cnt;
+
+ for (i = 0, cnt = 0; i < n_ports; i++) {
+ tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+ if ((tmp & 0x3) != 0x01)
+ continue;
+ if (!cnt)
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying R_ERR on DMA activate "
+ "FIS errata fix\n");
+ writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+ cnt++;
+ }
+ }
+
+ if (n_ports == 4) {
+ /* flip the magic "make 4 ports work" bit */
+ tmp = readl(mmio_base + sil_port[2].bmdma);
+ if ((tmp & SIL_INTR_STEERING) == 0)
+ writel(tmp | SIL_INTR_STEERING,
+ mmio_base + sil_port[2].bmdma);
+ }
+}
+
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
unsigned int i;
int pci_dev_busy = 0;
- u32 tmp;
- u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ata_std_ports(&probe_ent->port[i]);
}
- /* Initialize FIFO PCI bus arbitration */
- cls = sil_get_device_cache_line(pdev);
- if (cls) {
- cls >>= 3;
- cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < probe_ent->n_ports; i++)
- writew(cls << 8 | cls,
- mmio_base + sil_port[i].fifo_cfg);
- } else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
-
- /* Apply R_ERR on DMA activate FIS errata workaround */
- if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
- int cnt;
-
- for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
- tmp = readl(mmio_base + sil_port[i].sfis_cfg);
- if ((tmp & 0x3) != 0x01)
- continue;
- if (!cnt)
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying R_ERR on DMA activate "
- "FIS errata fix\n");
- writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
- cnt++;
- }
- }
-
- if (ent->driver_data == sil_3114) {
- /* flip the magic "make 4 ports work" bit */
- tmp = readl(mmio_base + sil_port[2].bmdma);
- if ((tmp & SIL_INTR_STEERING) == 0)
- writel(tmp | SIL_INTR_STEERING,
- mmio_base + sil_port[2].bmdma);
- }
+ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ mmio_base);
pci_set_master(pdev);
@@ -685,6 +700,18 @@ err_out:
return rc;
}
+static int sil_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
+ host_set->mmio_base);
+ ata_host_set_resume(host_set);
+
+ return 0;
+}
+
static int __init sil_init(void)
{
return pci_module_init(&sil_pci_driver);
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 07a1c6a8a41..2e0f4a4076a 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -92,6 +92,7 @@ enum {
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+ HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
/*
* Port registers
@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap);
static void sil24_port_stop(struct ata_port *ap);
static void sil24_host_stop(struct ata_host_set *host_set);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil24_pci_device_resume(struct pci_dev *pdev);
static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = {
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
.remove = ata_pci_remove_one, /* safe? */
+ .suspend = ata_pci_device_suspend,
+ .resume = sil24_pci_device_resume,
};
static struct scsi_host_template sil24_sht = {
@@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil24_ops = {
@@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
- rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
+ rc = sata_phy_debounce(ap, sata_deb_timing_long);
if (rc) {
reason = "PHY debouncing failed";
goto err;
@@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set)
kfree(hpriv);
}
+static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+ unsigned long host_flags,
+ void __iomem *host_base,
+ void __iomem *port_base)
+{
+ u32 tmp;
+ int i;
+
+ /* GPIO off */
+ writel(0, host_base + HOST_FLASH_CMD);
+
+ /* clear global reset & mask interrupts during initialization */
+ writel(0, host_base + HOST_CTRL);
+
+ /* init ports */
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
+
+ /* Initial PHY setting */
+ writel(0x20c, port + PORT_PHY_CFG);
+
+ /* Clear port RST */
+ tmp = readl(port + PORT_CTRL_STAT);
+ if (tmp & PORT_CS_PORT_RST) {
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_PORT_RST,
+ PORT_CS_PORT_RST, 10, 100);
+ if (tmp & PORT_CS_PORT_RST)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to clear port RST\n");
+ }
+
+ /* Configure IRQ WoC */
+ if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* Zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* Always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* Clear port multiplier enable and resume bits */
+ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+ }
+
+ /* Turn on interrupts */
+ writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+}
+
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@@ -1076,9 +1140,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- /* GPIO off */
- writel(0, host_base + HOST_FLASH_CMD);
-
/* Apply workaround for completion IRQ loss on PCI-X errata */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(host_base + HOST_CTRL);
@@ -1090,56 +1151,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
}
- /* clear global reset & mask interrupts during initialization */
- writel(0, host_base + HOST_CTRL);
-
for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
- unsigned long portu = (unsigned long)port;
+ unsigned long portu =
+ (unsigned long)port_base + i * PORT_REGS_SIZE;
probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
-
- /* Initial PHY setting */
- writel(0x20c, port + PORT_PHY_CFG);
-
- /* Clear port RST */
- tmp = readl(port + PORT_CTRL_STAT);
- if (tmp & PORT_CS_PORT_RST) {
- writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_PORT_RST,
- PORT_CS_PORT_RST, 10, 100);
- if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to clear port RST\n");
- }
-
- /* Configure IRQ WoC */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
- /* Turn on interrupts */
- writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ host_base, port_base);
pci_set_master(pdev);
@@ -1162,6 +1185,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
+static int sil24_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+ struct sil24_host_priv *hpriv = host_set->private_data;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+ writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+
+ sil24_init_controller(pdev, host_set->n_ports,
+ host_set->ports[0]->flags,
+ hpriv->host_base, hpriv->port_base);
+
+ ata_host_set_resume(host_set);
+
+ return 0;
+}
+
static int __init sil24_init(void)
{
return pci_module_init(&sil24_pci_driver);
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 916fe6fba75..ad37871594f 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_mmio_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c
index a7d664383da..54c6b2adf7b 100644
--- a/drivers/serial/at91_serial.c
+++ b/drivers/serial/at91_serial.c
@@ -41,6 +41,7 @@
#include <asm/mach/serial_at91.h>
#include <asm/arch/board.h>
#include <asm/arch/system.h>
+#include <asm/arch/gpio.h>
#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -140,9 +141,9 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
*/
if (port->mapbase == AT91_BASE_US0) {
if (mctrl & TIOCM_RTS)
- at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0);
+ at91_set_gpio_value(AT91_PIN_PA21, 0);
else
- at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0);
+ at91_set_gpio_value(AT91_PIN_PA21, 1);
}
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 5980c45998c..89ba0df14c2 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
fl->fl_ops = &nlmclnt_lock_ops;
}
-static void do_vfs_lock(struct file_lock *fl)
+static int do_vfs_lock(struct file_lock *fl)
{
int res = 0;
switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
@@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl)
default:
BUG();
}
- if (res < 0)
- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
- __FUNCTION__);
+ return res;
}
/*
@@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
struct nlm_wait *block = NULL;
+ unsigned char fl_flags = fl->fl_flags;
int status = -ENOLCK;
if (!host->h_monitored && nsm_monitor(host) < 0) {
@@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
host->h_name);
goto out;
}
+ fl->fl_flags |= FL_ACCESS;
+ status = do_vfs_lock(fl);
+ if (status < 0)
+ goto out;
block = nlmclnt_prepare_block(host, fl);
again:
@@ -539,9 +542,10 @@ again:
up_read(&host->h_rwsem);
goto again;
}
- fl->fl_flags |= FL_SLEEP;
/* Ensure the resulting lock will get added to granted list */
- do_vfs_lock(fl);
+ fl->fl_flags = fl_flags | FL_SLEEP;
+ if (do_vfs_lock(fl) < 0)
+ printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
up_read(&host->h_rwsem);
}
status = nlm_stat_to_errno(resp->status);
@@ -552,6 +556,7 @@ out_unblock:
nlmclnt_cancel(host, req->a_args.block, fl);
out:
nlm_release_call(req);
+ fl->fl_flags = fl_flags;
return status;
}
@@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
{
struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
- int status;
+ int status = 0;
/*
* Note: the server is supposed to either grant us the unlock
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
* case, we want to unlock.
*/
+ fl->fl_flags |= FL_EXISTS;
down_read(&host->h_rwsem);
- do_vfs_lock(fl);
+ if (do_vfs_lock(fl) == -ENOENT) {
+ up_read(&host->h_rwsem);
+ goto out;
+ }
up_read(&host->h_rwsem);
if (req->a_flags & RPC_TASK_ASYNC)
@@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
if (status < 0)
goto out;
- status = 0;
if (resp->status == NLM_LCK_GRANTED)
goto out;
diff --git a/fs/locks.c b/fs/locks.c
index 1ad29c9b625..b0b41a64e10 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -725,6 +725,10 @@ next_task:
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
* at the head of the list, but that's secret knowledge known only to
* flock_lock_file and posix_lock_file.
+ *
+ * Note that if called with an FL_EXISTS argument, the caller may determine
+ * whether or not a lock was successfully freed by testing the return
+ * value for -ENOENT.
*/
static int flock_lock_file(struct file *filp, struct file_lock *request)
{
@@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
int found = 0;
lock_kernel();
+ if (request->fl_flags & FL_ACCESS)
+ goto find_conflict;
for_each_lock(inode, before) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
@@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
break;
}
- if (request->fl_type == F_UNLCK)
+ if (request->fl_type == F_UNLCK) {
+ if ((request->fl_flags & FL_EXISTS) && !found)
+ error = -ENOENT;
goto out;
+ }
error = -ENOMEM;
new_fl = locks_alloc_lock();
@@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
if (found)
cond_resched();
+find_conflict:
for_each_lock(inode, before) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
@@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
locks_insert_block(fl, request);
goto out;
}
+ if (request->fl_flags & FL_ACCESS)
+ goto out;
locks_copy_lock(new_fl, request);
locks_insert_lock(&inode->i_flock, new_fl);
new_fl = NULL;
@@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
error = 0;
if (!added) {
- if (request->fl_type == F_UNLCK)
+ if (request->fl_type == F_UNLCK) {
+ if (request->fl_flags & FL_EXISTS)
+ error = -ENOENT;
goto out;
+ }
if (!new_fl) {
error = -ENOLCK;
@@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
* Add a POSIX style lock to a file.
* We merge adjacent & overlapping locks whenever possible.
* POSIX locks are sorted by owner task, then by starting address
+ *
+ * Note that if called with an FL_EXISTS argument, the caller may determine
+ * whether or not a lock was successfully freed by testing the return
+ * value for -ENOENT.
*/
int posix_lock_file(struct file *filp, struct file_lock *fl)
{
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 3ddda6f7ecc..e7ffb4deb3e 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -690,7 +690,9 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
goto out_force;
/* This is an open(2) */
if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
- !(server->flags & NFS_MOUNT_NOCTO))
+ !(server->flags & NFS_MOUNT_NOCTO) &&
+ (S_ISREG(inode->i_mode) ||
+ S_ISDIR(inode->i_mode)))
goto out_force;
}
return nfs_revalidate_inode(server, inode);
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 4cdd1b499e3..fecd3b095de 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -67,25 +67,19 @@ struct nfs_direct_req {
struct kref kref; /* release manager */
/* I/O parameters */
- struct list_head list, /* nfs_read/write_data structs */
- rewrite_list; /* saved nfs_write_data structs */
struct nfs_open_context *ctx; /* file open context info */
struct kiocb * iocb; /* controlling i/o request */
struct inode * inode; /* target file of i/o */
- unsigned long user_addr; /* location of user's buffer */
- size_t user_count; /* total bytes to move */
- loff_t pos; /* starting offset in file */
- struct page ** pages; /* pages in our buffer */
- unsigned int npages; /* count of pages */
/* completion state */
+ atomic_t io_count; /* i/os we're waiting for */
spinlock_t lock; /* protect completion state */
- int outstanding; /* i/os we're waiting for */
ssize_t count, /* bytes actually processed */
error; /* any reported error */
struct completion completion; /* wait for i/o completion */
/* commit state */
+ struct list_head rewrite_list; /* saved nfs_write_data structs */
struct nfs_write_data * commit_data; /* special write_data for commits */
int flags;
#define NFS_ODIRECT_DO_COMMIT (1) /* an unstable reply was received */
@@ -93,8 +87,37 @@ struct nfs_direct_req {
struct nfs_writeverf verf; /* unstable write verifier */
};
-static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync);
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode);
+static const struct rpc_call_ops nfs_write_direct_ops;
+
+static inline void get_dreq(struct nfs_direct_req *dreq)
+{
+ atomic_inc(&dreq->io_count);
+}
+
+static inline int put_dreq(struct nfs_direct_req *dreq)
+{
+ return atomic_dec_and_test(&dreq->io_count);
+}
+
+/*
+ * "size" is never larger than rsize or wsize.
+ */
+static inline int nfs_direct_count_pages(unsigned long user_addr, size_t size)
+{
+ int page_count;
+
+ page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ page_count -= user_addr >> PAGE_SHIFT;
+ BUG_ON(page_count < 0);
+
+ return page_count;
+}
+
+static inline unsigned int nfs_max_pages(unsigned int size)
+{
+ return (size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+}
/**
* nfs_direct_IO - NFS address space operation for direct I/O
@@ -118,50 +141,21 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
return -EINVAL;
}
-static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
+static void nfs_direct_dirty_pages(struct page **pages, int npages)
{
int i;
for (i = 0; i < npages; i++) {
struct page *page = pages[i];
- if (do_dirty && !PageCompound(page))
+ if (!PageCompound(page))
set_page_dirty_lock(page);
- page_cache_release(page);
}
- kfree(pages);
}
-static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages)
+static void nfs_direct_release_pages(struct page **pages, int npages)
{
- int result = -ENOMEM;
- unsigned long page_count;
- size_t array_size;
-
- page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- page_count -= user_addr >> PAGE_SHIFT;
-
- array_size = (page_count * sizeof(struct page *));
- *pages = kmalloc(array_size, GFP_KERNEL);
- if (*pages) {
- down_read(&current->mm->mmap_sem);
- result = get_user_pages(current, current->mm, user_addr,
- page_count, (rw == READ), 0,
- *pages, NULL);
- up_read(&current->mm->mmap_sem);
- if (result != page_count) {
- /*
- * If we got fewer pages than expected from
- * get_user_pages(), the user buffer runs off the
- * end of a mapping; return EFAULT.
- */
- if (result >= 0) {
- nfs_free_user_pages(*pages, result, 0);
- result = -EFAULT;
- } else
- kfree(*pages);
- *pages = NULL;
- }
- }
- return result;
+ int i;
+ for (i = 0; i < npages; i++)
+ page_cache_release(pages[i]);
}
static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
@@ -173,13 +167,13 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
return NULL;
kref_init(&dreq->kref);
+ kref_get(&dreq->kref);
init_completion(&dreq->completion);
- INIT_LIST_HEAD(&dreq->list);
INIT_LIST_HEAD(&dreq->rewrite_list);
dreq->iocb = NULL;
dreq->ctx = NULL;
spin_lock_init(&dreq->lock);
- dreq->outstanding = 0;
+ atomic_set(&dreq->io_count, 0);
dreq->count = 0;
dreq->error = 0;
dreq->flags = 0;
@@ -220,18 +214,11 @@ out:
}
/*
- * We must hold a reference to all the pages in this direct read request
- * until the RPCs complete. This could be long *after* we are woken up in
- * nfs_direct_wait (for instance, if someone hits ^C on a slow server).
- *
- * In addition, synchronous I/O uses a stack-allocated iocb. Thus we
- * can't trust the iocb is still valid here if this is a synchronous
- * request. If the waiter is woken prematurely, the iocb is long gone.
+ * Synchronous I/O uses a stack-allocated iocb. Thus we can't trust
+ * the iocb is still valid here if this is a synchronous request.
*/
static void nfs_direct_complete(struct nfs_direct_req *dreq)
{
- nfs_free_user_pages(dreq->pages, dreq->npages, 1);
-
if (dreq->iocb) {
long res = (long) dreq->error;
if (!res)
@@ -244,48 +231,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
}
/*
- * Note we also set the number of requests we have in the dreq when we are
- * done. This prevents races with I/O completion so we will always wait
- * until all requests have been dispatched and completed.
+ * We must hold a reference to all the pages in this direct read request
+ * until the RPCs complete. This could be long *after* we are woken up in
+ * nfs_direct_wait (for instance, if someone hits ^C on a slow server).
*/
-static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, size_t rsize)
-{
- struct list_head *list;
- struct nfs_direct_req *dreq;
- unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
- dreq = nfs_direct_req_alloc();
- if (!dreq)
- return NULL;
-
- list = &dreq->list;
- for(;;) {
- struct nfs_read_data *data = nfs_readdata_alloc(rpages);
-
- if (unlikely(!data)) {
- while (!list_empty(list)) {
- data = list_entry(list->next,
- struct nfs_read_data, pages);
- list_del(&data->pages);
- nfs_readdata_free(data);
- }
- kref_put(&dreq->kref, nfs_direct_req_release);
- return NULL;
- }
-
- INIT_LIST_HEAD(&data->pages);
- list_add(&data->pages, list);
-
- data->req = (struct nfs_page *) dreq;
- dreq->outstanding++;
- if (nbytes <= rsize)
- break;
- nbytes -= rsize;
- }
- kref_get(&dreq->kref);
- return dreq;
-}
-
static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
{
struct nfs_read_data *data = calldata;
@@ -294,6 +243,9 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
if (nfs_readpage_result(task, data) != 0)
return;
+ nfs_direct_dirty_pages(data->pagevec, data->npages);
+ nfs_direct_release_pages(data->pagevec, data->npages);
+
spin_lock(&dreq->lock);
if (likely(task->tk_status >= 0))
@@ -301,13 +253,10 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
else
dreq->error = task->tk_status;
- if (--dreq->outstanding) {
- spin_unlock(&dreq->lock);
- return;
- }
-
spin_unlock(&dreq->lock);
- nfs_direct_complete(dreq);
+
+ if (put_dreq(dreq))
+ nfs_direct_complete(dreq);
}
static const struct rpc_call_ops nfs_read_direct_ops = {
@@ -316,41 +265,60 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
};
/*
- * For each nfs_read_data struct that was allocated on the list, dispatch
- * an NFS READ operation
+ * For each rsize'd chunk of the user's buffer, dispatch an NFS READ
+ * operation. If nfs_readdata_alloc() or get_user_pages() fails,
+ * bail and stop sending more reads. Read length accounting is
+ * handled automatically by nfs_direct_read_result(). Otherwise, if
+ * no requests have been sent, just return an error.
*/
-static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
+static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
{
struct nfs_open_context *ctx = dreq->ctx;
struct inode *inode = ctx->dentry->d_inode;
- struct list_head *list = &dreq->list;
- struct page **pages = dreq->pages;
- size_t count = dreq->user_count;
- loff_t pos = dreq->pos;
size_t rsize = NFS_SERVER(inode)->rsize;
- unsigned int curpage, pgbase;
+ unsigned int rpages = nfs_max_pages(rsize);
+ unsigned int pgbase;
+ int result;
+ ssize_t started = 0;
+
+ get_dreq(dreq);
- curpage = 0;
- pgbase = dreq->user_addr & ~PAGE_MASK;
+ pgbase = user_addr & ~PAGE_MASK;
do {
struct nfs_read_data *data;
size_t bytes;
+ result = -ENOMEM;
+ data = nfs_readdata_alloc(rpages);
+ if (unlikely(!data))
+ break;
+
bytes = rsize;
if (count < rsize)
bytes = count;
- BUG_ON(list_empty(list));
- data = list_entry(list->next, struct nfs_read_data, pages);
- list_del_init(&data->pages);
+ data->npages = nfs_direct_count_pages(user_addr, bytes);
+ down_read(&current->mm->mmap_sem);
+ result = get_user_pages(current, current->mm, user_addr,
+ data->npages, 1, 0, data->pagevec, NULL);
+ up_read(&current->mm->mmap_sem);
+ if (unlikely(result < data->npages)) {
+ if (result > 0)
+ nfs_direct_release_pages(data->pagevec, result);
+ nfs_readdata_release(data);
+ break;
+ }
+
+ get_dreq(dreq);
+ data->req = (struct nfs_page *) dreq;
data->inode = inode;
data->cred = ctx->cred;
data->args.fh = NFS_FH(inode);
data->args.context = ctx;
data->args.offset = pos;
data->args.pgbase = pgbase;
- data->args.pages = &pages[curpage];
+ data->args.pages = data->pagevec;
data->args.count = bytes;
data->res.fattr = &data->fattr;
data->res.eof = 0;
@@ -373,33 +341,35 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
bytes,
(unsigned long long)data->args.offset);
+ started += bytes;
+ user_addr += bytes;
pos += bytes;
pgbase += bytes;
- curpage += pgbase >> PAGE_SHIFT;
pgbase &= ~PAGE_MASK;
count -= bytes;
} while (count != 0);
- BUG_ON(!list_empty(list));
+
+ if (put_dreq(dreq))
+ nfs_direct_complete(dreq);
+
+ if (started)
+ return 0;
+ return result < 0 ? (ssize_t) result : -EFAULT;
}
-static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, unsigned int nr_pages)
+static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
{
- ssize_t result;
+ ssize_t result = 0;
sigset_t oldset;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_direct_req *dreq;
- dreq = nfs_direct_read_alloc(count, NFS_SERVER(inode)->rsize);
+ dreq = nfs_direct_req_alloc();
if (!dreq)
return -ENOMEM;
- dreq->user_addr = user_addr;
- dreq->user_count = count;
- dreq->pos = pos;
- dreq->pages = pages;
- dreq->npages = nr_pages;
dreq->inode = inode;
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
if (!is_sync_kiocb(iocb))
@@ -407,8 +377,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
rpc_clnt_sigmask(clnt, &oldset);
- nfs_direct_read_schedule(dreq);
- result = nfs_direct_wait(dreq);
+ result = nfs_direct_read_schedule(dreq, user_addr, count, pos);
+ if (!result)
+ result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);
return result;
@@ -416,10 +387,10 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
{
- list_splice_init(&dreq->rewrite_list, &dreq->list);
- while (!list_empty(&dreq->list)) {
- struct nfs_write_data *data = list_entry(dreq->list.next, struct nfs_write_data, pages);
+ while (!list_empty(&dreq->rewrite_list)) {
+ struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages);
list_del(&data->pages);
+ nfs_direct_release_pages(data->pagevec, data->npages);
nfs_writedata_release(data);
}
}
@@ -427,14 +398,51 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
{
- struct list_head *pos;
+ struct inode *inode = dreq->inode;
+ struct list_head *p;
+ struct nfs_write_data *data;
- list_splice_init(&dreq->rewrite_list, &dreq->list);
- list_for_each(pos, &dreq->list)
- dreq->outstanding++;
dreq->count = 0;
+ get_dreq(dreq);
+
+ list_for_each(p, &dreq->rewrite_list) {
+ data = list_entry(p, struct nfs_write_data, pages);
+
+ get_dreq(dreq);
+
+ /*
+ * Reset data->res.
+ */
+ nfs_fattr_init(&data->fattr);
+ data->res.count = data->args.count;
+ memset(&data->verf, 0, sizeof(data->verf));
+
+ /*
+ * Reuse data->task; data->args should not have changed
+ * since the original request was sent.
+ */
+ rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC,
+ &nfs_write_direct_ops, data);
+ NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE);
+
+ data->task.tk_priority = RPC_PRIORITY_NORMAL;
+ data->task.tk_cookie = (unsigned long) inode;
+
+ /*
+ * We're called via an RPC callback, so BKL is already held.
+ */
+ rpc_execute(&data->task);
+
+ dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
+ data->task.tk_pid,
+ inode->i_sb->s_id,
+ (long long)NFS_FILEID(inode),
+ data->args.count,
+ (unsigned long long)data->args.offset);
+ }
- nfs_direct_write_schedule(dreq, FLUSH_STABLE);
+ if (put_dreq(dreq))
+ nfs_direct_write_complete(dreq, inode);
}
static void nfs_direct_commit_result(struct rpc_task *task, void *calldata)
@@ -471,8 +479,8 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
data->cred = dreq->ctx->cred;
data->args.fh = NFS_FH(data->inode);
- data->args.offset = dreq->pos;
- data->args.count = dreq->user_count;
+ data->args.offset = 0;
+ data->args.count = 0;
data->res.count = 0;
data->res.fattr = &data->fattr;
data->res.verf = &data->verf;
@@ -534,47 +542,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
}
#endif
-static struct nfs_direct_req *nfs_direct_write_alloc(size_t nbytes, size_t wsize)
-{
- struct list_head *list;
- struct nfs_direct_req *dreq;
- unsigned int wpages = (wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
- dreq = nfs_direct_req_alloc();
- if (!dreq)
- return NULL;
-
- list = &dreq->list;
- for(;;) {
- struct nfs_write_data *data = nfs_writedata_alloc(wpages);
-
- if (unlikely(!data)) {
- while (!list_empty(list)) {
- data = list_entry(list->next,
- struct nfs_write_data, pages);
- list_del(&data->pages);
- nfs_writedata_free(data);
- }
- kref_put(&dreq->kref, nfs_direct_req_release);
- return NULL;
- }
-
- INIT_LIST_HEAD(&data->pages);
- list_add(&data->pages, list);
-
- data->req = (struct nfs_page *) dreq;
- dreq->outstanding++;
- if (nbytes <= wsize)
- break;
- nbytes -= wsize;
- }
-
- nfs_alloc_commit_data(dreq);
-
- kref_get(&dreq->kref);
- return dreq;
-}
-
static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
{
struct nfs_write_data *data = calldata;
@@ -604,8 +571,6 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
}
}
}
- /* In case we have to resend */
- data->args.stable = NFS_FILE_SYNC;
spin_unlock(&dreq->lock);
}
@@ -619,14 +584,8 @@ static void nfs_direct_write_release(void *calldata)
struct nfs_write_data *data = calldata;
struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req;
- spin_lock(&dreq->lock);
- if (--dreq->outstanding) {
- spin_unlock(&dreq->lock);
- return;
- }
- spin_unlock(&dreq->lock);
-
- nfs_direct_write_complete(dreq, data->inode);
+ if (put_dreq(dreq))
+ nfs_direct_write_complete(dreq, data->inode);
}
static const struct rpc_call_ops nfs_write_direct_ops = {
@@ -635,41 +594,62 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
};
/*
- * For each nfs_write_data struct that was allocated on the list, dispatch
- * an NFS WRITE operation
+ * For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE
+ * operation. If nfs_writedata_alloc() or get_user_pages() fails,
+ * bail and stop sending more writes. Write length accounting is
+ * handled automatically by nfs_direct_write_result(). Otherwise, if
+ * no requests have been sent, just return an error.
*/
-static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
+static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
{
struct nfs_open_context *ctx = dreq->ctx;
struct inode *inode = ctx->dentry->d_inode;
- struct list_head *list = &dreq->list;
- struct page **pages = dreq->pages;
- size_t count = dreq->user_count;
- loff_t pos = dreq->pos;
size_t wsize = NFS_SERVER(inode)->wsize;
- unsigned int curpage, pgbase;
+ unsigned int wpages = nfs_max_pages(wsize);
+ unsigned int pgbase;
+ int result;
+ ssize_t started = 0;
- curpage = 0;
- pgbase = dreq->user_addr & ~PAGE_MASK;
+ get_dreq(dreq);
+
+ pgbase = user_addr & ~PAGE_MASK;
do {
struct nfs_write_data *data;
size_t bytes;
+ result = -ENOMEM;
+ data = nfs_writedata_alloc(wpages);
+ if (unlikely(!data))
+ break;
+
bytes = wsize;
if (count < wsize)
bytes = count;
- BUG_ON(list_empty(list));
- data = list_entry(list->next, struct nfs_write_data, pages);
+ data->npages = nfs_direct_count_pages(user_addr, bytes);
+ down_read(&current->mm->mmap_sem);
+ result = get_user_pages(current, current->mm, user_addr,
+ data->npages, 0, 0, data->pagevec, NULL);
+ up_read(&current->mm->mmap_sem);
+ if (unlikely(result < data->npages)) {
+ if (result > 0)
+ nfs_direct_release_pages(data->pagevec, result);
+ nfs_writedata_release(data);
+ break;
+ }
+
+ get_dreq(dreq);
+
list_move_tail(&data->pages, &dreq->rewrite_list);
+ data->req = (struct nfs_page *) dreq;
data->inode = inode;
data->cred = ctx->cred;
data->args.fh = NFS_FH(inode);
data->args.context = ctx;
data->args.offset = pos;
data->args.pgbase = pgbase;
- data->args.pages = &pages[curpage];
+ data->args.pages = data->pagevec;
data->args.count = bytes;
data->res.fattr = &data->fattr;
data->res.count = bytes;
@@ -693,19 +673,26 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
bytes,
(unsigned long long)data->args.offset);
+ started += bytes;
+ user_addr += bytes;
pos += bytes;
pgbase += bytes;
- curpage += pgbase >> PAGE_SHIFT;
pgbase &= ~PAGE_MASK;
count -= bytes;
} while (count != 0);
- BUG_ON(!list_empty(list));
+
+ if (put_dreq(dreq))
+ nfs_direct_write_complete(dreq, inode);
+
+ if (started)
+ return 0;
+ return result < 0 ? (ssize_t) result : -EFAULT;
}
-static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, int nr_pages)
+static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
{
- ssize_t result;
+ ssize_t result = 0;
sigset_t oldset;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
@@ -713,17 +700,14 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
size_t wsize = NFS_SERVER(inode)->wsize;
int sync = 0;
- dreq = nfs_direct_write_alloc(count, wsize);
+ dreq = nfs_direct_req_alloc();
if (!dreq)
return -ENOMEM;
+ nfs_alloc_commit_data(dreq);
+
if (dreq->commit_data == NULL || count < wsize)
sync = FLUSH_STABLE;
- dreq->user_addr = user_addr;
- dreq->user_count = count;
- dreq->pos = pos;
- dreq->pages = pages;
- dreq->npages = nr_pages;
dreq->inode = inode;
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
if (!is_sync_kiocb(iocb))
@@ -734,8 +718,9 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
nfs_begin_data_update(inode);
rpc_clnt_sigmask(clnt, &oldset);
- nfs_direct_write_schedule(dreq, sync);
- result = nfs_direct_wait(dreq);
+ result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
+ if (!result)
+ result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);
return result;
@@ -765,8 +750,6 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
{
ssize_t retval = -EINVAL;
- int page_count;
- struct page **pages;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
@@ -788,14 +771,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count,
if (retval)
goto out;
- retval = nfs_get_user_pages(READ, (unsigned long) buf,
- count, &pages);
- if (retval < 0)
- goto out;
- page_count = retval;
-
- retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos,
- pages, page_count);
+ retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos);
if (retval > 0)
iocb->ki_pos = pos + retval;
@@ -831,8 +807,6 @@ out:
ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
{
ssize_t retval;
- int page_count;
- struct page **pages;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
@@ -860,14 +834,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t
if (retval)
goto out;
- retval = nfs_get_user_pages(WRITE, (unsigned long) buf,
- count, &pages);
- if (retval < 0)
- goto out;
- page_count = retval;
-
- retval = nfs_direct_write(iocb, (unsigned long) buf, count,
- pos, pages, page_count);
+ retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
/*
* XXX: nfs_end_data_update() already ensures this file's
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index b4916b09219..e6ee97f19d8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
default:
BUG();
}
- if (res < 0)
- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
- __FUNCTION__);
return res;
}
@@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
return ERR_PTR(-ENOMEM);
}
- /* Unlock _before_ we do the RPC call */
- do_vfs_lock(fl->fl_file, fl);
return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
}
@@ -3270,30 +3265,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
struct rpc_task *task;
int status = 0;
- /* Is this a delegated lock? */
- if (test_bit(NFS_DELEGATED_STATE, &state->flags))
- goto out_unlock;
- /* Is this open_owner holding any locks on the server? */
- if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
- goto out_unlock;
-
status = nfs4_set_lock_state(state, request);
+ /* Unlock _before_ we do the RPC call */
+ request->fl_flags |= FL_EXISTS;
+ if (do_vfs_lock(request->fl_file, request) == -ENOENT)
+ goto out;
if (status != 0)
- goto out_unlock;
+ goto out;
+ /* Is this a delegated lock? */
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags))
+ goto out;
lsp = request->fl_u.nfs4_fl.owner;
- status = -ENOMEM;
seqid = nfs_alloc_seqid(&lsp->ls_seqid);
+ status = -ENOMEM;
if (seqid == NULL)
- goto out_unlock;
+ goto out;
task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
status = PTR_ERR(task);
if (IS_ERR(task))
- goto out_unlock;
+ goto out;
status = nfs4_wait_for_completion_rpc_task(task);
rpc_release_task(task);
- return status;
-out_unlock:
- do_vfs_lock(request->fl_file, request);
+out:
return status;
}
@@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
struct nfs4_exception exception = { };
int err;
- /* Cache the lock if possible... */
- if (test_bit(NFS_DELEGATED_STATE, &state->flags))
- return 0;
do {
+ /* Cache the lock if possible... */
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
+ return 0;
err = _nfs4_do_setlk(state, F_SETLK, request, 1);
if (err != -NFS4ERR_DELAY)
break;
@@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
if (err != 0)
return err;
do {
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
+ return 0;
err = _nfs4_do_setlk(state, F_SETLK, request, 0);
if (err != -NFS4ERR_DELAY)
break;
@@ -3494,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{
struct nfs4_client *clp = state->owner->so_client;
+ unsigned char fl_flags = request->fl_flags;
int status;
/* Is this a delegated open? */
- if (NFS_I(state->inode)->delegation_state != 0) {
- /* Yes: cache locks! */
- status = do_vfs_lock(request->fl_file, request);
- /* ...but avoid races with delegation recall... */
- if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags))
- return status;
- }
- down_read(&clp->cl_sem);
status = nfs4_set_lock_state(state, request);
if (status != 0)
goto out;
+ request->fl_flags |= FL_ACCESS;
+ status = do_vfs_lock(request->fl_file, request);
+ if (status < 0)
+ goto out;
+ down_read(&clp->cl_sem);
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
+ struct nfs_inode *nfsi = NFS_I(state->inode);
+ /* Yes: cache locks! */
+ down_read(&nfsi->rwsem);
+ /* ...but avoid races with delegation recall... */
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
+ request->fl_flags = fl_flags & ~FL_SLEEP;
+ status = do_vfs_lock(request->fl_file, request);
+ up_read(&nfsi->rwsem);
+ goto out_unlock;
+ }
+ up_read(&nfsi->rwsem);
+ }
status = _nfs4_do_setlk(state, cmd, request, 0);
if (status != 0)
- goto out;
+ goto out_unlock;
/* Note: we always want to sleep here! */
- request->fl_flags |= FL_SLEEP;
+ request->fl_flags = fl_flags | FL_SLEEP;
if (do_vfs_lock(request->fl_file, request) < 0)
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
-out:
+out_unlock:
up_read(&clp->cl_sem);
+out:
+ request->fl_flags = fl_flags;
return status;
}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index bca5734ca9f..86bac6a5008 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -578,7 +578,7 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
return ret;
}
-static void nfs_cancel_requests(struct list_head *head)
+static void nfs_cancel_dirty_list(struct list_head *head)
{
struct nfs_page *req;
while(!list_empty(head)) {
@@ -589,6 +589,19 @@ static void nfs_cancel_requests(struct list_head *head)
}
}
+static void nfs_cancel_commit_list(struct list_head *head)
+{
+ struct nfs_page *req;
+
+ while(!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_inode_remove_request(req);
+ nfs_clear_page_writeback(req);
+ dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+ }
+}
+
/*
* nfs_scan_dirty - Scan an inode for dirty requests
* @inode: NFS inode to scan
@@ -1381,6 +1394,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
nfs_list_remove_request(req);
nfs_mark_request_commit(req);
nfs_clear_page_writeback(req);
+ dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
}
return -ENOMEM;
}
@@ -1499,7 +1513,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
if (pages != 0) {
spin_unlock(&nfsi->req_lock);
if (how & FLUSH_INVALIDATE)
- nfs_cancel_requests(&head);
+ nfs_cancel_dirty_list(&head);
else
ret = nfs_flush_list(inode, &head, pages, how);
spin_lock(&nfsi->req_lock);
@@ -1512,7 +1526,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
break;
if (how & FLUSH_INVALIDATE) {
spin_unlock(&nfsi->req_lock);
- nfs_cancel_requests(&head);
+ nfs_cancel_commit_list(&head);
spin_lock(&nfsi->req_lock);
continue;
}
diff --git a/include/asm-arm/arch-at91rm9200/irqs.h b/include/asm-arm/arch-at91rm9200/irqs.h
index 2dc93b174a8..f63842c2c09 100644
--- a/include/asm-arm/arch-at91rm9200/irqs.h
+++ b/include/asm-arm/arch-at91rm9200/irqs.h
@@ -39,12 +39,4 @@
*/
#define NR_IRQS (NR_AIC_IRQS + (4 * 32))
-
-#ifndef __ASSEMBLY__
-/*
- * Initialize the IRQ controller.
- */
-extern void at91rm9200_init_irq(unsigned int priority[]);
-#endif
-
#endif
diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h
index 0f5b89c9323..27c46fbeebd 100644
--- a/include/asm-sparc64/dma-mapping.h
+++ b/include/asm-sparc64/dma-mapping.h
@@ -160,6 +160,20 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
BUG();
}
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
#endif /* PCI */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 134b3206824..43aef9b230f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -716,6 +716,7 @@ extern spinlock_t files_lock;
#define FL_POSIX 1
#define FL_FLOCK 2
#define FL_ACCESS 8 /* not trying to lock, just looking */
+#define FL_EXISTS 16 /* when unlocking, test for existence */
#define FL_LEASE 32 /* lease held on this file */
#define FL_CLOSE 64 /* unlock on close */
#define FL_SLEEP 128 /* A blocking lock */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index f4284bf8975..6cc497a2b6d 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -131,6 +131,7 @@ enum {
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
+ ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */
ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
ATA_DFLAG_DETACH = (1 << 16),
@@ -160,22 +161,28 @@ enum {
ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
* Register FIS clearing BSY */
-
ATA_FLAG_DEBUGMSG = (1 << 13),
- ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
- ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
- ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
- ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
- ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
- ATA_FLAG_LOADING = (1 << 19), /* boot/loading probe */
- ATA_FLAG_UNLOADING = (1 << 20), /* module is unloading */
- ATA_FLAG_SCSI_HOTPLUG = (1 << 21), /* SCSI hotplug scheduled */
+ /* The following flag belongs to ap->pflags but is kept in
+ * ap->flags because it's referenced in many LLDs and will be
+ * removed in not-too-distant future.
+ */
+ ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */
+
+ /* bits 24:31 of ap->flags are reserved for LLD specific flags */
- ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */
- ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */
+ /* struct ata_port pflags */
+ ATA_PFLAG_EH_PENDING = (1 << 0), /* EH pending */
+ ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */
+ ATA_PFLAG_FROZEN = (1 << 2), /* port is frozen */
+ ATA_PFLAG_RECOVERED = (1 << 3), /* recovery action performed */
+ ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */
+ ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */
+ ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
- /* bits 24:31 of ap->flags are reserved for LLDD specific flags */
+ ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
+ ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
+ ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
/* struct ata_queued_cmd flags */
ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
@@ -248,12 +255,19 @@ enum {
ATA_EH_REVALIDATE = (1 << 0),
ATA_EH_SOFTRESET = (1 << 1),
ATA_EH_HARDRESET = (1 << 2),
+ ATA_EH_SUSPEND = (1 << 3),
+ ATA_EH_RESUME = (1 << 4),
+ ATA_EH_PM_FREEZE = (1 << 5),
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
- ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
+ ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_SUSPEND |
+ ATA_EH_RESUME | ATA_EH_PM_FREEZE,
/* ata_eh_info->flags */
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
+ ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */
+ ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
+ ATA_EHI_QUIET = (1 << 3), /* be quiet */
ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
@@ -486,6 +500,7 @@ struct ata_port {
const struct ata_port_operations *ops;
spinlock_t *lock;
unsigned long flags; /* ATA_FLAG_xxx */
+ unsigned int pflags; /* ATA_PFLAG_xxx */
unsigned int id; /* unique id req'd by scsi midlyr */
unsigned int port_no; /* unique port #; from zero */
unsigned int hard_port_no; /* hardware port #; from zero */
@@ -535,6 +550,9 @@ struct ata_port {
struct list_head eh_done_q;
wait_queue_head_t eh_wait_q;
+ pm_message_t pm_mesg;
+ int *pm_result;
+
void *private_data;
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@@ -589,6 +607,9 @@ struct ata_port_operations {
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val);
+ int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
+ int (*port_resume) (struct ata_port *ap);
+
int (*port_start) (struct ata_port *ap);
void (*port_stop) (struct ata_port *ap);
@@ -622,9 +643,18 @@ struct ata_timing {
#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin)
-extern const unsigned long sata_deb_timing_boot[];
-extern const unsigned long sata_deb_timing_eh[];
-extern const unsigned long sata_deb_timing_before_fsrst[];
+extern const unsigned long sata_deb_timing_normal[];
+extern const unsigned long sata_deb_timing_hotplug[];
+extern const unsigned long sata_deb_timing_long[];
+
+static inline const unsigned long *
+sata_ehc_deb_timing(struct ata_eh_context *ehc)
+{
+ if (ehc->i.flags & ATA_EHI_HOTPLUGGED)
+ return sata_deb_timing_hotplug;
+ else
+ return sata_deb_timing_normal;
+}
extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap);
@@ -644,6 +674,8 @@ extern void ata_std_ports(struct ata_ioports *ioaddr);
extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports);
extern void ata_pci_remove_one (struct pci_dev *pdev);
+extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state);
+extern void ata_pci_device_do_resume(struct pci_dev *pdev);
extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
extern int ata_pci_device_resume(struct pci_dev *pdev);
extern int ata_pci_clear_simplex(struct pci_dev *pdev);
@@ -664,8 +696,9 @@ extern int ata_port_online(struct ata_port *ap);
extern int ata_port_offline(struct ata_port *ap);
extern int ata_scsi_device_resume(struct scsi_device *);
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
-extern int ata_device_resume(struct ata_device *);
-extern int ata_device_suspend(struct ata_device *, pm_message_t state);
+extern int ata_host_set_suspend(struct ata_host_set *host_set,
+ pm_message_t mesg);
+extern void ata_host_set_resume(struct ata_host_set *host_set);
extern int ata_ratelimit(void);
extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat,
@@ -825,19 +858,24 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
(ehi)->desc_len = 0; \
} while (0)
-static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
+static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
if (ehi->flags & ATA_EHI_HOTPLUGGED)
return;
- ehi->flags |= ATA_EHI_HOTPLUGGED;
+ ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
ehi->hotplug_timestamp = jiffies;
- ehi->err_mask |= AC_ERR_ATA_BUS;
ehi->action |= ATA_EH_SOFTRESET;
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
}
+static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
+{
+ __ata_ehi_hotplugged(ehi);
+ ehi->err_mask |= AC_ERR_ATA_BUS;
+}
+
/*
* qc helpers
*/
@@ -921,6 +959,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
return ata_class_absent(dev->class);
}
+static inline unsigned int ata_dev_ready(const struct ata_device *dev)
+{
+ return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED);
+}
+
/*
* port helpers
*/
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 7c7320fa51a..2d3fb6416d9 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -729,6 +729,7 @@ struct nfs_read_data {
struct list_head pages; /* Coalesced read requests */
struct nfs_page *req; /* multi ops per nfs_page */
struct page **pagevec;
+ unsigned int npages; /* active pages in pagevec */
struct nfs_readargs args;
struct nfs_readres res;
#ifdef CONFIG_NFS_V4
@@ -747,6 +748,7 @@ struct nfs_write_data {
struct list_head pages; /* Coalesced requests we wish to flush */
struct nfs_page *req; /* multi ops per nfs_page */
struct page **pagevec;
+ unsigned int npages; /* active pages in pagevec */
struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */
#ifdef CONFIG_NFS_V4
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 685081c0134..c09396d2c77 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2019,6 +2019,13 @@
#define PCI_VENDOR_ID_TDI 0x192E
#define PCI_DEVICE_ID_TDI_EHCI 0x0101
+#define PCI_VENDOR_ID_JMICRON 0x197B
+#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
+#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
+#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
+#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
+#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
+#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
index 7a483ab4022..00ad810eb88 100644
--- a/include/net/ieee80211softmac.h
+++ b/include/net/ieee80211softmac.h
@@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info {
*/
u8 static_essid:1,
associating:1,
+ assoc_wait:1,
bssvalid:1,
bssfixed:1;
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 47ccf159372..72d4d4e04d4 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -368,6 +368,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* Put this code here so that we avoid duplicating it in all
* Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
/* If spy monitoring on */
if (ieee->spy_data.spy_number > 0) {
@@ -396,15 +397,16 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
}
#endif /* IW_WIRELESS_SPY */
+#endif /* CONFIG_WIRELESS_EXT */
#ifdef NOT_YET
hostap_update_rx_stats(local->ap, hdr, rx_stats);
#endif
if (ieee->iw_mode == IW_MODE_MONITOR) {
- ieee80211_monitor_rx(ieee, skb, rx_stats);
stats->rx_packets++;
stats->rx_bytes += skb->len;
+ ieee80211_monitor_rx(ieee, skb, rx_stats);
return 1;
}
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index de148ae594f..bf042139c7a 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -562,10 +562,13 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
struct net_device_stats *stats = &ieee->stats;
struct sk_buff *skb_frag;
int priority = -1;
+ int fraglen = total_len;
+ int headroom = ieee->tx_headroom;
+ struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
spin_lock_irqsave(&ieee->lock, flags);
- if (encrypt_mpdu && !ieee->sec.encrypt)
+ if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
encrypt_mpdu = 0;
/* If there is no driver handler to take the TXB, dont' bother
@@ -581,20 +584,24 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
goto success;
}
- if (encrypt_mpdu)
+ if (encrypt_mpdu) {
frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ fraglen += crypt->ops->extra_mpdu_prefix_len +
+ crypt->ops->extra_mpdu_postfix_len;
+ headroom += crypt->ops->extra_mpdu_prefix_len;
+ }
/* When we allocate the TXB we allocate enough space for the reserve
* and full fragment bytes (bytes_per_frag doesn't include prefix,
* postfix, header, FCS, etc.) */
- txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC);
+ txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
if (unlikely(!txb)) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
ieee->dev->name);
goto failed;
}
txb->encrypted = 0;
- txb->payload_size = total_len;
+ txb->payload_size = fraglen;
skb_frag = txb->fragments[0];
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index 5e9a90651d0..44215ce64d4 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
dprintk(KERN_INFO PFX "sent association request!\n");
- /* Change the state to associating */
spin_lock_irqsave(&mac->lock, flags);
- mac->associnfo.associating = 1;
mac->associated = 0; /* just to make sure */
/* Set a timer for timeout */
@@ -63,6 +61,7 @@ void
ieee80211softmac_assoc_timeout(void *d)
{
struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
+ struct ieee80211softmac_network *n;
unsigned long flags;
spin_lock_irqsave(&mac->lock, flags);
@@ -75,11 +74,12 @@ ieee80211softmac_assoc_timeout(void *d)
mac->associnfo.associating = 0;
mac->associnfo.bssvalid = 0;
mac->associated = 0;
+
+ n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
spin_unlock_irqrestore(&mac->lock, flags);
dprintk(KERN_INFO PFX "assoc request timed out!\n");
- /* FIXME: we need to know the network here. that requires a bit of restructuring */
- ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
+ ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
}
void
@@ -203,6 +203,10 @@ ieee80211softmac_assoc_work(void *d)
if (mac->associated)
ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
+ spin_lock_irqsave(&mac->lock, flags);
+ mac->associnfo.associating = 1;
+ spin_unlock_irqrestore(&mac->lock, flags);
+
/* try to find the requested network in our list, if we found one already */
if (bssvalid || mac->associnfo.bssfixed)
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
@@ -295,19 +299,32 @@ ieee80211softmac_assoc_work(void *d)
memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
/* we found a network! authenticate (if necessary) and associate to it. */
- if (!found->authenticated) {
+ if (found->authenticating) {
+ dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
+ if(!mac->associnfo.assoc_wait) {
+ mac->associnfo.assoc_wait = 1;
+ ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+ }
+ return;
+ }
+ if (!found->authenticated && !found->authenticating) {
/* This relies on the fact that _auth_req only queues the work,
* otherwise adding the notification would be racy. */
if (!ieee80211softmac_auth_req(mac, found)) {
- dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
- ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+ if(!mac->associnfo.assoc_wait) {
+ dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
+ mac->associnfo.assoc_wait = 1;
+ ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+ }
} else {
printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
+ mac->associnfo.assoc_wait = 0;
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
}
return;
}
/* finally! now we can start associating */
+ mac->associnfo.assoc_wait = 0;
ieee80211softmac_assoc(mac, found);
}
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 90b8484e509..ebc33ca6e69 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
struct ieee80211softmac_auth_queue_item *auth;
unsigned long flags;
- if (net->authenticating)
+ if (net->authenticating || net->authenticated)
return 0;
+ net->authenticating = 1;
/* Add the network if it's not already added */
ieee80211softmac_add_network(mac, net);
@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
return;
}
net->authenticated = 0;
- net->authenticating = 1;
/* add a timeout call so we eventually give up waiting for an auth reply */
schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
auth->retry--;
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
index 09541611e48..8cc8b20f5cd 100644
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -229,6 +229,9 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
+ /* Fill in the capabilities */
+ (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
+
/* Fill in Listen Interval (?) */
(*pkt)->listen_interval = cpu_to_le16(10);
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 0e65ff4e33f..75320b6842a 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -70,12 +70,44 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
char *extra)
{
struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+ struct ieee80211softmac_network *n;
+ struct ieee80211softmac_auth_queue_item *authptr;
int length = 0;
unsigned long flags;
-
+
+ /* Check if we're already associating to this or another network
+ * If it's another network, cancel and start over with our new network
+ * If it's our network, ignore the change, we're already doing it!
+ */
+ if((sm->associnfo.associating || sm->associated) &&
+ (data->essid.flags && data->essid.length && extra)) {
+ /* Get the associating network */
+ n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
+ if(n && n->essid.len == (data->essid.length - 1) &&
+ !memcmp(n->essid.data, extra, n->essid.len)) {
+ dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
+ MAC_ARG(sm->associnfo.bssid));
+ return 0;
+ } else {
+ dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
+ spin_lock_irqsave(&sm->lock,flags);
+ /* Cancel assoc work */
+ cancel_delayed_work(&sm->associnfo.work);
+ /* We don't have to do this, but it's a little cleaner */
+ list_for_each_entry(authptr, &sm->auth_queue, list)
+ cancel_delayed_work(&authptr->work);
+ sm->associnfo.bssvalid = 0;
+ sm->associnfo.bssfixed = 0;
+ spin_unlock_irqrestore(&sm->lock,flags);
+ flush_scheduled_work();
+ }
+ }
+
+
spin_lock_irqsave(&sm->lock, flags);
-
+
sm->associnfo.static_essid = 0;
+ sm->associnfo.assoc_wait = 0;
if (data->essid.flags && data->essid.length && extra /*required?*/) {
length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 49174f0d0a3..6ac45103a27 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -191,7 +191,6 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
do {
/* Are any pointers crossing a page boundary? */
if (pgto_base == 0) {
- flush_dcache_page(*pgto);
pgto_base = PAGE_CACHE_SIZE;
pgto--;
}
@@ -211,11 +210,11 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
vto = kmap_atomic(*pgto, KM_USER0);
vfrom = kmap_atomic(*pgfrom, KM_USER1);
memmove(vto + pgto_base, vfrom + pgfrom_base, copy);
+ flush_dcache_page(*pgto);
kunmap_atomic(vfrom, KM_USER1);
kunmap_atomic(vto, KM_USER0);
} while ((len -= copy) != 0);
- flush_dcache_page(*pgto);
}
/*