Răsfoiți Sursa

Merge branch 'master'

Steven Whitehouse 19 ani în urmă
părinte
comite
71ec63c5d6
100 a modificat fișierele cu 9083 adăugiri și 1760 ștergeri
  1. 4 3
      MAINTAINERS
  2. 3 3
      Makefile
  3. 45 0
      arch/arm/mach-at91rm9200/at91rm9200.c
  4. 7 1
      arch/arm/mach-at91rm9200/generic.h
  5. 14 56
      arch/arm/mach-at91rm9200/irq.c
  6. 0 2
      arch/arm/mach-pnx4008/core.c
  7. 0 1
      arch/arm/mach-pnx4008/dma.c
  8. 10 12
      arch/arm/mach-pnx4008/irq.c
  9. 3 5
      arch/arm/mach-pnx4008/time.c
  10. 29 10
      arch/powerpc/sysdev/mpic.c
  11. 2 0
      arch/sparc64/kernel/prom.c
  12. 5 5
      arch/sparc64/kernel/sparc64_ksyms.c
  13. 4 1
      arch/sparc64/kernel/time.c
  14. 19 16
      drivers/net/8139cp.c
  15. 18 16
      drivers/net/8139too.c
  16. 12 15
      drivers/net/b44.c
  17. 15 15
      drivers/net/bnx2.c
  18. 10 15
      drivers/net/cassini.c
  19. 4 3
      drivers/net/declance.c
  20. 2 41
      drivers/net/dl2k.c
  21. 3 3
      drivers/net/eepro100.c
  22. 21 72
      drivers/net/epic100.c
  23. 19 17
      drivers/net/fealnx.c
  24. 1 2
      drivers/net/gt96100eth.c
  25. 0 2
      drivers/net/gt96100eth.h
  26. 5 11
      drivers/net/hamachi.c
  27. 9 8
      drivers/net/myri10ge/myri10ge.c
  28. 3 114
      drivers/net/natsemi.c
  29. 5 4
      drivers/net/ne2k-pci.c
  30. 24 28
      drivers/net/ni5010.c
  31. 22 19
      drivers/net/ns83820.c
  32. 10 9
      drivers/net/pci-skeleton.c
  33. 382 138
      drivers/net/pcnet32.c
  34. 36 6
      drivers/net/phy/cicada.c
  35. 16 24
      drivers/net/r8169.c
  36. 3 120
      drivers/net/starfire.c
  37. 14 92
      drivers/net/sundance.c
  38. 13 16
      drivers/net/tulip/winbond-840.c
  39. 4 23
      drivers/net/tulip/xircom_tulip_cb.c
  40. 8 113
      drivers/net/via-rhine.c
  41. 50 52
      drivers/net/via-velocity.c
  42. 2 2
      drivers/net/via-velocity.h
  43. 0 12
      drivers/net/wan/Kconfig
  44. 0 1
      drivers/net/wan/Makefile
  45. 1 0
      drivers/net/wireless/Kconfig
  46. 1 0
      drivers/net/wireless/Makefile
  47. 18 13
      drivers/net/wireless/bcm43xx/bcm43xx_main.c
  48. 0 24
      drivers/net/wireless/bcm43xx/bcm43xx_main.h
  49. 2 5
      drivers/net/wireless/bcm43xx/bcm43xx_radio.c
  50. 1 1
      drivers/net/wireless/bcm43xx/bcm43xx_wx.c
  51. 4 1
      drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
  52. 2 0
      drivers/net/wireless/hostap/hostap_plx.c
  53. 19 0
      drivers/net/wireless/zd1211rw/Kconfig
  54. 11 0
      drivers/net/wireless/zd1211rw/Makefile
  55. 1615 0
      drivers/net/wireless/zd1211rw/zd_chip.c
  56. 825 0
      drivers/net/wireless/zd1211rw/zd_chip.h
  57. 48 0
      drivers/net/wireless/zd1211rw/zd_def.h
  58. 191 0
      drivers/net/wireless/zd1211rw/zd_ieee80211.c
  59. 85 0
      drivers/net/wireless/zd1211rw/zd_ieee80211.h
  60. 1057 0
      drivers/net/wireless/zd1211rw/zd_mac.c
  61. 190 0
      drivers/net/wireless/zd1211rw/zd_mac.h
  62. 267 0
      drivers/net/wireless/zd1211rw/zd_netdev.c
  63. 45 0
      drivers/net/wireless/zd1211rw/zd_netdev.h
  64. 151 0
      drivers/net/wireless/zd1211rw/zd_rf.c
  65. 82 0
      drivers/net/wireless/zd1211rw/zd_rf.h
  66. 308 0
      drivers/net/wireless/zd1211rw/zd_rf_al2230.c
  67. 279 0
      drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
  68. 71 0
      drivers/net/wireless/zd1211rw/zd_types.h
  69. 1316 0
      drivers/net/wireless/zd1211rw/zd_usb.c
  70. 240 0
      drivers/net/wireless/zd1211rw/zd_usb.h
  71. 82 0
      drivers/net/wireless/zd1211rw/zd_util.c
  72. 29 0
      drivers/net/wireless/zd1211rw/zd_util.h
  73. 8 31
      drivers/net/yellowfin.c
  74. 12 5
      drivers/scsi/ahci.c
  75. 185 104
      drivers/scsi/libata-core.c
  76. 357 48
      drivers/scsi/libata-eh.c
  77. 117 7
      drivers/scsi/libata-scsi.c
  78. 66 39
      drivers/scsi/sata_sil.c
  79. 88 46
      drivers/scsi/sata_sil24.c
  80. 1 1
      drivers/scsi/sata_vsc.c
  81. 3 2
      drivers/serial/at91_serial.c
  82. 17 9
      fs/lockd/clntproc.c
  83. 21 2
      fs/locks.c
  84. 3 1
      fs/nfs/dir.c
  85. 201 234
      fs/nfs/direct.c
  86. 41 33
      fs/nfs/nfs4proc.c
  87. 17 3
      fs/nfs/write.c
  88. 0 8
      include/asm-arm/arch-at91rm9200/irqs.h
  89. 18 0
      include/asm-powerpc/cputime.h
  90. 14 0
      include/asm-sparc64/dma-mapping.h
  91. 1 0
      include/linux/fs.h
  92. 64 21
      include/linux/libata.h
  93. 2 0
      include/linux/nfs_xdr.h
  94. 7 0
      include/linux/pci_ids.h
  95. 1 0
      include/net/ieee80211softmac.h
  96. 3 1
      net/ieee80211/ieee80211_rx.c
  97. 11 4
      net/ieee80211/ieee80211_tx.c
  98. 24 7
      net/ieee80211/softmac/ieee80211softmac_assoc.c
  99. 2 2
      net/ieee80211/softmac/ieee80211softmac_auth.c
  100. 3 0
      net/ieee80211/softmac/ieee80211softmac_io.c

+ 4 - 3
MAINTAINERS

@@ -2057,9 +2057,10 @@ L:	linux-kernel@vger.kernel.org
 S:	Maintained
 S:	Maintained
 
 
 NI5010 NETWORK DRIVER
 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
 L:	netdev@vger.kernel.org
 S:	Maintained
 S:	Maintained
 
 

+ 3 - 3
Makefile

@@ -1,7 +1,7 @@
 VERSION = 2
 VERSION = 2
 PATCHLEVEL = 6
 PATCHLEVEL = 6
-SUBLEVEL = 17
-EXTRAVERSION =
+SUBLEVEL = 18
+EXTRAVERSION = -rc1
 NAME=Crazed Snow-Weasel
 NAME=Crazed Snow-Weasel
 
 
 # *DOCUMENTATION*
 # *DOCUMENTATION*
@@ -528,7 +528,7 @@ export MODLIB
 
 
 ifdef INSTALL_MOD_STRIP
 ifdef INSTALL_MOD_STRIP
 ifeq ($(INSTALL_MOD_STRIP),1)
 ifeq ($(INSTALL_MOD_STRIP),1)
-mod_strip_cmd = $STRIP) --strip-debug
+mod_strip_cmd = $(STRIP) --strip-debug
 else
 else
 mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP)
 mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP)
 endif # INSTALL_MOD_STRIP=1
 endif # INSTALL_MOD_STRIP=1

+ 45 - 0
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));
 	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);
+}

+ 7 - 1
arch/arm/mach-at91rm9200/generic.h

@@ -8,13 +8,19 @@
  * published by the Free Software Foundation.
  * 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;
 struct sys_timer;
 extern struct sys_timer at91rm9200_timer;
 extern struct sys_timer at91rm9200_timer;
 
 
+ /* Memory Map */
 extern void __init at91rm9200_map_io(void);
 extern void __init at91rm9200_map_io(void);
 
 
+ /* Clocks */
 extern int __init at91_clock_init(unsigned long main_clock);
 extern int __init at91_clock_init(unsigned long main_clock);
 struct device;
 struct device;
 extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);
 extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);

+ 14 - 56
arch/arm/mach-at91rm9200/irq.c

@@ -36,58 +36,20 @@
 
 
 #include "generic.h"
 #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 */
 	/* Disable interrupt on AIC */
 	at91_sys_write(AT91_AIC_IDCR, 1 << irq);
 	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 */
 	/* Enable interrupt on AIC */
 	at91_sys_write(AT91_AIC_IECR, 1 << irq);
 	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;
 	unsigned int smr, srctype;
 
 
@@ -122,7 +84,7 @@ static int at91rm9200_irq_type(unsigned irq, unsigned type)
 static u32 wakeups;
 static u32 wakeups;
 static u32 backups;
 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))
 	if (unlikely(irq >= 32))
 		return -EINVAL;
 		return -EINVAL;
@@ -149,28 +111,24 @@ void at91_irq_resume(void)
 }
 }
 
 
 #else
 #else
-#define at91rm9200_irq_set_wake	NULL
+#define at91_aic_set_wake	NULL
 #endif
 #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.
  * 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;
 	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 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.
 	 * 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++) {
 	for (i = 0; i < NR_AIC_IRQS; i++) {
 		/* Put irq number in Source Vector Register: */
 		/* Put irq number in Source Vector Register: */
 		at91_sys_write(AT91_AIC_SVR(i), i);
 		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]);
 		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_handler(i, do_level_IRQ);
 		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 
 

+ 0 - 2
arch/arm/mach-pnx4008/core.c

@@ -27,7 +27,6 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 
 
 #include <asm/hardware.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
@@ -36,7 +35,6 @@
 #include <asm/system.h>
 #include <asm/system.h>
 
 
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/mach/time.h>
 
 

+ 0 - 1
arch/arm/mach-pnx4008/dma.c

@@ -23,7 +23,6 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 
 
 #include <asm/system.h>
 #include <asm/system.h>
-#include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/hardware.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
 #include <asm/dma-mapping.h>
 #include <asm/dma-mapping.h>

+ 10 - 12
arch/arm/mach-pnx4008/irq.c

@@ -22,8 +22,8 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/device.h>
+#include <linux/irq.h>
 #include <asm/hardware.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
@@ -96,26 +96,24 @@ void __init pnx4008_init_irq(void)
 {
 {
 	unsigned int i;
 	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(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(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(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]);
 	pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_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) |
 	__raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
 			(1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
 			(1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
 		INTC_ER(MAIN_BASE_INT));
 		INTC_ER(MAIN_BASE_INT));
 	__raw_writel(0, INTC_ER(SIC1_BASE_INT));
 	__raw_writel(0, INTC_ER(SIC1_BASE_INT));
 	__raw_writel(0, INTC_ER(SIC2_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]);
-	}
 }
 }
 
 

+ 3 - 5
arch/arm/mach-pnx4008/time.c

@@ -20,17 +20,15 @@
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/kallsyms.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/irq.h>
 
 
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/leds.h>
-#include <asm/irq.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 #include <asm/mach/time.h>
-
-#include <linux/time.h>
-#include <linux/timex.h>
 #include <asm/errno.h>
 #include <asm/errno.h>
 
 
 /*! Note: all timers are UPCOUNTING */
 /*! Note: all timers are UPCOUNTING */

+ 29 - 10
arch/powerpc/sysdev/mpic.c

@@ -405,20 +405,22 @@ static void mpic_unmask_irq(unsigned int irq)
 	unsigned int loops = 100000;
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
 	struct mpic *mpic = mpic_from_irq(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
+	unsigned long flags;
 
 
 	DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
 	DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
 
 
+	spin_lock_irqsave(&mpic_lock, flags);
 	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
 	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
 		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
 		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
 		       ~MPIC_VECPRI_MASK);
 		       ~MPIC_VECPRI_MASK);
-
 	/* make sure mask gets to controller before we return to user */
 	/* make sure mask gets to controller before we return to user */
 	do {
 	do {
 		if (!loops--) {
 		if (!loops--) {
 			printk(KERN_ERR "mpic_enable_irq timeout\n");
 			printk(KERN_ERR "mpic_enable_irq timeout\n");
 			break;
 			break;
 		}
 		}
-	} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);	
+	} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
+	spin_unlock_irqrestore(&mpic_lock, flags);
 }
 }
 
 
 static void mpic_mask_irq(unsigned int irq)
 static void mpic_mask_irq(unsigned int irq)
@@ -426,9 +428,11 @@ static void mpic_mask_irq(unsigned int irq)
 	unsigned int loops = 100000;
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
 	struct mpic *mpic = mpic_from_irq(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
+	unsigned long flags;
 
 
 	DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
 	DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
 
 
+	spin_lock_irqsave(&mpic_lock, flags);
 	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
 	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
 		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
 		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
 		       MPIC_VECPRI_MASK);
 		       MPIC_VECPRI_MASK);
@@ -440,6 +444,7 @@ static void mpic_mask_irq(unsigned int irq)
 			break;
 			break;
 		}
 		}
 	} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
 	} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
+	spin_unlock_irqrestore(&mpic_lock, flags);
 }
 }
 
 
 static void mpic_end_irq(unsigned int irq)
 static void mpic_end_irq(unsigned int irq)
@@ -624,9 +629,10 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
 	struct irq_desc *desc = get_irq_desc(virq);
 	struct irq_desc *desc = get_irq_desc(virq);
 	struct irq_chip *chip;
 	struct irq_chip *chip;
 	struct mpic *mpic = h->host_data;
 	struct mpic *mpic = h->host_data;
-	unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL |
+	u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
 		MPIC_VECPRI_POLARITY_NEGATIVE;
 		MPIC_VECPRI_POLARITY_NEGATIVE;
 	int level;
 	int level;
+	unsigned long iflags;
 
 
 	pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
 	pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
 		 virq, hw, flags);
 		 virq, hw, flags);
@@ -668,11 +674,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
 	}
 	}
 #endif
 #endif
 
 
-	/* Reconfigure irq */
-	vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
-	mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
-
-	pr_debug("mpic: mapping as IRQ\n");
+	/* Reconfigure irq. We must preserve the mask bit as we can be called
+	 * while the interrupt is still active (This may change in the future
+	 * but for now, it is the case).
+	 */
+	spin_lock_irqsave(&mpic_lock, iflags);
+	v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
+	vecpri = (v &
+		~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
+		vecpri;
+	if (vecpri != v)
+		mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
+	spin_unlock_irqrestore(&mpic_lock, iflags);
+
+	pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
+		 vecpri, v);
 
 
 	set_irq_chip_data(virq, mpic);
 	set_irq_chip_data(virq, mpic);
 	set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
 	set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
@@ -904,8 +920,8 @@ void __init mpic_init(struct mpic *mpic)
 		
 		
 		/* do senses munging */
 		/* do senses munging */
 		if (mpic->senses && i < mpic->senses_count)
 		if (mpic->senses && i < mpic->senses_count)
-			vecpri = mpic_flags_to_vecpri(mpic->senses[i],
-						      &level);
+			vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
+						       &level);
 		else
 		else
 			vecpri |= MPIC_VECPRI_SENSE_LEVEL;
 			vecpri |= MPIC_VECPRI_SENSE_LEVEL;
 
 
@@ -955,14 +971,17 @@ void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
 
 
 void __init mpic_set_serial_int(struct mpic *mpic, int enable)
 void __init mpic_set_serial_int(struct mpic *mpic, int enable)
 {
 {
+	unsigned long flags;
 	u32 v;
 	u32 v;
 
 
+	spin_lock_irqsave(&mpic_lock, flags);
 	v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
 	v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
 	if (enable)
 	if (enable)
 		v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
 		v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
 	else
 	else
 		v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
 		v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
 	mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
 	mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
+	spin_unlock_irqrestore(&mpic_lock, flags);
 }
 }
 
 
 void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
 void mpic_irq_set_priority(unsigned int irq, unsigned int pri)

+ 2 - 0
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)
 static void irq_trans_init(struct device_node *dp)
 {
 {
 	const char *model;
 	const char *model;
+#ifdef CONFIG_PCI
 	int i;
 	int i;
+#endif
 
 
 	model = of_get_property(dp, "model", NULL);
 	model = of_get_property(dp, "model", NULL);
 	if (!model)
 	if (!model)

+ 5 - 5
arch/sparc64/kernel/sparc64_ksyms.c

@@ -124,11 +124,6 @@ EXPORT_SYMBOL(__write_lock);
 EXPORT_SYMBOL(__write_unlock);
 EXPORT_SYMBOL(__write_unlock);
 EXPORT_SYMBOL(__write_trylock);
 EXPORT_SYMBOL(__write_trylock);
 
 
-#if defined(CONFIG_MCOUNT)
-extern void _mcount(void);
-EXPORT_SYMBOL(_mcount);
-#endif
-
 /* CPU online map and active count.  */
 /* CPU online map and active count.  */
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(phys_cpu_present_map);
@@ -136,6 +131,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_call_function);
 #endif /* CONFIG_SMP */
 #endif /* CONFIG_SMP */
 
 
+#if defined(CONFIG_MCOUNT)
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
+
 EXPORT_SYMBOL(sparc64_get_clock_tick);
 EXPORT_SYMBOL(sparc64_get_clock_tick);
 
 
 /* semaphores */
 /* semaphores */

+ 4 - 1
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)
 	if (!regs)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+#ifdef CONFIG_PCI
 	if (!strcmp(model, "ds1287") ||
 	if (!strcmp(model, "ds1287") ||
 	    !strcmp(model, "m5819") ||
 	    !strcmp(model, "m5819") ||
 	    !strcmp(model, "m5819p") ||
 	    !strcmp(model, "m5819p") ||
 	    !strcmp(model, "m5823")) {
 	    !strcmp(model, "m5823")) {
 		ds1287_regs = (unsigned long) regs;
 		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;
 		mstk48t02_regs = regs;
 	} else if(model[5] == '0' && model[6] == '8') {
 	} else if(model[5] == '0' && model[6] == '8') {
 		mstk48t08_regs = regs;
 		mstk48t08_regs = regs;

+ 19 - 16
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 &&
 	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
 	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
 	    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;
 		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);
 	pciaddr = pci_resource_start(pdev, 1);
 	if (!pciaddr) {
 	if (!pciaddr) {
 		rc = -EIO;
 		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;
 		goto err_out_res;
 	}
 	}
 	if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
 	if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
 		rc = -EIO;
 		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;
 		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);
 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc) {
 		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;
 			goto err_out_res;
 		}
 		}
 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc) {
 		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;
 			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);
 	regs = ioremap(pciaddr, CP_REGS_SIZE);
 	if (!regs) {
 	if (!regs) {
 		rc = -EIO;
 		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;
 		goto err_out_res;
 	}
 	}
 	dev->base_addr = (unsigned long) regs;
 	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 */
 	/* enable busmastering and memory-write-invalidate */
 	pci_set_master(pdev);
 	pci_set_master(pdev);
 
 
