Browse Source

Merge branch 'master'

Jeff Garzik 19 years ago
parent
commit
ea19006f58
100 changed files with 15213 additions and 1066 deletions
  1. 36 0
      Documentation/networking/bcm43xx.txt
  2. 1 0
      arch/i386/kernel/syscall_table.S
  3. 1 0
      arch/ia64/kernel/entry.S
  4. 1 0
      arch/ia64/kernel/gate.lds.S
  5. 162 103
      arch/ia64/kernel/iosapic.c
  6. 9 9
      arch/ia64/kernel/vmlinux.lds.S
  7. 7 1
      arch/ia64/mm/init.c
  8. 3 3
      arch/ia64/mm/ioremap.c
  9. 7 5
      arch/ia64/mm/tlb.c
  10. 6 2
      arch/ia64/sn/kernel/sn2/sn_hwperf.c
  11. 1 5
      arch/parisc/Kconfig
  12. 74 86
      arch/parisc/configs/712_defconfig
  13. 2 2
      arch/parisc/configs/a500_defconfig
  14. 6 6
      arch/parisc/configs/b180_defconfig
  15. 108 144
      arch/parisc/configs/c3000_defconfig
  16. 110 55
      arch/parisc/defconfig
  17. 3 3
      arch/parisc/kernel/cache.c
  18. 39 6
      arch/parisc/kernel/entry.S
  19. 2 2
      arch/parisc/kernel/pacache.S
  20. 0 19
      arch/parisc/kernel/parisc_ksyms.c
  21. 2 3
      arch/parisc/kernel/pdc_chassis.c
  22. 1 1
      arch/parisc/kernel/perf.c
  23. 1 1
      arch/parisc/kernel/syscall_table.S
  24. 0 4
      arch/parisc/lib/iomap.c
  25. 3 4
      arch/parisc/mm/init.c
  26. 9 45
      arch/parisc/mm/ioremap.c
  27. 7 9
      drivers/char/drm/drmP.h
  28. 11 9
      drivers/char/drm/drm_bufs.c
  29. 1 3
      drivers/char/drm/drm_dma.c
  30. 0 59
      drivers/char/drm/drm_memory.c
  31. 0 70
      drivers/char/drm/drm_memory_debug.h
  32. 25 4
      drivers/char/drm/drm_pci.c
  33. 79 37
      drivers/char/drm/drm_pciids.h
  34. 0 2
      drivers/char/drm/i915_dma.c
  35. 2 0
      drivers/char/drm/i915_irq.c
  36. 78 8
      drivers/char/drm/r300_cmdbuf.c
  37. 32 7
      drivers/char/drm/r300_reg.h
  38. 108 43
      drivers/char/drm/radeon_cp.c
  39. 5 0
      drivers/char/drm/radeon_drm.h
  40. 17 8
      drivers/char/drm/radeon_drv.h
  41. 47 58
      drivers/char/drm/radeon_state.c
  42. 1 1
      drivers/char/drm/sis_mm.c
  43. 101 11
      drivers/infiniband/core/mad.c
  44. 2 1
      drivers/infiniband/core/mad_priv.h
  45. 17 37
      drivers/infiniband/core/mad_rmpp.c
  46. 6 24
      drivers/infiniband/core/user_mad.c
  47. 1 1
      drivers/infiniband/hw/mthca/mthca_av.c
  48. 1 1
      drivers/infiniband/hw/mthca/mthca_cq.c
  49. 3 3
      drivers/infiniband/hw/mthca/mthca_eq.c
  50. 1 1
      drivers/infiniband/hw/mthca/mthca_mad.c
  51. 1 1
      drivers/infiniband/hw/mthca/mthca_mcg.c
  52. 2 2
      drivers/infiniband/hw/mthca/mthca_mr.c
  53. 1 1
      drivers/infiniband/hw/mthca/mthca_pd.c
  54. 1 1
      drivers/infiniband/hw/mthca/mthca_qp.c
  55. 2 2
      drivers/infiniband/hw/mthca/mthca_srq.c
  56. 1 1
      drivers/infiniband/ulp/ipoib/ipoib_main.c
  57. 2 2
      drivers/infiniband/ulp/srp/ib_srp.c
  58. 30 26
      drivers/input/keyboard/hil_kbd.c
  59. 29 24
      drivers/input/keyboard/hilkbd.c
  60. 47 43
      drivers/input/mouse/hil_ptr.c
  61. 2 2
      drivers/input/serio/gscps2.c
  62. 1 1
      drivers/net/8390.h
  63. 5 5
      drivers/net/acenic_firmware.h
  64. 14 0
      drivers/net/b44.c
  65. 28 0
      drivers/net/bonding/bond_3ad.c
  66. 1 0
      drivers/net/bonding/bond_3ad.h
  67. 71 26
      drivers/net/bonding/bond_main.c
  68. 2 2
      drivers/net/bonding/bonding.h
  69. 1 4
      drivers/net/ixp2000/ixpdev.c
  70. 14 4
      drivers/net/natsemi.c
  71. 53 8
      drivers/net/pcmcia/axnet_cs.c
  72. 2 2
      drivers/net/pcnet32.c
  73. 2 2
      drivers/net/spider_net.c
  74. 21 0
      drivers/net/via-rhine.c
  75. 6 1
      drivers/net/wireless/Kconfig
  76. 1 0
      drivers/net/wireless/Makefile
  77. 62 0
      drivers/net/wireless/bcm43xx/Kconfig
  78. 12 0
      drivers/net/wireless/bcm43xx/Makefile
  79. 926 0
      drivers/net/wireless/bcm43xx/bcm43xx.h
  80. 499 0
      drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
  81. 117 0
      drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
  82. 968 0
      drivers/net/wireless/bcm43xx/bcm43xx_dma.c
  83. 218 0
      drivers/net/wireless/bcm43xx/bcm43xx_dma.h
  84. 50 0
      drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
  85. 8 0
      drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
  86. 337 0
      drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
  87. 32 0
      drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
  88. 293 0
      drivers/net/wireless/bcm43xx/bcm43xx_leds.c
  89. 56 0
      drivers/net/wireless/bcm43xx/bcm43xx_leds.h
  90. 3973 0
      drivers/net/wireless/bcm43xx/bcm43xx_main.c
  91. 168 0
      drivers/net/wireless/bcm43xx/bcm43xx_main.h
  92. 2345 0
      drivers/net/wireless/bcm43xx/bcm43xx_phy.c
  93. 74 0
      drivers/net/wireless/bcm43xx/bcm43xx_phy.h
  94. 606 0
      drivers/net/wireless/bcm43xx/bcm43xx_pio.c
  95. 138 0
      drivers/net/wireless/bcm43xx/bcm43xx_pio.h
  96. 358 0
      drivers/net/wireless/bcm43xx/bcm43xx_power.c
  97. 47 0
      drivers/net/wireless/bcm43xx/bcm43xx_power.h
  98. 2026 0
      drivers/net/wireless/bcm43xx/bcm43xx_radio.c
  99. 99 0
      drivers/net/wireless/bcm43xx/bcm43xx_radio.h
  100. 322 0
      drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c

+ 36 - 0
Documentation/networking/bcm43xx.txt

@@ -0,0 +1,36 @@
+
+			BCM43xx Linux Driver Project
+			============================
+
+About this software
+-------------------
+
+The goal of this project is to develop a linux driver for Broadcom
+BCM43xx chips, based on the specification at 
+http://bcm-specs.sipsolutions.net/
+
+The project page is http://bcm43xx.berlios.de/
+
+
+Requirements
+------------
+
+1)	Linux Kernel 2.6.16 or later
+	http://www.kernel.org/
+
+	You may want to configure your kernel with:
+
+	CONFIG_DEBUG_FS (optional):
+		-> Kernel hacking
+		  -> Debug Filesystem
+
+2)	SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
+	modules:
+	http://softmac.sipsolutions.net/
+
+3)	Firmware Files
+
+	Please try fwcutter. Fwcutter can extract the firmware from various 
+	binary driver files. It supports driver files from Windows, MacOS and 
+	Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
+	Also, fwcutter comes with a README file for further instructions.

+ 1 - 0
arch/i386/kernel/syscall_table.S

@@ -312,3 +312,4 @@ ENTRY(sys_call_table)
 	.long sys_unshare		/* 310 */
 	.long sys_unshare		/* 310 */
 	.long sys_set_robust_list
 	.long sys_set_robust_list
 	.long sys_get_robust_list
 	.long sys_get_robust_list
+	.long sys_splice

+ 1 - 0
arch/ia64/kernel/entry.S

@@ -1605,5 +1605,6 @@ sys_call_table:
 	data8 sys_ni_syscall			// reserved for pselect
 	data8 sys_ni_syscall			// reserved for pselect
 	data8 sys_ni_syscall			// 1295 reserved for ppoll
 	data8 sys_ni_syscall			// 1295 reserved for ppoll
 	data8 sys_unshare
 	data8 sys_unshare
+	data8 sys_splice
 
 
 	.org sys_call_table + 8*NR_syscalls	// guard against failures to increase NR_syscalls
 	.org sys_call_table + 8*NR_syscalls	// guard against failures to increase NR_syscalls

+ 1 - 0
arch/ia64/kernel/gate.lds.S

@@ -59,6 +59,7 @@ SECTIONS
 	*(.dynbss)
 	*(.dynbss)
 	*(.bss .bss.* .gnu.linkonce.b.*)
 	*(.bss .bss.* .gnu.linkonce.b.*)
 	*(__ex_table)
 	*(__ex_table)
+	*(__mca_table)
   }
   }
 }
 }
 
 

+ 162 - 103
arch/ia64/kernel/iosapic.c

@@ -9,54 +9,65 @@
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
  *
  *
- * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O APIC code.
- *				In particular, we now have separate handlers for edge
- *				and level triggered interrupts.
- * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation
- *				PCI to vector mapping, shared PCI interrupts.
- * 00/10/27	D. Mosberger	Document things a bit more to make them more understandable.
- *				Clean up much of the old IOSAPIC cruft.
- * 01/07/27	J.I. Lee	PCI irq routing, Platform/Legacy interrupts and fixes for
- *				ACPI S5(SoftOff) support.
+ * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O
+ *				APIC code.  In particular, we now have separate
+ *				handlers for edge and level triggered
+ *				interrupts.
+ * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector
+ *				allocation PCI to vector mapping, shared PCI
+ *				interrupts.
+ * 00/10/27	D. Mosberger	Document things a bit more to make them more
+ *				understandable.  Clean up much of the old
+ *				IOSAPIC cruft.
+ * 01/07/27	J.I. Lee	PCI irq routing, Platform/Legacy interrupts
+ *				and fixes for ACPI S5(SoftOff) support.
  * 02/01/23	J.I. Lee	iosapic pgm fixes for PCI irq routing from _PRT
  * 02/01/23	J.I. Lee	iosapic pgm fixes for PCI irq routing from _PRT
- * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt vectors in
- *                              iosapic_set_affinity(), initializations for
- *                              /proc/irq/#/smp_affinity
+ * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt
+ *				vectors in iosapic_set_affinity(),
+ *				initializations for /proc/irq/#/smp_affinity
  * 02/04/02	P. Diefenbaugh	Cleaned up ACPI PCI IRQ routing.
  * 02/04/02	P. Diefenbaugh	Cleaned up ACPI PCI IRQ routing.
  * 02/04/18	J.I. Lee	bug fix in iosapic_init_pci_irq
  * 02/04/18	J.I. Lee	bug fix in iosapic_init_pci_irq
- * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
- *				error
+ * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to
+ *				IOSAPIC mapping error
  * 02/07/29	T. Kochi	Allocate interrupt vectors dynamically
  * 02/07/29	T. Kochi	Allocate interrupt vectors dynamically
- * 02/08/04	T. Kochi	Cleaned up terminology (irq, global system interrupt, vector, etc.)
- * 02/09/20	D. Mosberger	Simplified by taking advantage of ACPI's pci_irq code.
+ * 02/08/04	T. Kochi	Cleaned up terminology (irq, global system
+ *				interrupt, vector, etc.)
+ * 02/09/20	D. Mosberger	Simplified by taking advantage of ACPI's
+ *				pci_irq code.
  * 03/02/19	B. Helgaas	Make pcat_compat system-wide, not per-IOSAPIC.
  * 03/02/19	B. Helgaas	Make pcat_compat system-wide, not per-IOSAPIC.
- *				Remove iosapic_address & gsi_base from external interfaces.
- *				Rationalize __init/__devinit attributes.
+ *				Remove iosapic_address & gsi_base from
+ *				external interfaces.  Rationalize
+ *				__init/__devinit attributes.
  * 04/12/04 Ashok Raj	<ashok.raj@intel.com> Intel Corporation 2004
  * 04/12/04 Ashok Raj	<ashok.raj@intel.com> Intel Corporation 2004
- *				Updated to work with irq migration necessary for CPU Hotplug
+ *				Updated to work with irq migration necessary
+ *				for CPU Hotplug
  */
  */
 /*
 /*
- * Here is what the interrupt logic between a PCI device and the kernel looks like:
+ * Here is what the interrupt logic between a PCI device and the kernel looks
+ * like:
  *
  *
- * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
- *     device is uniquely identified by its bus--, and slot-number (the function
- *     number does not matter here because all functions share the same interrupt
- *     lines).
+ * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC,
+ *     INTD).  The device is uniquely identified by its bus-, and slot-number
+ *     (the function number does not matter here because all functions share
+ *     the same interrupt lines).
  *
  *
- * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller.
- *     Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level
- *     triggered and use the same polarity).  Each interrupt line has a unique Global
- *     System Interrupt (GSI) number which can be calculated as the sum of the controller's
- *     base GSI number and the IOSAPIC pin number to which the line connects.
+ * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC
+ *     controller.  Multiple interrupt lines may have to share the same
+ *     IOSAPIC pin (if they're level triggered and use the same polarity).
+ *     Each interrupt line has a unique Global System Interrupt (GSI) number
+ *     which can be calculated as the sum of the controller's base GSI number
+ *     and the IOSAPIC pin number to which the line connects.
  *
  *
- * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin
- *     into the IA-64 interrupt vector.  This interrupt vector is then sent to the CPU.
+ * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the
+ * IOSAPIC pin into the IA-64 interrupt vector.  This interrupt vector is then
+ * sent to the CPU.
  *
  *
- * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface is used as
- *     architecture-independent interrupt handling mechanism in Linux.  As an
- *     IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number
- *     mapping.  On smaller systems, we use one-to-one mapping between IA-64 vector and
- *     IRQ.  A platform can implement platform_irq_to_vector(irq) and
+ * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface is
+ *     used as architecture-independent interrupt handling mechanism in Linux.
+ *     As an IRQ is a number, we have to have
+ *     IA-64 interrupt vector number <-> IRQ number mapping.  On smaller
+ *     systems, we use one-to-one mapping between IA-64 vector and IRQ.  A
+ *     platform can implement platform_irq_to_vector(irq) and
  *     platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
  *     platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
  *     Please see also include/asm-ia64/hw_irq.h for those APIs.
  *     Please see also include/asm-ia64/hw_irq.h for those APIs.
  *
  *
@@ -64,9 +75,9 @@
  *
  *
  *	PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
  *	PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
  *
  *
- * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts.
- * Now we use "IRQ" only for Linux IRQ's.  ISA IRQ (isa_irq) is the only exception in this
- * source code.
+ * Note: The term "IRQ" is loosely used everywhere in Linux kernel to
+ * describeinterrupts.  Now we use "IRQ" only for Linux IRQ's.  ISA IRQ
+ * (isa_irq) is the only exception in this source code.
  */
  */
 #include <linux/config.h>
 #include <linux/config.h>
 
 
@@ -90,7 +101,6 @@
 #include <asm/ptrace.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/system.h>
 
 
-
 #undef DEBUG_INTERRUPT_ROUTING
 #undef DEBUG_INTERRUPT_ROUTING
 
 
 #ifdef DEBUG_INTERRUPT_ROUTING
 #ifdef DEBUG_INTERRUPT_ROUTING
@@ -99,36 +109,46 @@
 #define DBG(fmt...)
 #define DBG(fmt...)
 #endif
 #endif
 
 
-#define NR_PREALLOCATE_RTE_ENTRIES	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
+#define NR_PREALLOCATE_RTE_ENTRIES \
+	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
 #define RTE_PREALLOCATED	(1)
 #define RTE_PREALLOCATED	(1)
 
 
 static DEFINE_SPINLOCK(iosapic_lock);
 static DEFINE_SPINLOCK(iosapic_lock);
 
 
-/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
+/*
+ * These tables map IA-64 vectors to the IOSAPIC pin that generates this
+ * vector.
+ */
 
 
 struct iosapic_rte_info {
 struct iosapic_rte_info {
-	struct list_head rte_list;	/* node in list of RTEs sharing the same vector */
+	struct list_head rte_list;	/* node in list of RTEs sharing the
+					 * same vector */
 	char __iomem	*addr;		/* base address of IOSAPIC */
 	char __iomem	*addr;		/* base address of IOSAPIC */
-	unsigned int	gsi_base;	/* first GSI assigned to this IOSAPIC */
+	unsigned int	gsi_base;	/* first GSI assigned to this
+					 * IOSAPIC */
 	char		rte_index;	/* IOSAPIC RTE index */
 	char		rte_index;	/* IOSAPIC RTE index */
 	int		refcnt;		/* reference counter */
 	int		refcnt;		/* reference counter */
 	unsigned int	flags;		/* flags */
 	unsigned int	flags;		/* flags */
 } ____cacheline_aligned;
 } ____cacheline_aligned;
 
 
 static struct iosapic_intr_info {
 static struct iosapic_intr_info {
-	struct list_head rtes;		/* RTEs using this vector (empty => not an IOSAPIC interrupt) */
+	struct list_head rtes;		/* RTEs using this vector (empty =>
+					 * not an IOSAPIC interrupt) */
 	int		count;		/* # of RTEs that shares this vector */
 	int		count;		/* # of RTEs that shares this vector */
-	u32		low32;		/* current value of low word of Redirection table entry */
+	u32		low32;		/* current value of low word of
+					 * Redirection table entry */
 	unsigned int	dest;		/* destination CPU physical ID */
 	unsigned int	dest;		/* destination CPU physical ID */
 	unsigned char	dmode	: 3;	/* delivery mode (see iosapic.h) */
 	unsigned char	dmode	: 3;	/* delivery mode (see iosapic.h) */
-	unsigned char 	polarity: 1;	/* interrupt polarity (see iosapic.h) */
+	unsigned char 	polarity: 1;	/* interrupt polarity
+					 * (see iosapic.h) */
 	unsigned char	trigger	: 1;	/* trigger mode (see iosapic.h) */
 	unsigned char	trigger	: 1;	/* trigger mode (see iosapic.h) */
 } iosapic_intr_info[IA64_NUM_VECTORS];
 } iosapic_intr_info[IA64_NUM_VECTORS];
 
 
 static struct iosapic {
 static struct iosapic {
 	char __iomem	*addr;		/* base address of IOSAPIC */
 	char __iomem	*addr;		/* base address of IOSAPIC */
-	unsigned int 	gsi_base;	/* first GSI assigned to this IOSAPIC */
-	unsigned short 	num_rte;	/* number of RTE in this IOSAPIC */
+	unsigned int 	gsi_base;	/* first GSI assigned to this
+					 * IOSAPIC */
+	unsigned short 	num_rte;	/* # of RTEs on this IOSAPIC */
 	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */
 	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */
 #ifdef CONFIG_NUMA
 #ifdef CONFIG_NUMA
 	unsigned short	node;		/* numa node association via pxm */
 	unsigned short	node;		/* numa node association via pxm */
@@ -149,7 +169,8 @@ find_iosapic (unsigned int gsi)
 	int i;
 	int i;
 
 
 	for (i = 0; i < NR_IOSAPICS; i++) {
 	for (i = 0; i < NR_IOSAPICS; i++) {
-		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
+		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) <
+		    iosapic_lists[i].num_rte)
 			return i;
 			return i;
 	}
 	}
 
 
@@ -162,7 +183,8 @@ _gsi_to_vector (unsigned int gsi)
 	struct iosapic_intr_info *info;
 	struct iosapic_intr_info *info;
 	struct iosapic_rte_info *rte;
 	struct iosapic_rte_info *rte;
 
 
-	for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
+	for (info = iosapic_intr_info; info <
+		     iosapic_intr_info + IA64_NUM_VECTORS; ++info)
 		list_for_each_entry(rte, &info->rtes, rte_list)
 		list_for_each_entry(rte, &info->rtes, rte_list)
 			if (rte->gsi_base + rte->rte_index == gsi)
 			if (rte->gsi_base + rte->rte_index == gsi)
 				return info - iosapic_intr_info;
 				return info - iosapic_intr_info;
@@ -185,8 +207,8 @@ gsi_to_irq (unsigned int gsi)
 	unsigned long flags;
 	unsigned long flags;
 	int irq;
 	int irq;
 	/*
 	/*
-	 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
-	 * numbers...
+	 * XXX fix me: this assumes an identity mapping between IA-64 vector
+	 * and Linux irq numbers...
 	 */
 	 */
 	spin_lock_irqsave(&iosapic_lock, flags);
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
 	{
@@ -197,7 +219,8 @@ gsi_to_irq (unsigned int gsi)
 	return irq;
 	return irq;
 }
 }
 
 
-static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
+static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi,
+						  unsigned int vec)
 {
 {
 	struct iosapic_rte_info *rte;
 	struct iosapic_rte_info *rte;
 
 
@@ -237,7 +260,9 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
 
 
 		for (irq = 0; irq < NR_IRQS; ++irq)
 		for (irq = 0; irq < NR_IRQS; ++irq)
 			if (irq_to_vector(irq) == vector) {
 			if (irq_to_vector(irq) == vector) {
-				set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
+				set_irq_affinity_info(irq,
+						      (int)(dest & 0xffff),
+						      redir);
 				break;
 				break;
 			}
 			}
 	}
 	}
@@ -259,7 +284,7 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
 }
 }
 
 
 static void
 static void
-nop (unsigned int vector)
+nop (unsigned int irq)
 {
 {
 	/* do nothing... */
 	/* do nothing... */
 }
 }
@@ -281,7 +306,8 @@ mask_irq (unsigned int irq)
 	{
 	{
 		/* set only the mask bit */
 		/* set only the mask bit */
 		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
 		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
-		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
+				    rte_list) {
 			addr = rte->addr;
 			addr = rte->addr;
 			rte_index = rte->rte_index;
 			rte_index = rte->rte_index;
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
@@ -306,7 +332,8 @@ unmask_irq (unsigned int irq)
 	spin_lock_irqsave(&iosapic_lock, flags);
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
 	{
 		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
 		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
-		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
+				    rte_list) {
 			addr = rte->addr;
 			addr = rte->addr;
 			rte_index = rte->rte_index;
 			rte_index = rte->rte_index;
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
@@ -346,21 +373,25 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
 
 
 	spin_lock_irqsave(&iosapic_lock, flags);
 	spin_lock_irqsave(&iosapic_lock, flags);
 	{
 	{
-		low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+		low32 = iosapic_intr_info[vec].low32 &
+			~(7 << IOSAPIC_DELIVERY_SHIFT);
 
 
 		if (redir)
 		if (redir)
 		        /* change delivery mode to lowest priority */
 		        /* change delivery mode to lowest priority */
-			low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+			low32 |= (IOSAPIC_LOWEST_PRIORITY <<
+				  IOSAPIC_DELIVERY_SHIFT);
 		else
 		else
 		        /* change delivery mode to fixed */
 		        /* change delivery mode to fixed */
 			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
 			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
 
 
 		iosapic_intr_info[vec].low32 = low32;
 		iosapic_intr_info[vec].low32 = low32;
 		iosapic_intr_info[vec].dest = dest;
 		iosapic_intr_info[vec].dest = dest;
-		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
+		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
+				    rte_list) {
 			addr = rte->addr;
 			addr = rte->addr;
 			rte_index = rte->rte_index;
 			rte_index = rte->rte_index;
-			iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
+			iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index),
+				      high32);
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 		}
 		}
 	}
 	}
@@ -433,7 +464,8 @@ iosapic_ack_edge_irq (unsigned int irq)
 	 * interrupt for real. This prevents IRQ storms from unhandled
 	 * interrupt for real. This prevents IRQ storms from unhandled
 	 * devices.
 	 * devices.
 	 */
 	 */
-	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
+	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) ==
+	    (IRQ_PENDING|IRQ_DISABLED))
 		mask_irq(irq);
 		mask_irq(irq);
 }
 }
 
 
@@ -467,7 +499,8 @@ iosapic_version (char __iomem *addr)
 	return iosapic_read(addr, IOSAPIC_VERSION);
 	return iosapic_read(addr, IOSAPIC_VERSION);
 }
 }
 
 
-static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
+static int iosapic_find_sharable_vector (unsigned long trigger,
+					 unsigned long pol)
 {
 {
 	int i, vector = -1, min_count = -1;
 	int i, vector = -1, min_count = -1;
 	struct iosapic_intr_info *info;
 	struct iosapic_intr_info *info;
@@ -482,7 +515,8 @@ static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long po
 	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
 	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
 		info = &iosapic_intr_info[i];
 		info = &iosapic_intr_info[i];
 		if (info->trigger == trigger && info->polarity == pol &&
 		if (info->trigger == trigger && info->polarity == pol &&
-		    (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {
+		    (info->dmode == IOSAPIC_FIXED || info->dmode ==
+		     IOSAPIC_LOWEST_PRIORITY)) {
 			if (min_count == -1 || info->count < min_count) {
 			if (min_count == -1 || info->count < min_count) {
 				vector = i;
 				vector = i;
 				min_count = info->count;
 				min_count = info->count;
@@ -506,12 +540,15 @@ iosapic_reassign_vector (int vector)
 		new_vector = assign_irq_vector(AUTO_ASSIGN);
 		new_vector = assign_irq_vector(AUTO_ASSIGN);
 		if (new_vector < 0)
 		if (new_vector < 0)
 			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
 			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
-		printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
+		printk(KERN_INFO "Reassigning vector %d to %d\n",
+		       vector, new_vector);
 		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
 		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
 		       sizeof(struct iosapic_intr_info));
 		       sizeof(struct iosapic_intr_info));
 		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
 		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
-		list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);
-		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
+		list_move(iosapic_intr_info[vector].rtes.next,
+			  &iosapic_intr_info[new_vector].rtes);
+		memset(&iosapic_intr_info[vector], 0,
+		       sizeof(struct iosapic_intr_info));
 		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
 		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
 		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
 		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
 	}
 	}
@@ -524,7 +561,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void)
 	int preallocated = 0;
 	int preallocated = 0;
 
 
 	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
 	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
-		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
+		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
+				    NR_PREALLOCATE_RTE_ENTRIES);
 		if (!rte)
 		if (!rte)
 			return NULL;
 			return NULL;
 		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
 		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
@@ -532,7 +570,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void)
 	}
 	}
 
 
 	if (!list_empty(&free_rte_list)) {
 	if (!list_empty(&free_rte_list)) {
-		rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
+		rte = list_entry(free_rte_list.next, struct iosapic_rte_info,
+				 rte_list);
 		list_del(&rte->rte_list);
 		list_del(&rte->rte_list);
 		preallocated++;
 		preallocated++;
 	} else {
 	} else {
@@ -575,7 +614,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
 
 
 	index = find_iosapic(gsi);
 	index = find_iosapic(gsi);
 	if (index < 0) {
 	if (index < 0) {
-		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
+		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",
+		       __FUNCTION__, gsi);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -586,7 +626,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
 	if (!rte) {
 	if (!rte) {
 		rte = iosapic_alloc_rte();
 		rte = iosapic_alloc_rte();
 		if (!rte) {
 		if (!rte) {
-			printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
+			printk(KERN_WARNING "%s: cannot allocate memory\n",
+			       __FUNCTION__);
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
 
 
@@ -602,7 +643,9 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
 	else if (vector_is_shared(vector)) {
 	else if (vector_is_shared(vector)) {
 		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
 		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
 		if (info->trigger != trigger || info->polarity != polarity) {
 		if (info->trigger != trigger || info->polarity != polarity) {
-			printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
+			printk (KERN_WARNING
+				"%s: cannot override the interrupt\n",
+				__FUNCTION__);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 	}
 	}
@@ -619,8 +662,10 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
 	idesc = irq_descp(vector);
 	idesc = irq_descp(vector);
 	if (idesc->handler != irq_type) {
 	if (idesc->handler != irq_type) {
 		if (idesc->handler != &no_irq_type)
 		if (idesc->handler != &no_irq_type)
-			printk(KERN_WARNING "%s: changing vector %d from %s to %s\n",
-			       __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);
+			printk(KERN_WARNING
+			       "%s: changing vector %d from %s to %s\n",
+			       __FUNCTION__, vector,
+			       idesc->handler->typename, irq_type->typename);
 		idesc->handler = irq_type;
 		idesc->handler = irq_type;
 	}
 	}
 	return 0;
 	return 0;
@@ -681,7 +726,7 @@ get_target_cpu (unsigned int gsi, int vector)
 		if (!num_cpus)
 		if (!num_cpus)
 			goto skip_numa_setup;
 			goto skip_numa_setup;
 
 
-		/* Use vector assigment to distribute across cpus in node */
+		/* Use vector assignment to distribute across cpus in node */
 		cpu_index = vector % num_cpus;
 		cpu_index = vector % num_cpus;
 
 
 		for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
 		for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
@@ -703,7 +748,7 @@ skip_numa_setup:
 	} while (!cpu_online(cpu));
 	} while (!cpu_online(cpu));
 
 
 	return cpu_physical_id(cpu);
 	return cpu_physical_id(cpu);
-#else
+#else  /* CONFIG_SMP */
 	return cpu_physical_id(smp_processor_id());
 	return cpu_physical_id(smp_processor_id());
 #endif
 #endif
 }
 }
@@ -755,7 +800,8 @@ again:
 			if (list_empty(&iosapic_intr_info[vector].rtes))
 			if (list_empty(&iosapic_intr_info[vector].rtes))
 				free_irq_vector(vector);
 				free_irq_vector(vector);
 			spin_unlock(&iosapic_lock);
 			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+			spin_unlock_irqrestore(&irq_descp(vector)->lock,
+					       flags);
 			goto again;
 			goto again;
 		}
 		}
 
 
@@ -764,7 +810,8 @@ again:
 			      polarity, trigger);
 			      polarity, trigger);
 		if (err < 0) {
 		if (err < 0) {
 			spin_unlock(&iosapic_lock);
 			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+			spin_unlock_irqrestore(&irq_descp(vector)->lock,
+					       flags);
 			return err;
 			return err;
 		}
 		}
 
 
@@ -806,7 +853,8 @@ iosapic_unregister_intr (unsigned int gsi)
 	 */
 	 */
 	irq = gsi_to_irq(gsi);
 	irq = gsi_to_irq(gsi);
 	if (irq < 0) {
 	if (irq < 0) {
-		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
+		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
+		       gsi);
 		WARN_ON(1);
 		WARN_ON(1);
 		return;
 		return;
 	}
 	}
@@ -817,7 +865,9 @@ iosapic_unregister_intr (unsigned int gsi)
 	spin_lock(&iosapic_lock);
 	spin_lock(&iosapic_lock);
 	{
 	{
 		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
 		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
-			printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
+			printk(KERN_ERR
+			       "iosapic_unregister_intr(%u) unbalanced\n",
+			       gsi);
 			WARN_ON(1);
 			WARN_ON(1);
 			goto out;
 			goto out;
 		}
 		}
@@ -827,7 +877,8 @@ iosapic_unregister_intr (unsigned int gsi)
 
 
 		/* Mask the interrupt */
 		/* Mask the interrupt */
 		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
 		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
-		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
+		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
+			      low32);
 
 
 		/* Remove the rte entry from the list */
 		/* Remove the rte entry from the list */
 		list_del(&rte->rte_list);
 		list_del(&rte->rte_list);
@@ -840,7 +891,9 @@ iosapic_unregister_intr (unsigned int gsi)
 		trigger	 = iosapic_intr_info[vector].trigger;
 		trigger	 = iosapic_intr_info[vector].trigger;
 		polarity = iosapic_intr_info[vector].polarity;
 		polarity = iosapic_intr_info[vector].polarity;
 		dest     = iosapic_intr_info[vector].dest;
 		dest     = iosapic_intr_info[vector].dest;
-		printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
+		printk(KERN_INFO
+		       "GSI %u (%s, %s) -> CPU %d (0x%04x)"
+		       " vector %d unregistered\n",
 		       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
 		       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
 		       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
 		       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
 		       cpu_logical_id(dest), dest, vector);
 		       cpu_logical_id(dest), dest, vector);
@@ -853,12 +906,15 @@ iosapic_unregister_intr (unsigned int gsi)
 			idesc->handler = &no_irq_type;
 			idesc->handler = &no_irq_type;
 
 
 			/* Clear the interrupt information */
 			/* Clear the interrupt information */
-			memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
+			memset(&iosapic_intr_info[vector], 0,
+			       sizeof(struct iosapic_intr_info));
 			iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
 			iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
 			INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
 			INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
 
 
 			if (idesc->action) {
 			if (idesc->action) {
-				printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq);
+				printk(KERN_ERR
+				       "interrupt handlers still exist on"
+				       "IRQ %u\n", irq);
 				WARN_ON(1);
 				WARN_ON(1);
 			}
 			}
 
 
@@ -873,7 +929,6 @@ iosapic_unregister_intr (unsigned int gsi)
 
 
 /*
 /*
  * ACPI calls this when it finds an entry for a platform interrupt.
  * ACPI calls this when it finds an entry for a platform interrupt.
- * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
  */
  */
 int __init
 int __init
 iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
@@ -907,13 +962,16 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 		mask = 1;
 		mask = 1;
 		break;
 		break;
 	      default:
 	      default:
-		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
+		printk(KERN_ERR "%s: invalid int type 0x%x\n", __FUNCTION__,
+		       int_type);
 		return -1;
 		return -1;
 	}
 	}
 
 
 	register_intr(gsi, vector, delivery, polarity, trigger);
 	register_intr(gsi, vector, delivery, polarity, trigger);
 
 
-	printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+	printk(KERN_INFO
+	       "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"
+	       " vector %d\n",
 	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
 	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
 	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
 	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
@@ -923,10 +981,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 	return vector;
 	return vector;
 }
 }
 
 
-
 /*
 /*
  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
- * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
  */
  */
 void __init
 void __init
 iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
 iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
@@ -955,16 +1011,19 @@ iosapic_system_init (int system_pcat_compat)
 
 
 	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
 	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
 		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
 		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
-		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);	/* mark as unused */
+		/* mark as unused */
+		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
 	}
 	}
 
 
 	pcat_compat = system_pcat_compat;
 	pcat_compat = system_pcat_compat;
 	if (pcat_compat) {
 	if (pcat_compat) {
 		/*
 		/*
-		 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
-		 * enabled.
+		 * Disable the compatibility mode interrupts (8259 style),
+		 * needs IN/OUT support enabled.
 		 */
 		 */
-		printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
+		printk(KERN_INFO
+		       "%s: Disabling PC-AT compatible 8259 interrupts\n",
+		       __FUNCTION__);
 		outb(0xff, 0xA1);
 		outb(0xff, 0xA1);
 		outb(0xff, 0x21);
 		outb(0xff, 0x21);
 	}
 	}
@@ -1004,10 +1063,7 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
 		base = iosapic_lists[index].gsi_base;
 		base = iosapic_lists[index].gsi_base;
 		end  = base + iosapic_lists[index].num_rte - 1;
 		end  = base + iosapic_lists[index].num_rte - 1;
 
 
-		if (gsi_base < base && gsi_end < base)
-			continue;/* OK */
-
-		if (gsi_base > end && gsi_end > end)
+		if (gsi_end < base || end < gsi_base)
 			continue; /* OK */
 			continue; /* OK */
 
 
 		return -EBUSY;
 		return -EBUSY;
@@ -1053,12 +1109,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
 
 
 	if ((gsi_base == 0) && pcat_compat) {
 	if ((gsi_base == 0) && pcat_compat) {
 		/*
 		/*
-		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
-		 * get reprogrammed later on with data from the ACPI Interrupt Source
-		 * Override table.
+		 * Map the legacy ISA devices into the IOSAPIC data.  Some of
+		 * these may get reprogrammed later on with data from the ACPI
+		 * Interrupt Source Override table.
 		 */
 		 */
 		for (isa_irq = 0; isa_irq < 16; ++isa_irq)
 		for (isa_irq = 0; isa_irq < 16; ++isa_irq)
-			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
+			iosapic_override_isa_irq(isa_irq, isa_irq,
+						 IOSAPIC_POL_HIGH,
+						 IOSAPIC_EDGE);
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -1081,7 +1139,8 @@ iosapic_remove (unsigned int gsi_base)
 
 
 		if (iosapic_lists[index].rtes_inuse) {
 		if (iosapic_lists[index].rtes_inuse) {
 			err = -EBUSY;
 			err = -EBUSY;
-			printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+			printk(KERN_WARNING
+			       "%s: IOSAPIC for GSI base %u is busy\n",
 			       __FUNCTION__, gsi_base);
 			       __FUNCTION__, gsi_base);
 			goto out;
 			goto out;
 		}
 		}

+ 9 - 9
arch/ia64/kernel/vmlinux.lds.S

@@ -70,6 +70,15 @@ SECTIONS
 	  __stop___ex_table = .;
 	  __stop___ex_table = .;
 	}
 	}
 
 
+  /* MCA table */
+  . = ALIGN(16);
+  __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
+	{
+	  __start___mca_table = .;
+	  *(__mca_table)
+	  __stop___mca_table = .;
+	}
+
   /* Global data */
   /* Global data */
   _data = .;
   _data = .;
 
 
@@ -130,15 +139,6 @@ SECTIONS
 	  __initcall_end = .;
 	  __initcall_end = .;
 	}
 	}
 
 
-  /* MCA table */
-  . = ALIGN(16);
-  __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
-	{
-	  __start___mca_table = .;
-	  *(__mca_table)
-	  __stop___mca_table = .;
-	}
-
   .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET)
   .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET)
 	{
 	{
 	  __start___vtop_patchlist = .;
 	  __start___vtop_patchlist = .;

+ 7 - 1
arch/ia64/mm/init.c

@@ -109,6 +109,7 @@ lazy_mmu_prot_update (pte_t pte)
 {
 {
 	unsigned long addr;
 	unsigned long addr;
 	struct page *page;
 	struct page *page;
+	unsigned long order;
 
 
 	if (!pte_exec(pte))
 	if (!pte_exec(pte))
 		return;				/* not an executable page... */
 		return;				/* not an executable page... */
@@ -119,7 +120,12 @@ lazy_mmu_prot_update (pte_t pte)
 	if (test_bit(PG_arch_1, &page->flags))
 	if (test_bit(PG_arch_1, &page->flags))
 		return;				/* i-cache is already coherent with d-cache */
 		return;				/* i-cache is already coherent with d-cache */
 
 
-	flush_icache_range(addr, addr + PAGE_SIZE);
+	if (PageCompound(page)) {
+		order = (unsigned long) (page[1].lru.prev);
+		flush_icache_range(addr, addr + (1UL << order << PAGE_SHIFT));
+	}
+	else
+		flush_icache_range(addr, addr + PAGE_SIZE);
 	set_bit(PG_arch_1, &page->flags);	/* mark page as clean */
 	set_bit(PG_arch_1, &page->flags);	/* mark page as clean */
 }
 }
 
 

+ 3 - 3
arch/ia64/mm/ioremap.c

@@ -21,12 +21,12 @@ __ioremap (unsigned long offset, unsigned long size)
 void __iomem *
 void __iomem *
 ioremap (unsigned long offset, unsigned long size)
 ioremap (unsigned long offset, unsigned long size)
 {
 {
-	if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC))
-		return __ioremap(offset, size);
-
 	if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB))
 	if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB))
 		return phys_to_virt(offset);
 		return phys_to_virt(offset);
 
 
+	if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC))
+		return __ioremap(offset, size);
+
 	/*
 	/*
 	 * Someday this should check ACPI resources so we
 	 * Someday this should check ACPI resources so we
 	 * can do the right thing for hot-plugged regions.
 	 * can do the right thing for hot-plugged regions.

+ 7 - 5
arch/ia64/mm/tlb.c

@@ -156,17 +156,19 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start,
 		nbits = purge.max_bits;
 		nbits = purge.max_bits;
 	start &= ~((1UL << nbits) - 1);
 	start &= ~((1UL << nbits) - 1);
 
 
-# ifdef CONFIG_SMP
-	platform_global_tlb_purge(mm, start, end, nbits);
-# else
 	preempt_disable();
 	preempt_disable();
+#ifdef CONFIG_SMP
+	if (mm != current->active_mm || cpus_weight(mm->cpu_vm_mask) != 1) {
+		platform_global_tlb_purge(mm, start, end, nbits);
+		preempt_enable();
+		return;
+	}
+#endif
 	do {
 	do {
 		ia64_ptcl(start, (nbits<<2));
 		ia64_ptcl(start, (nbits<<2));
 		start += (1UL << nbits);
 		start += (1UL << nbits);
 	} while (start < end);
 	} while (start < end);
 	preempt_enable();
 	preempt_enable();
-# endif
-
 	ia64_srlz_i();			/* srlz.i implies srlz.d */
 	ia64_srlz_i();			/* srlz.i implies srlz.d */
 }
 }
 EXPORT_SYMBOL(flush_tlb_range);
 EXPORT_SYMBOL(flush_tlb_range);

+ 6 - 2
arch/ia64/sn/kernel/sn2/sn_hwperf.c

@@ -110,7 +110,11 @@ static int sn_hwperf_geoid_to_cnode(char *location)
 	if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
 	if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
 		return -1;
 		return -1;
 
 
-	for_each_node(cnode) {
+	/*
+	 * FIXME: replace with cleaner for_each_XXX macro which addresses
+	 * both compute and IO nodes once ACPI3.0 is available.
+	 */
+	for (cnode = 0; cnode < num_cnodes; cnode++) {
 		geoid = cnodeid_get_geoid(cnode);
 		geoid = cnodeid_get_geoid(cnode);
 		module_id = geo_module(geoid);
 		module_id = geo_module(geoid);
 		this_rack = MODULE_GET_RACK(module_id);
 		this_rack = MODULE_GET_RACK(module_id);
@@ -605,7 +609,7 @@ static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info)
 	op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
 	op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
 
 
 	if (cpu != SN_HWPERF_ARG_ANY_CPU) {
 	if (cpu != SN_HWPERF_ARG_ANY_CPU) {
-		if (cpu >= num_online_cpus() || !cpu_online(cpu)) {
+		if (cpu >= NR_CPUS || !cpu_online(cpu)) {
 			r = -EINVAL;
 			r = -EINVAL;
 			goto out;
 			goto out;
 		}
 		}

+ 1 - 5
arch/parisc/Kconfig

@@ -177,14 +177,10 @@ config ARCH_DISCONTIGMEM_DEFAULT
 	def_bool y
 	def_bool y
 	depends on ARCH_DISCONTIGMEM_ENABLE
 	depends on ARCH_DISCONTIGMEM_ENABLE
 
 
+source "kernel/Kconfig.preempt"
 source "kernel/Kconfig.hz"
 source "kernel/Kconfig.hz"
 source "mm/Kconfig"
 source "mm/Kconfig"
 
 
-config PREEMPT
-	bool
-#	bool "Preemptible Kernel"
-	default n
-
 config COMPAT
 config COMPAT
 	def_bool y
 	def_bool y
 	depends on 64BIT
 	depends on 64BIT

+ 74 - 86
arch/parisc/configs/712_defconfig

@@ -1,7 +1,7 @@
 #
 #
 # Automatically generated make config: don't edit
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:04:34 2005
+# Linux kernel version: 2.6.16-pa6
+# Sun Mar 26 19:59:51 2006
 #
 #
 CONFIG_PARISC=y
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_MMU=y
@@ -10,14 +10,11 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 
 
 #
 #
 # Code maturity level options
 # Code maturity level options
 #
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
 
@@ -32,17 +29,18 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EMBEDDED is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_EPOLL=y
@@ -51,8 +49,10 @@ CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 
 #
 #
 # Loadable module support
 # Loadable module support
@@ -65,6 +65,23 @@ CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_KMOD=y
 
 
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
 #
 #
 # Processor type and features
 # Processor type and features
 #
 #
@@ -75,6 +92,10 @@ CONFIG_PA7100LC=y
 # CONFIG_PA8X00 is not set
 # CONFIG_PA8X00 is not set
 CONFIG_PA11=y
 CONFIG_PA11=y
 # CONFIG_SMP is not set
 # CONFIG_SMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
 # CONFIG_HZ_1000 is not set
@@ -86,7 +107,7 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_PREEMPT is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
 # CONFIG_HPUX is not set
 # CONFIG_HPUX is not set
 
 
 #
 #
@@ -130,6 +151,7 @@ CONFIG_NET=y
 #
 #
 # Networking options
 # Networking options
 #
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_UNIX=y
@@ -165,7 +187,12 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_IPV6 is not set
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
 # CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
 
 
 #
 #
 # IP: Netfilter Configuration
 # IP: Netfilter Configuration
@@ -182,64 +209,6 @@ CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_AMANDA=m
 CONFIG_IP_NF_AMANDA=m
 # CONFIG_IP_NF_PPTP is not set
 # CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-CONFIG_IP_NF_MATCH_SCTP=m
-# CONFIG_IP_NF_MATCH_DCCP is not set
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_HASHLIMIT=m
-# CONFIG_IP_NF_MATCH_STRING is not set
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
-# CONFIG_IP_NF_TARGET_TTL is not set
-CONFIG_IP_NF_TARGET_CONNMARK=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
 
 
 #
 #
 # DCCP Configuration (EXPERIMENTAL)
 # DCCP Configuration (EXPERIMENTAL)
@@ -250,6 +219,11 @@ CONFIG_IP_NF_ARP_MANGLE=m
 # SCTP Configuration (EXPERIMENTAL)
 # SCTP Configuration (EXPERIMENTAL)
 #
 #
 # CONFIG_IP_SCTP is not set
 # CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_VLAN_8021Q is not set
@@ -263,8 +237,11 @@ CONFIG_LLC2=m
 # CONFIG_NET_DIVERT is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 
 #
 #
 # Network testing
 # Network testing
@@ -304,6 +281,7 @@ CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=m
 CONFIG_PARPORT_PC=m
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_GSC=y
 CONFIG_PARPORT_GSC=y
 # CONFIG_PARPORT_1284 is not set
 # CONFIG_PARPORT_1284 is not set
 
 
@@ -314,7 +292,6 @@ CONFIG_PARPORT_GSC=y
 #
 #
 # Block devices
 # Block devices
 #
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_LOOP=y
@@ -325,14 +302,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=6144
 CONFIG_BLK_DEV_RAM_SIZE=6144
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_ATA_OVER_ETH=m
 CONFIG_ATA_OVER_ETH=m
 
 
 #
 #
@@ -376,6 +345,7 @@ CONFIG_SCSI_ISCSI_ATTRS=m
 #
 #
 # SCSI low-level drivers
 # SCSI low-level drivers
 #
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_IMM is not set
@@ -407,7 +377,6 @@ CONFIG_MD_RAID1=m
 #
 #
 # IEEE 1394 (FireWire) support
 # IEEE 1394 (FireWire) support
 #
 #
-# CONFIG_IEEE1394 is not set
 
 
 #
 #
 # I2O device support
 # I2O device support
@@ -471,6 +440,7 @@ CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
 CONFIG_PPPOE=m
 CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
 # CONFIG_SHAPER is not set
@@ -516,8 +486,8 @@ CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_KEYBOARD_HIL_OLD=y
-# CONFIG_KEYBOARD_HIL is not set
+# CONFIG_KEYBOARD_HIL_OLD is not set
+CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 CONFIG_MOUSE_PS2=y
 CONFIG_MOUSE_SERIAL=m
 CONFIG_MOUSE_SERIAL=m
@@ -554,6 +524,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=17
 CONFIG_SERIAL_8250_NR_UARTS=17
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -598,12 +569,20 @@ CONFIG_MAX_RAW_DEVS=256
 #
 #
 # TPM devices
 # TPM devices
 #
 #
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 
 #
 #
 # I2C support
 # I2C support
 #
 #
 # CONFIG_I2C is not set
 # CONFIG_I2C is not set
 
 
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
 #
 #
 # Dallas's 1-wire bus
 # Dallas's 1-wire bus
 #
 #
@@ -640,7 +619,6 @@ CONFIG_FB=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_TILEBLITTING=y
@@ -655,6 +633,7 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=128
 CONFIG_DUMMY_CONSOLE_COLUMNS=128
 CONFIG_DUMMY_CONSOLE_ROWS=48
 CONFIG_DUMMY_CONSOLE_ROWS=48
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_STI_CONSOLE=y
 CONFIG_FONTS=y
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x8=y
@@ -695,6 +674,8 @@ CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 # CONFIG_SND_DEBUG is not set
 
 
@@ -723,6 +704,10 @@ CONFIG_SND_HARMONY=y
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
 #
 #
 # USB Gadget Support
 # USB Gadget Support
 #
 #
@@ -736,10 +721,9 @@ CONFIG_SND_HARMONY=y
 #
 #
 # InfiniBand support
 # InfiniBand support
 #
 #
-# CONFIG_INFINIBAND is not set
 
 
 #
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 #
 
 
 #
 #
@@ -765,6 +749,7 @@ CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY=y
@@ -800,10 +785,10 @@ CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 
 #
 #
 # Miscellaneous filesystems
 # Miscellaneous filesystems
@@ -821,7 +806,6 @@ CONFIG_RAMFS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_SYSV_FS is not set
 CONFIG_UFS_FS=m
 CONFIG_UFS_FS=m
-# CONFIG_UFS_FS_WRITE is not set
 
 
 #
 #
 # Network File Systems
 # Network File Systems
@@ -917,18 +901,22 @@ CONFIG_OPROFILE=m
 # Kernel hacking
 # Kernel hacking
 #
 #
 # CONFIG_PRINTK_TIME is not set
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_DETECT_SOFTLOCKUP=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_RODATA=y
 
 
 #
 #
 # Security options
 # Security options

+ 2 - 2
arch/parisc/configs/a500_defconfig

@@ -1031,8 +1031,8 @@ CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
 # CONFIG_NLS_ISO8859_4 is not set

+ 6 - 6
arch/parisc/configs/b180_defconfig

@@ -939,10 +939,10 @@ CONFIG_MSDOS_PARTITION=y
 #
 #
 CONFIG_NLS=y
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -962,8 +962,8 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -973,10 +973,10 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 
 
 #
 #
 # Kernel hacking
 # Kernel hacking

+ 108 - 144
arch/parisc/configs/c3000_defconfig

@@ -1,7 +1,7 @@
 #
 #
 # Automatically generated make config: don't edit
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:06:31 2005
+# Linux kernel version: 2.6.16-pa6
+# Sun Mar 26 20:03:29 2006
 #
 #
 CONFIG_PARISC=y
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_MMU=y
@@ -10,14 +10,11 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 
 
 #
 #
 # Code maturity level options
 # Code maturity level options
 #
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
 
@@ -32,28 +29,30 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 
 #
 #
 # Loadable module support
 # Loadable module support
@@ -66,6 +65,23 @@ CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_KMOD=y
 
 
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
 #
 #
 # Processor type and features
 # Processor type and features
 #
 #
@@ -78,6 +94,10 @@ CONFIG_PA20=y
 CONFIG_PREFETCH=y
 CONFIG_PREFETCH=y
 # CONFIG_64BIT is not set
 # CONFIG_64BIT is not set
 # CONFIG_SMP is not set
 # CONFIG_SMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
 # CONFIG_HZ_1000 is not set
@@ -89,7 +109,7 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_PREEMPT is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_HPUX is not set
 # CONFIG_HPUX is not set
 
 
 #
 #
@@ -135,6 +155,7 @@ CONFIG_NET=y
 #
 #
 # Networking options
 # Networking options
 #
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_UNIX=y
@@ -175,7 +196,12 @@ CONFIG_INET6_TUNNEL=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_DEBUG=y
 CONFIG_NETFILTER_DEBUG=y
+
+#
+# Core Netfilter Configuration
+#
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
 
 
 #
 #
 # IP: Netfilter Configuration
 # IP: Netfilter Configuration
@@ -192,87 +218,11 @@ CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_AMANDA=m
 CONFIG_IP_NF_AMANDA=m
 # CONFIG_IP_NF_PPTP is not set
 # CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_OWNER=m
-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-# CONFIG_IP_NF_MATCH_SCTP is not set
-# CONFIG_IP_NF_MATCH_DCCP is not set
-# CONFIG_IP_NF_MATCH_COMMENT is not set
-# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
-# CONFIG_IP_NF_MATCH_STRING is not set
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
-# CONFIG_IP_NF_TARGET_TTL is not set
-# CONFIG_IP_NF_RAW is not set
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
 
 
 #
 #
 # IPv6: Netfilter Configuration (EXPERIMENTAL)
 # IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 #
 # CONFIG_IP6_NF_QUEUE is not set
 # CONFIG_IP6_NF_QUEUE is not set
-CONFIG_IP6_NF_IPTABLES=m
-# CONFIG_IP6_NF_MATCH_LIMIT is not set
-CONFIG_IP6_NF_MATCH_MAC=m
-CONFIG_IP6_NF_MATCH_RT=m
-# CONFIG_IP6_NF_MATCH_OPTS is not set
-# CONFIG_IP6_NF_MATCH_FRAG is not set
-# CONFIG_IP6_NF_MATCH_HL is not set
-# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
-CONFIG_IP6_NF_MATCH_OWNER=m
-# CONFIG_IP6_NF_MATCH_MARK is not set
-CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-# CONFIG_IP6_NF_MATCH_AHESP is not set
-CONFIG_IP6_NF_MATCH_LENGTH=m
-# CONFIG_IP6_NF_MATCH_EUI64 is not set
-CONFIG_IP6_NF_FILTER=m
-CONFIG_IP6_NF_TARGET_LOG=m
-CONFIG_IP6_NF_TARGET_REJECT=m
-# CONFIG_IP6_NF_TARGET_NFQUEUE is not set
-CONFIG_IP6_NF_MANGLE=m
-# CONFIG_IP6_NF_TARGET_MARK is not set
-# CONFIG_IP6_NF_TARGET_HL is not set
-# CONFIG_IP6_NF_RAW is not set
 
 
 #
 #
 # DCCP Configuration (EXPERIMENTAL)
 # DCCP Configuration (EXPERIMENTAL)
@@ -283,6 +233,11 @@ CONFIG_IP6_NF_MANGLE=m
 # SCTP Configuration (EXPERIMENTAL)
 # SCTP Configuration (EXPERIMENTAL)
 #
 #
 # CONFIG_IP_SCTP is not set
 # CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_VLAN_8021Q is not set
@@ -295,8 +250,11 @@ CONFIG_IP6_NF_MANGLE=m
 # CONFIG_NET_DIVERT is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 
 #
 #
 # Network testing
 # Network testing
@@ -341,7 +299,6 @@ CONFIG_FW_LOADER=y
 #
 #
 # Block devices
 # Block devices
 #
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -355,14 +312,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_RAM is not set
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_COUNT=16
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_ATA_OVER_ETH is not set
 
 
 #
 #
@@ -458,6 +407,7 @@ CONFIG_SCSI_ISCSI_ATTRS=m
 #
 #
 # SCSI low-level drivers
 # SCSI low-level drivers
 #
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_ACARD is not set
@@ -466,7 +416,6 @@ CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
 # CONFIG_MEGARAID_SAS is not set
@@ -476,18 +425,18 @@ CONFIG_SCSI_SATA=y
 CONFIG_SCSI_ATA_PIIX=m
 CONFIG_SCSI_ATA_PIIX=m
 # CONFIG_SCSI_SATA_MV is not set
 # CONFIG_SCSI_SATA_MV is not set
 # CONFIG_SCSI_SATA_NV is not set
 # CONFIG_SCSI_SATA_NV is not set
-CONFIG_SCSI_SATA_PROMISE=m
+# CONFIG_SCSI_PDC_ADMA is not set
 # CONFIG_SCSI_SATA_QSTOR is not set
 # CONFIG_SCSI_SATA_QSTOR is not set
+CONFIG_SCSI_SATA_PROMISE=m
 # CONFIG_SCSI_SATA_SX4 is not set
 # CONFIG_SCSI_SATA_SX4 is not set
 CONFIG_SCSI_SATA_SIL=m
 CONFIG_SCSI_SATA_SIL=m
+# CONFIG_SCSI_SATA_SIL24 is not set
 # CONFIG_SCSI_SATA_SIS is not set
 # CONFIG_SCSI_SATA_SIS is not set
 # CONFIG_SCSI_SATA_ULI is not set
 # CONFIG_SCSI_SATA_ULI is not set
 CONFIG_SCSI_SATA_VIA=m
 CONFIG_SCSI_SATA_VIA=m
 # CONFIG_SCSI_SATA_VITESSE is not set
 # CONFIG_SCSI_SATA_VITESSE is not set
 CONFIG_SCSI_SATA_INTEL_COMBINED=y
 CONFIG_SCSI_SATA_INTEL_COMBINED=y
-# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INITIO is not set
@@ -496,18 +445,11 @@ CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DC390T is not set
@@ -633,6 +575,7 @@ CONFIG_E1000=m
 # CONFIG_R8169 is not set
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=m
 CONFIG_TIGON3=m
@@ -668,6 +611,7 @@ CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
 CONFIG_PPPOE=m
 CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 # CONFIG_SLIP is not set
 # CONFIG_NET_FC is not set
 # CONFIG_NET_FC is not set
@@ -744,6 +688,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=13
 CONFIG_SERIAL_8250_NR_UARTS=13
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -753,7 +698,6 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 #
 #
 # Non-8250 serial port support
 # Non-8250 serial port support
 #
 #
-# CONFIG_SERIAL_MUX is not set
 # CONFIG_PDC_CONSOLE is not set
 # CONFIG_PDC_CONSOLE is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
@@ -788,12 +732,19 @@ CONFIG_MAX_RAW_DEVS=256
 # TPM devices
 # TPM devices
 #
 #
 # CONFIG_TCG_TPM is not set
 # CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 
 #
 #
 # I2C support
 # I2C support
 #
 #
 # CONFIG_I2C is not set
 # CONFIG_I2C is not set
 
 
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
 #
 #
 # Dallas's 1-wire bus
 # Dallas's 1-wire bus
 #
 #
@@ -830,7 +781,6 @@ CONFIG_FB=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_TILEBLITTING is not set
@@ -840,6 +790,7 @@ CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_IMSTT is not set
 CONFIG_FB_STI=y
 CONFIG_FB_STI=y
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_MATROX is not set
@@ -853,10 +804,7 @@ CONFIG_FB_STI=y
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_PM3 is not set
-# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_VIRTUAL is not set
 
 
 #
 #
@@ -866,6 +814,7 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_STI_CONSOLE=y
 # CONFIG_FONTS is not set
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x8=y
@@ -898,23 +847,27 @@ CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 # CONFIG_SND_DEBUG is not set
 
 
 #
 #
 # Generic devices
 # Generic devices
 #
 #
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
 # CONFIG_SND_MPU401 is not set
-CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_AC97_BUS=y
 
 
 #
 #
 # PCI devices
 # PCI devices
 #
 #
+CONFIG_SND_AD1889=y
+# CONFIG_SND_AD1889_OPL3 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -923,39 +876,38 @@ CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-CONFIG_SND_AD1889=y
-# CONFIG_SND_AD1889_OPL3 is not set
-# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
 # CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
 # CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_YMFPCI is not set
 
 
 #
 #
 # USB devices
 # USB devices
@@ -998,12 +950,15 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # USB Device Class drivers
 # USB Device Class drivers
 #
 #
 # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_ACM is not set
 CONFIG_USB_PRINTER=m
 CONFIG_USB_PRINTER=m
 
 
 #
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
 #
 #
 CONFIG_USB_STORAGE=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1015,12 +970,15 @@ CONFIG_USB_STORAGE_USBAT=y
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 
 #
 #
 # USB Input Devices
 # USB Input Devices
 #
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_AIPTEK is not set
@@ -1034,6 +992,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 # CONFIG_USB_APPLETOUCH is not set
 
 
@@ -1108,7 +1067,7 @@ CONFIG_USB_LEGOTOWER=m
 # CONFIG_INFINIBAND is not set
 # CONFIG_INFINIBAND is not set
 
 
 #
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 #
 
 
 #
 #
@@ -1130,6 +1089,7 @@ CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY=y
@@ -1164,10 +1124,10 @@ CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 
 #
 #
 # Miscellaneous filesystems
 # Miscellaneous filesystems
@@ -1225,10 +1185,10 @@ CONFIG_MSDOS_PARTITION=y
 #
 #
 CONFIG_NLS=y
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -1248,8 +1208,8 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1259,10 +1219,10 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 
 
 #
 #
 # Profiling support
 # Profiling support
@@ -1274,18 +1234,22 @@ CONFIG_OPROFILE=m
 # Kernel hacking
 # Kernel hacking
 #
 #
 # CONFIG_PRINTK_TIME is not set
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_DETECT_SOFTLOCKUP=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_RODATA=y
 
 
 #
 #
 # Security options
 # Security options

+ 110 - 55
arch/parisc/defconfig

@@ -1,7 +1,7 @@
 #
 #
 # Automatically generated make config: don't edit
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:01:33 2005
+# Linux kernel version: 2.6.16-pa6
+# Sun Mar 26 19:50:07 2006
 #
 #
 CONFIG_PARISC=y
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_MMU=y
@@ -15,7 +15,6 @@ CONFIG_GENERIC_IRQ_PROBE=y
 # Code maturity level options
 # Code maturity level options
 #
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
 
@@ -30,17 +29,18 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EMBEDDED is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_EPOLL=y
@@ -49,14 +49,33 @@ CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 
 #
 #
 # Loadable module support
 # Loadable module support
 #
 #
 # CONFIG_MODULES is not set
 # CONFIG_MODULES is not set
 
 
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
 #
 #
 # Processor type and features
 # Processor type and features
 #
 #
@@ -67,6 +86,10 @@ CONFIG_PA7000=y
 # CONFIG_PA8X00 is not set
 # CONFIG_PA8X00 is not set
 CONFIG_PA11=y
 CONFIG_PA11=y
 # CONFIG_SMP is not set
 # CONFIG_SMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
 # CONFIG_HZ_1000 is not set
@@ -78,7 +101,7 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_PREEMPT is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
 # CONFIG_HPUX is not set
 # CONFIG_HPUX is not set
 
 
 #
 #
@@ -132,6 +155,7 @@ CONFIG_NET=y
 #
 #
 # Networking options
 # Networking options
 #
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_UNIX=y
@@ -174,6 +198,11 @@ CONFIG_IPV6=y
 # SCTP Configuration (EXPERIMENTAL)
 # SCTP Configuration (EXPERIMENTAL)
 #
 #
 # CONFIG_IP_SCTP is not set
 # CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_VLAN_8021Q is not set
@@ -186,8 +215,11 @@ CONFIG_IPV6=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 
 #
 #
 # Network testing
 # Network testing
@@ -228,6 +260,7 @@ CONFIG_PARPORT_PC=y
 # CONFIG_PARPORT_SERIAL is not set
 # CONFIG_PARPORT_SERIAL is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_GSC=y
 CONFIG_PARPORT_GSC=y
 # CONFIG_PARPORT_1284 is not set
 # CONFIG_PARPORT_1284 is not set
 
 
@@ -254,14 +287,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
 # CONFIG_ATA_OVER_ETH is not set
 
 
 #
 #
@@ -305,6 +330,7 @@ CONFIG_SCSI_SPI_ATTRS=y
 #
 #
 # SCSI low-level drivers
 # SCSI low-level drivers
 #
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_ACARD is not set
@@ -331,7 +357,7 @@ CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_IPR is not set
 CONFIG_SCSI_ZALON=y
 CONFIG_SCSI_ZALON=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
@@ -340,13 +366,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC395x is not set
@@ -471,6 +491,7 @@ CONFIG_ACENIC=y
 # CONFIG_R8169 is not set
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 CONFIG_TIGON3=y
@@ -562,13 +583,13 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_KEYBOARD_HIL_OLD=y
+# CONFIG_KEYBOARD_HIL_OLD is not set
 CONFIG_KEYBOARD_HIL=y
 CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_INPUT_MOUSE=y
 # CONFIG_MOUSE_PS2 is not set
 # CONFIG_MOUSE_PS2 is not set
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_MOUSE_HIL is not set
+CONFIG_MOUSE_HIL=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_JOYSTICK=y
 # CONFIG_JOYSTICK_ANALOG is not set
 # CONFIG_JOYSTICK_ANALOG is not set
 # CONFIG_JOYSTICK_A3D is not set
 # CONFIG_JOYSTICK_A3D is not set
@@ -628,6 +649,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=13
 CONFIG_SERIAL_8250_NR_UARTS=13
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -675,12 +697,19 @@ CONFIG_GEN_RTC=y
 # TPM devices
 # TPM devices
 #
 #
 # CONFIG_TCG_TPM is not set
 # CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 
 #
 #
 # I2C support
 # I2C support
 #
 #
 # CONFIG_I2C is not set
 # CONFIG_I2C is not set
 
 
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
 #
 #
 # Dallas's 1-wire bus
 # Dallas's 1-wire bus
 #
 #
@@ -691,6 +720,7 @@ CONFIG_GEN_RTC=y
 #
 #
 CONFIG_HWMON=y
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 
 #
 #
@@ -718,7 +748,6 @@ CONFIG_FB=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_TILEBLITTING is not set
@@ -728,6 +757,7 @@ CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_IMSTT is not set
 CONFIG_FB_STI=y
 CONFIG_FB_STI=y
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_MATROX is not set
@@ -741,9 +771,7 @@ CONFIG_FB_STI=y
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_VIRTUAL is not set
 
 
 #
 #
@@ -753,15 +781,28 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_STI_CONSOLE=y
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
 CONFIG_FONT_8x16=y
 CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
 
 
 #
 #
 # Logo configuration
 # Logo configuration
 #
 #
-# CONFIG_LOGO is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_LOGO_PARISC_CLUT224=y
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 
 #
 #
@@ -781,23 +822,27 @@ CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 # CONFIG_SND_DEBUG is not set
 
 
 #
 #
 # Generic devices
 # Generic devices
 #
 #
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
 # CONFIG_SND_MPU401 is not set
-CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_AC97_BUS=y
 
 
 #
 #
 # PCI devices
 # PCI devices
 #
 #
+CONFIG_SND_AD1889=y
+# CONFIG_SND_AD1889_OPL3 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -806,39 +851,38 @@ CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-CONFIG_SND_AD1889=y
-# CONFIG_SND_AD1889_OPL3 is not set
-# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
 # CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
 # CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_YMFPCI is not set
 
 
 #
 #
 # USB devices
 # USB devices
@@ -888,14 +932,18 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # USB Device Class drivers
 # USB Device Class drivers
 #
 #
 # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_PRINTER is not set
 
 
 #
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
 #
 #
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 
 #
 #
 # USB Input Devices
 # USB Input Devices
@@ -918,6 +966,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 # CONFIG_USB_APPLETOUCH is not set
 
 
@@ -994,7 +1043,7 @@ CONFIG_USB_MON=y
 # CONFIG_INFINIBAND is not set
 # CONFIG_INFINIBAND is not set
 
 
 #
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 #
 
 
 #
 #
@@ -1011,6 +1060,7 @@ CONFIG_JBD=y
 # CONFIG_JFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY=y
@@ -1045,6 +1095,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 
 #
 #
 # Miscellaneous filesystems
 # Miscellaneous filesystems
@@ -1151,18 +1202,22 @@ CONFIG_OPROFILE=y
 # Kernel hacking
 # Kernel hacking
 #
 #
 # CONFIG_PRINTK_TIME is not set
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_DETECT_SOFTLOCKUP=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_RODATA=y
 
 
 #
 #
 # Security options
 # Security options

+ 3 - 3
arch/parisc/kernel/cache.c

@@ -89,7 +89,7 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 	if (pfn_valid(page_to_pfn(page)) && page_mapping(page) &&
 	if (pfn_valid(page_to_pfn(page)) && page_mapping(page) &&
 	    test_bit(PG_dcache_dirty, &page->flags)) {
 	    test_bit(PG_dcache_dirty, &page->flags)) {
 
 
-		flush_kernel_dcache_page(page_address(page));
+		flush_kernel_dcache_page(page);
 		clear_bit(PG_dcache_dirty, &page->flags);
 		clear_bit(PG_dcache_dirty, &page->flags);
 	}
 	}
 }
 }
@@ -278,7 +278,7 @@ void flush_dcache_page(struct page *page)
 		return;
 		return;
 	}
 	}
 
 
-	flush_kernel_dcache_page(page_address(page));
+	flush_kernel_dcache_page(page);
 
 
 	if (!mapping)
 	if (!mapping)
 		return;
 		return;
@@ -317,7 +317,7 @@ EXPORT_SYMBOL(flush_dcache_page);
 
 
 /* Defined in arch/parisc/kernel/pacache.S */
 /* Defined in arch/parisc/kernel/pacache.S */
 EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
 EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
-EXPORT_SYMBOL(flush_kernel_dcache_page);
+EXPORT_SYMBOL(flush_kernel_dcache_page_asm);
 EXPORT_SYMBOL(flush_data_cache_local);
 EXPORT_SYMBOL(flush_data_cache_local);
 EXPORT_SYMBOL(flush_kernel_icache_range_asm);
 EXPORT_SYMBOL(flush_kernel_icache_range_asm);
 
 

+ 39 - 6
arch/parisc/kernel/entry.S

@@ -563,10 +563,10 @@
 	extrd,u,*= 	\pte,_PAGE_GATEWAY_BIT+32,1,%r0
 	extrd,u,*= 	\pte,_PAGE_GATEWAY_BIT+32,1,%r0
 	depd		%r0,11,2,\prot	/* If Gateway, Set PL2 to 0 */
 	depd		%r0,11,2,\prot	/* If Gateway, Set PL2 to 0 */
 
 
-	/* Get rid of prot bits and convert to page addr for iitlbt */
+	/* Get rid of prot bits and convert to page addr for iitlbt and idtlbt */
 
 
 	depd		%r0,63,PAGE_SHIFT,\pte
 	depd		%r0,63,PAGE_SHIFT,\pte
-	extrd,u		\pte,56,32,\pte
+	extrd,s		\pte,(63-PAGE_SHIFT)+(63-58),64-PAGE_SHIFT,\pte
 	.endm
 	.endm
 
 
 	/* Identical macro to make_insert_tlb above, except it
 	/* Identical macro to make_insert_tlb above, except it
@@ -584,7 +584,7 @@
 
 
 	/* Get rid of prot bits and convert to page addr for iitlba */
 	/* Get rid of prot bits and convert to page addr for iitlba */
 
 
-	depi		0,31,12,\pte
+	depi		0,31,PAGE_SHIFT,\pte
 	extru		\pte,24,25,\pte
 	extru		\pte,24,25,\pte
 
 
 	.endm
 	.endm
@@ -1014,14 +1014,21 @@ intr_restore:
 	nop
 	nop
 	nop
 	nop
 
 
+#ifndef CONFIG_PREEMPT
+# define intr_do_preempt	intr_restore
+#endif /* !CONFIG_PREEMPT */
+
 	.import schedule,code
 	.import schedule,code
 intr_do_resched:
 intr_do_resched:
-	/* Only do reschedule if we are returning to user space */
+	/* Only call schedule on return to userspace. If we're returning
+	 * to kernel space, we may schedule if CONFIG_PREEMPT, otherwise
+	 * we jump back to intr_restore.
+	 */
 	LDREG	PT_IASQ0(%r16), %r20
 	LDREG	PT_IASQ0(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB=	0, %r20, intr_do_preempt
 	nop
 	nop
 	LDREG	PT_IASQ1(%r16), %r20
 	LDREG	PT_IASQ1(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB=	0, %r20, intr_do_preempt
 	nop
 	nop
 
 
 #ifdef CONFIG_64BIT
 #ifdef CONFIG_64BIT
@@ -1037,6 +1044,32 @@ intr_do_resched:
 #endif
 #endif
 	ldo	R%intr_check_sig(%r2), %r2
 	ldo	R%intr_check_sig(%r2), %r2
 
 
+	/* preempt the current task on returning to kernel
+	 * mode from an interrupt, iff need_resched is set,
+	 * and preempt_count is 0. otherwise, we continue on
+	 * our merry way back to the current running task.
+	 */
+#ifdef CONFIG_PREEMPT
+	.import preempt_schedule_irq,code
+intr_do_preempt:
+	rsm	PSW_SM_I, %r0		/* disable interrupts */
+
+	/* current_thread_info()->preempt_count */
+	mfctl	%cr30, %r1
+	LDREG	TI_PRE_COUNT(%r1), %r19
+	CMPIB<>	0, %r19, intr_restore	/* if preempt_count > 0 */
+	nop				/* prev insn branched backwards */
+
+	/* check if we interrupted a critical path */
+	LDREG	PT_PSW(%r16), %r20
+	bb,<,n	%r20, 31 - PSW_SM_I, intr_restore
+	nop
+
+	BL	preempt_schedule_irq, %r2
+	nop
+
+	b	intr_restore		/* ssm PSW_SM_I done by intr_restore */
+#endif /* CONFIG_PREEMPT */
 
 
 	.import do_signal,code
 	.import do_signal,code
 intr_do_signal:
 intr_do_signal:

+ 2 - 2
arch/parisc/kernel/pacache.S

@@ -621,9 +621,9 @@ __clear_user_page_asm:
 
 
 	.procend
 	.procend
 
 
-	.export flush_kernel_dcache_page
+	.export flush_kernel_dcache_page_asm
 
 
-flush_kernel_dcache_page:
+flush_kernel_dcache_page_asm:
 	.proc
 	.proc
 	.callinfo NO_CALLS
 	.callinfo NO_CALLS
 	.entry
 	.entry

+ 0 - 19
arch/parisc/kernel/parisc_ksyms.c

@@ -30,22 +30,7 @@
 #include <linux/syscalls.h>
 #include <linux/syscalls.h>
 
 
 #include <linux/string.h>
 #include <linux/string.h>
-EXPORT_SYMBOL(memchr);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strcpy);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strncat);
-EXPORT_SYMBOL(strncmp);
-EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strpbrk);
 
 
 #include <asm/atomic.h>
 #include <asm/atomic.h>
@@ -82,16 +67,12 @@ EXPORT_SYMBOL($global$);
 #endif
 #endif
 
 
 #include <asm/io.h>
 #include <asm/io.h>
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(memcpy_toio);
 EXPORT_SYMBOL(memcpy_toio);
 EXPORT_SYMBOL(memcpy_fromio);
 EXPORT_SYMBOL(memcpy_fromio);
 EXPORT_SYMBOL(memset_io);
 EXPORT_SYMBOL(memset_io);
 
 
 #include <asm/unistd.h>
 #include <asm/unistd.h>
-EXPORT_SYMBOL(sys_open);
 EXPORT_SYMBOL(sys_lseek);
 EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_read);
 EXPORT_SYMBOL(sys_write);
 EXPORT_SYMBOL(sys_write);
 
 
 #include <asm/semaphore.h>
 #include <asm/semaphore.h>

+ 2 - 3
arch/parisc/kernel/pdc_chassis.c

@@ -5,9 +5,8 @@
  *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.org>
  *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.org>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *    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.
+ *    it under the terms of the GNU General Public License, version 2, as
+ *    published by the Free Software Foundation.
  *
  *
  *    This program is distributed in the hope that it will be useful,
  *    This program is distributed in the hope that it will be useful,
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of

+ 1 - 1
arch/parisc/kernel/perf.c

@@ -805,7 +805,7 @@ static int perf_write_image(uint64_t *memaddr)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	runway = ioremap(cpu_device->hpa.start, 4096);
+	runway = ioremap_nocache(cpu_device->hpa.start, 4096);
 
 
 	/* Merge intrigue bits into Runway STATUS 0 */
 	/* Merge intrigue bits into Runway STATUS 0 */
 	tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful;
 	tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful;

+ 1 - 1
arch/parisc/kernel/syscall_table.S

@@ -287,7 +287,7 @@
 	ENTRY_SAME(chown)		/* 180 */
 	ENTRY_SAME(chown)		/* 180 */
 	/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
 	/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
 	ENTRY_COMP(setsockopt)
 	ENTRY_COMP(setsockopt)
-	ENTRY_SAME(getsockopt)
+	ENTRY_COMP(getsockopt)
 	ENTRY_COMP(sendmsg)
 	ENTRY_COMP(sendmsg)
 	ENTRY_COMP(recvmsg)
 	ENTRY_COMP(recvmsg)
 	ENTRY_SAME(semop)		/* 185 */
 	ENTRY_SAME(semop)		/* 185 */

+ 0 - 4
arch/parisc/lib/iomap.c

@@ -263,11 +263,7 @@ static const struct iomap_ops iomem_ops = {
 
 
 const struct iomap_ops *iomap_ops[8] = {
 const struct iomap_ops *iomap_ops[8] = {
 	[0] = &ioport_ops,
 	[0] = &ioport_ops,
-#ifdef CONFIG_DEBUG_IOREMAP
-	[6] = &iomem_ops,
-#else
 	[7] = &iomem_ops
 	[7] = &iomem_ops
-#endif
 };
 };
 
 
 
 

+ 3 - 4
arch/parisc/mm/init.c

@@ -1013,9 +1013,9 @@ void flush_tlb_all(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
 {
-#if 0
-	if (start < end)
-		printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+	if (start >= end)
+		return;
+	printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
 	for (; start < end; start += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(start));
 		ClearPageReserved(virt_to_page(start));
 		init_page_count(virt_to_page(start));
 		init_page_count(virt_to_page(start));
@@ -1023,6 +1023,5 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 		num_physpages++;
 		num_physpages++;
 		totalram_pages++;
 		totalram_pages++;
 	}
 	}
-#endif
 }
 }
 #endif
 #endif

+ 9 - 45
arch/parisc/mm/ioremap.c

@@ -72,7 +72,6 @@ remap_area_pmd(pmd_t *pmd, unsigned long address, unsigned long size,
 	return 0;
 	return 0;
 }
 }
 
 
-#if USE_HPPA_IOREMAP
 static int 
 static int 
 remap_area_pages(unsigned long address, unsigned long phys_addr,
 remap_area_pages(unsigned long address, unsigned long phys_addr,
 		 unsigned long size, unsigned long flags)
 		 unsigned long size, unsigned long flags)
@@ -114,31 +113,6 @@ remap_area_pages(unsigned long address, unsigned long phys_addr,
 
 
 	return error;
 	return error;
 }
 }
-#endif /* USE_HPPA_IOREMAP */
-
-#ifdef CONFIG_DEBUG_IOREMAP
-static unsigned long last = 0;
-
-void gsc_bad_addr(unsigned long addr)
-{
-	if (time_after(jiffies, last + HZ*10)) {
-		printk("gsc_foo() called with bad address 0x%lx\n", addr);
-		dump_stack();
-		last = jiffies;
-	}
-}
-EXPORT_SYMBOL(gsc_bad_addr);
-
-void __raw_bad_addr(const volatile void __iomem *addr)
-{
-	if (time_after(jiffies, last + HZ*10)) {
-		printk("__raw_foo() called with bad address 0x%p\n", addr);
-		dump_stack();
-		last = jiffies;
-	}
-}
-EXPORT_SYMBOL(__raw_bad_addr);
-#endif
 
 
 /*
 /*
  * Generic mapping function (not visible outside):
  * Generic mapping function (not visible outside):
@@ -154,26 +128,19 @@ EXPORT_SYMBOL(__raw_bad_addr);
  */
  */
 void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
 void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
 {
 {
-#if !(USE_HPPA_IOREMAP)
+	void *addr;
+	struct vm_struct *area;
+	unsigned long offset, last_addr;
 
 
+#ifdef CONFIG_EISA
 	unsigned long end = phys_addr + size - 1;
 	unsigned long end = phys_addr + size - 1;
 	/* Support EISA addresses */
 	/* Support EISA addresses */
-	if ((phys_addr >= 0x00080000 && end < 0x000fffff)
-			|| (phys_addr >= 0x00500000 && end < 0x03bfffff)) {
-		phys_addr |= 0xfc000000;
+	if ((phys_addr >= 0x00080000 && end < 0x000fffff) ||
+	    (phys_addr >= 0x00500000 && end < 0x03bfffff)) {
+		phys_addr |= F_EXTEND(0xfc000000);
 	}
 	}
-
-#ifdef CONFIG_DEBUG_IOREMAP
-	return (void __iomem *)(phys_addr - (0x1UL << NYBBLE_SHIFT));
-#else
-	return (void __iomem *)phys_addr;
 #endif
 #endif
 
 
-#else
-	void *addr;
-	struct vm_struct *area;
-	unsigned long offset, last_addr;
-
 	/* Don't allow wraparound or zero size */
 	/* Don't allow wraparound or zero size */
 	last_addr = phys_addr + size - 1;
 	last_addr = phys_addr + size - 1;
 	if (!size || last_addr < phys_addr)
 	if (!size || last_addr < phys_addr)
@@ -217,15 +184,12 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
 	}
 	}
 
 
 	return (void __iomem *) (offset + (char *)addr);
 	return (void __iomem *) (offset + (char *)addr);
-#endif
 }
 }
+EXPORT_SYMBOL(__ioremap);
 
 
 void iounmap(void __iomem *addr)
 void iounmap(void __iomem *addr)
 {
 {
-#if !(USE_HPPA_IOREMAP)
-	return;
-#else
 	if (addr > high_memory)
 	if (addr > high_memory)
 		return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
 		return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
-#endif
 }
 }
+EXPORT_SYMBOL(iounmap);

+ 7 - 9
drivers/char/drm/drmP.h

@@ -357,6 +357,12 @@ typedef struct drm_freelist {
 	spinlock_t lock;
 	spinlock_t lock;
 } drm_freelist_t;
 } drm_freelist_t;
 
 
+typedef struct drm_dma_handle {
+	dma_addr_t busaddr;
+	void *vaddr;
+	size_t size;
+} drm_dma_handle_t;
+
 /**
 /**
  * Buffer entry.  There is one of this for each buffer size order.
  * Buffer entry.  There is one of this for each buffer size order.
  */
  */
@@ -366,7 +372,7 @@ typedef struct drm_buf_entry {
 	drm_buf_t *buflist;		/**< buffer list */
 	drm_buf_t *buflist;		/**< buffer list */
 	int seg_count;
 	int seg_count;
 	int page_order;
 	int page_order;
-	unsigned long *seglist;
+	drm_dma_handle_t **seglist;
 
 
 	drm_freelist_t freelist;
 	drm_freelist_t freelist;
 } drm_buf_entry_t;
 } drm_buf_entry_t;
@@ -483,12 +489,6 @@ typedef struct drm_sigdata {
 	drm_hw_lock_t *lock;
 	drm_hw_lock_t *lock;
 } drm_sigdata_t;
 } drm_sigdata_t;
 
 
-typedef struct drm_dma_handle {
-	dma_addr_t busaddr;
-	void *vaddr;
-	size_t size;
-} drm_dma_handle_t;
-
 /**
 /**
  * Mappings list
  * Mappings list
  */
  */
@@ -813,8 +813,6 @@ extern void drm_mem_init(void);
 extern int drm_mem_info(char *buf, char **start, off_t offset,
 extern int drm_mem_info(char *buf, char **start, off_t offset,
 			int request, int *eof, void *data);
 			int request, int *eof, void *data);
 extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
 extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern unsigned long drm_alloc_pages(int order, int area);
-extern void drm_free_pages(unsigned long address, int order, int area);
 extern void *drm_ioremap(unsigned long offset, unsigned long size,
 extern void *drm_ioremap(unsigned long offset, unsigned long size,
 			 drm_device_t * dev);
 			 drm_device_t * dev);
 extern void *drm_ioremap_nocache(unsigned long offset, unsigned long size,
 extern void *drm_ioremap_nocache(unsigned long offset, unsigned long size,

+ 11 - 9
drivers/char/drm/drm_bufs.c

@@ -474,8 +474,7 @@ static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry)
 	if (entry->seg_count) {
 	if (entry->seg_count) {
 		for (i = 0; i < entry->seg_count; i++) {
 		for (i = 0; i < entry->seg_count; i++) {
 			if (entry->seglist[i]) {
 			if (entry->seglist[i]) {
-				drm_free_pages(entry->seglist[i],
-					       entry->page_order, DRM_MEM_DMA);
+				drm_pci_free(dev, entry->seglist[i]);
 			}
 			}
 		}
 		}
 		drm_free(entry->seglist,
 		drm_free(entry->seglist,
@@ -678,7 +677,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
 	int total;
 	int total;
 	int page_order;
 	int page_order;
 	drm_buf_entry_t *entry;
 	drm_buf_entry_t *entry;
-	unsigned long page;
+	drm_dma_handle_t *dmah;
 	drm_buf_t *buf;
 	drm_buf_t *buf;
 	int alignment;
 	int alignment;
 	unsigned long offset;
 	unsigned long offset;
@@ -781,8 +780,10 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
 	page_count = 0;
 	page_count = 0;
 
 
 	while (entry->buf_count < count) {
 	while (entry->buf_count < count) {
-		page = drm_alloc_pages(page_order, DRM_MEM_DMA);
-		if (!page) {
+		
+		dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful);
+		
+		if (!dmah) {
 			/* Set count correctly so we free the proper amount. */
 			/* Set count correctly so we free the proper amount. */
 			entry->buf_count = count;
 			entry->buf_count = count;
 			entry->seg_count = count;
 			entry->seg_count = count;
@@ -794,13 +795,13 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
 			atomic_dec(&dev->buf_alloc);
 			atomic_dec(&dev->buf_alloc);
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
-		entry->seglist[entry->seg_count++] = page;
+		entry->seglist[entry->seg_count++] = dmah;
 		for (i = 0; i < (1 << page_order); i++) {
 		for (i = 0; i < (1 << page_order); i++) {
 			DRM_DEBUG("page %d @ 0x%08lx\n",
 			DRM_DEBUG("page %d @ 0x%08lx\n",
 				  dma->page_count + page_count,
 				  dma->page_count + page_count,
-				  page + PAGE_SIZE * i);
+				  (unsigned long)dmah->vaddr + PAGE_SIZE * i);
 			temp_pagelist[dma->page_count + page_count++]
 			temp_pagelist[dma->page_count + page_count++]
-			    = page + PAGE_SIZE * i;
+				= (unsigned long)dmah->vaddr + PAGE_SIZE * i;
 		}
 		}
 		for (offset = 0;
 		for (offset = 0;
 		     offset + size <= total && entry->buf_count < count;
 		     offset + size <= total && entry->buf_count < count;
@@ -811,7 +812,8 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
 			buf->order = order;
 			buf->order = order;
 			buf->used = 0;
 			buf->used = 0;
 			buf->offset = (dma->byte_count + byte_count + offset);
 			buf->offset = (dma->byte_count + byte_count + offset);
-			buf->address = (void *)(page + offset);
+			buf->address = (void *)(dmah->vaddr + offset);
+			buf->bus_address = dmah->busaddr + offset;
 			buf->next = NULL;
 			buf->next = NULL;
 			buf->waiting = 0;
 			buf->waiting = 0;
 			buf->pending = 0;
 			buf->pending = 0;

+ 1 - 3
drivers/char/drm/drm_dma.c

@@ -85,9 +85,7 @@ void drm_dma_takedown(drm_device_t * dev)
 				  dma->bufs[i].seg_count);
 				  dma->bufs[i].seg_count);
 			for (j = 0; j < dma->bufs[i].seg_count; j++) {
 			for (j = 0; j < dma->bufs[i].seg_count; j++) {
 				if (dma->bufs[i].seglist[j]) {
 				if (dma->bufs[i].seglist[j]) {
-					drm_free_pages(dma->bufs[i].seglist[j],
-						       dma->bufs[i].page_order,
-						       DRM_MEM_DMA);
+					drm_pci_free(dev, dma->bufs[i].seglist[j]);
 				}
 				}
 			}
 			}
 			drm_free(dma->bufs[i].seglist,
 			drm_free(dma->bufs[i].seglist,

+ 0 - 59
drivers/char/drm/drm_memory.c

@@ -79,65 +79,6 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
 	return pt;
 	return pt;
 }
 }
 
 
-/**
- * Allocate pages.
- *
- * \param order size order.
- * \param area memory area. (Not used.)
- * \return page address on success, or zero on failure.
- *
- * Allocate and reserve free pages.
- */
-unsigned long drm_alloc_pages(int order, int area)
-{
-	unsigned long address;
-	unsigned long bytes = PAGE_SIZE << order;
-	unsigned long addr;
-	unsigned int sz;
-
-	address = __get_free_pages(GFP_KERNEL|__GFP_COMP, order);
-	if (!address)
-		return 0;
-
-	/* Zero */
-	memset((void *)address, 0, bytes);
-
-	/* Reserve */
-	for (addr = address, sz = bytes;
-	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-		SetPageReserved(virt_to_page(addr));
-	}
-
-	return address;
-}
-
-/**
- * Free pages.
- *
- * \param address address of the pages to free.
- * \param order size order.
- * \param area memory area. (Not used.)
- *
- * Unreserve and free pages allocated by alloc_pages().
- */
-void drm_free_pages(unsigned long address, int order, int area)
-{
-	unsigned long bytes = PAGE_SIZE << order;
-	unsigned long addr;
-	unsigned int sz;
-
-	if (!address)
-		return;
-
-	/* Unreserve */
-	for (addr = address, sz = bytes;
-	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(addr));
-	}
-
-	free_pages(address, order);
-}
-
 #if __OS_HAS_AGP
 #if __OS_HAS_AGP
 /** Wrapper around agp_allocate_memory() */
 /** Wrapper around agp_allocate_memory() */
 DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type)
 DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type)

+ 0 - 70
drivers/char/drm/drm_memory_debug.h

@@ -206,76 +206,6 @@ void drm_free (void *pt, size_t size, int area) {
 	}
 	}
 }
 }
 
 
-unsigned long drm_alloc_pages (int order, int area) {
-	unsigned long address;
-	unsigned long bytes = PAGE_SIZE << order;
-	unsigned long addr;
-	unsigned int sz;
-
-	spin_lock(&drm_mem_lock);
-	if ((drm_ram_used >> PAGE_SHIFT)
-	    > (DRM_RAM_PERCENT * drm_ram_available) / 100) {
-		spin_unlock(&drm_mem_lock);
-		return 0;
-	}
-	spin_unlock(&drm_mem_lock);
-
-	address = __get_free_pages(GFP_KERNEL|__GFP_COMP, order);
-	if (!address) {
-		spin_lock(&drm_mem_lock);
-		++drm_mem_stats[area].fail_count;
-		spin_unlock(&drm_mem_lock);
-		return 0;
-	}
-	spin_lock(&drm_mem_lock);
-	++drm_mem_stats[area].succeed_count;
-	drm_mem_stats[area].bytes_allocated += bytes;
-	drm_ram_used += bytes;
-	spin_unlock(&drm_mem_lock);
-
-	/* Zero outside the lock */
-	memset((void *)address, 0, bytes);
-
-	/* Reserve */
-	for (addr = address, sz = bytes;
-	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-		SetPageReserved(virt_to_page(addr));
-	}
-
-	return address;
-}
-
-void drm_free_pages (unsigned long address, int order, int area) {
-	unsigned long bytes = PAGE_SIZE << order;
-	int alloc_count;
-	int free_count;
-	unsigned long addr;
-	unsigned int sz;
-
-	if (!address) {
-		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
-	} else {
-		/* Unreserve */
-		for (addr = address, sz = bytes;
-		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-			ClearPageReserved(virt_to_page(addr));
-		}
-		free_pages(address, order);
-	}
-
-	spin_lock(&drm_mem_lock);
-	free_count = ++drm_mem_stats[area].free_count;
-	alloc_count = drm_mem_stats[area].succeed_count;
-	drm_mem_stats[area].bytes_freed += bytes;
-	drm_ram_used -= bytes;
-	spin_unlock(&drm_mem_lock);
-	if (free_count > alloc_count) {
-		DRM_MEM_ERROR(area,
-			      "Excess frees: %d frees, %d allocs\n",
-			      free_count, alloc_count);
-	}
-}
-
 void *drm_ioremap (unsigned long offset, unsigned long size,
 void *drm_ioremap (unsigned long offset, unsigned long size,
 		    drm_device_t * dev) {
 		    drm_device_t * dev) {
 	void *pt;
 	void *pt;

+ 25 - 4
drivers/char/drm/drm_pci.c

@@ -50,6 +50,10 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
 				dma_addr_t maxaddr)
 				dma_addr_t maxaddr)
 {
 {
 	drm_dma_handle_t *dmah;
 	drm_dma_handle_t *dmah;
+#if 1
+	unsigned long addr;
+	size_t sz;
+#endif
 #ifdef DRM_DEBUG_MEMORY
 #ifdef DRM_DEBUG_MEMORY
 	int area = DRM_MEM_DMA;
 	int area = DRM_MEM_DMA;
 
 
@@ -79,7 +83,7 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
 		return NULL;
 		return NULL;
 
 
 	dmah->size = size;
 	dmah->size = size;
-	dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr);
+	dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
 
 
 #ifdef DRM_DEBUG_MEMORY
 #ifdef DRM_DEBUG_MEMORY
 	if (dmah->vaddr == NULL) {
 	if (dmah->vaddr == NULL) {
@@ -104,18 +108,29 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
 
 
 	memset(dmah->vaddr, 0, size);
 	memset(dmah->vaddr, 0, size);
 
 
+	/* XXX - Is virt_to_page() legal for consistent mem? */
+	/* Reserve */
+	for (addr = (unsigned long)dmah->vaddr, sz = size;
+	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+		SetPageReserved(virt_to_page(addr));
+	}
+
 	return dmah;
 	return dmah;
 }
 }
 
 
 EXPORT_SYMBOL(drm_pci_alloc);
 EXPORT_SYMBOL(drm_pci_alloc);
 
 
 /**
 /**
- * \brief Free a PCI consistent memory block with freeing its descriptor.
+ * \brief Free a PCI consistent memory block without freeing its descriptor.
  *
  *
  * This function is for internal use in the Linux-specific DRM core code.
  * This function is for internal use in the Linux-specific DRM core code.
  */
  */
 void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
 void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
 {
 {
+#if 1
+	unsigned long addr;
+	size_t sz;
+#endif
 #ifdef DRM_DEBUG_MEMORY
 #ifdef DRM_DEBUG_MEMORY
 	int area = DRM_MEM_DMA;
 	int area = DRM_MEM_DMA;
 	int alloc_count;
 	int alloc_count;
@@ -127,8 +142,14 @@ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
 		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
 		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
 #endif
 #endif
 	} else {
 	} else {
-		pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr,
-				    dmah->busaddr);
+		/* XXX - Is virt_to_page() legal for consistent mem? */
+		/* Unreserve */
+		for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
+		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+			ClearPageReserved(virt_to_page(addr));
+		}
+		dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
+				  dmah->busaddr);
 	}
 	}
 
 
 #ifdef DRM_DEBUG_MEMORY
 #ifdef DRM_DEBUG_MEMORY

+ 79 - 37
drivers/char/drm/drm_pciids.h

@@ -3,49 +3,69 @@
    Please contact dri-devel@lists.sf.net to add new cards to this list
    Please contact dri-devel@lists.sf.net to add new cards to this list
 */
 */
 #define radeon_PCI_IDS \
 #define radeon_PCI_IDS \
-	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350},\
+	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
 	{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
 	{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
 	{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
 	{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+	{0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP}, \
+	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
 	{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
-	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+	{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
-	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
@@ -53,44 +73,66 @@
 	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
 	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
 	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
-	{0x1002, 0x5837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
 	{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5963, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+	{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x596A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x596B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+	{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
 	{0, 0, 0}
 	{0, 0, 0}
 
 
 #define r128_PCI_IDS \
 #define r128_PCI_IDS \

+ 0 - 2
drivers/char/drm/i915_dma.c

@@ -495,8 +495,6 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
 		}
 		}
 	}
 	}
 
 
-	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
-
 	i915_emit_breadcrumb(dev);
 	i915_emit_breadcrumb(dev);
 
 
 	return 0;
 	return 0;

+ 2 - 0
drivers/char/drm/i915_irq.c

@@ -53,6 +53,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
 
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
 
 
+	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+
 	if (temp & USER_INT_FLAG)
 	if (temp & USER_INT_FLAG)
 		DRM_WAKEUP(&dev_priv->irq_queue);
 		DRM_WAKEUP(&dev_priv->irq_queue);
 
 

+ 78 - 8
drivers/char/drm/r300_cmdbuf.c

@@ -214,13 +214,13 @@ void r300_init_reg_flags(void)
 	ADD_RANGE(0x4F54, 1);
 	ADD_RANGE(0x4F54, 1);
 
 
 	ADD_RANGE(R300_TX_FILTER_0, 16);
 	ADD_RANGE(R300_TX_FILTER_0, 16);
-	ADD_RANGE(R300_TX_UNK1_0, 16);
+	ADD_RANGE(R300_TX_FILTER1_0, 16);
 	ADD_RANGE(R300_TX_SIZE_0, 16);
 	ADD_RANGE(R300_TX_SIZE_0, 16);
 	ADD_RANGE(R300_TX_FORMAT_0, 16);
 	ADD_RANGE(R300_TX_FORMAT_0, 16);
 	ADD_RANGE(R300_TX_PITCH_0, 16);
 	ADD_RANGE(R300_TX_PITCH_0, 16);
 	/* Texture offset is dangerous and needs more checking */
 	/* Texture offset is dangerous and needs more checking */
 	ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
 	ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
-	ADD_RANGE(R300_TX_UNK4_0, 16);
+	ADD_RANGE(R300_TX_CHROMA_KEY_0, 16);
 	ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
 	ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
 
 
 	/* Sporadic registers used as primitives are emitted */
 	/* Sporadic registers used as primitives are emitted */
@@ -242,8 +242,10 @@ static __inline__ int r300_check_range(unsigned reg, int count)
 	return 0;
 	return 0;
 }
 }
 
 
-  /* we expect offsets passed to the framebuffer to be either within video memory or
-     within AGP space */
+/*
+ * we expect offsets passed to the framebuffer to be either within video 
+ * memory or within AGP space 
+ */
 static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
 static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
 					u32 offset)
 					u32 offset)
 {
 {
@@ -251,11 +253,11 @@ static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
 	   but this value is not being kept.
 	   but this value is not being kept.
 	   This code is correct for now (does the same thing as the
 	   This code is correct for now (does the same thing as the
 	   code that sets MC_FB_LOCATION) in radeon_cp.c */
 	   code that sets MC_FB_LOCATION) in radeon_cp.c */
-	if ((offset >= dev_priv->fb_location) &&
-	    (offset < dev_priv->gart_vm_start))
+	if (offset >= dev_priv->fb_location &&
+	    offset < (dev_priv->fb_location + dev_priv->fb_size))
 		return 0;
 		return 0;
-	if ((offset >= dev_priv->gart_vm_start) &&
-	    (offset < dev_priv->gart_vm_start + dev_priv->gart_size))
+	if (offset >= dev_priv->gart_vm_start &&
+	    offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
 		return 0;
 		return 0;
 	return 1;
 	return 1;
 }
 }
@@ -490,6 +492,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
 
 
 	return 0;
 	return 0;
 }
 }
+
 static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
 static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
 					     drm_radeon_kcmd_buffer_t *cmdbuf)
 					     drm_radeon_kcmd_buffer_t *cmdbuf)
 {
 {
@@ -701,6 +704,64 @@ static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
 	buf->used = 0;
 	buf->used = 0;
 }
 }
 
 
+static int r300_scratch(drm_radeon_private_t *dev_priv,
+			drm_radeon_kcmd_buffer_t *cmdbuf,
+			drm_r300_cmd_header_t header)
+{
+	u32 *ref_age_base;
+	u32 i, buf_idx, h_pending;
+	RING_LOCALS;
+	
+	if (cmdbuf->bufsz < 
+	    (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
+		return DRM_ERR(EINVAL);
+	}
+	
+	if (header.scratch.reg >= 5) {
+		return DRM_ERR(EINVAL);
+	}
+	
+	dev_priv->scratch_ages[header.scratch.reg]++;
+	
+	ref_age_base = *(u32 **)cmdbuf->buf;
+	
+	cmdbuf->buf += sizeof(u64);
+	cmdbuf->bufsz -= sizeof(u64);
+	
+	for (i=0; i < header.scratch.n_bufs; i++) {
+		buf_idx = *(u32 *)cmdbuf->buf;
+		buf_idx *= 2; /* 8 bytes per buf */
+		
+		if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		if (h_pending == 0) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		h_pending--;
+						
+		if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		cmdbuf->buf += sizeof(buf_idx);
+		cmdbuf->bufsz -= sizeof(buf_idx);
+	}
+	
+	BEGIN_RING(2);
+	OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0));
+	OUT_RING(dev_priv->scratch_ages[header.scratch.reg]);
+	ADVANCE_RING();
+	
+	return 0;
+}
+
 /**
 /**
  * Parses and validates a user-supplied command buffer and emits appropriate
  * Parses and validates a user-supplied command buffer and emits appropriate
  * commands on the DMA ring buffer.
  * commands on the DMA ring buffer.
@@ -838,6 +899,15 @@ int r300_do_cp_cmdbuf(drm_device_t *dev,
 			}
 			}
 			break;
 			break;
 
 
+		case R300_CMD_SCRATCH:
+			DRM_DEBUG("R300_CMD_SCRATCH\n");
+			ret = r300_scratch(dev_priv, cmdbuf, header);
+			if (ret) {
+				DRM_ERROR("r300_scratch failed\n");
+				goto cleanup;
+			}
+			break;
+			
 		default:
 		default:
 			DRM_ERROR("bad cmd_type %i at %p\n",
 			DRM_ERROR("bad cmd_type %i at %p\n",
 				  header.header.cmd_type,
 				  header.header.cmd_type,

+ 32 - 7
drivers/char/drm/r300_reg.h

@@ -711,8 +711,22 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #	define R300_TX_MAX_ANISO_16_TO_1 (8 << 21)
 #	define R300_TX_MAX_ANISO_16_TO_1 (8 << 21)
 #	define R300_TX_MAX_ANISO_MASK    (14 << 21)
 #	define R300_TX_MAX_ANISO_MASK    (14 << 21)
 
 
-#define R300_TX_UNK1_0                      0x4440
+#define R300_TX_FILTER1_0                      0x4440
+#	define R300_CHROMA_KEY_MODE_DISABLE    0
+#	define R300_CHROMA_KEY_FORCE	       1
+#	define R300_CHROMA_KEY_BLEND           2
+#	define R300_MC_ROUND_NORMAL            (0<<2)
+#	define R300_MC_ROUND_MPEG4             (1<<2)
 #	define R300_LOD_BIAS_MASK	    0x1fff
 #	define R300_LOD_BIAS_MASK	    0x1fff
+#	define R300_EDGE_ANISO_EDGE_DIAG       (0<<13)
+#	define R300_EDGE_ANISO_EDGE_ONLY       (1<<13)
+#	define R300_MC_COORD_TRUNCATE_DISABLE  (0<<14)
+#	define R300_MC_COORD_TRUNCATE_MPEG     (1<<14)
+#	define R300_TX_TRI_PERF_0_8            (0<<15)
+#	define R300_TX_TRI_PERF_1_8            (1<<15)
+#	define R300_TX_TRI_PERF_1_4            (2<<15)
+#	define R300_TX_TRI_PERF_3_8            (3<<15)
+#	define R300_ANISO_THRESHOLD_MASK       (7<<17)
 
 
 #define R300_TX_SIZE_0                      0x4480
 #define R300_TX_SIZE_0                      0x4480
 #       define R300_TX_WIDTHMASK_SHIFT           0
 #       define R300_TX_WIDTHMASK_SHIFT           0
@@ -722,6 +736,8 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #       define R300_TX_UNK23                     (1 << 23)
 #       define R300_TX_UNK23                     (1 << 23)
 #       define R300_TX_SIZE_SHIFT                26	/* largest of width, height */
 #       define R300_TX_SIZE_SHIFT                26	/* largest of width, height */
 #       define R300_TX_SIZE_MASK                 (15 << 26)
 #       define R300_TX_SIZE_MASK                 (15 << 26)
+#       define R300_TX_SIZE_PROJECTED                     (1<<30)
+#       define R300_TX_SIZE_TXPITCH_EN                     (1<<31)
 #define R300_TX_FORMAT_0                    0x44C0
 #define R300_TX_FORMAT_0                    0x44C0
 	/* The interpretation of the format word by Wladimir van der Laan */
 	/* The interpretation of the format word by Wladimir van der Laan */
 	/* The X, Y, Z and W refer to the layout of the components.
 	/* The X, Y, Z and W refer to the layout of the components.
@@ -750,7 +766,8 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #	define R300_TX_FORMAT_B8G8_B8G8	    	    0x14	/* no swizzle */
 #	define R300_TX_FORMAT_B8G8_B8G8	    	    0x14	/* no swizzle */
 #	define R300_TX_FORMAT_G8R8_G8B8	    	    0x15	/* no swizzle */
 #	define R300_TX_FORMAT_G8R8_G8B8	    	    0x15	/* no swizzle */
 						  /* 0x16 - some 16 bit green format.. ?? */
 						  /* 0x16 - some 16 bit green format.. ?? */
-#	define R300_TX_FORMAT_UNK25		   (1 << 25)	/* no swizzle */
+#	define R300_TX_FORMAT_UNK25		   (1 << 25) /* no swizzle */
+#	define R300_TX_FORMAT_CUBIC_MAP		   (1 << 26)
 
 
 	/* gap */
 	/* gap */
 	/* Floating point formats */
 	/* Floating point formats */
@@ -800,18 +817,20 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 
 
 #	define R300_TX_FORMAT_YUV_MODE		0x00800000
 #	define R300_TX_FORMAT_YUV_MODE		0x00800000
 
 
-#define R300_TX_PITCH_0			    0x4500
+#define R300_TX_PITCH_0			    0x4500 /* obvious missing in gap */
 #define R300_TX_OFFSET_0                    0x4540
 #define R300_TX_OFFSET_0                    0x4540
 /* BEGIN: Guess from R200 */
 /* BEGIN: Guess from R200 */
 #       define R300_TXO_ENDIAN_NO_SWAP           (0 << 0)
 #       define R300_TXO_ENDIAN_NO_SWAP           (0 << 0)
 #       define R300_TXO_ENDIAN_BYTE_SWAP         (1 << 0)
 #       define R300_TXO_ENDIAN_BYTE_SWAP         (1 << 0)
 #       define R300_TXO_ENDIAN_WORD_SWAP         (2 << 0)
 #       define R300_TXO_ENDIAN_WORD_SWAP         (2 << 0)
 #       define R300_TXO_ENDIAN_HALFDW_SWAP       (3 << 0)
 #       define R300_TXO_ENDIAN_HALFDW_SWAP       (3 << 0)
+#       define R300_TXO_MACRO_TILE               (1 << 2)
+#       define R300_TXO_MICRO_TILE               (1 << 3)
 #       define R300_TXO_OFFSET_MASK              0xffffffe0
 #       define R300_TXO_OFFSET_MASK              0xffffffe0
 #       define R300_TXO_OFFSET_SHIFT             5
 #       define R300_TXO_OFFSET_SHIFT             5
 /* END */
 /* END */
-#define R300_TX_UNK4_0                      0x4580
-#define R300_TX_BORDER_COLOR_0              0x45C0	//ff00ff00 == { 0, 1.0, 0, 1.0 }
+#define R300_TX_CHROMA_KEY_0                      0x4580 /* 32 bit chroma key */
+#define R300_TX_BORDER_COLOR_0              0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 }
 
 
 /* END */
 /* END */
 
 
@@ -868,7 +887,9 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #       define R300_PFS_NODE_TEX_OFFSET_MASK     (31 << 12)
 #       define R300_PFS_NODE_TEX_OFFSET_MASK     (31 << 12)
 #       define R300_PFS_NODE_TEX_END_SHIFT       17
 #       define R300_PFS_NODE_TEX_END_SHIFT       17
 #       define R300_PFS_NODE_TEX_END_MASK        (31 << 17)
 #       define R300_PFS_NODE_TEX_END_MASK        (31 << 17)
-#       define R300_PFS_NODE_LAST_NODE           (1 << 22)
+/*#       define R300_PFS_NODE_LAST_NODE           (1 << 22) */
+#		define R300_PFS_NODE_OUTPUT_COLOR        (1 << 22)
+#		define R300_PFS_NODE_OUTPUT_DEPTH        (1 << 23)
 
 
 /* TEX
 /* TEX
 // As far as I can tell, texture instructions cannot write into output
 // As far as I can tell, texture instructions cannot write into output
@@ -887,6 +908,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
  */
  */
 #		define R300_FPITX_OPCODE_SHIFT			15
 #		define R300_FPITX_OPCODE_SHIFT			15
 #			define R300_FPITX_OP_TEX			1
 #			define R300_FPITX_OP_TEX			1
+#			define R300_FPITX_OP_KIL			2
 #			define R300_FPITX_OP_TXP			3
 #			define R300_FPITX_OP_TXP			3
 #			define R300_FPITX_OP_TXB			4
 #			define R300_FPITX_OP_TXB			4
 
 
@@ -962,9 +984,11 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #       define R300_FPI1_SRC2C_CONST             (1 << 17)
 #       define R300_FPI1_SRC2C_CONST             (1 << 17)
 #       define R300_FPI1_DSTC_SHIFT              18
 #       define R300_FPI1_DSTC_SHIFT              18
 #       define R300_FPI1_DSTC_MASK               (31 << 18)
 #       define R300_FPI1_DSTC_MASK               (31 << 18)
+#		define R300_FPI1_DSTC_REG_MASK_SHIFT     23
 #       define R300_FPI1_DSTC_REG_X              (1 << 23)
 #       define R300_FPI1_DSTC_REG_X              (1 << 23)
 #       define R300_FPI1_DSTC_REG_Y              (1 << 24)
 #       define R300_FPI1_DSTC_REG_Y              (1 << 24)
 #       define R300_FPI1_DSTC_REG_Z              (1 << 25)
 #       define R300_FPI1_DSTC_REG_Z              (1 << 25)
+#		define R300_FPI1_DSTC_OUTPUT_MASK_SHIFT  26
 #       define R300_FPI1_DSTC_OUTPUT_X           (1 << 26)
 #       define R300_FPI1_DSTC_OUTPUT_X           (1 << 26)
 #       define R300_FPI1_DSTC_OUTPUT_Y           (1 << 27)
 #       define R300_FPI1_DSTC_OUTPUT_Y           (1 << 27)
 #       define R300_FPI1_DSTC_OUTPUT_Z           (1 << 28)
 #       define R300_FPI1_DSTC_OUTPUT_Z           (1 << 28)
@@ -983,6 +1007,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #       define R300_FPI3_DSTA_MASK               (31 << 18)
 #       define R300_FPI3_DSTA_MASK               (31 << 18)
 #       define R300_FPI3_DSTA_REG                (1 << 23)
 #       define R300_FPI3_DSTA_REG                (1 << 23)
 #       define R300_FPI3_DSTA_OUTPUT             (1 << 24)
 #       define R300_FPI3_DSTA_OUTPUT             (1 << 24)
+#		define R300_FPI3_DSTA_DEPTH              (1 << 27)
 
 
 #define R300_PFS_INSTR0_0                   0x48C0
 #define R300_PFS_INSTR0_0                   0x48C0
 #       define R300_FPI0_ARGC_SRC0C_XYZ          0
 #       define R300_FPI0_ARGC_SRC0C_XYZ          0
@@ -1036,7 +1061,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #       define R300_FPI0_OUTC_FRC                (9 << 23)
 #       define R300_FPI0_OUTC_FRC                (9 << 23)
 #       define R300_FPI0_OUTC_REPL_ALPHA         (10 << 23)
 #       define R300_FPI0_OUTC_REPL_ALPHA         (10 << 23)
 #       define R300_FPI0_OUTC_SAT                (1 << 30)
 #       define R300_FPI0_OUTC_SAT                (1 << 30)
-#       define R300_FPI0_UNKNOWN_31              (1 << 31)
+#       define R300_FPI0_INSERT_NOP              (1 << 31)
 
 
 #define R300_PFS_INSTR2_0                   0x49C0
 #define R300_PFS_INSTR2_0                   0x49C0
 #       define R300_FPI2_ARGA_SRC0C_X            0
 #       define R300_FPI2_ARGA_SRC0C_X            0

+ 108 - 43
drivers/char/drm/radeon_cp.c

@@ -1118,14 +1118,20 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
 {
 {
 	u32 ring_start, cur_read_ptr;
 	u32 ring_start, cur_read_ptr;
 	u32 tmp;
 	u32 tmp;
-
-	/* Initialize the memory controller */
-	RADEON_WRITE(RADEON_MC_FB_LOCATION,
-		     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
-		     | (dev_priv->fb_location >> 16));
+	
+	/* Initialize the memory controller. With new memory map, the fb location
+	 * is not changed, it should have been properly initialized already. Part
+	 * of the problem is that the code below is bogus, assuming the GART is
+	 * always appended to the fb which is not necessarily the case
+	 */
+	if (!dev_priv->new_memmap)
+		RADEON_WRITE(RADEON_MC_FB_LOCATION,
+			     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
+			     | (dev_priv->fb_location >> 16));
 
 
 #if __OS_HAS_AGP
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP) {
 	if (dev_priv->flags & CHIP_IS_AGP) {
+		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
 			     (((dev_priv->gart_vm_start - 1 +
 			     (((dev_priv->gart_vm_start - 1 +
 				dev_priv->gart_size) & 0xffff0000) |
 				dev_priv->gart_size) & 0xffff0000) |
@@ -1153,8 +1159,6 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
 
 
 #if __OS_HAS_AGP
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP) {
 	if (dev_priv->flags & CHIP_IS_AGP) {
-		/* set RADEON_AGP_BASE here instead of relying on X from user space */
-		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
 		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
 			     dev_priv->ring_rptr->offset
 			     dev_priv->ring_rptr->offset
 			     - dev->agp->base + dev_priv->gart_vm_start);
 			     - dev->agp->base + dev_priv->gart_vm_start);
@@ -1174,6 +1178,17 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
 			  entry->handle + tmp_ofs);
 			  entry->handle + tmp_ofs);
 	}
 	}
 
 
+	/* Set ring buffer size */
+#ifdef __BIG_ENDIAN
+	RADEON_WRITE(RADEON_CP_RB_CNTL,
+		     dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT);
+#else
+	RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw);
+#endif
+
+	/* Start with assuming that writeback doesn't work */
+	dev_priv->writeback_works = 0;
+
 	/* Initialize the scratch register pointer.  This will cause
 	/* Initialize the scratch register pointer.  This will cause
 	 * the scratch register values to be written out to memory
 	 * the scratch register values to be written out to memory
 	 * whenever they are updated.
 	 * whenever they are updated.
@@ -1190,28 +1205,9 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
 
 
 	RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
 	RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
 
 
-	/* Writeback doesn't seem to work everywhere, test it first */
-	DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
-	RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
-
-	for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
-		if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
-		    0xdeadbeef)
-			break;
-		DRM_UDELAY(1);
-	}
-
-	if (tmp < dev_priv->usec_timeout) {
-		dev_priv->writeback_works = 1;
-		DRM_DEBUG("writeback test succeeded, tmp=%d\n", tmp);
-	} else {
-		dev_priv->writeback_works = 0;
-		DRM_DEBUG("writeback test failed\n");
-	}
-	if (radeon_no_wb == 1) {
-		dev_priv->writeback_works = 0;
-		DRM_DEBUG("writeback forced off\n");
-	}
+	/* Turn on bus mastering */
+	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
 
 
 	dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
 	dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
 	RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
 	RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
@@ -1223,26 +1219,45 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
 	dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0;
 	dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0;
 	RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear);
 	RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear);
 
 
-	/* Set ring buffer size */
-#ifdef __BIG_ENDIAN
-	RADEON_WRITE(RADEON_CP_RB_CNTL,
-		     dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT);
-#else
-	RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw);
-#endif
-
 	radeon_do_wait_for_idle(dev_priv);
 	radeon_do_wait_for_idle(dev_priv);
 
 
-	/* Turn on bus mastering */
-	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
-	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
-
 	/* Sync everything up */
 	/* Sync everything up */
 	RADEON_WRITE(RADEON_ISYNC_CNTL,
 	RADEON_WRITE(RADEON_ISYNC_CNTL,
 		     (RADEON_ISYNC_ANY2D_IDLE3D |
 		     (RADEON_ISYNC_ANY2D_IDLE3D |
 		      RADEON_ISYNC_ANY3D_IDLE2D |
 		      RADEON_ISYNC_ANY3D_IDLE2D |
 		      RADEON_ISYNC_WAIT_IDLEGUI |
 		      RADEON_ISYNC_WAIT_IDLEGUI |
 		      RADEON_ISYNC_CPSCRATCH_IDLEGUI));
 		      RADEON_ISYNC_CPSCRATCH_IDLEGUI));
+
+}
+
+static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
+{
+	u32 tmp;
+
+	/* Writeback doesn't seem to work everywhere, test it here and possibly
+	 * enable it if it appears to work
+	 */
+	DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
+	RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
+
+	for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
+		if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
+		    0xdeadbeef)
+			break;
+		DRM_UDELAY(1);
+	}
+
+	if (tmp < dev_priv->usec_timeout) {
+		dev_priv->writeback_works = 1;
+		DRM_INFO("writeback test succeeded in %d usecs\n", tmp);
+	} else {
+		dev_priv->writeback_works = 0;
+		DRM_INFO("writeback test failed\n");
+	}
+	if (radeon_no_wb == 1) {
+		dev_priv->writeback_works = 0;
+		DRM_INFO("writeback forced off\n");
+	}
 }
 }
 
 
 /* Enable or disable PCI-E GART on the chip */
 /* Enable or disable PCI-E GART on the chip */
@@ -1317,6 +1332,14 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 
 
 	DRM_DEBUG("\n");
 	DRM_DEBUG("\n");
 
 
+	/* if we require new memory map but we don't have it fail */
+	if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
+	{
+		DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n");
+		radeon_do_cleanup_cp(dev);
+		return DRM_ERR(EINVAL);
+	}
+
 	if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
 	if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
 	{
 	{
 		DRM_DEBUG("Forcing AGP card to PCI mode\n");
 		DRM_DEBUG("Forcing AGP card to PCI mode\n");
@@ -1496,6 +1519,9 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 
 
 	dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION)
 	dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION)
 				 & 0xffff) << 16;
 				 & 0xffff) << 16;
+	dev_priv->fb_size = 
+		((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000)
+		- dev_priv->fb_location;
 
 
 	dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
 	dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
 					((dev_priv->front_offset
 					((dev_priv->front_offset
@@ -1510,8 +1536,46 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 					  + dev_priv->fb_location) >> 10));
 					  + dev_priv->fb_location) >> 10));
 
 
 	dev_priv->gart_size = init->gart_size;
 	dev_priv->gart_size = init->gart_size;
-	dev_priv->gart_vm_start = dev_priv->fb_location
-	    + RADEON_READ(RADEON_CONFIG_APER_SIZE);
+
+	/* New let's set the memory map ... */
+	if (dev_priv->new_memmap) {
+		u32 base = 0;
+
+		DRM_INFO("Setting GART location based on new memory map\n");
+
+		/* If using AGP, try to locate the AGP aperture at the same
+		 * location in the card and on the bus, though we have to
+		 * align it down.
+		 */
+#if __OS_HAS_AGP
+		if (dev_priv->flags & CHIP_IS_AGP) {
+			base = dev->agp->base;
+			/* Check if valid */
+			if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
+			    base < (dev_priv->fb_location + dev_priv->fb_size)) {
+				DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
+					 dev->agp->base);
+				base = 0;
+			}
+		}
+#endif
+		/* If not or if AGP is at 0 (Macs), try to put it elsewhere */
+		if (base == 0) {
+			base = dev_priv->fb_location + dev_priv->fb_size;
+			if (((base + dev_priv->gart_size) & 0xfffffffful)
+			    < base)
+				base = dev_priv->fb_location
+					- dev_priv->gart_size;
+		}		
+		dev_priv->gart_vm_start = base & 0xffc00000u;
+		if (dev_priv->gart_vm_start != base)
+			DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
+				 base, dev_priv->gart_vm_start);
+	} else {
+		DRM_INFO("Setting GART location based on old memory map\n");
+		dev_priv->gart_vm_start = dev_priv->fb_location +
+			RADEON_READ(RADEON_CONFIG_APER_SIZE);
+	}
 
 
 #if __OS_HAS_AGP
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP)
 	if (dev_priv->flags & CHIP_IS_AGP)
@@ -1596,6 +1660,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 	dev_priv->last_buf = 0;
 	dev_priv->last_buf = 0;
 
 
 	radeon_do_engine_reset(dev);
 	radeon_do_engine_reset(dev);
+	radeon_test_writeback(dev_priv);
 
 
 	return 0;
 	return 0;
 }
 }

+ 5 - 0
drivers/char/drm/radeon_drm.h

@@ -222,6 +222,7 @@ typedef union {
 #	define R300_WAIT_3D  		0x2
 #	define R300_WAIT_3D  		0x2
 #	define R300_WAIT_2D_CLEAN  	0x3
 #	define R300_WAIT_2D_CLEAN  	0x3
 #	define R300_WAIT_3D_CLEAN  	0x4
 #	define R300_WAIT_3D_CLEAN  	0x4
+#define R300_CMD_SCRATCH		8
 
 
 typedef union {
 typedef union {
 	unsigned int u;
 	unsigned int u;
@@ -247,6 +248,9 @@ typedef union {
 	struct {
 	struct {
 		unsigned char cmd_type, flags, pad0, pad1;
 		unsigned char cmd_type, flags, pad0, pad1;
 	} wait;
 	} wait;
+	struct {
+		unsigned char cmd_type, reg, n_bufs, flags;
+	} scratch;
 } drm_r300_cmd_header_t;
 } drm_r300_cmd_header_t;
 
 
 #define RADEON_FRONT			0x1
 #define RADEON_FRONT			0x1
@@ -697,6 +701,7 @@ typedef struct drm_radeon_setparam {
 #define RADEON_SETPARAM_FB_LOCATION    1	/* determined framebuffer location */
 #define RADEON_SETPARAM_FB_LOCATION    1	/* determined framebuffer location */
 #define RADEON_SETPARAM_SWITCH_TILING  2	/* enable/disable color tiling */
 #define RADEON_SETPARAM_SWITCH_TILING  2	/* enable/disable color tiling */
 #define RADEON_SETPARAM_PCIGART_LOCATION 3	/* PCI Gart Location */
 #define RADEON_SETPARAM_PCIGART_LOCATION 3	/* PCI Gart Location */
+#define RADEON_SETPARAM_NEW_MEMMAP 4		/* Use new memory map */
 
 
 /* 1.14: Clients can allocate/free a surface
 /* 1.14: Clients can allocate/free a surface
  */
  */

+ 17 - 8
drivers/char/drm/radeon_drv.h

@@ -38,7 +38,7 @@
 
 
 #define DRIVER_NAME		"radeon"
 #define DRIVER_NAME		"radeon"
 #define DRIVER_DESC		"ATI Radeon"
 #define DRIVER_DESC		"ATI Radeon"
-#define DRIVER_DATE		"20051229"
+#define DRIVER_DATE		"20060225"
 
 
 /* Interface history:
 /* Interface history:
  *
  *
@@ -91,9 +91,11 @@
  * 1.20- Add support for r300 texrect
  * 1.20- Add support for r300 texrect
  * 1.21- Add support for card type getparam
  * 1.21- Add support for card type getparam
  * 1.22- Add support for texture cache flushes (R300_TX_CNTL)
  * 1.22- Add support for texture cache flushes (R300_TX_CNTL)
+ * 1.23- Add new radeon memory map work from benh
+ * 1.24- Add general-purpose packet for manipulating scratch registers (r300)
  */
  */
 #define DRIVER_MAJOR		1
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		22
+#define DRIVER_MINOR		24
 #define DRIVER_PATCHLEVEL	0
 #define DRIVER_PATCHLEVEL	0
 
 
 /*
 /*
@@ -101,20 +103,21 @@
  */
  */
 enum radeon_family {
 enum radeon_family {
 	CHIP_R100,
 	CHIP_R100,
-	CHIP_RS100,
 	CHIP_RV100,
 	CHIP_RV100,
+	CHIP_RS100,
 	CHIP_RV200,
 	CHIP_RV200,
-	CHIP_R200,
 	CHIP_RS200,
 	CHIP_RS200,
-	CHIP_R250,
-	CHIP_RS250,
+	CHIP_R200,
 	CHIP_RV250,
 	CHIP_RV250,
+	CHIP_RS300,
 	CHIP_RV280,
 	CHIP_RV280,
 	CHIP_R300,
 	CHIP_R300,
-	CHIP_RS300,
 	CHIP_R350,
 	CHIP_R350,
 	CHIP_RV350,
 	CHIP_RV350,
+	CHIP_RV380,
 	CHIP_R420,
 	CHIP_R420,
+	CHIP_RV410,
+	CHIP_RS400,
 	CHIP_LAST,
 	CHIP_LAST,
 };
 };
 
 
@@ -136,9 +139,11 @@ enum radeon_chip_flags {
 	CHIP_IS_AGP = 0x00080000UL,
 	CHIP_IS_AGP = 0x00080000UL,
 	CHIP_HAS_HIERZ = 0x00100000UL,
 	CHIP_HAS_HIERZ = 0x00100000UL,
 	CHIP_IS_PCIE = 0x00200000UL,
 	CHIP_IS_PCIE = 0x00200000UL,
+	CHIP_NEW_MEMMAP = 0x00400000UL,
 };
 };
 
 
-#define GET_RING_HEAD(dev_priv)		DRM_READ32(  (dev_priv)->ring_rptr, 0 )
+#define GET_RING_HEAD(dev_priv)	(dev_priv->writeback_works ? \
+        DRM_READ32(  (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR))
 #define SET_RING_HEAD(dev_priv,val)	DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) )
 #define SET_RING_HEAD(dev_priv,val)	DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) )
 
 
 typedef struct drm_radeon_freelist {
 typedef struct drm_radeon_freelist {
@@ -199,6 +204,8 @@ typedef struct drm_radeon_private {
 	drm_radeon_sarea_t *sarea_priv;
 	drm_radeon_sarea_t *sarea_priv;
 
 
 	u32 fb_location;
 	u32 fb_location;
+	u32 fb_size;
+	int new_memmap;
 
 
 	int gart_size;
 	int gart_size;
 	u32 gart_vm_start;
 	u32 gart_vm_start;
@@ -272,6 +279,8 @@ typedef struct drm_radeon_private {
 	unsigned long pcigart_offset;
 	unsigned long pcigart_offset;
 	drm_ati_pcigart_info gart_info;
 	drm_ati_pcigart_info gart_info;
 
 
+	u32 scratch_ages[5];
+
 	/* starting from here on, data is preserved accross an open */
 	/* starting from here on, data is preserved accross an open */
 	uint32_t flags;		/* see radeon_chip_flags */
 	uint32_t flags;		/* see radeon_chip_flags */
 } drm_radeon_private_t;
 } drm_radeon_private_t;

+ 47 - 58
drivers/char/drm/radeon_state.c

@@ -45,22 +45,53 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
 	u32 off = *offset;
 	u32 off = *offset;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 
 
-	if (off >= dev_priv->fb_location &&
-	    off < (dev_priv->gart_vm_start + dev_priv->gart_size))
-		return 0;
-
-	radeon_priv = filp_priv->driver_priv;
-	off += radeon_priv->radeon_fb_delta;
+	/* Hrm ... the story of the offset ... So this function converts
+	 * the various ideas of what userland clients might have for an
+	 * offset in the card address space into an offset into the card
+	 * address space :) So with a sane client, it should just keep
+	 * the value intact and just do some boundary checking. However,
+	 * not all clients are sane. Some older clients pass us 0 based
+	 * offsets relative to the start of the framebuffer and some may
+	 * assume the AGP aperture it appended to the framebuffer, so we
+	 * try to detect those cases and fix them up.
+	 *
+	 * Note: It might be a good idea here to make sure the offset lands
+	 * in some "allowed" area to protect things like the PCIE GART...
+	 */
 
 
-	DRM_DEBUG("offset fixed up to 0x%x\n", off);
+	/* First, the best case, the offset already lands in either the
+	 * framebuffer or the GART mapped space
+	 */
+	if ((off >= dev_priv->fb_location &&
+	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+	    (off >= dev_priv->gart_vm_start &&
+	     off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
+		return 0;
 
 
-	if (off < dev_priv->fb_location ||
-	    off >= (dev_priv->gart_vm_start + dev_priv->gart_size))
-		return DRM_ERR(EINVAL);
+	/* Ok, that didn't happen... now check if we have a zero based
+	 * offset that fits in the framebuffer + gart space, apply the
+	 * magic offset we get from SETPARAM or calculated from fb_location
+	 */
+	if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
+		radeon_priv = filp_priv->driver_priv;
+		off += radeon_priv->radeon_fb_delta;
+	}
 
 
-	*offset = off;
+	/* Finally, assume we aimed at a GART offset if beyond the fb */
+	if (off > (dev_priv->fb_location + dev_priv->fb_size))
+		off = off - (dev_priv->fb_location + dev_priv->fb_size) +
+			dev_priv->gart_vm_start;
 
 
-	return 0;
+	/* Now recheck and fail if out of bounds */
+	if ((off >= dev_priv->fb_location &&
+	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+	    (off >= dev_priv->gart_vm_start &&
+	     off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
+		DRM_DEBUG("offset fixed up to 0x%x\n", off);
+		*offset = off;
+		return 0;
+	}
+	return DRM_ERR(EINVAL);
 }
 }
 
 
 static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
 static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
@@ -1939,11 +1970,6 @@ static int radeon_surface_alloc(DRM_IOCTL_ARGS)
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_surface_alloc_t alloc;
 	drm_radeon_surface_alloc_t alloc;
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(alloc,
 	DRM_COPY_FROM_USER_IOCTL(alloc,
 				 (drm_radeon_surface_alloc_t __user *) data,
 				 (drm_radeon_surface_alloc_t __user *) data,
 				 sizeof(alloc));
 				 sizeof(alloc));
@@ -1960,12 +1986,7 @@ static int radeon_surface_free(DRM_IOCTL_ARGS)
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_surface_free_t memfree;
 	drm_radeon_surface_free_t memfree;
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
-	DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
+	DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
 				 sizeof(memfree));
 				 sizeof(memfree));
 
 
 	if (free_surface(filp, dev_priv, memfree.address))
 	if (free_surface(filp, dev_priv, memfree.address))
@@ -2100,11 +2121,6 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
 
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
@@ -2189,11 +2205,6 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
 
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 
 	DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
 	DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
@@ -2340,11 +2351,6 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
 
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(indirect,
 	DRM_COPY_FROM_USER_IOCTL(indirect,
 				 (drm_radeon_indirect_t __user *) data,
 				 (drm_radeon_indirect_t __user *) data,
 				 sizeof(indirect));
 				 sizeof(indirect));
@@ -2417,11 +2423,6 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
 
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
@@ -2738,11 +2739,6 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
 
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 
 	DRM_COPY_FROM_USER_IOCTL(cmdbuf,
 	DRM_COPY_FROM_USER_IOCTL(cmdbuf,
@@ -2897,11 +2893,6 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
 	drm_radeon_getparam_t param;
 	drm_radeon_getparam_t param;
 	int value;
 	int value;
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
 	DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
 				 sizeof(param));
 				 sizeof(param));
 
 
@@ -2981,11 +2972,6 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
 	drm_radeon_setparam_t sp;
 	drm_radeon_setparam_t sp;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 
 	DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
 	DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
@@ -3012,6 +2998,9 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
 	case RADEON_SETPARAM_PCIGART_LOCATION:
 	case RADEON_SETPARAM_PCIGART_LOCATION:
 		dev_priv->pcigart_offset = sp.value;
 		dev_priv->pcigart_offset = sp.value;
 		break;
 		break;
+	case RADEON_SETPARAM_NEW_MEMMAP:
+		dev_priv->new_memmap = sp.value;
+		break;
 	default:
 	default:
 		DRM_DEBUG("Invalid parameter %d\n", sp.param);
 		DRM_DEBUG("Invalid parameter %d\n", sp.param);
 		return DRM_ERR(EINVAL);
 		return DRM_ERR(EINVAL);

+ 1 - 1
drivers/char/drm/sis_mm.c

@@ -110,7 +110,7 @@ static int sis_fb_alloc(DRM_IOCTL_ARGS)
 
 
 	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
 	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
 
 
-	DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
+	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
 
 
 	return retval;
 	return retval;
 }
 }

+ 101 - 11
drivers/infiniband/core/mad.c

@@ -227,6 +227,14 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
 			if (!is_vendor_oui(mad_reg_req->oui))
 			if (!is_vendor_oui(mad_reg_req->oui))
 				goto error1;
 				goto error1;
 		}
 		}
+		/* Make sure class supplied is consistent with RMPP */
+		if (ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) {
+			if (!rmpp_version)
+				goto error1;
+		} else {
+			if (rmpp_version)
+				goto error1;
+		}
 		/* Make sure class supplied is consistent with QP type */
 		/* Make sure class supplied is consistent with QP type */
 		if (qp_type == IB_QPT_SMI) {
 		if (qp_type == IB_QPT_SMI) {
 			if ((mad_reg_req->mgmt_class !=
 			if ((mad_reg_req->mgmt_class !=
@@ -890,6 +898,35 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
 }
 }
 EXPORT_SYMBOL(ib_create_send_mad);
 EXPORT_SYMBOL(ib_create_send_mad);
 
 
+int ib_get_mad_data_offset(u8 mgmt_class)
+{
+	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
+		return IB_MGMT_SA_HDR;
+	else if ((mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) ||
+		 (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) ||
+		 (mgmt_class == IB_MGMT_CLASS_BIS))
+		return IB_MGMT_DEVICE_HDR;
+	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
+		return IB_MGMT_VENDOR_HDR;
+	else
+		return IB_MGMT_MAD_HDR;
+}
+EXPORT_SYMBOL(ib_get_mad_data_offset);
+
+int ib_is_mad_class_rmpp(u8 mgmt_class)
+{
+	if ((mgmt_class == IB_MGMT_CLASS_SUBN_ADM) ||
+	    (mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) ||
+	    (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) ||
+	    (mgmt_class == IB_MGMT_CLASS_BIS) ||
+	    ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+	     (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)))
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(ib_is_mad_class_rmpp);
+
 void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num)
 void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num)
 {
 {
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wr_private *mad_send_wr;
@@ -1022,6 +1059,13 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
 			goto error;
 			goto error;
 		}
 		}
 
 
+		if (!ib_is_mad_class_rmpp(((struct ib_mad_hdr *) send_buf->mad)->mgmt_class)) {
+			if (mad_agent_priv->agent.rmpp_version) {
+				ret = -EINVAL;
+				goto error;
+			}
+		}
+
 		/*
 		/*
 		 * Save pointer to next work request to post in case the
 		 * Save pointer to next work request to post in case the
 		 * current one completes, and the user modifies the work
 		 * current one completes, and the user modifies the work
@@ -1618,14 +1662,59 @@ static int is_data_mad(struct ib_mad_agent_private *mad_agent_priv,
 		(rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA);
 		(rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA);
 }
 }
 
 
+static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr,
+				     struct ib_mad_recv_wc *rwc)
+{
+	return ((struct ib_mad *)(wr->send_buf.mad))->mad_hdr.mgmt_class ==
+		rwc->recv_buf.mad->mad_hdr.mgmt_class;
+}
+
+static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr,
+				   struct ib_mad_recv_wc *rwc )
+{
+	struct ib_ah_attr attr;
+	u8 send_resp, rcv_resp;
+
+	send_resp = ((struct ib_mad *)(wr->send_buf.mad))->
+		     mad_hdr.method & IB_MGMT_METHOD_RESP;
+	rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
+
+	if (!send_resp && rcv_resp)
+		/* is request/response. GID/LIDs are both local (same). */
+		return 1;
+
+	if (send_resp == rcv_resp)
+		/* both requests, or both responses. GIDs different */
+		return 0;
+
+	if (ib_query_ah(wr->send_buf.ah, &attr))
+		/* Assume not equal, to avoid false positives. */
+		return 0;
+
+	if (!(attr.ah_flags & IB_AH_GRH) && !(rwc->wc->wc_flags & IB_WC_GRH))
+		return attr.dlid == rwc->wc->slid;
+	else if ((attr.ah_flags & IB_AH_GRH) &&
+		 (rwc->wc->wc_flags & IB_WC_GRH))
+		return memcmp(attr.grh.dgid.raw,
+			      rwc->recv_buf.grh->sgid.raw, 16) == 0;
+	else
+		/* one has GID, other does not.  Assume different */
+		return 0;
+}
 struct ib_mad_send_wr_private*
 struct ib_mad_send_wr_private*
-ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid)
+ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
+		 struct ib_mad_recv_wc *mad_recv_wc)
 {
 {
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wr_private *mad_send_wr;
+	struct ib_mad *mad;
+
+	mad = (struct ib_mad *)mad_recv_wc->recv_buf.mad;
 
 
 	list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list,
 	list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list,
 			    agent_list) {
 			    agent_list) {
-		if (mad_send_wr->tid == tid)
+		if ((mad_send_wr->tid == mad->mad_hdr.tid) &&
+		    rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
+		    rcv_has_same_gid(mad_send_wr, mad_recv_wc))
 			return mad_send_wr;
 			return mad_send_wr;
 	}
 	}
 
 
@@ -1636,7 +1725,10 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid)
 	list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list,
 	list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list,
 			    agent_list) {
 			    agent_list) {
 		if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) &&
 		if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) &&
-		    mad_send_wr->tid == tid && mad_send_wr->timeout) {
+		    mad_send_wr->tid == mad->mad_hdr.tid &&
+		    mad_send_wr->timeout &&
+		    rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
+		    rcv_has_same_gid(mad_send_wr, mad_recv_wc)) {
 			/* Verify request has not been canceled */
 			/* Verify request has not been canceled */
 			return (mad_send_wr->status == IB_WC_SUCCESS) ?
 			return (mad_send_wr->status == IB_WC_SUCCESS) ?
 				mad_send_wr : NULL;
 				mad_send_wr : NULL;
@@ -1661,7 +1753,6 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wc mad_send_wc;
 	struct ib_mad_send_wc mad_send_wc;
 	unsigned long flags;
 	unsigned long flags;
-	__be64 tid;
 
 
 	INIT_LIST_HEAD(&mad_recv_wc->rmpp_list);
 	INIT_LIST_HEAD(&mad_recv_wc->rmpp_list);
 	list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
 	list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
@@ -1677,9 +1768,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
 
 
 	/* Complete corresponding request */
 	/* Complete corresponding request */
 	if (response_mad(mad_recv_wc->recv_buf.mad)) {
 	if (response_mad(mad_recv_wc->recv_buf.mad)) {
-		tid = mad_recv_wc->recv_buf.mad->mad_hdr.tid;
 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
-		mad_send_wr = ib_find_send_mad(mad_agent_priv, tid);
+		mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
 		if (!mad_send_wr) {
 		if (!mad_send_wr) {
 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 			ib_free_recv_mad(mad_recv_wc);
 			ib_free_recv_mad(mad_recv_wc);
@@ -2408,11 +2498,11 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
 			}
 			}
 		}
 		}
 		sg_list.addr = dma_map_single(qp_info->port_priv->
 		sg_list.addr = dma_map_single(qp_info->port_priv->
-						device->dma_device,
-					&mad_priv->grh,
-					sizeof *mad_priv -
-						sizeof mad_priv->header,
-					DMA_FROM_DEVICE);
+					      	device->dma_device,
+					      &mad_priv->grh,
+					      sizeof *mad_priv -
+					      	sizeof mad_priv->header,
+					      DMA_FROM_DEVICE);
 		pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr);
 		pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr);
 		recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list;
 		recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list;
 		mad_priv->header.mad_list.mad_queue = recv_queue;
 		mad_priv->header.mad_list.mad_queue = recv_queue;

+ 2 - 1
drivers/infiniband/core/mad_priv.h

@@ -216,7 +216,8 @@ extern kmem_cache_t *ib_mad_cache;
 int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr);
 int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr);
 
 
 struct ib_mad_send_wr_private *
 struct ib_mad_send_wr_private *
-ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid);
+ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
+		 struct ib_mad_recv_wc *mad_recv_wc);
 
 
 void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
 void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
 			     struct ib_mad_send_wc *mad_send_wc);
 			     struct ib_mad_send_wc *mad_send_wc);

+ 17 - 37
drivers/infiniband/core/mad_rmpp.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright (c) 2005 Intel Inc. All rights reserved.
  * Copyright (c) 2005 Intel Inc. All rights reserved.
- * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved.
  *
  *
  * This software is available to you under a choice of one of two
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -100,17 +100,6 @@ void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent)
 	}
 	}
 }
 }
 
 
-static int data_offset(u8 mgmt_class)
-{
-	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
-		return IB_MGMT_SA_HDR;
-	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
-		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
-		return IB_MGMT_VENDOR_HDR;
-	else
-		return IB_MGMT_RMPP_HDR;
-}
-
 static void format_ack(struct ib_mad_send_buf *msg,
 static void format_ack(struct ib_mad_send_buf *msg,
 		       struct ib_rmpp_mad *data,
 		       struct ib_rmpp_mad *data,
 		       struct mad_rmpp_recv *rmpp_recv)
 		       struct mad_rmpp_recv *rmpp_recv)
@@ -137,7 +126,7 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv,
 	struct ib_mad_send_buf *msg;
 	struct ib_mad_send_buf *msg;
 	int ret, hdr_len;
 	int ret, hdr_len;
 
 
-	hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
+	hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
 	msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
 	msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
 				 recv_wc->wc->pkey_index, 1, hdr_len,
 				 recv_wc->wc->pkey_index, 1, hdr_len,
 				 0, GFP_KERNEL);
 				 0, GFP_KERNEL);
@@ -163,7 +152,7 @@ static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent,
 	if (IS_ERR(ah))
 	if (IS_ERR(ah))
 		return (void *) ah;
 		return (void *) ah;
 
 
-	hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
+	hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
 	msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,
 	msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,
 				 recv_wc->wc->pkey_index, 1,
 				 recv_wc->wc->pkey_index, 1,
 				 hdr_len, 0, GFP_KERNEL);
 				 hdr_len, 0, GFP_KERNEL);
@@ -408,7 +397,7 @@ static inline int get_mad_len(struct mad_rmpp_recv *rmpp_recv)
 
 
 	rmpp_mad = (struct ib_rmpp_mad *)rmpp_recv->cur_seg_buf->mad;
 	rmpp_mad = (struct ib_rmpp_mad *)rmpp_recv->cur_seg_buf->mad;
 
 
-	hdr_size = data_offset(rmpp_mad->mad_hdr.mgmt_class);
+	hdr_size = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
 	data_size = sizeof(struct ib_rmpp_mad) - hdr_size;
 	data_size = sizeof(struct ib_rmpp_mad) - hdr_size;
 	pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 	pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 	if (pad > IB_MGMT_RMPP_DATA || pad < 0)
 	if (pad > IB_MGMT_RMPP_DATA || pad < 0)
@@ -562,15 +551,15 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
 	return ib_send_mad(mad_send_wr);
 	return ib_send_mad(mad_send_wr);
 }
 }
 
 
-static void abort_send(struct ib_mad_agent_private *agent, __be64 tid,
-		       u8 rmpp_status)
+static void abort_send(struct ib_mad_agent_private *agent,
+		       struct ib_mad_recv_wc *mad_recv_wc, u8 rmpp_status)
 {
 {
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wr_private *mad_send_wr;
 	struct ib_mad_send_wc wc;
 	struct ib_mad_send_wc wc;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&agent->lock, flags);
 	spin_lock_irqsave(&agent->lock, flags);
-	mad_send_wr = ib_find_send_mad(agent, tid);
+	mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
 	if (!mad_send_wr)
 	if (!mad_send_wr)
 		goto out;	/* Unmatched send */
 		goto out;	/* Unmatched send */
 
 
@@ -612,8 +601,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
 
 
 	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
 	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
 	if (rmpp_mad->rmpp_hdr.rmpp_status) {
 	if (rmpp_mad->rmpp_hdr.rmpp_status) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BAD_STATUS);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		return;
 		return;
 	}
 	}
@@ -621,14 +609,13 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
 	seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);
 	seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);
 	newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 	newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 	if (newwin < seg_num) {
 	if (newwin < seg_num) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_W2S);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
 		return;
 		return;
 	}
 	}
 
 
 	spin_lock_irqsave(&agent->lock, flags);
 	spin_lock_irqsave(&agent->lock, flags);
-	mad_send_wr = ib_find_send_mad(agent, rmpp_mad->mad_hdr.tid);
+	mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
 	if (!mad_send_wr)
 	if (!mad_send_wr)
 		goto out;	/* Unmatched ACK */
 		goto out;	/* Unmatched ACK */
 
 
@@ -639,8 +626,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
 	if (seg_num > mad_send_wr->send_buf.seg_count ||
 	if (seg_num > mad_send_wr->send_buf.seg_count ||
 	    seg_num > mad_send_wr->newwin) {
 	    seg_num > mad_send_wr->newwin) {
 		spin_unlock_irqrestore(&agent->lock, flags);
 		spin_unlock_irqrestore(&agent->lock, flags);
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_S2B);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);
 		return;
 		return;
 	}
 	}
@@ -728,12 +714,10 @@ static void process_rmpp_stop(struct ib_mad_agent_private *agent,
 	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
 	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
 
 
 	if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) {
 	if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BAD_STATUS);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 	} else
 	} else
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   rmpp_mad->rmpp_hdr.rmpp_status);
+		abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);
 }
 }
 
 
 static void process_rmpp_abort(struct ib_mad_agent_private *agent,
 static void process_rmpp_abort(struct ib_mad_agent_private *agent,
@@ -745,12 +729,10 @@ static void process_rmpp_abort(struct ib_mad_agent_private *agent,
 
 
 	if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN ||
 	if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN ||
 	    rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) {
 	    rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BAD_STATUS);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
 	} else
 	} else
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   rmpp_mad->rmpp_hdr.rmpp_status);
+		abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);
 }
 }
 
 
 struct ib_mad_recv_wc *
 struct ib_mad_recv_wc *
@@ -764,8 +746,7 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,
 		return mad_recv_wc;
 		return mad_recv_wc;
 
 
 	if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) {
 	if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) {
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_UNV);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);
 		goto out;
 		goto out;
 	}
 	}
@@ -783,8 +764,7 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,
 		process_rmpp_abort(agent, mad_recv_wc);
 		process_rmpp_abort(agent, mad_recv_wc);
 		break;
 		break;
 	default:
 	default:
-		abort_send(agent, rmpp_mad->mad_hdr.tid,
-			   IB_MGMT_RMPP_STATUS_BADT);
+		abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
 		nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);
 		break;
 		break;
 	}
 	}

+ 6 - 24
drivers/infiniband/core/user_mad.c

@@ -177,17 +177,6 @@ static int queue_packet(struct ib_umad_file *file,
 	return ret;
 	return ret;
 }
 }
 
 
-static int data_offset(u8 mgmt_class)
-{
-	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
-		return IB_MGMT_SA_HDR;
-	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
-		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
-		return IB_MGMT_VENDOR_HDR;
-	else
-		return IB_MGMT_RMPP_HDR;
-}
-
 static void send_handler(struct ib_mad_agent *agent,
 static void send_handler(struct ib_mad_agent *agent,
 			 struct ib_mad_send_wc *send_wc)
 			 struct ib_mad_send_wc *send_wc)
 {
 {
@@ -283,7 +272,7 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
 			 */
 			 */
 			return -ENOSPC;
 			return -ENOSPC;
 		}
 		}
-		offset = data_offset(recv_buf->mad->mad_hdr.mgmt_class);
+		offset = ib_get_mad_data_offset(recv_buf->mad->mad_hdr.mgmt_class);
 		max_seg_payload = sizeof (struct ib_mad) - offset;
 		max_seg_payload = sizeof (struct ib_mad) - offset;
 
 
 		for (left = packet->length - seg_payload, buf += seg_payload;
 		for (left = packet->length - seg_payload, buf += seg_payload;
@@ -441,21 +430,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
 	}
 	}
 
 
 	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
 	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
-	if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
-		hdr_len = IB_MGMT_SA_HDR;
-		copy_offset = IB_MGMT_RMPP_HDR;
-		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
-			      IB_MGMT_RMPP_FLAG_ACTIVE;
-	} else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START &&
-		   rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) {
-		hdr_len = IB_MGMT_VENDOR_HDR;
+	hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
+	if (!ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)) {
+		copy_offset = IB_MGMT_MAD_HDR;
+		rmpp_active = 0;
+	} else {
 		copy_offset = IB_MGMT_RMPP_HDR;
 		copy_offset = IB_MGMT_RMPP_HDR;
 		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
 		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
 			      IB_MGMT_RMPP_FLAG_ACTIVE;
 			      IB_MGMT_RMPP_FLAG_ACTIVE;
-	} else {
-		hdr_len = IB_MGMT_MAD_HDR;
-		copy_offset = IB_MGMT_MAD_HDR;
-		rmpp_active = 0;
 	}
 	}
 
 
 	data_len = count - sizeof (struct ib_user_mad) - hdr_len;
 	data_len = count - sizeof (struct ib_user_mad) - hdr_len;

+ 1 - 1
drivers/infiniband/hw/mthca/mthca_av.c

@@ -265,7 +265,7 @@ int __devinit mthca_init_av_table(struct mthca_dev *dev)
 	return -ENOMEM;
 	return -ENOMEM;
 }
 }
 
 
-void __devexit mthca_cleanup_av_table(struct mthca_dev *dev)
+void mthca_cleanup_av_table(struct mthca_dev *dev)
 {
 {
 	if (mthca_is_memfree(dev))
 	if (mthca_is_memfree(dev))
 		return;
 		return;

+ 1 - 1
drivers/infiniband/hw/mthca/mthca_cq.c

@@ -973,7 +973,7 @@ int __devinit mthca_init_cq_table(struct mthca_dev *dev)
 	return err;
 	return err;
 }
 }
 
 
-void __devexit mthca_cleanup_cq_table(struct mthca_dev *dev)
+void mthca_cleanup_cq_table(struct mthca_dev *dev)
 {
 {
 	mthca_array_cleanup(&dev->cq_table.cq, dev->limits.num_cqs);
 	mthca_array_cleanup(&dev->cq_table.cq, dev->limits.num_cqs);
 	mthca_alloc_cleanup(&dev->cq_table.alloc);
 	mthca_alloc_cleanup(&dev->cq_table.alloc);

+ 3 - 3
drivers/infiniband/hw/mthca/mthca_eq.c

@@ -765,7 +765,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
 
 
 }
 }
 
 
-static void __devexit mthca_unmap_eq_regs(struct mthca_dev *dev)
+static void mthca_unmap_eq_regs(struct mthca_dev *dev)
 {
 {
 	if (mthca_is_memfree(dev)) {
 	if (mthca_is_memfree(dev)) {
 		mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
 		mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
@@ -821,7 +821,7 @@ int __devinit mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt)
 	return ret;
 	return ret;
 }
 }
 
 
-void __devexit mthca_unmap_eq_icm(struct mthca_dev *dev)
+void mthca_unmap_eq_icm(struct mthca_dev *dev)
 {
 {
 	u8 status;
 	u8 status;
 
 
@@ -954,7 +954,7 @@ err_out_free:
 	return err;
 	return err;
 }
 }
 
 
-void __devexit mthca_cleanup_eq_table(struct mthca_dev *dev)
+void mthca_cleanup_eq_table(struct mthca_dev *dev)
 {
 {
 	u8 status;
 	u8 status;
 	int i;
 	int i;

+ 1 - 1
drivers/infiniband/hw/mthca/mthca_mad.c

@@ -271,7 +271,7 @@ err:
 	return PTR_ERR(agent);
 	return PTR_ERR(agent);
 }
 }
 
 
-void mthca_free_agents(struct mthca_dev *dev)
+void __devexit mthca_free_agents(struct mthca_dev *dev)
 {
 {
 	struct ib_mad_agent *agent;
 	struct ib_mad_agent *agent;
 	int p, q;
 	int p, q;

+ 1 - 1
drivers/infiniband/hw/mthca/mthca_mcg.c

@@ -388,7 +388,7 @@ int __devinit mthca_init_mcg_table(struct mthca_dev *dev)
 	return 0;
 	return 0;
 }
 }
 
 
-void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev)
+void mthca_cleanup_mcg_table(struct mthca_dev *dev)
 {
 {
 	mthca_alloc_cleanup(&dev->mcg_table.alloc);
 	mthca_alloc_cleanup(&dev->mcg_table.alloc);
 }
 }

+ 2 - 2
drivers/infiniband/hw/mthca/mthca_mr.c

@@ -170,7 +170,7 @@ err_out:
 	return -ENOMEM;
 	return -ENOMEM;
 }
 }
 
 
-static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
+static void mthca_buddy_cleanup(struct mthca_buddy *buddy)
 {
 {
 	int i;
 	int i;
 
 
@@ -866,7 +866,7 @@ err_mtt_buddy:
 	return err;
 	return err;
 }
 }
 
 
-void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev)
+void mthca_cleanup_mr_table(struct mthca_dev *dev)
 {
 {
 	/* XXX check if any MRs are still allocated? */
 	/* XXX check if any MRs are still allocated? */
 	if (dev->limits.fmr_reserved_mtts)
 	if (dev->limits.fmr_reserved_mtts)

+ 1 - 1
drivers/infiniband/hw/mthca/mthca_pd.c

@@ -77,7 +77,7 @@ int __devinit mthca_init_pd_table(struct mthca_dev *dev)
 				dev->limits.reserved_pds);
 				dev->limits.reserved_pds);
 }
 }
 
 
-void __devexit mthca_cleanup_pd_table(struct mthca_dev *dev)
+void mthca_cleanup_pd_table(struct mthca_dev *dev)
 {
 {
 	/* XXX check if any PDs are still allocated? */
 	/* XXX check if any PDs are still allocated? */
 	mthca_alloc_cleanup(&dev->pd_table.alloc);
 	mthca_alloc_cleanup(&dev->pd_table.alloc);

+ 1 - 1
drivers/infiniband/hw/mthca/mthca_qp.c

@@ -2204,7 +2204,7 @@ int __devinit mthca_init_qp_table(struct mthca_dev *dev)
 	return err;
 	return err;
 }
 }
 
 
-void __devexit mthca_cleanup_qp_table(struct mthca_dev *dev)
+void mthca_cleanup_qp_table(struct mthca_dev *dev)
 {
 {
 	int i;
 	int i;
 	u8 status;
 	u8 status;

+ 2 - 2
drivers/infiniband/hw/mthca/mthca_srq.c

@@ -206,7 +206,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
 		 roundup_pow_of_two(sizeof (struct mthca_next_seg) +
 		 roundup_pow_of_two(sizeof (struct mthca_next_seg) +
 				    srq->max_gs * sizeof (struct mthca_data_seg)));
 				    srq->max_gs * sizeof (struct mthca_data_seg)));
 
 
-	if (ds > dev->limits.max_desc_sz)
+	if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz))
 		return -EINVAL;
 		return -EINVAL;
 
 
 	srq->wqe_shift = long_log2(ds);
 	srq->wqe_shift = long_log2(ds);
@@ -684,7 +684,7 @@ int __devinit mthca_init_srq_table(struct mthca_dev *dev)
 	return err;
 	return err;
 }
 }
 
 
-void __devexit mthca_cleanup_srq_table(struct mthca_dev *dev)
+void mthca_cleanup_srq_table(struct mthca_dev *dev)
 {
 {
 	if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
 	if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
 		return;
 		return;

+ 1 - 1
drivers/infiniband/ulp/ipoib/ipoib_main.c

@@ -723,7 +723,7 @@ static int ipoib_hard_header(struct sk_buff *skb,
 	 * destination address onto the front of the skb so we can
 	 * destination address onto the front of the skb so we can
 	 * figure out where to send the packet later.
 	 * figure out where to send the packet later.
 	 */
 	 */
-	if (!skb->dst || !skb->dst->neighbour) {
+	if ((!skb->dst || !skb->dst->neighbour) && daddr) {
 		struct ipoib_pseudoheader *phdr =
 		struct ipoib_pseudoheader *phdr =
 			(struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
 			(struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
 		memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
 		memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);

+ 2 - 2
drivers/infiniband/ulp/srp/ib_srp.c

@@ -607,10 +607,10 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
 	 */
 	 */
 	if (likely(scmnd->use_sg)) {
 	if (likely(scmnd->use_sg)) {
 		nents = scmnd->use_sg;
 		nents = scmnd->use_sg;
-		scat  = (struct scatterlist *) scmnd->request_buffer;
+		scat  = scmnd->request_buffer;
 	} else {
 	} else {
 		nents = 1;
 		nents = 1;
-		scat  = (struct scatterlist *) scmnd->request_buffer;
+		scat  = &req->fake_sg;
 	}
 	}
 
 
 	dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents,
 	dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents,

+ 30 - 26
drivers/input/keyboard/hil_kbd.c

@@ -66,7 +66,7 @@ static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] =
 static char hil_language[][16] = { HIL_LOCALE_MAP };
 static char hil_language[][16] = { HIL_LOCALE_MAP };
 
 
 struct hil_kbd {
 struct hil_kbd {
-	struct input_dev dev;
+	struct input_dev *dev;
 	struct serio *serio;
 	struct serio *serio;
 
 
 	/* Input buffer and index for packets from HIL bus. */
 	/* Input buffer and index for packets from HIL bus. */
@@ -86,7 +86,7 @@ struct hil_kbd {
 /* Process a complete packet after transfer from the HIL */
 /* Process a complete packet after transfer from the HIL */
 static void hil_kbd_process_record(struct hil_kbd *kbd)
 static void hil_kbd_process_record(struct hil_kbd *kbd)
 {
 {
-	struct input_dev *dev = &kbd->dev;
+	struct input_dev *dev = kbd->dev;
 	hil_packet *data = kbd->data;
 	hil_packet *data = kbd->data;
 	hil_packet p;
 	hil_packet p;
 	int idx, i, cnt;
 	int idx, i, cnt;
@@ -240,8 +240,8 @@ static void hil_kbd_disconnect(struct serio *serio)
 		return;
 		return;
 	}
 	}
 
 
-	input_unregister_device(&kbd->dev);
 	serio_close(serio);
 	serio_close(serio);
+	input_unregister_device(kbd->dev);
 	kfree(kbd);
 	kfree(kbd);
 }
 }
 
 
@@ -251,16 +251,18 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
 	uint8_t		did, *idd;
 	uint8_t		did, *idd;
 	int		i;
 	int		i;
 	
 	
-	kbd = kmalloc(sizeof(*kbd), GFP_KERNEL);
+	kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
 	if (!kbd)
 	if (!kbd)
 		return -ENOMEM;
 		return -ENOMEM;
-	memset(kbd, 0, sizeof(struct hil_kbd));
+
+	kbd->dev = input_allocate_device();
+	if (!kbd->dev) goto bail1;
+	kbd->dev->private = kbd;
 
 
 	if (serio_open(serio, drv)) goto bail0;
 	if (serio_open(serio, drv)) goto bail0;
 
 
 	serio_set_drvdata(serio, kbd);
 	serio_set_drvdata(serio, kbd);
 	kbd->serio = serio;
 	kbd->serio = serio;
-	kbd->dev.private = kbd;
 
 
 	init_MUTEX_LOCKED(&(kbd->sem));
 	init_MUTEX_LOCKED(&(kbd->sem));
 
 
@@ -302,38 +304,38 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
 			did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
 			did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
 		break;
 		break;
 	default:
 	default:
-		goto bail1;
+		goto bail2;
 	}
 	}
 
 
 	if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
 	if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
 		printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
 		printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
-		goto bail1;
+		goto bail2;
 	}
 	}
 
 
 
 
-	kbd->dev.evbit[0]	= BIT(EV_KEY) | BIT(EV_REP);
-	kbd->dev.ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	kbd->dev.keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
-	kbd->dev.keycodesize	= sizeof(hil_kbd_set1[0]);
-	kbd->dev.keycode	= hil_kbd_set1;
-	kbd->dev.name		= strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
-	kbd->dev.phys		= "hpkbd/input0";	/* XXX */
+	kbd->dev->evbit[0]	= BIT(EV_KEY) | BIT(EV_REP);
+	kbd->dev->ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	kbd->dev->keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
+	kbd->dev->keycodesize	= sizeof(hil_kbd_set1[0]);
+	kbd->dev->keycode	= hil_kbd_set1;
+	kbd->dev->name		= strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
+	kbd->dev->phys		= "hpkbd/input0";	/* XXX */
 
 
-	kbd->dev.id.bustype	= BUS_HIL;
-	kbd->dev.id.vendor	= PCI_VENDOR_ID_HP;
-	kbd->dev.id.product	= 0x0001; /* TODO: get from kbd->rsc */
-	kbd->dev.id.version	= 0x0100; /* TODO: get from kbd->rsc */
-	kbd->dev.dev		= &serio->dev;
+	kbd->dev->id.bustype	= BUS_HIL;
+	kbd->dev->id.vendor	= PCI_VENDOR_ID_HP;
+	kbd->dev->id.product	= 0x0001; /* TODO: get from kbd->rsc */
+	kbd->dev->id.version	= 0x0100; /* TODO: get from kbd->rsc */
+	kbd->dev->dev		= &serio->dev;
 
 
 	for (i = 0; i < 128; i++) {
 	for (i = 0; i < 128; i++) {
-		set_bit(hil_kbd_set1[i], kbd->dev.keybit);
-		set_bit(hil_kbd_set3[i], kbd->dev.keybit);
+		set_bit(hil_kbd_set1[i], kbd->dev->keybit);
+		set_bit(hil_kbd_set3[i], kbd->dev->keybit);
 	}
 	}
-	clear_bit(0, kbd->dev.keybit);
+	clear_bit(0, kbd->dev->keybit);
 
 
-	input_register_device(&kbd->dev);
+	input_register_device(kbd->dev);
 	printk(KERN_INFO "input: %s, ID: %d\n",
 	printk(KERN_INFO "input: %s, ID: %d\n",
-		kbd->dev.name, did);
+		kbd->dev->name, did);
 
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, 0);
@@ -343,8 +345,10 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
 	up(&(kbd->sem));
 	up(&(kbd->sem));
 
 
 	return 0;
 	return 0;
- bail1:
+ bail2:
 	serio_close(serio);
 	serio_close(serio);
+ bail1:
+	input_free_device(kbd->dev);
  bail0:
  bail0:
 	kfree(kbd);
 	kfree(kbd);
 	serio_set_drvdata(serio, NULL);
 	serio_set_drvdata(serio, NULL);

+ 29 - 24
drivers/input/keyboard/hilkbd.c

@@ -3,7 +3,7 @@
  *
  *
  *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
  *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
  *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
  *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
- *  Copyright (C) 1999-2003 Helge Deller <deller@gmx.de>
+ *  Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
  *
  *
  *  Very basic HP Human Interface Loop (HIL) driver.
  *  Very basic HP Human Interface Loop (HIL) driver.
  *  This driver handles the keyboard on HP300 (m68k) and on some 
  *  This driver handles the keyboard on HP300 (m68k) and on some 
@@ -90,7 +90,7 @@ static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
 
 
 /* HIL structure */
 /* HIL structure */
 static struct {
 static struct {
-	struct input_dev dev;
+	struct input_dev *dev;
 
 
 	unsigned int curdev;
 	unsigned int curdev;
 	
 	
@@ -117,7 +117,7 @@ static void poll_finished(void)
 		down = (hil_dev.data[1] & 1) == 0;
 		down = (hil_dev.data[1] & 1) == 0;
 		scode = hil_dev.data[1] >> 1;
 		scode = hil_dev.data[1] >> 1;
 		key = hphilkeyb_keycode[scode];
 		key = hphilkeyb_keycode[scode];
-		input_report_key(&hil_dev.dev, key, down);
+		input_report_key(hil_dev.dev, key, down);
 		break;
 		break;
 	}
 	}
 	hil_dev.curdev = 0;
 	hil_dev.curdev = 0;
@@ -207,9 +207,14 @@ hil_keyb_init(void)
 	unsigned int i, kbid;
 	unsigned int i, kbid;
 	wait_queue_head_t hil_wait;
 	wait_queue_head_t hil_wait;
 
 
-	if (hil_dev.dev.id.bustype) {
+	if (hil_dev.dev) {
 		return -ENODEV; /* already initialized */
 		return -ENODEV; /* already initialized */
 	}
 	}
+
+	hil_dev.dev = input_allocate_device();
+	if (!hil_dev.dev)
+		return -ENOMEM;
+	hil_dev.dev->private = &hil_dev;
 	
 	
 #if defined(CONFIG_HP300)
 #if defined(CONFIG_HP300)
 	if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
 	if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
@@ -247,28 +252,26 @@ hil_keyb_init(void)
 	c = 0;
 	c = 0;
 	hil_do(HIL_WRITEKBDSADR, &c, 1);
 	hil_do(HIL_WRITEKBDSADR, &c, 1);
 	
 	
-	init_input_dev(&hil_dev.dev);
-
 	for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
 	for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
 		if (hphilkeyb_keycode[i] != KEY_RESERVED)
 		if (hphilkeyb_keycode[i] != KEY_RESERVED)
-			set_bit(hphilkeyb_keycode[i], hil_dev.dev.keybit);
-
-	hil_dev.dev.evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
-	hil_dev.dev.ledbit[0]   = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	hil_dev.dev.keycodemax  = HIL_KEYCODES_SET1_TBLSIZE;
-        hil_dev.dev.keycodesize = sizeof(hphilkeyb_keycode[0]);
-	hil_dev.dev.keycode     = hphilkeyb_keycode;
-	hil_dev.dev.name 	= "HIL keyboard";
-	hil_dev.dev.phys 	= "hpkbd/input0";
-
-	hil_dev.dev.id.bustype	= BUS_HIL;
-	hil_dev.dev.id.vendor	= PCI_VENDOR_ID_HP;
-	hil_dev.dev.id.product	= 0x0001;
-	hil_dev.dev.id.version	= 0x0010;
-
-	input_register_device(&hil_dev.dev);
+			set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
+
+	hil_dev.dev->evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
+	hil_dev.dev->ledbit[0]   = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	hil_dev.dev->keycodemax  = HIL_KEYCODES_SET1_TBLSIZE;
+	hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]);
+	hil_dev.dev->keycode     = hphilkeyb_keycode;
+	hil_dev.dev->name 	= "HIL keyboard";
+	hil_dev.dev->phys 	= "hpkbd/input0";
+
+	hil_dev.dev->id.bustype	= BUS_HIL;
+	hil_dev.dev->id.vendor	= PCI_VENDOR_ID_HP;
+	hil_dev.dev->id.product	= 0x0001;
+	hil_dev.dev->id.version	= 0x0010;
+
+	input_register_device(hil_dev.dev);
 	printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
 	printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
-		hil_dev.dev.name, kbid, HILBASE, HIL_IRQ);
+		hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -329,7 +332,9 @@ static void __exit hil_exit(void)
 	/* Turn off interrupts */
 	/* Turn off interrupts */
 	hil_do(HIL_INTOFF, NULL, 0);
 	hil_do(HIL_INTOFF, NULL, 0);
 
 
-	input_unregister_device(&hil_dev.dev);
+	input_unregister_device(hil_dev.dev);
+
+	hil_dev.dev = NULL;
 
 
 #if defined(CONFIG_PARISC)
 #if defined(CONFIG_PARISC)
 	unregister_parisc_driver(&hil_driver);
 	unregister_parisc_driver(&hil_driver);

+ 47 - 43
drivers/input/mouse/hil_ptr.c

@@ -55,7 +55,7 @@ MODULE_LICENSE("Dual BSD/GPL");
 #define HIL_PTR_MAX_LENGTH 16
 #define HIL_PTR_MAX_LENGTH 16
 
 
 struct hil_ptr {
 struct hil_ptr {
-	struct input_dev dev;
+	struct input_dev *dev;
 	struct serio *serio;
 	struct serio *serio;
 
 
 	/* Input buffer and index for packets from HIL bus. */
 	/* Input buffer and index for packets from HIL bus. */
@@ -79,7 +79,7 @@ struct hil_ptr {
 /* Process a complete packet after transfer from the HIL */
 /* Process a complete packet after transfer from the HIL */
 static void hil_ptr_process_record(struct hil_ptr *ptr)
 static void hil_ptr_process_record(struct hil_ptr *ptr)
 {
 {
-	struct input_dev *dev = &ptr->dev;
+	struct input_dev *dev = ptr->dev;
 	hil_packet *data = ptr->data;
 	hil_packet *data = ptr->data;
 	hil_packet p;
 	hil_packet p;
 	int idx, i, cnt, laxis;
 	int idx, i, cnt, laxis;
@@ -148,12 +148,12 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
 		if (absdev) {
 		if (absdev) {
 			val = lo + (hi<<8);
 			val = lo + (hi<<8);
 #ifdef TABLET_AUTOADJUST
 #ifdef TABLET_AUTOADJUST
-			if (val < ptr->dev.absmin[ABS_X + i])
-				ptr->dev.absmin[ABS_X + i] = val;
-			if (val > ptr->dev.absmax[ABS_X + i])
-				ptr->dev.absmax[ABS_X + i] = val;
+			if (val < dev->absmin[ABS_X + i])
+				dev->absmin[ABS_X + i] = val;
+			if (val > dev->absmax[ABS_X + i])
+				dev->absmax[ABS_X + i] = val;
 #endif
 #endif
-			if (i%3) val = ptr->dev.absmax[ABS_X + i] - val;
+			if (i%3) val = dev->absmax[ABS_X + i] - val;
 			input_report_abs(dev, ABS_X + i, val);
 			input_report_abs(dev, ABS_X + i, val);
 		} else {
 		} else {
 			val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
 			val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
@@ -233,26 +233,29 @@ static void hil_ptr_disconnect(struct serio *serio)
 		return;
 		return;
 	}
 	}
 
 
-	input_unregister_device(&ptr->dev);
 	serio_close(serio);
 	serio_close(serio);
+	input_unregister_device(ptr->dev);
 	kfree(ptr);
 	kfree(ptr);
 }
 }
 
 
 static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
 static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
 {
 {
-	struct hil_ptr	*ptr;
-	char		*txt;
-	unsigned int	i, naxsets, btntype;
-	uint8_t		did, *idd;
+	struct hil_ptr	 *ptr;
+	char		 *txt;
+	unsigned int	 i, naxsets, btntype;
+	uint8_t		 did, *idd;
 
 
-	if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return -ENOMEM;
-	memset(ptr, 0, sizeof(struct hil_ptr));
+	if (!(ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL)))
+		return -ENOMEM;
 
 
-	if (serio_open(serio, driver)) goto bail0;
+	ptr->dev = input_allocate_device();
+	if (!ptr->dev) goto bail0;
+	ptr->dev->private = ptr;
+
+	if (serio_open(serio, driver)) goto bail1;
 
 
 	serio_set_drvdata(serio, ptr);
 	serio_set_drvdata(serio, ptr);
 	ptr->serio = serio;
 	ptr->serio = serio;
-	ptr->dev.private = ptr;
 
 
 	init_MUTEX_LOCKED(&(ptr->sem));
 	init_MUTEX_LOCKED(&(ptr->sem));
 
 
@@ -283,25 +286,24 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
 
 
 	up(&(ptr->sem));
 	up(&(ptr->sem));
 
 
-	init_input_dev(&ptr->dev);
 	did = ptr->idd[0];
 	did = ptr->idd[0];
 	idd = ptr->idd + 1;
 	idd = ptr->idd + 1;
 	txt = "unknown";
 	txt = "unknown";
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
-		ptr->dev.evbit[0] = BIT(EV_REL);
+		ptr->dev->evbit[0] = BIT(EV_REL);
 		txt = "relative";
 		txt = "relative";
 	}
 	}
 
 
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
-		ptr->dev.evbit[0] = BIT(EV_ABS);
+		ptr->dev->evbit[0] = BIT(EV_ABS);
 		txt = "absolute";
 		txt = "absolute";
 	}
 	}
-	if (!ptr->dev.evbit[0]) {
-		goto bail1;
+	if (!ptr->dev->evbit[0]) {
+		goto bail2;
 	}
 	}
 
 
 	ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
 	ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
-	if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY);
+	if (ptr->nbtn) ptr->dev->evbit[0] |= BIT(EV_KEY);
 
 
 	naxsets = HIL_IDD_NUM_AXSETS(*idd);
 	naxsets = HIL_IDD_NUM_AXSETS(*idd);
 	ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
 	ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
@@ -325,7 +327,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
 		btntype = BTN_MOUSE;
 		btntype = BTN_MOUSE;
 
 
 	for (i = 0; i < ptr->nbtn; i++) {
 	for (i = 0; i < ptr->nbtn; i++) {
-		set_bit(btntype | i, ptr->dev.keybit);
+		set_bit(btntype | i, ptr->dev->keybit);
 		ptr->btnmap[i] = btntype | i;
 		ptr->btnmap[i] = btntype | i;
 	}
 	}
 
 
@@ -337,50 +339,52 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
 
 
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
 		for (i = 0; i < ptr->naxes; i++) {
 		for (i = 0; i < ptr->naxes; i++) {
-			set_bit(REL_X + i, ptr->dev.relbit);
+			set_bit(REL_X + i, ptr->dev->relbit);
 		}
 		}
 		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
 		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
-			set_bit(REL_X + i, ptr->dev.relbit);
+			set_bit(REL_X + i, ptr->dev->relbit);
 		}
 		}
 	} else {
 	} else {
 		for (i = 0; i < ptr->naxes; i++) {
 		for (i = 0; i < ptr->naxes; i++) {
-	  		set_bit(ABS_X + i, ptr->dev.absbit);
-			ptr->dev.absmin[ABS_X + i] = 0;
-			ptr->dev.absmax[ABS_X + i] = 
+			set_bit(ABS_X + i, ptr->dev->absbit);
+			ptr->dev->absmin[ABS_X + i] = 0;
+			ptr->dev->absmax[ABS_X + i] =
 				HIL_IDD_AXIS_MAX((ptr->idd + 1), i);
 				HIL_IDD_AXIS_MAX((ptr->idd + 1), i);
 		}
 		}
 		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
 		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
-			set_bit(ABS_X + i, ptr->dev.absbit);
-			ptr->dev.absmin[ABS_X + i] = 0;
-			ptr->dev.absmax[ABS_X + i] = 
+			set_bit(ABS_X + i, ptr->dev->absbit);
+			ptr->dev->absmin[ABS_X + i] = 0;
+			ptr->dev->absmax[ABS_X + i] =
 				HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3));
 				HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3));
 		}
 		}
 #ifdef TABLET_AUTOADJUST
 #ifdef TABLET_AUTOADJUST
 		for (i = 0; i < ABS_MAX; i++) {
 		for (i = 0; i < ABS_MAX; i++) {
-			int diff = ptr->dev.absmax[ABS_X + i] / 10;
-			ptr->dev.absmin[ABS_X + i] += diff;
-			ptr->dev.absmax[ABS_X + i] -= diff;
+			int diff = ptr->dev->absmax[ABS_X + i] / 10;
+			ptr->dev->absmin[ABS_X + i] += diff;
+			ptr->dev->absmax[ABS_X + i] -= diff;
 		}
 		}
 #endif
 #endif
 	}
 	}
 
 
-	ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
+	ptr->dev->name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
 
 
-	ptr->dev.id.bustype	= BUS_HIL;
-	ptr->dev.id.vendor	= PCI_VENDOR_ID_HP;
-	ptr->dev.id.product	= 0x0001; /* TODO: get from ptr->rsc */
-	ptr->dev.id.version	= 0x0100; /* TODO: get from ptr->rsc */
-	ptr->dev.dev		= &serio->dev;
+	ptr->dev->id.bustype	= BUS_HIL;
+	ptr->dev->id.vendor	= PCI_VENDOR_ID_HP;
+	ptr->dev->id.product	= 0x0001; /* TODO: get from ptr->rsc */
+	ptr->dev->id.version	= 0x0100; /* TODO: get from ptr->rsc */
+	ptr->dev->dev		= &serio->dev;
 
 
-	input_register_device(&ptr->dev);
+	input_register_device(ptr->dev);
 	printk(KERN_INFO "input: %s (%s), ID: %d\n",
 	printk(KERN_INFO "input: %s (%s), ID: %d\n",
-                ptr->dev.name, 
+		ptr->dev->name,
 		(btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
 		(btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
 		did);
 		did);
 
 
 	return 0;
 	return 0;
- bail1:
+ bail2:
 	serio_close(serio);
 	serio_close(serio);
+ bail1:
+	input_free_device(ptr->dev);
  bail0:
  bail0:
 	kfree(ptr);
 	kfree(ptr);
 	serio_set_drvdata(serio, NULL);
 	serio_set_drvdata(serio, NULL);

+ 2 - 2
drivers/input/serio/gscps2.c

@@ -1,7 +1,7 @@
 /*
 /*
  * drivers/input/serio/gscps2.c
  * drivers/input/serio/gscps2.c
  *
  *
- * Copyright (c) 2004 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2004-2006 Helge Deller <deller@gmx.de>
  * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
  * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
  * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org>
  * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org>
  *
  *
@@ -354,7 +354,7 @@ static int __init gscps2_probe(struct parisc_device *dev)
 	memset(serio, 0, sizeof(struct serio));
 	memset(serio, 0, sizeof(struct serio));
 	ps2port->port = serio;
 	ps2port->port = serio;
 	ps2port->padev = dev;
 	ps2port->padev = dev;
-	ps2port->addr = ioremap(hpa, GSC_STATUS + 4);
+	ps2port->addr = ioremap_nocache(hpa, GSC_STATUS + 4);
 	spin_lock_init(&ps2port->lock);
 	spin_lock_init(&ps2port->lock);
 
 
 	gscps2_reset(ps2port);
 	gscps2_reset(ps2port);

+ 1 - 1
drivers/net/8390.h

@@ -134,7 +134,7 @@ struct ei_device {
 #define inb_p(_p)	inb(_p)
 #define inb_p(_p)	inb(_p)
 #define outb_p(_v,_p)	outb(_v,_p)
 #define outb_p(_v,_p)	outb(_v,_p)
 
 
-#elif defined(CONFIG_NET_CBUS) || defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE)
+#elif defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #else
 #else
 #define EI_SHIFT(x)	(x)
 #define EI_SHIFT(x)	(x)

+ 5 - 5
drivers/net/acenic_firmware.h

@@ -4397,7 +4397,7 @@ static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 
 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 
 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
-static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
+static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 
 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 
@@ -4571,7 +4571,7 @@ static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
 0x0, 0x14c38, 0x14c38, 0x14b80, 
 0x0, 0x14c38, 0x14c38, 0x14b80, 
 0x14bc4, 0x14c38, 0x14c38, 0x0, 
 0x14bc4, 0x14c38, 0x14c38, 0x0, 
 0x0, 0x0 };
 0x0, 0x0 };
-static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
+static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
 0x416c7465, 
 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, 
@@ -4612,7 +4612,7 @@ static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
 #define tigon2FwSbssLen 0xcc
 #define tigon2FwSbssLen 0xcc
 #define tigon2FwBssAddr 0x00016f50
 #define tigon2FwBssAddr 0x00016f50
 #define tigon2FwBssLen 0x20c0
 #define tigon2FwBssLen 0x20c0
-static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
+static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
 0x0, 
 0x0, 
 0x10000003, 0x0, 0xd, 0xd, 
 0x10000003, 0x0, 0xd, 0xd, 
 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, 
 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, 
@@ -9154,7 +9154,7 @@ static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x24020001, 0x8f430328, 0x1021, 0x24630001, 
 0x24020001, 0x8f430328, 0x1021, 0x24630001, 
 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 
 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 
 0x0, 0x0, 0x0, 0x0 };
 0x0, 0x0, 0x0, 0x0 };
-static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
+static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 
 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 
@@ -9425,7 +9425,7 @@ static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 
 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 
 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 
 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 
 0x0, 0x0 };
 0x0, 0x0 };
-static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = {
+static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
 0x1, 
 0x1, 
 0x1, 0x1, 0xc001fc, 0x3ffc, 
 0x1, 0x1, 0xc001fc, 0x3ffc, 
 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, 
 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, 

+ 14 - 0
drivers/net/b44.c

@@ -1339,6 +1339,9 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
 	if (netif_running(dev))
 	if (netif_running(dev))
 		return -EBUSY;
 		return -EBUSY;
 
 
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
 
 	spin_lock_irq(&bp->lock);
 	spin_lock_irq(&bp->lock);
@@ -1876,6 +1879,12 @@ static int __devinit b44_get_invariants(struct b44 *bp)
 	bp->dev->dev_addr[3] = eeprom[80];
 	bp->dev->dev_addr[3] = eeprom[80];
 	bp->dev->dev_addr[4] = eeprom[83];
 	bp->dev->dev_addr[4] = eeprom[83];
 	bp->dev->dev_addr[5] = eeprom[82];
 	bp->dev->dev_addr[5] = eeprom[82];
+
+	if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
+		printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
+		return -EINVAL;
+	}
+
 	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
 	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
 
 
 	bp->phy_addr = eeprom[90] & 0x1f;
 	bp->phy_addr = eeprom[90] & 0x1f;
@@ -2033,6 +2042,11 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
 
 	pci_save_state(bp->pdev);
 	pci_save_state(bp->pdev);
 
 
+	/* Chip reset provides power to the b44 MAC & PCI cores, which 
+	 * is necessary for MAC register access.
+	 */ 
+	b44_chip_reset(bp);
+
 	printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
 	printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
 	for (i = 0; i < 6; i++)
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i],
 		printk("%2.2x%c", dev->dev_addr[i],

+ 28 - 0
drivers/net/bonding/bond_3ad.c

@@ -2294,6 +2294,34 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
 	port->sm_vars |= AD_PORT_BEGIN;
 	port->sm_vars |= AD_PORT_BEGIN;
 }
 }
 
 
+/*
+ * set link state for bonding master: if we have an active partnered
+ * aggregator, we're up, if not, we're down.  Presumes that we cannot
+ * have an active aggregator if there are no slaves with link up.
+ *
+ * Called by bond_set_carrier(). Return zero if carrier state does not
+ * change, nonzero if it does.
+ */
+int bond_3ad_set_carrier(struct bonding *bond)
+{
+	struct aggregator *agg;
+
+	agg = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator));
+	if (agg && MAC_ADDRESS_COMPARE(&agg->partner_system, &null_mac_addr)) {
+		if (!netif_carrier_ok(bond->dev)) {
+			netif_carrier_on(bond->dev);
+			return 1;
+		}
+		return 0;
+	}
+
+	if (netif_carrier_ok(bond->dev)) {
+		netif_carrier_off(bond->dev);
+		return 1;
+	}
+	return 0;
+}
+
 /**
 /**
  * bond_3ad_get_active_agg_info - get information of the active aggregator
  * bond_3ad_get_active_agg_info - get information of the active aggregator
  * @bond: bonding struct to work on
  * @bond: bonding struct to work on

+ 1 - 0
drivers/net/bonding/bond_3ad.h

@@ -283,5 +283,6 @@ void bond_3ad_handle_link_change(struct slave *slave, char link);
 int  bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
 int  bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
 int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev);
 int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev);
+int bond_3ad_set_carrier(struct bonding *bond);
 #endif //__BOND_3AD_H__
 #endif //__BOND_3AD_H__
 
 

+ 71 - 26
drivers/net/bonding/bond_main.c

@@ -558,6 +558,42 @@ out:
 
 
 /*------------------------------- Link status -------------------------------*/
 /*------------------------------- Link status -------------------------------*/
 
 
+/*
+ * Set the carrier state for the master according to the state of its
+ * slaves.  If any slaves are up, the master is up.  In 802.3ad mode,
+ * do special 802.3ad magic.
+ *
+ * Returns zero if carrier state does not change, nonzero if it does.
+ */
+static int bond_set_carrier(struct bonding *bond)
+{
+	struct slave *slave;
+	int i;
+
+	if (bond->slave_cnt == 0)
+		goto down;
+
+	if (bond->params.mode == BOND_MODE_8023AD)
+		return bond_3ad_set_carrier(bond);
+
+	bond_for_each_slave(bond, slave, i) {
+		if (slave->link == BOND_LINK_UP) {
+			if (!netif_carrier_ok(bond->dev)) {
+				netif_carrier_on(bond->dev);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+down:
+	if (netif_carrier_ok(bond->dev)) {
+		netif_carrier_off(bond->dev);
+		return 1;
+	}
+	return 0;
+}
+
 /*
 /*
  * Get link speed and duplex from the slave's base driver
  * Get link speed and duplex from the slave's base driver
  * using ethtool. If for some reason the call fails or the
  * using ethtool. If for some reason the call fails or the
@@ -1074,10 +1110,24 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
 void bond_select_active_slave(struct bonding *bond)
 void bond_select_active_slave(struct bonding *bond)
 {
 {
 	struct slave *best_slave;
 	struct slave *best_slave;
+	int rv;
 
 
 	best_slave = bond_find_best_slave(bond);
 	best_slave = bond_find_best_slave(bond);
 	if (best_slave != bond->curr_active_slave) {
 	if (best_slave != bond->curr_active_slave) {
 		bond_change_active_slave(bond, best_slave);
 		bond_change_active_slave(bond, best_slave);
+		rv = bond_set_carrier(bond);
+		if (!rv)
+			return;
+
+		if (netif_carrier_ok(bond->dev)) {
+			printk(KERN_INFO DRV_NAME
+			       ": %s: first active interface up!\n",
+			       bond->dev->name);
+		} else {
+			printk(KERN_INFO DRV_NAME ": %s: "
+			       "now running without any active interface !\n",
+			       bond->dev->name);
+		}
 	}
 	}
 }
 }
 
 
@@ -1458,10 +1508,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 		if (((!bond->curr_active_slave) ||
 		if (((!bond->curr_active_slave) ||
 		     (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
 		     (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
 		    (new_slave->link != BOND_LINK_DOWN)) {
 		    (new_slave->link != BOND_LINK_DOWN)) {
-			dprintk("This is the first active slave\n");
 			/* first slave or no active slave yet, and this link
 			/* first slave or no active slave yet, and this link
 			   is OK, so make this interface the active one */
 			   is OK, so make this interface the active one */
 			bond_change_active_slave(bond, new_slave);
 			bond_change_active_slave(bond, new_slave);
+			printk(KERN_INFO DRV_NAME
+			       ": %s: first active interface up!\n",
+			       bond->dev->name);
+			netif_carrier_on(bond->dev);
+
 		} else {
 		} else {
 			dprintk("This is just a backup slave\n");
 			dprintk("This is just a backup slave\n");
 			bond_set_slave_inactive_flags(new_slave);
 			bond_set_slave_inactive_flags(new_slave);
@@ -1517,6 +1571,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 		break;
 		break;
 	} /* switch(bond_mode) */
 	} /* switch(bond_mode) */
 
 
+	bond_set_carrier(bond);
+
 	write_unlock_bh(&bond->lock);
 	write_unlock_bh(&bond->lock);
 
 
 	res = bond_create_slave_symlinks(bond_dev, slave_dev);
 	res = bond_create_slave_symlinks(bond_dev, slave_dev);
@@ -1656,18 +1712,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 		bond_alb_deinit_slave(bond, slave);
 		bond_alb_deinit_slave(bond, slave);
 	}
 	}
 
 
-	if (oldcurrent == slave) {
+	if (oldcurrent == slave)
 		bond_select_active_slave(bond);
 		bond_select_active_slave(bond);
 
 
-		if (!bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-	}
-
 	if (bond->slave_cnt == 0) {
 	if (bond->slave_cnt == 0) {
+		bond_set_carrier(bond);
+
 		/* if the last slave was removed, zero the mac address
 		/* if the last slave was removed, zero the mac address
 		 * of the master so it will be set by the application
 		 * of the master so it will be set by the application
 		 * to the mac address of the first slave
 		 * to the mac address of the first slave
@@ -1751,6 +1801,8 @@ static int bond_release_all(struct net_device *bond_dev)
 
 
 	write_lock_bh(&bond->lock);
 	write_lock_bh(&bond->lock);
 
 
+	netif_carrier_off(bond_dev);
+
 	if (bond->slave_cnt == 0) {
 	if (bond->slave_cnt == 0) {
 		goto out;
 		goto out;
 	}
 	}
@@ -2187,15 +2239,9 @@ void bond_mii_monitor(struct net_device *bond_dev)
 
 
 		bond_select_active_slave(bond);
 		bond_select_active_slave(bond);
 
 
-		if (oldcurrent && !bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-
 		write_unlock(&bond->curr_slave_lock);
 		write_unlock(&bond->curr_slave_lock);
-	}
+	} else
+		bond_set_carrier(bond);
 
 
 re_arm:
 re_arm:
 	if (bond->params.miimon) {
 	if (bond->params.miimon) {
@@ -2499,13 +2545,6 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev)
 
 
 		bond_select_active_slave(bond);
 		bond_select_active_slave(bond);
 
 
-		if (oldcurrent && !bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-
 		write_unlock(&bond->curr_slave_lock);
 		write_unlock(&bond->curr_slave_lock);
 	}
 	}
 
 
@@ -2579,12 +2618,15 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
 					bond->current_arp_slave = NULL;
 					bond->current_arp_slave = NULL;
 				}
 				}
 
 
+				bond_set_carrier(bond);
+
 				if (slave == bond->curr_active_slave) {
 				if (slave == bond->curr_active_slave) {
 					printk(KERN_INFO DRV_NAME
 					printk(KERN_INFO DRV_NAME
 					       ": %s: %s is up and now the "
 					       ": %s: %s is up and now the "
 					       "active interface\n",
 					       "active interface\n",
 					       bond_dev->name,
 					       bond_dev->name,
 					       slave->dev->name);
 					       slave->dev->name);
+					netif_carrier_on(bond->dev);
 				} else {
 				} else {
 					printk(KERN_INFO DRV_NAME
 					printk(KERN_INFO DRV_NAME
 					       ": %s: backup interface %s is "
 					       ": %s: backup interface %s is "
@@ -2844,7 +2886,8 @@ static void bond_info_show_master(struct seq_file *seq)
 			   (curr) ? curr->dev->name : "None");
 			   (curr) ? curr->dev->name : "None");
 	}
 	}
 
 
-	seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down");
+	seq_printf(seq, "MII Status: %s\n", netif_carrier_ok(bond->dev) ?
+		   "up" : "down");
 	seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon);
 	seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon);
 	seq_printf(seq, "Up Delay (ms): %d\n",
 	seq_printf(seq, "Up Delay (ms): %d\n",
 		   bond->params.updelay * bond->params.miimon);
 		   bond->params.updelay * bond->params.miimon);
@@ -4531,6 +4574,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
 	if (newbond)
 	if (newbond)
 		*newbond = bond_dev->priv;
 		*newbond = bond_dev->priv;
 
 
+	netif_carrier_off(bond_dev);
+
 	rtnl_unlock(); /* allows sysfs registration of net device */
 	rtnl_unlock(); /* allows sysfs registration of net device */
 	res = bond_create_sysfs_entry(bond_dev->priv);
 	res = bond_create_sysfs_entry(bond_dev->priv);
 	goto done;
 	goto done;

+ 2 - 2
drivers/net/bonding/bonding.h

@@ -22,8 +22,8 @@
 #include "bond_3ad.h"
 #include "bond_3ad.h"
 #include "bond_alb.h"
 #include "bond_alb.h"
 
 
-#define DRV_VERSION	"3.0.2"
-#define DRV_RELDATE	"February 21, 2006"
+#define DRV_VERSION	"3.0.3"
+#define DRV_RELDATE	"March 23, 2006"
 #define DRV_NAME	"bonding"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
 

+ 1 - 4
drivers/net/ixp2000/ixpdev.c

@@ -299,10 +299,7 @@ int ixpdev_init(int __nds_count, struct net_device **__nds,
 	int i;
 	int i;
 	int err;
 	int err;
 
 
-	if (RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192) {
-		static void __too_many_rx_or_tx_buffers(void);
-		__too_many_rx_or_tx_buffers();
-	}
+	BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192);
 
 
 	printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION);
 	printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION);
 
 

+ 14 - 4
drivers/net/natsemi.c

@@ -226,7 +226,7 @@ static int full_duplex[MAX_UNITS];
 				 NATSEMI_PG1_NREGS)
 				 NATSEMI_PG1_NREGS)
 #define NATSEMI_REGS_VER	1 /* v1 added RFDR registers */
 #define NATSEMI_REGS_VER	1 /* v1 added RFDR registers */
 #define NATSEMI_REGS_SIZE	(NATSEMI_NREGS * sizeof(u32))
 #define NATSEMI_REGS_SIZE	(NATSEMI_NREGS * sizeof(u32))
-#define NATSEMI_EEPROM_SIZE	24 /* 12 16-bit values */
+#define NATSEMI_DEF_EEPROM_SIZE	24 /* 12 16-bit values */
 
 
 /* Buffer sizes:
 /* Buffer sizes:
  * The nic writes 32-bit values, even if the upper bytes of
  * The nic writes 32-bit values, even if the upper bytes of
@@ -714,6 +714,8 @@ struct netdev_private {
 	unsigned int iosize;
 	unsigned int iosize;
 	spinlock_t lock;
 	spinlock_t lock;
 	u32 msg_enable;
 	u32 msg_enable;
+	/* EEPROM data */
+	int eeprom_size;
 };
 };
 
 
 static void move_int_phy(struct net_device *dev, int addr);
 static void move_int_phy(struct net_device *dev, int addr);
@@ -890,6 +892,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
 	np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
 	np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
 	np->hands_off = 0;
 	np->hands_off = 0;
 	np->intr_status = 0;
 	np->intr_status = 0;
+	np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE;
 
 
 	/* Initial port:
 	/* Initial port:
 	 * - If the nic was configured to use an external phy and if find_mii
 	 * - If the nic was configured to use an external phy and if find_mii
@@ -2582,7 +2585,8 @@ static int get_regs_len(struct net_device *dev)
 
 
 static int get_eeprom_len(struct net_device *dev)
 static int get_eeprom_len(struct net_device *dev)
 {
 {
-	return NATSEMI_EEPROM_SIZE;
+	struct netdev_private *np = netdev_priv(dev);
+	return np->eeprom_size;
 }
 }
 
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -2669,15 +2673,20 @@ static u32 get_link(struct net_device *dev)
 static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 {
 {
 	struct netdev_private *np = netdev_priv(dev);
 	struct netdev_private *np = netdev_priv(dev);
-	u8 eebuf[NATSEMI_EEPROM_SIZE];
+	u8 *eebuf;
 	int res;
 	int res;
 
 
+	eebuf = kmalloc(np->eeprom_size, GFP_KERNEL);
+	if (!eebuf)
+		return -ENOMEM;
+
 	eeprom->magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16);
 	eeprom->magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16);
 	spin_lock_irq(&np->lock);
 	spin_lock_irq(&np->lock);
 	res = netdev_get_eeprom(dev, eebuf);
 	res = netdev_get_eeprom(dev, eebuf);
 	spin_unlock_irq(&np->lock);
 	spin_unlock_irq(&np->lock);
 	if (!res)
 	if (!res)
 		memcpy(data, eebuf+eeprom->offset, eeprom->len);
 		memcpy(data, eebuf+eeprom->offset, eeprom->len);
+	kfree(eebuf);
 	return res;
 	return res;
 }
 }
 
 
@@ -3033,9 +3042,10 @@ static int netdev_get_eeprom(struct net_device *dev, u8 *buf)
 	int i;
 	int i;
 	u16 *ebuf = (u16 *)buf;
 	u16 *ebuf = (u16 *)buf;
 	void __iomem * ioaddr = ns_ioaddr(dev);
 	void __iomem * ioaddr = ns_ioaddr(dev);
+	struct netdev_private *np = netdev_priv(dev);
 
 
 	/* eeprom_read reads 16 bits, and indexes by 16 bits */
 	/* eeprom_read reads 16 bits, and indexes by 16 bits */
-	for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) {
+	for (i = 0; i < np->eeprom_size/2; i++) {
 		ebuf[i] = eeprom_read(ioaddr, i);
 		ebuf[i] = eeprom_read(ioaddr, i);
 		/* The EEPROM itself stores data bit-swapped, but eeprom_read
 		/* The EEPROM itself stores data bit-swapped, but eeprom_read
 		 * reads it back "sanely". So we swap it back here in order to
 		 * reads it back "sanely". So we swap it back here in order to

+ 53 - 8
drivers/net/pcmcia/axnet_cs.c

@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/netdevice.h>
+#include <linux/crc32.h>
 #include "../8390.h"
 #include "../8390.h"
 
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs_types.h>
@@ -1682,17 +1683,67 @@ static struct net_device_stats *get_stats(struct net_device *dev)
 	return &ei_local->stat;
 	return &ei_local->stat;
 }
 }
 
 
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+ 
+static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+{
+	struct dev_mc_list *dmi;
+	u32 crc;
+
+	for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+		
+		crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+		/* 
+		 * The 8390 uses the 6 most significant bits of the
+		 * CRC to index the multicast table.
+		 */
+		bits[crc>>29] |= (1<<((crc>>26)&7));
+	}
+}
+
 /**
 /**
  * do_set_multicast_list - set/clear multicast filter
  * do_set_multicast_list - set/clear multicast filter
  * @dev: net device for which multicast filter is adjusted
  * @dev: net device for which multicast filter is adjusted
  *
  *
- *	Set or clear the multicast filter for this adaptor. May be called
- *	from a BH in 2.1.x. Must be called with lock held. 
+ *	Set or clear the multicast filter for this adaptor.
+ *	Must be called with lock held. 
  */
  */
  
  
 static void do_set_multicast_list(struct net_device *dev)
 static void do_set_multicast_list(struct net_device *dev)
 {
 {
 	long e8390_base = dev->base_addr;
 	long e8390_base = dev->base_addr;
+	int i;
+	struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
+		memset(ei_local->mcfilter, 0, 8);
+		if (dev->mc_list)
+			make_mc_bits(ei_local->mcfilter, dev);
+	} else {
+		/* set to accept-all */
+		memset(ei_local->mcfilter, 0xFF, 8);
+	}
+
+	/* 
+	 * DP8390 manuals don't specify any magic sequence for altering
+	 * the multicast regs on an already running card. To be safe, we
+	 * ensure multicast mode is off prior to loading up the new hash
+	 * table. If this proves to be not enough, we can always resort
+	 * to stopping the NIC, loading the table and then restarting.
+	 */
+	 
+	if (netif_running(dev))
+		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+
+	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+	for(i = 0; i < 8; i++) 
+	{
+		outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+	}
+	outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
 
 
   	if(dev->flags&IFF_PROMISC)
   	if(dev->flags&IFF_PROMISC)
   		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
   		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
@@ -1794,12 +1845,6 @@ static void AX88190_init(struct net_device *dev, int startp)
 		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
 		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
 			printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
 			printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
 	}
 	}
-	/*
-	 * Initialize the multicast list to accept-all.  If we enable multicast
-	 * the higher levels can do the filtering.
-	 */
-	for (i = 0; i < 8; i++)
-		outb_p(0xff, e8390_base + EN1_MULT + i);
 
 
 	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
 	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);

+ 2 - 2
drivers/net/pcnet32.c

@@ -1167,8 +1167,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 	 * station address PROM at the base address and programmed into the
 	 * station address PROM at the base address and programmed into the
 	 * "Physical Address Registers" CSR12-14.
 	 * "Physical Address Registers" CSR12-14.
 	 * As a precautionary measure, we read the PROM values and complain if
 	 * As a precautionary measure, we read the PROM values and complain if
-	 * they disagree with the CSRs.  Either way, we use the CSR values, and
-	 * double check that they are valid.
+	 * they disagree with the CSRs.  If they miscompare, and the PROM addr
+	 * is valid, then the PROM addr is used.
 	 */
 	 */
 	for (i = 0; i < 3; i++) {
 	for (i = 0; i < 3; i++) {
 		unsigned int val;
 		unsigned int val;

+ 2 - 2
drivers/net/spider_net.c

@@ -1442,7 +1442,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
 	case SPIDER_NET_GRFAFLLINT: /* fallthrough */
 	case SPIDER_NET_GRFAFLLINT: /* fallthrough */
 	case SPIDER_NET_GRMFLLINT:
 	case SPIDER_NET_GRMFLLINT:
 		if (netif_msg_intr(card) && net_ratelimit())
 		if (netif_msg_intr(card) && net_ratelimit())
-			pr_err("Spider RX RAM full, incoming packets "
+			pr_debug("Spider RX RAM full, incoming packets "
 			       "might be discarded!\n");
 			       "might be discarded!\n");
 		spider_net_rx_irq_off(card);
 		spider_net_rx_irq_off(card);
 		tasklet_schedule(&card->rxram_full_tl);
 		tasklet_schedule(&card->rxram_full_tl);
@@ -2086,7 +2086,7 @@ spider_net_setup_netdev(struct spider_net_card *card)
 
 
 	spider_net_setup_netdev_ops(netdev);
 	spider_net_setup_netdev_ops(netdev);
 
 
-	netdev->features = 0;
+	netdev->features = NETIF_F_HW_CSUM;
 	/* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
 	/* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
 	 *		NETIF_F_HW_VLAN_FILTER */
 	 *		NETIF_F_HW_VLAN_FILTER */
 
 

+ 21 - 0
drivers/net/via-rhine.c

@@ -1085,6 +1085,25 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
 	else
 	else
 	    iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
 	    iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
 		   ioaddr + ChipCmd1);
 		   ioaddr + ChipCmd1);
+	if (debug > 1)
+		printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name,
+			rp->mii_if.force_media, netif_carrier_ok(dev));
+}
+
+/* Called after status of force_media possibly changed */
+void rhine_set_carrier(struct mii_if_info *mii)
+{
+	if (mii->force_media) {
+		/* autoneg is off: Link is always assumed to be up */
+		if (!netif_carrier_ok(mii->dev))
+			netif_carrier_on(mii->dev);
+	}
+	else	/* Let MMI library update carrier status */
+		rhine_check_media(mii->dev, 0);
+	if (debug > 1)
+		printk(KERN_INFO "%s: force_media %d, carrier %d\n",
+		       mii->dev->name, mii->force_media,
+		       netif_carrier_ok(mii->dev));
 }
 }
 
 
 static void rhine_check_media_task(struct net_device *dev)
 static void rhine_check_media_task(struct net_device *dev)
@@ -1782,6 +1801,7 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 	spin_lock_irq(&rp->lock);
 	spin_lock_irq(&rp->lock);
 	rc = mii_ethtool_sset(&rp->mii_if, cmd);
 	rc = mii_ethtool_sset(&rp->mii_if, cmd);
 	spin_unlock_irq(&rp->lock);
 	spin_unlock_irq(&rp->lock);
+	rhine_set_carrier(&rp->mii_if);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -1869,6 +1889,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 	spin_lock_irq(&rp->lock);
 	spin_lock_irq(&rp->lock);
 	rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL);
 	rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL);
 	spin_unlock_irq(&rp->lock);
 	spin_unlock_irq(&rp->lock);
+	rhine_set_carrier(&rp->mii_if);
 
 
 	return rc;
 	return rc;
 }
 }

+ 6 - 1
drivers/net/wireless/Kconfig

@@ -309,7 +309,10 @@ config APPLE_AIRPORT
 	  Say Y here to support the Airport 802.11b wireless Ethernet hardware
 	  Say Y here to support the Airport 802.11b wireless Ethernet hardware
 	  built into the Macintosh iBook and other recent PowerPC-based
 	  built into the Macintosh iBook and other recent PowerPC-based
 	  Macintosh machines. This is essentially a Lucent Orinoco card with 
 	  Macintosh machines. This is essentially a Lucent Orinoco card with 
-	  a non-standard interface
+	  a non-standard interface.
+
+	  This driver does not support the Airport Extreme (802.11b/g). Use
+	  the BCM43xx driver for Airport Extreme cards.
 
 
 config PLX_HERMES
 config PLX_HERMES
 	tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
 	tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
@@ -401,6 +404,7 @@ config PCMCIA_HERMES
 config PCMCIA_SPECTRUM
 config PCMCIA_SPECTRUM
 	tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
 	tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
 	depends on NET_RADIO && PCMCIA && HERMES
 	depends on NET_RADIO && PCMCIA && HERMES
+	select FW_LOADER
 	---help---
 	---help---
 
 
 	  This is a driver for 802.11b cards using RAM-loadable Symbol
 	  This is a driver for 802.11b cards using RAM-loadable Symbol
@@ -500,6 +504,7 @@ config PRISM54
 	  will be called prism54.ko.
 	  will be called prism54.ko.
 
 
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
+source "drivers/net/wireless/bcm43xx/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

@@ -35,6 +35,7 @@ obj-$(CONFIG_PCMCIA_ATMEL)      += atmel_cs.o
 obj-$(CONFIG_PRISM54)		+= prism54/
 obj-$(CONFIG_PRISM54)		+= prism54/
 
 
 obj-$(CONFIG_HOSTAP)		+= hostap/
 obj-$(CONFIG_HOSTAP)		+= hostap/
+obj-$(CONFIG_BCM43XX)		+= bcm43xx/
 
 
 # 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

+ 62 - 0
drivers/net/wireless/bcm43xx/Kconfig

@@ -0,0 +1,62 @@
+config BCM43XX
+	tristate "Broadcom BCM43xx wireless support"
+	depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+	select FW_LOADER
+	---help---
+	  This is an experimental driver for the Broadcom 43xx wireless chip,
+	  found in the Apple Airport Extreme and various other devices.
+
+config BCM43XX_DEBUG
+	bool "Broadcom BCM43xx debugging (RECOMMENDED)"
+	depends on BCM43XX
+	default y
+	---help---
+	  Broadcom 43xx debugging messages.
+	  Say Y, because the driver is still very experimental and
+	  this will help you get it running.
+
+config BCM43XX_DMA
+	bool
+config BCM43XX_PIO
+	bool
+
+choice
+	prompt "BCM43xx data transfer mode"
+	depends on BCM43XX
+	default BCM43XX_DMA_AND_PIO_MODE
+
+config BCM43XX_DMA_AND_PIO_MODE
+	bool "DMA + PIO"
+	select BCM43XX_DMA
+	select BCM43XX_PIO
+	---help---
+	  Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+	  data transfer modes.
+	  The actually used mode is selectable through the module
+	  parameter "pio". If the module parameter is pio=0, DMA is used.
+	  Otherwise PIO is used. DMA is default.
+
+	  If unsure, choose this option.
+
+config BCM43XX_DMA_MODE
+	bool "DMA (Direct Memory Access) only"
+	select BCM43XX_DMA
+	---help---
+	  Only include Direct Memory Access (DMA).
+	  This reduces the size of the driver module, by omitting the PIO code.
+
+config BCM43XX_PIO_MODE
+	bool "PIO (Programmed I/O) only"
+	select BCM43XX_PIO
+	---help---
+	  Only include Programmed I/O (PIO).
+	  This reduces the size of the driver module, by omitting the DMA code.
+	  Please note that PIO transfers are slow (compared to DMA).
+
+	  Also note that not all devices of the 43xx series support PIO.
+	  The 4306 (Apple Airport Extreme and others) supports PIO, while
+	  the 4318 is known to _not_ support PIO.
+
+	  Only use PIO, if DMA does not work for you.
+
+endchoice

+ 12 - 0
drivers/net/wireless/bcm43xx/Makefile

@@ -0,0 +1,12 @@
+obj-$(CONFIG_BCM43XX) += bcm43xx.o
+bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o
+
+bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o
+bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o
+
+bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \
+		bcm43xx_radio.o bcm43xx_phy.o \
+		bcm43xx_power.o bcm43xx_wx.o \
+		bcm43xx_leds.o bcm43xx_ethtool.o \
+		bcm43xx_xmit.o bcm43xx_sysfs.o \
+		$(bcm43xx-obj-y)

+ 926 - 0
drivers/net/wireless/bcm43xx/bcm43xx.h

@@ -0,0 +1,926 @@
+#ifndef BCM43xx_H_
+#define BCM43xx_H_
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/stringify.h>
+#include <linux/pci.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_leds.h"
+#include "bcm43xx_sysfs.h"
+
+
+#define PFX				KBUILD_MODNAME ": "
+
+#define BCM43xx_SWITCH_CORE_MAX_RETRIES	50
+#define BCM43xx_IRQWAIT_MAX_RETRIES	50
+
+#define BCM43xx_IO_SIZE			8192
+
+/* Active Core PCI Configuration Register. */
+#define BCM43xx_PCICFG_ACTIVE_CORE	0x80
+/* SPROM control register. */
+#define BCM43xx_PCICFG_SPROMCTL		0x88
+/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */
+#define BCM43xx_PCICFG_ICR		0x94
+
+/* MMIO offsets */
+#define BCM43xx_MMIO_DMA1_REASON	0x20
+#define BCM43xx_MMIO_DMA1_IRQ_MASK	0x24
+#define BCM43xx_MMIO_DMA2_REASON	0x28
+#define BCM43xx_MMIO_DMA2_IRQ_MASK	0x2C
+#define BCM43xx_MMIO_DMA3_REASON	0x30
+#define BCM43xx_MMIO_DMA3_IRQ_MASK	0x34
+#define BCM43xx_MMIO_DMA4_REASON	0x38
+#define BCM43xx_MMIO_DMA4_IRQ_MASK	0x3C
+#define BCM43xx_MMIO_STATUS_BITFIELD	0x120
+#define BCM43xx_MMIO_STATUS2_BITFIELD	0x124
+#define BCM43xx_MMIO_GEN_IRQ_REASON	0x128
+#define BCM43xx_MMIO_GEN_IRQ_MASK	0x12C
+#define BCM43xx_MMIO_RAM_CONTROL	0x130
+#define BCM43xx_MMIO_RAM_DATA		0x134
+#define BCM43xx_MMIO_PS_STATUS		0x140
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI	0x158
+#define BCM43xx_MMIO_SHM_CONTROL	0x160
+#define BCM43xx_MMIO_SHM_DATA		0x164
+#define BCM43xx_MMIO_SHM_DATA_UNALIGNED	0x166
+#define BCM43xx_MMIO_XMITSTAT_0		0x170
+#define BCM43xx_MMIO_XMITSTAT_1		0x174
+#define BCM43xx_MMIO_REV3PLUS_TSF_LOW	0x180 /* core rev >= 3 only */
+#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH	0x184 /* core rev >= 3 only */
+#define BCM43xx_MMIO_DMA1_BASE		0x200
+#define BCM43xx_MMIO_DMA2_BASE		0x220
+#define BCM43xx_MMIO_DMA3_BASE		0x240
+#define BCM43xx_MMIO_DMA4_BASE		0x260
+#define BCM43xx_MMIO_PIO1_BASE		0x300
+#define BCM43xx_MMIO_PIO2_BASE		0x310
+#define BCM43xx_MMIO_PIO3_BASE		0x320
+#define BCM43xx_MMIO_PIO4_BASE		0x330
+#define BCM43xx_MMIO_PHY_VER		0x3E0
+#define BCM43xx_MMIO_PHY_RADIO		0x3E2
+#define BCM43xx_MMIO_ANTENNA		0x3E8
+#define BCM43xx_MMIO_CHANNEL		0x3F0
+#define BCM43xx_MMIO_CHANNEL_EXT	0x3F4
+#define BCM43xx_MMIO_RADIO_CONTROL	0x3F6
+#define BCM43xx_MMIO_RADIO_DATA_HIGH	0x3F8
+#define BCM43xx_MMIO_RADIO_DATA_LOW	0x3FA
+#define BCM43xx_MMIO_PHY_CONTROL	0x3FC
+#define BCM43xx_MMIO_PHY_DATA		0x3FE
+#define BCM43xx_MMIO_MACFILTER_CONTROL	0x420
+#define BCM43xx_MMIO_MACFILTER_DATA	0x422
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO	0x49A
+#define BCM43xx_MMIO_GPIO_CONTROL	0x49C
+#define BCM43xx_MMIO_GPIO_MASK		0x49E
+#define BCM43xx_MMIO_TSF_0		0x632 /* core rev < 3 only */
+#define BCM43xx_MMIO_TSF_1		0x634 /* core rev < 3 only */
+#define BCM43xx_MMIO_TSF_2		0x636 /* core rev < 3 only */
+#define BCM43xx_MMIO_TSF_3		0x638 /* core rev < 3 only */
+#define BCM43xx_MMIO_POWERUP_DELAY	0x6A8
+
+/* SPROM offsets. */
+#define BCM43xx_SPROM_BASE		0x1000
+#define BCM43xx_SPROM_BOARDFLAGS2	0x1c
+#define BCM43xx_SPROM_IL0MACADDR	0x24
+#define BCM43xx_SPROM_ET0MACADDR	0x27
+#define BCM43xx_SPROM_ET1MACADDR	0x2a
+#define BCM43xx_SPROM_ETHPHY		0x2d
+#define BCM43xx_SPROM_BOARDREV		0x2e
+#define BCM43xx_SPROM_PA0B0		0x2f
+#define BCM43xx_SPROM_PA0B1		0x30
+#define BCM43xx_SPROM_PA0B2		0x31
+#define BCM43xx_SPROM_WL0GPIO0		0x32
+#define BCM43xx_SPROM_WL0GPIO2		0x33
+#define BCM43xx_SPROM_MAXPWR		0x34
+#define BCM43xx_SPROM_PA1B0		0x35
+#define BCM43xx_SPROM_PA1B1		0x36
+#define BCM43xx_SPROM_PA1B2		0x37
+#define BCM43xx_SPROM_IDL_TSSI_TGT	0x38
+#define BCM43xx_SPROM_BOARDFLAGS	0x39
+#define BCM43xx_SPROM_ANTENNA_GAIN	0x3a
+#define BCM43xx_SPROM_VERSION		0x3f
+
+/* BCM43xx_SPROM_BOARDFLAGS values */
+#define BCM43xx_BFL_BTCOEXIST		0x0001 /* implements Bluetooth coexistance */
+#define BCM43xx_BFL_PACTRL		0x0002 /* GPIO 9 controlling the PA */
+#define BCM43xx_BFL_AIRLINEMODE		0x0004 /* implements GPIO 13 radio disable indication */
+#define BCM43xx_BFL_RSSI		0x0008 /* software calculates nrssi slope. */
+#define BCM43xx_BFL_ENETSPI		0x0010 /* has ephy roboswitch spi */
+#define BCM43xx_BFL_XTAL_NOSLOW		0x0020 /* no slow clock available */
+#define BCM43xx_BFL_CCKHIPWR		0x0040 /* can do high power CCK transmission */
+#define BCM43xx_BFL_ENETADM		0x0080 /* has ADMtek switch */
+#define BCM43xx_BFL_ENETVLAN		0x0100 /* can do vlan */
+#define BCM43xx_BFL_AFTERBURNER		0x0200 /* supports Afterburner mode */
+#define BCM43xx_BFL_NOPCI		0x0400 /* leaves PCI floating */
+#define BCM43xx_BFL_FEM			0x0800 /* supports the Front End Module */
+#define BCM43xx_BFL_EXTLNA		0x1000 /* has an external LNA */
+#define BCM43xx_BFL_HGPA		0x2000 /* had high gain PA */
+#define BCM43xx_BFL_BTCMOD		0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
+#define BCM43xx_BFL_ALTIQ		0x8000 /* alternate I/Q settings */
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define BCM43xx_GPIO_CONTROL		0x6c
+
+/* SHM Routing */
+#define BCM43xx_SHM_SHARED		0x0001
+#define BCM43xx_SHM_WIRELESS		0x0002
+#define BCM43xx_SHM_PCM			0x0003
+#define BCM43xx_SHM_HWMAC		0x0004
+#define BCM43xx_SHM_UCODE		0x0300
+
+/* MacFilter offsets. */
+#define BCM43xx_MACFILTER_SELF		0x0000
+#define BCM43xx_MACFILTER_ASSOC		0x0003
+
+/* Chipcommon registers. */
+#define BCM43xx_CHIPCOMMON_CAPABILITIES 	0x04
+#define BCM43xx_CHIPCOMMON_PLLONDELAY		0xB0
+#define BCM43xx_CHIPCOMMON_FREFSELDELAY		0xB4
+#define BCM43xx_CHIPCOMMON_SLOWCLKCTL		0xB8
+#define BCM43xx_CHIPCOMMON_SYSCLKCTL		0xC0
+
+/* PCI core specific registers. */
+#define BCM43xx_PCICORE_BCAST_ADDR	0x50
+#define BCM43xx_PCICORE_BCAST_DATA	0x54
+#define BCM43xx_PCICORE_SBTOPCI2	0x108
+
+/* SBTOPCI2 values. */
+#define BCM43xx_SBTOPCI2_PREFETCH	0x4
+#define BCM43xx_SBTOPCI2_BURST		0x8
+
+/* Chipcommon capabilities. */
+#define BCM43xx_CAPABILITIES_PCTL		0x00040000
+#define BCM43xx_CAPABILITIES_PLLMASK		0x00030000
+#define BCM43xx_CAPABILITIES_PLLSHIFT		16
+#define BCM43xx_CAPABILITIES_FLASHMASK		0x00000700
+#define BCM43xx_CAPABILITIES_FLASHSHIFT		8
+#define BCM43xx_CAPABILITIES_EXTBUSPRESENT	0x00000040
+#define BCM43xx_CAPABILITIES_UARTGPIO		0x00000020
+#define BCM43xx_CAPABILITIES_UARTCLOCKMASK	0x00000018
+#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT	3
+#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN	0x00000004
+#define BCM43xx_CAPABILITIES_NRUARTSMASK	0x00000003
+
+/* PowerControl */
+#define BCM43xx_PCTL_IN			0xB0
+#define BCM43xx_PCTL_OUT		0xB4
+#define BCM43xx_PCTL_OUTENABLE		0xB8
+#define BCM43xx_PCTL_XTAL_POWERUP	0x40
+#define BCM43xx_PCTL_PLL_POWERDOWN	0x80
+
+/* PowerControl Clock Modes */
+#define BCM43xx_PCTL_CLK_FAST		0x00
+#define BCM43xx_PCTL_CLK_SLOW		0x01
+#define BCM43xx_PCTL_CLK_DYNAMIC	0x02
+
+#define BCM43xx_PCTL_FORCE_SLOW		0x0800
+#define BCM43xx_PCTL_FORCE_PLL		0x1000
+#define BCM43xx_PCTL_DYN_XTAL		0x2000
+
+/* COREIDs */
+#define BCM43xx_COREID_CHIPCOMMON	0x800
+#define BCM43xx_COREID_ILINE20          0x801
+#define BCM43xx_COREID_SDRAM            0x803
+#define BCM43xx_COREID_PCI		0x804
+#define BCM43xx_COREID_MIPS             0x805
+#define BCM43xx_COREID_ETHERNET         0x806
+#define BCM43xx_COREID_V90		0x807
+#define BCM43xx_COREID_USB11_HOSTDEV    0x80a
+#define BCM43xx_COREID_IPSEC            0x80b
+#define BCM43xx_COREID_PCMCIA		0x80d
+#define BCM43xx_COREID_EXT_IF           0x80f
+#define BCM43xx_COREID_80211		0x812
+#define BCM43xx_COREID_MIPS_3302        0x816
+#define BCM43xx_COREID_USB11_HOST       0x817
+#define BCM43xx_COREID_USB11_DEV        0x818
+#define BCM43xx_COREID_USB20_HOST       0x819
+#define BCM43xx_COREID_USB20_DEV        0x81a
+#define BCM43xx_COREID_SDIO_HOST        0x81b
+
+/* Core Information Registers */
+#define BCM43xx_CIR_BASE		0xf00
+#define BCM43xx_CIR_SBTPSFLAG		(BCM43xx_CIR_BASE + 0x18)
+#define BCM43xx_CIR_SBIMSTATE		(BCM43xx_CIR_BASE + 0x90)
+#define BCM43xx_CIR_SBINTVEC		(BCM43xx_CIR_BASE + 0x94)
+#define BCM43xx_CIR_SBTMSTATELOW	(BCM43xx_CIR_BASE + 0x98)
+#define BCM43xx_CIR_SBTMSTATEHIGH	(BCM43xx_CIR_BASE + 0x9c)
+#define BCM43xx_CIR_SBIMCONFIGLOW	(BCM43xx_CIR_BASE + 0xa8)
+#define BCM43xx_CIR_SB_ID_HI		(BCM43xx_CIR_BASE + 0xfc)
+
+/* Mask to get the Backplane Flag Number from SBTPSFLAG. */
+#define BCM43xx_BACKPLANE_FLAG_NR_MASK	0x3f
+
+/* SBIMCONFIGLOW values/masks. */
+#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK		0x00000007
+#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT	0
+#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK		0x00000070
+#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT	4
+#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK		0x00ff0000
+#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT		16
+
+/* sbtmstatelow state flags */
+#define BCM43xx_SBTMSTATELOW_RESET		0x01
+#define BCM43xx_SBTMSTATELOW_REJECT		0x02
+#define BCM43xx_SBTMSTATELOW_CLOCK		0x10000
+#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK	0x20000
+
+/* sbtmstatehigh state flags */
+#define BCM43xx_SBTMSTATEHIGH_SERROR		0x1
+#define BCM43xx_SBTMSTATEHIGH_BUSY		0x4
+
+/* sbimstate flags */
+#define BCM43xx_SBIMSTATE_IB_ERROR		0x20000
+#define BCM43xx_SBIMSTATE_TIMEOUT		0x40000
+
+/* PHYVersioning */
+#define BCM43xx_PHYTYPE_A		0x00
+#define BCM43xx_PHYTYPE_B		0x01
+#define BCM43xx_PHYTYPE_G		0x02
+
+/* PHYRegisters */
+#define BCM43xx_PHY_ILT_A_CTRL		0x0072
+#define BCM43xx_PHY_ILT_A_DATA1		0x0073
+#define BCM43xx_PHY_ILT_A_DATA2		0x0074
+#define BCM43xx_PHY_G_LO_CONTROL	0x0810
+#define BCM43xx_PHY_ILT_G_CTRL		0x0472
+#define BCM43xx_PHY_ILT_G_DATA1		0x0473
+#define BCM43xx_PHY_ILT_G_DATA2		0x0474
+#define BCM43xx_PHY_A_PCTL		0x007B
+#define BCM43xx_PHY_G_PCTL		0x0029
+#define BCM43xx_PHY_A_CRS		0x0029
+#define BCM43xx_PHY_RADIO_BITFIELD	0x0401
+#define BCM43xx_PHY_G_CRS		0x0429
+#define BCM43xx_PHY_NRSSILT_CTRL	0x0803
+#define BCM43xx_PHY_NRSSILT_DATA	0x0804
+
+/* RadioRegisters */
+#define BCM43xx_RADIOCTL_ID		0x01
+
+/* StatusBitField */
+#define BCM43xx_SBF_MAC_ENABLED		0x00000001
+#define BCM43xx_SBF_2			0x00000002 /*FIXME: fix name*/
+#define BCM43xx_SBF_CORE_READY		0x00000004
+#define BCM43xx_SBF_400			0x00000400 /*FIXME: fix name*/
+#define BCM43xx_SBF_4000		0x00004000 /*FIXME: fix name*/
+#define BCM43xx_SBF_8000		0x00008000 /*FIXME: fix name*/
+#define BCM43xx_SBF_XFER_REG_BYTESWAP	0x00010000
+#define BCM43xx_SBF_MODE_NOTADHOC	0x00020000
+#define BCM43xx_SBF_MODE_AP		0x00040000
+#define BCM43xx_SBF_RADIOREG_LOCK	0x00080000
+#define BCM43xx_SBF_MODE_MONITOR	0x00400000
+#define BCM43xx_SBF_MODE_PROMISC	0x01000000
+#define BCM43xx_SBF_PS1			0x02000000
+#define BCM43xx_SBF_PS2			0x04000000
+#define BCM43xx_SBF_NO_SSID_BCAST	0x08000000
+#define BCM43xx_SBF_TIME_UPDATE		0x10000000
+#define BCM43xx_SBF_80000000		0x80000000 /*FIXME: fix name*/
+
+/* MicrocodeFlagsBitfield (addr + lo-word values?)*/
+#define BCM43xx_UCODEFLAGS_OFFSET	0x005E
+
+#define BCM43xx_UCODEFLAG_AUTODIV	0x0001
+#define BCM43xx_UCODEFLAG_UNKBGPHY	0x0002
+#define BCM43xx_UCODEFLAG_UNKBPHY	0x0004
+#define BCM43xx_UCODEFLAG_UNKGPHY	0x0020
+#define BCM43xx_UCODEFLAG_UNKPACTRL	0x0040
+#define BCM43xx_UCODEFLAG_JAPAN		0x0080
+
+/* Generic-Interrupt reasons. */
+#define BCM43xx_IRQ_READY		(1 << 0)
+#define BCM43xx_IRQ_BEACON		(1 << 1)
+#define BCM43xx_IRQ_PS			(1 << 2)
+#define BCM43xx_IRQ_REG124		(1 << 5)
+#define BCM43xx_IRQ_PMQ			(1 << 6)
+#define BCM43xx_IRQ_PIO_WORKAROUND	(1 << 8)
+#define BCM43xx_IRQ_XMIT_ERROR		(1 << 11)
+#define BCM43xx_IRQ_RX			(1 << 15)
+#define BCM43xx_IRQ_SCAN		(1 << 16)
+#define BCM43xx_IRQ_NOISE		(1 << 18)
+#define BCM43xx_IRQ_XMIT_STATUS		(1 << 29)
+
+#define BCM43xx_IRQ_ALL			0xffffffff
+#define BCM43xx_IRQ_INITIAL		(BCM43xx_IRQ_PS |		\
+					 BCM43xx_IRQ_REG124 |		\
+					 BCM43xx_IRQ_PMQ |		\
+					 BCM43xx_IRQ_XMIT_ERROR |	\
+					 BCM43xx_IRQ_RX |		\
+					 BCM43xx_IRQ_SCAN |		\
+					 BCM43xx_IRQ_NOISE |		\
+					 BCM43xx_IRQ_XMIT_STATUS)
+					 
+
+/* Initial default iw_mode */
+#define BCM43xx_INITIAL_IWMODE			IW_MODE_INFRA
+
+/* Bus type PCI. */
+#define BCM43xx_BUSTYPE_PCI	0
+/* Bus type Silicone Backplane Bus. */
+#define BCM43xx_BUSTYPE_SB	1
+/* Bus type PCMCIA. */
+#define BCM43xx_BUSTYPE_PCMCIA	2
+
+/* Threshold values. */
+#define BCM43xx_MIN_RTS_THRESHOLD		1U
+#define BCM43xx_MAX_RTS_THRESHOLD		2304U
+#define BCM43xx_DEFAULT_RTS_THRESHOLD		BCM43xx_MAX_RTS_THRESHOLD
+
+#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT	7
+#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT	4
+
+/* Max size of a security key */
+#define BCM43xx_SEC_KEYSIZE			16
+/* Security algorithms. */
+enum {
+	BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
+	BCM43xx_SEC_ALGO_WEP,
+	BCM43xx_SEC_ALGO_UNKNOWN,
+	BCM43xx_SEC_ALGO_AES,
+	BCM43xx_SEC_ALGO_WEP104,
+	BCM43xx_SEC_ALGO_TKIP,
+};
+
+#ifdef assert
+# undef assert
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+#define assert(expr) \
+	do {									\
+		if (unlikely(!(expr))) {					\
+		printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n",	\
+			#expr, __FILE__, __LINE__, __FUNCTION__);		\
+		}								\
+	} while (0)
+#else
+#define assert(expr)	do { /* nothing */ } while (0)
+#endif
+
+/* rate limited printk(). */
+#ifdef printkl
+# undef printkl
+#endif
+#define printkl(f, x...)  do { if (printk_ratelimit()) printk(f ,##x); } while (0)
+/* rate limited printk() for debugging */
+#ifdef dprintkl
+# undef dprintkl
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+# define dprintkl		printkl
+#else
+# define dprintkl(f, x...)	do { /* nothing */ } while (0)
+#endif
+
+/* Helper macro for if branches.
+ * An if branch marked with this macro is only taken in DEBUG mode.
+ * Example:
+ *	if (DEBUG_ONLY(foo == bar)) {
+ *		do something
+ *	}
+ *	In DEBUG mode, the branch will be taken if (foo == bar).
+ *	In non-DEBUG mode, the branch will never be taken.
+ */
+#ifdef DEBUG_ONLY
+# undef DEBUG_ONLY
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+# define DEBUG_ONLY(x)	(x)
+#else
+# define DEBUG_ONLY(x)	0
+#endif
+
+/* debugging printk() */
+#ifdef dprintk
+# undef dprintk
+#endif
+#ifdef CONFIG_BCM43XX_DEBUG
+# define dprintk(f, x...)  do { printk(f ,##x); } while (0)
+#else
+# define dprintk(f, x...)  do { /* nothing */ } while (0)
+#endif
+
+
+struct net_device;
+struct pci_dev;
+struct bcm43xx_dmaring;
+struct bcm43xx_pioqueue;
+
+struct bcm43xx_initval {
+	u16 offset;
+	u16 size;
+	u32 value;
+} __attribute__((__packed__));
+
+/* Values for bcm430x_sprominfo.locale */
+enum {
+	BCM43xx_LOCALE_WORLD = 0,
+	BCM43xx_LOCALE_THAILAND,
+	BCM43xx_LOCALE_ISRAEL,
+	BCM43xx_LOCALE_JORDAN,
+	BCM43xx_LOCALE_CHINA,
+	BCM43xx_LOCALE_JAPAN,
+	BCM43xx_LOCALE_USA_CANADA_ANZ,
+	BCM43xx_LOCALE_EUROPE,
+	BCM43xx_LOCALE_USA_LOW,
+	BCM43xx_LOCALE_JAPAN_HIGH,
+	BCM43xx_LOCALE_ALL,
+	BCM43xx_LOCALE_NONE,
+};
+
+#define BCM43xx_SPROM_SIZE	64 /* in 16-bit words. */
+struct bcm43xx_sprominfo {
+	u16 boardflags2;
+	u8 il0macaddr[6];
+	u8 et0macaddr[6];
+	u8 et1macaddr[6];
+	u8 et0phyaddr:5;
+	u8 et1phyaddr:5;
+	u8 et0mdcport:1;
+	u8 et1mdcport:1;
+	u8 boardrev;
+	u8 locale:4;
+	u8 antennas_aphy:2;
+	u8 antennas_bgphy:2;
+	u16 pa0b0;
+	u16 pa0b1;
+	u16 pa0b2;
+	u8 wl0gpio0;
+	u8 wl0gpio1;
+	u8 wl0gpio2;
+	u8 wl0gpio3;
+	u8 maxpower_aphy;
+	u8 maxpower_bgphy;
+	u16 pa1b0;
+	u16 pa1b1;
+	u16 pa1b2;
+	u8 idle_tssi_tgt_aphy;
+	u8 idle_tssi_tgt_bgphy;
+	u16 boardflags;
+	u16 antennagain_aphy;
+	u16 antennagain_bgphy;
+};
+
+/* Value pair to measure the LocalOscillator. */
+struct bcm43xx_lopair {
+	s8 low;
+	s8 high;
+	u8 used:1;
+};
+#define BCM43xx_LO_COUNT	(14*4)
+
+struct bcm43xx_phyinfo {
+	/* Hardware Data */
+	u8 version;
+	u8 type;
+	u8 rev;
+	u16 antenna_diversity;
+	u16 savedpctlreg;
+	u16 minlowsig[2];
+	u16 minlowsigpos[2];
+	u8 connected:1,
+	   calibrated:1,
+	   is_locked:1, /* used in bcm43xx_phy_{un}lock() */
+	   dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */
+	/* LO Measurement Data.
+	 * Use bcm43xx_get_lopair() to get a value.
+	 */
+	struct bcm43xx_lopair *_lo_pairs;
+
+	/* TSSI to dBm table in use */
+	const s8 *tssi2dbm;
+	/* idle TSSI value */
+	s8 idle_tssi;
+
+	/* Values from bcm43xx_calc_loopback_gain() */
+	u16 loopback_gain[2];
+
+	/* PHY lock for core.rev < 3
+	 * This lock is only used by bcm43xx_phy_{un}lock()
+	 */
+	spinlock_t lock;
+};
+
+
+struct bcm43xx_radioinfo {
+	u16 manufact;
+	u16 version;
+	u8 revision;
+
+	/* Desired TX power in dBm Q5.2 */
+	u16 txpower_desired;
+	/* TX Power control values. */
+	union {
+		/* B/G PHY */
+		struct {
+			u16 baseband_atten;
+			u16 radio_atten;
+			u16 txctl1;
+			u16 txctl2;
+		};
+		/* A PHY */
+		struct {
+			u16 txpwr_offset;
+		};
+	};
+
+	/* Current Interference Mitigation mode */
+	int interfmode;
+	/* Stack of saved values from the Interference Mitigation code.
+	 * Each value in the stack is layed out as follows:
+	 * bit 0-11:  offset
+	 * bit 12-15: register ID
+	 * bit 16-32: value
+	 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+	 */
+#define BCM43xx_INTERFSTACK_SIZE	26
+	u32 interfstack[BCM43xx_INTERFSTACK_SIZE];
+
+	/* Saved values from the NRSSI Slope calculation */
+	s16 nrssi[2];
+	s32 nrssislope;
+	/* In memory nrssi lookup table. */
+	s8 nrssi_lt[64];
+
+	/* current channel */
+	u8 channel;
+	u8 initial_channel;
+
+	u16 lofcal;
+
+	u16 initval;
+
+	u8 enabled:1;
+	/* ACI (adjacent channel interference) flags. */
+	u8 aci_enable:1,
+	   aci_wlan_automatic:1,
+	   aci_hw_rssi:1;
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct bcm43xx_dma {
+	struct bcm43xx_dmaring *tx_ring0;
+	struct bcm43xx_dmaring *tx_ring1;
+	struct bcm43xx_dmaring *tx_ring2;
+	struct bcm43xx_dmaring *tx_ring3;
+	struct bcm43xx_dmaring *rx_ring0;
+	struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct bcm43xx_pio {
+	struct bcm43xx_pioqueue *queue0;
+	struct bcm43xx_pioqueue *queue1;
+	struct bcm43xx_pioqueue *queue2;
+	struct bcm43xx_pioqueue *queue3;
+};
+
+#define BCM43xx_MAX_80211_CORES		2
+
+#ifdef CONFIG_BCM947XX
+#define core_offset(bcm) (bcm)->current_core_offset
+#else
+#define core_offset(bcm) 0
+#endif
+
+/* Generic information about a core. */
+struct bcm43xx_coreinfo {
+	u8 available:1,
+	   enabled:1,
+	   initialized:1;
+	/** core_id ID number */
+	u16 id;
+	/** core_rev revision number */
+	u8 rev;
+	/** Index number for _switch_core() */
+	u8 index;
+};
+
+/* Additional information for each 80211 core. */
+struct bcm43xx_coreinfo_80211 {
+	/* PHY device. */
+	struct bcm43xx_phyinfo phy;
+	/* Radio device. */
+	struct bcm43xx_radioinfo radio;
+	union {
+		/* DMA context. */
+		struct bcm43xx_dma dma;
+		/* PIO context. */
+		struct bcm43xx_pio pio;
+	};
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct bcm43xx_noise_calculation {
+	struct bcm43xx_coreinfo *core_at_start;
+	u8 channel_at_start;
+	u8 calculation_running:1;
+	u8 nr_samples;
+	s8 samples[8][4];
+};
+
+struct bcm43xx_stats {
+	u8 link_quality;
+	u8 noise;
+	struct iw_statistics wstats;
+	/* Store the last TX/RX times here for updating the leds. */
+	unsigned long last_tx;
+	unsigned long last_rx;
+};
+
+struct bcm43xx_key {
+	u8 enabled:1;
+	u8 algorithm;
+};
+
+struct bcm43xx_private {
+	struct bcm43xx_sysfs sysfs;
+
+	struct ieee80211_device *ieee;
+	struct ieee80211softmac_device *softmac;
+
+	struct net_device *net_dev;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+
+	void __iomem *mmio_addr;
+	unsigned int mmio_len;
+
+	/* Do not use the lock directly. Use the bcm43xx_lock* helper
+	 * functions, to be MMIO-safe. */
+	spinlock_t _lock;
+
+	/* Driver status flags. */
+	u32 initialized:1,		/* init_board() succeed */
+	    was_initialized:1,		/* for PCI suspend/resume. */
+	    shutting_down:1,		/* free_board() in progress */
+	    __using_pio:1,		/* Internal, use bcm43xx_using_pio(). */
+	    bad_frames_preempt:1,	/* Use "Bad Frames Preemption" (default off) */
+	    reg124_set_0x4:1,		/* Some variable to keep track of IRQ stuff. */
+	    powersaving:1,		/* TRUE if we are in PowerSaving mode. FALSE otherwise. */
+	    short_preamble:1,		/* TRUE, if short preamble is enabled. */
+	    firmware_norelease:1;	/* Do not release the firmware. Used on suspend. */
+
+	struct bcm43xx_stats stats;
+
+	/* Bus type we are connected to.
+	 * This is currently always BCM43xx_BUSTYPE_PCI
+	 */
+	u8 bustype;
+
+	u16 board_vendor;
+	u16 board_type;
+	u16 board_revision;
+
+	u16 chip_id;
+	u8 chip_rev;
+	u8 chip_package;
+
+	struct bcm43xx_sprominfo sprom;
+#define BCM43xx_NR_LEDS		4
+	struct bcm43xx_led leds[BCM43xx_NR_LEDS];
+
+	/* The currently active core. */
+	struct bcm43xx_coreinfo *current_core;
+#ifdef CONFIG_BCM947XX
+	/** current core memory offset */
+	u32 current_core_offset;
+#endif
+	struct bcm43xx_coreinfo *active_80211_core;
+	/* coreinfo structs for all possible cores follow.
+	 * Note that a core might not exist.
+	 * So check the coreinfo flags before using it.
+	 */
+	struct bcm43xx_coreinfo core_chipcommon;
+	struct bcm43xx_coreinfo core_pci;
+	struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
+	/* Additional information, specific to the 80211 cores. */
+	struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
+	/* Index of the current 80211 core. If current_core is not
+	 * an 80211 core, this is -1.
+	 */
+	int current_80211_core_idx;
+	/* Number of available 80211 cores. */
+	int nr_80211_available;
+
+	u32 chipcommon_capabilities;
+
+	/* Reason code of the last interrupt. */
+	u32 irq_reason;
+	u32 dma_reason[4];
+	/* saved irq enable/disable state bitfield. */
+	u32 irq_savedstate;
+	/* Link Quality calculation context. */
+	struct bcm43xx_noise_calculation noisecalc;
+
+	/* Threshold values. */
+	//TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
+	u32 rts_threshold;
+
+	/* Interrupt Service Routine tasklet (bottom-half) */
+	struct tasklet_struct isr_tasklet;
+
+	/* Periodic tasks */
+	struct timer_list periodic_tasks;
+	unsigned int periodic_state;
+
+	struct work_struct restart_work;
+
+	/* Informational stuff. */
+	char nick[IW_ESSID_MAX_SIZE + 1];
+
+	/* encryption/decryption */
+	u16 security_offset;
+	struct bcm43xx_key key[54];
+	u8 default_key_idx;
+
+	/* Firmware. */
+	const struct firmware *ucode;
+	const struct firmware *pcm;
+	const struct firmware *initvals0;
+	const struct firmware *initvals1;
+
+	/* Debugging stuff follows. */
+#ifdef CONFIG_BCM43XX_DEBUG
+	struct bcm43xx_dfsentry *dfsentry;
+#endif
+};
+
+/* bcm43xx_(un)lock() protect struct bcm43xx_private.
+ * Note that _NO_ MMIO writes are allowed. If you want to
+ * write to the device through MMIO in the critical section, use
+ * the *_mmio lock functions.
+ * MMIO read-access is allowed, though.
+ */
+#define bcm43xx_lock(bcm, flags)	spin_lock_irqsave(&(bcm)->_lock, flags)
+#define bcm43xx_unlock(bcm, flags)	spin_unlock_irqrestore(&(bcm)->_lock, flags)
+/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
+ * MMIO write-access to the device is allowed.
+ * All MMIO writes are flushed on unlock, so it is guaranteed to not
+ * interfere with other threads writing MMIO registers.
+ */
+#define bcm43xx_lock_mmio(bcm, flags)	bcm43xx_lock(bcm, flags)
+#define bcm43xx_unlock_mmio(bcm, flags)	do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)
+
+static inline
+struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
+{
+	return ieee80211softmac_priv(dev);
+}
+
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+	return bcm->__using_pio;
+}
+#elif defined(CONFIG_BCM43XX_DMA)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+	return 0;
+}
+#elif defined(CONFIG_BCM43XX_PIO)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+	return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+/* Helper functions to access data structures private to the 80211 cores.
+ * Note that we _must_ have an 80211 core mapped when calling
+ * any of these functions.
+ */
+static inline
+struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
+{
+	assert(bcm43xx_using_pio(bcm));
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
+}
+static inline
+struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
+{
+	assert(!bcm43xx_using_pio(bcm));
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
+}
+static inline
+struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
+{
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
+}
+static inline
+struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
+{
+	assert(bcm->current_80211_core_idx >= 0);
+	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
+	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
+}
+
+/* Are we running in init_board() context? */
+static inline
+int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
+{
+	if (bcm->initialized)
+		return 0;
+	if (bcm->shutting_down)
+		return 0;
+	return 1;
+}
+
+static inline
+struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
+					   u16 radio_attenuation,
+					   u16 baseband_attenuation)
+{
+	return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2));
+}
+
+
+static inline
+u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
+{
+	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
+{
+	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
+{
+	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
+{
+	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
+}
+
+static inline
+int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value)
+{
+	return pci_read_config_word(bcm->pci_dev, offset, value);
+}
+
+static inline
+int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value)
+{
+	return pci_read_config_dword(bcm->pci_dev, offset, value);
+}
+
+static inline
+int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value)
+{
+	return pci_write_config_word(bcm->pci_dev, offset, value);
+}
+
+static inline
+int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value)
+{
+	return pci_write_config_dword(bcm->pci_dev, offset, value);
+}
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max)  \
+	({						\
+		typeof(value) __value = (value);	\
+	 	typeof(value) __min = (min);		\
+	 	typeof(value) __max = (max);		\
+	 	if (__value < __min)			\
+	 		__value = __min;		\
+	 	else if (__value > __max)		\
+	 		__value = __max;		\
+	 	__value;				\
+	})
+
+/** Helpers to print MAC addresses. */
+#define BCM43xx_MACFMT		"%02x:%02x:%02x:%02x:%02x:%02x"
+#define BCM43xx_MACARG(x)	((u8*)(x))[0], ((u8*)(x))[1], \
+				((u8*)(x))[2], ((u8*)(x))[3], \
+				((u8*)(x))[4], ((u8*)(x))[5]
+
+#endif /* BCM43xx_H_ */

+ 499 - 0
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c

@@ -0,0 +1,499 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  debugfs driver debugging code
+
+  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_dma.h"
+#include "bcm43xx_pio.h"
+#include "bcm43xx_xmit.h"
+
+#define REALLY_BIG_BUFFER_SIZE	(1024*256)
+
+static struct bcm43xx_debugfs fs;
+static char really_big_buffer[REALLY_BIG_BUFFER_SIZE];
+static DECLARE_MUTEX(big_buffer_sem);
+
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	return count;
+}
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->u.generic_ip;
+	return 0;
+}
+
+#define fappend(fmt, x...)	pos += snprintf(buf + pos, len - pos, fmt , ##x)
+
+static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	struct net_device *net_dev;
+	struct pci_dev *pci_dev;
+	unsigned long flags;
+	u16 tmp16;
+	int i;
+
+	down(&big_buffer_sem);
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		fappend("Board not initialized.\n");
+		goto out;
+	}
+	net_dev = bcm->net_dev;
+	pci_dev = bcm->pci_dev;
+
+	/* This is where the information is written to the "devinfo" file */
+	fappend("*** %s devinfo ***\n", net_dev->name);
+	fappend("vendor:           0x%04x   device:           0x%04x\n",
+		pci_dev->vendor, pci_dev->device);
+	fappend("subsystem_vendor: 0x%04x   subsystem_device: 0x%04x\n",
+		pci_dev->subsystem_vendor, pci_dev->subsystem_device);
+	fappend("IRQ: %d\n", bcm->irq);
+	fappend("mmio_addr: 0x%p   mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len);
+	fappend("chip_id: 0x%04x   chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
+	if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
+		fappend("Radio disabled by hardware!\n");
+	if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4)))
+		fappend("Radio disabled by hardware!\n");
+	fappend("board_vendor: 0x%04x   board_type: 0x%04x\n", bcm->board_vendor,
+	        bcm->board_type);
+
+	fappend("\nCores:\n");
+#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, "	\
+					 "rev: 0x%02x, index: 0x%02x\n",		\
+					 (info).available				\
+						? "available" : "nonavailable",		\
+					 (info).enabled					\
+						? "enabled" : "disabled",		\
+					 (info).id, (info).rev, (info).index)
+	fappend_core("CHIPCOMMON", bcm->core_chipcommon);
+	fappend_core("PCI", bcm->core_pci);
+	fappend_core("first 80211", bcm->core_80211[0]);
+	fappend_core("second 80211", bcm->core_80211[1]);
+#undef fappend_core
+	tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	fappend("LEDs: ");
+	for (i = 0; i < BCM43xx_NR_LEDS; i++)
+		fappend("%d ", !!(tmp16 & (1 << i)));
+	fappend("\n");
+
+out:
+	bcm43xx_unlock_mmio(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+
+	down(&big_buffer_sem);
+
+	/* This is where the information is written to the "driver" file */
+	fappend(KBUILD_MODNAME " driver\n");
+	fappend("Compiled at: %s %s\n", __DATE__, __TIME__);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	unsigned long flags;
+
+	down(&big_buffer_sem);
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		fappend("Board not initialized.\n");
+		goto out;
+	}
+
+	/* This is where the information is written to the "sprom_dump" file */
+	fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
+
+out:
+	bcm43xx_unlock_mmio(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
+			     size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	unsigned long flags;
+	u64 tsf;
+
+	down(&big_buffer_sem);
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		fappend("Board not initialized.\n");
+		goto out;
+	}
+	bcm43xx_tsf_read(bcm, &tsf);
+	fappend("0x%08x%08x\n",
+		(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+		(unsigned int)(tsf & 0xFFFFFFFFULL));
+
+out:
+	bcm43xx_unlock_mmio(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	ssize_t buf_size;
+	ssize_t res;
+	unsigned long flags;
+	u64 tsf;
+
+	buf_size = min(count, sizeof (really_big_buffer) - 1);
+	down(&big_buffer_sem);
+	if (copy_from_user(buf, user_buf, buf_size)) {
+	        res = -EFAULT;
+		goto out_up;
+	}
+	bcm43xx_lock_mmio(bcm, flags);
+	if (!bcm->initialized) {
+		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	if (sscanf(buf, "%lli", &tsf) != 1) {
+		printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n");
+		res = -EINVAL;
+		goto out_unlock;
+	}
+	bcm43xx_tsf_write(bcm, tsf);
+	res = buf_size;
+	
+out_unlock:
+	bcm43xx_unlock_mmio(bcm, flags);
+out_up:
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	const size_t len = REALLY_BIG_BUFFER_SIZE;
+
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	size_t pos = 0;
+	ssize_t res;
+	unsigned long flags;
+	struct bcm43xx_dfsentry *e;
+	struct bcm43xx_xmitstatus *status;
+	int i, cnt, j = 0;
+
+	down(&big_buffer_sem);
+	bcm43xx_lock(bcm, flags);
+
+	fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
+		BCM43xx_NR_LOGGED_XMITSTATUS);
+	e = bcm->dfsentry;
+	if (e->xmitstatus_printing == 0) {
+		/* At the beginning, make a copy of all data to avoid
+		 * concurrency, as this function is called multiple
+		 * times for big logs. Without copying, the data might
+		 * change between reads. This would result in total trash.
+		 */
+		e->xmitstatus_printing = 1;
+		e->saved_xmitstatus_ptr = e->xmitstatus_ptr;
+		e->saved_xmitstatus_cnt = e->xmitstatus_cnt;
+		memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer,
+		       BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer)));
+	}
+	i = e->saved_xmitstatus_ptr - 1;
+	if (i < 0)
+		i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
+	cnt = e->saved_xmitstatus_cnt;
+	while (cnt) {
+		status = e->xmitstatus_print_buffer + i;
+		fappend("0x%02x:   cookie: 0x%04x,  flags: 0x%02x,  "
+			"cnt1: 0x%02x,  cnt2: 0x%02x,  seq: 0x%04x,  "
+			"unk: 0x%04x\n", j,
+			status->cookie, status->flags,
+			status->cnt1, status->cnt2, status->seq,
+			status->unknown);
+		j++;
+		cnt--;
+		i--;
+		if (i < 0)
+			i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
+	}
+
+	bcm43xx_unlock(bcm, flags);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	bcm43xx_lock(bcm, flags);
+	if (*ppos == pos) {
+		/* Done. Drop the copied data. */
+		e->xmitstatus_printing = 0;
+	}
+	bcm43xx_unlock(bcm, flags);
+	up(&big_buffer_sem);
+	return res;
+}
+
+#undef fappend
+
+
+static struct file_operations devinfo_fops = {
+	.read = devinfo_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+static struct file_operations spromdump_fops = {
+	.read = spromdump_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+static struct file_operations drvinfo_fops = {
+	.read = drvinfo_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+static struct file_operations tsf_fops = {
+	.read = tsf_read_file,
+	.write = tsf_write_file,
+	.open = open_file_generic,
+};
+
+static struct file_operations txstat_fops = {
+	.read = txstat_read_file,
+	.write = write_file_dummy,
+	.open = open_file_generic,
+};
+
+
+void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dfsentry *e;
+	char devdir[IFNAMSIZ];
+
+	assert(bcm);
+	e = kzalloc(sizeof(*e), GFP_KERNEL);
+	if (!e) {
+		printk(KERN_ERR PFX "out of memory\n");
+		return;
+	}
+	e->bcm = bcm;
+	e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
+				       * sizeof(*(e->xmitstatus_buffer)),
+				       GFP_KERNEL);
+	if (!e->xmitstatus_buffer) {
+		printk(KERN_ERR PFX "out of memory\n");
+		kfree(e);
+		return;
+	}
+	e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
+					     * sizeof(*(e->xmitstatus_buffer)),
+					     GFP_KERNEL);
+	if (!e->xmitstatus_print_buffer) {
+		printk(KERN_ERR PFX "out of memory\n");
+		kfree(e);
+		return;
+	}
+
+
+	bcm->dfsentry = e;
+
+	strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir));
+	e->subdir = debugfs_create_dir(devdir, fs.root);
+	e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir,
+						bcm, &devinfo_fops);
+	if (!e->dentry_devinfo)
+		printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir);
+	e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir,
+						  bcm, &spromdump_fops);
+	if (!e->dentry_spromdump)
+		printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir);
+	e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir,
+	                                    bcm, &tsf_fops);
+	if (!e->dentry_tsf)
+		printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
+	e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
+						bcm, &txstat_fops);
+	if (!e->dentry_txstat)
+		printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
+}
+
+void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dfsentry *e;
+
+	if (!bcm)
+		return;
+
+	e = bcm->dfsentry;
+	assert(e);
+	debugfs_remove(e->dentry_spromdump);
+	debugfs_remove(e->dentry_devinfo);
+	debugfs_remove(e->dentry_tsf);
+	debugfs_remove(e->dentry_txstat);
+	debugfs_remove(e->subdir);
+	kfree(e->xmitstatus_buffer);
+	kfree(e->xmitstatus_print_buffer);
+	kfree(e);
+}
+
+void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+				struct bcm43xx_xmitstatus *status)
+{
+	struct bcm43xx_dfsentry *e;
+	struct bcm43xx_xmitstatus *savedstatus;
+
+	/* This is protected by bcm->_lock */
+	e = bcm->dfsentry;
+	assert(e);
+	savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr;
+	memcpy(savedstatus, status, sizeof(*status));
+	e->xmitstatus_ptr++;
+	if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS)
+		e->xmitstatus_ptr = 0;
+	if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS)
+		e->xmitstatus_cnt++;
+}
+
+void bcm43xx_debugfs_init(void)
+{
+	memset(&fs, 0, sizeof(fs));
+	fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (!fs.root)
+		printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n");
+	fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
+	if (!fs.dentry_driverinfo)
+		printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n");
+}
+
+void bcm43xx_debugfs_exit(void)
+{
+	debugfs_remove(fs.dentry_driverinfo);
+	debugfs_remove(fs.root);
+}
+
+void bcm43xx_printk_dump(const char *data,
+			 size_t size,
+			 const char *description)
+{
+	size_t i;
+	char c;
+
+	printk(KERN_INFO PFX "Data dump (%s, %u bytes):",
+	       description, size);
+	for (i = 0; i < size; i++) {
+		c = data[i];
+		if (i % 8 == 0)
+			printk("\n" KERN_INFO PFX "0x%08x:  0x%02x, ", i, c & 0xff);
+		else
+			printk("0x%02x, ", c & 0xff);
+	}
+	printk("\n");
+}
+
+void bcm43xx_printk_bitdump(const unsigned char *data,
+			    size_t bytes, int msb_to_lsb,
+			    const char *description)
+{
+	size_t i;
+	int j;
+	const unsigned char *d;
+
+	printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***",
+	       description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
+	for (i = 0; i < bytes; i++) {
+		d = data + i;
+		if (i % 8 == 0)
+			printk("\n" KERN_INFO PFX "0x%08x:  ", i);
+		if (msb_to_lsb) {
+			for (j = 7; j >= 0; j--) {
+				if (*d & (1 << j))
+					printk("1");
+				else
+					printk("0");
+			}
+		} else {
+			for (j = 0; j < 8; j++) {
+				if (*d & (1 << j))
+					printk("1");
+				else
+					printk("0");
+			}
+		}
+		printk(" ");
+	}
+	printk("\n");
+}

+ 117 - 0
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h

@@ -0,0 +1,117 @@
+#ifndef BCM43xx_DEBUGFS_H_
+#define BCM43xx_DEBUGFS_H_
+
+struct bcm43xx_private;
+struct bcm43xx_xmitstatus;
+
+#ifdef CONFIG_BCM43XX_DEBUG
+
+#include <linux/list.h>
+#include <asm/semaphore.h>
+
+struct dentry;
+
+/* limited by the size of the "really_big_buffer" */
+#define BCM43xx_NR_LOGGED_XMITSTATUS	100
+
+struct bcm43xx_dfsentry {
+	struct dentry *subdir;
+	struct dentry *dentry_devinfo;
+	struct dentry *dentry_spromdump;
+	struct dentry *dentry_tsf;
+	struct dentry *dentry_txstat;
+
+	struct bcm43xx_private *bcm;
+
+	/* saved xmitstatus. */
+	struct bcm43xx_xmitstatus *xmitstatus_buffer;
+	int xmitstatus_ptr;
+	int xmitstatus_cnt;
+	/* We need a seperate buffer while printing to avoid
+	 * concurrency issues. (New xmitstatus can arrive
+	 * while we are printing).
+	 */
+	struct bcm43xx_xmitstatus *xmitstatus_print_buffer;
+	int saved_xmitstatus_ptr;
+	int saved_xmitstatus_cnt;
+	int xmitstatus_printing;
+};
+
+struct bcm43xx_debugfs {
+	struct dentry *root;
+	struct dentry *dentry_driverinfo;
+};
+
+void bcm43xx_debugfs_init(void);
+void bcm43xx_debugfs_exit(void);
+void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm);
+void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm);
+void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+				struct bcm43xx_xmitstatus *status);
+
+/* Debug helper: Dump binary data through printk. */
+void bcm43xx_printk_dump(const char *data,
+			 size_t size,
+			 const char *description);
+/* Debug helper: Dump bitwise binary data through printk. */
+void bcm43xx_printk_bitdump(const unsigned char *data,
+			    size_t bytes, int msb_to_lsb,
+			    const char *description);
+#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \
+	do {									\
+		bcm43xx_printk_bitdump((const unsigned char *)(pointer),	\
+				       sizeof(*(pointer)),			\
+				       (msb_to_lsb),				\
+				       (description));				\
+	} while (0)
+
+#else /* CONFIG_BCM43XX_DEBUG*/
+
+static inline
+void bcm43xx_debugfs_init(void) { }
+static inline
+void bcm43xx_debugfs_exit(void) { }
+static inline
+void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { }
+static inline
+void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { }
+static inline
+void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
+				struct bcm43xx_xmitstatus *status) { }
+
+static inline
+void bcm43xx_printk_dump(const char *data,
+			 size_t size,
+			 const char *description)
+{
+}
+static inline
+void bcm43xx_printk_bitdump(const unsigned char *data,
+			    size_t bytes, int msb_to_lsb,
+			    const char *description)
+{
+}
+#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description)  do { /* nothing */ } while (0)
+
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+/* Ugly helper macros to make incomplete code more verbose on runtime */
+#ifdef TODO
+# undef TODO
+#endif
+#define TODO()  \
+	do {										\
+		printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n",	\
+		       __FUNCTION__, __FILE__, __LINE__);				\
+	} while (0)
+
+#ifdef FIXME
+# undef FIXME
+#endif
+#define FIXME()  \
+	do {										\
+		printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n",	\
+		       __FUNCTION__, __FILE__, __LINE__);				\
+	} while (0)
+
+#endif /* BCM43xx_DEBUGFS_H_ */

+ 968 - 0
drivers/net/wireless/bcm43xx/bcm43xx_dma.c

@@ -0,0 +1,968 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  DMA ringbuffer and descriptor allocation/management
+
+  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+
+  Some code in this file is derived from the b44.c driver
+  Copyright (C) 2002 David S. Miller
+  Copyright (C) Pekka Pietikainen
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_dma.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_power.h"
+#include "bcm43xx_xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+
+
+static inline int free_slots(struct bcm43xx_dmaring *ring)
+{
+	return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct bcm43xx_dmaring *ring, int slot)
+{
+	assert(slot >= -1 && slot <= ring->nr_slots - 1);
+	if (slot == ring->nr_slots - 1)
+		return 0;
+	return slot + 1;
+}
+
+static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot)
+{
+	assert(slot >= 0 && slot <= ring->nr_slots - 1);
+	if (slot == 0)
+		return ring->nr_slots - 1;
+	return slot - 1;
+}
+
+/* Request a slot for usage. */
+static inline
+int request_slot(struct bcm43xx_dmaring *ring)
+{
+	int slot;
+
+	assert(ring->tx);
+	assert(!ring->suspended);
+	assert(free_slots(ring) != 0);
+
+	slot = next_slot(ring, ring->current_slot);
+	ring->current_slot = slot;
+	ring->used_slots++;
+
+	/* Check the number of available slots and suspend TX,
+	 * if we are running low on free slots.
+	 */
+	if (unlikely(free_slots(ring) < ring->suspend_mark)) {
+		netif_stop_queue(ring->bcm->net_dev);
+		ring->suspended = 1;
+	}
+#ifdef CONFIG_BCM43XX_DEBUG
+	if (ring->used_slots > ring->max_used_slots)
+		ring->max_used_slots = ring->used_slots;
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+	return slot;
+}
+
+/* Return a slot to the free slots. */
+static inline
+void return_slot(struct bcm43xx_dmaring *ring, int slot)
+{
+	assert(ring->tx);
+
+	ring->used_slots--;
+
+	/* Check if TX is suspended and check if we have
+	 * enough free slots to resume it again.
+	 */
+	if (unlikely(ring->suspended)) {
+		if (free_slots(ring) >= ring->resume_mark) {
+			ring->suspended = 0;
+			netif_wake_queue(ring->bcm->net_dev);
+		}
+	}
+}
+
+static inline
+dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
+			  unsigned char *buf,
+			  size_t len,
+			  int tx)
+{
+	dma_addr_t dmaaddr;
+
+	if (tx) {
+		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+					 buf, len,
+					 DMA_TO_DEVICE);
+	} else {
+		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+					 buf, len,
+					 DMA_FROM_DEVICE);
+	}
+
+	return dmaaddr;
+}
+
+static inline
+void unmap_descbuffer(struct bcm43xx_dmaring *ring,
+		      dma_addr_t addr,
+		      size_t len,
+		      int tx)
+{
+	if (tx) {
+		dma_unmap_single(&ring->bcm->pci_dev->dev,
+				 addr, len,
+				 DMA_TO_DEVICE);
+	} else {
+		dma_unmap_single(&ring->bcm->pci_dev->dev,
+				 addr, len,
+				 DMA_FROM_DEVICE);
+	}
+}
+
+static inline
+void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
+			     dma_addr_t addr,
+			     size_t len)
+{
+	assert(!ring->tx);
+
+	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
+				addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
+				dma_addr_t addr,
+				size_t len)
+{
+	assert(!ring->tx);
+
+	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
+				   addr, len, DMA_FROM_DEVICE);
+}
+
+/* Unmap and free a descriptor buffer. */
+static inline
+void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
+			    struct bcm43xx_dmadesc *desc,
+			    struct bcm43xx_dmadesc_meta *meta,
+			    int irq_context)
+{
+	assert(meta->skb);
+	if (irq_context)
+		dev_kfree_skb_irq(meta->skb);
+	else
+		dev_kfree_skb(meta->skb);
+	meta->skb = NULL;
+}
+
+static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
+{
+	struct device *dev = &(ring->bcm->pci_dev->dev);
+
+	ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+					 &(ring->dmabase), GFP_KERNEL);
+	if (!ring->vbase) {
+		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+		return -ENOMEM;
+	}
+	if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
+		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RINGMEMORY >1G "
+				    "(0x%08x, len: %lu)\n",
+		       ring->dmabase, BCM43xx_DMA_RINGMEMSIZE);
+		dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+				  ring->vbase, ring->dmabase);
+		return -ENOMEM;
+	}
+	assert(!(ring->dmabase & 0x000003FF));
+	memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+
+	return 0;
+}
+
+static void free_ringmemory(struct bcm43xx_dmaring *ring)
+{
+	struct device *dev = &(ring->bcm->pci_dev->dev);
+
+	dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+			  ring->vbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+				   u16 mmio_base)
+{
+	int i;
+	u32 value;
+
+	bcm43xx_write32(bcm,
+			mmio_base + BCM43xx_DMA_RX_CONTROL,
+			0x00000000);
+	for (i = 0; i < 1000; i++) {
+		value = bcm43xx_read32(bcm,
+				       mmio_base + BCM43xx_DMA_RX_STATUS);
+		value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
+		if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
+			i = -1;
+			break;
+		}
+		udelay(10);
+	}
+	if (i != -1) {
+		printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* Reset the RX DMA channel */
+int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+				   u16 mmio_base)
+{
+	int i;
+	u32 value;
+
+	for (i = 0; i < 1000; i++) {
+		value = bcm43xx_read32(bcm,
+				       mmio_base + BCM43xx_DMA_TX_STATUS);
+		value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
+		if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
+		    value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
+		    value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
+			break;
+		udelay(10);
+	}
+	bcm43xx_write32(bcm,
+			mmio_base + BCM43xx_DMA_TX_CONTROL,
+			0x00000000);
+	for (i = 0; i < 1000; i++) {
+		value = bcm43xx_read32(bcm,
+				       mmio_base + BCM43xx_DMA_TX_STATUS);
+		value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
+		if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
+			i = -1;
+			break;
+		}
+		udelay(10);
+	}
+	if (i != -1) {
+		printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n");
+		return -ENODEV;
+	}
+	/* ensure the reset is completed. */
+	udelay(300);
+
+	return 0;
+}
+
+static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
+			       struct bcm43xx_dmadesc *desc,
+			       struct bcm43xx_dmadesc_meta *meta,
+			       gfp_t gfp_flags)
+{
+	struct bcm43xx_rxhdr *rxhdr;
+	dma_addr_t dmaaddr;
+	u32 desc_addr;
+	u32 desc_ctl;
+	const int slot = (int)(desc - ring->vbase);
+	struct sk_buff *skb;
+
+	assert(slot >= 0 && slot < ring->nr_slots);
+	assert(!ring->tx);
+
+	skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+	if (unlikely(!skb))
+		return -ENOMEM;
+	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
+		unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+		dev_kfree_skb_any(skb);
+		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RX SKB >1G "
+				    "(0x%08x, len: %u)\n",
+		       dmaaddr, ring->rx_buffersize);
+		return -ENOMEM;
+	}
+	meta->skb = skb;
+	meta->dmaaddr = dmaaddr;
+	skb->dev = ring->bcm->net_dev;
+	desc_addr = (u32)(dmaaddr + ring->memoffset);
+	desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
+		    (u32)(ring->rx_buffersize - ring->frameoffset));
+	if (slot == ring->nr_slots - 1)
+		desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+	set_desc_addr(desc, desc_addr);
+	set_desc_ctl(desc, desc_ctl);
+
+	rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
+	rxhdr->frame_length = 0;
+	rxhdr->flags1 = 0;
+
+	return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
+{
+	int i, err = -ENOMEM;
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->vbase + i;
+		meta = ring->meta + i;
+
+		err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+		if (err)
+			goto err_unwind;
+	}
+	ring->used_slots = ring->nr_slots;
+	err = 0;
+out:
+	return err;
+
+err_unwind:
+	for (i--; i >= 0; i--) {
+		desc = ring->vbase + i;
+		meta = ring->meta + i;
+
+		unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+		dev_kfree_skb(meta->skb);
+	}
+	goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
+{
+	int err = 0;
+	u32 value;
+
+	if (ring->tx) {
+		/* Set Transmit Control register to "transmit enable" */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+				  BCM43xx_DMA_TXCTRL_ENABLE);
+		/* Set Transmit Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING,
+				  ring->dmabase + ring->memoffset);
+	} else {
+		err = alloc_initial_descbuffers(ring);
+		if (err)
+			goto out;
+		/* Set Receive Control "receive enable" and frame offset */
+		value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
+		value |= BCM43xx_DMA_RXCTRL_ENABLE;
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value);
+		/* Set Receive Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING,
+				  ring->dmabase + ring->memoffset);
+		/* Init the descriptor pointer. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200);
+	}
+
+out:
+	return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
+{
+	if (ring->tx) {
+		bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
+		/* Zero out Transmit Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0);
+	} else {
+		bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
+		/* Zero out Receive Descriptor ring address. */
+		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0);
+	}
+}
+
+static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
+{
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	int i;
+
+	if (!ring->used_slots)
+		return;
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->vbase + i;
+		meta = ring->meta + i;
+
+		if (!meta->skb) {
+			assert(ring->tx);
+			continue;
+		}
+		if (ring->tx) {
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 meta->skb->len, 1);
+		} else {
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 ring->rx_buffersize, 0);
+		}
+		free_descriptor_buffer(ring, desc, meta, 0);
+	}
+}
+
+/* Main initialization function. */
+static
+struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
+					       u16 dma_controller_base,
+					       int nr_descriptor_slots,
+					       int tx)
+{
+	struct bcm43xx_dmaring *ring;
+	int err;
+
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	if (!ring)
+		goto out;
+
+	ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
+			     GFP_KERNEL);
+	if (!ring->meta)
+		goto err_kfree_ring;
+
+	ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
+#ifdef CONFIG_BCM947XX
+	if (bcm->pci_dev->bus->number == 0)
+		ring->memoffset = 0;
+#endif
+
+	ring->bcm = bcm;
+	ring->nr_slots = nr_descriptor_slots;
+	ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
+	ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
+	assert(ring->suspend_mark < ring->resume_mark);
+	ring->mmio_base = dma_controller_base;
+	if (tx) {
+		ring->tx = 1;
+		ring->current_slot = -1;
+	} else {
+		switch (dma_controller_base) {
+		case BCM43xx_MMIO_DMA1_BASE:
+			ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
+			ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
+			break;
+		case BCM43xx_MMIO_DMA4_BASE:
+			ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
+			ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
+			break;
+		default:
+			assert(0);
+		}
+	}
+
+	err = alloc_ringmemory(ring);
+	if (err)
+		goto err_kfree_meta;
+	err = dmacontroller_setup(ring);
+	if (err)
+		goto err_free_ringmemory;
+
+out:
+	return ring;
+
+err_free_ringmemory:
+	free_ringmemory(ring);
+err_kfree_meta:
+	kfree(ring->meta);
+err_kfree_ring:
+	kfree(ring);
+	ring = NULL;
+	goto out;
+}
+
+/* Main cleanup function. */
+static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
+{
+	if (!ring)
+		return;
+
+	dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
+		ring->mmio_base,
+		(ring->tx) ? "TX" : "RX",
+		ring->max_used_slots, ring->nr_slots);
+	/* Device IRQs are disabled prior entering this function,
+	 * so no need to take care of concurrency with rx handler stuff.
+	 */
+	dmacontroller_cleanup(ring);
+	free_all_descbuffers(ring);
+	free_ringmemory(ring);
+
+	kfree(ring->meta);
+	kfree(ring);
+}
+
+void bcm43xx_dma_free(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dma *dma;
+
+	if (bcm43xx_using_pio(bcm))
+		return;
+	dma = bcm43xx_current_dma(bcm);
+
+	bcm43xx_destroy_dmaring(dma->rx_ring1);
+	dma->rx_ring1 = NULL;
+	bcm43xx_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+}
+
+int bcm43xx_dma_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
+	struct bcm43xx_dmaring *ring;
+	int err = -ENOMEM;
+
+	/* setup TX DMA channels. */
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto out;
+	dma->tx_ring0 = ring;
+
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto err_destroy_tx0;
+	dma->tx_ring1 = ring;
+
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto err_destroy_tx1;
+	dma->tx_ring2 = ring;
+
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
+				     BCM43xx_TXRING_SLOTS, 1);
+	if (!ring)
+		goto err_destroy_tx2;
+	dma->tx_ring3 = ring;
+
+	/* setup RX DMA channels. */
+	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
+				     BCM43xx_RXRING_SLOTS, 0);
+	if (!ring)
+		goto err_destroy_tx3;
+	dma->rx_ring0 = ring;
+
+	if (bcm->current_core->rev < 5) {
+		ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
+					     BCM43xx_RXRING_SLOTS, 0);
+		if (!ring)
+			goto err_destroy_rx0;
+		dma->rx_ring1 = ring;
+	}
+
+	dprintk(KERN_INFO PFX "DMA initialized\n");
+	err = 0;
+out:
+	return err;
+
+err_destroy_rx0:
+	bcm43xx_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+err_destroy_tx3:
+	bcm43xx_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+err_destroy_tx2:
+	bcm43xx_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+err_destroy_tx1:
+	bcm43xx_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+err_destroy_tx0:
+	bcm43xx_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+	goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct bcm43xx_dmaring *ring,
+			   int slot)
+{
+	u16 cookie = 0x0000;
+
+	/* Use the upper 4 bits of the cookie as
+	 * DMA controller ID and store the slot number
+	 * in the lower 12 bits
+	 */
+	switch (ring->mmio_base) {
+	default:
+		assert(0);
+	case BCM43xx_MMIO_DMA1_BASE:
+		break;
+	case BCM43xx_MMIO_DMA2_BASE:
+		cookie = 0x1000;
+		break;
+	case BCM43xx_MMIO_DMA3_BASE:
+		cookie = 0x2000;
+		break;
+	case BCM43xx_MMIO_DMA4_BASE:
+		cookie = 0x3000;
+		break;
+	}
+	assert(((u16)slot & 0xF000) == 0x0000);
+	cookie |= (u16)slot;
+
+	return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
+				      u16 cookie, int *slot)
+{
+	struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
+	struct bcm43xx_dmaring *ring = NULL;
+
+	switch (cookie & 0xF000) {
+	case 0x0000:
+		ring = dma->tx_ring0;
+		break;
+	case 0x1000:
+		ring = dma->tx_ring1;
+		break;
+	case 0x2000:
+		ring = dma->tx_ring2;
+		break;
+	case 0x3000:
+		ring = dma->tx_ring3;
+		break;
+	default:
+		assert(0);
+	}
+	*slot = (cookie & 0x0FFF);
+	assert(*slot >= 0 && *slot < ring->nr_slots);
+
+	return ring;
+}
+
+static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
+				  int slot)
+{
+	/* Everything is ready to start. Buffers are DMA mapped and
+	 * associated with slots.
+	 * "slot" is the last slot of the new frame we want to transmit.
+	 * Close your seat belts now, please.
+	 */
+	wmb();
+	slot = next_slot(ring, slot);
+	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX,
+			  (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+}
+
+static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
+			   struct sk_buff *skb,
+			   u8 cur_frag)
+{
+	int slot;
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	u32 desc_ctl;
+	u32 desc_addr;
+
+	assert(skb_shinfo(skb)->nr_frags == 0);
+
+	slot = request_slot(ring);
+	desc = ring->vbase + slot;
+	meta = ring->meta + slot;
+
+	/* Add a device specific TX header. */
+	assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
+	/* Reserve enough headroom for the device tx header. */
+	__skb_push(skb, sizeof(struct bcm43xx_txhdr));
+	/* Now calculate and add the tx header.
+	 * The tx header includes the PLCP header.
+	 */
+	bcm43xx_generate_txhdr(ring->bcm,
+			       (struct bcm43xx_txhdr *)skb->data,
+			       skb->data + sizeof(struct bcm43xx_txhdr),
+			       skb->len - sizeof(struct bcm43xx_txhdr),
+			       (cur_frag == 0),
+			       generate_cookie(ring, slot));
+
+	meta->skb = skb;
+	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
+		return_slot(ring, slot);
+		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA TX SKB >1G "
+				    "(0x%08x, len: %u)\n",
+		       meta->dmaaddr, skb->len);
+		return -ENOMEM;
+	}
+
+	desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
+	desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
+	desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
+	desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
+		     (u32)(meta->skb->len - ring->frameoffset));
+	if (slot == ring->nr_slots - 1)
+		desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+
+	set_desc_ctl(desc, desc_ctl);
+	set_desc_addr(desc, desc_addr);
+	/* Now transfer the whole frame. */
+	dmacontroller_poke_tx(ring, slot);
+
+	return 0;
+}
+
+int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	/* We just received a packet from the kernel network subsystem.
+	 * Add headers and DMA map the memory. Poke
+	 * the device to send the stuff.
+	 * Note that this is called from atomic context.
+	 */
+	struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1;
+	u8 i;
+	struct sk_buff *skb;
+
+	assert(ring->tx);
+	if (unlikely(free_slots(ring) < txb->nr_frags)) {
+		/* The queue should be stopped,
+		 * if we are low on free slots.
+		 * If this ever triggers, we have to lower the suspend_mark.
+		 */
+		dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < txb->nr_frags; i++) {
+		skb = txb->fragments[i];
+		/* Take skb from ieee80211_txb_free */
+		txb->fragments[i] = NULL;
+		dma_tx_fragment(ring, skb, i);
+		//TODO: handle failure of dma_tx_fragment
+	}
+	ieee80211_txb_free(txb);
+
+	return 0;
+}
+
+void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+	struct bcm43xx_dmaring *ring;
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	int is_last_fragment;
+	int slot;
+
+	ring = parse_cookie(bcm, status->cookie, &slot);
+	assert(ring);
+	assert(ring->tx);
+	assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
+	while (1) {
+		assert(slot >= 0 && slot < ring->nr_slots);
+		desc = ring->vbase + slot;
+		meta = ring->meta + slot;
+
+		is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
+		unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
+		free_descriptor_buffer(ring, desc, meta, 1);
+		/* Everything belonging to the slot is unmapped
+		 * and freed, so we can return it.
+		 */
+		return_slot(ring, slot);
+
+		if (is_last_fragment)
+			break;
+		slot = next_slot(ring, slot);
+	}
+	bcm->stats.last_tx = jiffies;
+}
+
+static void dma_rx(struct bcm43xx_dmaring *ring,
+		   int *slot)
+{
+	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_meta *meta;
+	struct bcm43xx_rxhdr *rxhdr;
+	struct sk_buff *skb;
+	u16 len;
+	int err;
+	dma_addr_t dmaaddr;
+
+	desc = ring->vbase + *slot;
+	meta = ring->meta + *slot;
+
+	sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+	skb = meta->skb;
+
+	if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
+		/* We received an xmit status. */
+		struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
+		struct bcm43xx_xmitstatus stat;
+
+		stat.cookie = le16_to_cpu(hw->cookie);
+		stat.flags = hw->flags;
+		stat.cnt1 = hw->cnt1;
+		stat.cnt2 = hw->cnt2;
+		stat.seq = le16_to_cpu(hw->seq);
+		stat.unknown = le16_to_cpu(hw->unknown);
+
+		bcm43xx_debugfs_log_txstat(ring->bcm, &stat);
+		bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat);
+		/* recycle the descriptor buffer. */
+		sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize);
+
+		return;
+	}
+	rxhdr = (struct bcm43xx_rxhdr *)skb->data;
+	len = le16_to_cpu(rxhdr->frame_length);
+	if (len == 0) {
+		int i = 0;
+
+		do {
+			udelay(2);
+			barrier();
+			len = le16_to_cpu(rxhdr->frame_length);
+		} while (len == 0 && i++ < 5);
+		if (unlikely(len == 0)) {
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			goto drop;
+		}
+	}
+	if (unlikely(len > ring->rx_buffersize)) {
+		/* The data did not fit into one descriptor buffer
+		 * and is split over multiple buffers.
+		 * This should never happen, as we try to allocate buffers
+		 * big enough. So simply ignore this packet.
+		 */
+		int cnt = 0;
+		s32 tmp = len;
+
+		while (1) {
+			desc = ring->vbase + *slot;
+			meta = ring->meta + *slot;
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			*slot = next_slot(ring, *slot);
+			cnt++;
+			tmp -= ring->rx_buffersize;
+			if (tmp <= 0)
+				break;
+		}
+		printkl(KERN_ERR PFX "DMA RX buffer too small "
+				     "(len: %u, buffer: %u, nr-dropped: %d)\n",
+		        len, ring->rx_buffersize, cnt);
+		goto drop;
+	}
+	len -= IEEE80211_FCS_LEN;
+
+	dmaaddr = meta->dmaaddr;
+	err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+	if (unlikely(err)) {
+		dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n");
+		sync_descbuffer_for_device(ring, dmaaddr,
+					   ring->rx_buffersize);
+		goto drop;
+	}
+
+	unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+	skb_put(skb, len + ring->frameoffset);
+	skb_pull(skb, ring->frameoffset);
+
+	err = bcm43xx_rx(ring->bcm, skb, rxhdr);
+	if (err) {
+		dev_kfree_skb_irq(skb);
+		goto drop;
+	}
+
+drop:
+	return;
+}
+
+void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
+{
+	u32 status;
+	u16 descptr;
+	int slot, current_slot;
+#ifdef CONFIG_BCM43XX_DEBUG
+	int used_slots = 0;
+#endif
+
+	assert(!ring->tx);
+	status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS);
+	descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
+	current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
+	assert(current_slot >= 0 && current_slot < ring->nr_slots);
+
+	slot = ring->current_slot;
+	for ( ; slot != current_slot; slot = next_slot(ring, slot)) {
+		dma_rx(ring, &slot);
+#ifdef CONFIG_BCM43XX_DEBUG
+		if (++used_slots > ring->max_used_slots)
+			ring->max_used_slots = used_slots;
+#endif
+	}
+	bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX,
+			  (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+	ring->current_slot = slot;
+}
+
+void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
+{
+	assert(ring->tx);
+	bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
+	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+			  bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
+			  | BCM43xx_DMA_TXCTRL_SUSPEND);
+}
+
+void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
+{
+	assert(ring->tx);
+	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
+			  bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
+			  & ~BCM43xx_DMA_TXCTRL_SUSPEND);
+	bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
+}

+ 218 - 0
drivers/net/wireless/bcm43xx/bcm43xx_dma.h

@@ -0,0 +1,218 @@
+#ifndef BCM43xx_DMA_H_
+#define BCM43xx_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+
+/* DMA-Interrupt reasons. */
+#define BCM43xx_DMAIRQ_FATALMASK	((1 << 10) | (1 << 11) | (1 << 12) \
+					 | (1 << 14) | (1 << 15))
+#define BCM43xx_DMAIRQ_NONFATALMASK	(1 << 13)
+#define BCM43xx_DMAIRQ_RX_DONE		(1 << 16)
+
+/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
+#define BCM43xx_DMA_TX_CONTROL		0x00
+#define BCM43xx_DMA_TX_DESC_RING	0x04
+#define BCM43xx_DMA_TX_DESC_INDEX	0x08
+#define BCM43xx_DMA_TX_STATUS		0x0c
+#define BCM43xx_DMA_RX_CONTROL		0x10
+#define BCM43xx_DMA_RX_DESC_RING	0x14
+#define BCM43xx_DMA_RX_DESC_INDEX	0x18
+#define BCM43xx_DMA_RX_STATUS		0x1c
+
+/* DMA controller channel control word values. */
+#define BCM43xx_DMA_TXCTRL_ENABLE		(1 << 0)
+#define BCM43xx_DMA_TXCTRL_SUSPEND		(1 << 1)
+#define BCM43xx_DMA_TXCTRL_LOOPBACK		(1 << 2)
+#define BCM43xx_DMA_TXCTRL_FLUSH		(1 << 4)
+#define BCM43xx_DMA_RXCTRL_ENABLE		(1 << 0)
+#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK	0x000000fe
+#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT	1
+#define BCM43xx_DMA_RXCTRL_PIO			(1 << 8)
+/* DMA controller channel status word values. */
+#define BCM43xx_DMA_TXSTAT_DPTR_MASK		0x00000fff
+#define BCM43xx_DMA_TXSTAT_STAT_MASK		0x0000f000
+#define BCM43xx_DMA_TXSTAT_STAT_DISABLED	0x00000000
+#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE		0x00001000
+#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT	0x00002000
+#define BCM43xx_DMA_TXSTAT_STAT_STOPPED		0x00003000
+#define BCM43xx_DMA_TXSTAT_STAT_SUSP		0x00004000
+#define BCM43xx_DMA_TXSTAT_ERROR_MASK		0x000f0000
+#define BCM43xx_DMA_TXSTAT_FLUSHED		(1 << 20)
+#define BCM43xx_DMA_RXSTAT_DPTR_MASK		0x00000fff
+#define BCM43xx_DMA_RXSTAT_STAT_MASK		0x0000f000
+#define BCM43xx_DMA_RXSTAT_STAT_DISABLED	0x00000000
+#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE		0x00001000
+#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT	0x00002000
+#define BCM43xx_DMA_RXSTAT_STAT_RESERVED	0x00003000
+#define BCM43xx_DMA_RXSTAT_STAT_ERRORS		0x00004000
+#define BCM43xx_DMA_RXSTAT_ERROR_MASK		0x000f0000
+
+/* DMA descriptor control field values. */
+#define BCM43xx_DMADTOR_BYTECNT_MASK		0x00001fff
+#define BCM43xx_DMADTOR_DTABLEEND		(1 << 28) /* End of descriptor table */
+#define BCM43xx_DMADTOR_COMPIRQ			(1 << 29) /* IRQ on completion request */
+#define BCM43xx_DMADTOR_FRAMEEND		(1 << 30)
+#define BCM43xx_DMADTOR_FRAMESTART		(1 << 31)
+
+/* Misc DMA constants */
+#define BCM43xx_DMA_RINGMEMSIZE		PAGE_SIZE
+#define BCM43xx_DMA_BUSADDRMAX		0x3FFFFFFF
+#define BCM43xx_DMA_DMABUSADDROFFSET	(1 << 30)
+#define BCM43xx_DMA1_RX_FRAMEOFFSET	30
+#define BCM43xx_DMA4_RX_FRAMEOFFSET	0
+
+/* DMA engine tuning knobs */
+#define BCM43xx_TXRING_SLOTS		512
+#define BCM43xx_RXRING_SLOTS		64
+#define BCM43xx_DMA1_RXBUFFERSIZE	(2304 + 100)
+#define BCM43xx_DMA4_RXBUFFERSIZE	16
+/* Suspend the tx queue, if less than this percent slots are free. */
+#define BCM43xx_TXSUSPEND_PERCENT	20
+/* Resume the tx queue, if more than this percent slots are free. */
+#define BCM43xx_TXRESUME_PERCENT	50
+
+
+
+#ifdef CONFIG_BCM43XX_DMA
+
+
+struct sk_buff;
+struct bcm43xx_private;
+struct bcm43xx_xmitstatus;
+
+
+struct bcm43xx_dmadesc {
+	__le32 _control;
+	__le32 _address;
+} __attribute__((__packed__));
+
+/* Macros to access the bcm43xx_dmadesc struct */
+#define get_desc_ctl(desc)		le32_to_cpu((desc)->_control)
+#define set_desc_ctl(desc, ctl)		do { (desc)->_control = cpu_to_le32(ctl); } while (0)
+#define get_desc_addr(desc)		le32_to_cpu((desc)->_address)
+#define set_desc_addr(desc, addr)	do { (desc)->_address = cpu_to_le32(addr); } while (0)
+
+struct bcm43xx_dmadesc_meta {
+	/* The kernel DMA-able buffer. */
+	struct sk_buff *skb;
+	/* DMA base bus-address of the descriptor buffer. */
+	dma_addr_t dmaaddr;
+};
+
+struct bcm43xx_dmaring {
+	struct bcm43xx_private *bcm;
+	/* Kernel virtual base address of the ring memory. */
+	struct bcm43xx_dmadesc *vbase;
+	/* DMA memory offset */
+	dma_addr_t memoffset;
+	/* (Unadjusted) DMA base bus-address of the ring memory. */
+	dma_addr_t dmabase;
+	/* Meta data about all descriptors. */
+	struct bcm43xx_dmadesc_meta *meta;
+	/* Number of descriptor slots in the ring. */
+	int nr_slots;
+	/* Number of used descriptor slots. */
+	int used_slots;
+	/* Currently used slot in the ring. */
+	int current_slot;
+	/* Marks to suspend/resume the queue. */
+	int suspend_mark;
+	int resume_mark;
+	/* Frameoffset in octets. */
+	u32 frameoffset;
+	/* Descriptor buffer size. */
+	u16 rx_buffersize;
+	/* The MMIO base register of the DMA controller, this
+	 * ring is posted to.
+	 */
+	u16 mmio_base;
+	u8 tx:1,	/* TRUE, if this is a TX ring. */
+	   suspended:1;	/* TRUE, if transfers are suspended on this ring. */
+#ifdef CONFIG_BCM43XX_DEBUG
+	/* Maximum number of used slots. */
+	int max_used_slots;
+#endif /* CONFIG_BCM43XX_DEBUG*/
+};
+
+
+static inline
+u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
+		     u16 offset)
+{
+	return bcm43xx_read32(ring->bcm, ring->mmio_base + offset);
+}
+
+static inline
+void bcm43xx_dma_write(struct bcm43xx_dmaring *ring,
+		       u16 offset, u32 value)
+{
+	bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value);
+}
+
+
+int bcm43xx_dma_init(struct bcm43xx_private *bcm);
+void bcm43xx_dma_free(struct bcm43xx_private *bcm);
+
+int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base);
+int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base);
+
+void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
+void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
+
+void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status);
+
+int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb);
+void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
+
+
+#else /* CONFIG_BCM43XX_DMA */
+
+
+static inline
+int bcm43xx_dma_init(struct bcm43xx_private *bcm)
+{
+	return 0;
+}
+static inline
+void bcm43xx_dma_free(struct bcm43xx_private *bcm)
+{
+}
+static inline
+int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base)
+{
+	return 0;
+}
+static inline
+int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+				   u16 dmacontroller_mmio_base)
+{
+	return 0;
+}
+static inline
+int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	return 0;
+}
+static inline
+void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+}
+static inline
+void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
+{
+}
+
+#endif /* CONFIG_BCM43XX_DMA */
+#endif /* BCM43xx_DMA_H_ */

+ 50 - 0
drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c

@@ -0,0 +1,50 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  ethtool support
+
+  Copyright (c) 2006 Jason Lunz <lunz@falooley.org>
+
+  Some code in this file is derived from the 8139too.c driver
+  Copyright (C) 2002 Jeff Garzik
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_ethtool.h"
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/version.h>
+
+
+static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(dev);
+
+	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+	strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
+}
+
+struct ethtool_ops bcm43xx_ethtool_ops = {
+	.get_drvinfo = bcm43xx_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};

+ 8 - 0
drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h

@@ -0,0 +1,8 @@
+#ifndef BCM43xx_ETHTOOL_H_
+#define BCM43xx_ETHTOOL_H_
+
+#include <linux/ethtool.h>
+
+extern struct ethtool_ops bcm43xx_ethtool_ops;
+
+#endif /* BCM43xx_ETHTOOL_H_ */

+ 337 - 0
drivers/net/wireless/bcm43xx/bcm43xx_ilt.c

@@ -0,0 +1,337 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_ilt.h"
+#include "bcm43xx_phy.h"
+
+
+/**** Initial Internal Lookup Tables ****/
+
+const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = {
+	0xFEB93FFD, 0xFEC63FFD, /* 0 */
+	0xFED23FFD, 0xFEDF3FFD,
+	0xFEEC3FFE, 0xFEF83FFE,
+	0xFF053FFE, 0xFF113FFE,
+	0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
+	0xFF373FFF, 0xFF443FFF,
+	0xFF503FFF, 0xFF5D3FFF,
+	0xFF693FFF, 0xFF763FFF,
+	0xFF824000, 0xFF8F4000, /* 16 */
+	0xFF9B4000, 0xFFA84000,
+	0xFFB54000, 0xFFC14000,
+	0xFFCE4000, 0xFFDA4000,
+	0xFFE74000, 0xFFF34000, /* 24 */
+	0x00004000, 0x000D4000,
+	0x00194000, 0x00264000,
+	0x00324000, 0x003F4000,
+	0x004B4000, 0x00584000, /* 32 */
+	0x00654000, 0x00714000,
+	0x007E4000, 0x008A3FFF,
+	0x00973FFF, 0x00A33FFF,
+	0x00B03FFF, 0x00BC3FFF, /* 40 */
+	0x00C93FFF, 0x00D63FFF,
+	0x00E23FFE, 0x00EF3FFE,
+	0x00FB3FFE, 0x01083FFE,
+	0x01143FFE, 0x01213FFD, /* 48 */
+	0x012E3FFD, 0x013A3FFD,
+	0x01473FFD,
+};
+
+const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = {
+	0xDB93CB87, 0xD666CF64, /* 0 */
+	0xD1FDD358, 0xCDA6D826,
+	0xCA38DD9F, 0xC729E2B4,
+	0xC469E88E, 0xC26AEE2B,
+	0xC0DEF46C, 0xC073FA62, /* 8 */
+	0xC01D00D5, 0xC0760743,
+	0xC1560D1E, 0xC2E51369,
+	0xC4ED18FF, 0xC7AC1ED7,
+	0xCB2823B2, 0xCEFA28D9, /* 16 */
+	0xD2F62D3F, 0xD7BB3197,
+	0xDCE53568, 0xE1FE3875,
+	0xE7D13B35, 0xED663D35,
+	0xF39B3EC4, 0xF98E3FA7, /* 24 */
+	0x00004000, 0x06723FA7,
+	0x0C653EC4, 0x129A3D35,
+	0x182F3B35, 0x1E023875,
+	0x231B3568, 0x28453197, /* 32 */
+	0x2D0A2D3F, 0x310628D9,
+	0x34D823B2, 0x38541ED7,
+	0x3B1318FF, 0x3D1B1369,
+	0x3EAA0D1E, 0x3F8A0743, /* 40 */
+	0x3FE300D5, 0x3F8DFA62,
+	0x3F22F46C, 0x3D96EE2B,
+	0x3B97E88E, 0x38D7E2B4,
+	0x35C8DD9F, 0x325AD826, /* 48 */
+	0x2E03D358, 0x299ACF64,
+	0x246DCB87,
+};
+
+const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = {
+	0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
+ 	0x0202, 0x0282, 0x0302, 0x0382,
+ 	0x0402, 0x0482, 0x0502, 0x0582,
+ 	0x05E2, 0x0662, 0x06E2, 0x0762,
+ 	0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
+ 	0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+ 	0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+ 	0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+ 	0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
+ 	0x1062, 0x10C2, 0x1122, 0x1182,
+ 	0x11E2, 0x1242, 0x12A2, 0x12E2,
+ 	0x1342, 0x13A2, 0x1402, 0x1442,
+ 	0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
+ 	0x15E2, 0x1622, 0x1662, 0x16C1,
+ 	0x1701, 0x1741, 0x1781, 0x17E1,
+ 	0x1821, 0x1861, 0x18A1, 0x18E1,
+ 	0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
+ 	0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+ 	0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+ 	0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+ 	0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
+ 	0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+ 	0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+ 	0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+ 	0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
+ 	0x2001, 0x2041, 0x2061, 0x2081,
+ 	0x20A1, 0x20C1, 0x20E1, 0x2101,
+ 	0x2121, 0x2141, 0x2161, 0x2181,
+ 	0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
+ 	0x2221, 0x2241, 0x2261, 0x2281,
+ 	0x22A1, 0x22C1, 0x22C1, 0x22E1,
+ 	0x2301, 0x2321, 0x2341, 0x2361,
+ 	0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
+ 	0x23E1, 0x23E1, 0x2401, 0x2421,
+ 	0x2441, 0x2441, 0x2461, 0x2481,
+ 	0x2481, 0x24A1, 0x24C1, 0x24C1,
+ 	0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
+ 	0x2541, 0x2541, 0x2561, 0x2561,
+ 	0x2581, 0x25A1, 0x25A1, 0x25C1,
+ 	0x25C1, 0x25E1, 0x2601, 0x2601,
+ 	0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
+ 	0x2661, 0x2661, 0x2681, 0x2681,
+ 	0x26A1, 0x26A1, 0x26C1, 0x26C1,
+ 	0x26E1, 0x26E1, 0x2701, 0x2701,
+ 	0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
+ 	0x2760, 0x2760, 0x2780, 0x2780,
+ 	0x2780, 0x27A0, 0x27A0, 0x27C0,
+ 	0x27C0, 0x27E0, 0x27E0, 0x27E0,
+ 	0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
+ 	0x2820, 0x2840, 0x2840, 0x2840,
+ 	0x2860, 0x2860, 0x2880, 0x2880,
+ 	0x2880, 0x28A0, 0x28A0, 0x28A0,
+ 	0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
+ 	0x28E0, 0x28E0, 0x2900, 0x2900,
+ 	0x2900, 0x2920, 0x2920, 0x2920,
+ 	0x2940, 0x2940, 0x2940, 0x2960,
+ 	0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
+ 	0x2980, 0x2980, 0x29A0, 0x29A0,
+ 	0x29A0, 0x29A0, 0x29C0, 0x29C0,
+ 	0x29C0, 0x29E0, 0x29E0, 0x29E0,
+ 	0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
+ 	0x2A00, 0x2A20, 0x2A20, 0x2A20,
+ 	0x2A20, 0x2A40, 0x2A40, 0x2A40,
+ 	0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = {
+	0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
+	0x05A9, 0x0669, 0x0709, 0x0789,
+	0x0829, 0x08A9, 0x0929, 0x0989,
+	0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+	0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
+	0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+	0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+	0x0FA9, 0x0FE9, 0x1029, 0x1089,
+	0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
+	0x11E9, 0x1229, 0x1289, 0x12C9,
+	0x1309, 0x1349, 0x1389, 0x13C9,
+	0x1409, 0x1449, 0x14A9, 0x14E9,
+	0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
+	0x1629, 0x1669, 0x16A9, 0x16E8,
+	0x1728, 0x1768, 0x17A8, 0x17E8,
+	0x1828, 0x1868, 0x18A8, 0x18E8,
+	0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
+	0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+	0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+	0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+	0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
+	0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+	0x1F48, 0x1F88, 0x1FE8, 0x2028,
+	0x2068, 0x20A8, 0x2108, 0x2148,
+	0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
+	0x22C8, 0x2308, 0x2348, 0x23A8,
+	0x23E8, 0x2448, 0x24A8, 0x24E8,
+	0x2548, 0x25A8, 0x2608, 0x2668,
+	0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
+	0x2847, 0x28C7, 0x2947, 0x29A7,
+	0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+	0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+	0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
+	0x3806, 0x38A6, 0x3946, 0x39E6,
+	0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+	0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+	0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
+	0x3F45, 0x3FA5, 0x4005, 0x4045,
+	0x40A5, 0x40E5, 0x4145, 0x4185,
+	0x41E5, 0x4225, 0x4265, 0x42C5,
+	0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
+	0x4424, 0x4464, 0x44C4, 0x4504,
+	0x4544, 0x4584, 0x45C4, 0x4604,
+	0x4644, 0x46A4, 0x46E4, 0x4724,
+	0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
+	0x4864, 0x48A4, 0x48E4, 0x4924,
+	0x4964, 0x49A4, 0x49E4, 0x4A24,
+	0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+	0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
+	0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+	0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+	0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+	0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
+	0x5083, 0x50C3, 0x5103, 0x5143,
+	0x5183, 0x51E2, 0x5222, 0x5262,
+	0x52A2, 0x52E2, 0x5342, 0x5382,
+	0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
+	0x5502, 0x5542, 0x55A2, 0x55E2,
+	0x5642, 0x5682, 0x56E2, 0x5722,
+	0x5782, 0x57E1, 0x5841, 0x58A1,
+	0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
+	0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+	0x5C61, 0x5D01, 0x5D80, 0x5E20,
+	0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = {
+	0x0001, 0x0001, 0x0001, 0xFFFE,
+	0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = {
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = {
+	0x013C, 0x01F5, 0x031A, 0x0631,
+	0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = {
+	0x5484, 0x3C40, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = {
+	0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
+	0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+	0x1A1D, 0x1719, 0x1616, 0x1414,
+	0x1414, 0x1400, 0x1414, 0x1614,
+	0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
+	0x2A27, 0x2F2A, 0x332D, 0x3B35,
+	0x5140, 0x6C62, 0x0077,
+};
+
+const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = {
+	0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+	0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+	0x969B, 0x9195, 0x8F8F, 0x8A8A,
+	0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+	0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
+	0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+	0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = {
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = {
+	0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
+	0x0067, 0x0063, 0x005E, 0x0059,
+	0x0054, 0x0050, 0x004B, 0x0046,
+	0x0042, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x0000, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x0042, 0x0046, 0x004B, 0x0050,
+	0x0054, 0x0059, 0x005E, 0x0063,
+	0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
+	0x007A,
+};
+
+const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = {
+	0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
+	0x00D6, 0x00D4, 0x00D2, 0x00CF,
+	0x00CD, 0x00CA, 0x00C7, 0x00C4,
+	0x00C1, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x0000, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00C1, 0x00C4, 0x00C7, 0x00CA,
+	0x00CD, 0x00CF, 0x00D2, 0x00D4,
+	0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
+	0x00DE,
+};
+
+/**** Helper functions to access the device Internal Lookup Tables ****/
+
+void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
+		mmiowb();
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val);
+	} else {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
+		mmiowb();
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val);
+	}
+}
+
+u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
+		return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1);
+	} else {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
+		return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1);
+	}
+}

+ 32 - 0
drivers/net/wireless/bcm43xx/bcm43xx_ilt.h

@@ -0,0 +1,32 @@
+#ifndef BCM43xx_ILT_H_
+#define BCM43xx_ILT_H_
+
+#define BCM43xx_ILT_ROTOR_SIZE		53
+extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE];
+#define BCM43xx_ILT_RETARD_SIZE		53
+extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE];
+#define BCM43xx_ILT_FINEFREQA_SIZE	256
+extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE];
+#define BCM43xx_ILT_FINEFREQG_SIZE	256
+extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE];
+#define BCM43xx_ILT_NOISEA2_SIZE	8
+extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE];
+#define BCM43xx_ILT_NOISEA3_SIZE	8
+extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE];
+#define BCM43xx_ILT_NOISEG1_SIZE	8
+extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE];
+#define BCM43xx_ILT_NOISEG2_SIZE	8
+extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE];
+#define BCM43xx_ILT_NOISESCALEG_SIZE	27
+extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE];
+extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE];
+extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE];
+#define BCM43xx_ILT_SIGMASQR_SIZE	53
+extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE];
+extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE];
+
+
+void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
+u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset);
+
+#endif /* BCM43xx_ILT_H_ */

+ 293 - 0
drivers/net/wireless/bcm43xx/bcm43xx_leds.c

@@ -0,0 +1,293 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx_leds.h"
+#include "bcm43xx.h"
+
+#include <asm/bitops.h>
+
+
+static void bcm43xx_led_changestate(struct bcm43xx_led *led)
+{
+	struct bcm43xx_private *bcm = led->bcm;
+	const int index = bcm43xx_led_index(led);
+	const u16 mask = (1 << index);
+	u16 ledctl;
+
+	assert(index >= 0 && index < BCM43xx_NR_LEDS);
+	assert(led->blink_interval);
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void bcm43xx_led_blink(unsigned long d)
+{
+	struct bcm43xx_led *led = (struct bcm43xx_led *)d;
+	struct bcm43xx_private *bcm = led->bcm;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (led->blink_interval) {
+		bcm43xx_led_changestate(led);
+		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
+				    unsigned long interval)
+{
+	if (led->blink_interval)
+		return;
+	led->blink_interval = interval;
+	bcm43xx_led_changestate(led);
+	led->blink_timer.expires = jiffies + interval;
+	add_timer(&led->blink_timer);
+}
+
+static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
+{
+	struct bcm43xx_private *bcm = led->bcm;
+	const int index = bcm43xx_led_index(led);
+	u16 ledctl;
+
+	if (!led->blink_interval)
+		return;
+	if (unlikely(sync))
+		del_timer_sync(&led->blink_timer);
+	else
+		del_timer(&led->blink_timer);
+	led->blink_interval = 0;
+
+	/* Make sure the LED is turned off. */
+	assert(index >= 0 && index < BCM43xx_NR_LEDS);
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	if (led->activelow)
+		ledctl |= (1 << index);
+	else
+		ledctl &= ~(1 << index);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
+				       struct bcm43xx_led *led,
+				       int led_index)
+{
+	/* This function is called, if the behaviour (and activelow)
+	 * information for a LED is missing in the SPROM.
+	 * We hardcode the behaviour values for various devices here.
+	 * Note that the BCM43xx_LED_TEST_XXX behaviour values can
+	 * be used to figure out which led is mapped to which index.
+	 */
+
+	switch (led_index) {
+	case 0:
+		led->behaviour = BCM43xx_LED_ACTIVITY;
+		if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
+			led->behaviour = BCM43xx_LED_RADIO_ALL;
+		break;
+	case 1:
+		led->behaviour = BCM43xx_LED_RADIO_B;
+		if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
+			led->behaviour = BCM43xx_LED_ASSOC;
+		break;
+	case 2:
+		led->behaviour = BCM43xx_LED_RADIO_A;
+		break;
+	case 3:
+		led->behaviour = BCM43xx_LED_OFF;
+		break;
+	default:
+		assert(0);
+	}
+}
+
+int bcm43xx_leds_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_led *led;
+	u8 sprom[4];
+	int i;
+
+	sprom[0] = bcm->sprom.wl0gpio0;
+	sprom[1] = bcm->sprom.wl0gpio1;
+	sprom[2] = bcm->sprom.wl0gpio2;
+	sprom[3] = bcm->sprom.wl0gpio3;
+
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+		led->bcm = bcm;
+		setup_timer(&led->blink_timer,
+			    bcm43xx_led_blink,
+			    (unsigned long)led);
+
+		if (sprom[i] == 0xFF) {
+			bcm43xx_led_init_hardcoded(bcm, led, i);
+		} else {
+			led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
+			led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
+		}
+	}
+
+	return 0;
+}
+
+void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_led *led;
+	int i;
+
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+		bcm43xx_led_blink_stop(led, 1);
+	}
+	bcm43xx_leds_switch_all(bcm, 0);
+}
+
+void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
+{
+	struct bcm43xx_led *led;
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
+	int i, turn_on;
+	unsigned long interval = 0;
+	u16 ledctl;
+
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+
+		turn_on = 0;
+		switch (led->behaviour) {
+		case BCM43xx_LED_INACTIVE:
+			continue;
+		case BCM43xx_LED_OFF:
+			break;
+		case BCM43xx_LED_ON:
+			turn_on = 1;
+			break;
+		case BCM43xx_LED_ACTIVITY:
+			turn_on = activity;
+			break;
+		case BCM43xx_LED_RADIO_ALL:
+			turn_on = radio->enabled;
+			break;
+		case BCM43xx_LED_RADIO_A:
+			turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+			break;
+		case BCM43xx_LED_RADIO_B:
+			turn_on = (radio->enabled &&
+				   (phy->type == BCM43xx_PHYTYPE_B ||
+				    phy->type == BCM43xx_PHYTYPE_G));
+			break;
+		case BCM43xx_LED_MODE_BG:
+			if (phy->type == BCM43xx_PHYTYPE_G &&
+			    1/*FIXME: using G rates.*/)
+				turn_on = 1;
+			break;
+		case BCM43xx_LED_TRANSFER:
+			if (transferring)
+				bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
+			else
+				bcm43xx_led_blink_stop(led, 0);
+			continue;
+		case BCM43xx_LED_APTRANSFER:
+			if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
+				if (transferring) {
+					interval = BCM43xx_LEDBLINK_FAST;
+					turn_on = 1;
+				}
+			} else {
+				turn_on = 1;
+				if (0/*TODO: not assoc*/)
+					interval = BCM43xx_LEDBLINK_SLOW;
+				else if (transferring)
+					interval = BCM43xx_LEDBLINK_FAST;
+				else
+					turn_on = 0;
+			}
+			if (turn_on)
+				bcm43xx_led_blink_start(led, interval);
+			else
+				bcm43xx_led_blink_stop(led, 0);
+			continue;
+		case BCM43xx_LED_WEIRD:
+			//TODO
+			break;
+		case BCM43xx_LED_ASSOC:
+			if (bcm->softmac->associated)
+				turn_on = 1;
+			break;
+#ifdef CONFIG_BCM43XX_DEBUG
+		case BCM43xx_LED_TEST_BLINKSLOW:
+			bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
+			continue;
+		case BCM43xx_LED_TEST_BLINKMEDIUM:
+			bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
+			continue;
+		case BCM43xx_LED_TEST_BLINKFAST:
+			bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
+			continue;
+#endif /* CONFIG_BCM43XX_DEBUG */
+		default:
+			assert(0);
+		};
+
+		if (led->activelow)
+			turn_on = !turn_on;
+		if (turn_on)
+			ledctl |= (1 << i);
+		else
+			ledctl &= ~(1 << i);
+	}
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}
+
+void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
+{
+	struct bcm43xx_led *led;
+	u16 ledctl;
+	int i;
+	int bit_on;
+
+	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
+	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
+		led = &(bcm->leds[i]);
+		if (led->behaviour == BCM43xx_LED_INACTIVE)
+			continue;
+		if (on)
+			bit_on = led->activelow ? 0 : 1;
+		else
+			bit_on = led->activelow ? 1 : 0;
+		if (bit_on)
+			ledctl |= (1 << i);
+		else
+			ledctl &= ~(1 << i);
+	}
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+}

+ 56 - 0
drivers/net/wireless/bcm43xx/bcm43xx_leds.h

@@ -0,0 +1,56 @@
+#ifndef BCM43xx_LEDS_H_
+#define BCM43xx_LEDS_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+
+struct bcm43xx_led {
+	u8 behaviour:7;
+	u8 activelow:1;
+
+	struct bcm43xx_private *bcm;
+	struct timer_list blink_timer;
+	unsigned long blink_interval;
+};
+#define bcm43xx_led_index(led)	((int)((led) - (led)->bcm->leds))
+
+/* Delay between state changes when blinking in jiffies */
+#define BCM43xx_LEDBLINK_SLOW		(HZ / 1)
+#define BCM43xx_LEDBLINK_MEDIUM		(HZ / 4)
+#define BCM43xx_LEDBLINK_FAST		(HZ / 8)
+
+#define BCM43xx_LED_XFER_THRES		(HZ / 100)
+
+#define BCM43xx_LED_BEHAVIOUR		0x7F
+#define BCM43xx_LED_ACTIVELOW		0x80
+enum { /* LED behaviour values */
+	BCM43xx_LED_OFF,
+	BCM43xx_LED_ON,
+	BCM43xx_LED_ACTIVITY,
+	BCM43xx_LED_RADIO_ALL,
+	BCM43xx_LED_RADIO_A,
+	BCM43xx_LED_RADIO_B,
+	BCM43xx_LED_MODE_BG,
+	BCM43xx_LED_TRANSFER,
+	BCM43xx_LED_APTRANSFER,
+	BCM43xx_LED_WEIRD,//FIXME
+	BCM43xx_LED_ASSOC,
+	BCM43xx_LED_INACTIVE,
+
+	/* Behaviour values for testing.
+	 * With these values it is easier to figure out
+	 * the real behaviour of leds, in case the SPROM
+	 * is missing information.
+	 */
+	BCM43xx_LED_TEST_BLINKSLOW,
+	BCM43xx_LED_TEST_BLINKMEDIUM,
+	BCM43xx_LED_TEST_BLINKFAST,
+};
+
+int bcm43xx_leds_init(struct bcm43xx_private *bcm);
+void bcm43xx_leds_exit(struct bcm43xx_private *bcm);
+void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity);
+void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on);
+
+#endif /* BCM43xx_LEDS_H_ */

+ 3973 - 0
drivers/net/wireless/bcm43xx/bcm43xx_main.c

@@ -0,0 +1,3973 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <net/iw_handler.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_debugfs.h"
+#include "bcm43xx_radio.h"
+#include "bcm43xx_phy.h"
+#include "bcm43xx_dma.h"
+#include "bcm43xx_pio.h"
+#include "bcm43xx_power.h"
+#include "bcm43xx_wx.h"
+#include "bcm43xx_ethtool.h"
+#include "bcm43xx_xmit.h"
+
+
+MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_BCM947XX
+extern char *nvram_get(char *name);
+#endif
+
+#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_BCM43XX_DMA)
+# define modparam_pio	0
+#elif defined(CONFIG_BCM43XX_PIO)
+# define modparam_pio	1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
+
+static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static int modparam_locale = -1;
+module_param_named(locale, modparam_locale, int, 0444);
+MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
+
+static int modparam_noleds;
+module_param_named(noleds, modparam_noleds, int, 0444);
+MODULE_PARM_DESC(noleds, "Turn off all LED activity");
+
+#ifdef CONFIG_BCM43XX_DEBUG
+static char modparam_fwpostfix[64];
+module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
+#else
+# define modparam_fwpostfix  ""
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+
+/* If you want to debug with just a single device, enable this,
+ * where the string is the pci device ID (as given by the kernel's
+ * pci_name function) of the device to be used.
+ */
+//#define DEBUG_SINGLE_DEVICE_ONLY	"0001:11:00.0"
+
+/* If you want to enable printing of each MMIO access, enable this. */
+//#define DEBUG_ENABLE_MMIO_PRINT
+
+/* If you want to enable printing of MMIO access within
+ * ucode/pcm upload, initvals write, enable this.
+ */
+//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
+
+/* If you want to enable printing of PCI Config Space access, enable this */
+//#define DEBUG_ENABLE_PCILOG
+
+
+/* Detailed list maintained at:
+ * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
+ */
+	static struct pci_device_id bcm43xx_pci_tbl[] = {
+	/* Broadcom 4303 802.11b */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+		/* Broadcom 4307 802.11b */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+		/* Broadcom 4318 802.11b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 4306 802.11b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+		/* Broadcom 4306 802.11a */
+//	{ PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 4309 802.11a/b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 43XG 802.11b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#ifdef CONFIG_BCM947XX
+	/* SB bus on BCM947xx */
+	{ PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+	{ 0 },
+};
+MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
+
+static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
+{
+	u32 status;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
+		val = swab32(val);
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
+	mmiowb();
+	bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
+}
+
+static inline
+void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
+			      u16 routing, u16 offset)
+{
+	u32 control;
+
+	/* "offset" is the WORD offset. */
+
+	control = routing;
+	control <<= 16;
+	control |= offset;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
+}
+
+u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset)
+{
+	u32 ret;
+
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
+			ret <<= 16;
+			bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
+			ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset)
+{
+	u16 ret;
+
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u32 value)
+{
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			mmiowb();
+			bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
+					(value >> 16) & 0xffff);
+			mmiowb();
+			bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
+			mmiowb();
+			bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA,
+					value & 0xffff);
+			return;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	mmiowb();
+	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
+}
+
+void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u16 value)
+{
+	if (routing == BCM43xx_SHM_SHARED) {
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			bcm43xx_shm_control_word(bcm, routing, offset >> 2);
+			mmiowb();
+			bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
+					value);
+			return;
+		}
+		offset >>= 2;
+	}
+	bcm43xx_shm_control_word(bcm, routing, offset);
+	mmiowb();
+	bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);
+}
+
+void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf)
+{
+	/* We need to be careful. As we read the TSF from multiple
+	 * registers, we should take care of register overflows.
+	 * In theory, the whole tsf read process should be atomic.
+	 * We try to be atomic here, by restaring the read process,
+	 * if any of the high registers changed (overflew).
+	 */
+	if (bcm->current_core->rev >= 3) {
+		u32 low, high, high2;
+
+		do {
+			high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
+			low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW);
+			high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
+		} while (unlikely(high != high2));
+
+		*tsf = high;
+		*tsf <<= 32;
+		*tsf |= low;
+	} else {
+		u64 tmp;
+		u16 v0, v1, v2, v3;
+		u16 test1, test2, test3;
+
+		do {
+			v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
+			v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
+			v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
+			v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0);
+
+			test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
+			test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
+			test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
+		} while (v3 != test3 || v2 != test2 || v1 != test1);
+
+		*tsf = v3;
+		*tsf <<= 48;
+		tmp = v2;
+		tmp <<= 32;
+		*tsf |= tmp;
+		tmp = v1;
+		tmp <<= 16;
+		*tsf |= tmp;
+		*tsf |= v0;
+	}
+}
+
+void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
+{
+	u32 status;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status |= BCM43xx_SBF_TIME_UPDATE;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+
+	/* Be careful with the in-progress timer.
+	 * First zero out the low register, so we have a full
+	 * register-overflow duration to complete the operation.
+	 */
+	if (bcm->current_core->rev >= 3) {
+		u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+		u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+		bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
+		mmiowb();
+		bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
+		mmiowb();
+		bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
+	} else {
+		u16 v0 = (tsf & 0x000000000000FFFFULL);
+		u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+		u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+		u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
+		mmiowb();
+		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
+	}
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status &= ~BCM43xx_SBF_TIME_UPDATE;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+}
+
+static
+void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
+			   u16 offset,
+			   const u8 *mac)
+{
+	u16 data;
+
+	offset |= 0x0020;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
+
+	data = mac[0];
+	data |= mac[1] << 8;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
+	data = mac[2];
+	data |= mac[3] << 8;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
+	data = mac[4];
+	data |= mac[5] << 8;
+	bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
+}
+
+static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
+				    u16 offset)
+{
+	const u8 zero_addr[ETH_ALEN] = { 0 };
+
+	bcm43xx_macfilter_set(bcm, offset, zero_addr);
+}
+
+static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
+{
+	const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
+	const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
+	u8 mac_bssid[ETH_ALEN * 2];
+	int i;
+
+	memcpy(mac_bssid, mac, ETH_ALEN);
+	memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+	/* Write our MAC address and BSSID to template ram */
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
+		bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
+		bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
+		bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
+}
+
+//FIXME: Well, we should probably call them from somewhere.
+#if 0
+static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
+{
+	/* slot_time is in usec. */
+	if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G)
+		return;
+	bcm43xx_write16(bcm, 0x684, 510 + slot_time);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
+}
+
+static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_set_slot_time(bcm, 9);
+}
+
+static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_set_slot_time(bcm, 20);
+}
+#endif
+
+/* FIXME: To get the MAC-filter working, we need to implement the
+ *        following functions (and rename them :)
+ */
+#if 0
+static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
+{
+	bcm43xx_mac_suspend(bcm);
+	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
+
+	bcm43xx_ram_write(bcm, 0x0026, 0x0000);
+	bcm43xx_ram_write(bcm, 0x0028, 0x0000);
+	bcm43xx_ram_write(bcm, 0x007E, 0x0000);
+	bcm43xx_ram_write(bcm, 0x0080, 0x0000);
+	bcm43xx_ram_write(bcm, 0x047E, 0x0000);
+	bcm43xx_ram_write(bcm, 0x0480, 0x0000);
+
+	if (bcm->current_core->rev < 3) {
+		bcm43xx_write16(bcm, 0x0610, 0x8000);
+		bcm43xx_write16(bcm, 0x060E, 0x0000);
+	} else
+		bcm43xx_write32(bcm, 0x0188, 0x80000000);
+
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
+
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G &&
+	    ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
+		bcm43xx_short_slot_timing_enable(bcm);
+
+	bcm43xx_mac_enable(bcm);
+}
+
+static void bcm43xx_associate(struct bcm43xx_private *bcm,
+			      const u8 *mac)
+{
+	memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
+
+	bcm43xx_mac_suspend(bcm);
+	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
+	bcm43xx_write_mac_bssid_templates(bcm);
+	bcm43xx_mac_enable(bcm);
+}
+#endif
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
+
+	return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+	return old_mask;
+}
+
+/* Make sure we don't receive more data from the device. */
+static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
+{
+	u32 old;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
+		bcm43xx_unlock_mmio(bcm, flags);
+		return -EBUSY;
+	}
+	old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	tasklet_disable(&bcm->isr_tasklet);
+	bcm43xx_unlock_mmio(bcm, flags);
+	if (oldstate)
+		*oldstate = old;
+
+	return 0;
+}
+
+static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u32 radio_id;
+	u16 manufact;
+	u16 version;
+	u8 revision;
+	s8 i;
+
+	if (bcm->chip_id == 0x4317) {
+		if (bcm->chip_rev == 0x00)
+			radio_id = 0x3205017F;
+		else if (bcm->chip_rev == 0x01)
+			radio_id = 0x4205017F;
+		else
+			radio_id = 0x5205017F;
+	} else {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
+		radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
+		radio_id <<= 16;
+		bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
+		radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
+	}
+
+	manufact = (radio_id & 0x00000FFF);
+	version = (radio_id & 0x0FFFF000) >> 12;
+	revision = (radio_id & 0xF0000000) >> 28;
+
+	dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
+		radio_id, manufact, version, revision);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
+			goto err_unsupported_radio;
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if ((version & 0xFFF0) != 0x2050)
+			goto err_unsupported_radio;
+		break;
+	case BCM43xx_PHYTYPE_G:
+		if (version != 0x2050)
+			goto err_unsupported_radio;
+		break;
+	}
+
+	radio->manufact = manufact;
+	radio->version = version;
+	radio->revision = revision;
+
+	/* Set default attenuation values. */
+	radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+	radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+	radio->txctl1 = bcm43xx_default_txctl1(bcm);
+	radio->txctl2 = 0xFFFF;
+	if (phy->type == BCM43xx_PHYTYPE_A)
+		radio->txpower_desired = bcm->sprom.maxpower_aphy;
+	else
+		radio->txpower_desired = bcm->sprom.maxpower_bgphy;
+
+	/* Initialize the in-memory nrssi Lookup Table. */
+	for (i = 0; i < 64; i++)
+		radio->nrssi_lt[i] = i;
+
+	return 0;
+
+err_unsupported_radio:
+	printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
+	return -ENODEV;
+}
+
+static const char * bcm43xx_locale_iso(u8 locale)
+{
+	/* ISO 3166-1 country codes.
+	 * Note that there aren't ISO 3166-1 codes for
+	 * all or locales. (Not all locales are countries)
+	 */
+	switch (locale) {
+	case BCM43xx_LOCALE_WORLD:
+	case BCM43xx_LOCALE_ALL:
+		return "XX";
+	case BCM43xx_LOCALE_THAILAND:
+		return "TH";
+	case BCM43xx_LOCALE_ISRAEL:
+		return "IL";
+	case BCM43xx_LOCALE_JORDAN:
+		return "JO";
+	case BCM43xx_LOCALE_CHINA:
+		return "CN";
+	case BCM43xx_LOCALE_JAPAN:
+	case BCM43xx_LOCALE_JAPAN_HIGH:
+		return "JP";
+	case BCM43xx_LOCALE_USA_CANADA_ANZ:
+	case BCM43xx_LOCALE_USA_LOW:
+		return "US";
+	case BCM43xx_LOCALE_EUROPE:
+		return "EU";
+	case BCM43xx_LOCALE_NONE:
+		return "  ";
+	}
+	assert(0);
+	return "  ";
+}
+
+static const char * bcm43xx_locale_string(u8 locale)
+{
+	switch (locale) {
+	case BCM43xx_LOCALE_WORLD:
+		return "World";
+	case BCM43xx_LOCALE_THAILAND:
+		return "Thailand";
+	case BCM43xx_LOCALE_ISRAEL:
+		return "Israel";
+	case BCM43xx_LOCALE_JORDAN:
+		return "Jordan";
+	case BCM43xx_LOCALE_CHINA:
+		return "China";
+	case BCM43xx_LOCALE_JAPAN:
+		return "Japan";
+	case BCM43xx_LOCALE_USA_CANADA_ANZ:
+		return "USA/Canada/ANZ";
+	case BCM43xx_LOCALE_EUROPE:
+		return "Europe";
+	case BCM43xx_LOCALE_USA_LOW:
+		return "USAlow";
+	case BCM43xx_LOCALE_JAPAN_HIGH:
+		return "JapanHigh";
+	case BCM43xx_LOCALE_ALL:
+		return "All";
+	case BCM43xx_LOCALE_NONE:
+		return "None";
+	}
+	assert(0);
+	return "";
+}
+
+static inline u8 bcm43xx_crc8(u8 crc, u8 data)
+{
+	static const u8 t[] = {
+		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+	};
+	return t[crc ^ data];
+}
+
+static u8 bcm43xx_sprom_crc(const u16 *sprom)
+{
+	int word;
+	u8 crc = 0xFF;
+
+	for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
+		crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
+		crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+	}
+	crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
+	crc ^= 0xFF;
+
+	return crc;
+}
+
+int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
+{
+	int i;
+	u8 crc, expected_crc;
+
+	for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
+		sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
+	/* CRC-8 check. */
+	crc = bcm43xx_sprom_crc(sprom);
+	expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
+	if (crc != expected_crc) {
+		printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
+					"(0x%02X, expected: 0x%02X)\n",
+		       crc, expected_crc);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
+{
+	int i, err;
+	u8 crc, expected_crc;
+	u32 spromctl;
+
+	/* CRC-8 validation of the input data. */
+	crc = bcm43xx_sprom_crc(sprom);
+	expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
+	if (crc != expected_crc) {
+		printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
+	if (err)
+		goto err_ctlreg;
+	spromctl |= 0x10; /* SPROM WRITE enable. */
+	bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	/* We must burn lots of CPU cycles here, but that does not
+	 * really matter as one does not write the SPROM every other minute...
+	 */
+	printk(KERN_INFO PFX "[ 0%%");
+	mdelay(500);
+	for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
+		if (i == 16)
+			printk("25%%");
+		else if (i == 32)
+			printk("50%%");
+		else if (i == 48)
+			printk("75%%");
+		else if (i % 2)
+			printk(".");
+		bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
+		mmiowb();
+		mdelay(20);
+	}
+	spromctl &= ~0x10; /* SPROM WRITE enable. */
+	bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	mdelay(500);
+	printk("100%% ]\n");
+	printk(KERN_INFO PFX "SPROM written.\n");
+	bcm43xx_controller_restart(bcm, "SPROM update");
+
+	return 0;
+err_ctlreg:
+	printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+	return -ENODEV;
+}
+
+static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
+{
+	u16 value;
+	u16 *sprom;
+#ifdef CONFIG_BCM947XX
+	char *c;
+#endif
+
+	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
+			GFP_KERNEL);
+	if (!sprom) {
+		printk(KERN_ERR PFX "sprom_extract OOM\n");
+		return -ENOMEM;
+	}
+#ifdef CONFIG_BCM947XX
+	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
+	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
+
+	if ((c = nvram_get("il0macaddr")) != NULL)
+		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
+
+	if ((c = nvram_get("et1macaddr")) != NULL)
+		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
+
+	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
+	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
+	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
+
+	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
+	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
+	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
+
+	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
+#else
+	bcm43xx_sprom_read(bcm, sprom);
+#endif
+
+	/* boardflags2 */
+	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
+	bcm->sprom.boardflags2 = value;
+
+	/* il0macaddr */
+	value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
+	*(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
+	*(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
+	*(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
+
+	/* et0macaddr */
+	value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
+	*(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
+	*(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
+	*(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
+
+	/* et1macaddr */
+	value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
+	*(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
+	*(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
+	value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
+	*(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
+
+	/* ethernet phy settings */
+	value = sprom[BCM43xx_SPROM_ETHPHY];
+	bcm->sprom.et0phyaddr = (value & 0x001F);
+	bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
+	bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
+	bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
+
+	/* boardrev, antennas, locale */
+	value = sprom[BCM43xx_SPROM_BOARDREV];
+	bcm->sprom.boardrev = (value & 0x00FF);
+	bcm->sprom.locale = (value & 0x0F00) >> 8;
+	bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
+	bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
+	if (modparam_locale != -1) {
+		if (modparam_locale >= 0 && modparam_locale <= 11) {
+			bcm->sprom.locale = modparam_locale;
+			printk(KERN_WARNING PFX "Operating with modified "
+						"LocaleCode %u (%s)\n",
+			       bcm->sprom.locale,
+			       bcm43xx_locale_string(bcm->sprom.locale));
+		} else {
+			printk(KERN_WARNING PFX "Module parameter \"locale\" "
+						"invalid value. (0 - 11)\n");
+		}
+	}
+
+	/* pa0b* */
+	value = sprom[BCM43xx_SPROM_PA0B0];
+	bcm->sprom.pa0b0 = value;
+	value = sprom[BCM43xx_SPROM_PA0B1];
+	bcm->sprom.pa0b1 = value;
+	value = sprom[BCM43xx_SPROM_PA0B2];
+	bcm->sprom.pa0b2 = value;
+
+	/* wl0gpio* */
+	value = sprom[BCM43xx_SPROM_WL0GPIO0];
+	if (value == 0x0000)
+		value = 0xFFFF;
+	bcm->sprom.wl0gpio0 = value & 0x00FF;
+	bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
+	value = sprom[BCM43xx_SPROM_WL0GPIO2];
+	if (value == 0x0000)
+		value = 0xFFFF;
+	bcm->sprom.wl0gpio2 = value & 0x00FF;
+	bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
+
+	/* maxpower */
+	value = sprom[BCM43xx_SPROM_MAXPWR];
+	bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
+	bcm->sprom.maxpower_bgphy = value & 0x00FF;
+
+	/* pa1b* */
+	value = sprom[BCM43xx_SPROM_PA1B0];
+	bcm->sprom.pa1b0 = value;
+	value = sprom[BCM43xx_SPROM_PA1B1];
+	bcm->sprom.pa1b1 = value;
+	value = sprom[BCM43xx_SPROM_PA1B2];
+	bcm->sprom.pa1b2 = value;
+
+	/* idle tssi target */
+	value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
+	bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
+	bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
+
+	/* boardflags */
+	value = sprom[BCM43xx_SPROM_BOARDFLAGS];
+	if (value == 0xFFFF)
+		value = 0x0000;
+	bcm->sprom.boardflags = value;
+	/* boardflags workarounds */
+	if (bcm->board_vendor == PCI_VENDOR_ID_DELL &&
+	    bcm->chip_id == 0x4301 &&
+	    bcm->board_revision == 0x74)
+		bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST;
+	if (bcm->board_vendor == PCI_VENDOR_ID_APPLE &&
+	    bcm->board_type == 0x4E &&
+	    bcm->board_revision > 0x40)
+		bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL;
+
+	/* antenna gain */
+	value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
+	if (value == 0x0000 || value == 0xFFFF)
+		value = 0x0202;
+	/* convert values to Q5.2 */
+	bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
+	bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
+
+	kfree(sprom);
+
+	return 0;
+}
+
+static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
+{
+	struct ieee80211_geo geo;
+	struct ieee80211_channel *chan;
+	int have_a = 0, have_bg = 0;
+	int i;
+	u8 channel;
+	struct bcm43xx_phyinfo *phy;
+	const char *iso_country;
+
+	memset(&geo, 0, sizeof(geo));
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		phy = &(bcm->core_80211_ext[i].phy);
+		switch (phy->type) {
+		case BCM43xx_PHYTYPE_B:
+		case BCM43xx_PHYTYPE_G:
+			have_bg = 1;
+			break;
+		case BCM43xx_PHYTYPE_A:
+			have_a = 1;
+			break;
+		default:
+			assert(0);
+		}
+	}
+	iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
+
+ 	if (have_a) {
+		for (i = 0, channel = 0; channel < 201; channel++) {
+			chan = &geo.a[i++];
+			chan->freq = bcm43xx_channel_to_freq_a(channel);
+			chan->channel = channel;
+		}
+		geo.a_channels = i;
+	}
+	if (have_bg) {
+		for (i = 0, channel = 1; channel < 15; channel++) {
+			chan = &geo.bg[i++];
+			chan->freq = bcm43xx_channel_to_freq_bg(channel);
+			chan->channel = channel;
+		}
+		geo.bg_channels = i;
+	}
+	memcpy(geo.name, iso_country, 2);
+	if (0 /*TODO: Outdoor use only */)
+		geo.name[2] = 'O';
+	else if (0 /*TODO: Indoor use only */)
+		geo.name[2] = 'I';
+	else
+		geo.name[2] = ' ';
+	geo.name[3] = '\0';
+
+	ieee80211_set_geo(bcm->ieee, &geo);
+}
+
+/* DummyTransmission function, as documented on 
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	unsigned int i, max_loop;
+	u16 value = 0;
+	u32 buffer[5] = {
+		0x00000000,
+		0x0000D400,
+		0x00000000,
+		0x00000001,
+		0x00000000,
+	};
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		max_loop = 0x1E;
+		buffer[0] = 0xCC010200;
+		break;
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G:
+		max_loop = 0xFA;
+		buffer[0] = 0x6E840B00; 
+		break;
+	default:
+		assert(0);
+		return;
+	}
+
+	for (i = 0; i < 5; i++)
+		bcm43xx_ram_write(bcm, i * 4, buffer[i]);
+
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+
+	bcm43xx_write16(bcm, 0x0568, 0x0000);
+	bcm43xx_write16(bcm, 0x07C0, 0x0000);
+	bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
+	bcm43xx_write16(bcm, 0x0508, 0x0000);
+	bcm43xx_write16(bcm, 0x050A, 0x0000);
+	bcm43xx_write16(bcm, 0x054C, 0x0000);
+	bcm43xx_write16(bcm, 0x056A, 0x0014);
+	bcm43xx_write16(bcm, 0x0568, 0x0826);
+	bcm43xx_write16(bcm, 0x0500, 0x0000);
+	bcm43xx_write16(bcm, 0x0502, 0x0030);
+
+	if (radio->version == 0x2050 && radio->revision <= 0x5)
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0017);
+	for (i = 0x00; i < max_loop; i++) {
+		value = bcm43xx_read16(bcm, 0x050E);
+		if (value & 0x0080)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = bcm43xx_read16(bcm, 0x050E);
+		if (value & 0x0400)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = bcm43xx_read16(bcm, 0x0690);
+		if (!(value & 0x0100))
+			break;
+		udelay(10);
+	}
+	if (radio->version == 0x2050 && radio->revision <= 0x5)
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
+}
+
+static void key_write(struct bcm43xx_private *bcm,
+		      u8 index, u8 algorithm, const u16 *key)
+{
+	unsigned int i, basic_wep = 0;
+	u32 offset;
+	u16 value;
+ 
+	/* Write associated key information */
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
+			    ((index << 4) | (algorithm & 0x0F)));
+ 
+	/* The first 4 WEP keys need extra love */
+	if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
+	    (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
+		basic_wep = 1;
+ 
+	/* Write key payload, 8 little endian words */
+	offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
+	for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
+		value = cpu_to_le16(key[i]);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+				    offset + (i * 2), value);
+ 
+		if (!basic_wep)
+			continue;
+ 
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+				    offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
+				    value);
+	}
+}
+
+static void keymac_write(struct bcm43xx_private *bcm,
+			 u8 index, const u32 *addr)
+{
+	/* for keys 0-3 there is no associated mac address */
+	if (index < 4)
+		return;
+
+	index -= 4;
+	if (bcm->current_core->rev >= 5) {
+		bcm43xx_shm_write32(bcm,
+				    BCM43xx_SHM_HWMAC,
+				    index * 2,
+				    cpu_to_be32(*addr));
+		bcm43xx_shm_write16(bcm,
+				    BCM43xx_SHM_HWMAC,
+				    (index * 2) + 1,
+				    cpu_to_be16(*((u16 *)(addr + 1))));
+	} else {
+		if (index < 8) {
+			TODO(); /* Put them in the macaddress filter */
+		} else {
+			TODO();
+			/* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
+			   Keep in mind to update the count of keymacs in 0x003E as well! */
+		}
+	}
+}
+
+static int bcm43xx_key_write(struct bcm43xx_private *bcm,
+			     u8 index, u8 algorithm,
+			     const u8 *_key, int key_len,
+			     const u8 *mac_addr)
+{
+	u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
+
+	if (index >= ARRAY_SIZE(bcm->key))
+		return -EINVAL;
+	if (key_len > ARRAY_SIZE(key))
+		return -EINVAL;
+	if (algorithm < 1 || algorithm > 5)
+		return -EINVAL;
+
+	memcpy(key, _key, key_len);
+	key_write(bcm, index, algorithm, (const u16 *)key);
+	keymac_write(bcm, index, (const u32 *)mac_addr);
+
+	bcm->key[index].algorithm = algorithm;
+
+	return 0;
+}
+
+static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
+{
+	static const u32 zero_mac[2] = { 0 };
+	unsigned int i,j, nr_keys = 54;
+	u16 offset;
+
+	if (bcm->current_core->rev < 5)
+		nr_keys = 16;
+	assert(nr_keys <= ARRAY_SIZE(bcm->key));
+
+	for (i = 0; i < nr_keys; i++) {
+		bcm->key[i].enabled = 0;
+		/* returns for i < 4 immediately */
+		keymac_write(bcm, i, zero_mac);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+				    0x100 + (i * 2), 0x0000);
+		for (j = 0; j < 8; j++) {
+			offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
+			bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+					    offset, 0x0000);
+		}
+	}
+	dprintk(KERN_INFO PFX "Keys cleared\n");
+}
+
+/* Lowlevel core-switch function. This is only to be used in
+ * bcm43xx_switch_core() and bcm43xx_probe_cores()
+ */
+static int _switch_core(struct bcm43xx_private *bcm, int core)
+{
+	int err;
+	int attempts = 0;
+	u32 current_core;
+
+	assert(core >= 0);
+	while (1) {
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
+						 (core * 0x1000) + 0x18000000);
+		if (unlikely(err))
+			goto error;
+		err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
+						&current_core);
+		if (unlikely(err))
+			goto error;
+		current_core = (current_core - 0x18000000) / 0x1000;
+		if (current_core == core)
+			break;
+
+		if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
+			goto error;
+		udelay(10);
+	}
+#ifdef CONFIG_BCM947XX
+	if (bcm->pci_dev->bus->number == 0)
+		bcm->current_core_offset = 0x1000 * core;
+	else
+		bcm->current_core_offset = 0;
+#endif
+
+	return 0;
+error:
+	printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
+	return -ENODEV;
+}
+
+int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
+{
+	int err;
+
+	if (unlikely(!new_core))
+		return 0;
+	if (!new_core->available)
+		return -ENODEV;
+	if (bcm->current_core == new_core)
+		return 0;
+	err = _switch_core(bcm, new_core->index);
+	if (unlikely(err))
+		goto out;
+
+	bcm->current_core = new_core;
+	bcm->current_80211_core_idx = -1;
+	if (new_core->id == BCM43xx_COREID_80211)
+		bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
+
+out:
+	return err;
+}
+
+static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
+{
+	u32 value;
+
+	value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
+		 | BCM43xx_SBTMSTATELOW_REJECT;
+
+	return (value == BCM43xx_SBTMSTATELOW_CLOCK);
+}
+
+/* disable current core */
+static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
+{
+	u32 sbtmstatelow;
+	u32 sbtmstatehigh;
+	int i;
+
+	/* fetch sbtmstatelow from core information registers */
+	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+
+	/* core is already in reset */
+	if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
+		goto out;
+
+	if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
+		sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
+			       BCM43xx_SBTMSTATELOW_REJECT;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+
+		for (i = 0; i < 1000; i++) {
+			sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+			if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
+				i = -1;
+				break;
+			}
+			udelay(10);
+		}
+		if (i != -1) {
+			printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
+			return -EBUSY;
+		}
+
+		for (i = 0; i < 1000; i++) {
+			sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+			if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
+				i = -1;
+				break;
+			}
+			udelay(10);
+		}
+		if (i != -1) {
+			printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
+			return -EBUSY;
+		}
+
+		sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
+			       BCM43xx_SBTMSTATELOW_REJECT |
+			       BCM43xx_SBTMSTATELOW_RESET |
+			       BCM43xx_SBTMSTATELOW_CLOCK |
+			       core_flags;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+		udelay(10);
+	}
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
+		       BCM43xx_SBTMSTATELOW_REJECT |
+		       core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+
+out:
+	bcm->current_core->enabled = 0;
+
+	return 0;
+}
+
+/* enable (reset) current core */
+static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
+{
+	u32 sbtmstatelow;
+	u32 sbtmstatehigh;
+	u32 sbimstate;
+	int err;
+
+	err = bcm43xx_core_disable(bcm, core_flags);
+	if (err)
+		goto out;
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
+		       BCM43xx_SBTMSTATELOW_RESET |
+		       BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
+		       core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+	if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
+		sbtmstatehigh = 0x00000000;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
+	}
+
+	sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
+	if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
+		sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
+	}
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
+		       BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
+		       core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	bcm->current_core->enabled = 1;
+	assert(err == 0);
+out:
+	return err;
+}
+
+/* http://bcm-specs.sipsolutions.net/80211CoreReset */
+void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
+{
+	u32 flags = 0x00040000;
+
+	if ((bcm43xx_core_enabled(bcm)) &&
+	    !bcm43xx_using_pio(bcm)) {
+//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
+#ifndef CONFIG_BCM947XX
+		/* reset all used DMA controllers. */
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
+		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
+		bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
+		if (bcm->current_core->rev < 5)
+			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
+#endif
+	}
+	if (bcm->shutting_down) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
+	} else {
+		if (connect_phy)
+			flags |= 0x20000000;
+		bcm43xx_phy_connect(bcm, connect_phy);
+		bcm43xx_core_enable(bcm, flags);
+		bcm43xx_write16(bcm, 0x03E6, 0x0000);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+				bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				| BCM43xx_SBF_400);
+	}
+}
+
+static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_radio_turn_off(bcm);
+	bcm43xx_write16(bcm, 0x03E6, 0x00F4);
+	bcm43xx_core_disable(bcm, 0);
+}
+
+/* Mark the current 80211 core inactive.
+ * "active_80211_core" is the other 80211 core, which is used.
+ */
+static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
+					       struct bcm43xx_coreinfo *active_80211_core)
+{
+	u32 sbtmstatelow;
+	struct bcm43xx_coreinfo *old_core;
+	int err = 0;
+
+	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	bcm43xx_radio_turn_off(bcm);
+	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	sbtmstatelow &= ~0x200a0000;
+	sbtmstatelow |= 0xa0000;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	sbtmstatelow &= ~0xa0000;
+	sbtmstatelow |= 0x80000;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	udelay(1);
+
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
+		old_core = bcm->current_core;
+		err = bcm43xx_switch_core(bcm, active_80211_core);
+		if (err)
+			goto out;
+		sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		sbtmstatelow &= ~0x20000000;
+		sbtmstatelow |= 0x20000000;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+		err = bcm43xx_switch_core(bcm, old_core);
+	}
+
+out:
+	return err;
+}
+
+static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
+{
+	u32 v0, v1;
+	u16 tmp;
+	struct bcm43xx_xmitstatus stat;
+
+	while (1) {
+		v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
+		if (!v0)
+			break;
+		v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
+
+		stat.cookie = (v0 >> 16) & 0x0000FFFF;
+		tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
+		stat.flags = tmp & 0xFF;
+		stat.cnt1 = (tmp & 0x0F00) >> 8;
+		stat.cnt2 = (tmp & 0xF000) >> 12;
+		stat.seq = (u16)(v1 & 0xFFFF);
+		stat.unknown = (u16)((v1 >> 16) & 0xFF);
+
+		bcm43xx_debugfs_log_txstat(bcm, &stat);
+
+		if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
+			continue;
+		if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
+			//TODO: packet was not acked (was lost)
+		}
+		//TODO: There are more (unknown) flags to test. see bcm43xx_main.h
+
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_handle_xmitstatus(bcm, &stat);
+		else
+			bcm43xx_dma_handle_xmitstatus(bcm, &stat);
+	}
+}
+
+static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
+{
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
+			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
+	assert(bcm->noisecalc.core_at_start == bcm->current_core);
+	assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);
+}
+
+static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
+{
+	/* Top half of Link Quality calculation. */
+
+	if (bcm->noisecalc.calculation_running)
+		return;
+	bcm->noisecalc.core_at_start = bcm->current_core;
+	bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;
+	bcm->noisecalc.calculation_running = 1;
+	bcm->noisecalc.nr_samples = 0;
+
+	bcm43xx_generate_noise_sample(bcm);
+}
+
+static void handle_irq_noise(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tmp;
+	u8 noise[4];
+	u8 i, j;
+	s32 average;
+
+	/* Bottom half of Link Quality calculation. */
+
+	assert(bcm->noisecalc.calculation_running);
+	if (bcm->noisecalc.core_at_start != bcm->current_core ||
+	    bcm->noisecalc.channel_at_start != radio->channel)
+		goto drop_calculation;
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
+	noise[0] = (tmp & 0x00FF);
+	noise[1] = (tmp & 0xFF00) >> 8;
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
+	noise[2] = (tmp & 0x00FF);
+	noise[3] = (tmp & 0xFF00) >> 8;
+	if (noise[0] == 0x7F || noise[1] == 0x7F ||
+	    noise[2] == 0x7F || noise[3] == 0x7F)
+		goto generate_new;
+
+	/* Get the noise samples. */
+	assert(bcm->noisecalc.nr_samples <= 8);
+	i = bcm->noisecalc.nr_samples;
+	noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
+	bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
+	bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
+	bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
+	bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
+	bcm->noisecalc.nr_samples++;
+	if (bcm->noisecalc.nr_samples == 8) {
+		/* Calculate the Link Quality by the noise samples. */
+		average = 0;
+		for (i = 0; i < 8; i++) {
+			for (j = 0; j < 4; j++)
+				average += bcm->noisecalc.samples[i][j];
+		}
+		average /= (8 * 4);
+		average *= 125;
+		average += 64;
+		average /= 128;
+
+		tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
+		tmp = (tmp / 128) & 0x1F;
+		if (tmp >= 8)
+			average += 2;
+		else
+			average -= 25;
+		if (tmp == 8)
+			average -= 72;
+		else
+			average -= 48;
+
+/* FIXME: This is wrong, but people want fancy stats. well... */
+bcm->stats.noise = average;
+		if (average > -65)
+			bcm->stats.link_quality = 0;
+		else if (average > -75)
+			bcm->stats.link_quality = 1;
+		else if (average > -85)
+			bcm->stats.link_quality = 2;
+		else
+			bcm->stats.link_quality = 3;
+//		dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
+drop_calculation:
+		bcm->noisecalc.calculation_running = 0;
+		return;
+	}
+generate_new:
+	bcm43xx_generate_noise_sample(bcm);
+}
+
+static void handle_irq_ps(struct bcm43xx_private *bcm)
+{
+	if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
+		///TODO: PS TBTT
+	} else {
+		if (1/*FIXME: the last PSpoll frame was sent successfully */)
+			bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	}
+	if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
+		bcm->reg124_set_0x4 = 1;
+	//FIXME else set to false?
+}
+
+static void handle_irq_reg124(struct bcm43xx_private *bcm)
+{
+	if (!bcm->reg124_set_0x4)
+		return;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
+			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
+			| 0x4);
+	//FIXME: reset reg124_set_0x4 to false?
+}
+
+static void handle_irq_pmq(struct bcm43xx_private *bcm)
+{
+	u32 tmp;
+
+	//TODO: AP mode.
+
+	while (1) {
+		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
+		if (!(tmp & 0x00000008))
+			break;
+	}
+	/* 16bit write is odd, but correct. */
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
+}
+
+static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
+					     u16 ram_offset, u16 shm_size_offset)
+{
+	u32 value;
+	u16 size = 0;
+
+	/* Timestamp. */
+	//FIXME: assumption: The chip sets the timestamp
+	value = 0;
+	bcm43xx_ram_write(bcm, ram_offset++, value);
+	bcm43xx_ram_write(bcm, ram_offset++, value);
+	size += 8;
+
+	/* Beacon Interval / Capability Information */
+	value = 0x0000;//FIXME: Which interval?
+	value |= (1 << 0) << 16; /* ESS */
+	value |= (1 << 2) << 16; /* CF Pollable */	//FIXME?
+	value |= (1 << 3) << 16; /* CF Poll Request */	//FIXME?
+	if (!bcm->ieee->open_wep)
+		value |= (1 << 4) << 16; /* Privacy */
+	bcm43xx_ram_write(bcm, ram_offset++, value);
+	size += 4;
+
+	/* SSID */
+	//TODO
+
+	/* FH Parameter Set */
+	//TODO
+
+	/* DS Parameter Set */
+	//TODO
+
+	/* CF Parameter Set */
+	//TODO
+
+	/* TIM */
+	//TODO
+
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
+}
+
+static void handle_irq_beacon(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
+
+	if ((status & 0x1) && (status & 0x2)) {
+		/* ACK beacon IRQ. */
+		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
+				BCM43xx_IRQ_BEACON);
+		bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
+		return;
+	}
+	if (!(status & 0x1)) {
+		bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
+		status |= 0x1;
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
+	}
+	if (!(status & 0x2)) {
+		bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
+		status |= 0x2;
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
+	}
+}
+
+/* Interrupt handler bottom-half */
+static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
+{
+	u32 reason;
+	u32 dma_reason[4];
+	int activity = 0;
+	unsigned long flags;
+
+#ifdef CONFIG_BCM43XX_DEBUG
+	u32 _handled = 0x00000000;
+# define bcmirq_handled(irq)	do { _handled |= (irq); } while (0)
+#else
+# define bcmirq_handled(irq)	do { /* nothing */ } while (0)
+#endif /* CONFIG_BCM43XX_DEBUG*/
+
+	bcm43xx_lock_mmio(bcm, flags);
+	reason = bcm->irq_reason;
+	dma_reason[0] = bcm->dma_reason[0];
+	dma_reason[1] = bcm->dma_reason[1];
+	dma_reason[2] = bcm->dma_reason[2];
+	dma_reason[3] = bcm->dma_reason[3];
+
+	if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
+		/* TX error. We get this when Template Ram is written in wrong endianess
+		 * in dummy_tx(). We also get this if something is wrong with the TX header
+		 * on DMA or PIO queues.
+		 * Maybe we get this in other error conditions, too.
+		 */
+		printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
+		bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
+	}
+	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
+		     (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
+		     (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
+		     (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
+		printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
+				     "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+		        dma_reason[0], dma_reason[1],
+			dma_reason[2], dma_reason[3]);
+		bcm43xx_controller_restart(bcm, "DMA error");
+		bcm43xx_unlock_mmio(bcm, flags);
+		return;
+	}
+	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
+		     (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
+		     (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
+		     (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
+		printkl(KERN_ERR PFX "DMA error: "
+				     "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+		        dma_reason[0], dma_reason[1],
+			dma_reason[2], dma_reason[3]);
+	}
+
+	if (reason & BCM43xx_IRQ_PS) {
+		handle_irq_ps(bcm);
+		bcmirq_handled(BCM43xx_IRQ_PS);
+	}
+
+	if (reason & BCM43xx_IRQ_REG124) {
+		handle_irq_reg124(bcm);
+		bcmirq_handled(BCM43xx_IRQ_REG124);
+	}
+
+	if (reason & BCM43xx_IRQ_BEACON) {
+		if (bcm->ieee->iw_mode == IW_MODE_MASTER)
+			handle_irq_beacon(bcm);
+		bcmirq_handled(BCM43xx_IRQ_BEACON);
+	}
+
+	if (reason & BCM43xx_IRQ_PMQ) {
+		handle_irq_pmq(bcm);
+		bcmirq_handled(BCM43xx_IRQ_PMQ);
+	}
+
+	if (reason & BCM43xx_IRQ_SCAN) {
+		/*TODO*/
+		//bcmirq_handled(BCM43xx_IRQ_SCAN);
+	}
+
+	if (reason & BCM43xx_IRQ_NOISE) {
+		handle_irq_noise(bcm);
+		bcmirq_handled(BCM43xx_IRQ_NOISE);
+	}
+
+	/* Check the DMA reason registers for received data. */
+	assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
+	assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
+	if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
+		else
+			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
+		/* We intentionally don't set "activity" to 1, here. */
+	}
+	if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
+		else
+			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
+		activity = 1;
+	}
+	bcmirq_handled(BCM43xx_IRQ_RX);
+
+	if (reason & BCM43xx_IRQ_XMIT_STATUS) {
+		handle_irq_transmit_status(bcm);
+		activity = 1;
+		//TODO: In AP mode, this also causes sending of powersave responses.
+		bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
+	}
+
+	/* IRQ_PIO_WORKAROUND is handled in the top-half. */
+	bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
+#ifdef CONFIG_BCM43XX_DEBUG
+	if (unlikely(reason & ~_handled)) {
+		printkl(KERN_WARNING PFX
+			"Unhandled IRQ! Reason: 0x%08x,  Unhandled: 0x%08x,  "
+			"DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+			reason, (reason & ~_handled),
+			dma_reason[0], dma_reason[1],
+			dma_reason[2], dma_reason[3]);
+	}
+#endif
+#undef bcmirq_handled
+
+	if (!modparam_noleds)
+		bcm43xx_leds_update(bcm, activity);
+	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void pio_irq_workaround(struct bcm43xx_private *bcm,
+			       u16 base, int queueidx)
+{
+	u16 rxctl;
+
+	rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);
+	if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)
+		bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;
+	else
+		bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;
+}
+
+static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
+{
+	if (bcm43xx_using_pio(bcm) &&
+	    (bcm->current_core->rev < 3) &&
+	    (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
+		/* Apply a PIO specific workaround to the dma_reasons */
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);
+		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);
+	}
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
+			bcm->dma_reason[0]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
+			bcm->dma_reason[1]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
+			bcm->dma_reason[2]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+			bcm->dma_reason[3]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	irqreturn_t ret = IRQ_HANDLED;
+	struct bcm43xx_private *bcm = dev_id;
+	u32 reason;
+
+	if (!bcm)
+		return IRQ_NONE;
+
+	spin_lock(&bcm->_lock);
+
+	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+	if (reason == 0xffffffff) {
+		/* irq not for us (shared irq) */
+		ret = IRQ_NONE;
+		goto out;
+	}
+	reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
+	if (!reason)
+		goto out;
+
+	bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
+			     & 0x0001dc00;
+	bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
+			     & 0x0000dc00;
+	bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
+			     & 0x0000dc00;
+	bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
+			     & 0x0001dc00;
+
+	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(bcm->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);
+	}
+
+out:
+	mmiowb();
+	spin_unlock(&bcm->_lock);
+
+	return ret;
+}
+
+static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
+{
+	if (bcm->firmware_norelease && !force)
+		return; /* Suspending or controller reset. */
+	release_firmware(bcm->ucode);
+	bcm->ucode = NULL;
+	release_firmware(bcm->pcm);
+	bcm->pcm = NULL;
+	release_firmware(bcm->initvals0);
+	bcm->initvals0 = NULL;
+	release_firmware(bcm->initvals1);
+	bcm->initvals1 = NULL;
+}
+
+static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u8 rev = bcm->current_core->rev;
+	int err = 0;
+	int nr;
+	char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
+
+	if (!bcm->ucode) {
+		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
+			 (rev >= 5 ? 5 : rev),
+			 modparam_fwpostfix);
+		err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
+		if (err) {
+			printk(KERN_ERR PFX 
+			       "Error: Microcode \"%s\" not available or load failed.\n",
+			        buf);
+			goto error;
+		}
+	}
+
+	if (!bcm->pcm) {
+		snprintf(buf, ARRAY_SIZE(buf),
+			 "bcm43xx_pcm%d%s.fw",
+			 (rev < 5 ? 4 : 5),
+			 modparam_fwpostfix);
+		err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
+		if (err) {
+			printk(KERN_ERR PFX
+			       "Error: PCM \"%s\" not available or load failed.\n",
+			       buf);
+			goto error;
+		}
+	}
+
+	if (!bcm->initvals0) {
+		if (rev == 2 || rev == 4) {
+			switch (phy->type) {
+			case BCM43xx_PHYTYPE_A:
+				nr = 3;
+				break;
+			case BCM43xx_PHYTYPE_B:
+			case BCM43xx_PHYTYPE_G:
+				nr = 1;
+				break;
+			default:
+				goto err_noinitval;
+			}
+		
+		} else if (rev >= 5) {
+			switch (phy->type) {
+			case BCM43xx_PHYTYPE_A:
+				nr = 7;
+				break;
+			case BCM43xx_PHYTYPE_B:
+			case BCM43xx_PHYTYPE_G:
+				nr = 5;
+				break;
+			default:
+				goto err_noinitval;
+			}
+		} else
+			goto err_noinitval;
+		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
+			 nr, modparam_fwpostfix);
+
+		err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
+		if (err) {
+			printk(KERN_ERR PFX 
+			       "Error: InitVals \"%s\" not available or load failed.\n",
+			        buf);
+			goto error;
+		}
+		if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
+			printk(KERN_ERR PFX "InitVals fileformat error.\n");
+			goto error;
+		}
+	}
+
+	if (!bcm->initvals1) {
+		if (rev >= 5) {
+			u32 sbtmstatehigh;
+
+			switch (phy->type) {
+			case BCM43xx_PHYTYPE_A:
+				sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+				if (sbtmstatehigh & 0x00010000)
+					nr = 9;
+				else
+					nr = 10;
+				break;
+			case BCM43xx_PHYTYPE_B:
+			case BCM43xx_PHYTYPE_G:
+					nr = 6;
+				break;
+			default:
+				goto err_noinitval;
+			}
+			snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
+				 nr, modparam_fwpostfix);
+
+			err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
+			if (err) {
+				printk(KERN_ERR PFX 
+				       "Error: InitVals \"%s\" not available or load failed.\n",
+			        	buf);
+				goto error;
+			}
+			if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
+				printk(KERN_ERR PFX "InitVals fileformat error.\n");
+				goto error;
+			}
+		}
+	}
+
+out:
+	return err;
+error:
+	bcm43xx_release_firmware(bcm, 1);
+	goto out;
+err_noinitval:
+	printk(KERN_ERR PFX "Error: No InitVals available!\n");
+	err = -ENOENT;
+	goto error;
+}
+
+static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
+{
+	const u32 *data;
+	unsigned int i, len;
+
+	/* Upload Microcode. */
+	data = (u32 *)(bcm->ucode->data);
+	len = bcm->ucode->size / sizeof(u32);
+	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
+	for (i = 0; i < len; i++) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
+				be32_to_cpu(data[i]));
+		udelay(10);
+	}
+
+	/* Upload PCM data. */
+	data = (u32 *)(bcm->pcm->data);
+	len = bcm->pcm->size / sizeof(u32);
+	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
+	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
+	for (i = 0; i < len; i++) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
+				be32_to_cpu(data[i]));
+		udelay(10);
+	}
+}
+
+static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
+				  const struct bcm43xx_initval *data,
+				  const unsigned int len)
+{
+	u16 offset, size;
+	u32 value;
+	unsigned int i;
+
+	for (i = 0; i < len; i++) {
+		offset = be16_to_cpu(data[i].offset);
+		size = be16_to_cpu(data[i].size);
+		value = be32_to_cpu(data[i].value);
+
+		if (unlikely(offset >= 0x1000))
+			goto err_format;
+		if (size == 2) {
+			if (unlikely(value & 0xFFFF0000))
+				goto err_format;
+			bcm43xx_write16(bcm, offset, (u16)value);
+		} else if (size == 4) {
+			bcm43xx_write32(bcm, offset, value);
+		} else
+			goto err_format;
+	}
+
+	return 0;
+
+err_format:
+	printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
+			    "Please fix your bcm43xx firmware files.\n");
+	return -EPROTO;
+}
+
+static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
+				     bcm->initvals0->size / sizeof(struct bcm43xx_initval));
+	if (err)
+		goto out;
+	if (bcm->initvals1) {
+		err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
+					     bcm->initvals1->size / sizeof(struct bcm43xx_initval));
+		if (err)
+			goto out;
+	}
+out:
+	return err;
+}
+
+static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
+{
+	int res;
+	unsigned int i;
+	u32 data;
+
+	bcm->irq = bcm->pci_dev->irq;
+#ifdef CONFIG_BCM947XX
+	if (bcm->pci_dev->bus->number == 0) {
+		struct pci_dev *d = NULL;
+		/* FIXME: we will probably need more device IDs here... */
+		d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
+		if (d != NULL) {
+			bcm->irq = d->irq;
+		}
+	}
+#endif
+	res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
+			  SA_SHIRQ, KBUILD_MODNAME, bcm);
+	if (res) {
+		printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
+		return -ENODEV;
+	}
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
+	i = 0;
+	while (1) {
+		data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+		if (data == BCM43xx_IRQ_READY)
+			break;
+		i++;
+		if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
+			printk(KERN_ERR PFX "Card IRQ register not responding. "
+					    "Giving up.\n");
+			free_irq(bcm->irq, bcm);
+			return -ENODEV;
+		}
+		udelay(10);
+	}
+	// dummy read
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+
+	return 0;
+}
+
+/* Switch to the core used to write the GPIO register.
+ * This is either the ChipCommon, or the PCI core.
+ */
+static int switch_to_gpio_core(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	/* Where to find the GPIO register depends on the chipset.
+	 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
+	 * control register. Otherwise the register at offset 0x6c in the
+	 * PCI core is the GPIO control register.
+	 */
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV) {
+		err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+		if (unlikely(err == -ENODEV)) {
+			printk(KERN_ERR PFX "gpio error: "
+			       "Neither ChipCommon nor PCI core available!\n");
+		}
+	}
+
+	return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_coreinfo *old_core;
+	int err;
+	u32 mask, set;
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+			& 0xFFFF3FFF);
+
+	bcm43xx_leds_switch_all(bcm, 0);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+			bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
+
+	mask = 0x0000001F;
+	set = 0x0000000F;
+	if (bcm->chip_id == 0x4301) {
+		mask |= 0x0060;
+		set |= 0x0060;
+	}
+	if (0 /* FIXME: conditional unknown */) {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+				bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
+				| 0x0100);
+		mask |= 0x0180;
+		set |= 0x0180;
+	}
+	if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+				bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
+				| 0x0200);
+		mask |= 0x0200;
+		set |= 0x0200;
+	}
+	if (bcm->current_core->rev >= 2)
+		mask  |= 0x0010; /* FIXME: This is redundant. */
+
+	old_core = bcm->current_core;
+	err = switch_to_gpio_core(bcm);
+	if (err)
+		goto out;
+	bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
+	                (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);
+	err = bcm43xx_switch_core(bcm, old_core);
+out:
+	return err;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_coreinfo *old_core;
+	int err;
+
+	old_core = bcm->current_core;
+	err = switch_to_gpio_core(bcm);
+	if (err)
+		return err;
+	bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
+{
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+			| BCM43xx_SBF_MAC_ENABLED);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+	bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
+{
+	int i;
+	u32 tmp;
+
+	bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+			& ~BCM43xx_SBF_MAC_ENABLED);
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+	for (i = 100000; i; i--) {
+		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+		if (tmp & BCM43xx_IRQ_READY)
+			return;
+		udelay(10);
+	}
+	printkl(KERN_ERR PFX "MAC suspend failed\n");
+}
+
+void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
+			int iw_mode)
+{
+	unsigned long flags;
+	struct net_device *net_dev = bcm->net_dev;
+	u32 status;
+	u16 value;
+
+	spin_lock_irqsave(&bcm->ieee->lock, flags);
+	bcm->ieee->iw_mode = iw_mode;
+	spin_unlock_irqrestore(&bcm->ieee->lock, flags);
+	if (iw_mode == IW_MODE_MONITOR)
+		net_dev->type = ARPHRD_IEEE80211;
+	else
+		net_dev->type = ARPHRD_ETHER;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	/* Reset status to infrastructured mode */
+	status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
+	status &= ~BCM43xx_SBF_MODE_PROMISC;
+	status |= BCM43xx_SBF_MODE_NOTADHOC;
+
+/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */
+status |= BCM43xx_SBF_MODE_PROMISC;
+
+	switch (iw_mode) {
+	case IW_MODE_MONITOR:
+		status |= BCM43xx_SBF_MODE_MONITOR;
+		status |= BCM43xx_SBF_MODE_PROMISC;
+		break;
+	case IW_MODE_ADHOC:
+		status &= ~BCM43xx_SBF_MODE_NOTADHOC;
+		break;
+	case IW_MODE_MASTER:
+		status |= BCM43xx_SBF_MODE_AP;
+		break;
+	case IW_MODE_SECOND:
+	case IW_MODE_REPEAT:
+		TODO(); /* TODO */
+		break;
+	case IW_MODE_INFRA:
+		/* nothing to be done here... */
+		break;
+	default:
+		dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);
+	}
+	if (net_dev->flags & IFF_PROMISC)
+		status |= BCM43xx_SBF_MODE_PROMISC;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+
+	value = 0x0002;
+	if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
+		if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
+			value = 0x0064;
+		else
+			value = 0x0032;
+	}
+	bcm43xx_write16(bcm, 0x0612, value);
+}
+
+/* This is the opposite of bcm43xx_chip_init() */
+static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
+{
+	bcm43xx_radio_turn_off(bcm);
+	if (!modparam_noleds)
+		bcm43xx_leds_exit(bcm);
+	bcm43xx_gpio_cleanup(bcm);
+	free_irq(bcm->irq, bcm);
+	bcm43xx_release_firmware(bcm, 0);
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	int err;
+	int tmp;
+	u32 value32;
+	u16 value16;
+
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+			BCM43xx_SBF_CORE_READY
+			| BCM43xx_SBF_400);
+
+	err = bcm43xx_request_firmware(bcm);
+	if (err)
+		goto out;
+	bcm43xx_upload_microcode(bcm);
+
+	err = bcm43xx_initialize_irq(bcm);
+	if (err)
+		goto err_release_fw;
+
+	err = bcm43xx_gpio_init(bcm);
+	if (err)
+		goto err_free_irq;
+
+	err = bcm43xx_upload_initvals(bcm);
+	if (err)
+		goto err_gpio_cleanup;
+	bcm43xx_radio_turn_on(bcm);
+
+	bcm43xx_write16(bcm, 0x03E6, 0x0000);
+	err = bcm43xx_phy_init(bcm);
+	if (err)
+		goto err_radio_off;
+
+	/* Select initial Interference Mitigation. */
+	tmp = radio->interfmode;
+	radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
+	bcm43xx_radio_set_interference_mitigation(bcm, tmp);
+
+	bcm43xx_phy_set_antenna_diversity(bcm);
+	bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		value16 = bcm43xx_read16(bcm, 0x005E);
+		value16 |= 0x0004;
+		bcm43xx_write16(bcm, 0x005E, value16);
+	}
+	bcm43xx_write32(bcm, 0x0100, 0x01000000);
+	if (bcm->current_core->rev < 5)
+		bcm43xx_write32(bcm, 0x010C, 0x01000000);
+
+	value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
+	value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value32 |= BCM43xx_SBF_MODE_NOTADHOC;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
+
+	value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value32 |= 0x100000;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
+
+	if (bcm43xx_using_pio(bcm)) {
+		bcm43xx_write32(bcm, 0x0210, 0x00000100);
+		bcm43xx_write32(bcm, 0x0230, 0x00000100);
+		bcm43xx_write32(bcm, 0x0250, 0x00000100);
+		bcm43xx_write32(bcm, 0x0270, 0x00000100);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
+	}
+
+	/* Probe Response Timeout value */
+	/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
+
+	/* Initially set the wireless operation mode. */
+	bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode);
+
+	if (bcm->current_core->rev < 3) {
+		bcm43xx_write16(bcm, 0x060E, 0x0000);
+		bcm43xx_write16(bcm, 0x0610, 0x8000);
+		bcm43xx_write16(bcm, 0x0604, 0x0000);
+		bcm43xx_write16(bcm, 0x0606, 0x0200);
+	} else {
+		bcm43xx_write32(bcm, 0x0188, 0x80000000);
+		bcm43xx_write32(bcm, 0x018C, 0x02000000);
+	}
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
+
+	value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	value32 |= 0x00100000;
+	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
+
+	bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
+
+	assert(err == 0);
+	dprintk(KERN_INFO PFX "Chip initialized\n");
+out:
+	return err;
+
+err_radio_off:
+	bcm43xx_radio_turn_off(bcm);
+err_gpio_cleanup:
+	bcm43xx_gpio_cleanup(bcm);
+err_free_irq:
+	free_irq(bcm->irq, bcm);
+err_release_fw:
+	bcm43xx_release_firmware(bcm, 1);
+	goto out;
+}
+	
+/* Validate chip access
+ * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
+static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
+{
+	u32 value;
+	u32 shm_backup;
+
+	shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
+	if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
+		goto error;
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
+	if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
+		goto error;
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
+
+	value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	if ((value | 0x80000000) != 0x80000400)
+		goto error;
+
+	value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+	if (value != 0x00000000)
+		goto error;
+
+	return 0;
+error:
+	printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
+	return -ENODEV;
+}
+
+static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
+{
+	/* Initialize a "phyinfo" structure. The structure is already
+	 * zeroed out.
+	 */
+	phy->antenna_diversity = 0xFFFF;
+	phy->savedpctlreg = 0xFFFF;
+	phy->minlowsig[0] = 0xFFFF;
+	phy->minlowsig[1] = 0xFFFF;
+	spin_lock_init(&phy->lock);
+}
+
+static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
+{
+	/* Initialize a "radioinfo" structure. The structure is already
+	 * zeroed out.
+	 */
+	radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
+	radio->channel = 0xFF;
+	radio->initial_channel = 0xFF;
+	radio->lofcal = 0xFFFF;
+	radio->initval = 0xFFFF;
+	radio->nrssi[0] = -1000;
+	radio->nrssi[1] = -1000;
+}
+
+static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
+{
+	int err, i;
+	int current_core;
+	u32 core_vendor, core_id, core_rev;
+	u32 sb_id_hi, chip_id_32 = 0;
+	u16 pci_device, chip_id_16;
+	u8 core_count;
+
+	memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
+	memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
+	memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
+				    * BCM43xx_MAX_80211_CORES);
+	memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
+					* BCM43xx_MAX_80211_CORES);
+	bcm->current_80211_core_idx = -1;
+	bcm->nr_80211_available = 0;
+	bcm->current_core = NULL;
+	bcm->active_80211_core = NULL;
+
+	/* map core 0 */
+	err = _switch_core(bcm, 0);
+	if (err)
+		goto out;
+
+	/* fetch sb_id_hi from core information registers */
+	sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
+
+	core_id = (sb_id_hi & 0xFFF0) >> 4;
+	core_rev = (sb_id_hi & 0xF);
+	core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
+
+	/* if present, chipcommon is always core 0; read the chipid from it */
+	if (core_id == BCM43xx_COREID_CHIPCOMMON) {
+		chip_id_32 = bcm43xx_read32(bcm, 0);
+		chip_id_16 = chip_id_32 & 0xFFFF;
+		bcm->core_chipcommon.available = 1;
+		bcm->core_chipcommon.id = core_id;
+		bcm->core_chipcommon.rev = core_rev;
+		bcm->core_chipcommon.index = 0;
+		/* While we are at it, also read the capabilities. */
+		bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
+	} else {
+		/* without a chipCommon, use a hard coded table. */
+		pci_device = bcm->pci_dev->device;
+		if (pci_device == 0x4301)
+			chip_id_16 = 0x4301;
+		else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
+			chip_id_16 = 0x4307;
+		else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
+			chip_id_16 = 0x4402;
+		else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
+			chip_id_16 = 0x4610;
+		else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
+			chip_id_16 = 0x4710;
+#ifdef CONFIG_BCM947XX
+		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
+			chip_id_16 = 0x4309;
+#endif
+		else {
+			printk(KERN_ERR PFX "Could not determine Chip ID\n");
+			return -ENODEV;
+		}
+	}
+
+	/* ChipCommon with Core Rev >=4 encodes number of cores,
+	 * otherwise consult hardcoded table */
+	if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
+		core_count = (chip_id_32 & 0x0F000000) >> 24;
+	} else {
+		switch (chip_id_16) {
+			case 0x4610:
+			case 0x4704:
+			case 0x4710:
+				core_count = 9;
+				break;
+			case 0x4310:
+				core_count = 8;
+				break;
+			case 0x5365:
+				core_count = 7;
+				break;
+			case 0x4306:
+				core_count = 6;
+				break;
+			case 0x4301:
+			case 0x4307:
+				core_count = 5;
+				break;
+			case 0x4402:
+				core_count = 3;
+				break;
+			default:
+				/* SOL if we get here */
+				assert(0);
+				core_count = 1;
+		}
+	}
+
+	bcm->chip_id = chip_id_16;
+	bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16;
+	bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20;
+
+	dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
+		bcm->chip_id, bcm->chip_rev);
+	dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
+	if (bcm->core_chipcommon.available) {
+		dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
+			core_id, core_rev, core_vendor,
+			bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
+	}
+
+	if (bcm->core_chipcommon.available)
+		current_core = 1;
+	else
+		current_core = 0;
+	for ( ; current_core < core_count; current_core++) {
+		struct bcm43xx_coreinfo *core;
+		struct bcm43xx_coreinfo_80211 *ext_80211;
+
+		err = _switch_core(bcm, current_core);
+		if (err)
+			goto out;
+		/* Gather information */
+		/* fetch sb_id_hi from core information registers */
+		sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
+
+		/* extract core_id, core_rev, core_vendor */
+		core_id = (sb_id_hi & 0xFFF0) >> 4;
+		core_rev = (sb_id_hi & 0xF);
+		core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
+
+		dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
+			current_core, core_id, core_rev, core_vendor,
+			bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
+
+		core = NULL;
+		switch (core_id) {
+		case BCM43xx_COREID_PCI:
+			core = &bcm->core_pci;
+			if (core->available) {
+				printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
+				continue;
+			}
+			break;
+		case BCM43xx_COREID_80211:
+			for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+				core = &(bcm->core_80211[i]);
+				ext_80211 = &(bcm->core_80211_ext[i]);
+				if (!core->available)
+					break;
+				core = NULL;
+			}
+			if (!core) {
+				printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
+				       BCM43xx_MAX_80211_CORES);
+				continue;
+			}
+			if (i != 0) {
+				/* More than one 80211 core is only supported
+				 * by special chips.
+				 * There are chips with two 80211 cores, but with
+				 * dangling pins on the second core. Be careful
+				 * and ignore these cores here.
+				 */
+				if (bcm->pci_dev->device != 0x4324) {
+					dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
+					continue;
+				}
+			}
+			switch (core_rev) {
+			case 2:
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+			case 9:
+				break;
+			default:
+				printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
+				       core_rev);
+				err = -ENODEV;
+				goto out;
+			}
+			bcm->nr_80211_available++;
+			bcm43xx_init_struct_phyinfo(&ext_80211->phy);
+			bcm43xx_init_struct_radioinfo(&ext_80211->radio);
+			break;
+		case BCM43xx_COREID_CHIPCOMMON:
+			printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
+			break;
+		}
+		if (core) {
+			core->available = 1;
+			core->id = core_id;
+			core->rev = core_rev;
+			core->index = current_core;
+		}
+	}
+
+	if (!bcm->core_80211[0].available) {
+		printk(KERN_ERR PFX "Error: No 80211 core found!\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
+
+	assert(err == 0);
+out:
+	return err;
+}
+
+static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
+{
+	const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
+	u8 *bssid = bcm->ieee->bssid;
+
+	switch (bcm->ieee->iw_mode) {
+	case IW_MODE_ADHOC:
+		random_ether_addr(bssid);
+		break;
+	case IW_MODE_MASTER:
+	case IW_MODE_INFRA:
+	case IW_MODE_REPEAT:
+	case IW_MODE_SECOND:
+	case IW_MODE_MONITOR:
+		memcpy(bssid, mac, ETH_ALEN);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
+				      u16 rate,
+				      int is_ofdm)
+{
+	u16 offset;
+
+	if (is_ofdm) {
+		offset = 0x480;
+		offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+	}
+	else {
+		offset = 0x4C0;
+		offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+	}
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
+			    bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
+}
+
+static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
+{
+	switch (bcm43xx_current_phy(bcm)->type) {
+	case BCM43xx_PHYTYPE_A:
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
+	case BCM43xx_PHYTYPE_B:
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
+		bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
+{
+	bcm43xx_chip_cleanup(bcm);
+	bcm43xx_pio_free(bcm);
+	bcm43xx_dma_free(bcm);
+
+	bcm->current_core->initialized = 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/80211Init */
+static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u32 ucodeflags;
+	int err;
+	u32 sbimconfiglow;
+	u8 limit;
+
+	if (bcm->chip_rev < 5) {
+		sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
+		sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
+		sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
+		if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
+			sbimconfiglow |= 0x32;
+		else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
+			sbimconfiglow |= 0x53;
+		else
+			assert(0);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
+	}
+
+	bcm43xx_phy_calibrate(bcm);
+	err = bcm43xx_chip_init(bcm);
+	if (err)
+		goto out;
+
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
+	ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
+
+	if (0 /*FIXME: which condition has to be used here? */)
+		ucodeflags |= 0x00000010;
+
+	/* HW decryption needs to be set now */
+	ucodeflags |= 0x40000000;
+	
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
+		if (phy->rev == 1)
+			ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
+		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+			ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
+	} else if (phy->type == BCM43xx_PHYTYPE_B) {
+		ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
+		if (phy->rev >= 2 && radio->version == 0x2050)
+			ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
+	}
+
+	if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+					     BCM43xx_UCODEFLAGS_OFFSET)) {
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+				    BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
+	}
+
+	/* Short/Long Retry Limit.
+	 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter.
+	 */
+	limit = limit_value(modparam_short_retry, 0, 0xF);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
+	limit = limit_value(modparam_long_retry, 0, 0xF);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
+
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
+
+	bcm43xx_rate_memory_init(bcm);
+
+	/* Minimum Contention Window */
+	if (phy->type == BCM43xx_PHYTYPE_B)
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
+	else
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
+	/* Maximum Contention Window */
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
+
+	bcm43xx_gen_bssid(bcm);
+	bcm43xx_write_mac_bssid_templates(bcm);
+
+	if (bcm->current_core->rev >= 5)
+		bcm43xx_write16(bcm, 0x043C, 0x000C);
+
+	if (bcm43xx_using_pio(bcm))
+		err = bcm43xx_pio_init(bcm);
+	else
+		err = bcm43xx_dma_init(bcm);
+	if (err)
+		goto err_chip_cleanup;
+	bcm43xx_write16(bcm, 0x0612, 0x0050);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
+
+	bcm43xx_mac_enable(bcm);
+	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+
+	bcm->current_core->initialized = 1;
+out:
+	return err;
+
+err_chip_cleanup:
+	bcm43xx_chip_cleanup(bcm);
+	goto out;
+}
+
+static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
+{
+	int err;
+	u16 pci_status;
+
+	err = bcm43xx_pctl_set_crystal(bcm, 1);
+	if (err)
+		goto out;
+	bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
+	bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
+
+out:
+	return err;
+}
+
+static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
+{
+	bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+	bcm43xx_pctl_set_crystal(bcm, 0);
+}
+
+static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
+					    u32 address,
+					    u32 data)
+{
+	bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
+	bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
+}
+
+static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
+{
+	int err;
+	struct bcm43xx_coreinfo *old_core;
+
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+	if (err)
+		goto out;
+
+	bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+
+	bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+out:
+	return err;
+}
+
+/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
+ * To enable core 0, pass a core_mask of 1<<0
+ */
+static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
+						  u32 core_mask)
+{
+	u32 backplane_flag_nr;
+	u32 value;
+	struct bcm43xx_coreinfo *old_core;
+	int err = 0;
+
+	value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
+	backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
+
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+	if (err)
+		goto out;
+
+	if (bcm->core_pci.rev < 6) {
+		value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
+		value |= (1 << backplane_flag_nr);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
+	} else {
+		err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
+		if (err) {
+			printk(KERN_ERR PFX "Error: ICR setup failure!\n");
+			goto out_switch_back;
+		}
+		value |= core_mask << 8;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
+		if (err) {
+			printk(KERN_ERR PFX "Error: ICR setup failure!\n");
+			goto out_switch_back;
+		}
+	}
+
+	value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
+	value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
+	bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
+
+	if (bcm->core_pci.rev < 5) {
+		value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
+		value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
+			 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
+		value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
+			 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
+		err = bcm43xx_pcicore_commit_settings(bcm);
+		assert(err == 0);
+	}
+
+out_switch_back:
+	err = bcm43xx_switch_core(bcm, old_core);
+out:
+	return err;
+}
+
+static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
+{
+	ieee80211softmac_start(bcm->net_dev);
+}
+
+static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
+		return;
+
+	bcm43xx_mac_suspend(bcm);
+	bcm43xx_phy_lo_g_measure(bcm);
+	bcm43xx_mac_enable(bcm);
+}
+
+static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
+{
+	bcm43xx_phy_lo_mark_all_unused(bcm);
+	if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+		bcm43xx_mac_suspend(bcm);
+		bcm43xx_calc_nrssi_slope(bcm);
+		bcm43xx_mac_enable(bcm);
+	}
+}
+
+static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
+{
+	/* Update device statistics. */
+	bcm43xx_calculate_link_quality(bcm);
+}
+
+static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		//TODO: update_aci_moving_average
+		if (radio->aci_enable && radio->aci_wlan_automatic) {
+			bcm43xx_mac_suspend(bcm);
+			if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
+				if (0 /*TODO: bunch of conditions*/) {
+					bcm43xx_radio_set_interference_mitigation(bcm,
+										  BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
+				}
+			} else if (1/*TODO*/) {
+				/*
+				if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
+					bcm43xx_radio_set_interference_mitigation(bcm,
+										  BCM43xx_RADIO_INTERFMODE_NONE);
+				}
+				*/
+			}
+			bcm43xx_mac_enable(bcm);
+		} else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
+			   phy->rev == 1) {
+			//TODO: implement rev1 workaround
+		}
+	}
+	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+	//TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_task_handler(unsigned long d)
+{
+	struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
+	unsigned long flags;
+	unsigned int state;
+
+	bcm43xx_lock_mmio(bcm, flags);
+
+	assert(bcm->initialized);
+	state = bcm->periodic_state;
+	if (state % 8 == 0)
+		bcm43xx_periodic_every120sec(bcm);
+	if (state % 4 == 0)
+		bcm43xx_periodic_every60sec(bcm);
+	if (state % 2 == 0)
+		bcm43xx_periodic_every30sec(bcm);
+	bcm43xx_periodic_every15sec(bcm);
+	bcm->periodic_state = state + 1;
+
+	mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
+
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
+{
+	del_timer_sync(&bcm->periodic_tasks);
+}
+
+static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
+{
+	struct timer_list *timer = &(bcm->periodic_tasks);
+
+	assert(bcm->initialized);
+	setup_timer(timer,
+		    bcm43xx_periodic_task_handler,
+		    (unsigned long)bcm);
+	timer->expires = jiffies;
+	add_timer(timer);
+}
+
+static void bcm43xx_security_init(struct bcm43xx_private *bcm)
+{
+	bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+						  0x0056) * 2;
+	bcm43xx_clear_keys(bcm);
+}
+
+/* This is the opposite of bcm43xx_init_board() */
+static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+{
+	int i, err;
+	unsigned long flags;
+
+	bcm43xx_sysfs_unregister(bcm);
+
+	bcm43xx_periodic_tasks_delete(bcm);
+
+	bcm43xx_lock(bcm, flags);
+	bcm->initialized = 0;
+	bcm->shutting_down = 1;
+	bcm43xx_unlock(bcm, flags);
+
+	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+		if (!bcm->core_80211[i].available)
+			continue;
+		if (!bcm->core_80211[i].initialized)
+			continue;
+
+		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+		assert(err == 0);
+		bcm43xx_wireless_core_cleanup(bcm);
+	}
+
+	bcm43xx_pctl_set_crystal(bcm, 0);
+
+	bcm43xx_lock(bcm, flags);
+	bcm->shutting_down = 0;
+	bcm43xx_unlock(bcm, flags);
+}
+
+static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+{
+	int i, err;
+	int connect_phy;
+	unsigned long flags;
+
+	might_sleep();
+
+	bcm43xx_lock(bcm, flags);
+	bcm->initialized = 0;
+	bcm->shutting_down = 0;
+	bcm43xx_unlock(bcm, flags);
+
+	err = bcm43xx_pctl_set_crystal(bcm, 1);
+	if (err)
+		goto out;
+	err = bcm43xx_pctl_init(bcm);
+	if (err)
+		goto err_crystal_off;
+	err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
+	if (err)
+		goto err_crystal_off;
+
+	tasklet_enable(&bcm->isr_tasklet);
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+		assert(err != -ENODEV);
+		if (err)
+			goto err_80211_unwind;
+
+		/* Enable the selected wireless core.
+		 * Connect PHY only on the first core.
+		 */
+		if (!bcm43xx_core_enabled(bcm)) {
+			if (bcm->nr_80211_available == 1) {
+				connect_phy = bcm43xx_current_phy(bcm)->connected;
+			} else {
+				if (i == 0)
+					connect_phy = 1;
+				else
+					connect_phy = 0;
+			}
+			bcm43xx_wireless_core_reset(bcm, connect_phy);
+		}
+
+		if (i != 0)
+			bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
+
+		err = bcm43xx_wireless_core_init(bcm);
+		if (err)
+			goto err_80211_unwind;
+
+		if (i != 0) {
+			bcm43xx_mac_suspend(bcm);
+			bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+			bcm43xx_radio_turn_off(bcm);
+		}
+	}
+	bcm->active_80211_core = &bcm->core_80211[0];
+	if (bcm->nr_80211_available >= 2) {
+		bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
+		bcm43xx_mac_enable(bcm);
+	}
+	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
+	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
+	dprintk(KERN_INFO PFX "80211 cores initialized\n");
+	bcm43xx_security_init(bcm);
+	bcm43xx_softmac_init(bcm);
+
+	bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+
+	if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
+		bcm43xx_mac_suspend(bcm);
+		bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
+		bcm43xx_mac_enable(bcm);
+	}
+
+	/* Initialization of the board is done. Flag it as such. */
+	bcm43xx_lock(bcm, flags);
+	bcm->initialized = 1;
+	bcm43xx_unlock(bcm, flags);
+
+	bcm43xx_periodic_tasks_setup(bcm);
+	bcm43xx_sysfs_register(bcm);
+	//FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
+
+	assert(err == 0);
+out:
+	return err;
+
+err_80211_unwind:
+	tasklet_disable(&bcm->isr_tasklet);
+	/* unwind all 80211 initialization */
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		if (!bcm->core_80211[i].initialized)
+			continue;
+		bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+		bcm43xx_wireless_core_cleanup(bcm);
+	}
+err_crystal_off:
+	bcm43xx_pctl_set_crystal(bcm, 0);
+	goto out;
+}
+
+static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
+{
+	struct pci_dev *pci_dev = bcm->pci_dev;
+	int i;
+
+	bcm43xx_chipset_detach(bcm);
+	/* Do _not_ access the chip, after it is detached. */
+	iounmap(bcm->mmio_addr);
+	
+	pci_release_regions(pci_dev);
+	pci_disable_device(pci_dev);
+
+	/* Free allocated structures/fields */
+	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+		kfree(bcm->core_80211_ext[i].phy._lo_pairs);
+		if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
+			kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
+	}
+}	
+
+static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 value;
+	u8 phy_version;
+	u8 phy_type;
+	u8 phy_rev;
+	int phy_rev_ok = 1;
+	void *p;
+
+	value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
+
+	phy_version = (value & 0xF000) >> 12;
+	phy_type = (value & 0x0F00) >> 8;
+	phy_rev = (value & 0x000F);
+
+	dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
+		phy_version, phy_type, phy_rev);
+
+	switch (phy_type) {
+	case BCM43xx_PHYTYPE_A:
+		if (phy_rev >= 4)
+			phy_rev_ok = 0;
+		/*FIXME: We need to switch the ieee->modulation, etc.. flags,
+		 *       if we switch 80211 cores after init is done.
+		 *       As we do not implement on the fly switching between
+		 *       wireless cores, I will leave this as a future task.
+		 */
+		bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
+		bcm->ieee->mode = IEEE_A;
+		bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
+				       IEEE80211_24GHZ_BAND;
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
+			phy_rev_ok = 0;
+		bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
+		bcm->ieee->mode = IEEE_B;
+		bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
+		break;
+	case BCM43xx_PHYTYPE_G:
+		if (phy_rev > 7)
+			phy_rev_ok = 0;
+		bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
+					IEEE80211_CCK_MODULATION;
+		bcm->ieee->mode = IEEE_G;
+		bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
+		break;
+	default:
+		printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
+		       phy_type);
+		return -ENODEV;
+	};
+	if (!phy_rev_ok) {
+		printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
+		       phy_rev);
+	}
+
+	phy->version = phy_version;
+	phy->type = phy_type;
+	phy->rev = phy_rev;
+	if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
+		p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
+			    GFP_KERNEL);
+		if (!p)
+			return -ENOMEM;
+		phy->_lo_pairs = p;
+	}
+
+	return 0;
+}
+
+static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
+{
+	struct pci_dev *pci_dev = bcm->pci_dev;
+	struct net_device *net_dev = bcm->net_dev;
+	int err;
+	int i;
+	unsigned long mmio_start, mmio_flags, mmio_len;
+	u32 coremask;
+
+	err = pci_enable_device(pci_dev);
+	if (err) {
+		printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
+		goto out;
+	}
+	mmio_start = pci_resource_start(pci_dev, 0);
+	mmio_flags = pci_resource_flags(pci_dev, 0);
+	mmio_len = pci_resource_len(pci_dev, 0);
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX
+		       "%s, region #0 not an MMIO resource, aborting\n",
+		       pci_name(pci_dev));
+		err = -ENODEV;
+		goto err_pci_disable;
+	}
+	err = pci_request_regions(pci_dev, KBUILD_MODNAME);
+	if (err) {
+		printk(KERN_ERR PFX
+		       "could not access PCI resources (%i)\n", err);
+		goto err_pci_disable;
+	}
+	/* enable PCI bus-mastering */
+	pci_set_master(pci_dev);
+	bcm->mmio_addr = ioremap(mmio_start, mmio_len);
+	if (!bcm->mmio_addr) {
+		printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
+		       pci_name(pci_dev));
+		err = -EIO;
+		goto err_pci_release;
+	}
+	bcm->mmio_len = mmio_len;
+	net_dev->base_addr = (unsigned long)bcm->mmio_addr;
+
+	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
+	                          &bcm->board_vendor);
+	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
+	                          &bcm->board_type);
+	bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
+	                          &bcm->board_revision);
+
+	err = bcm43xx_chipset_attach(bcm);
+	if (err)
+		goto err_iounmap;
+	err = bcm43xx_pctl_init(bcm);
+	if (err)
+		goto err_chipset_detach;
+	err = bcm43xx_probe_cores(bcm);
+	if (err)
+		goto err_chipset_detach;
+	
+	/* Attach all IO cores to the backplane. */
+	coremask = 0;
+	for (i = 0; i < bcm->nr_80211_available; i++)
+		coremask |= (1 << bcm->core_80211[i].index);
+	//FIXME: Also attach some non80211 cores?
+	err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
+	if (err) {
+		printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
+		goto err_chipset_detach;
+	}
+
+	err = bcm43xx_sprom_extract(bcm);
+	if (err)
+		goto err_chipset_detach;
+	err = bcm43xx_leds_init(bcm);
+	if (err)
+		goto err_chipset_detach;
+
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+		assert(err != -ENODEV);
+		if (err)
+			goto err_80211_unwind;
+
+		/* Enable the selected wireless core.
+		 * Connect PHY only on the first core.
+		 */
+		bcm43xx_wireless_core_reset(bcm, (i == 0));
+
+		err = bcm43xx_read_phyinfo(bcm);
+		if (err && (i == 0))
+			goto err_80211_unwind;
+
+		err = bcm43xx_read_radioinfo(bcm);
+		if (err && (i == 0))
+			goto err_80211_unwind;
+
+		err = bcm43xx_validate_chip(bcm);
+		if (err && (i == 0))
+			goto err_80211_unwind;
+
+		bcm43xx_radio_turn_off(bcm);
+		err = bcm43xx_phy_init_tssi2dbm_table(bcm);
+		if (err)
+			goto err_80211_unwind;
+		bcm43xx_wireless_core_disable(bcm);
+	}
+	bcm43xx_pctl_set_crystal(bcm, 0);
+
+	/* Set the MAC address in the networking subsystem */
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
+	else
+		memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
+
+	bcm43xx_geo_init(bcm);
+
+	snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
+		 "Broadcom %04X", bcm->chip_id);
+
+	assert(err == 0);
+out:
+	return err;
+
+err_80211_unwind:
+	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
+		kfree(bcm->core_80211_ext[i].phy._lo_pairs);
+		if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
+			kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
+	}
+err_chipset_detach:
+	bcm43xx_chipset_detach(bcm);
+err_iounmap:
+	iounmap(bcm->mmio_addr);
+err_pci_release:
+	pci_release_regions(pci_dev);
+err_pci_disable:
+	pci_disable_device(pci_dev);
+	goto out;
+}
+
+/* Do the Hardware IO operations to send the txb */
+static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
+			     struct ieee80211_txb *txb)
+{
+	int err = -ENODEV;
+
+	if (bcm43xx_using_pio(bcm))
+		err = bcm43xx_pio_tx(bcm, txb);
+	else
+		err = bcm43xx_dma_tx(bcm, txb);
+
+	return err;
+}
+
+static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
+				       u8 channel)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct bcm43xx_radioinfo *radio;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (bcm->initialized) {
+		bcm43xx_mac_suspend(bcm);
+		bcm43xx_radio_selectchannel(bcm, channel, 0);
+		bcm43xx_mac_enable(bcm);
+	} else {
+		radio = bcm43xx_current_radio(bcm);
+		radio->initial_channel = channel;
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+/* set_security() callback in struct ieee80211_device */
+static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
+					   struct ieee80211_security *sec)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	struct ieee80211_security *secinfo = &bcm->ieee->sec;
+	unsigned long flags;
+	int keyidx;
+	
+	dprintk(KERN_INFO PFX "set security called\n");
+
+	bcm43xx_lock_mmio(bcm, flags);
+
+	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;
+		dprintk(KERN_INFO PFX "   .active_key = %d\n", sec->active_key);
+	}
+	if (sec->flags & SEC_UNICAST_GROUP) {
+		secinfo->unicast_uses_group = sec->unicast_uses_group;
+		dprintk(KERN_INFO PFX "   .unicast_uses_group = %d\n", sec->unicast_uses_group);
+	}
+	if (sec->flags & SEC_LEVEL) {
+		secinfo->level = sec->level;
+		dprintk(KERN_INFO PFX "   .level = %d\n", sec->level);
+	}
+	if (sec->flags & SEC_ENABLED) {
+		secinfo->enabled = sec->enabled;
+		dprintk(KERN_INFO PFX "   .enabled = %d\n", sec->enabled);
+	}
+	if (sec->flags & SEC_ENCRYPT) {
+		secinfo->encrypt = sec->encrypt;
+		dprintk(KERN_INFO PFX "   .encrypt = %d\n", sec->encrypt);
+	}
+	if (bcm->initialized && !bcm->ieee->host_encrypt) {
+		if (secinfo->enabled) {
+			/* upload WEP keys to hardware */
+			char null_address[6] = { 0 };
+			u8 algorithm = 0;
+			for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
+				if (!(sec->flags & (1<<keyidx)))
+					continue;
+				switch (sec->encode_alg[keyidx]) {
+					case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
+					case SEC_ALG_WEP:
+						algorithm = BCM43xx_SEC_ALGO_WEP;
+						if (secinfo->key_sizes[keyidx] == 13)
+							algorithm = BCM43xx_SEC_ALGO_WEP104;
+						break;
+					case SEC_ALG_TKIP:
+						FIXME();
+						algorithm = BCM43xx_SEC_ALGO_TKIP;
+						break;
+					case SEC_ALG_CCMP:
+						FIXME();
+						algorithm = BCM43xx_SEC_ALGO_AES;
+						break;
+					default:
+						assert(0);
+						break;
+				}
+				bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
+				bcm->key[keyidx].enabled = 1;
+				bcm->key[keyidx].algorithm = algorithm;
+			}
+		} else
+				bcm43xx_clear_keys(bcm);
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+/* hard_start_xmit() callback in struct ieee80211_device */
+static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
+					     struct net_device *net_dev,
+					     int pri)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err = -ENODEV;
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	if (likely(bcm->initialized))
+		err = bcm43xx_tx(bcm, txb);
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return err;
+}
+
+static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
+{
+	return &(bcm43xx_priv(net_dev)->ieee->stats);
+}
+
+static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_controller_restart(bcm, "TX timeout");
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void bcm43xx_net_poll_controller(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
+	local_irq_restore(flags);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+static int bcm43xx_net_open(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+	return bcm43xx_init_board(bcm);
+}
+
+static int bcm43xx_net_stop(struct net_device *net_dev)
+{
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+	ieee80211softmac_stop(net_dev);
+	bcm43xx_disable_interrupts_sync(bcm, NULL);
+	bcm43xx_free_board(bcm);
+
+	return 0;
+}
+
+static int bcm43xx_init_private(struct bcm43xx_private *bcm,
+				struct net_device *net_dev,
+				struct pci_dev *pci_dev)
+{
+	int err;
+
+	bcm->ieee = netdev_priv(net_dev);
+	bcm->softmac = ieee80211_priv(net_dev);
+	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
+
+	bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+	bcm->pci_dev = pci_dev;
+	bcm->net_dev = net_dev;
+	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
+	spin_lock_init(&bcm->_lock);
+	tasklet_init(&bcm->isr_tasklet,
+		     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
+		     (unsigned long)bcm);
+	tasklet_disable_nosync(&bcm->isr_tasklet);
+	if (modparam_pio) {
+		bcm->__using_pio = 1;
+	} else {
+		err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
+		err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
+		if (err) {
+#ifdef CONFIG_BCM43XX_PIO
+			printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
+			bcm->__using_pio = 1;
+#else
+			printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+					    "Recompile the driver with PIO support, please.\n");
+			return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
+		}
+	}
+	bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
+
+	/* default to sw encryption for now */
+	bcm->ieee->host_build_iv = 0;
+	bcm->ieee->host_encrypt = 1;
+	bcm->ieee->host_decrypt = 1;
+	
+	bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
+	bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
+	bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
+	bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
+
+	return 0;
+}
+
+static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	struct net_device *net_dev;
+	struct bcm43xx_private *bcm;
+	int err;
+
+#ifdef CONFIG_BCM947XX
+	if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
+		return -ENODEV;
+#endif
+
+#ifdef DEBUG_SINGLE_DEVICE_ONLY
+	if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
+		return -ENODEV;
+#endif
+
+	net_dev = alloc_ieee80211softmac(sizeof(*bcm));
+	if (!net_dev) {
+		printk(KERN_ERR PFX
+		       "could not allocate ieee80211 device %s\n",
+		       pci_name(pdev));
+		err = -ENOMEM;
+		goto out;
+	}
+	/* initialize the net_device struct */
+	SET_MODULE_OWNER(net_dev);
+	SET_NETDEV_DEV(net_dev, &pdev->dev);
+
+	net_dev->open = bcm43xx_net_open;
+	net_dev->stop = bcm43xx_net_stop;
+	net_dev->get_stats = bcm43xx_net_get_stats;
+	net_dev->tx_timeout = bcm43xx_net_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	net_dev->poll_controller = bcm43xx_net_poll_controller;
+#endif
+	net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
+	net_dev->irq = pdev->irq;
+	SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
+
+	/* initialize the bcm43xx_private struct */
+	bcm = bcm43xx_priv(net_dev);
+	memset(bcm, 0, sizeof(*bcm));
+	err = bcm43xx_init_private(bcm, net_dev, pdev);
+	if (err)
+		goto err_free_netdev;
+
+	pci_set_drvdata(pdev, net_dev);
+
+	err = bcm43xx_attach_board(bcm);
+	if (err)
+		goto err_free_netdev;
+
+	err = register_netdev(net_dev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		err = -ENOMEM;
+		goto err_detach_board;
+	}
+
+	bcm43xx_debugfs_add_device(bcm);
+
+	assert(err == 0);
+out:
+	return err;
+
+err_detach_board:
+	bcm43xx_detach_board(bcm);
+err_free_netdev:
+	free_ieee80211softmac(net_dev);
+	goto out;
+}
+
+static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *net_dev = pci_get_drvdata(pdev);
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+
+	bcm43xx_debugfs_remove_device(bcm);
+	unregister_netdev(net_dev);
+	bcm43xx_detach_board(bcm);
+	assert(bcm->ucode == NULL);
+	free_ieee80211softmac(net_dev);
+}
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use bcm43xx_controller_restart()
+ */
+static void bcm43xx_chip_reset(void *_bcm)
+{
+	struct bcm43xx_private *bcm = _bcm;
+	struct net_device *net_dev = bcm->net_dev;
+	struct pci_dev *pci_dev = bcm->pci_dev;
+	int err;
+	int was_initialized = bcm->initialized;
+
+	netif_stop_queue(bcm->net_dev);
+	tasklet_disable(&bcm->isr_tasklet);
+
+	bcm->firmware_norelease = 1;
+	if (was_initialized)
+		bcm43xx_free_board(bcm);
+	bcm->firmware_norelease = 0;
+	bcm43xx_detach_board(bcm);
+	err = bcm43xx_init_private(bcm, net_dev, pci_dev);
+	if (err)
+		goto failure;
+	err = bcm43xx_attach_board(bcm);
+	if (err)
+		goto failure;
+	if (was_initialized) {
+		err = bcm43xx_init_board(bcm);
+		if (err)
+			goto failure;
+	}
+	netif_wake_queue(bcm->net_dev);
+	printk(KERN_INFO PFX "Controller restarted\n");
+
+	return;
+failure:
+	printk(KERN_ERR PFX "Controller restart failed\n");
+}
+
+/* Hard-reset the chip.
+ * This can be called from interrupt or process context.
+ * Make sure to _not_ re-enable device interrupts after this has been called.
+*/
+void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
+{
+	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+	printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
+	INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
+	schedule_work(&bcm->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *net_dev = pci_get_drvdata(pdev);
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	unsigned long flags;
+	int try_to_shutdown = 0, err;
+
+	dprintk(KERN_INFO PFX "Suspending...\n");
+
+	bcm43xx_lock(bcm, flags);
+	bcm->was_initialized = bcm->initialized;
+	if (bcm->initialized)
+		try_to_shutdown = 1;
+	bcm43xx_unlock(bcm, flags);
+
+	netif_device_detach(net_dev);
+	if (try_to_shutdown) {
+		ieee80211softmac_stop(net_dev);
+		err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
+		if (unlikely(err)) {
+			dprintk(KERN_ERR PFX "Suspend failed.\n");
+			return -EAGAIN;
+		}
+		bcm->firmware_norelease = 1;
+		bcm43xx_free_board(bcm);
+		bcm->firmware_norelease = 0;
+	}
+	bcm43xx_chipset_detach(bcm);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	dprintk(KERN_INFO PFX "Device suspended.\n");
+
+	return 0;
+}
+
+static int bcm43xx_resume(struct pci_dev *pdev)
+{
+	struct net_device *net_dev = pci_get_drvdata(pdev);
+	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err = 0;
+
+	dprintk(KERN_INFO PFX "Resuming...\n");
+
+	pci_set_power_state(pdev, 0);
+	pci_enable_device(pdev);
+	pci_restore_state(pdev);
+
+	bcm43xx_chipset_attach(bcm);
+	if (bcm->was_initialized) {
+		bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+		err = bcm43xx_init_board(bcm);
+	}
+	if (err) {
+		printk(KERN_ERR PFX "Resume failed!\n");
+		return err;
+	}
+
+	netif_device_attach(net_dev);
+	
+	/*FIXME: This should be handled by softmac instead. */
+	schedule_work(&bcm->softmac->associnfo.work);
+
+	dprintk(KERN_INFO PFX "Device resumed.\n");
+
+	return 0;
+}
+
+#endif				/* CONFIG_PM */
+
+static struct pci_driver bcm43xx_pci_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = bcm43xx_pci_tbl,
+	.probe = bcm43xx_init_one,
+	.remove = __devexit_p(bcm43xx_remove_one),
+#ifdef CONFIG_PM
+	.suspend = bcm43xx_suspend,
+	.resume = bcm43xx_resume,
+#endif				/* CONFIG_PM */
+};
+
+static int __init bcm43xx_init(void)
+{
+	printk(KERN_INFO KBUILD_MODNAME " driver\n");
+	bcm43xx_debugfs_init();
+	return pci_register_driver(&bcm43xx_pci_driver);
+}
+
+static void __exit bcm43xx_exit(void)
+{
+	pci_unregister_driver(&bcm43xx_pci_driver);
+	bcm43xx_debugfs_exit();
+}
+
+module_init(bcm43xx_init)
+module_exit(bcm43xx_exit)

+ 168 - 0
drivers/net/wireless/bcm43xx/bcm43xx_main.h

@@ -0,0 +1,168 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_MAIN_H_
+#define BCM43xx_MAIN_H_
+
+#include "bcm43xx.h"
+
+#ifdef CONFIG_BCM947XX
+#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
+
+static inline void e_aton(char *str, char *dest)
+{
+	int i = 0;
+	u16 *d = (u16 *) dest;
+
+	for (;;) {
+		dest[i++] = (char) simple_strtoul(str, NULL, 16);
+		str += 2;
+		if (!*str++ || i == 6)
+			break;
+	}
+	for (i = 0; i < 3; i++)
+		d[i] = cpu_to_be16(d[i]);
+}
+#endif
+
+#define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes)		P4D_BYTES( __LINE__ , (nr_bytes))
+
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline
+u8 bcm43xx_freq_to_channel_a(int freq)
+{
+	return ((freq - 5000) / 5);
+}
+static inline
+u8 bcm43xx_freq_to_channel_bg(int freq)
+{
+	u8 channel;
+
+	if (freq == 2484)
+		channel = 14;
+	else
+		channel = (freq - 2407) / 5;
+
+	return channel;
+}
+static inline
+u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm,
+			   int freq)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		return bcm43xx_freq_to_channel_a(freq);
+	return bcm43xx_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline
+int bcm43xx_channel_to_freq_a(u8 channel)
+{
+	return (5000 + (5 * channel));
+}
+static inline
+int bcm43xx_channel_to_freq_bg(u8 channel)
+{
+	int freq;
+
+	if (channel == 14)
+		freq = 2484;
+	else
+		freq = 2407 + (5 * channel);
+
+	return freq;
+}
+static inline
+int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
+			    u8 channel)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		return bcm43xx_channel_to_freq_a(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 <= 200);
+}
+static inline
+int bcm43xx_is_valid_channel_bg(u8 channel)
+{
+	return (channel >= 1 && channel <= 14);
+}
+static inline
+int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
+			     u8 channel)
+{
+	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+		return bcm43xx_is_valid_channel_a(channel);
+	return bcm43xx_is_valid_channel_bg(channel);
+}
+
+void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
+void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
+
+void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
+			int iw_mode);
+
+u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset);
+u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
+		       u16 routing, u16 offset);
+void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u32 value);
+void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
+			 u16 routing, u16 offset,
+			 u16 value);
+
+void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
+
+int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
+
+void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
+
+void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
+void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
+
+void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
+
+int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
+int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom);
+
+#endif /* BCM43xx_MAIN_H_ */

+ 2345 - 0
drivers/net/wireless/bcm43xx/bcm43xx_phy.c

@@ -0,0 +1,2345 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_phy.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_radio.h"
+#include "bcm43xx_ilt.h"
+#include "bcm43xx_power.h"
+
+
+static const s8 bcm43xx_tssi2dbm_b_table[] = {
+	0x4D, 0x4C, 0x4B, 0x4A,
+	0x4A, 0x49, 0x48, 0x47,
+	0x47, 0x46, 0x45, 0x45,
+	0x44, 0x43, 0x42, 0x42,
+	0x41, 0x40, 0x3F, 0x3E,
+	0x3D, 0x3C, 0x3B, 0x3A,
+	0x39, 0x38, 0x37, 0x36,
+	0x35, 0x34, 0x32, 0x31,
+	0x30, 0x2F, 0x2D, 0x2C,
+	0x2B, 0x29, 0x28, 0x26,
+	0x25, 0x23, 0x21, 0x1F,
+	0x1D, 0x1A, 0x17, 0x14,
+	0x10, 0x0C, 0x06, 0x00,
+	  -7,   -7,   -7,   -7,
+	  -7,   -7,   -7,   -7,
+	  -7,   -7,   -7,   -7,
+};
+
+static const s8 bcm43xx_tssi2dbm_g_table[] = {
+	 77,  77,  77,  76,
+	 76,  76,  75,  75,
+	 74,  74,  73,  73,
+	 73,  72,  72,  71,
+	 71,  70,  70,  69,
+	 68,  68,  67,  67,
+	 66,  65,  65,  64,
+	 63,  63,  62,  61,
+	 60,  59,  58,  57,
+	 56,  55,  54,  53,
+	 52,  50,  49,  47,
+	 45,  43,  40,  37,
+	 33,  28,  22,  14,
+	  5,  -7, -20, -20,
+	-20, -20, -20, -20,
+	-20, -20, -20, -20,
+};
+
+static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
+
+
+void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	assert(irqs_disabled());
+	if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) {
+		phy->is_locked = 0;
+		return;
+	}
+	if (bcm->current_core->rev < 3) {
+		bcm43xx_mac_suspend(bcm);
+		spin_lock(&phy->lock);
+	} else {
+		if (bcm->ieee->iw_mode != IW_MODE_MASTER)
+			bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+	}
+	phy->is_locked = 1;
+}
+
+void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	assert(irqs_disabled());
+	if (bcm->current_core->rev < 3) {
+		if (phy->is_locked) {
+			spin_unlock(&phy->lock);
+			bcm43xx_mac_enable(bcm);
+		}
+	} else {
+		if (bcm->ieee->iw_mode != IW_MODE_MASTER)
+			bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	}
+	phy->is_locked = 0;
+}
+
+u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset)
+{
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset);
+	return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA);
+}
+
+void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
+{
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset);
+	mmiowb();
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val);
+}
+
+void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	unsigned long flags;
+
+	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
+	if (phy->calibrated)
+		return;
+	if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
+		/* We do not want to be preempted while calibrating
+		 * the hardware.
+		 */
+		local_irq_save(flags);
+
+		bcm43xx_wireless_core_reset(bcm, 0);
+		bcm43xx_phy_initg(bcm);
+		bcm43xx_wireless_core_reset(bcm, 1);
+
+		local_irq_restore(flags);
+	}
+	phy->calibrated = 1;
+}
+
+/* Connect the PHY 
+ * http://bcm-specs.sipsolutions.net/SetPHY
+ */
+int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u32 flags;
+
+	if (bcm->current_core->rev < 5)
+		goto out;
+
+	flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+	if (connect) {
+		if (!(flags & 0x00010000))
+			return -ENODEV;
+		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		flags |= (0x800 << 18);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
+	} else {
+		if (!(flags & 0x00020000))
+			return -ENODEV;
+		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		flags &= ~(0x800 << 18);
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
+	}
+out:
+	phy->connected = connect;
+	if (connect)
+		dprintk(KERN_INFO PFX "PHY connected\n");
+	else
+		dprintk(KERN_INFO PFX "PHY disconnected\n");
+
+	return 0;
+}
+
+/* intialize B PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0;
+	int must_reset_txpower = 0;
+
+	assert(phy->type != BCM43xx_PHYTYPE_A);
+	if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
+	    (bcm->board_type == 0x0416))
+		return;
+
+	bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF);
+	bcm43xx_phy_write(bcm, 0x0028, 0x8018);
+
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		if (!phy->connected)
+			return;
+		bcm43xx_phy_write(bcm, 0x047A, 0xC111);
+	}
+	if (phy->savedpctlreg != 0xFFFF)
+		return;
+
+	if (phy->type == BCM43xx_PHYTYPE_B &&
+	    phy->rev >= 2 &&
+	    radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0076,
+				      bcm43xx_radio_read16(bcm, 0x0076) | 0x0084);
+	} else {
+		saved_batt = radio->baseband_atten;
+		saved_ratt = radio->radio_atten;
+		saved_txctl1 = radio->txctl1;
+		if ((radio->revision >= 6) && (radio->revision <= 8)
+		    && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
+			bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0);
+		else
+			bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0);
+		must_reset_txpower = 1;
+	}
+	bcm43xx_dummy_transmission(bcm);
+
+	phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL);
+
+	if (must_reset_txpower)
+		bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1);
+	else
+		bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B);
+	bcm43xx_radio_clear_tssi(bcm);
+}
+
+static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 offset = 0x0000;
+
+	if (phy->rev == 1)
+		offset = 0x4C00;
+
+	bcm43xx_ilt_write(bcm, offset, 0x00FE);
+	bcm43xx_ilt_write(bcm, offset + 1, 0x000D);
+	bcm43xx_ilt_write(bcm, offset + 2, 0x0013);
+	bcm43xx_ilt_write(bcm, offset + 3, 0x0019);
+
+	if (phy->rev == 1) {
+		bcm43xx_ilt_write(bcm, 0x1800, 0x2710);
+		bcm43xx_ilt_write(bcm, 0x1801, 0x9B83);
+		bcm43xx_ilt_write(bcm, 0x1802, 0x9B83);
+		bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D);
+		bcm43xx_phy_write(bcm, 0x0455, 0x0004);
+	}
+
+	bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700);
+	bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F);
+	bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80);
+	bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300);
+
+	bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008);
+
+	bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008);
+	bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600);
+	bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700);
+	bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100);
+
+	if (phy->rev == 1)
+		bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007);
+
+	bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C);
+	bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200);
+	bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C);
+	bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020);
+	bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200);
+	bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E);
+	bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00);
+	bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028);
+	bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00);
+
+	if (phy->rev == 1) {
+		bcm43xx_phy_write(bcm, 0x0430, 0x092B);
+		bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002);
+	} else {
+		bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1);
+		bcm43xx_phy_write(bcm, 0x041F, 0x287A);
+		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004);
+	}
+
+	if (phy->rev > 2) {
+		bcm43xx_phy_write(bcm, 0x0422, 0x287A);
+		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); 
+	}
+		
+	bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
+	bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
+
+	if (phy->rev == 1) {
+		bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
+		bcm43xx_phy_write(bcm, 0x048B, 0x005E);
+		bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
+		bcm43xx_phy_write(bcm, 0x048D, 0x0002);
+	}
+
+	bcm43xx_ilt_write(bcm, offset + 0x0800, 0);
+	bcm43xx_ilt_write(bcm, offset + 0x0801, 7);
+	bcm43xx_ilt_write(bcm, offset + 0x0802, 16);
+	bcm43xx_ilt_write(bcm, offset + 0x0803, 28);
+}
+
+static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i;
+
+	assert(phy->type == BCM43xx_PHYTYPE_G);
+	if (phy->rev == 1) {
+		bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
+		bcm43xx_phy_write(bcm, 0x042C, 0x005A);
+		bcm43xx_phy_write(bcm, 0x0427, 0x001A);
+
+		for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]);
+		for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]);
+		for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
+	} else {
+		/* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
+		bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654);
+
+		if (phy->rev == 2) {
+			bcm43xx_phy_write(bcm, 0x04C0, 0x1861);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x0271);
+		} else if (phy->rev > 2) {
+			bcm43xx_phy_write(bcm, 0x04C0, 0x0098);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x0070);
+			bcm43xx_phy_write(bcm, 0x04C9, 0x0080);
+		}
+		bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800);
+
+		for (i = 0; i < 64; i++)
+			bcm43xx_ilt_write(bcm, 0x4000 + i, i);
+		for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]);
+	}
+	
+	if (phy->rev <= 2)
+		for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
+	else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
+		for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
+	else
+		for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]);
+	
+	if (phy->rev == 2)
+		for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
+	else if ((phy->rev > 2) && (phy->rev <= 7))
+		for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
+	
+	if (phy->rev == 1) {
+		for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
+		for (i = 0; i < 4; i++) {
+			bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020);
+			bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020);
+			bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020);
+			bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020);
+		}
+		bcm43xx_phy_agcsetup(bcm);
+
+		if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
+		    (bcm->board_type == 0x0416) &&
+		    (bcm->board_revision == 0x0017))
+			return;
+
+		bcm43xx_ilt_write(bcm, 0x5001, 0x0002);
+		bcm43xx_ilt_write(bcm, 0x5002, 0x0001);
+	} else {
+		for (i = 0; i <= 0x2F; i++)
+			bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820);
+		bcm43xx_phy_agcsetup(bcm);
+		bcm43xx_phy_read(bcm, 0x0400); /* dummy read */
+		bcm43xx_phy_write(bcm, 0x0403, 0x1000);
+		bcm43xx_ilt_write(bcm, 0x3C02, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x3C03, 0x0014);
+
+		if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
+		    (bcm->board_type == 0x0416) &&
+		    (bcm->board_revision == 0x0017))
+			return;
+
+		bcm43xx_ilt_write(bcm, 0x0401, 0x0002);
+		bcm43xx_ilt_write(bcm, 0x0402, 0x0001);
+	}
+}
+
+/* Initialize the noisescaletable for APHY */
+static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	int i;
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400);
+	for (i = 0; i < 12; i++) {
+		if (phy->rev == 2)
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
+		else
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
+	}
+	if (phy->rev == 2)
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700);
+	else
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300);
+	for (i = 0; i < 11; i++) {
+		if (phy->rev == 2)
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
+		else
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
+	}
+	if (phy->rev == 2)
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067);
+	else
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023);
+}
+
+static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i;
+
+	assert(phy->type == BCM43xx_PHYTYPE_A);
+	switch (phy->rev) {
+	case 2:
+		bcm43xx_phy_write(bcm, 0x008E, 0x3800);
+		bcm43xx_phy_write(bcm, 0x0035, 0x03FF);
+		bcm43xx_phy_write(bcm, 0x0036, 0x0400);
+
+		bcm43xx_ilt_write(bcm, 0x3807, 0x0051);
+
+		bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
+		bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
+		bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF);
+		bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
+
+		bcm43xx_phy_write(bcm, 0x0024, 0x4680);
+		bcm43xx_phy_write(bcm, 0x0020, 0x0003);
+		bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
+		bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
+
+		bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
+		bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF);
+		bcm43xx_phy_write(bcm, 0x008E, 0x58C1);
+
+		bcm43xx_ilt_write(bcm, 0x0803, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x0804, 0x001F);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x002A);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x0030);
+		bcm43xx_ilt_write(bcm, 0x0807, 0x003A);
+
+		bcm43xx_ilt_write(bcm, 0x0000, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0001, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0002, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0003, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0004, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0005, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0006, 0x0019);
+
+		bcm43xx_ilt_write(bcm, 0x0404, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0405, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0406, 0x0007);
+
+		for (i = 0; i < 16; i++)
+			bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F);
+
+		bcm43xx_ilt_write(bcm, 0x3003, 0x1044);
+		bcm43xx_ilt_write(bcm, 0x3004, 0x7201);
+		bcm43xx_ilt_write(bcm, 0x3006, 0x0040);
+		bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008);
+
+		for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]);
+		for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]);
+		for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
+		bcm43xx_phy_init_noisescaletbl(bcm);
+		for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
+		break;
+	case 3:
+		for (i = 0; i < 64; i++)
+			bcm43xx_ilt_write(bcm, 0x4000 + i, i);
+
+		bcm43xx_ilt_write(bcm, 0x3807, 0x0051);
+
+		bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
+		bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
+		bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
+
+		bcm43xx_phy_write(bcm, 0x0024, 0x4680);
+		bcm43xx_phy_write(bcm, 0x0020, 0x0003);
+		bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
+		bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
+		bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
+
+		bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008);
+		for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]);
+		bcm43xx_phy_init_noisescaletbl(bcm);
+		for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
+			bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
+
+		bcm43xx_phy_write(bcm, 0x0003, 0x1808);
+
+		bcm43xx_ilt_write(bcm, 0x0803, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x0804, 0x001F);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x002A);
+		bcm43xx_ilt_write(bcm, 0x0805, 0x0030);
+		bcm43xx_ilt_write(bcm, 0x0807, 0x003A);
+
+		bcm43xx_ilt_write(bcm, 0x0000, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0001, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0002, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0003, 0x0013);
+		bcm43xx_ilt_write(bcm, 0x0004, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0005, 0x0015);
+		bcm43xx_ilt_write(bcm, 0x0006, 0x0019);
+
+		bcm43xx_ilt_write(bcm, 0x0404, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0405, 0x0003);
+		bcm43xx_ilt_write(bcm, 0x0406, 0x0007);
+
+		bcm43xx_ilt_write(bcm, 0x3C02, 0x000F);
+		bcm43xx_ilt_write(bcm, 0x3C03, 0x0014);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+/* Initialize APHY. This is also called for the GPHY in some cases. */
+static void bcm43xx_phy_inita(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tval;
+
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_phy_setupa(bcm);
+	} else {
+		bcm43xx_phy_setupg(bcm);
+		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+			bcm43xx_phy_write(bcm, 0x046E, 0x03CF);
+		return;
+	}
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
+	                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340);
+	bcm43xx_phy_write(bcm, 0x0034, 0x0001);
+
+	TODO();//TODO: RSSI AGC
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
+	                  bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14));
+	bcm43xx_radio_init2060(bcm);
+
+	if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)
+	    && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) {
+		if (radio->lofcal == 0xFFFF) {
+			TODO();//TODO: LOF Cal
+			bcm43xx_radio_set_tx_iq(bcm);
+		} else
+			bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal);
+	}
+
+	bcm43xx_phy_write(bcm, 0x007A, 0xF111);
+
+	if (phy->savedpctlreg == 0xFFFF) {
+		bcm43xx_radio_write16(bcm, 0x0019, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0017, 0x0020);
+
+		tval = bcm43xx_ilt_read(bcm, 0x3001);
+		if (phy->rev == 1) {
+			bcm43xx_ilt_write(bcm, 0x3001,
+					  (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87)
+					  | 0x0058);
+		} else {
+			bcm43xx_ilt_write(bcm, 0x3001,
+					  (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3)
+					  | 0x002C);
+		}
+		bcm43xx_dummy_transmission(bcm);
+		phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL);
+		bcm43xx_ilt_write(bcm, 0x3001, tval);
+
+		bcm43xx_radio_set_txpower_a(bcm, 0x0018);
+	}
+	bcm43xx_radio_clear_tssi(bcm);
+}
+
+static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset, val;
+
+	bcm43xx_write16(bcm, 0x03EC, 0x3F22);
+	bcm43xx_phy_write(bcm, 0x0020, 0x301C);
+	bcm43xx_phy_write(bcm, 0x0026, 0x0000);
+	bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
+	bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
+	if (radio->channel == 0xFF)
+		bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+	else
+		bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
+	if (radio->version != 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
+	}
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+		bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
+		bcm43xx_phy_write(bcm, 0x0038, 0x0677);
+		bcm43xx_radio_init2050(bcm);
+	}
+	bcm43xx_phy_write(bcm, 0x0014, 0x0080);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CC);
+	bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
+	bcm43xx_phy_lo_b_measure(bcm);
+	bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
+	if (radio->version != 0x2050)
+		bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000);
+	bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
+	if (radio->version != 0x2050)
+		bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+	bcm43xx_phy_init_pctl(bcm);
+}
+
+static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset, val;
+
+	bcm43xx_write16(bcm, 0x03EC, 0x3F22);
+	bcm43xx_phy_write(bcm, 0x0020, 0x301C);
+	bcm43xx_phy_write(bcm, 0x0026, 0x0000);
+	bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
+	bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
+	if (radio->channel == 0xFF)
+		bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+	else
+		bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
+	if (radio->version != 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
+	}
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+		bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
+		bcm43xx_phy_write(bcm, 0x0038, 0x0677);
+		bcm43xx_radio_init2050(bcm);
+	}
+	bcm43xx_phy_write(bcm, 0x0014, 0x0080);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0032, 0x00E0);
+	bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
+
+	bcm43xx_phy_lo_b_measure(bcm);
+
+	bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100);
+	bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+	if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+		bcm43xx_calc_nrssi_slope(bcm);
+		bcm43xx_calc_nrssi_threshold(bcm);
+	}
+	bcm43xx_phy_init_pctl(bcm);
+}
+
+static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset;
+
+	if (phy->version == 1 &&
+	    radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A)
+				      | 0x0050);
+	}
+	if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) &&
+	    (bcm->board_type != 0x0416)) {
+		for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
+			bcm43xx_phy_write(bcm, offset,
+					  (bcm43xx_phy_read(bcm, offset) + 0x2020)
+					  & 0x3F3F);
+		}
+	}
+	bcm43xx_phy_write(bcm, 0x0035,
+			  (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF)
+			  | 0x0700);
+	if (radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0038, 0x0667);
+
+	if (phy->connected) {
+		if (radio->version == 0x2050) {
+			bcm43xx_radio_write16(bcm, 0x007A,
+					      bcm43xx_radio_read16(bcm, 0x007A)
+					      | 0x0020);
+			bcm43xx_radio_write16(bcm, 0x0051,
+					      bcm43xx_radio_read16(bcm, 0x0051)
+					      | 0x0004);
+		}
+		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000);
+
+		bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
+		bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
+
+		bcm43xx_phy_write(bcm, 0x001C, 0x186A);
+
+		bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900);
+		bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064);
+		bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A);
+	}
+
+	if (bcm->bad_frames_preempt) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11));
+	}
+
+	if (phy->version == 1 && radio->version == 0x2050) {
+		bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
+		bcm43xx_phy_write(bcm, 0x0021, 0x3763);
+		bcm43xx_phy_write(bcm, 0x0022, 0x1BC3);
+		bcm43xx_phy_write(bcm, 0x0023, 0x06F9);
+		bcm43xx_phy_write(bcm, 0x0024, 0x037E);
+	} else
+		bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
+	bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
+	bcm43xx_write16(bcm, 0x03EC, 0x3F22);
+
+	if (phy->version == 1 && radio->version == 0x2050)
+		bcm43xx_phy_write(bcm, 0x0020, 0x3E1C);
+	else
+		bcm43xx_phy_write(bcm, 0x0020, 0x301C);
+
+	if (phy->version == 0)
+		bcm43xx_write16(bcm, 0x03E4, 0x3000);
+
+	/* Force to channel 7, even if not supported. */
+	bcm43xx_radio_selectchannel(bcm, 7, 0);
+
+	if (radio->version != 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
+	}
+
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+	}
+
+	bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+	bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+
+	bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007);
+
+	bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+
+	bcm43xx_phy_write(bcm, 0x0014, 0x0080);
+	bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
+	bcm43xx_phy_write(bcm, 0x88A3, 0x002A);
+
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+
+	if (radio->version == 0x2050)
+		bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
+
+	bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004);
+}
+
+static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 offset, val;
+
+	bcm43xx_phy_write(bcm, 0x003E, 0x817A);
+	bcm43xx_radio_write16(bcm, 0x007A,
+	                      (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058));
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 3 ||
+	     radio->revision == 4 ||
+	     radio->revision == 5)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x001F);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x005B);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
+	}
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 6)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x008B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B5);
+		bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
+		bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
+	}
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 7)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x00A8);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x0075);
+		bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
+		bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x00E8);
+		bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
+		bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
+		bcm43xx_radio_write16(bcm, 0x007B, 0x0000);
+	}
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2050) &&
+	    (radio->revision == 8)) {
+		bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
+		bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
+		bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x006B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x000F);
+		if (bcm->sprom.boardflags & 0x8000) {
+			bcm43xx_radio_write16(bcm, 0x005D, 0x00FA);
+			bcm43xx_radio_write16(bcm, 0x005E, 0x00D8);
+		} else {
+			bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
+			bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
+		}
+		bcm43xx_radio_write16(bcm, 0x0073, 0x0003);
+		bcm43xx_radio_write16(bcm, 0x007D, 0x00A8);
+		bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
+		bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
+	}
+	val = 0x1E1F;
+	for (offset = 0x0088; offset < 0x0098; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x3E3F;
+	for (offset = 0x0098; offset < 0x00A8; offset++) {
+		bcm43xx_phy_write(bcm, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x2120;
+	for (offset = 0x00A8; offset < 0x00C8; offset++) {
+		bcm43xx_phy_write(bcm, offset, (val & 0x3F3F));
+		val += 0x0202;
+	}
+	if (phy->type == BCM43xx_PHYTYPE_G) {
+		bcm43xx_radio_write16(bcm, 0x007A,
+		                      bcm43xx_radio_read16(bcm, 0x007A) | 0x0020);
+		bcm43xx_radio_write16(bcm, 0x0051,
+		                      bcm43xx_radio_read16(bcm, 0x0051) | 0x0004);
+		bcm43xx_phy_write(bcm, 0x0802,
+		                  bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
+		bcm43xx_phy_write(bcm, 0x042B,
+		                  bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
+	}
+
+	/* Force to channel 7, even if not supported. */
+	bcm43xx_radio_selectchannel(bcm, 7, 0);
+
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
+	udelay(40);
+	bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002));
+	bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+	if (radio->manufact == 0x17F &&
+	    radio->version == 0x2050 &&
+	    radio->revision <= 2) {
+		bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
+		bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
+		bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
+	}
+	bcm43xx_radio_write16(bcm, 0x007A,
+	                      (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007);
+
+	bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+
+	bcm43xx_phy_write(bcm, 0x0014, 0x0200);
+	if (radio->version == 0x2050){
+		if (radio->revision == 3 ||
+		    radio->revision == 4 ||
+		    radio->revision == 5)
+			bcm43xx_phy_write(bcm, 0x002A, 0x8AC0);
+		else
+			bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
+	}
+	bcm43xx_phy_write(bcm, 0x0038, 0x0668);
+	bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
+	if (radio->version == 0x2050) {
+		if (radio->revision == 3 ||
+		    radio->revision == 4 ||
+		    radio->revision == 5)
+			bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003);
+		else if (radio->revision <= 2)
+			bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
+	}
+	
+	if (phy->rev == 4)
+		bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004);
+	else
+		bcm43xx_write16(bcm, 0x03E4, 0x0009);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		bcm43xx_write16(bcm, 0x03E6, 0x8140);
+		bcm43xx_phy_write(bcm, 0x0016, 0x0410);
+		bcm43xx_phy_write(bcm, 0x0017, 0x0820);
+		bcm43xx_phy_write(bcm, 0x0062, 0x0007);
+		(void) bcm43xx_radio_calibrationvalue(bcm);
+		bcm43xx_phy_lo_b_measure(bcm);
+		if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+			bcm43xx_calc_nrssi_slope(bcm);
+			bcm43xx_calc_nrssi_threshold(bcm);
+		}
+		bcm43xx_phy_init_pctl(bcm);
+	} else
+		bcm43xx_write16(bcm, 0x03E6, 0x0);
+}
+
+static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 backup_phy[15];
+	u16 backup_radio[3];
+	u16 backup_bband;
+	u16 i;
+	u16 loop1_cnt, loop1_done, loop1_omitted;
+	u16 loop2_done;
+
+	backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429);
+	backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001);
+	backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811);
+	backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812);
+	backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814);
+	backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815);
+	backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A);
+	backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059);
+	backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058);
+	backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A);
+	backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003);
+	backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F);
+	backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810);
+	backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B);
+	backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015);
+	bcm43xx_phy_read(bcm, 0x002D); /* dummy read */
+	backup_bband = radio->baseband_atten;
+	backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052);
+	backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043);
+	backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A);
+
+	bcm43xx_phy_write(bcm, 0x0429,
+			  bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF);
+	bcm43xx_phy_write(bcm, 0x0001,
+			  bcm43xx_phy_read(bcm, 0x0001) & 0x8000);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x0002);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x0001);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE);
+	bcm43xx_phy_write(bcm, 0x0814,
+			  bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
+	bcm43xx_phy_write(bcm, 0x0815,
+			  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
+	bcm43xx_phy_write(bcm, 0x0814,
+			  bcm43xx_phy_read(bcm, 0x0814) | 0x0002);
+	bcm43xx_phy_write(bcm, 0x0815,
+			  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
+
+	bcm43xx_phy_write(bcm, 0x0811,
+			  (bcm43xx_phy_read(bcm, 0x0811)
+			   & 0xFFCF) | 0x0030);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  (bcm43xx_phy_read(bcm, 0x0812)
+			   & 0xFFCF) | 0x0010);
+
+	bcm43xx_phy_write(bcm, 0x005A, 0x0780);
+	bcm43xx_phy_write(bcm, 0x0059, 0xC810);
+	bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+	if (phy->version == 0) {
+		bcm43xx_phy_write(bcm, 0x0003, 0x0122);
+	} else {
+		bcm43xx_phy_write(bcm, 0x000A,
+				  bcm43xx_phy_read(bcm, 0x000A)
+				  | 0x2000);
+	}
+	bcm43xx_phy_write(bcm, 0x0814,
+			  bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
+	bcm43xx_phy_write(bcm, 0x0815,
+			  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
+	bcm43xx_phy_write(bcm, 0x0003,
+			  (bcm43xx_phy_read(bcm, 0x0003)
+			   & 0xFF9F) | 0x0040);
+	if (radio->version == 0x2050 && radio->revision == 2) {
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0043,
+				      (bcm43xx_radio_read16(bcm, 0x0043)
+				       & 0xFFF0) | 0x0009);
+		loop1_cnt = 9;
+	} else if (radio->revision == 8) {
+		bcm43xx_radio_write16(bcm, 0x0043, 0x000F);
+		loop1_cnt = 15;
+	} else
+		loop1_cnt = 0;
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, 11);
+
+	if (phy->rev >= 3)
+		bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+	else
+		bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+	bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+
+	bcm43xx_phy_write(bcm, 0x002B,
+			  (bcm43xx_phy_read(bcm, 0x002B)
+			   & 0xFFC0) | 0x0001);
+	bcm43xx_phy_write(bcm, 0x002B,
+			  (bcm43xx_phy_read(bcm, 0x002B)
+			   & 0xC0FF) | 0x0800);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x0100);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF);
+	if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) {
+		if (phy->rev >= 7) {
+			bcm43xx_phy_write(bcm, 0x0811,
+					  bcm43xx_phy_read(bcm, 0x0811)
+					  | 0x0800);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_phy_read(bcm, 0x0812)
+					  | 0x8000);
+		}
+	}
+	bcm43xx_radio_write16(bcm, 0x007A,
+			      bcm43xx_radio_read16(bcm, 0x007A)
+			      & 0x00F7);
+
+	for (i = 0; i < loop1_cnt; i++) {
+		bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt);
+		bcm43xx_phy_write(bcm, 0x0812,
+				  (bcm43xx_phy_read(bcm, 0x0812)
+				   & 0xF0FF) | (i << 8));
+		bcm43xx_phy_write(bcm, 0x0015,
+				  (bcm43xx_phy_read(bcm, 0x0015)
+				   & 0x0FFF) | 0xA000);
+		bcm43xx_phy_write(bcm, 0x0015,
+				  (bcm43xx_phy_read(bcm, 0x0015)
+				   & 0x0FFF) | 0xF000);
+		udelay(20);
+		if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC)
+			break;
+	}
+	loop1_done = i;
+	loop1_omitted = loop1_cnt - loop1_done;
+
+	loop2_done = 0;
+	if (loop1_done >= 8) {
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_phy_read(bcm, 0x0812)
+				  | 0x0030);
+		for (i = loop1_done - 8; i < 16; i++) {
+			bcm43xx_phy_write(bcm, 0x0812,
+					  (bcm43xx_phy_read(bcm, 0x0812)
+					   & 0xF0FF) | (i << 8));
+			bcm43xx_phy_write(bcm, 0x0015,
+					  (bcm43xx_phy_read(bcm, 0x0015)
+					   & 0x0FFF) | 0xA000);
+			bcm43xx_phy_write(bcm, 0x0015,
+					  (bcm43xx_phy_read(bcm, 0x0015)
+					   & 0x0FFF) | 0xF000);
+			udelay(20);
+			if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC)
+				break;
+		}
+	}
+
+	bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]);
+	bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]);
+	bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]);
+	bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]);
+	bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]);
+	bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]);
+	bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]);
+	bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]);
+	bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]);
+	bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]);
+	bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]);
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband);
+
+	bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]);
+	bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]);
+	bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]);
+
+	bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003);
+	udelay(10);
+	bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]);
+	bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]);
+	bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]);
+	bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]);
+
+	phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
+	phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
+}
+
+static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tmp;
+
+	if (phy->rev == 1)
+		bcm43xx_phy_initb5(bcm);
+	else if (phy->rev >= 2 && phy->rev <= 7)
+		bcm43xx_phy_initb6(bcm);
+	if (phy->rev >= 2 || phy->connected)
+		bcm43xx_phy_inita(bcm);
+
+	if (phy->rev >= 2) {
+		bcm43xx_phy_write(bcm, 0x0814, 0x0000);
+		bcm43xx_phy_write(bcm, 0x0815, 0x0000);
+		if (phy->rev == 2)
+			bcm43xx_phy_write(bcm, 0x0811, 0x0000);
+		else if (phy->rev >= 3)
+			bcm43xx_phy_write(bcm, 0x0811, 0x0400);
+		bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
+		if (phy->connected) {
+			tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF;
+			if (tmp < 6) {
+				bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
+				bcm43xx_phy_write(bcm, 0x04C3, 0x8006);
+				if (tmp != 3) {
+					bcm43xx_phy_write(bcm, 0x04CC,
+							  (bcm43xx_phy_read(bcm, 0x04CC)
+							   & 0x00FF) | 0x1F00);
+				}
+			}
+		}
+	}
+	if (phy->rev < 3 && phy->connected)
+		bcm43xx_phy_write(bcm, 0x047E, 0x0078);
+	if (phy->rev >= 6 && phy->rev <= 8) {
+		bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080);
+		bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004);
+	}
+	if (phy->rev >= 2 && phy->connected)
+		bcm43xx_calc_loopback_gain(bcm);
+	if (radio->revision != 8) {
+		if (radio->initval == 0xFFFF)
+			radio->initval = bcm43xx_radio_init2050(bcm);
+		else
+			bcm43xx_radio_write16(bcm, 0x0078, radio->initval);
+	}
+	if (radio->txctl2 == 0xFFFF) {
+		bcm43xx_phy_lo_g_measure(bcm);
+	} else {
+		if (radio->version == 0x2050 && radio->revision == 8) {
+			//FIXME
+		} else {
+			bcm43xx_radio_write16(bcm, 0x0052,
+					      (bcm43xx_radio_read16(bcm, 0x0052)
+					       & 0xFFF0) | radio->txctl1);
+		}
+		if (phy->rev >= 6) {
+			/*
+			bcm43xx_phy_write(bcm, 0x0036,
+					  (bcm43xx_phy_read(bcm, 0x0036)
+					   & 0xF000) | (FIXME << 12));
+			*/
+		}
+		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+			bcm43xx_phy_write(bcm, 0x002E, 0x8075);
+		else
+			bcm43xx_phy_write(bcm, 0x003E, 0x807F);
+		if (phy->rev < 2)
+			bcm43xx_phy_write(bcm, 0x002F, 0x0101);
+		else
+			bcm43xx_phy_write(bcm, 0x002F, 0x0202);
+	}
+	if (phy->connected) {
+		bcm43xx_phy_lo_adjust(bcm, 0);
+		bcm43xx_phy_write(bcm, 0x080F, 0x8078);
+	}
+
+	if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
+		/* The specs state to update the NRSSI LT with
+		 * the value 0x7FFFFFFF here. I think that is some weird
+		 * compiler optimization in the original driver.
+		 * Essentially, what we do here is resetting all NRSSI LT
+		 * entries to -32 (see the limit_value() in nrssi_hw_update())
+		 */
+		bcm43xx_nrssi_hw_update(bcm, 0xFFFF);
+		bcm43xx_calc_nrssi_threshold(bcm);
+	} else if (phy->connected) {
+		if (radio->nrssi[0] == -1000) {
+			assert(radio->nrssi[1] == -1000);
+			bcm43xx_calc_nrssi_slope(bcm);
+		} else {
+			assert(radio->nrssi[1] != -1000);
+			bcm43xx_calc_nrssi_threshold(bcm);
+		}
+	}
+	if (radio->revision == 8)
+		bcm43xx_phy_write(bcm, 0x0805, 0x3230);
+	bcm43xx_phy_init_pctl(bcm);
+	if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) {
+		bcm43xx_phy_write(bcm, 0x0429,
+				  bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF);
+		bcm43xx_phy_write(bcm, 0x04C3,
+				  bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF);
+	}
+}
+
+static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
+{
+	int i;
+	u16 ret = 0;
+
+	for (i = 0; i < 10; i++){
+		bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
+		udelay(1);
+		bcm43xx_phy_write(bcm, 0x0015, 0xEFA0);
+		udelay(10);
+		bcm43xx_phy_write(bcm, 0x0015, 0xFFA0);
+		udelay(40);
+		ret += bcm43xx_phy_read(bcm, 0x002C);
+	}
+
+	return ret;
+}
+
+void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 regstack[12] = { 0 };
+	u16 mls;
+	u16 fval;
+	int i, j;
+
+	regstack[0] = bcm43xx_phy_read(bcm, 0x0015);
+	regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0;
+
+	if (radio->version == 0x2053) {
+		regstack[2] = bcm43xx_phy_read(bcm, 0x000A);
+		regstack[3] = bcm43xx_phy_read(bcm, 0x002A);
+		regstack[4] = bcm43xx_phy_read(bcm, 0x0035);
+		regstack[5] = bcm43xx_phy_read(bcm, 0x0003);
+		regstack[6] = bcm43xx_phy_read(bcm, 0x0001);
+		regstack[7] = bcm43xx_phy_read(bcm, 0x0030);
+
+		regstack[8] = bcm43xx_radio_read16(bcm, 0x0043);
+		regstack[9] = bcm43xx_radio_read16(bcm, 0x007A);
+		regstack[10] = bcm43xx_read16(bcm, 0x03EC);
+		regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0;
+
+		bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
+		bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
+		bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F);
+		bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0);
+	}
+	bcm43xx_phy_write(bcm, 0x0015, 0xB000);
+	bcm43xx_phy_write(bcm, 0x002B, 0x0004);
+
+	if (radio->version == 0x2053) {
+		bcm43xx_phy_write(bcm, 0x002B, 0x0203);
+		bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
+	}
+
+	phy->minlowsig[0] = 0xFFFF;
+
+	for (i = 0; i < 4; i++) {
+		bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
+		bcm43xx_phy_lo_b_r15_loop(bcm);
+	}
+	for (i = 0; i < 10; i++) {
+		bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
+		mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
+		if (mls < phy->minlowsig[0]) {
+			phy->minlowsig[0] = mls;
+			phy->minlowsigpos[0] = i;
+		}
+	}
+	bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]);
+
+	phy->minlowsig[1] = 0xFFFF;
+
+	for (i = -4; i < 5; i += 2) {
+		for (j = -4; j < 5; j += 2) {
+			if (j < 0)
+				fval = (0x0100 * i) + j + 0x0100;
+			else
+				fval = (0x0100 * i) + j;
+			bcm43xx_phy_write(bcm, 0x002F, fval);
+			mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
+			if (mls < phy->minlowsig[1]) {
+				phy->minlowsig[1] = mls;
+				phy->minlowsigpos[1] = fval;
+			}
+		}
+	}
+	phy->minlowsigpos[1] += 0x0101;
+
+	bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]);
+	if (radio->version == 0x2053) {
+		bcm43xx_phy_write(bcm, 0x000A, regstack[2]);
+		bcm43xx_phy_write(bcm, 0x002A, regstack[3]);
+		bcm43xx_phy_write(bcm, 0x0035, regstack[4]);
+		bcm43xx_phy_write(bcm, 0x0003, regstack[5]);
+		bcm43xx_phy_write(bcm, 0x0001, regstack[6]);
+		bcm43xx_phy_write(bcm, 0x0030, regstack[7]);
+
+		bcm43xx_radio_write16(bcm, 0x0043, regstack[8]);
+		bcm43xx_radio_write16(bcm, 0x007A, regstack[9]);
+
+		bcm43xx_radio_write16(bcm, 0x0052,
+		                      (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F)
+				      | regstack[11]);
+
+		bcm43xx_write16(bcm, 0x03EC, regstack[10]);
+	}
+	bcm43xx_phy_write(bcm, 0x0015, regstack[0]);
+}
+
+static inline
+u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x15, 0xE300);
+		control <<= 8;
+		bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0);
+		udelay(5);
+		bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2);
+		udelay(2);
+		bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3);
+		udelay(4);
+		bcm43xx_phy_write(bcm, 0x0015, 0xF300);
+		udelay(8);
+	} else {
+		bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0);
+		udelay(2);
+		bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0);
+		udelay(4);
+		bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
+		udelay(8);
+	}
+
+	return bcm43xx_phy_read(bcm, 0x002D);
+}
+
+static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
+{
+	int i;
+	u32 ret = 0;
+
+	for (i = 0; i < 8; i++)
+		ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control);
+
+	return ret;
+}
+
+/* Write the LocalOscillator CONTROL */
+static inline
+void bcm43xx_lo_write(struct bcm43xx_private *bcm,
+		      struct bcm43xx_lopair *pair)
+{
+	u16 value;
+
+	value = (u8)(pair->low);
+	value |= ((u8)(pair->high)) << 8;
+
+#ifdef CONFIG_BCM43XX_DEBUG
+	/* Sanity check. */
+	if (pair->low < -8 || pair->low > 8 ||
+	    pair->high < -8 || pair->high > 8) {
+		printk(KERN_WARNING PFX
+		       "WARNING: Writing invalid LOpair "
+		       "(low: %d, high: %d, index: %lu)\n",
+		       pair->low, pair->high,
+		       (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs));
+		dump_stack();
+	}
+#endif
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value);
+}
+
+static inline
+struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm,
+					    u16 baseband_attenuation,
+					    u16 radio_attenuation,
+					    u16 tx)
+{
+	static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (baseband_attenuation > 6)
+		baseband_attenuation = 6;
+	assert(radio_attenuation < 10);
+
+	if (tx == 3) {
+		return bcm43xx_get_lopair(phy,
+					  radio_attenuation,
+					  baseband_attenuation);
+	}
+	return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation);
+}
+
+static inline
+struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	return bcm43xx_find_lopair(bcm,
+				   radio->baseband_atten,
+				   radio->radio_atten,
+				   radio->txctl1);
+}
+
+/* Adjust B/G LO */
+void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed)
+{
+	struct bcm43xx_lopair *pair;
+
+	if (fixed) {
+		/* Use fixed values. Only for initialization. */
+		pair = bcm43xx_find_lopair(bcm, 2, 3, 0);
+	} else
+		pair = bcm43xx_current_lopair(bcm);
+	bcm43xx_lo_write(bcm, pair);
+}
+
+static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 txctl2 = 0, i;
+	u32 smallest, tmp;
+
+	bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+	udelay(10);
+	smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
+	for (i = 0; i < 16; i++) {
+		bcm43xx_radio_write16(bcm, 0x0052, i);
+		udelay(10);
+		tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
+		if (tmp < smallest) {
+			smallest = tmp;
+			txctl2 = i;
+		}
+	}
+	radio->txctl2 = txctl2;
+}
+
+static
+void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm,
+			    const struct bcm43xx_lopair *in_pair,
+			    struct bcm43xx_lopair *out_pair,
+			    u16 r27)
+{
+	static const struct bcm43xx_lopair transitions[8] = {
+		{ .high =  1,  .low =  1, },
+		{ .high =  1,  .low =  0, },
+		{ .high =  1,  .low = -1, },
+		{ .high =  0,  .low = -1, },
+		{ .high = -1,  .low = -1, },
+		{ .high = -1,  .low =  0, },
+		{ .high = -1,  .low =  1, },
+		{ .high =  0,  .low =  1, },
+	};
+	struct bcm43xx_lopair lowest_transition = {
+		.high = in_pair->high,
+		.low = in_pair->low,
+	};
+	struct bcm43xx_lopair tmp_pair;
+	struct bcm43xx_lopair transition;
+	int i = 12;
+	int state = 0;
+	int found_lower;
+	int j, begin, end;
+	u32 lowest_deviation;
+	u32 tmp;
+
+	/* Note that in_pair and out_pair can point to the same pair. Be careful. */
+
+	bcm43xx_lo_write(bcm, &lowest_transition);
+	lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
+	do {
+		found_lower = 0;
+		assert(state >= 0 && state <= 8);
+		if (state == 0) {
+			begin = 1;
+			end = 8;
+		} else if (state % 2 == 0) {
+			begin = state - 1;
+			end = state + 1;
+		} else {
+			begin = state - 2;
+			end = state + 2;
+		}
+		if (begin < 1)
+			begin += 8;
+		if (end > 8)
+			end -= 8;
+
+		j = begin;
+		tmp_pair.high = lowest_transition.high;
+		tmp_pair.low = lowest_transition.low;
+		while (1) {
+			assert(j >= 1 && j <= 8);
+			transition.high = tmp_pair.high + transitions[j - 1].high;
+			transition.low = tmp_pair.low + transitions[j - 1].low;
+			if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) {
+				bcm43xx_lo_write(bcm, &transition);
+				tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
+				if (tmp < lowest_deviation) {
+					lowest_deviation = tmp;
+					state = j;
+					found_lower = 1;
+
+					lowest_transition.high = transition.high;
+					lowest_transition.low = transition.low;
+				}
+			}
+			if (j == end)
+				break;
+			if (j == 8)
+				j = 1;
+			else
+				j++;
+		}
+	} while (i-- && found_lower);
+
+	out_pair->high = lowest_transition.high;
+	out_pair->low = lowest_transition.low;
+}
+
+/* Set the baseband attenuation value on chip. */
+void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
+					  u16 baseband_attenuation)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 value;
+
+	if (phy->version == 0) {
+		value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0);
+		value |= (baseband_attenuation & 0x000F);
+		bcm43xx_write16(bcm, 0x03E6, value);
+		return;
+	}
+
+	if (phy->version > 1) {
+		value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
+		value |= (baseband_attenuation << 2) & 0x003C;
+	} else {
+		value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078;
+		value |= (baseband_attenuation << 3) & 0x0078;
+	}
+	bcm43xx_phy_write(bcm, 0x0060, value);
+}
+
+/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
+void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
+{
+	static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
+	const int is_initializing = bcm43xx_is_initializing(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 h, i, oldi = 0, j;
+	struct bcm43xx_lopair control;
+	struct bcm43xx_lopair *tmp_control;
+	u16 tmp;
+	u16 regstack[16] = { 0 };
+	u8 oldchannel;
+
+	//XXX: What are these?
+	u8 r27 = 0, r31;
+
+	oldchannel = radio->channel;
+	/* Setup */
+	if (phy->connected) {
+		regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
+		regstack[1] = bcm43xx_phy_read(bcm, 0x0802);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
+		bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
+	}
+	regstack[3] = bcm43xx_read16(bcm, 0x03E2);
+	bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000);
+	regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+	regstack[5] = bcm43xx_phy_read(bcm, 0x15);
+	regstack[6] = bcm43xx_phy_read(bcm, 0x2A);
+	regstack[7] = bcm43xx_phy_read(bcm, 0x35);
+	regstack[8] = bcm43xx_phy_read(bcm, 0x60);
+	regstack[9] = bcm43xx_radio_read16(bcm, 0x43);
+	regstack[10] = bcm43xx_radio_read16(bcm, 0x7A);
+	regstack[11] = bcm43xx_radio_read16(bcm, 0x52);
+	if (phy->connected) {
+		regstack[12] = bcm43xx_phy_read(bcm, 0x0811);
+		regstack[13] = bcm43xx_phy_read(bcm, 0x0812);
+		regstack[14] = bcm43xx_phy_read(bcm, 0x0814);
+		regstack[15] = bcm43xx_phy_read(bcm, 0x0815);
+	}
+	bcm43xx_radio_selectchannel(bcm, 6, 0);
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
+		bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
+		bcm43xx_dummy_transmission(bcm);
+	}
+	bcm43xx_radio_write16(bcm, 0x0043, 0x0006);
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, 2);
+
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000);
+	bcm43xx_phy_write(bcm, 0x002E, 0x007F);
+	bcm43xx_phy_write(bcm, 0x080F, 0x0078);
+	bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7));
+	bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0);
+	bcm43xx_phy_write(bcm, 0x002B, 0x0203);
+	bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003);
+		bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC);
+		bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+		bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+	}
+	if (is_initializing)
+		bcm43xx_phy_lo_g_measure_txctl2(bcm);
+	bcm43xx_phy_write(bcm, 0x080F, 0x8078);
+
+	/* Measure */
+	control.low = 0;
+	control.high = 0;
+	for (h = 0; h < 10; h++) {
+		/* Loop over each possible RadioAttenuation (0-9) */
+		i = pairorder[h];
+		if (is_initializing) {
+			if (i == 3) {
+				control.low = 0;
+				control.high = 0;
+			} else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
+				  ((i % 2 == 0) && (oldi % 2 == 0))) {
+				tmp_control = bcm43xx_get_lopair(phy, oldi, 0);
+				memcpy(&control, tmp_control, sizeof(control));
+			} else {
+				tmp_control = bcm43xx_get_lopair(phy, 3, 0);
+				memcpy(&control, tmp_control, sizeof(control));
+			}
+		}
+		/* Loop over each possible BasebandAttenuation/2 */
+		for (j = 0; j < 4; j++) {
+			if (is_initializing) {
+				tmp = i * 2 + j;
+				r27 = 0;
+				r31 = 0;
+				if (tmp > 14) {
+					r31 = 1;
+					if (tmp > 17)
+						r27 = 1;
+					if (tmp > 19)
+						r27 = 2;
+				}
+			} else {
+				tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
+				if (!tmp_control->used)
+					continue;
+				memcpy(&control, tmp_control, sizeof(control));
+				r27 = 3;
+				r31 = 0;
+			}
+			bcm43xx_radio_write16(bcm, 0x43, i);
+			bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
+			udelay(10);
+
+			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
+
+			tmp = (regstack[10] & 0xFFF0);
+			if (r31)
+				tmp |= 0x0008;
+			bcm43xx_radio_write16(bcm, 0x007A, tmp);
+
+			tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
+			bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
+		}
+		oldi = i;
+	}
+	/* Loop over each possible RadioAttenuation (10-13) */
+	for (i = 10; i < 14; i++) {
+		/* Loop over each possible BasebandAttenuation/2 */
+		for (j = 0; j < 4; j++) {
+			if (is_initializing) {
+				tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
+				memcpy(&control, tmp_control, sizeof(control));
+				tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger.
+				r27 = 0;
+				r31 = 0;
+				if (tmp > 14) {
+					r31 = 1;
+					if (tmp > 17)
+						r27 = 1;
+					if (tmp > 19)
+						r27 = 2;
+				}
+			} else {
+				tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
+				if (!tmp_control->used)
+					continue;
+				memcpy(&control, tmp_control, sizeof(control));
+				r27 = 3;
+				r31 = 0;
+			}
+			bcm43xx_radio_write16(bcm, 0x43, i - 9);
+			bcm43xx_radio_write16(bcm, 0x52,
+					      radio->txctl2
+					      | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
+			udelay(10);
+
+			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
+
+			tmp = (regstack[10] & 0xFFF0);
+			if (r31)
+				tmp |= 0x0008;
+			bcm43xx_radio_write16(bcm, 0x7A, tmp);
+
+			tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
+			bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
+		}
+	}
+
+	/* Restoration */
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x0015, 0xE300);
+		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0);
+		udelay(5);
+		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
+		udelay(2);
+		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
+	} else
+		bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
+	bcm43xx_phy_lo_adjust(bcm, is_initializing);
+	bcm43xx_phy_write(bcm, 0x002E, 0x807F);
+	if (phy->connected)
+		bcm43xx_phy_write(bcm, 0x002F, 0x0202);
+	else
+		bcm43xx_phy_write(bcm, 0x002F, 0x0101);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]);
+	bcm43xx_phy_write(bcm, 0x0015, regstack[5]);
+	bcm43xx_phy_write(bcm, 0x002A, regstack[6]);
+	bcm43xx_phy_write(bcm, 0x0035, regstack[7]);
+	bcm43xx_phy_write(bcm, 0x0060, regstack[8]);
+	bcm43xx_radio_write16(bcm, 0x0043, regstack[9]);
+	bcm43xx_radio_write16(bcm, 0x007A, regstack[10]);
+	regstack[11] &= 0x00F0;
+	regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F);
+	bcm43xx_radio_write16(bcm, 0x52, regstack[11]);
+	bcm43xx_write16(bcm, 0x03E2, regstack[3]);
+	if (phy->connected) {
+		bcm43xx_phy_write(bcm, 0x0811, regstack[12]);
+		bcm43xx_phy_write(bcm, 0x0812, regstack[13]);
+		bcm43xx_phy_write(bcm, 0x0814, regstack[14]);
+		bcm43xx_phy_write(bcm, 0x0815, regstack[15]);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]);
+		bcm43xx_phy_write(bcm, 0x0802, regstack[1]);
+	}
+	bcm43xx_radio_selectchannel(bcm, oldchannel, 1);
+
+#ifdef CONFIG_BCM43XX_DEBUG
+	{
+		/* Sanity check for all lopairs. */
+		for (i = 0; i < BCM43xx_LO_COUNT; i++) {
+			tmp_control = phy->_lo_pairs + i;
+			if (tmp_control->low < -8 || tmp_control->low > 8 ||
+			    tmp_control->high < -8 || tmp_control->high > 8) {
+				printk(KERN_WARNING PFX
+				       "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n",
+				       tmp_control->low, tmp_control->high, i);
+			}
+		}
+	}
+#endif /* CONFIG_BCM43XX_DEBUG */
+}
+
+static
+void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_lopair *pair;
+
+	pair = bcm43xx_current_lopair(bcm);
+	pair->used = 1;
+}
+
+void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_lopair *pair;
+	int i;
+
+	for (i = 0; i < BCM43xx_LO_COUNT; i++) {
+		pair = phy->_lo_pairs + i;
+		pair->used = 0;
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	s8 dbm = 0;
+	s32 tmp;
+
+	tmp = phy->idle_tssi;
+	tmp += tssi;
+	tmp -= phy->savedpctlreg;
+
+	switch (phy->type) {
+		case BCM43xx_PHYTYPE_A:
+			tmp += 0x80;
+			tmp = limit_value(tmp, 0x00, 0xFF);
+			dbm = phy->tssi2dbm[tmp];
+			TODO(); //TODO: There's a FIXME on the specs
+			break;
+		case BCM43xx_PHYTYPE_B:
+		case BCM43xx_PHYTYPE_G:
+			tmp = limit_value(tmp, 0x00, 0x3F);
+			dbm = phy->tssi2dbm[tmp];
+			break;
+		default:
+			assert(0);
+	}
+
+	return dbm;
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	
+	if (phy->savedpctlreg == 0xFFFF)
+		return;
+	if ((bcm->board_type == 0x0416) &&
+	    (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM))
+		return;
+	
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A: {
+
+		TODO(); //TODO: Nothing for A PHYs yet :-/
+
+		break;
+	}
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G: {
+		u16 tmp;
+		u16 txpower;
+		s8 v0, v1, v2, v3;
+		s8 average;
+		u8 max_pwr;
+		s16 desired_pwr, estimated_pwr, pwr_adjust;
+		s16 radio_att_delta, baseband_att_delta;
+		s16 radio_attenuation, baseband_attenuation;
+		unsigned long phylock_flags;
+
+		tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058);
+		v0 = (s8)(tmp & 0x00FF);
+		v1 = (s8)((tmp & 0xFF00) >> 8);
+		tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A);
+		v2 = (s8)(tmp & 0x00FF);
+		v3 = (s8)((tmp & 0xFF00) >> 8);
+		tmp = 0;
+
+		if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
+			tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070);
+			v0 = (s8)(tmp & 0x00FF);
+			v1 = (s8)((tmp & 0xFF00) >> 8);
+			tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072);
+			v2 = (s8)(tmp & 0x00FF);
+			v3 = (s8)((tmp & 0xFF00) >> 8);
+			if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
+				return;
+			v0 = (v0 + 0x20) & 0x3F;
+			v1 = (v1 + 0x20) & 0x3F;
+			v2 = (v2 + 0x20) & 0x3F;
+			v3 = (v3 + 0x20) & 0x3F;
+			tmp = 1;
+		}
+		bcm43xx_radio_clear_tssi(bcm);
+
+		average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+		if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8))
+			average -= 13;
+
+		estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average);
+
+		max_pwr = bcm->sprom.maxpower_bgphy;
+
+		if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) &&
+		    (phy->type == BCM43xx_PHYTYPE_G))
+			max_pwr -= 0x3;
+
+		/*TODO:
+		max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr)
+			where REG is the max power as per the regulatory domain
+		*/
+
+		desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr);
+		/* Check if we need to adjust the current power. */
+		pwr_adjust = desired_pwr - estimated_pwr;
+		radio_att_delta = -(pwr_adjust + 7) >> 3;
+		baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
+		if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
+			bcm43xx_phy_lo_mark_current_used(bcm);
+			return;
+		}
+
+		/* Calculate the new attenuation values. */
+		baseband_attenuation = radio->baseband_atten;
+		baseband_attenuation += baseband_att_delta;
+		radio_attenuation = radio->radio_atten;
+		radio_attenuation += radio_att_delta;
+
+		/* Get baseband and radio attenuation values into their permitted ranges.
+		 * baseband 0-11, radio 0-9.
+		 * Radio attenuation affects power level 4 times as much as baseband.
+		 */
+		if (radio_attenuation < 0) {
+			baseband_attenuation -= (4 * -radio_attenuation);
+			radio_attenuation = 0;
+		} else if (radio_attenuation > 9) {
+			baseband_attenuation += (4 * (radio_attenuation - 9));
+			radio_attenuation = 9;
+		} else {
+			while (baseband_attenuation < 0 && radio_attenuation > 0) {
+				baseband_attenuation += 4;
+				radio_attenuation--;
+			}
+			while (baseband_attenuation > 11 && radio_attenuation < 9) {
+				baseband_attenuation -= 4;
+				radio_attenuation++;
+			}
+		}
+		baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+
+		txpower = radio->txctl1;
+		if ((radio->version == 0x2050) && (radio->revision == 2)) {
+			if (radio_attenuation <= 1) {
+				if (txpower == 0) {
+					txpower = 3;
+					radio_attenuation += 2;
+					baseband_attenuation += 2;
+				} else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
+					baseband_attenuation += 4 * (radio_attenuation - 2);
+					radio_attenuation = 2;
+				}
+			} else if (radio_attenuation > 4 && txpower != 0) {
+				txpower = 0;
+				if (baseband_attenuation < 3) {
+					radio_attenuation -= 3;
+					baseband_attenuation += 2;
+				} else {
+					radio_attenuation -= 2;
+					baseband_attenuation -= 2;
+				}
+			}
+		}
+		radio->txctl1 = txpower;
+		baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+		radio_attenuation = limit_value(radio_attenuation, 0, 9);
+
+		bcm43xx_phy_lock(bcm, phylock_flags);
+		bcm43xx_radio_lock(bcm);
+		bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation,
+					     radio_attenuation, txpower);
+		bcm43xx_phy_lo_mark_current_used(bcm);
+		bcm43xx_radio_unlock(bcm);
+		bcm43xx_phy_unlock(bcm, phylock_flags);
+		break;
+	}
+	default:
+		assert(0);
+	}
+}
+
+static inline
+s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den)
+{
+	if (num < 0)
+		return num/den;
+	else
+		return (num+den/2)/den;
+}
+
+static inline
+s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+	s32 m1, m2, f = 256, q, delta;
+	s8 i = 0;
+	
+	m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+	m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+	do {
+		if (i > 15)
+			return -EINVAL;
+		q = bcm43xx_tssi2dbm_ad(f * 4096 -
+					bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048);
+		delta = abs(q - f);
+		f = q;
+		i++;
+	} while (delta >= 2);
+	entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	s16 pab0, pab1, pab2;
+	u8 idx;
+	s8 *dyn_tssi2dbm;
+	
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		pab0 = (s16)(bcm->sprom.pa1b0);
+		pab1 = (s16)(bcm->sprom.pa1b1);
+		pab2 = (s16)(bcm->sprom.pa1b2);
+	} else {
+		pab0 = (s16)(bcm->sprom.pa0b0);
+		pab1 = (s16)(bcm->sprom.pa0b1);
+		pab2 = (s16)(bcm->sprom.pa0b2);
+	}
+
+	if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) {
+		phy->idle_tssi = 0x34;
+		phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
+		return 0;
+	}
+
+	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
+		/* The pabX values are set in SPROM. Use them. */
+		if (phy->type == BCM43xx_PHYTYPE_A) {
+			if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 &&
+			    (s8)bcm->sprom.idle_tssi_tgt_aphy != -1)
+				phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy);
+			else
+				phy->idle_tssi = 62;
+		} else {
+			if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 &&
+			    (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1)
+				phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy);
+			else
+				phy->idle_tssi = 62;
+		}
+		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+		if (dyn_tssi2dbm == NULL) {
+			printk(KERN_ERR PFX "Could not allocate memory"
+					    "for tssi2dbm table\n");
+			return -ENOMEM;
+		}
+		for (idx = 0; idx < 64; idx++)
+			if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
+				phy->tssi2dbm = NULL;
+				printk(KERN_ERR PFX "Could not generate "
+						    "tssi2dBm table\n");
+				return -ENODEV;
+			}
+		phy->tssi2dbm = dyn_tssi2dbm;
+		phy->dyn_tssi_tbl = 1;
+	} else {
+		/* pabX values not set in SPROM. */
+		switch (phy->type) {
+		case BCM43xx_PHYTYPE_A:
+			/* APHY needs a generated table. */
+			phy->tssi2dbm = NULL;
+			printk(KERN_ERR PFX "Could not generate tssi2dBm "
+					    "table (wrong SPROM info)!\n");
+			return -ENODEV;
+		case BCM43xx_PHYTYPE_B:
+			phy->idle_tssi = 0x34;
+			phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
+			break;
+		case BCM43xx_PHYTYPE_G:
+			phy->idle_tssi = 0x34;
+			phy->tssi2dbm = bcm43xx_tssi2dbm_g_table;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int bcm43xx_phy_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	int err = -ENODEV;
+	unsigned long flags;
+
+	/* We do not want to be preempted while calibrating
+	 * the hardware.
+	 */
+	local_irq_save(flags);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		if (phy->rev == 2 || phy->rev == 3) {
+			bcm43xx_phy_inita(bcm);
+			err = 0;
+		}
+		break;
+	case BCM43xx_PHYTYPE_B:
+		switch (phy->rev) {
+		case 2:
+			bcm43xx_phy_initb2(bcm);
+			err = 0;
+			break;
+		case 4:
+			bcm43xx_phy_initb4(bcm);
+			err = 0;
+			break;
+		case 5:
+			bcm43xx_phy_initb5(bcm);
+			err = 0;
+			break;
+		case 6:
+			bcm43xx_phy_initb6(bcm);
+			err = 0;
+			break;
+		}
+		break;
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_phy_initg(bcm);
+		err = 0;
+		break;
+	}
+	local_irq_restore(flags);
+	if (err)
+		printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
+
+	return err;
+}
+
+void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 antennadiv;
+	u16 offset;
+	u16 value;
+	u32 ucodeflags;
+
+	antennadiv = phy->antenna_diversity;
+
+	if (antennadiv == 0xFFFF)
+		antennadiv = 3;
+	assert(antennadiv <= 3);
+
+	ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+					BCM43xx_UCODEFLAGS_OFFSET);
+	bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+			    BCM43xx_UCODEFLAGS_OFFSET,
+			    ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+	case BCM43xx_PHYTYPE_G:
+		if (phy->type == BCM43xx_PHYTYPE_A)
+			offset = 0x0000;
+		else
+			offset = 0x0400;
+
+		if (antennadiv == 2)
+			value = (3/*automatic*/ << 7);
+		else
+			value = (antennadiv << 7);
+		bcm43xx_phy_write(bcm, offset + 1,
+				  (bcm43xx_phy_read(bcm, offset + 1)
+				   & 0x7E7F) | value);
+
+		if (antennadiv >= 2) {
+			if (antennadiv == 2)
+				value = (antennadiv << 7);
+			else
+				value = (0/*force0*/ << 7);
+			bcm43xx_phy_write(bcm, offset + 0x2B,
+					  (bcm43xx_phy_read(bcm, offset + 0x2B)
+					   & 0xFEFF) | value);
+		}
+
+		if (phy->type == BCM43xx_PHYTYPE_G) {
+			if (antennadiv >= 2)
+				bcm43xx_phy_write(bcm, 0x048C,
+						  bcm43xx_phy_read(bcm, 0x048C)
+						   | 0x2000);
+			else
+				bcm43xx_phy_write(bcm, 0x048C,
+						  bcm43xx_phy_read(bcm, 0x048C)
+						   & ~0x2000);
+			if (phy->rev >= 2) {
+				bcm43xx_phy_write(bcm, 0x0461,
+						  bcm43xx_phy_read(bcm, 0x0461)
+						   | 0x0010);
+				bcm43xx_phy_write(bcm, 0x04AD,
+						  (bcm43xx_phy_read(bcm, 0x04AD)
+						   & 0x00FF) | 0x0015);
+				if (phy->rev == 2)
+					bcm43xx_phy_write(bcm, 0x0427, 0x0008);
+				else
+					bcm43xx_phy_write(bcm, 0x0427,
+						(bcm43xx_phy_read(bcm, 0x0427)
+						 & 0x00FF) | 0x0008);
+			}
+			else if (phy->rev >= 6)
+				bcm43xx_phy_write(bcm, 0x049B, 0x00DC);
+		} else {
+			if (phy->rev < 3)
+				bcm43xx_phy_write(bcm, 0x002B,
+						  (bcm43xx_phy_read(bcm, 0x002B)
+						   & 0x00FF) | 0x0024);
+			else {
+				bcm43xx_phy_write(bcm, 0x0061,
+						  bcm43xx_phy_read(bcm, 0x0061)
+						   | 0x0010);
+				if (phy->rev == 3) {
+					bcm43xx_phy_write(bcm, 0x0093, 0x001D);
+					bcm43xx_phy_write(bcm, 0x0027, 0x0008);
+				} else {
+					bcm43xx_phy_write(bcm, 0x0093, 0x003A);
+					bcm43xx_phy_write(bcm, 0x0027,
+						(bcm43xx_phy_read(bcm, 0x0027)
+						 & 0x00FF) | 0x0008);
+				}
+			}
+		}
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if (bcm->current_core->rev == 2)
+			value = (3/*automatic*/ << 7);
+		else
+			value = (antennadiv << 7);
+		bcm43xx_phy_write(bcm, 0x03E2,
+				  (bcm43xx_phy_read(bcm, 0x03E2)
+				   & 0xFE7F) | value);
+		break;
+	default:
+		assert(0);
+	}
+
+	if (antennadiv >= 2) {
+		ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+						BCM43xx_UCODEFLAGS_OFFSET);
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+				    BCM43xx_UCODEFLAGS_OFFSET,
+				    ucodeflags | BCM43xx_UCODEFLAG_AUTODIV);
+	}
+
+	phy->antenna_diversity = antennadiv;
+}

+ 74 - 0
drivers/net/wireless/bcm43xx/bcm43xx_phy.h

@@ -0,0 +1,74 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_PHY_H_
+#define BCM43xx_PHY_H_
+
+#include <linux/types.h>
+
+struct bcm43xx_private;
+
+void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm);
+#define bcm43xx_phy_lock(bcm, flags) \
+	do {					\
+		local_irq_save(flags);		\
+		bcm43xx_raw_phy_lock(bcm);	\
+	} while (0)
+void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
+#define bcm43xx_phy_unlock(bcm, flags) \
+	do {					\
+		bcm43xx_raw_phy_unlock(bcm);	\
+		local_irq_restore(flags);	\
+	} while (0)
+
+u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
+void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
+
+int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm);
+int bcm43xx_phy_init(struct bcm43xx_private *bcm);
+
+void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm);
+void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm);
+int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect);
+
+void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm);
+void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm);
+void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm);
+
+/* Adjust the LocalOscillator to the saved values.
+ * "fixed" is only set to 1 once in initialization. Set to 0 otherwise.
+ */
+void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed);
+void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm);
+
+void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
+					  u16 baseband_attenuation);
+
+#endif /* BCM43xx_PHY_H_ */

+ 606 - 0
drivers/net/wireless/bcm43xx/bcm43xx_pio.c

@@ -0,0 +1,606 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  PIO Transmission
+
+  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx.h"
+#include "bcm43xx_pio.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_xmit.h"
+
+#include <linux/delay.h>
+
+
+static void tx_start(struct bcm43xx_pioqueue *queue)
+{
+	bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+			  BCM43xx_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct bcm43xx_pioqueue *queue,
+		     u8 octet)
+{
+	if (queue->need_workarounds) {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+				  octet);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_WRITEHI);
+	} else {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_WRITEHI);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+				  octet);
+	}
+}
+
+static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr,
+			    const u8 *packet,
+			    unsigned int *pos)
+{
+	const u8 *source;
+	unsigned int i = *pos;
+	u16 ret;
+
+	if (i < sizeof(*txhdr)) {
+		source = (const u8 *)txhdr;
+	} else {
+		source = packet;
+		i -= sizeof(*txhdr);
+	}
+	ret = le16_to_cpu( *((u16 *)(source + i)) );
+	*pos += 2;
+
+	return ret;
+}
+
+static void tx_data(struct bcm43xx_pioqueue *queue,
+		    struct bcm43xx_txhdr *txhdr,
+		    const u8 *packet,
+		    unsigned int octets)
+{
+	u16 data;
+	unsigned int i = 0;
+
+	if (queue->need_workarounds) {
+		data = tx_get_next_word(txhdr, packet, &i);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
+	}
+	bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+			  BCM43xx_PIO_TXCTL_WRITELO |
+			  BCM43xx_PIO_TXCTL_WRITEHI);
+	while (i < octets - 1) {
+		data = tx_get_next_word(txhdr, packet, &i);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
+	}
+	if (octets % 2)
+		tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]);
+}
+
+static void tx_complete(struct bcm43xx_pioqueue *queue,
+			struct sk_buff *skb)
+{
+	if (queue->need_workarounds) {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+				  skb->data[skb->len - 1]);
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_WRITEHI |
+				  BCM43xx_PIO_TXCTL_COMPLETE);
+	} else {
+		bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+				  BCM43xx_PIO_TXCTL_COMPLETE);
+	}
+}
+
+static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
+			   int packetindex)
+{
+	u16 cookie = 0x0000;
+
+	/* We use the upper 4 bits for the PIO
+	 * controller ID and the lower 12 bits
+	 * for the packet index (in the cache).
+	 */
+	switch (queue->mmio_base) {
+	case BCM43xx_MMIO_PIO1_BASE:
+		break;
+	case BCM43xx_MMIO_PIO2_BASE:
+		cookie = 0x1000;
+		break;
+	case BCM43xx_MMIO_PIO3_BASE:
+		cookie = 0x2000;
+		break;
+	case BCM43xx_MMIO_PIO4_BASE:
+		cookie = 0x3000;
+		break;
+	default:
+		assert(0);
+	}
+	assert(((u16)packetindex & 0xF000) == 0x0000);
+	cookie |= (u16)packetindex;
+
+	return cookie;
+}
+
+static
+struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm,
+				       u16 cookie,
+				       struct bcm43xx_pio_txpacket **packet)
+{
+	struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);
+	struct bcm43xx_pioqueue *queue = NULL;
+	int packetindex;
+
+	switch (cookie & 0xF000) {
+	case 0x0000:
+		queue = pio->queue0;
+		break;
+	case 0x1000:
+		queue = pio->queue1;
+		break;
+	case 0x2000:
+		queue = pio->queue2;
+		break;
+	case 0x3000:
+		queue = pio->queue3;
+		break;
+	default:
+		assert(0);
+	}
+	packetindex = (cookie & 0x0FFF);
+	assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS);
+	*packet = &(queue->tx_packets_cache[packetindex]);
+
+	return queue;
+}
+
+static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
+				  struct sk_buff *skb,
+				  struct bcm43xx_pio_txpacket *packet)
+{
+	struct bcm43xx_txhdr txhdr;
+	unsigned int octets;
+
+	assert(skb_shinfo(skb)->nr_frags == 0);
+	bcm43xx_generate_txhdr(queue->bcm,
+			       &txhdr, skb->data, skb->len,
+			       (packet->xmitted_frags == 0),
+			       generate_cookie(queue, pio_txpacket_getindex(packet)));
+
+	tx_start(queue);
+	octets = skb->len + sizeof(txhdr);
+	if (queue->need_workarounds)
+		octets--;
+	tx_data(queue, &txhdr, (u8 *)skb->data, octets);
+	tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct bcm43xx_pio_txpacket *packet,
+			  int irq_context)
+{
+	struct bcm43xx_pioqueue *queue = packet->queue;
+
+	ieee80211_txb_free(packet->txb);
+	list_move(&packet->list, &queue->txfree);
+	queue->nr_txfree++;
+
+	assert(queue->tx_devq_used >= packet->xmitted_octets);
+	assert(queue->tx_devq_packets >= packet->xmitted_frags);
+	queue->tx_devq_used -= packet->xmitted_octets;
+	queue->tx_devq_packets -= packet->xmitted_frags;
+}
+
+static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
+{
+	struct bcm43xx_pioqueue *queue = packet->queue;
+	struct ieee80211_txb *txb = packet->txb;
+	struct sk_buff *skb;
+	u16 octets;
+	int i;
+
+	for (i = packet->xmitted_frags; i < txb->nr_frags; i++) {
+		skb = txb->fragments[i];
+
+		octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr);
+		assert(queue->tx_devq_size >= octets);
+		assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS);
+		assert(queue->tx_devq_used <= queue->tx_devq_size);
+		/* Check if there is sufficient free space on the device
+		 * TX queue. If not, return and let the TX tasklet
+		 * retry later.
+		 */
+		if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS)
+			return -EBUSY;
+		if (queue->tx_devq_used + octets > queue->tx_devq_size)
+			return -EBUSY;
+		/* Now poke the device. */
+		pio_tx_write_fragment(queue, skb, packet);
+
+		/* Account for the packet size.
+		 * (We must not overflow the device TX queue)
+		 */
+		queue->tx_devq_packets++;
+		queue->tx_devq_used += octets;
+
+		assert(packet->xmitted_frags <= packet->txb->nr_frags);
+		packet->xmitted_frags++;
+		packet->xmitted_octets += octets;
+	}
+	list_move_tail(&packet->list, &queue->txrunning);
+
+	return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+	struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d;
+	struct bcm43xx_private *bcm = queue->bcm;
+	unsigned long flags;
+	struct bcm43xx_pio_txpacket *packet, *tmp_packet;
+	int err;
+
+	bcm43xx_lock_mmio(bcm, flags);
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+		assert(packet->xmitted_frags < packet->txb->nr_frags);
+		if (packet->xmitted_frags == 0) {
+			int i;
+			struct sk_buff *skb;
+
+			/* Check if the device queue is big
+			 * enough for every fragment. If not, drop the
+			 * whole packet.
+			 */
+			for (i = 0; i < packet->txb->nr_frags; i++) {
+				skb = packet->txb->fragments[i];
+				if (unlikely(skb->len > queue->tx_devq_size)) {
+					dprintkl(KERN_ERR PFX "PIO TX device queue too small. "
+							      "Dropping packet.\n");
+					free_txpacket(packet, 1);
+					goto next_packet;
+				}
+			}
+		}
+		/* Try to transmit the packet.
+		 * This may not completely succeed.
+		 */
+		err = pio_tx_packet(packet);
+		if (err)
+			break;
+	next_packet:
+		continue;
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+}
+
+static void setup_txqueues(struct bcm43xx_pioqueue *queue)
+{
+	struct bcm43xx_pio_txpacket *packet;
+	int i;
+
+	queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS;
+	for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) {
+		packet = &(queue->tx_packets_cache[i]);
+
+		packet->queue = queue;
+		INIT_LIST_HEAD(&packet->list);
+
+		list_add(&packet->list, &queue->txfree);
+	}
+}
+
+static
+struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,
+						 u16 pio_mmio_base)
+{
+	struct bcm43xx_pioqueue *queue;
+	u32 value;
+	u16 qsize;
+
+	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+	if (!queue)
+		goto out;
+
+	queue->bcm = bcm;
+	queue->mmio_base = pio_mmio_base;
+	queue->need_workarounds = (bcm->current_core->rev < 3);
+
+	INIT_LIST_HEAD(&queue->txfree);
+	INIT_LIST_HEAD(&queue->txqueue);
+	INIT_LIST_HEAD(&queue->txrunning);
+	tasklet_init(&queue->txtask, tx_tasklet,
+		     (unsigned long)queue);
+
+	value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	value |= BCM43xx_SBF_XFER_REG_BYTESWAP;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
+
+	qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
+	if (qsize <= BCM43xx_PIO_TXQADJUST) {
+		printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize);
+		goto err_freequeue;
+	}
+	qsize -= BCM43xx_PIO_TXQADJUST;
+	queue->tx_devq_size = qsize;
+
+	setup_txqueues(queue);
+
+out:
+	return queue;
+
+err_freequeue:
+	kfree(queue);
+	queue = NULL;
+	goto out;
+}
+
+static void cancel_transfers(struct bcm43xx_pioqueue *queue)
+{
+	struct bcm43xx_pio_txpacket *packet, *tmp_packet;
+
+	netif_tx_disable(queue->bcm->net_dev);
+	assert(queue->bcm->shutting_down);
+	tasklet_disable(&queue->txtask);
+
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+		free_txpacket(packet, 0);
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+		free_txpacket(packet, 0);
+}
+
+static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue)
+{
+	if (!queue)
+		return;
+
+	cancel_transfers(queue);
+	kfree(queue);
+}
+
+void bcm43xx_pio_free(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio;
+
+	if (!bcm43xx_using_pio(bcm))
+		return;
+	pio = bcm43xx_current_pio(bcm);
+
+	bcm43xx_destroy_pioqueue(pio->queue3);
+	pio->queue3 = NULL;
+	bcm43xx_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+	bcm43xx_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+	bcm43xx_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+}
+
+int bcm43xx_pio_init(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);
+	struct bcm43xx_pioqueue *queue;
+	int err = -ENOMEM;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE);
+	if (!queue)
+		goto out;
+	pio->queue0 = queue;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE);
+	if (!queue)
+		goto err_destroy0;
+	pio->queue1 = queue;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE);
+	if (!queue)
+		goto err_destroy1;
+	pio->queue2 = queue;
+
+	queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE);
+	if (!queue)
+		goto err_destroy2;
+	pio->queue3 = queue;
+
+	if (bcm->current_core->rev < 3)
+		bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND;
+
+	dprintk(KERN_INFO PFX "PIO initialized\n");
+	err = 0;
+out:
+	return err;
+
+err_destroy2:
+	bcm43xx_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+err_destroy1:
+	bcm43xx_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+err_destroy0:
+	bcm43xx_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+	goto out;
+}
+
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1;
+	struct bcm43xx_pio_txpacket *packet;
+	u16 tmp;
+
+	assert(!queue->tx_suspended);
+	assert(!list_empty(&queue->txfree));
+
+	tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
+	if (tmp & BCM43xx_PIO_TXCTL_SUSPEND)
+		return -EBUSY;
+
+	packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
+	packet->txb = txb;
+	packet->xmitted_frags = 0;
+	packet->xmitted_octets = 0;
+	list_move_tail(&packet->list, &queue->txqueue);
+	queue->nr_txfree--;
+	assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS);
+
+	/* Suspend TX, if we are out of packets in the "free" queue. */
+	if (unlikely(list_empty(&queue->txfree))) {
+		netif_stop_queue(queue->bcm->net_dev);
+		queue->tx_suspended = 1;
+	}
+
+	tasklet_schedule(&queue->txtask);
+
+	return 0;
+}
+
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+	struct bcm43xx_pioqueue *queue;
+	struct bcm43xx_pio_txpacket *packet;
+
+	queue = parse_cookie(bcm, status->cookie, &packet);
+	assert(queue);
+//TODO
+if (!queue)
+return;
+	free_txpacket(packet, 1);
+	if (unlikely(queue->tx_suspended)) {
+		queue->tx_suspended = 0;
+		netif_wake_queue(queue->bcm->net_dev);
+	}
+	/* If there are packets on the txqueue, poke the tasklet. */
+	if (!list_empty(&queue->txqueue))
+		tasklet_schedule(&queue->txtask);
+}
+
+static void pio_rx_error(struct bcm43xx_pioqueue *queue,
+			 int clear_buffers,
+			 const char *error)
+{
+	int i;
+
+	printkl("PIO RX error: %s\n", error);
+	bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
+			  BCM43xx_PIO_RXCTL_READY);
+	if (clear_buffers) {
+		assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE);
+		for (i = 0; i < 15; i++) {
+			/* Dummy read. */
+			bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+		}
+	}
+}
+
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
+{
+	u16 preamble[21] = { 0 };
+	struct bcm43xx_rxhdr *rxhdr;
+	u16 tmp, len, rxflags2;
+	int i, preamble_readwords;
+	struct sk_buff *skb;
+
+return;
+	tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
+	if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) {
+		dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk.
+		return;
+	}
+	bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
+			  BCM43xx_PIO_RXCTL_DATAAVAILABLE);
+
+	for (i = 0; i < 10; i++) {
+		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
+		if (tmp & BCM43xx_PIO_RXCTL_READY)
+			goto data_ready;
+		udelay(10);
+	}
+	dprintkl(KERN_ERR PFX "PIO RX timed out\n");
+	return;
+data_ready:
+
+//FIXME: endianess in this function.
+	len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
+	if (unlikely(len > 0x700)) {
+		pio_rx_error(queue, 0, "len > 0x700");
+		return;
+	}
+	if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) {
+		pio_rx_error(queue, 0, "len == 0");
+		return;
+	}
+	preamble[0] = cpu_to_le16(len);
+	if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE)
+		preamble_readwords = 14 / sizeof(u16);
+	else
+		preamble_readwords = 18 / sizeof(u16);
+	for (i = 0; i < preamble_readwords; i++) {
+		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+		preamble[i + 1] = cpu_to_be16(tmp);//FIXME?
+	}
+	rxhdr = (struct bcm43xx_rxhdr *)preamble;
+	rxflags2 = le16_to_cpu(rxhdr->flags2);
+	if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) {
+		pio_rx_error(queue,
+			     (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE),
+			     "invalid frame");
+		return;
+	}
+	if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) {
+		/* We received an xmit status. */
+		struct bcm43xx_hwxmitstatus *hw;
+		struct bcm43xx_xmitstatus stat;
+
+		hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1);
+		stat.cookie = le16_to_cpu(hw->cookie);
+		stat.flags = hw->flags;
+		stat.cnt1 = hw->cnt1;
+		stat.cnt2 = hw->cnt2;
+		stat.seq = le16_to_cpu(hw->seq);
+		stat.unknown = le16_to_cpu(hw->unknown);
+
+		bcm43xx_debugfs_log_txstat(queue->bcm, &stat);
+		bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat);
+
+		return;
+	}
+
+	skb = dev_alloc_skb(len);
+	if (unlikely(!skb)) {
+		pio_rx_error(queue, 1, "OOM");
+		return;
+	}
+	skb_put(skb, len);
+	for (i = 0; i < len - 1; i += 2) {
+		tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
+		*((u16 *)(skb->data + i)) = tmp;
+	}
+	if (len % 2) {
+		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+		skb->data[len - 1] = (tmp & 0x00FF);
+		if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
+			skb->data[0x20] = (tmp & 0xFF00) >> 8;
+		else
+			skb->data[0x1E] = (tmp & 0xFF00) >> 8;
+	}
+	bcm43xx_rx(queue->bcm, skb, rxhdr);
+}

+ 138 - 0
drivers/net/wireless/bcm43xx/bcm43xx_pio.h

@@ -0,0 +1,138 @@
+#ifndef BCM43xx_PIO_H_
+#define BCM43xx_PIO_H_
+
+#include "bcm43xx.h"
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+
+#define BCM43xx_PIO_TXCTL		0x00
+#define BCM43xx_PIO_TXDATA		0x02
+#define BCM43xx_PIO_TXQBUFSIZE		0x04
+#define BCM43xx_PIO_RXCTL		0x08
+#define BCM43xx_PIO_RXDATA		0x0A
+
+#define BCM43xx_PIO_TXCTL_WRITEHI	(1 << 0)
+#define BCM43xx_PIO_TXCTL_WRITELO	(1 << 1)
+#define BCM43xx_PIO_TXCTL_COMPLETE	(1 << 2)
+#define BCM43xx_PIO_TXCTL_INIT		(1 << 3)
+#define BCM43xx_PIO_TXCTL_SUSPEND	(1 << 7)
+
+#define BCM43xx_PIO_RXCTL_DATAAVAILABLE	(1 << 0)
+#define BCM43xx_PIO_RXCTL_READY		(1 << 1)
+
+/* PIO constants */
+#define BCM43xx_PIO_MAXTXDEVQPACKETS	31
+#define BCM43xx_PIO_TXQADJUST		80
+
+/* PIO tuning knobs */
+#define BCM43xx_PIO_MAXTXPACKETS	256
+
+
+
+#ifdef CONFIG_BCM43XX_PIO
+
+
+struct bcm43xx_pioqueue;
+struct bcm43xx_xmitstatus;
+
+struct bcm43xx_pio_txpacket {
+	struct bcm43xx_pioqueue *queue;
+	struct ieee80211_txb *txb;
+	struct list_head list;
+
+	u8 xmitted_frags;
+	u16 xmitted_octets;
+};
+
+#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) 
+
+struct bcm43xx_pioqueue {
+	struct bcm43xx_private *bcm;
+	u16 mmio_base;
+
+	u8 tx_suspended:1,
+	   need_workarounds:1; /* Workarounds needed for core.rev < 3 */
+
+	/* Adjusted size of the device internal TX buffer. */
+	u16 tx_devq_size;
+	/* Used octets of the device internal TX buffer. */
+	u16 tx_devq_used;
+	/* Used packet slots in the device internal TX buffer. */
+	u8 tx_devq_packets;
+	/* Packets from the txfree list can
+	 * be taken on incoming TX requests.
+	 */
+	struct list_head txfree;
+	unsigned int nr_txfree;
+	/* Packets on the txqueue are queued,
+	 * but not completely written to the chip, yet.
+	 */
+	struct list_head txqueue;
+	/* Packets on the txrunning queue are completely
+	 * posted to the device. We are waiting for the txstatus.
+	 */
+	struct list_head txrunning;
+	/* Total number or packets sent.
+	 * (This counter can obviously wrap).
+	 */
+	unsigned int nr_tx_packets;
+	struct tasklet_struct txtask;
+	struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS];
+};
+
+static inline
+u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue,
+		     u16 offset)
+{
+	return bcm43xx_read16(queue->bcm, queue->mmio_base + offset);
+}
+
+static inline
+void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
+		       u16 offset, u16 value)
+{
+	bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
+}
+
+
+int bcm43xx_pio_init(struct bcm43xx_private *bcm);
+void bcm43xx_pio_free(struct bcm43xx_private *bcm);
+
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb);
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status);
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
+
+#else /* CONFIG_BCM43XX_PIO */
+
+static inline
+int bcm43xx_pio_init(struct bcm43xx_private *bcm)
+{
+	return 0;
+}
+static inline
+void bcm43xx_pio_free(struct bcm43xx_private *bcm)
+{
+}
+static inline
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+		   struct ieee80211_txb *txb)
+{
+	return 0;
+}
+static inline
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+				   struct bcm43xx_xmitstatus *status)
+{
+}
+static inline
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
+{
+}
+
+#endif /* CONFIG_BCM43XX_PIO */
+#endif /* BCM43xx_PIO_H_ */

+ 358 - 0
drivers/net/wireless/bcm43xx/bcm43xx_power.c

@@ -0,0 +1,358 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_power.h"
+#include "bcm43xx_main.h"
+
+
+/* Get max/min slowclock frequency
+ * as described in http://bcm-specs.sipsolutions.net/PowerControl
+ */
+static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
+				       int get_max)
+{
+	int limit = 0;
+	int divisor;
+	int selection;
+	int err;
+	u32 tmp;
+	struct bcm43xx_coreinfo *old_core;
+
+	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+		goto out;
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err)
+		goto out;
+
+	if (bcm->current_core->rev < 6) {
+		if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) ||
+			(bcm->bustype == BCM43xx_BUSTYPE_SB)) {
+			selection = 1;
+			divisor = 32;
+		} else {
+			err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
+			if (err) {
+				printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n");
+				goto out_switchback;
+			}
+			if (tmp & 0x10) {
+				/* PCI */
+				selection = 2;
+				divisor = 64;
+			} else {
+				/* XTAL */
+				selection = 1;
+				divisor = 32;
+			}
+		}
+	} else if (bcm->current_core->rev < 10) {
+		selection = (tmp & 0x07);
+		if (selection) {
+			tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+			divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
+		} else
+			divisor = 1;
+	} else {
+		tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
+		divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
+		selection = 1;
+	}
+	
+	switch (selection) {
+	case 0:
+		/* LPO */
+		if (get_max)
+			limit = 43000;
+		else
+			limit = 25000;
+		break;
+	case 1:
+		/* XTAL */
+		if (get_max)
+			limit = 20200000;
+		else
+			limit = 19800000;
+		break;
+	case 2:
+		/* PCI */
+		if (get_max)
+			limit = 34000000;
+		else
+			limit = 25000000;
+		break;
+	default:
+		assert(0);
+	}
+	limit /= divisor;
+
+out_switchback:
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return limit;
+}
+
+/* init power control
+ * as described in http://bcm-specs.sipsolutions.net/PowerControl
+ */
+int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
+{
+	int err, maxfreq;
+	struct bcm43xx_coreinfo *old_core;
+
+	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+		return 0;
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV)
+		return 0;
+	if (err)
+		goto out;
+
+	maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
+	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
+			(maxfreq * 150 + 999999) / 1000000);
+	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
+			(maxfreq * 15 + 999999) / 1000000);
+
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return err;
+}
+
+u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
+{
+	u16 delay = 0;
+	int err;
+	u32 pll_on_delay;
+	struct bcm43xx_coreinfo *old_core;
+	int minfreq;
+
+	if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
+		goto out;
+	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+		goto out;
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV)
+		goto out;
+
+	minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
+	pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
+	delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
+
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return delay;
+}
+
+/* set the powercontrol clock
+ * as described in http://bcm-specs.sipsolutions.net/PowerControl
+ */
+int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
+{
+	int err;
+	struct bcm43xx_coreinfo *old_core;
+	u32 tmp;
+
+	old_core = bcm->current_core;
+	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+	if (err == -ENODEV)
+		return 0;
+	if (err)
+		goto out;
+	
+	if (bcm->core_chipcommon.rev < 6) {
+		if (mode == BCM43xx_PCTL_CLK_FAST) {
+			err = bcm43xx_pctl_set_crystal(bcm, 1);
+			if (err)
+				goto out;
+		}
+	} else {
+		if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
+			(bcm->core_chipcommon.rev < 10)) {
+			switch (mode) {
+			case BCM43xx_PCTL_CLK_FAST:
+				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
+				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+				break;
+			case BCM43xx_PCTL_CLK_SLOW:
+				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp |= BCM43xx_PCTL_FORCE_SLOW;
+				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+				break;
+			case BCM43xx_PCTL_CLK_DYNAMIC:
+				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
+				tmp |= BCM43xx_PCTL_FORCE_PLL;
+				tmp &= ~BCM43xx_PCTL_DYN_XTAL;
+				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+			}
+		}
+	}
+	
+	err = bcm43xx_switch_core(bcm, old_core);
+	assert(err == 0);
+
+out:
+	return err;
+}
+
+int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
+{
+	int err;
+	u32 in, out, outenable;
+
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
+	if (err)
+		goto err_pci;
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
+	if (err)
+		goto err_pci;
+	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
+	if (err)
+		goto err_pci;
+
+	outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
+
+	if (on) {
+		if (in & 0x40)
+			return 0;
+
+		out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
+
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
+		if (err)
+			goto err_pci;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
+		if (err)
+			goto err_pci;
+		udelay(1000);
+
+		out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
+		if (err)
+			goto err_pci;
+		udelay(5000);
+	} else {
+		if (bcm->current_core->rev < 5)
+			return 0;
+		if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
+			return 0;
+
+/*		XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
+ *		err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
+ *		if (err)
+ *			return err;
+ *		if (((bcm->current_core->rev >= 3) &&
+ *			(bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
+ *		      ((bcm->current_core->rev < 3) &&
+ *			!(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
+ *			return 0;
+ *		err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+ *		if (err)
+ *			return err;
+ */
+		
+		err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+		if (err)
+			goto out;
+		out &= ~BCM43xx_PCTL_XTAL_POWERUP;
+		out |= BCM43xx_PCTL_PLL_POWERDOWN;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
+		if (err)
+			goto err_pci;
+		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
+		if (err)
+			goto err_pci;
+	}
+
+out:
+	return err;
+
+err_pci:
+	printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
+	err = -EBUSY;
+	goto out;
+}
+
+/* Set the PowerSavingControlBits.
+ * Bitvalues:
+ *   0  => unset the bit
+ *   1  => set the bit
+ *   -1 => calculate the bit
+ */
+void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
+				   int bit25, int bit26)
+{
+	int i;
+	u32 status;
+
+//FIXME: Force 25 to off and 26 to on for now:
+bit25 = 0;
+bit26 = 1;
+
+	if (bit25 == -1) {
+		//TODO: If powersave is not off and FIXME is not set and we are not in adhoc
+		//	and thus is not an AP and we are associated, set bit 25
+	}
+	if (bit26 == -1) {
+		//TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
+		//	or we are associated, or FIXME, or the latest PS-Poll packet sent was
+		//	successful, set bit26
+	}
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	if (bit25)
+		status |= BCM43xx_SBF_PS1;
+	else
+		status &= ~BCM43xx_SBF_PS1;
+	if (bit26)
+		status |= BCM43xx_SBF_PS2;
+	else
+		status &= ~BCM43xx_SBF_PS2;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	if (bit26 && bcm->current_core->rev >= 5) {
+		for (i = 0; i < 100; i++) {
+			if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
+				break;
+			udelay(10);
+		}
+	}
+}

+ 47 - 0
drivers/net/wireless/bcm43xx/bcm43xx_power.h

@@ -0,0 +1,47 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_POWER_H_
+#define BCM43xx_POWER_H_
+
+#include <linux/types.h>
+
+
+struct bcm43xx_private;
+
+int bcm43xx_pctl_init(struct bcm43xx_private *bcm);
+int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode);
+int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on);
+u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm);
+
+void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
+				   int bit25, int bit26);
+
+#endif /* BCM43xx_POWER_H_ */

+ 2026 - 0
drivers/net/wireless/bcm43xx/bcm43xx_radio.c

@@ -0,0 +1,2026 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_phy.h"
+#include "bcm43xx_radio.h"
+#include "bcm43xx_ilt.h"
+
+
+/* Table for bcm43xx_radio_calibrationvalue() */
+static const u16 rcc_table[16] = {
+	0x0002, 0x0003, 0x0001, 0x000F,
+	0x0006, 0x0007, 0x0005, 0x000F,
+	0x000A, 0x000B, 0x0009, 0x000F,
+	0x000E, 0x000F, 0x000D, 0x000F,
+};
+
+/* Reverse the bits of a 4bit value.
+ * Example:  1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+	u16 flipped = 0x0000;
+
+	assert((value & ~0x000F) == 0x0000);
+
+	flipped |= (value & 0x0001) << 3;
+	flipped |= (value & 0x0002) << 1;
+	flipped |= (value & 0x0004) >> 1;
+	flipped |= (value & 0x0008) >> 3;
+
+	return flipped;
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline
+u16 channel2freq_bg(u8 channel)
+{
+	/* Frequencies are given as frequencies_bg[index] + 2.4GHz
+	 * Starting with channel 1
+	 */
+	static const u16 frequencies_bg[14] = {
+		12, 17, 22, 27,
+		32, 37, 42, 47,
+		52, 57, 62, 67,
+		72, 84,
+	};
+
+	assert(channel >= 1 && channel <= 14);
+
+	return frequencies_bg[channel - 1];
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline
+u16 channel2freq_a(u8 channel)
+{
+	assert(channel <= 200);
+
+	return (5000 + 5 * channel);
+}
+
+void bcm43xx_radio_lock(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status |= BCM43xx_SBF_RADIOREG_LOCK;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+	udelay(10);
+}
+
+void bcm43xx_radio_unlock(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status &= ~BCM43xx_SBF_RADIOREG_LOCK;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+}
+
+u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		offset |= 0x0040;
+		break;
+	case BCM43xx_PHYTYPE_B:
+		if (radio->version == 0x2053) {
+			if (offset < 0x70)
+				offset += 0x80;
+			else if (offset < 0x80)
+				offset += 0x70;
+		} else if (radio->version == 0x2050) {
+			offset |= 0x80;
+		} else
+			assert(0);
+		break;
+	case BCM43xx_PHYTYPE_G:
+		offset |= 0x80;
+		break;
+	}
+
+	bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
+	return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
+}
+
+void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val)
+{
+	bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
+	mmiowb();
+	bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm,
+				  s16 first, s16 second, s16 third)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i;
+	u16 start = 0x08, end = 0x18;
+	u16 offset = 0x0400;
+	u16 tmp;
+
+	if (phy->rev <= 1) {
+		offset = 0x5000;
+		start = 0x10;
+		end = 0x20;
+	}
+
+	for (i = 0; i < 4; i++)
+		bcm43xx_ilt_write(bcm, offset + i, first);
+
+	for (i = start; i < end; i++)
+		bcm43xx_ilt_write(bcm, offset + i, second);
+
+	if (third != -1) {
+		tmp = ((u16)third << 14) | ((u16)third << 6);
+		bcm43xx_phy_write(bcm, 0x04A0,
+		                  (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp);
+		bcm43xx_phy_write(bcm, 0x04A1,
+		                  (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp);
+		bcm43xx_phy_write(bcm, 0x04A2,
+		                  (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp);
+	}
+	bcm43xx_dummy_transmission(bcm);
+}
+
+static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 i, tmp;
+	u16 offset = 0x0400;
+	u16 start = 0x0008, end = 0x0018;
+
+	if (phy->rev <= 1) {
+		offset = 0x5000;
+		start = 0x0010;
+		end = 0x0020;
+	}
+
+	for (i = 0; i < 4; i++) {
+		tmp = (i & 0xFFFC);
+		tmp |= (i & 0x0001) << 1;
+		tmp |= (i & 0x0002) >> 1;
+
+		bcm43xx_ilt_write(bcm, offset + i, tmp);
+	}
+
+	for (i = start; i < end; i++)
+		bcm43xx_ilt_write(bcm, offset + i, i - start);
+
+	bcm43xx_phy_write(bcm, 0x04A0,
+	                  (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040);
+	bcm43xx_phy_write(bcm, 0x04A1,
+	                  (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040);
+	bcm43xx_phy_write(bcm, 0x04A2,
+	                  (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000);
+	bcm43xx_dummy_transmission(bcm);
+}
+
+/* Synthetic PU workaround */
+static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	
+	if (radio->version != 0x2050 || radio->revision >= 6) {
+		/* We do not need the workaround. */
+		return;
+	}
+
+	if (channel <= 10) {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+				channel2freq_bg(channel + 4));
+	} else {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+				channel2freq_bg(1));
+	}
+	udelay(100);
+	bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+			channel2freq_bg(channel));
+}
+
+u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u8 ret = 0;
+	u16 saved, rssi, temp;
+	int i, j = 0;
+
+	saved = bcm43xx_phy_read(bcm, 0x0403);
+	bcm43xx_radio_selectchannel(bcm, channel, 0);
+	bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5);
+	if (radio->aci_hw_rssi)
+		rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F;
+	else
+		rssi = saved & 0x3F;
+	/* clamp temp to signed 5bit */
+	if (rssi > 32)
+		rssi -= 64;
+	for (i = 0;i < 100; i++) {
+		temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F;
+		if (temp > 32)
+			temp -= 64;
+		if (temp < rssi)
+			j++;
+		if (j >= 20)
+			ret = 1;
+	}
+	bcm43xx_phy_write(bcm, 0x0403, saved);
+
+	return ret;
+}
+
+u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u8 ret[13];
+	unsigned int channel = radio->channel;
+	unsigned int i, j, start, end;
+	unsigned long phylock_flags;
+
+	if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0)))
+		return 0;
+
+	bcm43xx_phy_lock(bcm, phylock_flags);
+	bcm43xx_radio_lock(bcm);
+	bcm43xx_phy_write(bcm, 0x0802,
+	                  bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+	                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
+	bcm43xx_set_all_gains(bcm, 3, 8, 1);
+
+	start = (channel - 5 > 0) ? channel - 5 : 1;
+	end = (channel + 5 < 14) ? channel + 5 : 13;
+
+	for (i = start; i <= end; i++) {
+		if (abs(channel - i) > 2)
+			ret[i-1] = bcm43xx_radio_aci_detect(bcm, i);
+	}
+	bcm43xx_radio_selectchannel(bcm, channel, 0);
+	bcm43xx_phy_write(bcm, 0x0802,
+	                  (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003);
+	bcm43xx_phy_write(bcm, 0x0403,
+	                  bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8);
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+	                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
+	bcm43xx_set_original_gains(bcm);
+	for (i = 0; i < 13; i++) {
+		if (!ret[i])
+			continue;
+		end = (i + 5 < 13) ? i + 5 : 13;
+		for (j = i; j < end; j++)
+			ret[j] = 1;
+	}
+	bcm43xx_radio_unlock(bcm);
+	bcm43xx_phy_unlock(bcm, phylock_flags);
+
+	return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val)
+{
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
+	mmiowb();
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset)
+{
+	u16 val;
+
+	bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
+	val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA);
+
+	return (s16)val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val)
+{
+	u16 i;
+	s16 tmp;
+
+	for (i = 0; i < 64; i++) {
+		tmp = bcm43xx_nrssi_hw_read(bcm, i);
+		tmp -= val;
+		tmp = limit_value(tmp, -32, 31);
+		bcm43xx_nrssi_hw_write(bcm, i, tmp);
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	s16 i, delta;
+	s32 tmp;
+
+	delta = 0x1F - radio->nrssi[0];
+	for (i = 0; i < 64; i++) {
+		tmp = (i - delta) * radio->nrssislope;
+		tmp /= 0x10000;
+		tmp += 0x3A;
+		tmp = limit_value(tmp, 0, 0x3F);
+		radio->nrssi_lt[i] = tmp;
+	}
+}
+
+static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 backup[20] = { 0 };
+	s16 v47F;
+	u16 i;
+	u16 saved = 0xFFFF;
+
+	backup[0] = bcm43xx_phy_read(bcm, 0x0001);
+	backup[1] = bcm43xx_phy_read(bcm, 0x0811);
+	backup[2] = bcm43xx_phy_read(bcm, 0x0812);
+	backup[3] = bcm43xx_phy_read(bcm, 0x0814);
+	backup[4] = bcm43xx_phy_read(bcm, 0x0815);
+	backup[5] = bcm43xx_phy_read(bcm, 0x005A);
+	backup[6] = bcm43xx_phy_read(bcm, 0x0059);
+	backup[7] = bcm43xx_phy_read(bcm, 0x0058);
+	backup[8] = bcm43xx_phy_read(bcm, 0x000A);
+	backup[9] = bcm43xx_phy_read(bcm, 0x0003);
+	backup[10] = bcm43xx_radio_read16(bcm, 0x007A);
+	backup[11] = bcm43xx_radio_read16(bcm, 0x0043);
+
+	bcm43xx_phy_write(bcm, 0x0429,
+			  bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF);
+	bcm43xx_phy_write(bcm, 0x0001,
+			  (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000);
+	bcm43xx_phy_write(bcm, 0x0811,
+			  bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
+	bcm43xx_phy_write(bcm, 0x0812,
+			  (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004);
+	bcm43xx_phy_write(bcm, 0x0802,
+			  bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2));
+	if (phy->rev >= 6) {
+		backup[12] = bcm43xx_phy_read(bcm, 0x002E);
+		backup[13] = bcm43xx_phy_read(bcm, 0x002F);
+		backup[14] = bcm43xx_phy_read(bcm, 0x080F);
+		backup[15] = bcm43xx_phy_read(bcm, 0x0810);
+		backup[16] = bcm43xx_phy_read(bcm, 0x0801);
+		backup[17] = bcm43xx_phy_read(bcm, 0x0060);
+		backup[18] = bcm43xx_phy_read(bcm, 0x0014);
+		backup[19] = bcm43xx_phy_read(bcm, 0x0478);
+
+		bcm43xx_phy_write(bcm, 0x002E, 0);
+		bcm43xx_phy_write(bcm, 0x002F, 0);
+		bcm43xx_phy_write(bcm, 0x080F, 0);
+		bcm43xx_phy_write(bcm, 0x0810, 0);
+		bcm43xx_phy_write(bcm, 0x0478,
+				  bcm43xx_phy_read(bcm, 0x0478) | 0x0100);
+		bcm43xx_phy_write(bcm, 0x0801,
+				  bcm43xx_phy_read(bcm, 0x0801) | 0x0040);
+		bcm43xx_phy_write(bcm, 0x0060,
+				  bcm43xx_phy_read(bcm, 0x0060) | 0x0040);
+		bcm43xx_phy_write(bcm, 0x0014,
+				  bcm43xx_phy_read(bcm, 0x0014) | 0x0200);
+	}
+	bcm43xx_radio_write16(bcm, 0x007A,
+			      bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
+	bcm43xx_radio_write16(bcm, 0x007A,
+			      bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
+	udelay(30);
+
+	v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+	if (v47F >= 0x20)
+		v47F -= 0x40;
+	if (v47F == 31) {
+		for (i = 7; i >= 4; i--) {
+			bcm43xx_radio_write16(bcm, 0x007B, i);
+			udelay(20);
+			v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+			if (v47F >= 0x20)
+				v47F -= 0x40;
+			if (v47F < 31 && saved == 0xFFFF)
+				saved = i;
+		}
+		if (saved == 0xFFFF)
+			saved = 4;
+	} else {
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
+		bcm43xx_phy_write(bcm, 0x0814,
+				  bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
+		bcm43xx_phy_write(bcm, 0x0815,
+				  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
+		bcm43xx_phy_write(bcm, 0x0811,
+				  bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
+		bcm43xx_phy_write(bcm, 0x0811,
+				  bcm43xx_phy_read(bcm, 0x0811) | 0x0030);
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_phy_read(bcm, 0x0812) | 0x0030);
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0x0810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		if (phy->rev == 0) {
+			bcm43xx_phy_write(bcm, 0x0003, 0x0122);
+		} else {
+			bcm43xx_phy_write(bcm, 0x000A,
+					  bcm43xx_phy_read(bcm, 0x000A)
+					  | 0x2000);
+		}
+		bcm43xx_phy_write(bcm, 0x0814,
+				  bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
+		bcm43xx_phy_write(bcm, 0x0815,
+				  bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
+		bcm43xx_phy_write(bcm, 0x0003,
+				  (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F)
+				  | 0x0040);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
+		bcm43xx_set_all_gains(bcm, 3, 0, 1);
+		bcm43xx_radio_write16(bcm, 0x0043,
+				      (bcm43xx_radio_read16(bcm, 0x0043)
+				       & 0x00F0) | 0x000F);
+		udelay(30);
+		v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+		if (v47F >= 0x20)
+			v47F -= 0x40;
+		if (v47F == -32) {
+			for (i = 0; i < 4; i++) {
+				bcm43xx_radio_write16(bcm, 0x007B, i);
+				udelay(20);
+				v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+				if (v47F >= 0x20)
+					v47F -= 0x40;
+				if (v47F > -31 && saved == 0xFFFF)
+					saved = i;
+			}
+			if (saved == 0xFFFF)
+				saved = 3;
+		} else
+			saved = 0;
+	}
+	bcm43xx_radio_write16(bcm, 0x007B, saved);
+
+	if (phy->rev >= 6) {
+		bcm43xx_phy_write(bcm, 0x002E, backup[12]);
+		bcm43xx_phy_write(bcm, 0x002F, backup[13]);
+		bcm43xx_phy_write(bcm, 0x080F, backup[14]);
+		bcm43xx_phy_write(bcm, 0x0810, backup[15]);
+	}
+	bcm43xx_phy_write(bcm, 0x0814, backup[3]);
+	bcm43xx_phy_write(bcm, 0x0815, backup[4]);
+	bcm43xx_phy_write(bcm, 0x005A, backup[5]);
+	bcm43xx_phy_write(bcm, 0x0059, backup[6]);
+	bcm43xx_phy_write(bcm, 0x0058, backup[7]);
+	bcm43xx_phy_write(bcm, 0x000A, backup[8]);
+	bcm43xx_phy_write(bcm, 0x0003, backup[9]);
+	bcm43xx_radio_write16(bcm, 0x0043, backup[11]);
+	bcm43xx_radio_write16(bcm, 0x007A, backup[10]);
+	bcm43xx_phy_write(bcm, 0x0802,
+			  bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2);
+	bcm43xx_phy_write(bcm, 0x0429,
+			  bcm43xx_phy_read(bcm, 0x0429) | 0x8000);
+	bcm43xx_set_original_gains(bcm);
+	if (phy->rev >= 6) {
+		bcm43xx_phy_write(bcm, 0x0801, backup[16]);
+		bcm43xx_phy_write(bcm, 0x0060, backup[17]);
+		bcm43xx_phy_write(bcm, 0x0014, backup[18]);
+		bcm43xx_phy_write(bcm, 0x0478, backup[19]);
+	}
+	bcm43xx_phy_write(bcm, 0x0001, backup[0]);
+	bcm43xx_phy_write(bcm, 0x0812, backup[2]);
+	bcm43xx_phy_write(bcm, 0x0811, backup[1]);
+}
+
+void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 backup[18] = { 0 };
+	u16 tmp;
+	s16 nrssi0, nrssi1;
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_B:
+		backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
+		backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
+		backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
+		backup[3] = bcm43xx_phy_read(bcm, 0x0030);
+		backup[4] = bcm43xx_phy_read(bcm, 0x0026);
+		backup[5] = bcm43xx_phy_read(bcm, 0x0015);
+		backup[6] = bcm43xx_phy_read(bcm, 0x002A);
+		backup[7] = bcm43xx_phy_read(bcm, 0x0020);
+		backup[8] = bcm43xx_phy_read(bcm, 0x005A);
+		backup[9] = bcm43xx_phy_read(bcm, 0x0059);
+		backup[10] = bcm43xx_phy_read(bcm, 0x0058);
+		backup[11] = bcm43xx_read16(bcm, 0x03E2);
+		backup[12] = bcm43xx_read16(bcm, 0x03E6);
+		backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+
+		tmp  = bcm43xx_radio_read16(bcm, 0x007A);
+		tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+		bcm43xx_radio_write16(bcm, 0x007A, tmp);
+		bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
+		bcm43xx_write16(bcm, 0x03EC, 0x7F7F);
+		bcm43xx_phy_write(bcm, 0x0026, 0x0000);
+		bcm43xx_phy_write(bcm, 0x0015,
+				  bcm43xx_phy_read(bcm, 0x0015) | 0x0020);
+		bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
+
+		nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
+		if (phy->rev >= 2) {
+			bcm43xx_write16(bcm, 0x03E6, 0x0040);
+		} else if (phy->rev == 0) {
+			bcm43xx_write16(bcm, 0x03E6, 0x0122);
+		} else {
+			bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+					bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000);
+		}
+		bcm43xx_phy_write(bcm, 0x0020, 0x3F3F);
+		bcm43xx_phy_write(bcm, 0x0015, 0xF330);
+		bcm43xx_radio_write16(bcm, 0x005A, 0x0060);
+		bcm43xx_radio_write16(bcm, 0x0043,
+				      bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0);
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0x0810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		udelay(20);
+
+		nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027);
+		bcm43xx_phy_write(bcm, 0x0030, backup[3]);
+		bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
+		bcm43xx_write16(bcm, 0x03E2, backup[11]);
+		bcm43xx_phy_write(bcm, 0x0026, backup[4]);
+		bcm43xx_phy_write(bcm, 0x0015, backup[5]);
+		bcm43xx_phy_write(bcm, 0x002A, backup[6]);
+		bcm43xx_synth_pu_workaround(bcm, radio->channel);
+		if (phy->rev != 0)
+			bcm43xx_write16(bcm, 0x03F4, backup[13]);
+
+		bcm43xx_phy_write(bcm, 0x0020, backup[7]);
+		bcm43xx_phy_write(bcm, 0x005A, backup[8]);
+		bcm43xx_phy_write(bcm, 0x0059, backup[9]);
+		bcm43xx_phy_write(bcm, 0x0058, backup[10]);
+		bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
+		bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
+
+		if (nrssi0 == nrssi1)
+			radio->nrssislope = 0x00010000;
+		else 
+			radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+		if (nrssi0 <= -4) {
+			radio->nrssi[0] = nrssi0;
+			radio->nrssi[1] = nrssi1;
+		}
+		break;
+	case BCM43xx_PHYTYPE_G:
+		if (radio->revision >= 9)
+			return;
+		if (radio->revision == 8)
+			bcm43xx_calc_nrssi_offset(bcm);
+
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
+		bcm43xx_phy_write(bcm, 0x0802,
+				  bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
+		backup[7] = bcm43xx_read16(bcm, 0x03E2);
+		bcm43xx_write16(bcm, 0x03E2,
+				bcm43xx_read16(bcm, 0x03E2) | 0x8000);
+		backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
+		backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
+		backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
+		backup[3] = bcm43xx_phy_read(bcm, 0x0015);
+		backup[4] = bcm43xx_phy_read(bcm, 0x005A);
+		backup[5] = bcm43xx_phy_read(bcm, 0x0059);
+		backup[6] = bcm43xx_phy_read(bcm, 0x0058);
+		backup[8] = bcm43xx_read16(bcm, 0x03E6);
+		backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+		if (phy->rev >= 3) {
+			backup[10] = bcm43xx_phy_read(bcm, 0x002E);
+			backup[11] = bcm43xx_phy_read(bcm, 0x002F);
+			backup[12] = bcm43xx_phy_read(bcm, 0x080F);
+			backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL);
+			backup[14] = bcm43xx_phy_read(bcm, 0x0801);
+			backup[15] = bcm43xx_phy_read(bcm, 0x0060);
+			backup[16] = bcm43xx_phy_read(bcm, 0x0014);
+			backup[17] = bcm43xx_phy_read(bcm, 0x0478);
+			bcm43xx_phy_write(bcm, 0x002E, 0);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0);
+			switch (phy->rev) {
+			case 4: case 6: case 7:
+				bcm43xx_phy_write(bcm, 0x0478,
+						  bcm43xx_phy_read(bcm, 0x0478)
+						  | 0x0100);
+				bcm43xx_phy_write(bcm, 0x0801,
+						  bcm43xx_phy_read(bcm, 0x0801)
+						  | 0x0040);
+				break;
+			case 3: case 5:
+				bcm43xx_phy_write(bcm, 0x0801,
+						  bcm43xx_phy_read(bcm, 0x0801)
+						  & 0xFFBF);
+				break;
+			}
+			bcm43xx_phy_write(bcm, 0x0060,
+					  bcm43xx_phy_read(bcm, 0x0060)
+					  | 0x0040);
+			bcm43xx_phy_write(bcm, 0x0014,
+					  bcm43xx_phy_read(bcm, 0x0014)
+					  | 0x0200);
+		}
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
+		bcm43xx_set_all_gains(bcm, 0, 8, 0);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7);
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0811,
+					  (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010);
+		}
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
+		udelay(20);
+
+		nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+		if (nrssi0 >= 0x0020)
+			nrssi0 -= 0x0040;
+
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0003,
+					  (bcm43xx_phy_read(bcm, 0x0003)
+					   & 0xFF9F) | 0x0040);
+		}
+
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+				bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+				| 0x2000);
+		bcm43xx_radio_write16(bcm, 0x007A,
+				      bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
+		bcm43xx_phy_write(bcm, 0x0015, 0xF330);
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0812,
+					  (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020);
+			bcm43xx_phy_write(bcm, 0x0811,
+					  (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020);
+		}
+
+		bcm43xx_set_all_gains(bcm, 3, 0, 1);
+		if (radio->revision == 8) {
+			bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+		} else {
+			tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F;
+			bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060);
+			tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0;
+			bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009);
+		}
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0x0810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		udelay(20);
+		nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
+		if (nrssi1 >= 0x0020)
+			nrssi1 -= 0x0040;
+		if (nrssi0 == nrssi1)
+			radio->nrssislope = 0x00010000;
+		else
+			radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+		if (nrssi0 >= -4) {
+			radio->nrssi[0] = nrssi1;
+			radio->nrssi[1] = nrssi0;
+		}
+		if (phy->rev >= 3) {
+			bcm43xx_phy_write(bcm, 0x002E, backup[10]);
+			bcm43xx_phy_write(bcm, 0x002F, backup[11]);
+			bcm43xx_phy_write(bcm, 0x080F, backup[12]);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]);
+		}
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF);
+			bcm43xx_phy_write(bcm, 0x0811,
+					  bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF);
+		}
+
+		bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
+		bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
+		bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
+		bcm43xx_write16(bcm, 0x03E2, backup[7]);
+		bcm43xx_write16(bcm, 0x03E6, backup[8]);
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]);
+		bcm43xx_phy_write(bcm, 0x0015, backup[3]);
+		bcm43xx_phy_write(bcm, 0x005A, backup[4]);
+		bcm43xx_phy_write(bcm, 0x0059, backup[5]);
+		bcm43xx_phy_write(bcm, 0x0058, backup[6]);
+		bcm43xx_synth_pu_workaround(bcm, radio->channel);
+		bcm43xx_phy_write(bcm, 0x0802,
+				  bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002));
+		bcm43xx_set_original_gains(bcm);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
+		if (phy->rev >= 3) {
+			bcm43xx_phy_write(bcm, 0x0801, backup[14]);
+			bcm43xx_phy_write(bcm, 0x0060, backup[15]);
+			bcm43xx_phy_write(bcm, 0x0014, backup[16]);
+			bcm43xx_phy_write(bcm, 0x0478, backup[17]);
+		}
+		bcm43xx_nrssi_mem_update(bcm);
+		bcm43xx_calc_nrssi_threshold(bcm);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	s32 threshold;
+	s32 a, b;
+	s16 tmp16;
+	u16 tmp_u16;
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_B: {
+		if (radio->version != 0x2050)
+			return;
+		if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI))
+			return;
+
+		if (radio->revision >= 6) {
+			threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32;
+			threshold += 20 * (radio->nrssi[0] + 1);
+			threshold /= 40;
+		} else
+			threshold = radio->nrssi[1] - 5;
+
+		threshold = limit_value(threshold, 0, 0x3E);
+		bcm43xx_phy_read(bcm, 0x0020); /* dummy read */
+		bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C);
+
+		if (radio->revision >= 6) {
+			bcm43xx_phy_write(bcm, 0x0087, 0x0E0D);
+			bcm43xx_phy_write(bcm, 0x0086, 0x0C0B);
+			bcm43xx_phy_write(bcm, 0x0085, 0x0A09);
+			bcm43xx_phy_write(bcm, 0x0084, 0x0808);
+			bcm43xx_phy_write(bcm, 0x0083, 0x0808);
+			bcm43xx_phy_write(bcm, 0x0082, 0x0604);
+			bcm43xx_phy_write(bcm, 0x0081, 0x0302);
+			bcm43xx_phy_write(bcm, 0x0080, 0x0100);
+		}
+		break;
+	}
+	case BCM43xx_PHYTYPE_G:
+		if (!phy->connected ||
+		    !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
+			tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20);
+			if (tmp16 >= 0x20)
+				tmp16 -= 0x40;
+			if (tmp16 < 3) {
+				bcm43xx_phy_write(bcm, 0x048A,
+						  (bcm43xx_phy_read(bcm, 0x048A)
+						   & 0xF000) | 0x09EB);
+			} else {
+				bcm43xx_phy_write(bcm, 0x048A,
+						  (bcm43xx_phy_read(bcm, 0x048A)
+						   & 0xF000) | 0x0AED);
+			}
+		} else {
+			if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) {
+				a = 0xE;
+				b = 0xA;
+			} else if (!radio->aci_wlan_automatic && radio->aci_enable) {
+				a = 0x13;
+				b = 0x12;
+			} else {
+				a = 0xE;
+				b = 0x11;
+			}
+
+			a = a * (radio->nrssi[1] - radio->nrssi[0]);
+			a += (radio->nrssi[0] << 6);
+			if (a < 32)
+				a += 31;
+			else
+				a += 32;
+			a = a >> 6;
+			a = limit_value(a, -31, 31);
+
+			b = b * (radio->nrssi[1] - radio->nrssi[0]);
+			b += (radio->nrssi[0] << 6);
+			if (b < 32)
+				b += 31;
+			else
+				b += 32;
+			b = b >> 6;
+			b = limit_value(b, -31, 31);
+
+			tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000;
+			tmp_u16 |= ((u32)b & 0x0000003F);
+			tmp_u16 |= (((u32)a & 0x0000003F) << 6);
+			bcm43xx_phy_write(bcm, 0x048A, tmp_u16);
+		}
+		break;
+	default:
+		assert(0);
+	}
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 *_stackptr, size_t *stackidx,
+			u8 id, u16 offset, u16 value)
+{
+	u32 *stackptr = &(_stackptr[*stackidx]);
+
+	assert((offset & 0xF000) == 0x0000);
+	assert((id & 0xF0) == 0x00);
+	*stackptr = offset;
+	*stackptr |= ((u32)id) << 12;
+	*stackptr |= ((u32)value) << 16;
+	(*stackidx)++;
+	assert(*stackidx < BCM43xx_INTERFSTACK_SIZE);
+}
+
+static u16 _stack_restore(u32 *stackptr,
+			  u8 id, u16 offset)
+{
+	size_t i;
+
+	assert((offset & 0xF000) == 0x0000);
+	assert((id & 0xF0) == 0x00);
+	for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
+		if ((*stackptr & 0x00000FFF) != offset)
+			continue;
+		if (((*stackptr & 0x0000F000) >> 12) != id)
+			continue;
+		return ((*stackptr & 0xFFFF0000) >> 16);
+	}
+	assert(0);
+
+	return 0;
+}
+
+#define phy_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x1, (offset),	\
+			    bcm43xx_phy_read(bcm, (offset)));	\
+	} while (0)
+#define phy_stackrestore(offset)				\
+	do {							\
+		bcm43xx_phy_write(bcm, (offset),		\
+				  _stack_restore(stack, 0x1,	\
+					  	 (offset)));	\
+	} while (0)
+#define radio_stacksave(offset)						\
+	do {								\
+		_stack_save(stack, &stackidx, 0x2, (offset),		\
+			    bcm43xx_radio_read16(bcm, (offset)));	\
+	} while (0)
+#define radio_stackrestore(offset)					\
+	do {								\
+		bcm43xx_radio_write16(bcm, (offset),			\
+				      _stack_restore(stack, 0x2,	\
+						     (offset)));	\
+	} while (0)
+#define ilt_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x3, (offset),	\
+			    bcm43xx_ilt_read(bcm, (offset)));	\
+	} while (0)
+#define ilt_stackrestore(offset)				\
+	do {							\
+		bcm43xx_ilt_write(bcm, (offset),		\
+				  _stack_restore(stack, 0x3,	\
+						 (offset)));	\
+	} while (0)
+
+static void
+bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm,
+					     int mode)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 tmp, flipped;
+	u32 tmp32;
+	size_t stackidx = 0;
+	u32 *stack = radio->interfstack;
+
+	switch (mode) {
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			bcm43xx_phy_write(bcm, 0x042B,
+			                  bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+			                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000);
+			break;
+		}
+		radio_stacksave(0x0078);
+		tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E);
+		flipped = flip_4bit(tmp);
+		if (flipped < 10 && flipped >= 8)
+			flipped = 7;
+		else if (flipped >= 10)
+			flipped -= 3;
+		flipped = flip_4bit(flipped);
+		flipped = (flipped << 1) | 0x0020;
+		bcm43xx_radio_write16(bcm, 0x0078, flipped);
+
+		bcm43xx_calc_nrssi_threshold(bcm);
+
+		phy_stacksave(0x0406);
+		bcm43xx_phy_write(bcm, 0x0406, 0x7E28);
+
+		bcm43xx_phy_write(bcm, 0x042B,
+		                  bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+		                  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000);
+
+		phy_stacksave(0x04A0);
+		bcm43xx_phy_write(bcm, 0x04A0,
+		                  (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008);
+		phy_stacksave(0x04A1);
+		bcm43xx_phy_write(bcm, 0x04A1,
+				  (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605);
+		phy_stacksave(0x04A2);
+		bcm43xx_phy_write(bcm, 0x04A2,
+				  (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204);
+		phy_stacksave(0x04A8);
+		bcm43xx_phy_write(bcm, 0x04A8,
+				  (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803);
+		phy_stacksave(0x04AB);
+		bcm43xx_phy_write(bcm, 0x04AB,
+				  (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605);
+
+		phy_stacksave(0x04A7);
+		bcm43xx_phy_write(bcm, 0x04A7, 0x0002);
+		phy_stacksave(0x04A3);
+		bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
+		phy_stacksave(0x04A9);
+		bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
+		phy_stacksave(0x0493);
+		bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
+		phy_stacksave(0x04AA);
+		bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
+		phy_stacksave(0x04AC);
+		bcm43xx_phy_write(bcm, 0x04AC, 0x32F5);
+		break;
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800)
+			break;
+
+		radio->aci_enable = 1;
+
+		phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD);
+		phy_stacksave(BCM43xx_PHY_G_CRS);
+		if (phy->rev < 2) {
+			phy_stacksave(0x0406);
+		} else {
+			phy_stacksave(0x04C0);
+			phy_stacksave(0x04C1);
+		}
+		phy_stacksave(0x0033);
+		phy_stacksave(0x04A7);
+		phy_stacksave(0x04A3);
+		phy_stacksave(0x04A9);
+		phy_stacksave(0x04AA);
+		phy_stacksave(0x04AC);
+		phy_stacksave(0x0493);
+		phy_stacksave(0x04A1);
+		phy_stacksave(0x04A0);
+		phy_stacksave(0x04A2);
+		phy_stacksave(0x048A);
+		phy_stacksave(0x04A8);
+		phy_stacksave(0x04AB);
+		if (phy->rev == 2) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x0415);
+			phy_stacksave(0x0416);
+			phy_stacksave(0x0417);
+			ilt_stacksave(0x1A00 + 0x2);
+			ilt_stacksave(0x1A00 + 0x3);
+		}
+		phy_stacksave(0x042B);
+		phy_stacksave(0x048C);
+
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)
+				  & ~0x1000);
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+				   & 0xFFFC) | 0x0002);
+
+		bcm43xx_phy_write(bcm, 0x0033, 0x0800);
+		bcm43xx_phy_write(bcm, 0x04A3, 0x2027);
+		bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8);
+		bcm43xx_phy_write(bcm, 0x0493, 0x287A);
+		bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8);
+		bcm43xx_phy_write(bcm, 0x04AC, 0x287A);
+
+		bcm43xx_phy_write(bcm, 0x04A0,
+				  (bcm43xx_phy_read(bcm, 0x04A0)
+				   & 0xFFC0) | 0x001A);
+		bcm43xx_phy_write(bcm, 0x04A7, 0x000D);
+
+		if (phy->rev < 2) {
+			bcm43xx_phy_write(bcm, 0x0406, 0xFF0D);
+		} else if (phy->rev == 2) {
+			bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x00A9);
+		} else {
+			bcm43xx_phy_write(bcm, 0x04C0, 0x00C1);
+			bcm43xx_phy_write(bcm, 0x04C1, 0x0059);
+		}
+
+		bcm43xx_phy_write(bcm, 0x04A1,
+		                  (bcm43xx_phy_read(bcm, 0x04A1)
+				   & 0xC0FF) | 0x1800);
+		bcm43xx_phy_write(bcm, 0x04A1,
+		                  (bcm43xx_phy_read(bcm, 0x04A1)
+				   & 0xFFC0) | 0x0015);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xCFFF) | 0x1000);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xF0FF) | 0x0A00);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xCFFF) | 0x1000);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xF0FF) | 0x0800);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xFFCF) | 0x0010);
+		bcm43xx_phy_write(bcm, 0x04AB,
+		                  (bcm43xx_phy_read(bcm, 0x04AB)
+				   & 0xFFF0) | 0x0005);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xFFCF) | 0x0010);
+		bcm43xx_phy_write(bcm, 0x04A8,
+		                  (bcm43xx_phy_read(bcm, 0x04A8)
+				   & 0xFFF0) | 0x0006);
+		bcm43xx_phy_write(bcm, 0x04A2,
+		                  (bcm43xx_phy_read(bcm, 0x04A2)
+				   & 0xF0FF) | 0x0800);
+		bcm43xx_phy_write(bcm, 0x04A0,
+				  (bcm43xx_phy_read(bcm, 0x04A0)
+				   & 0xF0FF) | 0x0500);
+		bcm43xx_phy_write(bcm, 0x04A2,
+				  (bcm43xx_phy_read(bcm, 0x04A2)
+				   & 0xFFF0) | 0x000B);
+
+		if (phy->rev >= 3) {
+			bcm43xx_phy_write(bcm, 0x048A,
+					  bcm43xx_phy_read(bcm, 0x048A)
+					  & ~0x8000);
+			bcm43xx_phy_write(bcm, 0x0415,
+					  (bcm43xx_phy_read(bcm, 0x0415)
+					   & 0x8000) | 0x36D8);
+			bcm43xx_phy_write(bcm, 0x0416,
+					  (bcm43xx_phy_read(bcm, 0x0416)
+					   & 0x8000) | 0x36D8);
+			bcm43xx_phy_write(bcm, 0x0417,
+					  (bcm43xx_phy_read(bcm, 0x0417)
+					   & 0xFE00) | 0x016D);
+		} else {
+			bcm43xx_phy_write(bcm, 0x048A,
+					  bcm43xx_phy_read(bcm, 0x048A)
+					  | 0x1000);
+			bcm43xx_phy_write(bcm, 0x048A,
+					  (bcm43xx_phy_read(bcm, 0x048A)
+					   & 0x9FFF) | 0x2000);
+			tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+						   BCM43xx_UCODEFLAGS_OFFSET);
+			if (!(tmp32 & 0x800)) {
+				tmp32 |= 0x800;
+				bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+						    BCM43xx_UCODEFLAGS_OFFSET,
+						    tmp32);
+			}
+		}
+		if (phy->rev >= 2) {
+			bcm43xx_phy_write(bcm, 0x042B,
+					  bcm43xx_phy_read(bcm, 0x042B)
+					  | 0x0800);
+		}
+		bcm43xx_phy_write(bcm, 0x048C,
+				  (bcm43xx_phy_read(bcm, 0x048C)
+				   & 0xF0FF) | 0x0200);
+		if (phy->rev == 2) {
+			bcm43xx_phy_write(bcm, 0x04AE,
+					  (bcm43xx_phy_read(bcm, 0x04AE)
+					   & 0xFF00) | 0x007F);
+			bcm43xx_phy_write(bcm, 0x04AD,
+					  (bcm43xx_phy_read(bcm, 0x04AD)
+					   & 0x00FF) | 0x1300);
+		} else if (phy->rev >= 6) {
+			bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F);
+			bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F);
+			bcm43xx_phy_write(bcm, 0x04AD,
+					  bcm43xx_phy_read(bcm, 0x04AD)
+					  & 0x00FF);
+		}
+		bcm43xx_calc_nrssi_slope(bcm);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+static void
+bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm,
+					      int mode)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u32 tmp32;
+	u32 *stack = radio->interfstack;
+
+	switch (mode) {
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			bcm43xx_phy_write(bcm, 0x042B,
+			                  bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+			                  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000);
+			break;
+		}
+		phy_stackrestore(0x0078);
+		bcm43xx_calc_nrssi_threshold(bcm);
+		phy_stackrestore(0x0406);
+		bcm43xx_phy_write(bcm, 0x042B,
+				  bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
+		if (!bcm->bad_frames_preempt) {
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
+					  bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)
+					  & ~(1 << 11));
+		}
+		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+				  bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A7);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		break;
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800))
+			break;
+
+		radio->aci_enable = 0;
+
+		phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD);
+		phy_stackrestore(BCM43xx_PHY_G_CRS);
+		phy_stackrestore(0x0033);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A7);
+		if (phy->rev >= 2) {
+			phy_stackrestore(0x04C0);
+			phy_stackrestore(0x04C1);
+		} else
+			phy_stackrestore(0x0406);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A8);
+		if (phy->rev == 2) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x0415);
+			phy_stackrestore(0x0416);
+			phy_stackrestore(0x0417);
+			ilt_stackrestore(0x1A00 + 0x2);
+			ilt_stackrestore(0x1A00 + 0x3);
+		}
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x042B);
+		phy_stackrestore(0x048C);
+		tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+					   BCM43xx_UCODEFLAGS_OFFSET);
+		if (tmp32 & 0x800) {
+			tmp32 &= ~0x800;
+			bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+					    BCM43xx_UCODEFLAGS_OFFSET,
+					    tmp32);
+		}
+		bcm43xx_calc_nrssi_slope(bcm);
+		break;
+	default:
+		assert(0);
+	}
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ilt_stacksave
+#undef ilt_stackrestore
+
+int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm,
+					      int mode)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	int currentmode;
+
+	if ((phy->type != BCM43xx_PHYTYPE_G) ||
+	    (phy->rev == 0) ||
+	    (!phy->connected))
+		return -ENODEV;
+
+	radio->aci_wlan_automatic = 0;
+	switch (mode) {
+	case BCM43xx_RADIO_INTERFMODE_AUTOWLAN:
+		radio->aci_wlan_automatic = 1;
+		if (radio->aci_enable)
+			mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
+		else
+			mode = BCM43xx_RADIO_INTERFMODE_NONE;
+		break;
+	case BCM43xx_RADIO_INTERFMODE_NONE:
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	currentmode = radio->interfmode;
+	if (currentmode == mode)
+		return 0;
+	if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE)
+		bcm43xx_radio_interference_mitigation_disable(bcm, currentmode);
+
+	if (mode == BCM43xx_RADIO_INTERFMODE_NONE) {
+		radio->aci_enable = 0;
+		radio->aci_hw_rssi = 0;
+	} else
+		bcm43xx_radio_interference_mitigation_enable(bcm, mode);
+	radio->interfmode = mode;
+
+	return 0;
+}
+
+u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
+{
+	u16 reg, index, ret;
+
+	reg = bcm43xx_radio_read16(bcm, 0x0060);
+	index = (reg & 0x001E) >> 1;
+	ret = rcc_table[index] << 1;
+	ret |= (reg & 0x0001);
+	ret |= 0x0020;
+
+	return ret;
+}
+
+u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 backup[19] = { 0 };
+	u16 ret;
+	u16 i, j;
+	u32 tmp1 = 0, tmp2 = 0;
+
+	backup[0] = bcm43xx_radio_read16(bcm, 0x0043);
+	backup[14] = bcm43xx_radio_read16(bcm, 0x0051);
+	backup[15] = bcm43xx_radio_read16(bcm, 0x0052);
+	backup[1] = bcm43xx_phy_read(bcm, 0x0015);
+	backup[16] = bcm43xx_phy_read(bcm, 0x005A);
+	backup[17] = bcm43xx_phy_read(bcm, 0x0059);
+	backup[18] = bcm43xx_phy_read(bcm, 0x0058);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		backup[2] = bcm43xx_phy_read(bcm, 0x0030);
+		backup[3] = bcm43xx_read16(bcm, 0x03EC);
+		bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
+		bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
+	} else {
+		if (phy->connected) {
+			backup[4] = bcm43xx_phy_read(bcm, 0x0811);
+			backup[5] = bcm43xx_phy_read(bcm, 0x0812);
+			backup[6] = bcm43xx_phy_read(bcm, 0x0814);
+			backup[7] = bcm43xx_phy_read(bcm, 0x0815);
+			backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
+			backup[9] = bcm43xx_phy_read(bcm, 0x0802);
+			bcm43xx_phy_write(bcm, 0x0814,
+			                  (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+			bcm43xx_phy_write(bcm, 0x0815,
+			                  (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));	
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
+			                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+			bcm43xx_phy_write(bcm, 0x0802,
+			                  (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
+			bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+			bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+		}
+		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+		                (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
+	}
+	backup[10] = bcm43xx_phy_read(bcm, 0x0035);
+	bcm43xx_phy_write(bcm, 0x0035,
+	                  (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
+	backup[11] = bcm43xx_read16(bcm, 0x03E6);
+	backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
+
+	// Initialization
+	if (phy->version == 0) {
+		bcm43xx_write16(bcm, 0x03E6, 0x0122);
+	} else {
+		if (phy->version >= 2)
+			bcm43xx_write16(bcm, 0x03E6, 0x0040);
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+		                (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+	}
+
+	ret = bcm43xx_radio_calibrationvalue(bcm);
+
+	if (phy->type == BCM43xx_PHYTYPE_B)
+		bcm43xx_radio_write16(bcm, 0x0078, 0x0003);
+
+	bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
+	bcm43xx_phy_write(bcm, 0x002B, 0x1403);
+	if (phy->connected)
+		bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+	bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
+	bcm43xx_radio_write16(bcm, 0x0051,
+	                      (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
+	bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+	bcm43xx_radio_write16(bcm, 0x0043,
+			      bcm43xx_radio_read16(bcm, 0x0043) | 0x0009);
+	bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+
+	for (i = 0; i < 16; i++) {
+		bcm43xx_phy_write(bcm, 0x005A, 0x0480);
+		bcm43xx_phy_write(bcm, 0x0059, 0xC810);
+		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+		udelay(10);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
+		udelay(10);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
+		udelay(10);
+		tmp1 += bcm43xx_phy_read(bcm, 0x002D);
+		bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+		if (phy->connected)
+			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+	}
+
+	tmp1++;
+	tmp1 >>= 9;
+	udelay(10);
+	bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+
+	for (i = 0; i < 16; i++) {
+		bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020);
+		backup[13] = bcm43xx_radio_read16(bcm, 0x0078);
+		udelay(10);
+		for (j = 0; j < 16; j++) {
+			bcm43xx_phy_write(bcm, 0x005A, 0x0D80);
+			bcm43xx_phy_write(bcm, 0x0059, 0xC810);
+			bcm43xx_phy_write(bcm, 0x0058, 0x000D);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+			udelay(10);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
+			udelay(10);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+			bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
+			udelay(10);
+			tmp2 += bcm43xx_phy_read(bcm, 0x002D);
+			bcm43xx_phy_write(bcm, 0x0058, 0x0000);
+			if (phy->connected)
+				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
+		}
+		tmp2++;
+		tmp2 >>= 8;
+		if (tmp1 < tmp2)
+			break;
+	}
+
+	/* Restore the registers */
+	bcm43xx_phy_write(bcm, 0x0015, backup[1]);
+	bcm43xx_radio_write16(bcm, 0x0051, backup[14]);
+	bcm43xx_radio_write16(bcm, 0x0052, backup[15]);
+	bcm43xx_radio_write16(bcm, 0x0043, backup[0]);
+	bcm43xx_phy_write(bcm, 0x005A, backup[16]);
+	bcm43xx_phy_write(bcm, 0x0059, backup[17]);
+	bcm43xx_phy_write(bcm, 0x0058, backup[18]);
+	bcm43xx_write16(bcm, 0x03E6, backup[11]);
+	if (phy->version != 0)
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]);
+	bcm43xx_phy_write(bcm, 0x0035, backup[10]);
+	bcm43xx_radio_selectchannel(bcm, radio->channel, 1);
+	if (phy->type == BCM43xx_PHYTYPE_B) {
+		bcm43xx_phy_write(bcm, 0x0030, backup[2]);
+		bcm43xx_write16(bcm, 0x03EC, backup[3]);
+	} else {
+		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+				(bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
+		if (phy->connected) {
+			bcm43xx_phy_write(bcm, 0x0811, backup[4]);
+			bcm43xx_phy_write(bcm, 0x0812, backup[5]);
+			bcm43xx_phy_write(bcm, 0x0814, backup[6]);
+			bcm43xx_phy_write(bcm, 0x0815, backup[7]);
+			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
+			bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+		}
+	}
+	if (i >= 15)
+		ret = backup[13];
+
+	return ret;
+}
+
+void bcm43xx_radio_init2060(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
+	bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
+	bcm43xx_radio_write16(bcm, 0x0009, 0x0040);
+	bcm43xx_radio_write16(bcm, 0x0005, 0x00AA);
+	bcm43xx_radio_write16(bcm, 0x0032, 0x008F);
+	bcm43xx_radio_write16(bcm, 0x0006, 0x008F);
+	bcm43xx_radio_write16(bcm, 0x0034, 0x008F);
+	bcm43xx_radio_write16(bcm, 0x002C, 0x0007);
+	bcm43xx_radio_write16(bcm, 0x0082, 0x0080);
+	bcm43xx_radio_write16(bcm, 0x0080, 0x0000);
+	bcm43xx_radio_write16(bcm, 0x003F, 0x00DA);
+	bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
+	udelay(400);
+
+	bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010);
+	udelay(400);
+
+	bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008);
+	bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010);
+	bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
+	bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040);
+	bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040);
+	bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008);
+	bcm43xx_phy_write(bcm, 0x0063, 0xDDC6);
+	bcm43xx_phy_write(bcm, 0x0069, 0x07BE);
+	bcm43xx_phy_write(bcm, 0x006A, 0x0000);
+
+	err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0);
+	assert(err == 0);
+	udelay(1000);
+}
+
+static inline
+u16 freq_r3A_value(u16 frequency)
+{
+	u16 value;
+
+	if (frequency < 5091)
+		value = 0x0040;
+	else if (frequency < 5321)
+		value = 0x0000;
+	else if (frequency < 5806)
+		value = 0x0080;
+	else
+		value = 0x0040;
+
+	return value;
+}
+
+void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm)
+{
+	static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+	static const u8 data_low[5]  = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+	u16 tmp = bcm43xx_radio_read16(bcm, 0x001E);
+	int i, j;
+	
+	for (i = 0; i < 5; i++) {
+		for (j = 0; j < 5; j++) {
+			if (tmp == (data_high[i] << 4 | data_low[j])) {
+				bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0);
+				return;
+			}
+		}
+	}
+}
+
+int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
+				u8 channel,
+				int synthetic_pu_workaround)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 r8, tmp;
+	u16 freq;
+
+	if ((radio->manufact == 0x17F) &&
+	    (radio->version == 0x2060) &&
+	    (radio->revision == 1)) {
+		if (channel > 200)
+			return -EINVAL;
+		freq = channel2freq_a(channel);
+
+		r8 = bcm43xx_radio_read16(bcm, 0x0008);
+		bcm43xx_write16(bcm, 0x03F0, freq);
+		bcm43xx_radio_write16(bcm, 0x0008, r8);
+
+		TODO();//TODO: write max channel TX power? to Radio 0x2D
+		tmp = bcm43xx_radio_read16(bcm, 0x002E);
+		tmp &= 0x0080;
+		TODO();//TODO: OR tmp with the Power out estimation for this channel?
+		bcm43xx_radio_write16(bcm, 0x002E, tmp);
+
+		if (freq >= 4920 && freq <= 5500) {
+			/* 
+			 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
+			 *    = (freq * 0.025862069
+			 */
+			r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
+		}
+		bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8);
+		bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8);
+		bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8);
+		bcm43xx_radio_write16(bcm, 0x0022,
+				      (bcm43xx_radio_read16(bcm, 0x0022)
+				       & 0x000F) | (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x0008,
+				      (bcm43xx_radio_read16(bcm, 0x0008)
+				       & 0x00F0) | (r8 << 4));
+		bcm43xx_radio_write16(bcm, 0x0029,
+				      (bcm43xx_radio_read16(bcm, 0x0029)
+				       & 0xFF0F) | 0x00B0);
+		bcm43xx_radio_write16(bcm, 0x0035, 0x00AA);
+		bcm43xx_radio_write16(bcm, 0x0036, 0x0085);
+		bcm43xx_radio_write16(bcm, 0x003A,
+				      (bcm43xx_radio_read16(bcm, 0x003A)
+				       & 0xFF20) | freq_r3A_value(freq));
+		bcm43xx_radio_write16(bcm, 0x003D,
+				      bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF);
+		bcm43xx_radio_write16(bcm, 0x0081,
+				      (bcm43xx_radio_read16(bcm, 0x0081)
+				       & 0xFF7F) | 0x0080);
+		bcm43xx_radio_write16(bcm, 0x0035,
+				      bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF);
+		bcm43xx_radio_write16(bcm, 0x0035,
+				      (bcm43xx_radio_read16(bcm, 0x0035)
+				       & 0xFFEF) | 0x0010);
+		bcm43xx_radio_set_tx_iq(bcm);
+		TODO();	//TODO:	TSSI2dbm workaround
+		bcm43xx_phy_xmitpower(bcm);//FIXME correct?
+	} else {
+		if ((channel < 1) || (channel > 14))
+			return -EINVAL;
+
+		if (synthetic_pu_workaround)
+			bcm43xx_synth_pu_workaround(bcm, channel);
+
+		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
+				channel2freq_bg(channel));
+
+		if (channel == 14) {
+			if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) {
+				bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+						    BCM43xx_UCODEFLAGS_OFFSET,
+						    bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+								       BCM43xx_UCODEFLAGS_OFFSET)
+						    & ~(1 << 7));
+			} else {
+				bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+						    BCM43xx_UCODEFLAGS_OFFSET,
+						    bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+								       BCM43xx_UCODEFLAGS_OFFSET)
+						    | (1 << 7));
+			}
+			bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+					bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+					| (1 << 11));
+		} else {
+			bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
+					bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+					& 0xF7BF);
+		}
+	}
+
+	radio->channel = channel;
+	//XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
+	//     that 2000 usecs might suffice.
+	udelay(8000);
+
+	return 0;
+}
+
+void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val)
+{
+	u16 tmp;
+
+	val <<= 8;
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF;
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val);
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF;
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val);
+	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF;
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val);
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 bcm43xx_get_txgain_base_band(u16 txpower)
+{
+	u16 ret;
+
+	assert(txpower <= 63);
+
+	if (txpower >= 54)
+		ret = 2;
+	else if (txpower >= 49)
+		ret = 4;
+	else if (txpower >= 44)
+		ret = 5;
+	else
+		ret = 6;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower)
+{
+	u16 ret;
+
+	assert(txpower <= 63);
+
+	if (txpower >= 32)
+		ret = 0;
+	else if (txpower >= 25)
+		ret = 1;
+	else if (txpower >= 20)
+		ret = 2;
+	else if (txpower >= 12)
+		ret = 3;
+	else
+		ret = 4;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 bcm43xx_get_txgain_dac(u16 txpower)
+{
+	u16 ret;
+
+	assert(txpower <= 63);
+
+	if (txpower >= 54)
+		ret = txpower - 53;
+	else if (txpower >= 49)
+		ret = txpower - 42;
+	else if (txpower >= 44)
+		ret = txpower - 37;
+	else if (txpower >= 32)
+		ret = txpower - 32;
+	else if (txpower >= 25)
+		ret = txpower - 20;
+	else if (txpower >= 20)
+		ret = txpower - 13;
+	else if (txpower >= 12)
+		ret = txpower - 8;
+	else
+		ret = txpower;
+
+	return ret;
+}
+
+void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 pamp, base, dac, ilt;
+
+	txpower = limit_value(txpower, 0, 63);
+
+	pamp = bcm43xx_get_txgain_freq_power_amp(txpower);
+	pamp <<= 5;
+	pamp &= 0x00E0;
+	bcm43xx_phy_write(bcm, 0x0019, pamp);
+
+	base = bcm43xx_get_txgain_base_band(txpower);
+	base &= 0x000F;
+	bcm43xx_phy_write(bcm, 0x0017, base | 0x0020);
+
+	ilt = bcm43xx_ilt_read(bcm, 0x3001);
+	ilt &= 0x0007;
+
+	dac = bcm43xx_get_txgain_dac(txpower);
+	dac <<= 3;
+	dac |= ilt;
+
+	bcm43xx_ilt_write(bcm, 0x3001, dac);
+
+	radio->txpwr_offset = txpower;
+
+	TODO();
+	//TODO: FuncPlaceholder (Adjust BB loft cancel)
+}
+
+void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
+                                 u16 baseband_attenuation, u16 radio_attenuation,
+                                 u16 txpower)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	if (baseband_attenuation == 0xFFFF)
+		baseband_attenuation = radio->baseband_atten;
+	if (radio_attenuation == 0xFFFF)
+		radio_attenuation = radio->radio_atten;
+	if (txpower == 0xFFFF)
+		txpower = radio->txctl1;
+	radio->baseband_atten = baseband_attenuation;
+	radio->radio_atten = radio_attenuation;
+	radio->txctl1 = txpower;
+
+	assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11);
+	if (radio->revision < 6)
+		assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9);
+	else
+		assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31);
+	assert(/*txpower >= 0 &&*/ txpower <= 7);
+
+	bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation);
+	bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation);
+	if (radio->version == 0x2050) {
+		bcm43xx_radio_write16(bcm, 0x0052,
+		                      (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070)
+				       | ((txpower << 4) & 0x0070));
+	}
+	//FIXME: The spec is very weird and unclear here.
+	if (phy->type == BCM43xx_PHYTYPE_G)
+		bcm43xx_phy_lo_adjust(bcm, 0);
+}
+
+u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (radio->version == 0x2050 && radio->revision < 6)
+		return 0;
+	return 2;
+}
+
+u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 att = 0xFFFF;
+
+	if (phy->type == BCM43xx_PHYTYPE_A)
+		return 0x60;
+
+	switch (radio->version) {
+	case 0x2053:
+		switch (radio->revision) {
+		case 1:
+			att = 6;
+			break;
+		}
+		break;
+	case 0x2050:
+		switch (radio->revision) {
+		case 0:
+			att = 5;
+			break;
+		case 1:
+			if (phy->type == BCM43xx_PHYTYPE_G) {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 3;
+				else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+					 bcm->board_type == 0x416)
+					att = 3;
+				else
+					att = 1;
+			} else {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 7;
+				else
+					att = 6;
+			}
+			break;
+		case 2:
+			if (phy->type == BCM43xx_PHYTYPE_G) {
+				if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+				    bcm->board_type == 0x421 &&
+				    bcm->board_revision >= 30)
+					att = 3;
+				else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+					 bcm->board_type == 0x416)
+					att = 5;
+				else if (bcm->chip_id == 0x4320)
+					att = 4;
+				else
+					att = 3;
+			} else
+				att = 6;
+			break;
+		case 3:
+			att = 5;
+			break;
+		case 4:
+		case 5:
+			att = 1;
+			break;
+		case 6:
+		case 7:
+			att = 5;
+			break;
+		case 8:
+			att = 0x1A;
+			break;
+		case 9:
+		default:
+			att = 5;
+		}
+	}
+	if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
+	    bcm->board_type == 0x421) {
+		if (bcm->board_revision < 0x43)
+			att = 2;
+		else if (bcm->board_revision < 0x51)
+			att = 3;
+	}
+	if (att == 0xFFFF)
+		att = 5;
+
+	return att;
+}
+
+u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (radio->version != 0x2050)
+		return 0;
+	if (radio->revision == 1)
+		return 3;
+	if (radio->revision < 6)
+		return 2;
+	if (radio->revision == 8)
+		return 1;
+	return 0;
+}
+
+void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	int err;
+
+	if (radio->enabled)
+		return;
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
+		bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
+		bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7);
+		bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7);
+		bcm43xx_radio_init2060(bcm);	
+		break;
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_phy_write(bcm, 0x0015, 0x8000);
+		bcm43xx_phy_write(bcm, 0x0015, 0xCC00);
+		bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000));
+		err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1);
+		assert(err == 0);
+		break;
+	default:
+		assert(0);
+	}
+	radio->enabled = 1;
+	dprintk(KERN_INFO PFX "Radio turned on\n");
+}
+	
+void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+
+	if (phy->type == BCM43xx_PHYTYPE_A) {
+		bcm43xx_radio_write16(bcm, 0x0004, 0x00FF);
+		bcm43xx_radio_write16(bcm, 0x0005, 0x00FB);
+		bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008);
+		bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008);
+	}
+	if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) {
+		bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C);
+		bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73);
+	} else
+		bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
+	radio->enabled = 0;
+	dprintk(KERN_INFO PFX "Radio turned off\n");
+}
+
+void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
+	switch (phy->type) {
+	case BCM43xx_PHYTYPE_A:
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F);
+		break;
+	case BCM43xx_PHYTYPE_B:
+	case BCM43xx_PHYTYPE_G:
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F);
+		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F);
+		break;
+	}
+}

+ 99 - 0
drivers/net/wireless/bcm43xx/bcm43xx_radio.h

@@ -0,0 +1,99 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mbuesch@freenet.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 2004 Intel Corporation.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef BCM43xx_RADIO_H_
+#define BCM43xx_RADIO_H_
+
+#include "bcm43xx.h"
+
+
+#define BCM43xx_RADIO_DEFAULT_CHANNEL_A		36
+#define BCM43xx_RADIO_DEFAULT_CHANNEL_BG	6
+
+/* Force antenna 0. */
+#define BCM43xx_RADIO_TXANTENNA_0		0
+/* Force antenna 1. */
+#define BCM43xx_RADIO_TXANTENNA_1		1
+/* Use the RX antenna, that was selected for the most recently
+ * received good PLCP header.
+ */
+#define BCM43xx_RADIO_TXANTENNA_LASTPLCP	3
+#define BCM43xx_RADIO_TXANTENNA_DEFAULT		BCM43xx_RADIO_TXANTENNA_LASTPLCP
+
+#define BCM43xx_RADIO_INTERFMODE_NONE		0
+#define BCM43xx_RADIO_INTERFMODE_NONWLAN	1
+#define BCM43xx_RADIO_INTERFMODE_MANUALWLAN	2
+#define BCM43xx_RADIO_INTERFMODE_AUTOWLAN	3
+
+
+void bcm43xx_radio_lock(struct bcm43xx_private *bcm);
+void bcm43xx_radio_unlock(struct bcm43xx_private *bcm);
+
+u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset);
+void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val);
+
+u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm);
+void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
+
+void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
+void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
+
+int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
+				int synthetic_pu_workaround);
+
+void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower);
+void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
+                               u16 baseband_attenuation, u16 attenuation,
+			       u16 txpower);
+
+u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm);
+u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm);
+u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm);
+
+void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val);
+
+void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm);
+
+u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel);
+u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm);
+
+int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode);
+
+void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm);
+void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm);
+s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset);
+void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val);
+void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val);
+void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm);
+
+void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm);
+u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm);
+
+#endif /* BCM43xx_RADIO_H_ */

+ 322 - 0
drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c

@@ -0,0 +1,322 @@
+/*
+
+  Broadcom BCM43xx wireless driver
+
+  SYSFS support routines
+
+  Copyright (c) 2006 Michael Buesch <mbuesch@freenet.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "bcm43xx_sysfs.h"
+#include "bcm43xx.h"
+#include "bcm43xx_main.h"
+#include "bcm43xx_radio.h"
+
+#include <linux/capability.h>
+
+
+#define GENERIC_FILESIZE	64
+
+
+static int get_integer(const char *buf, size_t count)
+{
+	char tmp[10 + 1] = { 0 };
+	int ret = -EINVAL;
+
+	if (count == 0)
+		goto out;
+	count = min(count, (size_t)10);
+	memcpy(tmp, buf, count);
+	ret = simple_strtol(tmp, NULL, 10);
+out:
+	return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+	if (count != 0) {
+		if (buf[0] == '1')
+			return 1;
+		if (buf[0] == '0')
+			return 0;
+		if (count >= 4 && memcmp(buf, "true", 4) == 0)
+			return 1;
+		if (count >= 5 && memcmp(buf, "false", 5) == 0)
+			return 0;
+		if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+			return 1;
+		if (count >= 2 && memcmp(buf, "no", 2) == 0)
+			return 0;
+		if (count >= 2 && memcmp(buf, "on", 2) == 0)
+			return 1;
+		if (count >= 3 && memcmp(buf, "off", 3) == 0)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom);
+	u16 *sprom;
+	unsigned long flags;
+	int i, err;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE);
+	sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
+			GFP_KERNEL);
+	if (!sprom)
+		return -ENOMEM;
+	bcm43xx_lock_mmio(bcm, flags);
+	assert(bcm->initialized);
+	err = bcm43xx_sprom_read(bcm, sprom);
+	if (!err) {
+		for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
+			buf[i * 2] = sprom[i] & 0x00FF;
+			buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8;
+		}
+	}
+	bcm43xx_unlock_mmio(bcm, flags);
+	kfree(sprom);
+
+	return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16);
+}
+
+static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom);
+	u16 *sprom;
+	unsigned long flags;
+	int i, err;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (count != BCM43xx_SPROM_SIZE * sizeof(u16))
+		return -EINVAL;
+	sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
+			GFP_KERNEL);
+	if (!sprom)
+		return -ENOMEM;
+	for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
+		sprom[i] = buf[i * 2] & 0xFF;
+		sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8;
+	}
+	bcm43xx_lock_mmio(bcm, flags);
+	assert(bcm->initialized);
+	err = bcm43xx_sprom_write(bcm, sprom);
+	bcm43xx_unlock_mmio(bcm, flags);
+	kfree(sprom);
+
+	return err ? err : count;
+
+}
+
+static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode);
+	unsigned long flags;
+	int err;
+	ssize_t count = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bcm43xx_lock(bcm, flags);
+	assert(bcm->initialized);
+
+	switch (bcm43xx_current_radio(bcm)->interfmode) {
+	case BCM43xx_RADIO_INTERFMODE_NONE:
+		count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n");
+		break;
+	case BCM43xx_RADIO_INTERFMODE_NONWLAN:
+		count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n");
+		break;
+	case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
+		count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n");
+		break;
+	default:
+		assert(0);
+	}
+	err = 0;
+
+	bcm43xx_unlock(bcm, flags);
+
+	return err ? err : count;
+
+}
+
+static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode);
+	unsigned long flags;
+	int err;
+	int mode;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mode = get_integer(buf, count);
+	switch (mode) {
+	case 0:
+		mode = BCM43xx_RADIO_INTERFMODE_NONE;
+		break;
+	case 1:
+		mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
+		break;
+	case 2:
+		mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
+		break;
+	case 3:
+		mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	bcm43xx_lock_mmio(bcm, flags);
+	assert(bcm->initialized);
+
+	err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
+	if (err) {
+		printk(KERN_ERR PFX "Interference Mitigation not "
+				    "supported by device\n");
+	}
+
+	bcm43xx_unlock_mmio(bcm, flags);
+
+	return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble);
+	unsigned long flags;
+	int err;
+	ssize_t count;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bcm43xx_lock(bcm, flags);
+	assert(bcm->initialized);
+
+	if (bcm->short_preamble)
+		count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
+	else
+		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
+
+	err = 0;
+	bcm43xx_unlock(bcm, flags);
+
+	return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble);
+	unsigned long flags;
+	int err;
+	int value;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	value = get_boolean(buf, count);
+	if (value < 0)
+		return value;
+	bcm43xx_lock(bcm, flags);
+	assert(bcm->initialized);
+
+	bcm->short_preamble = !!value;
+
+	err = 0;
+	bcm43xx_unlock(bcm, flags);
+
+	return err ? err : count;
+}
+
+int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
+{
+	struct device *dev = &bcm->pci_dev->dev;
+	struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
+	int err;
+
+	assert(bcm->initialized);
+
+	sysfs->attr_sprom.attr.name = "sprom";
+	sysfs->attr_sprom.attr.owner = THIS_MODULE;
+	sysfs->attr_sprom.attr.mode = 0600;
+	sysfs->attr_sprom.show = bcm43xx_attr_sprom_show;
+	sysfs->attr_sprom.store = bcm43xx_attr_sprom_store;
+	err = device_create_file(dev, &sysfs->attr_sprom);
+	if (err)
+		goto out;
+
+	sysfs->attr_interfmode.attr.name = "interference";
+	sysfs->attr_interfmode.attr.owner = THIS_MODULE;
+	sysfs->attr_interfmode.attr.mode = 0600;
+	sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show;
+	sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store;
+	err = device_create_file(dev, &sysfs->attr_interfmode);
+	if (err)
+		goto err_remove_sprom;
+
+	sysfs->attr_preamble.attr.name = "shortpreamble";
+	sysfs->attr_preamble.attr.owner = THIS_MODULE;
+	sysfs->attr_preamble.attr.mode = 0600;
+	sysfs->attr_preamble.show = bcm43xx_attr_preamble_show;
+	sysfs->attr_preamble.store = bcm43xx_attr_preamble_store;
+	err = device_create_file(dev, &sysfs->attr_preamble);
+	if (err)
+		goto err_remove_interfmode;
+
+out:
+	return err;
+err_remove_interfmode:
+	device_remove_file(dev, &sysfs->attr_interfmode);
+err_remove_sprom:
+	device_remove_file(dev, &sysfs->attr_sprom);
+	goto out;
+}
+
+void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
+{
+	struct device *dev = &bcm->pci_dev->dev;
+	struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
+
+	device_remove_file(dev, &sysfs->attr_preamble);
+	device_remove_file(dev, &sysfs->attr_interfmode);
+	device_remove_file(dev, &sysfs->attr_sprom);
+}

Some files were not shown because too many files changed in this diff