-	if (cp->wol_enabled) cp_set_d3_state (cp);
+	if (cp->wol_enabled)
+		cp_set_d3_state (cp);
 
 
 	return 0;
 	return 0;
 
 
@@ -2011,7 +2013,8 @@ static void cp_remove_one (struct pci_dev *pdev)
 	BUG_ON(!dev);
 	BUG_ON(!dev);
 	unregister_netdev(dev);
 	unregister_netdev(dev);
 	iounmap(cp->regs);
 	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_release_regions(pdev);
 	pci_clear_mwi(pdev);
 	pci_clear_mwi(pdev);
 	pci_disable_device(pdev);
 	pci_disable_device(pdev);

+ 18 - 16
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 and priv zeroed in alloc_etherdev */
 	dev = alloc_etherdev (sizeof (*tp));
 	dev = alloc_etherdev (sizeof (*tp));
 	if (dev == NULL) {
 	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;
 		return -ENOMEM;
 	}
 	}
 	SET_MODULE_OWNER(dev);
 	SET_MODULE_OWNER(dev);
@@ -800,31 +800,31 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 #ifdef USE_IO_OPS
 #ifdef USE_IO_OPS
 	/* make sure PCI base addr 0 is PIO */
 	/* make sure PCI base addr 0 is PIO */
 	if (!(pio_flags & IORESOURCE_IO)) {
 	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;
 		rc = -ENODEV;
 		goto err_out;
 		goto err_out;
 	}
 	}
 	/* check for weird/broken PCI region reporting */
 	/* check for weird/broken PCI region reporting */
 	if (pio_len < RTL_MIN_IO_SIZE) {
 	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;
 		rc = -ENODEV;
 		goto err_out;
 		goto err_out;
 	}
 	}
 #else
 #else
 	/* make sure PCI base addr 1 is MMIO */
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(mmio_flags & IORESOURCE_MEM)) {
 	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;
 		rc = -ENODEV;
 		goto err_out;
 		goto err_out;
 	}
 	}
 	if (mmio_len < RTL_MIN_IO_SIZE) {
 	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;
 		rc = -ENODEV;
 		goto err_out;
 		goto err_out;
 	}
 	}
 #endif
 #endif
 
 
-	rc = pci_request_regions (pdev, "8139too");
+	rc = pci_request_regions (pdev, DRV_NAME);
 	if (rc)
 	if (rc)
 		goto err_out;
 		goto err_out;
 	disable_dev_on_err = 1;
 	disable_dev_on_err = 1;
@@ -835,7 +835,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 #ifdef USE_IO_OPS
 #ifdef USE_IO_OPS
 	ioaddr = ioport_map(pio_start, pio_len);
 	ioaddr = ioport_map(pio_start, pio_len);
 	if (!ioaddr) {
 	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;
 		rc = -EIO;
 		goto err_out;
 		goto err_out;
 	}
 	}
@@ -846,7 +846,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 	/* ioremap MMIO region */
 	/* ioremap MMIO region */
 	ioaddr = pci_iomap(pdev, 1, 0);
 	ioaddr = pci_iomap(pdev, 1, 0);
 	if (ioaddr == NULL) {
 	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;
 		rc = -EIO;
 		goto err_out;
 		goto err_out;
 	}
 	}
@@ -860,8 +860,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 
 
 	/* check for missing/broken hardware */
 	/* check for missing/broken hardware */
 	if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
 	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;
 		rc = -EIO;
 		goto err_out;
 		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 */
 	/* 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;
 	tp->chipset = 0;
 
 
 match:
 match:
@@ -954,9 +954,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
 
 
 	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
 	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
 	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
 	    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);
 	i = rtl8139_init_board (pdev, &dev);

+ 12 - 15
drivers/net/b44.c

@@ -2120,13 +2120,14 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
 
 	err = pci_enable_device(pdev);
 	err = pci_enable_device(pdev);
 	if (err) {
 	if (err) {
-		printk(KERN_ERR PFX "Cannot enable PCI device, "
+		dev_err(&pdev->dev, "Cannot enable PCI device, "
 		       "aborting.\n");
 		       "aborting.\n");
 		return err;
 		return err;
 	}
 	}
 
 
 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
 	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");
 		       "base address, aborting.\n");
 		err = -ENODEV;
 		err = -ENODEV;
 		goto err_out_disable_pdev;
 		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);
 	err = pci_request_regions(pdev, DRV_MODULE_NAME);
 	if (err) {
 	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;
 		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);
 	err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
 	if (err) {
 	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;
 		goto err_out_free_res;
 	}
 	}
 
 
 	err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
 	err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
 	if (err) {
 	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;
 		goto err_out_free_res;
 	}
 	}
 
 
@@ -2160,7 +2159,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
 
 	dev = alloc_etherdev(sizeof(*bp));
 	dev = alloc_etherdev(sizeof(*bp));
 	if (!dev) {
 	if (!dev) {
-		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto err_out_free_res;
 		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);
 	bp->regs = ioremap(b44reg_base, b44reg_len);
 	if (bp->regs == 0UL) {
 	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;
 		err = -ENOMEM;
 		goto err_out_free_dev;
 		goto err_out_free_dev;
 	}
 	}
@@ -2212,8 +2210,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
 
 	err = b44_get_invariants(bp);
 	err = b44_get_invariants(bp);
 	if (err) {
 	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;
 		goto err_out_iounmap;
 	}
 	}
 
 
@@ -2233,8 +2231,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
 
 	err = register_netdev(dev);
 	err = register_netdev(dev);
 	if (err) {
 	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;
 		goto err_out_iounmap;
 	}
 	}
 
 

+ 15 - 15
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 */
 	/* enable device (incl. PCI PM wakeup), and bus-mastering */
 	rc = pci_enable_device(pdev);
 	rc = pci_enable_device(pdev);
 	if (rc) {
 	if (rc) {
-		printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
+		dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
 		goto err_out;
 		goto err_out;
 	}
 	}
 
 
 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
 	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;
 		rc = -ENODEV;
 		goto err_out_disable;
 		goto err_out_disable;
 	}
 	}
 
 
 	rc = pci_request_regions(pdev, DRV_MODULE_NAME);
 	rc = pci_request_regions(pdev, DRV_MODULE_NAME);
 	if (rc) {
 	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;
 		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);
 	bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
 	if (bp->pm_cap == 0) {
 	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;
 		rc = -EIO;
 		goto err_out_release;
 		goto err_out_release;
 	}
 	}
 
 
 	bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
 	bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
 	if (bp->pcix_cap == 0) {
 	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;
 		rc = -EIO;
 		goto err_out_release;
 		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) {
 	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
 		bp->flags |= USING_DAC_FLAG;
 		bp->flags |= USING_DAC_FLAG;
 		if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
 		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;
 			rc = -EIO;
 			goto err_out_release;
 			goto err_out_release;
 		}
 		}
 	}
 	}
 	else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
 	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;
 		rc = -EIO;
 		goto err_out_release;
 		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);
 	bp->regview = ioremap_nocache(dev->base_addr, mem_len);
 
 
 	if (!bp->regview) {
 	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;
 		rc = -ENOMEM;
 		goto err_out_release;
 		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) &&
 	else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
 		!(bp->flags & PCIX_FLAG)) {
 		!(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;
 		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) !=
 	if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
 	    BNX2_DEV_INFO_SIGNATURE_MAGIC) {
 	    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;
 		rc = -ENODEV;
 		goto err_out_unmap;
 		goto err_out_unmap;
 	}
 	}
@@ -5895,7 +5895,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #endif
 #endif
 
 
 	if ((rc = register_netdev(dev))) {
 	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)
 		if (bp->regview)
 			iounmap(bp->regview);
 			iounmap(bp->regview);
 		pci_release_regions(pdev);
 		pci_release_regions(pdev);

+ 10 - 15
drivers/net/cassini.c

@@ -4887,13 +4887,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 
 
 	err = pci_enable_device(pdev);
 	err = pci_enable_device(pdev);
 	if (err) {
 	if (err) {
-		printk(KERN_ERR PFX "Cannot enable PCI device, "
-		       "aborting.\n");
+		dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
 		return err;
 		return err;
 	}
 	}
 
 
 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
 	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");
 		       "base address, aborting.\n");
 		err = -ENODEV;
 		err = -ENODEV;
 		goto err_out_disable_pdev;
 		goto err_out_disable_pdev;
@@ -4901,7 +4900,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 
 
 	dev = alloc_etherdev(sizeof(*cp));
 	dev = alloc_etherdev(sizeof(*cp));
 	if (!dev) {
 	if (!dev) {
-		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto err_out_disable_pdev;
 		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);
 	err = pci_request_regions(pdev, dev->name);
 	if (err) {
 	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;
 		goto err_out_free_netdev;
 	}
 	}
 	pci_set_master(pdev);
 	pci_set_master(pdev);
@@ -4941,7 +4939,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 		if (pci_write_config_byte(pdev, 
 		if (pci_write_config_byte(pdev, 
 					  PCI_CACHE_LINE_SIZE, 
 					  PCI_CACHE_LINE_SIZE, 
 					  cas_cacheline_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");
 			       "line size\n");
 			goto err_write_cacheline;
 			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,
 		err = pci_set_consistent_dma_mask(pdev,
 						  DMA_64BIT_MASK);
 						  DMA_64BIT_MASK);
 		if (err < 0) {
 		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");
 			       "for consistent allocations\n");
 			goto err_out_free_res;
 			goto err_out_free_res;
 		}
 		}
@@ -4963,7 +4961,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 	} else {
 	} else {
 		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (err) {
 		if (err) {
-			printk(KERN_ERR PFX "No usable DMA configuration, "
+			dev_err(&pdev->dev, "No usable DMA configuration, "
 			       "aborting.\n");
 			       "aborting.\n");
 			goto err_out_free_res;
 			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 */
 	/* give us access to cassini registers */
 	cp->regs = pci_iomap(pdev, 0, casreg_len);
 	cp->regs = pci_iomap(pdev, 0, casreg_len);
 	if (cp->regs == 0UL) {
 	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;
 		goto err_out_free_res;
 	}
 	}
 	cp->casreg_len = casreg_len;
 	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),
 		pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
 				     &cp->block_dvma);
 				     &cp->block_dvma);
 	if (!cp->init_block) {
 	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;
 		goto err_out_iounmap;
 	}
 	}
 
 
@@ -5085,8 +5081,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 		dev->features |= NETIF_F_HIGHDMA;
 		dev->features |= NETIF_F_HIGHDMA;
 
 
 	if (register_netdev(dev)) {
 	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;
 		goto err_out_free_consistent;
 	}
 	}
 
 

+ 4 - 3
drivers/net/declance.c

@@ -703,8 +703,8 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
 	return IRQ_HANDLED;
 	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 net_device *dev = (struct net_device *) dev_id;
 	struct lance_private *lp = netdev_priv(dev);
 	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;
 	return 0;
 
 
 err_out_free_dev:
 err_out_free_dev:
-	kfree(dev);
+	free_netdev(dev);
 
 
 err_out:
 err_out:
 	return ret;
 	return ret;
@@ -1299,6 +1299,7 @@ static void __exit dec_lance_cleanup(void)
 	while (root_lance_dev) {
 	while (root_lance_dev) {
 		struct net_device *dev = root_lance_dev;
 		struct net_device *dev = root_lance_dev;
 		struct lance_private *lp = netdev_priv(dev);
 		struct lance_private *lp = netdev_priv(dev);
+
 		unregister_netdev(dev);
 		unregister_netdev(dev);
 #ifdef CONFIG_TC
 #ifdef CONFIG_TC
 		if (lp->slot >= 0)
 		if (lp->slot >= 0)

+ 2 - 41
drivers/net/dl2k.c

@@ -9,49 +9,10 @@
     the Free Software Foundation; either version 2 of the License, or
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
     (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_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 "dl2k.h"
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 
 

+ 3 - 3
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),
 	if (!request_region(pci_resource_start(pdev, 1),
 			pci_resource_len(pdev, 1), "eepro100")) {
 			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;
 		goto err_out_none;
 	}
 	}
 	if (!request_mem_region(pci_resource_start(pdev, 0),
 	if (!request_mem_region(pci_resource_start(pdev, 0),
 			pci_resource_len(pdev, 0), "eepro100")) {
 			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;
 		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);
 	ioaddr = pci_iomap(pdev, pci_bar, 0);
 	if (!ioaddr) {
 	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;
 		goto err_out_free_mmio_region;
 	}
 	}
 
 

+ 21 - 72
drivers/net/epic100.c

@@ -19,62 +19,15 @@
 
 
 	Information and updates available at
 	Information and updates available at
 	http://www.scyld.com/network/epic100.html
 	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_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.
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
    These may be modified when a driver module is loaded.*/
@@ -204,19 +157,15 @@ typedef enum {
 
 
 struct epic_chip_info {
 struct epic_chip_info {
 	const char *name;
 	const char *name;
-        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. */
 };
 };
 
 
 
 
 /* indexed by chip_t */
 /* indexed by chip_t */
 static const struct epic_chip_info pci_id_tbl[] = {
 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;
 		goto out;
 	irq = pdev->irq;
 	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;
 		ret = -ENODEV;
 		goto err_out_disable;
 		goto err_out_disable;
 	}
 	}
@@ -401,7 +350,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
 
 
 	dev = alloc_etherdev(sizeof (*ep));
 	dev = alloc_etherdev(sizeof (*ep));
 	if (!dev) {
 	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;
 		goto err_out_free_res;
 	}
 	}
 	SET_MODULE_OWNER(dev);
 	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 = pci_resource_start (pdev, 1);
 	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
 	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
 	if (!ioaddr) {
 	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;
 		goto err_out_free_netdev;
 	}
 	}
 #endif
 #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));
 		((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
 
 
 	if (debug > 2) {
 	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++)
 		for (i = 0; i < 64; i++)
 			printk(" %4.4x%s", read_eeprom(ioaddr, i),
 			printk(" %4.4x%s", read_eeprom(ioaddr, i),
 				   i % 16 == 15 ? "\n" : "");
 				   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);
 			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				ep->phys[phy_idx++] = phy;
 				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;
 		ep->mii_phy_cnt = phy_idx;
 		if (phy_idx != 0) {
 		if (phy_idx != 0) {
 			phy = ep->phys[0];
 			phy = ep->phys[0];
 			ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 			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",
 				   "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)) {
 		} 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. */
 			/* Use the known PHY address of the EPII. */
 			ep->phys[0] = 3;
 			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. */
 	/* The lower four bits are the media type. */
 	if (duplex) {
 	if (duplex) {
 		ep->mii.force_media = ep->mii.full_duplex = 1;
 		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;
 	dev->if_port = ep->default_port = option;
 
 

+ 19 - 17
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(options, "fealnx: Bits 0-3: media type, bit 17: full duplex");
 MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
 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. */
 /* A chip capabilities table, matching the entries in pci_tbl[] above. */
 enum chip_capability_flags {
 enum chip_capability_flags {
@@ -146,14 +148,13 @@ enum phy_type_flags {
 
 
 struct chip_info {
 struct chip_info {
 	char *chip_name;
 	char *chip_name;
-	int io_size;
 	int flags;
 	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. */
 /* 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);
 	len = pci_resource_len(pdev, bar);
 	if (len < MIN_REGION_SIZE) {
 	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;
 		return -ENODEV;
 	}
 	}
 
 
 	i = pci_request_regions(pdev, boardname);
 	i = pci_request_regions(pdev, boardname);
-	if (i) return i;
+	if (i)
+		return i;
 	
 	
 	irq = pdev->irq;
 	irq = pdev->irq;
 
 
@@ -576,9 +578,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
 
 
 			if (mii_status != 0xffff && mii_status != 0x0000) {
 			if (mii_status != 0xffff && mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
 				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 */
 				/* get phy type */
 				{
 				{
 					unsigned int data;
 					unsigned int data;
@@ -601,10 +603,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
 		}
 		}
 
 
 		np->mii_cnt = phy_idx;
 		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 {
 	} else {
 		np->phys[0] = 32;
 		np->phys[0] = 32;
 /* 89/6/23 add, (begin) */
 /* 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];
 		np->mii.full_duplex = full_duplex[card_idx];
 
 
 	if (np->mii.full_duplex) {
 	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) */
 /* 89/6/13 add, (begin) */
 //      if (np->PHYType==MarvellPHY)
 //      if (np->PHYType==MarvellPHY)
 		if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {
 		if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {

+ 1 - 2
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
 	memset(gp, 0, sizeof(*gp)); // clear it
 
 
 	gp->port_num = port_num;
 	gp->port_num = port_num;
-	gp->io_size = GT96100_ETH_IO_SIZE;
 	gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
 	gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
 	gp->phy_addr = phy_addr;
 	gp->phy_addr = phy_addr;
 	gp->chip_rev = chip_rev;
 	gp->chip_rev = chip_rev;
@@ -1531,7 +1530,7 @@ static void gt96100_cleanup_module(void)
 				+ sizeof(gt96100_td_t) * TX_RING_SIZE,
 				+ sizeof(gt96100_td_t) * TX_RING_SIZE,
 				gp->rx_ring);
 				gp->rx_ring);
 			free_netdev(gtif->dev);
 			free_netdev(gtif->dev);
-			release_region(gtif->iobase, gp->io_size);
+			release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
 		}
 		}
 	}
 	}
 }
 }

+ 0 - 2
drivers/net/gt96100eth.h

@@ -331,7 +331,6 @@ struct gt96100_private {
 	mib_counters_t mib;
 	mib_counters_t mib;
 	struct net_device_stats stats;
 	struct net_device_stats stats;
 
 
-	int io_size;
 	int port_num;  // 0 or 1
 	int port_num;  // 0 or 1
 	int chip_rev;
 	int chip_rev;
 	u32 port_offset;
 	u32 port_offset;
@@ -340,7 +339,6 @@ struct gt96100_private {
 	u32 last_psr; // last value of the port status register
 	u32 last_psr; // last value of the port status register
 
 
 	int options;     /* User-settable misc. driver options. */
 	int options;     /* User-settable misc. driver options. */
-	int drv_flags;
 	struct timer_list timer;
 	struct timer_list timer;
 	spinlock_t lock; /* Serialise access to device */
 	spinlock_t lock; /* Serialise access to device */
 };
 };

+ 5 - 11
drivers/net/hamachi.c

@@ -20,22 +20,15 @@
 
 
 	Support and updates available at
 	Support and updates available at
 	http://www.scyld.com/network/hamachi.html
 	http://www.scyld.com/network/hamachi.html
+	[link no longer provides useful info -jgarzik]
 	or
 	or
 	http://www.parl.clemson.edu/~keithu/hamachi.html
 	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_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. */
 /* A few user-configurable values. */
@@ -608,7 +601,8 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
 	pci_set_master(pdev);
 	pci_set_master(pdev);
 
 
 	i = pci_request_regions(pdev, DRV_NAME);
 	i = pci_request_regions(pdev, DRV_NAME);
-	if (i) return i;
+	if (i)
+		return i;
 
 
 	irq = pdev->irq;
 	irq = pdev->irq;
 	ioaddr = ioremap(base, 0x400);
 	ioaddr = ioremap(base, 0x400);

+ 9 - 8
drivers/net/myri10ge/myri10ge.c

@@ -188,7 +188,6 @@ struct myri10ge_priv {
 	int vendor_specific_offset;
 	int vendor_specific_offset;
 	u32 devctl;
 	u32 devctl;
 	u16 msi_flags;
 	u16 msi_flags;
-	u32 pm_state[16];
 	u32 read_dma;
 	u32 read_dma;
 	u32 write_dma;
 	u32 write_dma;
 	u32 read_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_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
 	"tx_heartbeat_errors", "tx_window_errors",
 	"tx_heartbeat_errors", "tx_window_errors",
 	/* device-specific stats */
 	/* device-specific stats */
+	"tx_boundary", "WC", "irq", "MSI",
 	"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
 	"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
 	"serial_number", "tx_pkt_start", "tx_pkt_done",
 	"serial_number", "tx_pkt_start", "tx_pkt_done",
 	"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
 	"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++)
 	for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
 		data[i] = ((unsigned long *)&mgp->stats)[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->read_dma;
 	data[i++] = (unsigned int)mgp->write_dma;
 	data[i++] = (unsigned int)mgp->write_dma;
 	data[i++] = (unsigned int)mgp->read_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.
  * 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)
 static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
 {
 {
 	struct pci_dev *bridge = mgp->pdev->bus->self;
 	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);
 		dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
 		goto abort_with_irq;
 		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;
 	return 0;
 
 

+ 3 - 114
drivers/net/natsemi.c

@@ -20,120 +20,9 @@
 
 
 	Support information and updates available at
 	Support information and updates available at
 	http://www.scyld.com/network/netsemi.html
 	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:
 	TODO:
 	* big endian support with CFG:BEM instead of cpu_to_le32
 	* big endian support with CFG:BEM instead of cpu_to_le32
 */
 */
@@ -165,8 +54,8 @@
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
 #define DRV_NAME	"natsemi"
 #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
 #define RX_OFFSET	2
 
 

+ 5 - 4
drivers/net/ne2k-pci.c

@@ -231,12 +231,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
 	irq = pdev->irq;
 	irq = pdev->irq;
 
 
 	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
 	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;
 		return -ENODEV;
 	}
 	}
 
 
 	if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
 	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);
 			NE_IO_EXTENT, ioaddr);
 		return -EBUSY;
 		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. */
 	/* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
 	dev = alloc_ei_netdev();
 	dev = alloc_ei_netdev();
 	if (!dev) {
 	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;
 		goto err_out_free_res;
 	}
 	}
 	SET_MODULE_OWNER(dev);
 	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)
 		while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
 			/* Limit wait: '2' avoids jiffy roll-over. */
 			/* Limit wait: '2' avoids jiffy roll-over. */
 			if (jiffies - reset_start_time > 2) {
 			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;
 				goto err_out_free_netdev;
 			}
 			}
 
 

+ 24 - 28
drivers/net/ni5010.c

@@ -1,17 +1,12 @@
 /*	ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
 /*	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
  *	This software may be used and distributed according to the terms
  *	of the GNU General Public License, incorporated herein by reference.
  *	of the GNU General Public License, incorporated herein by reference.
  *
  *
  * 	The authors may be reached as:
  * 	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:
  *	Sources:
  * 	 	Donald Becker's "skeleton.c"
  * 	 	Donald Becker's "skeleton.c"
@@ -27,8 +22,9 @@
  *	970503	v0.93: Fixed auto-irq failure on warm reboot (JB)
  *	970503	v0.93: Fixed auto-irq failure on warm reboot (JB)
  *	970623	v1.00: First kernel version (AM)
  *	970623	v1.00: First kernel version (AM)
  *	970814	v1.01: Added detection of onboard receive buffer size (AM)
  *	970814	v1.01: Added detection of onboard receive buffer size (AM)
+ *	060611	v1.02: slight cleanup: email addresses, driver modernization.
  *	Bugs:
  *	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
  *		- Note that you have to patch ifconfig for the new /proc/net/dev
  *		format. It gives incorrect stats otherwise.
  *		format. It gives incorrect stats otherwise.
  *
  *
@@ -39,7 +35,7 @@
  *		Complete merge with Andreas' driver
  *		Complete merge with Andreas' driver
  *		Implement ring buffers (Is this useful? You can't squeeze
  *		Implement ring buffers (Is this useful? You can't squeeze
  *			too many packet in a 2k buffer!)
  *			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)
  *			slower than programmed I/O)
  *
  *
  *	Compile with:
  *	Compile with:
@@ -47,7 +43,7 @@
  *			-DMODULE -c ni5010.c 
  *			-DMODULE -c ni5010.c 
  *
  *
  *	Insert with e.g.:
  *	Insert with e.g.:
- *		insmod ni5010.o io=0x300 irq=5 	
+ *		insmod ni5010.ko io=0x300 irq=5
  */
  */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -69,15 +65,15 @@
 
 
 #include "ni5010.h"
 #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 */
 /* bufsize_rcv == 0 means autoprobing */
 static unsigned int bufsize_rcv;
 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 */
 #undef FULL_IODETECT		/* Only detect in portlist */
 
 
 #ifndef FULL_IODETECT
 #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));
 	PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
 
 
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
 	if (dev->irq == 0xff)
 	if (dev->irq == 0xff)
 		;
 		;
 	else if (dev->irq < 2) {
 	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) {
 	} else if (dev->irq == 2) {
 		dev->irq = 9;
 		dev->irq = 9;
 	}
 	}
-#endif	/* jumpered_irq */
+#endif	/* JUMPERED_INTERRUPTS */
 	PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
 	PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
 
 
 	/* DMA is not supported (yet?), so no use detecting it */
 	/* 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 */
         	outw(0, IE_GP);		/* Point GP at start of packet */
         	outb(0, IE_RBUF);	/* set buffer byte 0 to 0 again */
         	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));
 	memset(dev->priv, 0, sizeof(struct ni5010_local));
 	
 	
 	dev->open		= ni5010_open;
 	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 */
 	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);
 	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(".\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;
 	return 0;
 out:
 out:
 	release_region(dev->base_addr, NI5010_IO_EXTENT);
 	release_region(dev->base_addr, NI5010_IO_EXTENT);
@@ -371,7 +365,7 @@ out:
  *
  *
  * This routine should set everything up anew at each open, even
  * This routine should set everything up anew at each open, even
  * registers that "should" only need to be set once at boot, so that
  * 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)
 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,
          * Always allocate the DMA channel after the IRQ,
          * and clean up on failure.
          * and clean up on failure.
          */
          */
-#ifdef jumpered_dma
+#ifdef JUMPERED_DMA
         if (request_dma(dev->dma, cardname)) {
         if (request_dma(dev->dma, cardname)) {
 		printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
 		printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
                 free_irq(dev->irq, NULL);
                 free_irq(dev->irq, NULL);
                 return -EAGAIN;
                 return -EAGAIN;
         }
         }
-#endif	/* jumpered_dma */
+#endif	/* JUMPERED_DMA */
 
 
 	PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
 	PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
 	/* Reset the hardware here.  Don't forget to set the station address. */
 	/* 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;
 	int ioaddr = dev->base_addr;
 
 
 	PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
 	PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef jumpered_interrupts	
+#ifdef JUMPERED_INTERRUPTS
 	free_irq(dev->irq, NULL);
 	free_irq(dev->irq, NULL);
 #endif
 #endif
 	/* Put card in held-RESET state */
 	/* 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(io, "ni5010 I/O base address");
 MODULE_PARM_DESC(irq, "ni5010 IRQ number");
 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));
 	PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
 	/*
 	/*
@@ -792,13 +786,15 @@ int init_module(void)
         return 0;
         return 0;
 }
 }
 
 
-void cleanup_module(void)
+static void __exit ni5010_cleanup_module(void)
 {
 {
 	PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
 	PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
 	unregister_netdev(dev_ni5010);
 	unregister_netdev(dev_ni5010);
 	release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
 	release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
 	free_netdev(dev_ni5010);
 	free_netdev(dev_ni5010);
 }
 }
+module_init(ni5010_init_module);
+module_exit(ni5010_cleanup_module);
 #endif /* MODULE */
 #endif /* MODULE */
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 

+ 22 - 19
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(dev->IMR_cache, dev->base + IMR);
 		writel(1, dev->base + IER);
 		writel(1, dev->base + IER);
-		spin_unlock_irq(&dev->misc_lock);
+		spin_unlock(&dev->misc_lock);
 
 
 		kick_rx(ndev);
 		kick_rx(ndev);
 
 
@@ -1012,8 +1012,6 @@ static void do_tx_done(struct net_device *ndev)
 	struct ns83820 *dev = PRIV(ndev);
 	struct ns83820 *dev = PRIV(ndev);
 	u32 cmdsts, tx_done_idx, *desc;
 	u32 cmdsts, tx_done_idx, *desc;
 
 
-	spin_lock_irq(&dev->tx_lock);
-
 	dprintk("do_tx_done(%p)\n", ndev);
 	dprintk("do_tx_done(%p)\n", ndev);
 	tx_done_idx = dev->tx_done_idx;
 	tx_done_idx = dev->tx_done_idx;
 	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 	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_start_queue(ndev);
 		netif_wake_queue(ndev);
 		netif_wake_queue(ndev);
 	}
 	}
-	spin_unlock_irq(&dev->tx_lock);
 }
 }
 
 
 static void ns83820_cleanup_tx(struct ns83820 *dev)
 static void ns83820_cleanup_tx(struct ns83820 *dev)
@@ -1281,11 +1278,13 @@ static struct ethtool_ops ops = {
 	.get_link = ns83820_get_link
 	.get_link = ns83820_get_link
 };
 };
 
 
+/* this function is called in irq context from the ISR */
 static void ns83820_mib_isr(struct ns83820 *dev)
 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);
 	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);
 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)
 static void ns83820_do_isr(struct net_device *ndev, u32 isr)
 {
 {
 	struct ns83820 *dev = PRIV(ndev);
 	struct ns83820 *dev = PRIV(ndev);
+	unsigned long flags;
+
 #ifdef DEBUG
 #ifdef DEBUG
 	if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
 	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);
 		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) {
 	if ((ISR_RXDESC | ISR_RXOK) & isr) {
 		prefetch(dev->rx_info.next_rx_desc);
 		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);
 		dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
 		writel(dev->IMR_cache, dev->base + IMR);
 		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);
 		tasklet_schedule(&dev->rx_tasklet);
 		//rx_irq(ndev);
 		//rx_irq(ndev);
@@ -1370,16 +1371,18 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
 	 * work has accumulated
 	 * work has accumulated
 	 */
 	 */
 	if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
 	if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
+		spin_lock_irqsave(&dev->tx_lock, flags);
 		do_tx_done(ndev);
 		do_tx_done(ndev);
+		spin_unlock_irqrestore(&dev->tx_lock, flags);
 
 
 		/* Disable TxOk if there are no outstanding tx packets.
 		/* Disable TxOk if there are no outstanding tx packets.
 		 */
 		 */
 		if ((dev->tx_done_idx == dev->tx_free_idx) &&
 		if ((dev->tx_done_idx == dev->tx_free_idx) &&
 		    (dev->IMR_cache & ISR_TXOK)) {
 		    (dev->IMR_cache & ISR_TXOK)) {
-			spin_lock_irq(&dev->misc_lock);
+			spin_lock_irqsave(&dev->misc_lock, flags);
 			dev->IMR_cache &= ~ISR_TXOK;
 			dev->IMR_cache &= ~ISR_TXOK;
 			writel(dev->IMR_cache, dev->base + IMR);
 			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.
 	 * nature are expected, we must enable TxOk.
 	 */
 	 */
 	if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
 	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;
 		dev->IMR_cache |= ISR_TXOK;
 		writel(dev->IMR_cache, dev->base + IMR);
 		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 */
 	/* 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;
         u32 tx_done_idx, *desc;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&dev->tx_lock, flags);
 
 
 	tx_done_idx = dev->tx_done_idx;
 	tx_done_idx = dev->tx_done_idx;
 	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1482,7 +1485,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
 		ndev->name,
 		ndev->name,
 		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
 		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)
 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)) {
 	} else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
 		using_dac = 0;
 		using_dac = 0;
 	} else {
 	} 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;
 		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);
 	err = pci_enable_device(pci_dev);
 	if (err) {
 	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;
 		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,
 	err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED,
 			  DRV_NAME, ndev);
 			  DRV_NAME, ndev);
 	if (err) {
 	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;
 		goto out_disable;
 	}
 	}
 
 
@@ -1899,7 +1902,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
 	rtnl_lock();
 	rtnl_lock();
 	err = dev_alloc_name(ndev, ndev->name);
 	err = dev_alloc_name(ndev, ndev->name);
 	if (err < 0) {
 	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;
 		goto out_free_irq;
 	}
 	}
 
 

+ 10 - 9
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 zeroed in alloc_etherdev */
 	dev = alloc_etherdev (sizeof (*tp));
 	dev = alloc_etherdev (sizeof (*tp));
 	if (dev == NULL) {
 	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");
 		DPRINTK ("EXIT, returning -ENOMEM\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
@@ -631,14 +631,14 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
 
 
 	/* make sure PCI base addr 0 is PIO */
 	/* make sure PCI base addr 0 is PIO */
 	if (!(pio_flags & IORESOURCE_IO)) {
 	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;
 		rc = -ENODEV;
 		goto err_out;
 		goto err_out;
 	}
 	}
 
 
 	/* make sure PCI base addr 1 is MMIO */
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(mmio_flags & IORESOURCE_MEM)) {
 	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;
 		rc = -ENODEV;
 		goto err_out;
 		goto err_out;
 	}
 	}
@@ -646,12 +646,12 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
 	/* check for weird/broken PCI region reporting */
 	/* check for weird/broken PCI region reporting */
 	if ((pio_len < NETDRV_MIN_IO_SIZE) ||
 	if ((pio_len < NETDRV_MIN_IO_SIZE) ||
 	    (mmio_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;
 		rc = -ENODEV;
 		goto err_out;
 		goto err_out;
 	}
 	}
 
 
-	rc = pci_request_regions (pdev, "pci-skeleton");
+	rc = pci_request_regions (pdev, MODNAME);
 	if (rc)
 	if (rc)
 		goto err_out;
 		goto err_out;
 
 
@@ -663,7 +663,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
 	/* ioremap MMIO region */
 	/* ioremap MMIO region */
 	ioaddr = ioremap (mmio_start, mmio_len);
 	ioaddr = ioremap (mmio_start, mmio_len);
 	if (ioaddr == NULL) {
 	if (ioaddr == NULL) {
-		printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
+		dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
 		rc = -EIO;
 		rc = -EIO;
 		goto err_out_free_res;
 		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 */
 	/* 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;
 	tp->chipset = 0;
 
 
 match:
 match:

+ 382 - 138
drivers/net/pcnet32.c

@@ -58,18 +58,15 @@ static const char *const version =
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  */
  */
 static struct pci_device_id pcnet32_pci_tbl[] = {
 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
 	 * Adapters that were sold with IBM's RS/6000 or pSeries hardware have
 	 * the incorrect vendor id.
 	 * 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 */
 	{ }	/* terminate list */
 };
 };
@@ -188,6 +185,23 @@ static int homepna[MAX_UNITS];
 
 
 #define PCNET32_TOTAL_SIZE	0x20
 #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. */
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
 struct pcnet32_rx_head {
 	u32	base;
 	u32	base;
@@ -277,7 +291,6 @@ struct pcnet32_private {
 	u32			phymask;
 	u32			phymask;
 };
 };
 
 
-static void pcnet32_probe_vlbus(void);
 static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
 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_probe1(unsigned long, int, struct pci_dev *);
 static int pcnet32_open(struct net_device *);
 static int pcnet32_open(struct net_device *);
@@ -419,6 +432,238 @@ static struct pcnet32_access pcnet32_dwio = {
 	.reset = pcnet32_dwio_reset
 	.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
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void pcnet32_poll_controller(struct net_device *dev)
 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;
 	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,
 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;
 	struct pcnet32_private *lp = dev->priv;
 	unsigned long flags;
 	unsigned long flags;
+	unsigned int size;
+	ulong ioaddr = dev->base_addr;
 	int i;
 	int i;
 
 
 	if (ering->rx_mini_pending || ering->rx_jumbo_pending)
 	if (ering->rx_mini_pending || ering->rx_jumbo_pending)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	if (netif_running(dev))
 	if (netif_running(dev))
-		pcnet32_close(dev);
+		pcnet32_netif_stop(dev);
 
 
 	spin_lock_irqsave(&lp->lock, flags);
 	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
 	/* set the minimum ring size to 4, to allow the loopback test to work
 	 * unchanged.
 	 * unchanged.
 	 */
 	 */
 	for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
 	for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
-		if (lp->tx_ring_size <= (1 << i))
+		if (size <= (1 << i))
 			break;
 			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++) {
 	for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
-		if (lp->rx_ring_size <= (1 << i))
+		if (size <= (1 << i))
 			break;
 			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);
 	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,
 		       "%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
 		       lp->rx_ring_size, lp->tx_ring_size);
 		       lp->rx_ring_size, lp->tx_ring_size);
 
 
-	if (netif_running(dev))
-		pcnet32_open(dev);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -633,29 +875,27 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
 	unsigned long flags;
 	unsigned long flags;
 	unsigned long ticks;
 	unsigned long ticks;
 
 
-	*data1 = 1;		/* status of test, default to fail */
 	rc = 1;			/* default to fail */
 	rc = 1;			/* default to fail */
 
 
 	if (netif_running(dev))
 	if (netif_running(dev))
 		pcnet32_close(dev);
 		pcnet32_close(dev);
 
 
 	spin_lock_irqsave(&lp->lock, flags);
 	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 */
 	/* Reset the PCNET32 */
 	lp->a.reset(ioaddr);
 	lp->a.reset(ioaddr);
+	lp->a.write_csr(ioaddr, CSR4, 0x0915);
 
 
 	/* switch pcnet32 to 32bit mode */
 	/* switch pcnet32 to 32bit mode */
 	lp->a.write_bcr(ioaddr, 20, 2);
 	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 */
 	/* purge & init rings but don't actually restart */
 	pcnet32_restart(dev, 0x0000);
 	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. */
 	/* Initialize Transmit buffers. */
 	size = data_len + 15;
 	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);
 	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 */
 	/* Check status of descriptors */
 	for (x = 0; x < numbuffs; x++) {
 	for (x = 0; x < numbuffs; x++) {
@@ -712,7 +953,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
 		rmb();
 		rmb();
 		while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
 		while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
 			spin_unlock_irqrestore(&lp->lock, flags);
 			spin_unlock_irqrestore(&lp->lock, flags);
-			mdelay(1);
+			msleep(1);
 			spin_lock_irqsave(&lp->lock, flags);
 			spin_lock_irqsave(&lp->lock, flags);
 			rmb();
 			rmb();
 			ticks++;
 			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();
 	wmb();
 	if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
 	if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
 		printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
 		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++;
 		x++;
 	}
 	}
-	if (!rc) {
-		*data1 = 0;
-	}
 
 
       clean_up:
       clean_up:
+	*data1 = rc;
 	pcnet32_purge_tx_ring(dev);
 	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)) {
 	if (netif_running(dev)) {
+		spin_unlock_irqrestore(&lp->lock, flags);
 		pcnet32_open(dev);
 		pcnet32_open(dev);
 	} else {
 	} else {
+		pcnet32_purge_rx_ring(dev);
 		lp->a.write_bcr(ioaddr, 20, 4);	/* return to 16bit mode */
 		lp->a.write_bcr(ioaddr, 20, 4);	/* return to 16bit mode */
+		spin_unlock_irqrestore(&lp->lock, flags);
 	}
 	}
 
 
 	return (rc);
 	return (rc);
@@ -839,6 +1079,43 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
 	return 0;
 	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_REGS_PER_PHY	32
 #define PCNET32_MAX_PHYS	32
 #define PCNET32_MAX_PHYS	32
 static int pcnet32_get_regs_len(struct net_device *dev)
 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_private *lp = dev->priv;
 	struct pcnet32_access *a = &lp->a;
 	struct pcnet32_access *a = &lp->a;
 	ulong ioaddr = dev->base_addr;
 	ulong ioaddr = dev->base_addr;
-	int ticks;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&lp->lock, 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 */
 	/* read address PROM */
 	for (i = 0; i < 16; i += 2)
 	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 */
 		/* 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);
 	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
 /* only probes for non-PCI devices, the rest are handled by
  * pci_register_driver via pcnet32_probe_pci */
  * 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;
 	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_size,
 					   &lp->tx_ring_dma_addr);
 					   &lp->tx_ring_dma_addr);
 	if (lp->tx_ring == NULL) {
 	if (lp->tx_ring == NULL) {
-		if (pcnet32_debug & NETIF_MSG_DRV)
+		if (netif_msg_drv(lp))
 			printk("\n" KERN_ERR PFX
 			printk("\n" KERN_ERR PFX
 			       "%s: Consistent memory allocation failed.\n",
 			       "%s: Consistent memory allocation failed.\n",
 			       name);
 			       name);
@@ -1448,52 +1709,48 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
 					   lp->rx_ring_size,
 					   lp->rx_ring_size,
 					   &lp->rx_ring_dma_addr);
 					   &lp->rx_ring_dma_addr);
 	if (lp->rx_ring == NULL) {
 	if (lp->rx_ring == NULL) {
-		if (pcnet32_debug & NETIF_MSG_DRV)
+		if (netif_msg_drv(lp))
 			printk("\n" KERN_ERR PFX
 			printk("\n" KERN_ERR PFX
 			       "%s: Consistent memory allocation failed.\n",
 			       "%s: Consistent memory allocation failed.\n",
 			       name);
 			       name);
 		return -ENOMEM;
 		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);
 				  GFP_ATOMIC);
 	if (!lp->tx_dma_addr) {
 	if (!lp->tx_dma_addr) {
-		if (pcnet32_debug & NETIF_MSG_DRV)
+		if (netif_msg_drv(lp))
 			printk("\n" KERN_ERR PFX
 			printk("\n" KERN_ERR PFX
 			       "%s: Memory allocation failed.\n", name);
 			       "%s: Memory allocation failed.\n", name);
 		return -ENOMEM;
 		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);
 				  GFP_ATOMIC);
 	if (!lp->rx_dma_addr) {
 	if (!lp->rx_dma_addr) {
-		if (pcnet32_debug & NETIF_MSG_DRV)
+		if (netif_msg_drv(lp))
 			printk("\n" KERN_ERR PFX
 			printk("\n" KERN_ERR PFX
 			       "%s: Memory allocation failed.\n", name);
 			       "%s: Memory allocation failed.\n", name);
 		return -ENOMEM;
 		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);
 				GFP_ATOMIC);
 	if (!lp->tx_skbuff) {
 	if (!lp->tx_skbuff) {
-		if (pcnet32_debug & NETIF_MSG_DRV)
+		if (netif_msg_drv(lp))
 			printk("\n" KERN_ERR PFX
 			printk("\n" KERN_ERR PFX
 			       "%s: Memory allocation failed.\n", name);
 			       "%s: Memory allocation failed.\n", name);
 		return -ENOMEM;
 		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);
 				GFP_ATOMIC);
 	if (!lp->rx_skbuff) {
 	if (!lp->rx_skbuff) {
-		if (pcnet32_debug & NETIF_MSG_DRV)
+		if (netif_msg_drv(lp))
 			printk("\n" KERN_ERR PFX
 			printk("\n" KERN_ERR PFX
 			       "%s: Memory allocation failed.\n", name);
 			       "%s: Memory allocation failed.\n", name);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
-	memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1757,16 +2014,7 @@ static int pcnet32_open(struct net_device *dev)
 
 
       err_free_ring:
       err_free_ring:
 	/* free any allocated skbuffs */
 	/* 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
 	 * 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;
 	unsigned long ioaddr = dev->base_addr;
 	struct pcnet32_private *lp = dev->priv;
 	struct pcnet32_private *lp = dev->priv;
-	int i;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	del_timer_sync(&lp->watchdog_timer);
 	del_timer_sync(&lp->watchdog_timer);
@@ -2379,31 +2626,8 @@ static int pcnet32_close(struct net_device *dev)
 
 
 	spin_lock_irqsave(&lp->lock, flags);
 	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);
 	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 struct pcnet32_init_block *ib = &lp->init_block;
 	volatile u16 *mcast_table = (u16 *) & ib->filter;
 	volatile u16 *mcast_table = (u16 *) & ib->filter;
 	struct dev_mc_list *dmi = dev->mc_list;
 	struct dev_mc_list *dmi = dev->mc_list;
+	unsigned long ioaddr = dev->base_addr;
 	char *addrs;
 	char *addrs;
 	int i;
 	int i;
 	u32 crc;
 	u32 crc;
@@ -2441,6 +2666,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
 	if (dev->flags & IFF_ALLMULTI) {
 	if (dev->flags & IFF_ALLMULTI) {
 		ib->filter[0] = 0xffffffff;
 		ib->filter[0] = 0xffffffff;
 		ib->filter[1] = 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;
 		return;
 	}
 	}
 	/* clear the multicast filter */
 	/* 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]) |
 		    le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
 				(1 << (crc & 0xf)));
 				(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;
 	return;
 }
 }
 
 
@@ -2472,8 +2704,11 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
 {
 {
 	unsigned long ioaddr = dev->base_addr, flags;
 	unsigned long ioaddr = dev->base_addr, flags;
 	struct pcnet32_private *lp = dev->priv;
 	struct pcnet32_private *lp = dev->priv;
+	int csr15, suspended;
 
 
 	spin_lock_irqsave(&lp->lock, flags);
 	spin_lock_irqsave(&lp->lock, flags);
+	suspended = pcnet32_suspend(dev, &flags, 0);
+	csr15 = lp->a.read_csr(ioaddr, CSR15);
 	if (dev->flags & IFF_PROMISC) {
 	if (dev->flags & IFF_PROMISC) {
 		/* Log any net taps. */
 		/* Log any net taps. */
 		if (netif_msg_hw(lp))
 		if (netif_msg_hw(lp))
@@ -2482,15 +2717,24 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
 		lp->init_block.mode =
 		lp->init_block.mode =
 		    le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
 		    le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
 				7);
 				7);
+		lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
 	} else {
 	} else {
 		lp->init_block.mode =
 		lp->init_block.mode =
 		    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
 		    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+		lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
 		pcnet32_load_multicast(dev);
 		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);
 	spin_unlock_irqrestore(&lp->lock, flags);
 }
 }
@@ -2730,7 +2974,7 @@ static int __init pcnet32_init_module(void)
 
 
 	/* should we find any remaining VLbus devices ? */
 	/* should we find any remaining VLbus devices ? */
 	if (pcnet32vlb)
 	if (pcnet32vlb)
-		pcnet32_probe_vlbus();
+		pcnet32_probe_vlbus(pcnet32_portlist);
 
 
 	if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
 	if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
 		printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
 		printk(KERN_INFO PFX "%d cards_found.\n", cards_found);

+ 36 - 6
drivers/net/phy/cicada.c

@@ -103,7 +103,22 @@ static int cis820x_config_intr(struct phy_device *phydev)
 	return err;
 	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 = {
 static struct phy_driver cis8204_driver = {
 	.phy_id		= 0x000fc440,
 	.phy_id		= 0x000fc440,
 	.name		= "Cicada Cis8204",
 	.name		= "Cicada Cis8204",
@@ -118,15 +133,30 @@ static struct phy_driver cis8204_driver = {
 	.driver 	= { .owner = THIS_MODULE,},
 	.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(&cis8204_driver);
+	phy_driver_unregister(&cis8201_driver);
 }
 }
 
 
-module_init(cis8204_init);
-module_exit(cis8204_exit);
+module_init(cicada_init);
+module_exit(cicada_exit);

+ 16 - 24
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));
 	dev = alloc_etherdev(sizeof (*tp));
 	if (dev == NULL) {
 	if (dev == NULL) {
 		if (netif_msg_drv(&debug))
 		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;
 		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) */
 	/* enable device (incl. PCI PM wakeup and hotplug setup) */
 	rc = pci_enable_device(pdev);
 	rc = pci_enable_device(pdev);
 	if (rc < 0) {
 	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;
 		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);
 		pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
 		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
 		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
 	} else {
 	} else {
-		if (netif_msg_probe(tp)) {
-			printk(KERN_ERR PFX
+		if (netif_msg_probe(tp))
+			dev_err(&pdev->dev,
 			       "PowerManagement capability not found.\n");
 			       "PowerManagement capability not found.\n");
-		}
 	}
 	}
 
 
 	/* make sure PCI base addr 1 is MMIO */
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
 	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");
 			       "region #1 not an MMIO resource, aborting\n");
-		}
 		rc = -ENODEV;
 		rc = -ENODEV;
 		goto err_out_mwi;
 		goto err_out_mwi;
 	}
 	}
 	/* check for weird/broken PCI region reporting */
 	/* check for weird/broken PCI region reporting */
 	if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
 	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");
 			       "Invalid PCI region size(s), aborting\n");
-		}
 		rc = -ENODEV;
 		rc = -ENODEV;
 		goto err_out_mwi;
 		goto err_out_mwi;
 	}
 	}
 
 
 	rc = pci_request_regions(pdev, MODULENAME);
 	rc = pci_request_regions(pdev, MODULENAME);
 	if (rc < 0) {
 	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;
 		goto err_out_mwi;
 	}
 	}
 
 
@@ -1480,10 +1473,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 	} else {
 	} else {
 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc < 0) {
 		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");
 				       "DMA configuration failed.\n");
-			}
 			goto err_out_free_res;
 			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);
 	ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
 	if (ioaddr == NULL) {
 	if (ioaddr == NULL) {
 		if (netif_msg_probe(tp))
 		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;
 		rc = -EIO;
 		goto err_out_free_res;
 		goto err_out_free_res;
 	}
 	}
@@ -1526,9 +1518,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 	if (i < 0) {
 	if (i < 0) {
 		/* Unknown chip: assume array element #0, original RTL-8169 */
 		/* Unknown chip: assume array element #0, original RTL-8169 */
 		if (netif_msg_probe(tp)) {
 		if (netif_msg_probe(tp)) {
-			printk(KERN_DEBUG PFX "PCI device %s: "
+			dev_printk(KERN_DEBUG, &pdev->dev,
 			       "unknown chip version, assuming %s\n",
 			       "unknown chip version, assuming %s\n",
-			       pci_name(pdev), rtl_chip_info[0].name);
+			       rtl_chip_info[0].name);
 		}
 		}
 		i++;
 		i++;
 	}
 	}

+ 3 - 120
drivers/net/starfire.c

@@ -22,129 +22,13 @@
 
 
 	Support and updates available at
 	Support and updates available at
 	http://www.scyld.com/network/starfire.html
 	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_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/module.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -846,7 +730,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
 		goto err_out_free_netdev;
 		goto err_out_free_netdev;
 	}
 	}
 
 
-	/* ioremap is borken in Linux-2.2.x/sparc64 */
 	base = ioremap(ioaddr, io_size);
 	base = ioremap(ioaddr, io_size);
 	if (!base) {
 	if (!base) {
 		printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
 		printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",

+ 14 - 92
drivers/net/sundance.c

@@ -16,91 +16,13 @@
 
 
 	Support and updates available at
 	Support and updates available at
 	http://www.scyld.com/network/sundance.html
 	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_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.
 /* The user-configurable values.
@@ -282,15 +204,15 @@ IVc. Errata
 #define USE_IO_OPS 1
 #define USE_IO_OPS 1
 #endif
 #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);
 MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
 
 
@@ -301,7 +223,7 @@ enum {
 struct pci_id_info {
 struct pci_id_info {
         const char *name;
         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-550TX FAST Ethernet Adapter"},
 	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
 	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
 	{"D-Link DFE-580TX 4 port Server 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"},
 	{"D-Link DL10050-based FAST Ethernet Adapter"},
 	{"Sundance Technology Alta"},
 	{"Sundance Technology Alta"},
 	{"IC Plus Corporation IP100A FAST Ethernet Adapter"},
 	{"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
 /* This driver was written to use PCI memory space, however x86-oriented

+ 13 - 16
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);
 MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
 
 
+enum {
+	netdev_res_size		= 128,	/* size of PCI BAR resource */
+};
+
 struct pci_id_info {
 struct pci_id_info {
         const char *name;
         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
 /* 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
 #ifdef USE_IO_OPS
 	bar = 0;
 	bar = 0;
 #endif
 #endif
-	ioaddr = pci_iomap(pdev, bar, pci_id_tbl[chip_idx].io_size);
+	ioaddr = pci_iomap(pdev, bar, netdev_res_size);
 	if (!ioaddr)
 	if (!ioaddr)
 		goto err_out_free_res;
 		goto err_out_free_res;
 
 

+ 4 - 23
drivers/net/tulip/xircom_tulip_cb.c

@@ -10,26 +10,11 @@
 	410 Severn Ave., Suite 210
 	410 Severn Ave., Suite 210
 	Annapolis MD 21403
 	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_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. */
 /* A few user-configurable values. */
 
 
@@ -306,10 +291,10 @@ struct xircom_private {
 	struct xircom_tx_desc tx_ring[TX_RING_SIZE];
 	struct xircom_tx_desc tx_ring[TX_RING_SIZE];
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-#ifdef CARDBUS
+
 	/* The X3201-3 requires 4-byte aligned tx bufs */
 	/* The X3201-3 requires 4-byte aligned tx bufs */
 	struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
 	struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
-#endif
+
 	/* The addresses of receive-in-place skbuffs. */
 	/* The addresses of receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)];	/* Pseudo-Tx frame to init address table. */
 	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_skbuff[i] = NULL;
 		tp->tx_ring[i].status = 0;
 		tp->tx_ring[i].status = 0;
 		tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
 		tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
-#ifdef CARDBUS
 		if (tp->chip_id == X3201_3)
 		if (tp->chip_id == X3201_3)
 			tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
 			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]);
 	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;
 	entry = tp->cur_tx % TX_RING_SIZE;
 
 
 	tp->tx_skbuff[entry] = skb;
 	tp->tx_skbuff[entry] = skb;
-#ifdef CARDBUS
 	if (tp->chip_id == X3201_3) {
 	if (tp->chip_id == X3201_3) {
 		memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
 		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);
 		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
 	} else
 	} else
-#endif
 		tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
 		tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
 
 
 	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
 	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */

+ 8 - 113
drivers/net/via-rhine.c

@@ -25,117 +25,13 @@
 	version. He may or may not be interested in bug reports on this
 	version. He may or may not be interested in bug reports on this
 	code. You can find his versions at:
 	code. You can find his versions at:
 	http://www.scyld.com/network/via-rhine.html
 	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_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.
 /* A few user-configurable values.
@@ -356,12 +252,11 @@ enum rhine_quirks {
 /* Beware of PCI posted writes */
 /* Beware of PCI posted writes */
 #define IOSYNC	do { ioread8(ioaddr + StationAddr); } while (0)
 #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 */
 	{ }	/* terminate list */
 };
 };
 MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
 MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);

+ 50 - 52
drivers/net/via-velocity.c

@@ -229,7 +229,8 @@ static int rx_copybreak = 200;
 module_param(rx_copybreak, int, 0644);
 module_param(rx_copybreak, int, 0644);
 MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 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 int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
 static void velocity_print_info(struct velocity_info *vptr);
 static void velocity_print_info(struct velocity_info *vptr);
 static int velocity_open(struct net_device *dev);
 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
  *	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.
  *	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);
 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)
 static void __devexit velocity_remove1(struct pci_dev *pdev)
 {
 {
 	struct net_device *dev = pci_get_drvdata(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
 #ifdef CONFIG_PM
 	unsigned long flags;
 	unsigned long flags;
@@ -686,21 +686,23 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
 	static int first = 1;
 	static int first = 1;
 	struct net_device *dev;
 	struct net_device *dev;
 	int i;
 	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 velocity_info *vptr;
 	struct mac_regs __iomem * regs;
 	struct mac_regs __iomem * regs;
 	int ret = -ENOMEM;
 	int ret = -ENOMEM;
 
 
+	/* FIXME: this driver, like almost all other ethernet drivers,
+	 * can support more than MAX_UNITS.
+	 */
 	if (velocity_nics >= 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;
 		return -ENODEV;
 	}
 	}
 
 
 	dev = alloc_etherdev(sizeof(struct velocity_info));
 	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;
 		goto out;
 	}
 	}
 	
 	
@@ -708,7 +710,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
 	
 	
 	SET_MODULE_OWNER(dev);
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
-	vptr = dev->priv;
+	vptr = netdev_priv(dev);
 
 
 
 
 	if (first) {
 	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);
 	ret = velocity_get_pci_info(vptr, pdev);
 	if (ret < 0) {
 	if (ret < 0) {
-		printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+		/* error message already printed */
 		goto err_disable;
 		goto err_disable;
 	}
 	}
 
 
 	ret = pci_request_regions(pdev, VELOCITY_NAME);
 	ret = pci_request_regions(pdev, VELOCITY_NAME);
 	if (ret < 0) {
 	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;
 		goto err_disable;
 	}
 	}
 
 
-	regs = ioremap(vptr->memaddr, vptr->io_size);
+	regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
 	if (regs == NULL) {
 	if (regs == NULL) {
 		ret = -EIO;
 		ret = -EIO;
 		goto err_release_res;
 		goto err_release_res;
@@ -859,13 +861,14 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
  *	discovered.
  *	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));
 	memset(vptr, 0, sizeof(struct velocity_info));
 
 
 	vptr->pdev = pdev;
 	vptr->pdev = pdev;
 	vptr->chip_id = info->chip_id;
 	vptr->chip_id = info->chip_id;
-	vptr->io_size = info->io_size;
 	vptr->num_txq = info->txqueue;
 	vptr->num_txq = info->txqueue;
 	vptr->multicast_limit = MCAM_SIZE;
 	vptr->multicast_limit = MCAM_SIZE;
 	spin_lock_init(&vptr->lock);
 	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)
 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;
 		return -EIO;
 		
 		
 	pci_set_master(pdev);
 	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->ioaddr = pci_resource_start(pdev, 0);
 	vptr->memaddr = pci_resource_start(pdev, 1);
 	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;
 		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;
 		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;
 		return -EINVAL;
 	}
 	}
 	vptr->pdev = pdev;
 	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)
 static int velocity_open(struct net_device *dev)
 {
 {
-	struct velocity_info *vptr = dev->priv;
+	struct velocity_info *vptr = netdev_priv(dev);
 	int ret;
 	int ret;
 
 
 	vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
 	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)
 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;
 	unsigned long flags;
 	int oldmtu = dev->mtu;
 	int oldmtu = dev->mtu;
 	int ret = 0;
 	int ret = 0;
@@ -1861,7 +1859,7 @@ static void velocity_shutdown(struct velocity_info *vptr)
 
 
 static int velocity_close(struct net_device *dev)
 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);
 	netif_stop_queue(dev);
 	velocity_shutdown(vptr);
 	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)
 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;
 	int qnum = 0;
 	struct tx_desc *td_ptr;
 	struct tx_desc *td_ptr;
 	struct velocity_td_info *tdinfo;
 	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)
 static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
 {
 {
 	struct net_device *dev = dev_instance;
 	struct net_device *dev = dev_instance;
-	struct velocity_info *vptr = dev->priv;
+	struct velocity_info *vptr = netdev_priv(dev);
 	u32 isr_status;
 	u32 isr_status;
 	int max_count = 0;
 	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)
 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;
 	struct mac_regs __iomem * regs = vptr->mac_regs;
 	u8 rx_mode;
 	u8 rx_mode;
 	int i;
 	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)
 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 the hardware is down, don't touch MII */
 	if(!netif_running(dev))
 	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)
 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;
 	int ret;
 
 
 	/* If we are asked for information and the device is power
 	/* 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)
 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))
 	if (!netif_running(dev))
 		pci_set_power_state(vptr->pdev, PCI_D0);
 		pci_set_power_state(vptr->pdev, PCI_D0);
 	return 0;
 	return 0;
@@ -2841,14 +2839,14 @@ static int velocity_ethtool_up(struct net_device *dev)
  
  
 static void velocity_ethtool_down(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))
 	if (!netif_running(dev))
 		pci_set_power_state(vptr->pdev, PCI_D3hot);
 		pci_set_power_state(vptr->pdev, PCI_D3hot);
 }
 }
 
 
 static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 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;
 	struct mac_regs __iomem * regs = vptr->mac_regs;
 	u32 status;
 	u32 status;
 	status = check_connection_type(vptr->mac_regs);
 	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)
 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 curr_status;
 	u32 new_status = 0;
 	u32 new_status = 0;
 	int ret = 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)
 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;
 	struct mac_regs __iomem * regs = vptr->mac_regs;
 	return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0)  ? 0 : 1;
 	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)
 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->driver, VELOCITY_NAME);
 	strcpy(info->version, VELOCITY_VERSION);
 	strcpy(info->version, VELOCITY_VERSION);
 	strcpy(info->bus_info, pci_name(vptr->pdev));
 	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)
 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->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
 	wol->wolopts |= WAKE_MAGIC;
 	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)
 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)))
 	if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
 		return -EFAULT;
 		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)
 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;
 	struct mac_regs __iomem * regs = vptr->mac_regs;
 	unsigned long flags;
 	unsigned long flags;
 	struct mii_ioctl_data *miidata = if_mii(ifr);
 	struct mii_ioctl_data *miidata = if_mii(ifr);

+ 2 - 2
drivers/net/via-velocity.h

@@ -31,6 +31,8 @@
 #define VELOCITY_FULL_DRV_NAM  "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
 #define VELOCITY_FULL_DRV_NAM  "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
 #define VELOCITY_VERSION       "1.13"
 #define VELOCITY_VERSION       "1.13"
 
 
+#define VELOCITY_IO_SIZE	256
+
 #define PKT_BUF_SZ          1540
 #define PKT_BUF_SZ          1540
 
 
 #define MAX_UNITS           8
 #define MAX_UNITS           8
@@ -1191,7 +1193,6 @@ enum chip_type {
 struct velocity_info_tbl {
 struct velocity_info_tbl {
 	enum chip_type chip_id;
 	enum chip_type chip_id;
 	char *name;
 	char *name;
-	int io_size;
 	int txqueue;
 	int txqueue;
 	u32 flags;
 	u32 flags;
 };
 };
@@ -1751,7 +1752,6 @@ struct velocity_info {
 	struct mac_regs __iomem * mac_regs;
 	struct mac_regs __iomem * mac_regs;
 	unsigned long memaddr;
 	unsigned long memaddr;
 	unsigned long ioaddr;
 	unsigned long ioaddr;
-	u32 io_size;
 
 
 	u8 rev_id;
 	u8 rev_id;
 
 

+ 0 - 12
drivers/net/wan/Kconfig

@@ -134,18 +134,6 @@ config SEALEVEL_4021
 	  The driver will be compiled as a module: the
 	  The driver will be compiled as a module: the
 	  module will be called sealevel.
 	  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
 # Generic HDLC
 config HDLC
 config HDLC
 	tristate "Generic HDLC layer"
 	tristate "Generic HDLC layer"

+ 0 - 1
drivers/net/wan/Makefile

@@ -28,7 +28,6 @@ obj-$(CONFIG_COSA)		+=		syncppp.o	cosa.o
 obj-$(CONFIG_FARSYNC)		+=		syncppp.o	farsync.o
 obj-$(CONFIG_FARSYNC)		+=		syncppp.o	farsync.o
 obj-$(CONFIG_DSCC4)             +=				dscc4.o
 obj-$(CONFIG_DSCC4)             +=				dscc4.o
 obj-$(CONFIG_LANMEDIA)		+=		syncppp.o
 obj-$(CONFIG_LANMEDIA)		+=		syncppp.o
-obj-$(CONFIG_SYNCLINK_SYNCPPP)	+=		syncppp.o
 obj-$(CONFIG_X25_ASY)		+= x25_asy.o
 obj-$(CONFIG_X25_ASY)		+= x25_asy.o
 
 
 obj-$(CONFIG_LANMEDIA)		+= lmc/
 obj-$(CONFIG_LANMEDIA)		+= lmc/

+ 1 - 0
drivers/net/wireless/Kconfig

@@ -550,6 +550,7 @@ config USB_ZD1201
 
 
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/zd1211rw/Kconfig"
 
 
 # yes, this works even when no drivers are selected
 # yes, this works even when no drivers are selected
 config NET_WIRELESS
 config NET_WIRELESS

+ 1 - 0
drivers/net/wireless/Makefile

@@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54)		+= prism54/
 
 
 obj-$(CONFIG_HOSTAP)		+= hostap/
 obj-$(CONFIG_HOSTAP)		+= hostap/
 obj-$(CONFIG_BCM43XX)		+= bcm43xx/
 obj-$(CONFIG_BCM43XX)		+= bcm43xx/
+obj-$(CONFIG_ZD1211RW)		+= zd1211rw/
 
 
 # 16-bit wireless PCMCIA client drivers
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o

+ 18 - 13
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);
 	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);
 	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) {
 	if (reason == 0xffffffff) {
 		/* irq not for us (shared irq) */
 		/* 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);
 	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:
 out:
 	mmiowb();
 	mmiowb();
@@ -3698,6 +3699,10 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
 		secinfo->encrypt = sec->encrypt;
 		secinfo->encrypt = sec->encrypt;
 		dprintk(", .encrypt = %d", 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");
 	dprintk("\n");
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
 	    !bcm->ieee->host_encrypt) {
 	    !bcm->ieee->host_encrypt) {

+ 0 - 24
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);
 	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_read(struct bcm43xx_private *bcm, u64 *tsf);
 void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
 void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
 
 

+ 2 - 5
drivers/net/wireless/bcm43xx/bcm43xx_radio.c

@@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
 	u16 r8, tmp;
 	u16 r8, tmp;
 	u16 freq;
 	u16 freq;
 
 
+	if (!ieee80211_is_valid_channel(bcm->ieee, channel))
+		return -EINVAL;
 	if ((radio->manufact == 0x17F) &&
 	if ((radio->manufact == 0x17F) &&
 	    (radio->version == 0x2060) &&
 	    (radio->version == 0x2060) &&
 	    (radio->revision == 1)) {
 	    (radio->revision == 1)) {
-		if (channel > 200)
-			return -EINVAL;
 		freq = channel2freq_a(channel);
 		freq = channel2freq_a(channel);
 
 
 		r8 = bcm43xx_radio_read16(bcm, 0x0008);
 		r8 = bcm43xx_radio_read16(bcm, 0x0008);
@@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
 		TODO();	//TODO:	TSSI2dbm workaround
 		TODO();	//TODO:	TSSI2dbm workaround
 		bcm43xx_phy_xmitpower(bcm);//FIXME correct?
 		bcm43xx_phy_xmitpower(bcm);//FIXME correct?
 	} else {
 	} else {
-		if ((channel < 1) || (channel > 14))
-			return -EINVAL;
-
 		if (synthetic_pu_workaround)
 		if (synthetic_pu_workaround)
 			bcm43xx_synth_pu_workaround(bcm, channel);
 			bcm43xx_synth_pu_workaround(bcm, channel);
 
 

+ 1 - 1
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);
 		channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
 		freq = 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;
 		goto out_unlock;
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		//ieee80211softmac_disassoc(softmac, $REASON);
 		//ieee80211softmac_disassoc(softmac, $REASON);

+ 4 - 1
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c

@@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
 	u16 control = 0;
 	u16 control = 0;
 	u16 wsec_rate = 0;
 	u16 wsec_rate = 0;
 	u16 encrypt_frame;
 	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. */
 	/* Now construct the TX header. */
 	memset(txhdr, 0, sizeof(*txhdr));
 	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));
 	ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
 	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
 	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
 	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
 	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));

+ 2 - 0
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(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
 	PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
 	PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
 	PLXDEV(0x126c, 0x8030, "Nortel emobility"),
 	PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+	PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
 	PLXDEV(0x1385, 0x4100, "Netgear MA301"),
 	PLXDEV(0x1385, 0x4100, "Netgear MA301"),
 	PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
 	PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
 	PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
 	PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
 	PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
 	PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+	PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
 	PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
 	PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
 	PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
 	PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
 	PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
 	PLXDEV(0x16ab, 0x1103, "Longshine 8031"),

+ 19 - 0
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.
+

+ 11 - 0
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
+

+ 1615 - 0
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;
+}

+ 825 - 0
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 */

+ 48 - 0
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 */

+ 191 - 0
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;
+}

+ 85 - 0
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 */

+ 1057 - 0
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 */

+ 190 - 0
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 */

+ 267 - 0
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);
+}

+ 45 - 0
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 */

+ 151 - 0
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;
+}

+ 82 - 0
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 */

+ 308 - 0
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;
+}

+ 279 - 0
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;
+}

+ 71 - 0
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 */

+ 1316 - 0
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;
+}

+ 240 - 0
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 */

+ 82 - 0
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);
+}

+ 29 - 0
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 */

+ 8 - 31
drivers/net/yellowfin.c

@@ -19,37 +19,13 @@
 
 
 	Support and updates available at
 	Support and updates available at
 	http://www.scyld.com/network/yellowfin.html
 	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_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 ": "
 #define PFX DRV_NAME ": "
 
 
@@ -239,8 +215,11 @@ enum capability_flags {
 	HasMACAddrBug=32, /* Only on early revs.  */
 	HasMACAddrBug=32, /* Only on early revs.  */
 	DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
 	DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
 };
 };
+
 /* The PCI I/O space extent. */
 /* The PCI I/O space extent. */
-#define YELLOWFIN_SIZE 0x100
+enum {
+	YELLOWFIN_SIZE	= 0x100,
+};
 
 
 struct pci_id_info {
 struct pci_id_info {
         const char *name;
         const char *name;
@@ -248,16 +227,14 @@ struct pci_id_info {
                 int     pci, pci_mask, subsystem, subsystem_mask;
                 int     pci, pci_mask, subsystem, subsystem_mask;
                 int revision, revision_mask;                            /* Only 8 bits. */
                 int revision, revision_mask;                            /* Only 8 bits. */
         } id;
         } 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 const struct pci_id_info pci_id_tbl[] = {
 static const struct pci_id_info pci_id_tbl[] = {
 	{"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
 	{"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
-	 YELLOWFIN_SIZE,
 	 FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
 	 FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
 	{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
 	{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
-	 YELLOWFIN_SIZE, HasMII | DontUseEeprom },
+	  HasMII | DontUseEeprom },
 	{ }
 	{ }
 };
 };
 
 

+ 12 - 5
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)
 static void ahci_error_handler(struct ata_port *ap)
 {
 {
-	if (!(ap->flags & ATA_FLAG_FROZEN)) {
+	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
 		/* restart engine */
 		/* restart engine */
 		ahci_stop_engine(ap);
 		ahci_stop_engine(ap);
 		ahci_start_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++)
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 		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);
 	rc = pci_enable_device(pdev);
 	if (rc)
 	if (rc)
 		return 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)
 	if (have_msi)
 		hpriv->flags |= AHCI_FLAG_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 */
 	/* initialize adapter */
 	rc = ahci_host_init(probe_ent);
 	rc = ahci_host_init(probe_ent);
 	if (rc)
 	if (rc)

+ 185 - 104
drivers/scsi/libata-core.c

@@ -61,9 +61,9 @@
 #include "libata.h"
 #include "libata.h"
 
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
 /* 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,
 static unsigned int ata_dev_init_params(struct ata_device *dev,
 					u16 heads, u16 sectors);
 					u16 heads, u16 sectors);
@@ -907,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
 {
 {
 	int rc;
 	int rc;
 
 
-	if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+	if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
 		return;
 		return;
 
 
 	PREPARE_WORK(&ap->port_task, fn, data);
 	PREPARE_WORK(&ap->port_task, fn, data);
@@ -938,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap)
 	DPRINTK("ENTER\n");
 	DPRINTK("ENTER\n");
 
 
 	spin_lock_irqsave(ap->lock, flags);
 	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);
 	spin_unlock_irqrestore(ap->lock, flags);
 
 
 	DPRINTK("flush #1\n");
 	DPRINTK("flush #1\n");
@@ -957,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap)
 	}
 	}
 
 
 	spin_lock_irqsave(ap->lock, flags);
 	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);
 	spin_unlock_irqrestore(ap->lock, flags);
 
 
 	if (ata_msg_ctl(ap))
 	if (ata_msg_ctl(ap))
@@ -1009,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
 	spin_lock_irqsave(ap->lock, flags);
 	spin_lock_irqsave(ap->lock, flags);
 
 
 	/* no internal command while frozen */
 	/* no internal command while frozen */
-	if (ap->flags & ATA_FLAG_FROZEN) {
+	if (ap->pflags & ATA_PFLAG_FROZEN) {
 		spin_unlock_irqrestore(ap->lock, flags);
 		spin_unlock_irqrestore(ap->lock, flags);
 		return AC_ERR_SYSTEM;
 		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);
 		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
  *	ata_dev_configure - Configure the specified ATA/ATAPI device
  *	@dev: Target device to configure
  *	@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;
 	struct ata_port *ap = dev->ap;
 	const u16 *id = dev->id;
 	const u16 *id = dev->id;
 	unsigned int xfer_mask;
 	unsigned int xfer_mask;
-	int i, rc;
+	int rc;
 
 
 	if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
 	if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
 		ata_dev_printk(dev, KERN_INFO,
 		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));
 			ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
 
 			/* print device info to dmesg */
 			/* 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, "
 				ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
 					"max %s, %Lu sectors: %s %s\n",
 					"max %s, %Lu sectors: %s %s\n",
 					ata_id_major_version(id),
 					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 */
 			/* 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, "
 				ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
 					"max %s, %Lu sectors: CHS %u/%u/%u\n",
 					"max %s, %Lu sectors: CHS %u/%u/%u\n",
 					ata_id_major_version(id),
 					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) {
 		if (dev->id[59] & 0x100) {
 			dev->multi_count = dev->id[59] & 0xff;
 			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_dev_printk(dev, KERN_INFO,
 					"ata%u: dev %u multi count %u\n",
 					"ata%u: dev %u multi count %u\n",
 					ap->id, dev->devno, dev->multi_count);
 					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 */
 		/* 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_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
 				       ata_mode_string(xfer_mask),
 				       ata_mode_string(xfer_mask),
 				       cdb_intr_string);
 				       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 */
 	/* limit bridge transfers to udma5, 200 sectors */
 	if (ata_dev_knobble(dev)) {
 	if (ata_dev_knobble(dev)) {
-		if (ata_msg_info(ap))
+		if (ata_msg_drv(ap) && print_info)
 			ata_dev_printk(dev, KERN_INFO,
 			ata_dev_printk(dev, KERN_INFO,
 				       "applying bridge limits\n");
 				       "applying bridge limits\n");
 		dev->udma_mask &= ATA_UDMA5;
 		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.
 		 * return error code and failing device on failure.
 		 */
 		 */
 		for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		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);
 				ap->ops->set_mode(ap);
 				break;
 				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++) {
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		dev = &ap->device[i];
 		dev = &ap->device[i];
 
 
-		if (!ata_dev_enabled(dev))
+		/* don't udpate suspended devices' xfer mode */
+		if (!ata_dev_ready(dev))
 			continue;
 			continue;
 
 
 		rc = ata_dev_set_mode(dev);
 		rc = ata_dev_set_mode(dev);
@@ -2579,7 +2589,7 @@ static void ata_wait_spinup(struct ata_port *ap)
 
 
 	/* first, debounce phy if SATA */
 	/* first, debounce phy if SATA */
 	if (ap->cbl == ATA_CBL_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 debounced successfully and offline, no need to wait */
 		if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
 		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)
 int ata_std_prereset(struct ata_port *ap)
 {
 {
 	struct ata_eh_context *ehc = &ap->eh_context;
 	struct ata_eh_context *ehc = &ap->eh_context;
-	const unsigned long *timing;
+	const unsigned long *timing = sata_ehc_deb_timing(ehc);
 	int rc;
 	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 we're about to do hardreset, nothing more to do */
 	if (ehc->i.action & ATA_EH_HARDRESET)
 	if (ehc->i.action & ATA_EH_HARDRESET)
@@ -2632,11 +2643,6 @@ int ata_std_prereset(struct ata_port *ap)
 
 
 	/* if SATA, resume phy */
 	/* if SATA, resume phy */
 	if (ap->cbl == ATA_CBL_SATA) {
 	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);
 		rc = sata_phy_resume(ap, timing);
 		if (rc && rc != -EOPNOTSUPP) {
 		if (rc && rc != -EOPNOTSUPP) {
 			/* phy resume failed */
 			/* 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)
 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;
 	u32 scontrol;
 	int rc;
 	int rc;
 
 
@@ -2761,7 +2769,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
 	msleep(1);
 	msleep(1);
 
 
 	/* bring phy back */
 	/* bring phy back */
-	sata_phy_resume(ap, sata_deb_timing_eh);
+	sata_phy_resume(ap, timing);
 
 
 	/* TODO: phy layer with polling, timeouts, etc. */
 	/* TODO: phy layer with polling, timeouts, etc. */
 	if (ata_port_offline(ap)) {
 	if (ata_port_offline(ap)) {
@@ -4285,7 +4293,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
 	unsigned int i;
 	unsigned int i;
 
 
 	/* no command while frozen */
 	/* no command while frozen */
-	if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+	if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
 		return NULL;
 		return NULL;
 
 
 	/* the last tag is reserved for internal command. */
 	/* the last tag is reserved for internal command. */
@@ -4407,7 +4415,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
 	 * taken care of.
 	 * taken care of.
 	 */
 	 */
 	if (ap->ops->error_handler) {
 	if (ap->ops->error_handler) {
-		WARN_ON(ap->flags & ATA_FLAG_FROZEN);
+		WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
 
 
 		if (unlikely(qc->err_mask))
 		if (unlikely(qc->err_mask))
 			qc->flags |= ATA_QCFLAG_FAILED;
 			qc->flags |= ATA_QCFLAG_FAILED;
@@ -5001,86 +5009,120 @@ int ata_flush_cache(struct ata_device *dev)
 	return 0;
 	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;
 	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;
 	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) {
 		if (ap->ops->error_handler) {
+			struct ata_eh_info *ehi = &ap->eh_info;
 			unsigned long flags;
 			unsigned long flags;
 
 
 			ata_port_probe(ap);
 			ata_port_probe(ap);
@@ -5447,10 +5490,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
 			/* kick EH for boot probing */
 			/* kick EH for boot probing */
 			spin_lock_irqsave(ap->lock, flags);
 			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);
 			ata_port_schedule_eh(ap);
 
 
 			spin_unlock_irqrestore(ap->lock, flags);
 			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 */
 	/* tell EH we're leaving & flush EH */
 	spin_lock_irqsave(ap->lock, flags);
 	spin_lock_irqsave(ap->lock, flags);
-	ap->flags |= ATA_FLAG_UNLOADING;
+	ap->pflags |= ATA_PFLAG_UNLOADING;
 	spin_unlock_irqrestore(ap->lock, flags);
 	spin_unlock_irqrestore(ap->lock, flags);
 
 
 	ata_port_wait_eh(ap);
 	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;
 	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_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_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 	pci_restore_state(pdev);
 	pci_enable_device(pdev);
 	pci_enable_device(pdev);
 	pci_set_master(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;
 	return 0;
 }
 }
 #endif /* CONFIG_PCI */
 #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.
  * 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_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_device_add);
 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(sata_scr_write_flush);
 EXPORT_SYMBOL_GPL(ata_port_online);
 EXPORT_SYMBOL_GPL(ata_port_online);
 EXPORT_SYMBOL_GPL(ata_port_offline);
 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_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
 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_native_mode);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_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_suspend);
 EXPORT_SYMBOL_GPL(ata_pci_device_resume);
 EXPORT_SYMBOL_GPL(ata_pci_device_resume);
 EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 #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_suspend);
 EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
 EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
 
 

+ 357 - 48
drivers/scsi/libata-eh.c

@@ -47,6 +47,8 @@
 
 
 static void __ata_port_freeze(struct ata_port *ap);
 static void __ata_port_freeze(struct ata_port *ap);
 static void ata_eh_finish(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,
 static void ata_ering_record(struct ata_ering *ering, int is_io,
 			     unsigned int err_mask)
 			     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)
 void ata_scsi_error(struct Scsi_Host *host)
 {
 {
 	struct ata_port *ap = ata_shost_to_port(host);
 	struct ata_port *ap = ata_shost_to_port(host);
-	spinlock_t *ap_lock = ap->lock;
 	int i, repeat_cnt = ATA_EH_MAX_REPEAT;
 	int i, repeat_cnt = ATA_EH_MAX_REPEAT;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -217,7 +218,7 @@ void ata_scsi_error(struct Scsi_Host *host)
 		struct scsi_cmnd *scmd, *tmp;
 		struct scsi_cmnd *scmd, *tmp;
 		int nr_timedout = 0;
 		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) {
 		list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
 			struct ata_queued_cmd *qc;
 			struct ata_queued_cmd *qc;
@@ -256,43 +257,49 @@ void ata_scsi_error(struct Scsi_Host *host)
 		if (nr_timedout)
 		if (nr_timedout)
 			__ata_port_freeze(ap);
 			__ata_port_freeze(ap);
 
 
-		spin_unlock_irqrestore(ap_lock, flags);
+		spin_unlock_irqrestore(ap->lock, flags);
 	} else
 	} else
-		spin_unlock_wait(ap_lock);
+		spin_unlock_wait(ap->lock);
 
 
  repeat:
  repeat:
 	/* invoke error handler */
 	/* invoke error handler */
 	if (ap->ops->error_handler) {
 	if (ap->ops->error_handler) {
+		/* process port resume request */
+		ata_eh_handle_port_resume(ap);
+
 		/* fetch & clear EH info */
 		/* 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));
 		memset(&ap->eh_context, 0, sizeof(ap->eh_context));
 		ap->eh_context.i = ap->eh_info;
 		ap->eh_context.i = ap->eh_info;
 		memset(&ap->eh_info, 0, sizeof(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);
 			ap->ops->error_handler(ap);
 		else
 		else
 			ata_eh_finish(ap);
 			ata_eh_finish(ap);
 
 
+		/* process port suspend request */
+		ata_eh_handle_port_suspend(ap);
+
 		/* Exception might have happend after ->error_handler
 		/* Exception might have happend after ->error_handler
 		 * recovered the port but before this point.  Repeat
 		 * recovered the port but before this point.  Repeat
 		 * EH in such case.
 		 * 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) {
 			if (--repeat_cnt) {
 				ata_port_printk(ap, KERN_INFO,
 				ata_port_printk(ap, KERN_INFO,
 					"EH pending after completion, "
 					"EH pending after completion, "
 					"repeating EH (cnt=%d)\n", repeat_cnt);
 					"repeating EH (cnt=%d)\n", repeat_cnt);
-				spin_unlock_irqrestore(ap_lock, flags);
+				spin_unlock_irqrestore(ap->lock, flags);
 				goto repeat;
 				goto repeat;
 			}
 			}
 			ata_port_printk(ap, KERN_ERR, "EH pending after %d "
 			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 */
 		/* this run is complete, make sure EH info is clear */
 		memset(&ap->eh_info, 0, sizeof(ap->eh_info));
 		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
 		 * that if exception occurs after this point but
 		 * before EH completion, SCSI midlayer will
 		 * before EH completion, SCSI midlayer will
 		 * re-initiate EH.
 		 * re-initiate EH.
 		 */
 		 */
 		host->host_eh_scheduled = 0;
 		host->host_eh_scheduled = 0;
 
 
-		spin_unlock_irqrestore(ap_lock, flags);
+		spin_unlock_irqrestore(ap->lock, flags);
 	} else {
 	} else {
 		WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
 		WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
 		ap->ops->eng_timeout(ap);
 		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);
 	scsi_eh_flush_done_q(&ap->eh_done_q);
 
 
 	/* clean up */
 	/* 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 */
 	/* 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);
 	wake_up_all(&ap->eh_wait_q);
 
 
-	spin_unlock_irqrestore(ap_lock, flags);
+	spin_unlock_irqrestore(ap->lock, flags);
 
 
 	DPRINTK("EXIT\n");
 	DPRINTK("EXIT\n");
 }
 }
@@ -360,7 +366,7 @@ void ata_port_wait_eh(struct ata_port *ap)
  retry:
  retry:
 	spin_lock_irqsave(ap->lock, flags);
 	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);
 		prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
 		spin_unlock_irqrestore(ap->lock, flags);
 		spin_unlock_irqrestore(ap->lock, flags);
 		schedule();
 		schedule();
@@ -489,7 +495,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
 	WARN_ON(!ap->ops->error_handler);
 	WARN_ON(!ap->ops->error_handler);
 
 
 	qc->flags |= ATA_QCFLAG_FAILED;
 	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.
 	/* The following will fail if timeout has already expired.
 	 * ata_scsi_error() takes care of such scmds on EH entry.
 	 * 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);
 	WARN_ON(!ap->ops->error_handler);
 
 
-	ap->flags |= ATA_FLAG_EH_PENDING;
+	ap->pflags |= ATA_PFLAG_EH_PENDING;
 	scsi_schedule_eh(ap->host);
 	scsi_schedule_eh(ap->host);
 
 
 	DPRINTK("port EH scheduled\n");
 	DPRINTK("port EH scheduled\n");
@@ -578,7 +584,7 @@ static void __ata_port_freeze(struct ata_port *ap)
 	if (ap->ops->freeze)
 	if (ap->ops->freeze)
 		ap->ops->freeze(ap);
 		ap->ops->freeze(ap);
 
 
-	ap->flags |= ATA_FLAG_FROZEN;
+	ap->pflags |= ATA_PFLAG_FROZEN;
 
 
 	DPRINTK("ata%u port frozen\n", ap->id);
 	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);
 	spin_lock_irqsave(ap->lock, flags);
 
 
-	ap->flags &= ~ATA_FLAG_FROZEN;
+	ap->pflags &= ~ATA_PFLAG_FROZEN;
 
 
 	if (ap->ops->thaw)
 	if (ap->ops->thaw)
 		ap->ops->thaw(ap);
 		ap->ops->thaw(ap);
@@ -731,7 +737,7 @@ static void ata_eh_detach_dev(struct ata_device *dev)
 
 
 	if (ata_scsi_offline_dev(dev)) {
 	if (ata_scsi_offline_dev(dev)) {
 		dev->flags |= ATA_DFLAG_DETACHED;
 		dev->flags |= ATA_DFLAG_DETACHED;
-		ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+		ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
 	}
 	}
 
 
 	/* clear per-dev EH actions */
 	/* 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;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(ap->lock, flags);
 	spin_lock_irqsave(ap->lock, flags);
+
 	ata_eh_clear_action(dev, &ap->eh_info, action);
 	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);
 	spin_unlock_irqrestore(ap->lock, flags);
 }
 }
 
 
@@ -1027,7 +1037,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
 	int tag, rc;
 	int tag, rc;
 
 
 	/* if frozen, we can't do much */
 	/* if frozen, we can't do much */
-	if (ap->flags & ATA_FLAG_FROZEN)
+	if (ap->pflags & ATA_PFLAG_FROZEN)
 		return;
 		return;
 
 
 	/* is it NCQ device error? */
 	/* is it NCQ device error? */
@@ -1275,6 +1285,9 @@ static void ata_eh_autopsy(struct ata_port *ap)
 
 
 	DPRINTK("ENTER\n");
 	DPRINTK("ENTER\n");
 
 
+	if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
+		return;
+
 	/* obtain and analyze SError */
 	/* obtain and analyze SError */
 	rc = sata_scr_read(ap, SCR_ERROR, &serror);
 	rc = sata_scr_read(ap, SCR_ERROR, &serror);
 	if (rc == 0) {
 	if (rc == 0) {
@@ -1327,7 +1340,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
 	}
 	}
 
 
 	/* enforce default EH actions */
 	/* 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))
 	    all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
 		action |= ATA_EH_SOFTRESET;
 		action |= ATA_EH_SOFTRESET;
 	else if (all_err_mask)
 	else if (all_err_mask)
@@ -1346,7 +1359,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
 
 
 	/* record autopsy result */
 	/* record autopsy result */
 	ehc->i.dev = failed_dev;
 	ehc->i.dev = failed_dev;
-	ehc->i.action = action;
+	ehc->i.action |= action;
 
 
 	DPRINTK("EXIT\n");
 	DPRINTK("EXIT\n");
 }
 }
@@ -1385,7 +1398,7 @@ static void ata_eh_report(struct ata_port *ap)
 		return;
 		return;
 
 
 	frozen = "";
 	frozen = "";
-	if (ap->flags & ATA_FLAG_FROZEN)
+	if (ap->pflags & ATA_PFLAG_FROZEN)
 		frozen = " frozen";
 		frozen = " frozen";
 
 
 	if (ehc->i.dev) {
 	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;
 	struct ata_eh_context *ehc = &ap->eh_context;
 	unsigned int *classes = ehc->classes;
 	unsigned int *classes = ehc->classes;
 	int tries = ATA_EH_RESET_TRIES;
 	int tries = ATA_EH_RESET_TRIES;
-	int verbose = !(ap->flags & ATA_FLAG_LOADING);
+	int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
 	unsigned int action;
 	unsigned int action;
 	ata_reset_fn_t reset;
 	ata_reset_fn_t reset;
 	int i, did_followup_srst, rc;
 	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];
 		dev = &ap->device[i];
 		action = ata_eh_dev_action(dev);
 		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)) {
 			if (ata_port_offline(ap)) {
 				rc = -EIO;
 				rc = -EIO;
 				break;
 				break;
@@ -1636,7 +1649,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
 			}
 			}
 
 
 			spin_lock_irqsave(ap->lock, flags);
 			spin_lock_irqsave(ap->lock, flags);
-			ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+			ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
 			spin_unlock_irqrestore(ap->lock, flags);
 			spin_unlock_irqrestore(ap->lock, flags);
 		}
 		}
 	}
 	}
@@ -1648,6 +1661,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
 	return rc;
 	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)
 static int ata_port_nr_enabled(struct ata_port *ap)
 {
 {
 	int i, cnt = 0;
 	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;
 	struct ata_eh_context *ehc = &ap->eh_context;
 	int i;
 	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;
 		return 0;
 
 
 	/* skip if class codes for all vacant slots are ATA_DEV_NONE */
 	/* 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;
 	rc = 0;
 
 
 	/* if UNLOADING, finish immediately */
 	/* if UNLOADING, finish immediately */
-	if (ap->flags & ATA_FLAG_UNLOADING)
+	if (ap->pflags & ATA_PFLAG_UNLOADING)
 		goto out;
 		goto out;
 
 
+	/* prep for resume */
+	ata_eh_prep_resume(ap);
+
 	/* skip EH if possible. */
 	/* skip EH if possible. */
 	if (ata_eh_skip_recovery(ap))
 	if (ata_eh_skip_recovery(ap))
 		ehc->i.action = 0;
 		ehc->i.action = 0;
@@ -1774,6 +1960,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 	if (rc)
 	if (rc)
 		goto dev_fail;
 		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 */
 	/* configure transfer mode if the port has been reset */
 	if (ehc->i.flags & ATA_EHI_DID_RESET) {
 	if (ehc->i.flags & ATA_EHI_DID_RESET) {
 		rc = ata_set_mode(ap, &dev);
 		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;
 	goto out;
 
 
  dev_fail:
  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_reset_fn_t softreset, ata_reset_fn_t hardreset,
 	       ata_postreset_fn_t postreset)
 	       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_recover(ap, prereset, softreset, hardreset, postreset);
 	ata_eh_finish(ap);
 	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);
+}

+ 117 - 7
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_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_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;
 	struct ata_port *ap = data;
 	int i;
 	int i;
 
 
-	if (ap->flags & ATA_FLAG_UNLOADING) {
+	if (ap->pflags & ATA_PFLAG_UNLOADING) {
 		DPRINTK("ENTER/EXIT - unloading\n");
 		DPRINTK("ENTER/EXIT - unloading\n");
 		return;
 		return;
 	}
 	}
@@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
 		if (dev) {
 		if (dev) {
 			ap->eh_info.probe_mask |= 1 << dev->devno;
 			ap->eh_info.probe_mask |= 1 << dev->devno;
 			ap->eh_info.action |= ATA_EH_SOFTRESET;
 			ap->eh_info.action |= ATA_EH_SOFTRESET;
+			ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
 		} else
 		} else
 			rc = -EINVAL;
 			rc = -EINVAL;
 	}
 	}

+ 66 - 39
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_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 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 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);
 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,
 	.id_table		= sil_pci_tbl,
 	.probe			= sil_init_one,
 	.probe			= sil_init_one,
 	.remove			= ata_pci_remove_one,
 	.remove			= ata_pci_remove_one,
+	.suspend		= ata_pci_device_suspend,
+	.resume			= sil_pci_device_resume,
 };
 };
 
 
 static struct scsi_host_template sil_sht = {
 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_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 	.bios_param		= ata_std_bios_param,
+	.suspend		= ata_scsi_device_suspend,
+	.resume			= ata_scsi_device_resume,
 };
 };
 
 
 static const struct ata_port_operations sil_ops = {
 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
 		 * during hardreset makes controllers with broken SIEN
 		 * repeat probing needlessly.
 		 * repeat probing needlessly.
 		 */
 		 */
-		if (!(ap->flags & ATA_FLAG_FROZEN)) {
+		if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
 			ata_ehi_hotplugged(&ap->eh_info);
 			ata_ehi_hotplugged(&ap->eh_info);
 			ap->eh_info.serror |= serror;
 			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 sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 {
 	static int printed_version;
 	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;
 	int rc;
 	unsigned int i;
 	unsigned int i;
 	int pci_dev_busy = 0;
 	int pci_dev_busy = 0;
-	u32 tmp;
-	u8 cls;
 
 
 	if (!printed_version++)
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 		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]);
 		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);
 	pci_set_master(pdev);
 
 
@@ -685,6 +700,18 @@ err_out:
 	return rc;
 	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)
 static int __init sil_init(void)
 {
 {
 	return pci_module_init(&sil_pci_driver);
 	return pci_module_init(&sil_pci_driver);

+ 88 - 46
drivers/scsi/sata_sil24.c

@@ -92,6 +92,7 @@ enum {
 	HOST_CTRL_STOP		= (1 << 18), /* latched PCI STOP */
 	HOST_CTRL_STOP		= (1 << 18), /* latched PCI STOP */
 	HOST_CTRL_DEVSEL	= (1 << 19), /* latched PCI DEVSEL */
 	HOST_CTRL_DEVSEL	= (1 << 19), /* latched PCI DEVSEL */
 	HOST_CTRL_REQ64		= (1 << 20), /* latched PCI REQ64 */
 	HOST_CTRL_REQ64		= (1 << 20), /* latched PCI REQ64 */
+	HOST_CTRL_GLOBAL_RST	= (1 << 31), /* global reset */
 
 
 	/*
 	/*
 	 * Port registers
 	 * 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_port_stop(struct ata_port *ap);
 static void sil24_host_stop(struct ata_host_set *host_set);
 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_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[] = {
 static const struct pci_device_id sil24_pci_tbl[] = {
 	{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
 	{ 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,
 	.id_table		= sil24_pci_tbl,
 	.probe			= sil24_init_one,
 	.probe			= sil24_init_one,
 	.remove			= ata_pci_remove_one, /* safe? */
 	.remove			= ata_pci_remove_one, /* safe? */
+	.suspend		= ata_pci_device_suspend,
+	.resume			= sil24_pci_device_resume,
 };
 };
 
 
 static struct scsi_host_template sil24_sht = {
 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_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 	.bios_param		= ata_std_bios_param,
+	.suspend		= ata_scsi_device_suspend,
+	.resume			= ata_scsi_device_resume,
 };
 };
 
 
 static const struct ata_port_operations sil24_ops = {
 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
 	/* SStatus oscillates between zero and valid status after
 	 * DEV_RST, debounce it.
 	 * 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) {
 	if (rc) {
 		reason = "PHY debouncing failed";
 		reason = "PHY debouncing failed";
 		goto err;
 		goto err;
@@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set)
 	kfree(hpriv);
 	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 sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 {
 	static int printed_version = 0;
 	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 */
 	/* Apply workaround for completion IRQ loss on PCI-X errata */
 	if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
 	if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
 		tmp = readl(host_base + HOST_CTRL);
 		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;
 			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++) {
 	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].cmd_addr = portu;
 		probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
 		probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
 
 
 		ata_std_ports(&probe_ent->port[i]);
 		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);
 	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;
 	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)
 static int __init sil24_init(void)
 {
 {
 	return pci_module_init(&sil24_pci_driver);
 	return pci_module_init(&sil24_pci_driver);

+ 1 - 1
drivers/scsi/sata_vsc.c

@@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
 	.bmdma_status		= ata_bmdma_status,
 	.bmdma_status		= ata_bmdma_status,
 	.qc_prep		= ata_qc_prep,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 	.qc_issue		= ata_qc_issue_prot,
-	.data_xfer		= ata_pio_data_xfer,
+	.data_xfer		= ata_mmio_data_xfer,
 	.freeze			= ata_bmdma_freeze,
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= ata_bmdma_error_handler,
 	.error_handler		= ata_bmdma_error_handler,

+ 3 - 2
drivers/serial/at91_serial.c

@@ -41,6 +41,7 @@
 #include <asm/mach/serial_at91.h>
 #include <asm/mach/serial_at91.h>
 #include <asm/arch/board.h>
 #include <asm/arch/board.h>
 #include <asm/arch/system.h>
 #include <asm/arch/system.h>
+#include <asm/arch/gpio.h>
 
 
 #if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_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 (port->mapbase == AT91_BASE_US0) {
 			if (mctrl & TIOCM_RTS)
 			if (mctrl & TIOCM_RTS)
-				at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0);
+				at91_set_gpio_value(AT91_PIN_PA21, 0);
 			else
 			else
-				at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0);
+				at91_set_gpio_value(AT91_PIN_PA21, 1);
 		}
 		}
 	}
 	}
 
 

+ 17 - 9
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;
 	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;
 	int res = 0;
 	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
 	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
@@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl)
 		default:
 		default:
 			BUG();
 			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_host	*host = req->a_host;
 	struct nlm_res	*resp = &req->a_res;
 	struct nlm_res	*resp = &req->a_res;
 	struct nlm_wait *block = NULL;
 	struct nlm_wait *block = NULL;
+	unsigned char fl_flags = fl->fl_flags;
 	int status = -ENOLCK;
 	int status = -ENOLCK;
 
 
 	if (!host->h_monitored && nsm_monitor(host) < 0) {
 	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);
 					host->h_name);
 		goto out;
 		goto out;
 	}
 	}
+	fl->fl_flags |= FL_ACCESS;
+	status = do_vfs_lock(fl);
+	if (status < 0)
+		goto out;
 
 
 	block = nlmclnt_prepare_block(host, fl);
 	block = nlmclnt_prepare_block(host, fl);
 again:
 again:
@@ -539,9 +542,10 @@ again:
 			up_read(&host->h_rwsem);
 			up_read(&host->h_rwsem);
 			goto again;
 			goto again;
 		}
 		}
-		fl->fl_flags |= FL_SLEEP;
 		/* Ensure the resulting lock will get added to granted list */
 		/* 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);
 		up_read(&host->h_rwsem);
 	}
 	}
 	status = nlm_stat_to_errno(resp->status);
 	status = nlm_stat_to_errno(resp->status);
@@ -552,6 +556,7 @@ out_unblock:
 		nlmclnt_cancel(host, req->a_args.block, fl);
 		nlmclnt_cancel(host, req->a_args.block, fl);
 out:
 out:
 	nlm_release_call(req);
 	nlm_release_call(req);
+	fl->fl_flags = fl_flags;
 	return status;
 	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_host	*host = req->a_host;
 	struct nlm_res	*resp = &req->a_res;
 	struct nlm_res	*resp = &req->a_res;
-	int		status;
+	int status = 0;
 
 
 	/*
 	/*
 	 * Note: the server is supposed to either grant us the unlock
 	 * Note: the server is supposed to either grant us the unlock
 	 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
 	 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
 	 * case, we want to unlock.
 	 * case, we want to unlock.
 	 */
 	 */
+	fl->fl_flags |= FL_EXISTS;
 	down_read(&host->h_rwsem);
 	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);
 	up_read(&host->h_rwsem);
 
 
 	if (req->a_flags & RPC_TASK_ASYNC)
 	if (req->a_flags & RPC_TASK_ASYNC)
@@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
 	if (status < 0)
 	if (status < 0)
 		goto out;
 		goto out;
 
 
-	status = 0;
 	if (resp->status == NLM_LCK_GRANTED)
 	if (resp->status == NLM_LCK_GRANTED)
 		goto out;
 		goto out;
 
 

+ 21 - 2
fs/locks.c

@@ -725,6 +725,10 @@ next_task:
 /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
 /* 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
  * at the head of the list, but that's secret knowledge known only to
  * flock_lock_file and posix_lock_file.
  * 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)
 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;
 	int found = 0;
 
 
 	lock_kernel();
 	lock_kernel();
+	if (request->fl_flags & FL_ACCESS)
+		goto find_conflict;
 	for_each_lock(inode, before) {
 	for_each_lock(inode, before) {
 		struct file_lock *fl = *before;
 		struct file_lock *fl = *before;
 		if (IS_POSIX(fl))
 		if (IS_POSIX(fl))
@@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
 		break;
 		break;
 	}
 	}
 
 
-	if (request->fl_type == F_UNLCK)
+	if (request->fl_type == F_UNLCK) {
+		if ((request->fl_flags & FL_EXISTS) && !found)
+			error = -ENOENT;
 		goto out;
 		goto out;
+	}
 
 
 	error = -ENOMEM;
 	error = -ENOMEM;
 	new_fl = locks_alloc_lock();
 	new_fl = locks_alloc_lock();
@@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
 	if (found)
 	if (found)
 		cond_resched();
 		cond_resched();
 
 
+find_conflict:
 	for_each_lock(inode, before) {
 	for_each_lock(inode, before) {
 		struct file_lock *fl = *before;
 		struct file_lock *fl = *before;
 		if (IS_POSIX(fl))
 		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);
 			locks_insert_block(fl, request);
 		goto out;
 		goto out;
 	}
 	}
+	if (request->fl_flags & FL_ACCESS)
+		goto out;
 	locks_copy_lock(new_fl, request);
 	locks_copy_lock(new_fl, request);
 	locks_insert_lock(&inode->i_flock, new_fl);
 	locks_insert_lock(&inode->i_flock, new_fl);
 	new_fl = NULL;
 	new_fl = NULL;
@@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
 
 
 	error = 0;
 	error = 0;
 	if (!added) {
 	if (!added) {
-		if (request->fl_type == F_UNLCK)
+		if (request->fl_type == F_UNLCK) {
+			if (request->fl_flags & FL_EXISTS)
+				error = -ENOENT;
 			goto out;
 			goto out;
+		}
 
 
 		if (!new_fl) {
 		if (!new_fl) {
 			error = -ENOLCK;
 			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.
  * Add a POSIX style lock to a file.
  * We merge adjacent & overlapping locks whenever possible.
  * We merge adjacent & overlapping locks whenever possible.
  * POSIX locks are sorted by owner task, then by starting address
  * 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)
 int posix_lock_file(struct file *filp, struct file_lock *fl)
 {
 {

+ 3 - 1
fs/nfs/dir.c

@@ -690,7 +690,9 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
 			goto out_force;
 			goto out_force;
 		/* This is an open(2) */
 		/* This is an open(2) */
 		if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
 		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;
 			goto out_force;
 	}
 	}
 	return nfs_revalidate_inode(server, inode);
 	return nfs_revalidate_inode(server, inode);

+ 201 - 234
fs/nfs/direct.c

@@ -67,25 +67,19 @@ struct nfs_direct_req {
 	struct kref		kref;		/* release manager */
 	struct kref		kref;		/* release manager */
 
 
 	/* I/O parameters */
 	/* 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 nfs_open_context	*ctx;		/* file open context info */
 	struct kiocb *		iocb;		/* controlling i/o request */
 	struct kiocb *		iocb;		/* controlling i/o request */
 	struct inode *		inode;		/* target file of i/o */
 	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 */
 	/* completion state */
+	atomic_t		io_count;	/* i/os we're waiting for */
 	spinlock_t		lock;		/* protect completion state */
 	spinlock_t		lock;		/* protect completion state */
-	int			outstanding;	/* i/os we're waiting for */
 	ssize_t			count,		/* bytes actually processed */
 	ssize_t			count,		/* bytes actually processed */
 				error;		/* any reported error */
 				error;		/* any reported error */
 	struct completion	completion;	/* wait for i/o completion */
 	struct completion	completion;	/* wait for i/o completion */
 
 
 	/* commit state */
 	/* commit state */
+	struct list_head	rewrite_list;	/* saved nfs_write_data structs */
 	struct nfs_write_data *	commit_data;	/* special write_data for commits */
 	struct nfs_write_data *	commit_data;	/* special write_data for commits */
 	int			flags;
 	int			flags;
 #define NFS_ODIRECT_DO_COMMIT		(1)	/* an unstable reply was received */
 #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 */
 	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 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
  * 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;
 	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;
 	int i;
 	for (i = 0; i < npages; i++) {
 	for (i = 0; i < npages; i++) {
 		struct page *page = pages[i];
 		struct page *page = pages[i];
-		if (do_dirty && !PageCompound(page))
+		if (!PageCompound(page))
 			set_page_dirty_lock(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)
 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;
 		return NULL;
 
 
 	kref_init(&dreq->kref);
 	kref_init(&dreq->kref);
+	kref_get(&dreq->kref);
 	init_completion(&dreq->completion);
 	init_completion(&dreq->completion);
-	INIT_LIST_HEAD(&dreq->list);
 	INIT_LIST_HEAD(&dreq->rewrite_list);
 	INIT_LIST_HEAD(&dreq->rewrite_list);
 	dreq->iocb = NULL;
 	dreq->iocb = NULL;
 	dreq->ctx = NULL;
 	dreq->ctx = NULL;
 	spin_lock_init(&dreq->lock);
 	spin_lock_init(&dreq->lock);
-	dreq->outstanding = 0;
+	atomic_set(&dreq->io_count, 0);
 	dreq->count = 0;
 	dreq->count = 0;
 	dreq->error = 0;
 	dreq->error = 0;
 	dreq->flags = 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)
 static void nfs_direct_complete(struct nfs_direct_req *dreq)
 {
 {
-	nfs_free_user_pages(dreq->pages, dreq->npages, 1);
-
 	if (dreq->iocb) {
 	if (dreq->iocb) {
 		long res = (long) dreq->error;
 		long res = (long) dreq->error;
 		if (!res)
 		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)
 static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
 {
 {
 	struct nfs_read_data *data = 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)
 	if (nfs_readpage_result(task, data) != 0)
 		return;
 		return;
 
 
+	nfs_direct_dirty_pages(data->pagevec, data->npages);
+	nfs_direct_release_pages(data->pagevec, data->npages);
+
 	spin_lock(&dreq->lock);
 	spin_lock(&dreq->lock);
 
 
 	if (likely(task->tk_status >= 0))
 	if (likely(task->tk_status >= 0))
@@ -301,13 +253,10 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
 	else
 	else
 		dreq->error = task->tk_status;
 		dreq->error = task->tk_status;
 
 
-	if (--dreq->outstanding) {
-		spin_unlock(&dreq->lock);
-		return;
-	}
-
 	spin_unlock(&dreq->lock);
 	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 = {
 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 nfs_open_context *ctx = dreq->ctx;
 	struct inode *inode = ctx->dentry->d_inode;
 	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;
 	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 {
 	do {
 		struct nfs_read_data *data;
 		struct nfs_read_data *data;
 		size_t bytes;
 		size_t bytes;
 
 
+		result = -ENOMEM;
+		data = nfs_readdata_alloc(rpages);
+		if (unlikely(!data))
+			break;
+
 		bytes = rsize;
 		bytes = rsize;
 		if (count < rsize)
 		if (count < rsize)
 			bytes = count;
 			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->inode = inode;
 		data->cred = ctx->cred;
 		data->cred = ctx->cred;
 		data->args.fh = NFS_FH(inode);
 		data->args.fh = NFS_FH(inode);
 		data->args.context = ctx;
 		data->args.context = ctx;
 		data->args.offset = pos;
 		data->args.offset = pos;
 		data->args.pgbase = pgbase;
 		data->args.pgbase = pgbase;
-		data->args.pages = &pages[curpage];
+		data->args.pages = data->pagevec;
 		data->args.count = bytes;
 		data->args.count = bytes;
 		data->res.fattr = &data->fattr;
 		data->res.fattr = &data->fattr;
 		data->res.eof = 0;
 		data->res.eof = 0;
@@ -373,33 +341,35 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
 				bytes,
 				bytes,
 				(unsigned long long)data->args.offset);
 				(unsigned long long)data->args.offset);
 
 
+		started += bytes;
+		user_addr += bytes;
 		pos += bytes;
 		pos += bytes;
 		pgbase += bytes;
 		pgbase += bytes;
-		curpage += pgbase >> PAGE_SHIFT;
 		pgbase &= ~PAGE_MASK;
 		pgbase &= ~PAGE_MASK;
 
 
 		count -= bytes;
 		count -= bytes;
 	} while (count != 0);
 	} 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;
 	sigset_t oldset;
 	struct inode *inode = iocb->ki_filp->f_mapping->host;
 	struct inode *inode = iocb->ki_filp->f_mapping->host;
 	struct rpc_clnt *clnt = NFS_CLIENT(inode);
 	struct rpc_clnt *clnt = NFS_CLIENT(inode);
 	struct nfs_direct_req *dreq;
 	struct nfs_direct_req *dreq;
 
 
-	dreq = nfs_direct_read_alloc(count, NFS_SERVER(inode)->rsize);
+	dreq = nfs_direct_req_alloc();
 	if (!dreq)
 	if (!dreq)
 		return -ENOMEM;
 		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->inode = inode;
 	dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
 	dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
 	if (!is_sync_kiocb(iocb))
 	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);
 	nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
 	rpc_clnt_sigmask(clnt, &oldset);
 	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);
 	rpc_clnt_sigunmask(clnt, &oldset);
 
 
 	return result;
 	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)
 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);
 		list_del(&data->pages);
+		nfs_direct_release_pages(data->pagevec, data->npages);
 		nfs_writedata_release(data);
 		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)
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
 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;
 	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)
 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->cred = dreq->ctx->cred;
 
 
 	data->args.fh = NFS_FH(data->inode);
 	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.count = 0;
 	data->res.fattr = &data->fattr;
 	data->res.fattr = &data->fattr;
 	data->res.verf = &data->verf;
 	data->res.verf = &data->verf;
@@ -534,47 +542,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
 }
 }
 #endif
 #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)
 static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
 {
 {
 	struct nfs_write_data *data = 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);
 	spin_unlock(&dreq->lock);
 }
 }
@@ -619,14 +584,8 @@ static void nfs_direct_write_release(void *calldata)
 	struct nfs_write_data *data = calldata;
 	struct nfs_write_data *data = calldata;
 	struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req;
 	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 = {
 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 nfs_open_context *ctx = dreq->ctx;
 	struct inode *inode = ctx->dentry->d_inode;
 	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;
 	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 {
 	do {
 		struct nfs_write_data *data;
 		struct nfs_write_data *data;
 		size_t bytes;
 		size_t bytes;
 
 
+		result = -ENOMEM;
+		data = nfs_writedata_alloc(wpages);
+		if (unlikely(!data))
+			break;
+
 		bytes = wsize;
 		bytes = wsize;
 		if (count < wsize)
 		if (count < wsize)
 			bytes = count;
 			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);
 		list_move_tail(&data->pages, &dreq->rewrite_list);
 
 
+		data->req = (struct nfs_page *) dreq;
 		data->inode = inode;
 		data->inode = inode;
 		data->cred = ctx->cred;
 		data->cred = ctx->cred;
 		data->args.fh = NFS_FH(inode);
 		data->args.fh = NFS_FH(inode);
 		data->args.context = ctx;
 		data->args.context = ctx;
 		data->args.offset = pos;
 		data->args.offset = pos;
 		data->args.pgbase = pgbase;
 		data->args.pgbase = pgbase;
-		data->args.pages = &pages[curpage];
+		data->args.pages = data->pagevec;
 		data->args.count = bytes;
 		data->args.count = bytes;
 		data->res.fattr = &data->fattr;
 		data->res.fattr = &data->fattr;
 		data->res.count = bytes;
 		data->res.count = bytes;
@@ -693,19 +673,26 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
 				bytes,
 				bytes,
 				(unsigned long long)data->args.offset);
 				(unsigned long long)data->args.offset);
 
 
+		started += bytes;
+		user_addr += bytes;
 		pos += bytes;
 		pos += bytes;
 		pgbase += bytes;
 		pgbase += bytes;
-		curpage += pgbase >> PAGE_SHIFT;
 		pgbase &= ~PAGE_MASK;
 		pgbase &= ~PAGE_MASK;
 
 
 		count -= bytes;
 		count -= bytes;
 	} while (count != 0);
 	} 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;
 	sigset_t oldset;
 	struct inode *inode = iocb->ki_filp->f_mapping->host;
 	struct inode *inode = iocb->ki_filp->f_mapping->host;
 	struct rpc_clnt *clnt = NFS_CLIENT(inode);
 	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;
 	size_t wsize = NFS_SERVER(inode)->wsize;
 	int sync = 0;
 	int sync = 0;
 
 
-	dreq = nfs_direct_write_alloc(count, wsize);
+	dreq = nfs_direct_req_alloc();
 	if (!dreq)
 	if (!dreq)
 		return -ENOMEM;
 		return -ENOMEM;
+	nfs_alloc_commit_data(dreq);
+
 	if (dreq->commit_data == NULL || count < wsize)
 	if (dreq->commit_data == NULL || count < wsize)
 		sync = FLUSH_STABLE;
 		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->inode = inode;
 	dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
 	dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
 	if (!is_sync_kiocb(iocb))
 	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);
 	nfs_begin_data_update(inode);
 
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	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);
 	rpc_clnt_sigunmask(clnt, &oldset);
 
 
 	return result;
 	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 nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
 {
 {
 	ssize_t retval = -EINVAL;
 	ssize_t retval = -EINVAL;
-	int page_count;
-	struct page **pages;
 	struct file *file = iocb->ki_filp;
 	struct file *file = iocb->ki_filp;
 	struct address_space *mapping = file->f_mapping;
 	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)
 	if (retval)
 		goto out;
 		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)
 	if (retval > 0)
 		iocb->ki_pos = pos + retval;
 		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 nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
 {
 {
 	ssize_t retval;
 	ssize_t retval;
-	int page_count;
-	struct page **pages;
 	struct file *file = iocb->ki_filp;
 	struct file *file = iocb->ki_filp;
 	struct address_space *mapping = file->f_mapping;
 	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)
 	if (retval)
 		goto out;
 		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
 	 * XXX: nfs_end_data_update() already ensures this file's

+ 41 - 33
fs/nfs/nfs4proc.c

@@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
 		default:
 		default:
 			BUG();
 			BUG();
 	}
 	}
-	if (res < 0)
-		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
-				__FUNCTION__);
 	return res;
 	return res;
 }
 }
 
 
@@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
 		return ERR_PTR(-ENOMEM);
 		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);
 	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;
 	struct rpc_task *task;
 	int status = 0;
 	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);
 	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)
 	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;
 	lsp = request->fl_u.nfs4_fl.owner;
-	status = -ENOMEM;
 	seqid = nfs_alloc_seqid(&lsp->ls_seqid);
 	seqid = nfs_alloc_seqid(&lsp->ls_seqid);
+	status = -ENOMEM;
 	if (seqid == NULL)
 	if (seqid == NULL)
-		goto out_unlock;
+		goto out;
 	task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
 	task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
 	status = PTR_ERR(task);
 	status = PTR_ERR(task);
 	if (IS_ERR(task))
 	if (IS_ERR(task))
-		goto out_unlock;
+		goto out;
 	status = nfs4_wait_for_completion_rpc_task(task);
 	status = nfs4_wait_for_completion_rpc_task(task);
 	rpc_release_task(task);
 	rpc_release_task(task);
-	return status;
-out_unlock:
-	do_vfs_lock(request->fl_file, request);
+out:
 	return status;
 	return status;
 }
 }
 
 
@@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
 	struct nfs4_exception exception = { };
 	struct nfs4_exception exception = { };
 	int err;
 	int err;
 
 
-	/* Cache the lock if possible... */
-	if (test_bit(NFS_DELEGATED_STATE, &state->flags))
-		return 0;
 	do {
 	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);
 		err = _nfs4_do_setlk(state, F_SETLK, request, 1);
 		if (err != -NFS4ERR_DELAY)
 		if (err != -NFS4ERR_DELAY)
 			break;
 			break;
@@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
 	if (err != 0)
 	if (err != 0)
 		return err;
 		return err;
 	do {
 	do {
+		if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
+			return 0;
 		err = _nfs4_do_setlk(state, F_SETLK, request, 0);
 		err = _nfs4_do_setlk(state, F_SETLK, request, 0);
 		if (err != -NFS4ERR_DELAY)
 		if (err != -NFS4ERR_DELAY)
 			break;
 			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)
 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
 {
 	struct nfs4_client *clp = state->owner->so_client;
 	struct nfs4_client *clp = state->owner->so_client;
+	unsigned char fl_flags = request->fl_flags;
 	int status;
 	int status;
 
 
 	/* Is this a delegated open? */
 	/* 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);
 	status = nfs4_set_lock_state(state, request);
 	if (status != 0)
 	if (status != 0)
 		goto out;
 		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);
 	status = _nfs4_do_setlk(state, cmd, request, 0);
 	if (status != 0)
 	if (status != 0)
-		goto out;
+		goto out_unlock;
 	/* Note: we always want to sleep here! */
 	/* 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)
 	if (do_vfs_lock(request->fl_file, request) < 0)
 		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
 		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
-out:
+out_unlock:
 	up_read(&clp->cl_sem);
 	up_read(&clp->cl_sem);
+out:
+	request->fl_flags = fl_flags;
 	return status;
 	return status;
 }
 }
 
 

+ 17 - 3
fs/nfs/write.c

@@ -578,7 +578,7 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
 	return ret;
 	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;
 	struct nfs_page *req;
 	while(!list_empty(head)) {
 	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
  * nfs_scan_dirty - Scan an inode for dirty requests
  * @inode: NFS inode to scan
  * @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_list_remove_request(req);
 		nfs_mark_request_commit(req);
 		nfs_mark_request_commit(req);
 		nfs_clear_page_writeback(req);
 		nfs_clear_page_writeback(req);
+		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 	}
 	}
 	return -ENOMEM;
 	return -ENOMEM;
 }
 }
@@ -1499,7 +1513,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
 		if (pages != 0) {
 		if (pages != 0) {
 			spin_unlock(&nfsi->req_lock);
 			spin_unlock(&nfsi->req_lock);
 			if (how & FLUSH_INVALIDATE)
 			if (how & FLUSH_INVALIDATE)
-				nfs_cancel_requests(&head);
+				nfs_cancel_dirty_list(&head);
 			else
 			else
 				ret = nfs_flush_list(inode, &head, pages, how);
 				ret = nfs_flush_list(inode, &head, pages, how);
 			spin_lock(&nfsi->req_lock);
 			spin_lock(&nfsi->req_lock);
@@ -1512,7 +1526,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
 			break;
 			break;
 		if (how & FLUSH_INVALIDATE) {
 		if (how & FLUSH_INVALIDATE) {
 			spin_unlock(&nfsi->req_lock);
 			spin_unlock(&nfsi->req_lock);
-			nfs_cancel_requests(&head);
+			nfs_cancel_commit_list(&head);
 			spin_lock(&nfsi->req_lock);
 			spin_lock(&nfsi->req_lock);
 			continue;
 			continue;
 		}
 		}

+ 0 - 8
include/asm-arm/arch-at91rm9200/irqs.h

@@ -39,12 +39,4 @@
  */
  */
 #define	NR_IRQS		(NR_AIC_IRQS + (4 * 32))
 #define	NR_IRQS		(NR_AIC_IRQS + (4 * 32))
 
 
-
-#ifndef __ASSEMBLY__
-/*
- * Initialize the IRQ controller.
- */
-extern void at91rm9200_init_irq(unsigned int priority[]);
-#endif
-
 #endif
 #endif

+ 18 - 0
include/asm-powerpc/cputime.h

@@ -43,6 +43,7 @@ typedef u64 cputime64_t;
 
 
 #define cputime64_zero			((cputime64_t)0)
 #define cputime64_zero			((cputime64_t)0)
 #define cputime64_add(__a, __b)		((__a) + (__b))
 #define cputime64_add(__a, __b)		((__a) + (__b))
+#define cputime64_sub(__a, __b)		((__a) - (__b))
 #define cputime_to_cputime64(__ct)	(__ct)
 #define cputime_to_cputime64(__ct)	(__ct)
 
 
 #ifdef __KERNEL__
 #ifdef __KERNEL__
@@ -74,6 +75,23 @@ static inline cputime_t jiffies_to_cputime(const unsigned long jif)
 	return ct;
 	return ct;
 }
 }
 
 
+static inline cputime64_t jiffies64_to_cputime64(const u64 jif)
+{
+	cputime_t ct;
+	u64 sec;
+
+	/* have to be a little careful about overflow */
+	ct = jif % HZ;
+	sec = jif / HZ;
+	if (ct) {
+		ct *= tb_ticks_per_sec;
+		do_div(ct, HZ);
+	}
+	if (sec)
+		ct += (cputime_t) sec * tb_ticks_per_sec;
+	return ct;
+}
+
 static inline u64 cputime64_to_jiffies64(const cputime_t ct)
 static inline u64 cputime64_to_jiffies64(const cputime_t ct)
 {
 {
 	return mulhdu(ct, __cputime_jiffies_factor);
 	return mulhdu(ct, __cputime_jiffies_factor);

+ 14 - 0
include/asm-sparc64/dma-mapping.h

@@ -160,6 +160,20 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
 	BUG();
 	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 */
 #endif /* PCI */
 
 
 
 

+ 1 - 0
include/linux/fs.h

@@ -716,6 +716,7 @@ extern spinlock_t files_lock;
 #define FL_POSIX	1
 #define FL_POSIX	1
 #define FL_FLOCK	2
 #define FL_FLOCK	2
 #define FL_ACCESS	8	/* not trying to lock, just looking */
 #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_LEASE	32	/* lease held on this file */
 #define FL_CLOSE	64	/* unlock on close */
 #define FL_CLOSE	64	/* unlock on close */
 #define FL_SLEEP	128	/* A blocking lock */
 #define FL_SLEEP	128	/* A blocking lock */

+ 64 - 21
include/linux/libata.h

@@ -131,6 +131,7 @@ enum {
 	ATA_DFLAG_CFG_MASK	= (1 << 8) - 1,
 	ATA_DFLAG_CFG_MASK	= (1 << 8) - 1,
 
 
 	ATA_DFLAG_PIO		= (1 << 8), /* device currently in PIO mode */
 	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_INIT_MASK	= (1 << 16) - 1,
 
 
 	ATA_DFLAG_DETACH	= (1 << 16),
 	ATA_DFLAG_DETACH	= (1 << 16),
@@ -160,22 +161,28 @@ enum {
 	ATA_FLAG_HRST_TO_RESUME	= (1 << 11), /* hardreset to resume phy */
 	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
 	ATA_FLAG_SKIP_D2H_BSY	= (1 << 12), /* can't wait for the first D2H
 					      * Register FIS clearing BSY */
 					      * Register FIS clearing BSY */
-
 	ATA_FLAG_DEBUGMSG	= (1 << 13),
 	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 */
 	/* struct ata_queued_cmd flags */
 	ATA_QCFLAG_ACTIVE	= (1 << 0), /* cmd not yet ack'd to scsi lyer */
 	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_REVALIDATE	= (1 << 0),
 	ATA_EH_SOFTRESET	= (1 << 1),
 	ATA_EH_SOFTRESET	= (1 << 1),
 	ATA_EH_HARDRESET	= (1 << 2),
 	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_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_eh_info->flags */
 	ATA_EHI_HOTPLUGGED	= (1 << 0),  /* could have been hotplugged */
 	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 */
 	ATA_EHI_DID_RESET	= (1 << 16), /* already reset this port */
 
 
@@ -486,6 +500,7 @@ struct ata_port {
 	const struct ata_port_operations *ops;
 	const struct ata_port_operations *ops;
 	spinlock_t		*lock;
 	spinlock_t		*lock;
 	unsigned long		flags;	/* ATA_FLAG_xxx */
 	unsigned long		flags;	/* ATA_FLAG_xxx */
+	unsigned int		pflags; /* ATA_PFLAG_xxx */
 	unsigned int		id;	/* unique id req'd by scsi midlyr */
 	unsigned int		id;	/* unique id req'd by scsi midlyr */
 	unsigned int		port_no; /* unique port #; from zero */
 	unsigned int		port_no; /* unique port #; from zero */
 	unsigned int		hard_port_no;	/* hardware 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;
 	struct list_head	eh_done_q;
 	wait_queue_head_t	eh_wait_q;
 	wait_queue_head_t	eh_wait_q;
 
 
+	pm_message_t		pm_mesg;
+	int			*pm_result;
+
 	void			*private_data;
 	void			*private_data;
 
 
 	u8			sector_buf[ATA_SECT_SIZE]; /* owned by EH */
 	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,
 	void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
 			   u32 val);
 			   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);
 	int (*port_start) (struct ata_port *ap);
 	void (*port_stop) (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)
 #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 ata_port_probe(struct ata_port *);
 extern void __sata_phy_reset(struct ata_port *ap);
 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,
 extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
 			     unsigned int n_ports);
 			     unsigned int n_ports);
 extern void ata_pci_remove_one (struct pci_dev *pdev);
 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_suspend(struct pci_dev *pdev, pm_message_t state);
 extern int ata_pci_device_resume(struct pci_dev *pdev);
 extern int ata_pci_device_resume(struct pci_dev *pdev);
 extern int ata_pci_clear_simplex(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_port_offline(struct ata_port *ap);
 extern int ata_scsi_device_resume(struct scsi_device *);
 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_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 int ata_ratelimit(void);
 extern unsigned int ata_busy_sleep(struct ata_port *ap,
 extern unsigned int ata_busy_sleep(struct ata_port *ap,
 				   unsigned long timeout_pat,
 				   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; \
 	(ehi)->desc_len = 0; \
 } while (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)
 	if (ehi->flags & ATA_EHI_HOTPLUGGED)
 		return;
 		return;
 
 
-	ehi->flags |= ATA_EHI_HOTPLUGGED;
+	ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
 	ehi->hotplug_timestamp = jiffies;
 	ehi->hotplug_timestamp = jiffies;
 
 
-	ehi->err_mask |= AC_ERR_ATA_BUS;
 	ehi->action |= ATA_EH_SOFTRESET;
 	ehi->action |= ATA_EH_SOFTRESET;
 	ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
 	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
  * qc helpers
  */
  */
@@ -921,6 +959,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
 	return ata_class_absent(dev->class);
 	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
  * port helpers
  */
  */

+ 2 - 0
include/linux/nfs_xdr.h

@@ -729,6 +729,7 @@ struct nfs_read_data {
 	struct list_head	pages;	/* Coalesced read requests */
 	struct list_head	pages;	/* Coalesced read requests */
 	struct nfs_page		*req;	/* multi ops per nfs_page */
 	struct nfs_page		*req;	/* multi ops per nfs_page */
 	struct page		**pagevec;
 	struct page		**pagevec;
+	unsigned int		npages;	/* active pages in pagevec */
 	struct nfs_readargs args;
 	struct nfs_readargs args;
 	struct nfs_readres  res;
 	struct nfs_readres  res;
 #ifdef CONFIG_NFS_V4
 #ifdef CONFIG_NFS_V4
@@ -747,6 +748,7 @@ struct nfs_write_data {
 	struct list_head	pages;		/* Coalesced requests we wish to flush */
 	struct list_head	pages;		/* Coalesced requests we wish to flush */
 	struct nfs_page		*req;		/* multi ops per nfs_page */
 	struct nfs_page		*req;		/* multi ops per nfs_page */
 	struct page		**pagevec;
 	struct page		**pagevec;
+	unsigned int		npages;		/* active pages in pagevec */
 	struct nfs_writeargs	args;		/* argument struct */
 	struct nfs_writeargs	args;		/* argument struct */
 	struct nfs_writeres	res;		/* result struct */
 	struct nfs_writeres	res;		/* result struct */
 #ifdef CONFIG_NFS_V4
 #ifdef CONFIG_NFS_V4

+ 7 - 0
include/linux/pci_ids.h

@@ -2019,6 +2019,13 @@
 #define PCI_VENDOR_ID_TDI               0x192E
 #define PCI_VENDOR_ID_TDI               0x192E
 #define PCI_DEVICE_ID_TDI_EHCI          0x0101
 #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_VENDOR_ID_TEKRAM		0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
 #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29

+ 1 - 0
include/net/ieee80211softmac.h

@@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info {
 	 */
 	 */
 	u8 static_essid:1,
 	u8 static_essid:1,
 	   associating:1,
 	   associating:1,
+	   assoc_wait:1,
 	   bssvalid:1,
 	   bssvalid:1,
 	   bssfixed:1;
 	   bssfixed:1;
 
 

+ 3 - 1
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
 	/* Put this code here so that we avoid duplicating it in all
 	 * Rx paths. - Jean II */
 	 * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
 #ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
 #ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
 	/* If spy monitoring on */
 	/* If spy monitoring on */
 	if (ieee->spy_data.spy_number > 0) {
 	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);
 		wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
 	}
 	}
 #endif				/* IW_WIRELESS_SPY */
 #endif				/* IW_WIRELESS_SPY */
+#endif				/* CONFIG_WIRELESS_EXT */
 
 
 #ifdef NOT_YET
 #ifdef NOT_YET
 	hostap_update_rx_stats(local->ap, hdr, rx_stats);
 	hostap_update_rx_stats(local->ap, hdr, rx_stats);
 #endif
 #endif
 
 
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
-		ieee80211_monitor_rx(ieee, skb, rx_stats);
 		stats->rx_packets++;
 		stats->rx_packets++;
 		stats->rx_bytes += skb->len;
 		stats->rx_bytes += skb->len;
+		ieee80211_monitor_rx(ieee, skb, rx_stats);
 		return 1;
 		return 1;
 	}
 	}
 
 

+ 11 - 4
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 net_device_stats *stats = &ieee->stats;
 	struct sk_buff *skb_frag;
 	struct sk_buff *skb_frag;
 	int priority = -1;
 	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);
 	spin_lock_irqsave(&ieee->lock, flags);
 
 
-	if (encrypt_mpdu && !ieee->sec.encrypt)
+	if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
 		encrypt_mpdu = 0;
 		encrypt_mpdu = 0;
 
 
 	/* If there is no driver handler to take the TXB, dont' bother
 	/* 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;
 		goto success;
 	}
 	}
 
 
-	if (encrypt_mpdu)
+	if (encrypt_mpdu) {
 		frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 		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
 	/* When we allocate the TXB we allocate enough space for the reserve
 	 * and full fragment bytes (bytes_per_frag doesn't include prefix,
 	 * and full fragment bytes (bytes_per_frag doesn't include prefix,
 	 * postfix, header, FCS, etc.) */
 	 * 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)) {
 	if (unlikely(!txb)) {
 		printk(KERN_WARNING "%s: Could not allocate TXB\n",
 		printk(KERN_WARNING "%s: Could not allocate TXB\n",
 		       ieee->dev->name);
 		       ieee->dev->name);
 		goto failed;
 		goto failed;
 	}
 	}
 	txb->encrypted = 0;
 	txb->encrypted = 0;
-	txb->payload_size = total_len;
+	txb->payload_size = fraglen;
 
 
 	skb_frag = txb->fragments[0];
 	skb_frag = txb->fragments[0];
 
 

+ 24 - 7
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");
 	dprintk(KERN_INFO PFX "sent association request!\n");
 
 
-	/* Change the state to associating */
 	spin_lock_irqsave(&mac->lock, flags);
 	spin_lock_irqsave(&mac->lock, flags);
-	mac->associnfo.associating = 1;
 	mac->associated = 0; /* just to make sure */
 	mac->associated = 0; /* just to make sure */
 
 
 	/* Set a timer for timeout */
 	/* Set a timer for timeout */
@@ -63,6 +61,7 @@ void
 ieee80211softmac_assoc_timeout(void *d)
 ieee80211softmac_assoc_timeout(void *d)
 {
 {
 	struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
 	struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
+	struct ieee80211softmac_network *n;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&mac->lock, flags);
 	spin_lock_irqsave(&mac->lock, flags);
@@ -75,11 +74,12 @@ ieee80211softmac_assoc_timeout(void *d)
 	mac->associnfo.associating = 0;
 	mac->associnfo.associating = 0;
 	mac->associnfo.bssvalid = 0;
 	mac->associnfo.bssvalid = 0;
 	mac->associated = 0;
 	mac->associated = 0;
+
+	n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
 	spin_unlock_irqrestore(&mac->lock, flags);
 	spin_unlock_irqrestore(&mac->lock, flags);
 
 
 	dprintk(KERN_INFO PFX "assoc request timed out!\n");
 	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
 void
@@ -203,6 +203,10 @@ ieee80211softmac_assoc_work(void *d)
 	if (mac->associated)
 	if (mac->associated)
 		ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
 		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 */
 	/* try to find the requested network in our list, if we found one already */
 	if (bssvalid || mac->associnfo.bssfixed)
 	if (bssvalid || mac->associnfo.bssfixed)
 		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);	
 		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);
 	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. */
 	/* 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,
 		/* This relies on the fact that _auth_req only queues the work,
 		 * otherwise adding the notification would be racy. */
 		 * otherwise adding the notification would be racy. */
 		if (!ieee80211softmac_auth_req(mac, found)) {
 		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 {
 		} else {
 			printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
 			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);
 			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
 		}
 		}
 		return;
 		return;
 	}
 	}
 	/* finally! now we can start associating */
 	/* finally! now we can start associating */
+	mac->associnfo.assoc_wait = 0;
 	ieee80211softmac_assoc(mac, found);
 	ieee80211softmac_assoc(mac, found);
 }
 }
 
 

+ 2 - 2
net/ieee80211/softmac/ieee80211softmac_auth.c

@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
 	struct ieee80211softmac_auth_queue_item *auth;
 	struct ieee80211softmac_auth_queue_item *auth;
 	unsigned long flags;
 	unsigned long flags;
 	
 	
-	if (net->authenticating)
+	if (net->authenticating || net->authenticated)
 		return 0;
 		return 0;
+	net->authenticating = 1;
 
 
 	/* Add the network if it's not already added */
 	/* Add the network if it's not already added */
 	ieee80211softmac_add_network(mac, net);
 	ieee80211softmac_add_network(mac, net);
@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
 			return;
 			return;
 		}
 		}
 		net->authenticated = 0;
 		net->authenticated = 0;
-		net->authenticating = 1;
 		/* add a timeout call so we eventually give up waiting for an auth reply */
 		/* add a timeout call so we eventually give up waiting for an auth reply */
 		schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
 		schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
 		auth->retry--;
 		auth->retry--;

+ 3 - 0
net/ieee80211/softmac/ieee80211softmac_io.c

@@ -229,6 +229,9 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
 		return 0;
 		return 0;
 	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
 	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 (?) */
 	/* Fill in Listen Interval (?) */
 	(*pkt)->listen_interval = cpu_to_le16(10);
 	(*pkt)->listen_interval = cpu_to_le16(10);
 	
 	

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff