netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Sonics Silicon Backplane driver
@ 2006-08-23  9:58 Michael Buesch
       [not found] ` <200608231158.06178.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Buesch @ 2006-08-23  9:58 UTC (permalink / raw)
  To: linville-2XuSBdqkA4R54TAoqtyWWQ
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bcm43xx-dev-0fE9KPoRgkgATYTw5x5z8w

Hi,

This patch series adds a lowlevel driver for the
Sonics Silicon Backplane (short ssb). The ssb is used
in some broadcom devices such as bcm43xx and bcm44xx.

The ssb is a common backplane to host several operating
"cores". It's responsible to manage these "cores".

John, please apply this patch series to wireless-dev.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] Add Sonics Silicon Backplane driver
       [not found] ` <200608231158.06178.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>
@ 2006-08-23  9:59   ` Michael Buesch
  2006-08-23 10:59     ` Martin Michlmayr
  2006-08-23 10:01   ` [PATCH 2/2] bcm43xx: convert driver to use ssb Michael Buesch
  1 sibling, 1 reply; 7+ messages in thread
From: Michael Buesch @ 2006-08-23  9:59 UTC (permalink / raw)
  To: linville-2XuSBdqkA4R54TAoqtyWWQ
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bcm43xx-dev-0fE9KPoRgkgATYTw5x5z8w

This patch adds a Sonics Silicon Backplane driver backend
that can be used by ssb based device drivers auch as bcm43xx
and b44.

Signed-off-by: Michael Buesch <mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>

Index: wireless-dev/drivers/misc/Kconfig
===================================================================
--- wireless-dev.orig/drivers/misc/Kconfig	2006-08-21 22:45:56.000000000 +0200
+++ wireless-dev/drivers/misc/Kconfig	2006-08-22 21:07:01.000000000 +0200
@@ -28,5 +28,9 @@
 
 	  If unsure, say N.
 
+config SONICS_SILICON_BACKPLANE
+	tristate
+	depends on PCI
+
 endmenu
 
Index: wireless-dev/drivers/misc/Makefile
===================================================================
--- wireless-dev.orig/drivers/misc/Makefile	2006-08-21 22:45:56.000000000 +0200
+++ wireless-dev/drivers/misc/Makefile	2006-08-21 22:47:10.000000000 +0200
@@ -3,5 +3,6 @@
 #
 obj- := misc.o	# Dummy rule to force built-in.o to be made
 
-obj-$(CONFIG_IBM_ASM)	+= ibmasm/
-obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
+obj-$(CONFIG_IBM_ASM)			+= ibmasm/
+obj-$(CONFIG_HDPU_FEATURES)		+= hdpuftrs/
+obj-$(CONFIG_SONICS_SILICON_BACKPLANE)	+= ssb.o
Index: wireless-dev/drivers/misc/ssb.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/drivers/misc/ssb.c	2006-08-23 10:58:06.000000000 +0200
@@ -0,0 +1,1015 @@
+/*
+ * Sonics Silicon Backplane backend.
+ *
+ * Copyright (C) 2005-2006 Michael Buesch <mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>
+ * Copyright (C) 2005 Martin Langer <martin-langer-Mmb7MZpHnFY@public.gmane.org>
+ * Copyright (C) 2005 Stefano Brivio <st3-sGOZH3hwPm2sTnJN9+BGXg@public.gmane.org>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi-xegAWGFB9mQXXHkOk0aIfQ@public.gmane.org>
+ *
+ * Derived from the Broadcom 4400 device driver.
+ * Copyright (C) 2002 David S. Miller (davem-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org)
+ * Fixed by Pekka Pietikainen (pp-YuCZbdju05vHOG6cAo2yLw@public.gmane.org)
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+
+#define SSB_DEBUG	0
+#define PFX		"ssb: "
+
+
+#if SSB_DEBUG
+# define dprintk(f, x...)	do { printk(f ,##x); } while (0)
+# 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 dprintk(f, x...)	do { /* nothing */ } while (0)
+# define assert(expr)		do { if (expr) { /* nothing */ } } while (0)
+#endif
+
+
+static inline int ssb_pci_read_config32(struct ssb *ssb, int offset,
+					u32 *value)
+{
+	return pci_read_config_dword(ssb->pci_dev, offset, value);
+}
+
+static inline int ssb_pci_read_config16(struct ssb *ssb, int offset,
+					u16 *value)
+{
+	return pci_read_config_word(ssb->pci_dev, offset, value);
+}
+
+static inline int ssb_pci_write_config32(struct ssb *ssb, int offset,
+					 u32 value)
+{
+	return pci_write_config_dword(ssb->pci_dev, offset, value);
+}
+
+static inline u32 ssb_read32(struct ssb *ssb, u16 offset)
+{
+	return ioread32(ssb->mmio + offset + ssb_core_offset(ssb));
+}
+
+static inline void ssb_write32(struct ssb *ssb, u16 offset,
+			       u32 value)
+{
+	iowrite32(value, ssb->mmio + offset + ssb_core_offset(ssb));
+}
+
+static inline u16 ssb_read16(struct ssb *ssb, u16 offset)
+{
+	return ioread16(ssb->mmio + offset + ssb_core_offset(ssb));
+}
+
+static inline void ssb_write16(struct ssb *ssb, u16 offset,
+			       u16 value)
+{
+	iowrite16(value, ssb->mmio + offset + ssb_core_offset(ssb));
+}
+
+
+static inline u8 ssb_crc8(u8 crc, u8 data)
+{
+	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
+	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];
+}
+
+#define SPOFF(offset)	(((offset) - SSB_SPROM_BASE) / sizeof(u16))
+
+static u8 ssb_sprom_crc(const u16 *sprom)
+{
+	int word;
+	u8 crc = 0xFF;
+
+	for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
+		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
+		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+	}
+	crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
+	crc ^= 0xFF;
+
+	return crc;
+}
+
+static void sprom_do_read(struct ssb *ssb, u16 *sprom)
+{
+	int i;
+
+	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
+		sprom[i] = ssb_read16(ssb, SSB_SPROM_BASE + (i * 2));
+}
+
+static int sprom_do_write(struct ssb *ssb, const u16 *sprom)
+{
+	int i, err;
+	u32 spromctl;
+
+	printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+	err = ssb_pci_read_config32(ssb, SSB_SPROMCTL, &spromctl);
+	if (err)
+		goto err_ctlreg;
+	spromctl |= SSB_SPROMCTL_WE;
+	ssb_pci_write_config32(ssb, SSB_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	printk(KERN_INFO PFX "[ 0%%");
+	msleep(500);
+	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+		if (i == SSB_SPROMSIZE_WORDS / 4)
+			printk("25%%");
+		else if (i == SSB_SPROMSIZE_WORDS / 2)
+			printk("50%%");
+		else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
+			printk("75%%");
+		else if (i % 2)
+			printk(".");
+		ssb_write16(ssb, SSB_SPROM_BASE + (i * 2), sprom[i]);
+		mmiowb();
+		msleep(20);
+	}
+	err = ssb_pci_read_config32(ssb, SSB_SPROMCTL, &spromctl);
+	if (err)
+		goto err_ctlreg;
+	spromctl &= ~SSB_SPROMCTL_WE;
+	err = ssb_pci_write_config32(ssb, SSB_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	msleep(500);
+	printk("100%% ]\n");
+	printk(KERN_INFO PFX "SPROM written.\n");
+
+out:
+	return err;
+err_ctlreg:
+	printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+	goto out;
+}
+
+static int sprom_check_crc(const u16 *sprom)
+{
+	u8 crc;
+	u8 expected_crc;
+	u16 tmp;
+
+	crc = ssb_sprom_crc(sprom);
+	tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
+	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+	if (crc != expected_crc)
+		return -EPROTO;
+
+	return 0;
+}
+
+static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
+{
+	int i;
+	u16 v;
+
+#define SPEX(_outvar, _offset, _mask, _shift)	\
+	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
+
+	SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
+	SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
+	SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
+		*(((u16 *)out->il0mac) + i) = cpu_to_be16(v);
+	}
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
+		*(((u16 *)out->et0mac) + i) = cpu_to_be16(v);
+	}
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
+		*(((u16 *)out->et1mac) + i) = cpu_to_be16(v);
+	}
+	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
+	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
+	     SSB_SPROM1_ETHPHY_ET1A_SHIFT);
+	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
+	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
+	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
+	SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
+	     SSB_SPROM1_BINF_CCODE_SHIFT);
+	SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
+	     SSB_SPROM1_BINF_ANTA_SHIFT);
+	SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
+	     SSB_SPROM1_BINF_ANTBG_SHIFT);
+	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
+	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
+	SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
+	SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
+	SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
+	SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
+	SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
+	SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
+	     SSB_SPROM1_GPIOA_P1_SHIFT);
+	SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
+	SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
+	     SSB_SPROM1_GPIOB_P3_SHIFT);
+	SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, 0);
+	SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG,
+	     SSB_SPROM1_MAXPWR_BG_SHIFT);
+	SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, 0);
+	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG,
+	     SSB_SPROM1_ITSSI_BG_SHIFT);
+	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
+	SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
+	SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
+	     SSB_SPROM1_AGAIN_BG_SHIFT);
+	for (i = 0; i < 4; i++) {
+		v = in[SPOFF(SSB_SPROM1_OEM) + i];
+		*(((u16 *)out->oem) + i) = cpu_to_le16(v);
+	}
+}
+
+static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
+{
+	int i;
+	u16 v;
+
+	SPEX(boardflags_hi, SSB_SPROM2_BFLHI,  0xFFFF, 0);
+	SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
+	SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
+	     SSB_SPROM2_MAXP_A_LO_SHIFT);
+	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
+	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
+	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
+	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
+	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
+	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
+	SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
+	for (i = 0; i < 4; i++) {
+		v = in[SPOFF(SSB_SPROM2_CCODE) + i];
+		*(((u16 *)out->country_str) + i) = cpu_to_le16(v);
+	}
+}
+
+static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
+{
+	out->ofdmapo  = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
+	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
+	out->ofdmapo <<= 16;
+	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
+	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
+
+	out->ofdmalpo  = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
+	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
+	out->ofdmalpo <<= 16;
+	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
+	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
+
+	out->ofdmahpo  = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
+	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
+	out->ofdmahpo <<= 16;
+	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
+	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
+
+	SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
+	     SSB_SPROM3_GPIOLDC_ON_SHIFT);
+	SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
+	     SSB_SPROM3_GPIOLDC_OFF_SHIFT);
+	SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
+	SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
+	     SSB_SPROM3_CCKPO_2M_SHIFT);
+	SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
+	     SSB_SPROM3_CCKPO_55M_SHIFT);
+	SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
+	     SSB_SPROM3_CCKPO_11M_SHIFT);
+
+	out->ofdmgpo  = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
+	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
+	out->ofdmgpo <<= 16;
+	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
+	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
+}
+
+static int sprom_extract(struct ssb_sprom *out, const u16 *in)
+{
+	memset(out, 0, sizeof(*out));
+
+	SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
+	SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
+	     SSB_SPROM_REVISION_CRC_SHIFT);
+
+	if (out->revision == 0)
+		return -EOPNOTSUPP;
+	if (out->revision >= 1 && out->revision <= 3)
+		sprom_extract_r1(&out->r1, in);
+	if (out->revision >= 2 && out->revision <= 3)
+		sprom_extract_r2(&out->r2, in);
+	if (out->revision == 3)
+		sprom_extract_r3(&out->r3, in);
+	if (out->revision >= 4)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+int ssb_sprom_read(struct ssb *ssb, struct ssb_sprom *sprom, int force)
+{
+	int err = -ENOMEM;
+	u16 *buf;
+
+	buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	if (!buf)
+		goto out;
+	sprom_do_read(ssb, buf);
+	err = sprom_check_crc(buf);
+	if (err) {
+		printk(KERN_ERR PFX "Invalid SPROM CRC (corrupt SPROM)\n");
+		if (!force)
+			goto out_kfree;
+	}
+	err = sprom_extract(sprom, buf);
+	if (err)
+		goto out_kfree;
+
+out_kfree:
+	kfree(buf);
+out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(ssb_sprom_read);
+
+
+static struct list_head ssb_list = LIST_HEAD_INIT(ssb_list);
+static DEFINE_MUTEX(ssb_list_mutex);
+
+static struct ssb * device_to_ssb(struct device *dev)
+{
+	struct ssb *ssb = NULL;
+
+	mutex_lock(&ssb_list_mutex);
+	list_for_each_entry(ssb, &ssb_list, list) {
+		if (&ssb->pci_dev->dev == dev)
+			break;
+	}
+	mutex_unlock(&ssb_list_mutex);
+
+	return ssb;
+}
+
+static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
+{
+	int i, pos = 0;
+
+	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+		pos += snprintf(buf + pos, buf_len - pos - 1,
+				"%04X", swab16(sprom[i]) & 0xFFFF);
+	}
+	pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
+
+	return pos + 1;
+}
+
+static int hex2sprom(u16 *sprom, const char *dump, size_t len)
+{
+	char tmp[5] = { 0 };
+	int cnt = 0;
+	unsigned long parsed;
+
+	if (len < SSB_SPROMSIZE_BYTES * 2)
+		return -EINVAL;
+
+	while (cnt < SSB_SPROMSIZE_WORDS) {
+		memcpy(tmp, dump, 4);
+		dump += 4;
+		parsed = simple_strtoul(tmp, NULL, 16);
+		sprom[cnt++] = swab16((u16)parsed);
+	}
+
+	return 0;
+}
+
+static ssize_t ssb_attr_sprom_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct ssb *ssb;
+	int err = -ENODEV;
+	ssize_t count = 0;
+	u16 *sprom;
+
+	ssb = device_to_ssb(dev);
+	if (!ssb)
+		goto out;
+	err = -ENOMEM;
+	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	if (!sprom)
+		goto out;
+
+	err = -ERESTARTSYS;
+	if (mutex_lock_interruptible(&ssb->mutex))
+		goto out_kfree;
+	sprom_do_read(ssb, sprom);
+	mutex_unlock(&ssb->mutex);
+
+	count = sprom2hex(sprom, buf, PAGE_SIZE);
+	err = 0;
+
+out_kfree:
+	kfree(sprom);
+out:
+	return (err ? err : count);
+}
+
+static ssize_t ssb_attr_sprom_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct ssb *ssb;
+	int err = -ENODEV;
+	u16 *sprom;
+
+	ssb = device_to_ssb(dev);
+	if (!ssb)
+		goto out;
+	err = -ENOMEM;
+	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	if (!sprom)
+		goto out;
+	err = hex2sprom(sprom, buf, count);
+	if (err)
+		goto out_kfree;
+	err = sprom_check_crc(sprom);
+	if (err) {
+		err = -EINVAL;
+		goto out_kfree;
+	}
+
+	err = -ERESTARTSYS;
+	if (mutex_lock_interruptible(&ssb->suspend_mutex))
+		goto out_kfree;
+	err = ssb->device_suspend(ssb);
+	if (err)
+		goto out_unlock_susp;
+	err = -ERESTARTSYS;
+	if (mutex_lock_interruptible(&ssb->mutex))
+		goto out_unlock_susp;
+	err = sprom_do_write(ssb, sprom);
+	mutex_unlock(&ssb->mutex);
+	err = ssb->device_resume(ssb);
+	if (err)
+		goto out_unlock_susp;
+out_unlock_susp:
+	mutex_unlock(&ssb->suspend_mutex);
+out_kfree:
+	kfree(sprom);
+out:
+	return (err ? err : count);
+}
+
+static DEVICE_ATTR(ssb_sprom, 0600,
+		   ssb_attr_sprom_show,
+		   ssb_attr_sprom_store);
+
+int ssb_init(struct ssb *ssb,
+	     struct pci_dev *pci_dev,
+	     void __iomem *mmio,
+	     int (*device_suspend)(struct ssb *ssb),
+	     int (*device_resume)(struct ssb *ssb))
+{
+	int err;
+
+	if (!ssb || !pci_dev || !device_suspend || !device_resume)
+		return -EINVAL;
+
+	memset(ssb, 0, sizeof(*ssb));
+	ssb->pci_dev = pci_dev;
+	ssb->mmio = mmio;
+	ssb->device_suspend = device_suspend;
+	ssb->device_resume = device_resume;
+	mutex_init(&ssb->mutex);
+	mutex_init(&ssb->suspend_mutex);
+	INIT_LIST_HEAD(&ssb->list);
+
+	mutex_lock(&ssb_list_mutex);
+	list_add(&ssb->list, &ssb_list);
+	mutex_unlock(&ssb_list_mutex);
+
+	err = device_create_file(&pci_dev->dev, &dev_attr_ssb_sprom);
+	if (err)
+		goto out;
+
+out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(ssb_init);
+
+void ssb_exit(struct ssb *ssb)
+{
+	device_remove_file(&ssb->pci_dev->dev, &dev_attr_ssb_sprom);
+
+	mutex_lock(&ssb_list_mutex);
+	list_del(&ssb->list);
+	mutex_unlock(&ssb_list_mutex);
+
+	kfree(ssb->cores);
+	if (SSB_DEBUG)
+		memset(ssb, 0x5B, sizeof(*ssb));
+}
+EXPORT_SYMBOL_GPL(ssb_exit);
+
+static int do_switch_core(struct ssb *ssb, u8 coreidx)
+{
+	int err;
+	int attempts = 0;
+	u32 cur_core;
+
+	while (1) {
+		err = ssb_pci_write_config32(ssb, SSB_BAR0_WIN,
+					     (coreidx * 0x1000) + 0x18000000);
+		if (unlikely(err))
+			goto error;
+		err = ssb_pci_read_config32(ssb, SSB_BAR0_WIN,
+					    &cur_core);
+		if (unlikely(err))
+			goto error;
+		cur_core = (cur_core - 0x18000000) / 0x1000;
+		if (cur_core == coreidx)
+			break;
+
+		if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
+			goto error;
+		msleep(1);
+	}
+#ifdef CONFIG_BCM947XX
+	ssb->current_core_offset = 0;
+	if (ssb->pci_dev->bus->number == 0)
+		ssb->current_core_offset = 0x1000 * coreidx;
+#endif /* CONFIG_BCM947XX */
+
+	return 0;
+error:
+	printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+	return -ENODEV;
+}
+
+int ssb_switch_core_locked(struct ssb *ssb,
+			   struct ssb_core *new_core)
+{
+	int err = 0;
+
+	if (unlikely(!new_core))
+		return -EINVAL;
+	if (ssb->current_core != new_core) {
+		err = do_switch_core(ssb, new_core->index);
+		if (likely(!err))
+			ssb->current_core = new_core;
+	}
+
+	return err;
+}
+
+int ssb_switch_core(struct ssb *ssb,
+		    struct ssb_core *new_core)
+{
+	int err;
+
+	mutex_lock(&ssb->mutex);
+	err = ssb_switch_core_locked(ssb, new_core);
+	mutex_unlock(&ssb->mutex);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ssb_switch_core);
+
+int ssb_probe_cores(struct ssb *ssb,
+		    u16 chipid_fallback,
+		    const struct ssb_nrcores_elem *nrcores_fallback,
+		    size_t nrcores_fb_size)
+{
+	struct ssb_core *core;
+	int err;
+	u32 idhi;
+	u32 cc, rev;
+	u32 tmp;
+	int i;
+
+	WARN_ON(ssb->cores);
+
+	mutex_lock(&ssb->mutex);
+
+	err = do_switch_core(ssb, 0);
+	if (err)
+		goto error;
+
+	idhi = ssb_read32(ssb, SSB_IDHIGH);
+	cc = (idhi & SSB_IDHIGH_CC_MASK) >> SSB_IDHIGH_CC_SHIFT;
+	rev = (idhi & SSB_IDHIGH_RC_MASK);
+
+	ssb->chipcommon_capabilities = 0;
+	ssb->nr_cores = 0;
+	if (cc == SSB_CC_CHIPCOMMON) {
+		tmp = ssb_read32(ssb, SSB_CHIPCOMMON_CHIPID);
+
+		ssb->chip_id = (tmp & SSB_CHIPCOMMON_IDMASK);
+		ssb->chip_rev = (tmp & SSB_CHIPCOMMON_REVMASK) >>
+				SSB_CHIPCOMMON_REVSHIFT;
+		ssb->chip_package = (tmp & SSB_CHIPCOMMON_PACKMASK) >>
+				    SSB_CHIPCOMMON_PACKSHIFT;
+		if (rev >= 4) {
+			ssb->nr_cores = (tmp & SSB_CHIPCOMMON_NRCORESMASK) >>
+					SSB_CHIPCOMMON_NRCORESSHIFT;
+		}
+		tmp = ssb_read32(ssb, SSB_CHIPCOMMON_CAP);
+		ssb->chipcommon_capabilities = tmp;
+	} else {
+		u16 revtmp;
+
+		if (chipid_fallback == 0) {
+			printk(KERN_ERR PFX "No ChipCommon rev >= 4 present and "
+					    "chipid_fallback == 0\n");
+			err = -EINVAL;
+			goto error;
+		}
+		ssb->chip_id = chipid_fallback;
+		err = ssb_pci_read_config16(ssb, PCI_REVISION_ID, &revtmp);
+		if (err)
+			goto error;
+		ssb->chip_rev = revtmp;
+		ssb->chip_package = 0;
+	}
+	if (!ssb->nr_cores) {
+		const struct ssb_nrcores_elem *elem;
+
+		/* Search the fallback array. */
+		if (!nrcores_fallback) {
+			printk(KERN_ERR PFX "Could not read number of cores from "
+					    "ChipCommon and no nrcores_fallback "
+					    "available\n");
+			err = -EINVAL;
+			goto error;
+		}
+		for (i = 0; i < nrcores_fb_size; i++) {
+			elem = &(nrcores_fallback[i]);
+			if (elem->chip_id_key == ssb->chip_id) {
+				ssb->nr_cores = elem->nr_cores_value;
+				break;
+			}
+		}
+	}
+	if (!ssb->nr_cores) {
+		printk(KERN_ERR PFX "Could not determine number of cores.\n");
+		err = -ESRCH;
+		goto error;
+	}
+
+	err = -ENOMEM;
+	ssb->cores = kcalloc(ssb->nr_cores, sizeof(struct ssb_core),
+			     GFP_KERNEL);
+	if (!ssb->cores)
+		goto error;
+
+	for (i = 0; i < ssb->nr_cores; i++) {
+		err = do_switch_core(ssb, i);
+		if (err)
+			goto error;
+		core = &(ssb->cores[i]);
+
+		idhi = ssb_read32(ssb, SSB_IDHIGH);
+		core->cc = (idhi & SSB_IDHIGH_CC_MASK) >> SSB_IDHIGH_CC_SHIFT;
+		core->rev = (idhi & SSB_IDHIGH_RC_MASK);
+		core->vendor = (idhi & SSB_IDHIGH_VC_MASK) >> SSB_IDHIGH_VC_SHIFT;
+		core->index = i;
+
+		dprintk(KERN_DEBUG PFX "Core %d found: "
+				       "cc %04X, rev %02X, vendor %04X\n",
+			i, core->cc, core->rev, core->vendor);
+	}
+	err = 0;
+out_unlock:
+	mutex_unlock(&ssb->mutex);
+
+	return err;
+error:
+	printk(KERN_ERR PFX "Failed to probe cores\n");
+	goto out_unlock;
+}
+EXPORT_SYMBOL_GPL(ssb_probe_cores);
+
+int ssb_core_is_enabled(struct ssb *ssb)
+{
+	u32 val;
+
+	mutex_lock(&ssb->mutex);
+	val = ssb_read32(ssb, SSB_TMSLOW);
+	mutex_unlock(&ssb->mutex);
+	val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT;
+
+	return (val == SSB_TMSLOW_CLOCK);
+}
+EXPORT_SYMBOL_GPL(ssb_core_is_enabled);
+
+static void ssb_flush_bus(struct ssb *ssb, u16 dummyreg)
+{
+	ssb_read32(ssb, dummyreg); /* dummy read */
+	udelay(1);
+}
+
+static int ssb_wait_bit(struct ssb *ssb, u16 reg, u32 bitmask,
+			int timeout, int set)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < timeout; i++) {
+		val = ssb_read32(ssb, reg);
+		if (set) {
+			if (val & bitmask)
+				return 0;
+		} else {
+			if (!(val & bitmask))
+				return 0;
+		}
+		msleep(1);
+	}
+	printk(KERN_ERR PFX "Timeout waiting for bitmask %08X on "
+			    "register %04X to %s.\n",
+	       bitmask, reg, (set ? "set" : "clear"));
+
+	return -ETIMEDOUT;
+}
+
+static void ssb_core_disable_locked(struct ssb *ssb,
+				    u32 core_specific_flags)
+{
+	if (ssb_read32(ssb, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+		return;
+
+	ssb_write32(ssb, SSB_TMSLOW, SSB_TMSLOW_REJECT | SSB_TMSLOW_CLOCK);
+	ssb_wait_bit(ssb, SSB_TMSLOW, SSB_TMSLOW_REJECT, 100, 1);
+	ssb_wait_bit(ssb, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 100, 0);
+	ssb_write32(ssb, SSB_TMSLOW,
+		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+		    SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET |
+		    core_specific_flags);
+	ssb_flush_bus(ssb, SSB_TMSLOW);
+
+	ssb_write32(ssb, SSB_TMSLOW,
+		    SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET |
+		    core_specific_flags);
+	ssb_flush_bus(ssb, SSB_TMSLOW);
+}
+
+void ssb_core_enable(struct ssb *ssb, u32 core_specific_flags)
+{
+	u32 val;
+
+	mutex_lock(&ssb->mutex);
+
+	ssb_core_disable_locked(ssb, core_specific_flags);
+	ssb_write32(ssb, SSB_TMSLOW,
+		    SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK |
+		    SSB_TMSLOW_FGC | core_specific_flags);
+	ssb_flush_bus(ssb, SSB_TMSLOW);
+
+	/* Clear SERR if set. This is a hw bug workaround. */
+	if (ssb_read32(ssb, SSB_TMSHIGH) & SSB_TMSHIGH_SERR)
+		ssb_write32(ssb, SSB_TMSHIGH, 0);
+
+	val = ssb_read32(ssb, SSB_IMSTATE);
+	if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) {
+		val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO);
+		ssb_write32(ssb, SSB_IMSTATE, val);
+	}
+
+	ssb_write32(ssb, SSB_TMSLOW,
+		    SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC |
+		    core_specific_flags);
+	ssb_flush_bus(ssb, SSB_TMSLOW);
+
+	ssb_write32(ssb, SSB_TMSLOW, SSB_TMSLOW_CLOCK |
+		    core_specific_flags);
+	ssb_flush_bus(ssb, SSB_TMSLOW);
+
+	mutex_unlock(&ssb->mutex);
+}
+EXPORT_SYMBOL_GPL(ssb_core_enable);
+
+void ssb_core_disable(struct ssb *ssb, u32 core_specific_flags)
+{
+	mutex_lock(&ssb->mutex);
+	ssb_core_disable_locked(ssb, core_specific_flags);
+	mutex_unlock(&ssb->mutex);
+}
+EXPORT_SYMBOL_GPL(ssb_core_disable);
+
+static u32 ssb_pcie_read(struct ssb *ssb, u32 address)
+{
+	ssb_write32(ssb, 0x130, address);
+	return ssb_read32(ssb, 0x134);
+}
+
+static void ssb_pcie_write(struct ssb *ssb, u32 address, u32 data)
+{
+	ssb_write32(ssb, 0x130, address);
+	ssb_write32(ssb, 0x134, data);
+}
+
+static void ssb_pcie_mdio_write(struct ssb *ssb, u8 device,
+				u8 address, u16 data)
+{
+	const u16 mdio_control = 0x128;
+	const u16 mdio_data = 0x12C;
+	u32 v;
+	int i;
+
+	v = 0x80; /* Enable Preamble Sequence */
+	v |= 0x2; /* MDIO Clock Divisor */
+	ssb_write32(ssb, mdio_control, v);
+
+	v = (1 << 30); /* Start of Transaction */
+	v |= (1 << 28); /* Write Transaction */
+	v |= (1 << 17); /* Turnaround */
+	v |= (u32)device << 22;
+	v |= (u32)address << 18;
+	v |= data;
+	ssb_write32(ssb, mdio_data, v);
+	udelay(10);
+	for (i = 0; i < 10; i++) {
+		v = ssb_read32(ssb, mdio_control);
+		if (v & 0x100 /* Trans complete */)
+			break;
+		msleep(1);
+	}
+	ssb_write32(ssb, mdio_control, 0);
+}
+
+static void ssb_broadcast_value(struct ssb *ssb,
+				u32 address, u32 data)
+{
+	/* This is for both, PCI and ChipCommon core, so be careful. */
+	BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCOMMON_BCAST_ADDR);
+	BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCOMMON_BCAST_DATA);
+
+	ssb_write32(ssb, SSB_PCICORE_BCAST_ADDR, address);
+	ssb_flush_bus(ssb, 0x0);
+	ssb_write32(ssb, SSB_PCICORE_BCAST_DATA, data);
+	ssb_flush_bus(ssb, 0x0);
+}
+
+static int ssb_pcicore_commit_settings(struct ssb *ssb,
+				       struct ssb_core *chipcommon_core)
+{
+	struct ssb_core *old_core = NULL;
+	int err;
+
+	if (chipcommon_core) {
+		old_core = ssb->current_core;
+		err = ssb_switch_core_locked(ssb, chipcommon_core);
+		if (err)
+			goto out;
+	}
+	/* This forces an update of the cached registers. */
+	ssb_broadcast_value(ssb, 0xFD8, 0);
+	if (old_core) {
+		err = ssb_switch_core_locked(ssb, old_core);
+		if (err)
+			goto out;
+	}
+out:
+	return err;
+}
+
+int ssb_cores_connect(struct ssb *ssb, u32 coremask)
+{
+	struct ssb_core *old_core;
+	struct ssb_core *pci_core = NULL;
+	struct ssb_core *chipcommon_core = NULL;
+	u32 backplane_flag_nr;
+	u32 value;
+	int i, err;
+
+	mutex_lock(&ssb->mutex);
+
+	for (i = 0; i < ssb->nr_cores; i++) {
+		if (ssb->cores[i].cc == SSB_CC_PCI ||
+		    ssb->cores[i].cc == SSB_CC_PCIE)
+			pci_core = &(ssb->cores[i]);
+		else if (ssb->cores[i].cc == SSB_CC_CHIPCOMMON)
+			chipcommon_core = &(ssb->cores[i]);
+	}
+
+	value = ssb_read32(ssb, SSB_TPSFLAG);
+	backplane_flag_nr = value & SSB_TPSFLAG_BPFLAG;
+
+	old_core = ssb->current_core;
+	err = ssb_switch_core_locked(ssb, pci_core);
+	if (err)
+		goto out;
+	if ((pci_core->rev >= 6) || (pci_core->cc == SSB_CC_PCIE)) {
+		err = ssb_pci_read_config32(ssb, SSB_PCI_IRQMASK, &value);
+		if (err)
+			goto out_switch_back;
+		value |= coremask << 8;
+		err = ssb_pci_write_config32(ssb, SSB_PCI_IRQMASK, value);
+		if (err)
+			goto out_switch_back;
+	} else {
+		value = ssb_read32(ssb, SSB_INTVEC);
+		value |= (1 << backplane_flag_nr);
+		ssb_write32(ssb, SSB_INTVEC, value);
+	}
+	if (pci_core->cc == SSB_CC_PCI) {
+		value = ssb_read32(ssb, SSB_PCICORE_TRANS2);
+		value |= SSB_PCICORE_TRANS2_PREF;
+		value |= SSB_PCICORE_TRANS2_BURST;
+		ssb_write32(ssb, SSB_PCICORE_TRANS2, value);
+		if (pci_core->rev < 5) {
+			value = ssb_read32(ssb, SSB_IMCFGLO);
+			value &= ~SSB_IMCFGLO_SERTO;
+			value |= 2;
+			value &= ~SSB_IMCFGLO_REQTO;
+			value |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
+			ssb_write32(ssb, SSB_IMCFGLO, value);
+			err = ssb_pcicore_commit_settings(ssb, chipcommon_core);
+			if (err)
+				goto out_switch_back;
+		} else if (pci_core->rev >= 11) {
+			value = ssb_read32(ssb, SSB_PCICORE_TRANS2);
+			value |= SSB_PCICORE_TRANS2_MRM;
+			ssb_write32(ssb, SSB_PCICORE_TRANS2, value);
+		}
+	} else {
+		if ((pci_core->rev == 0) || (pci_core->rev == 1)) {
+			/* TLP Workaround register. */
+			value = ssb_pcie_read(ssb, 0x4);
+			value |= 0x8;
+			ssb_pcie_write(ssb, 0x4, value);
+		}
+		if (pci_core->rev == 0) {
+			const u8 serdes_rx_device = 0x1F;
+
+			ssb_pcie_mdio_write(ssb, serdes_rx_device,
+					    2 /* Timer */, 0x8128);
+			ssb_pcie_mdio_write(ssb, serdes_rx_device,
+					    6 /* CDR */, 0x0100);
+			ssb_pcie_mdio_write(ssb, serdes_rx_device,
+					    7 /* CDR BW */, 0x1466);
+		} else if (pci_core->rev == 1) {
+			/* DLLP Link Control register. */
+			value = ssb_pcie_read(ssb, 0x100);
+			value |= 0x40;
+			ssb_pcie_write(ssb, 0x100, value);
+		}
+	}
+out_switch_back:
+	err = ssb_switch_core_locked(ssb, old_core);
+out:
+	mutex_unlock(&ssb->mutex);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ssb_cores_connect);
+
+
+MODULE_DESCRIPTION("Sonics Silicon Backplane driver");
+MODULE_LICENSE("GPL");
Index: wireless-dev/include/linux/ssb.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/include/linux/ssb.h	2006-08-23 10:52:21.000000000 +0200
@@ -0,0 +1,577 @@
+#ifndef LINUX__SONICS_SILICON_BACKPLANE_H_
+#define LINUX__SONICS_SILICON_BACKPLANE_H_
+
+/* Sonics SiliconBackplane support routines. */
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+/* SSB PCI config space registers. */
+#define	SSB_BAR0_WIN		0x80	/* Backplane address space 0 */
+#define	SSB_BAR1_WIN		0x84	/* Backplane address space 1 */
+#define	SSB_SPROMCTL		0x88	/* SPROM control */
+#define  SSB_SPROMCTL_WE	0x10	/* SPROM write enable */
+#define	SSB_BAR1_CONTROL	0x8c	/* Address space 1 burst control */
+#define SSB_PCI_IRQS		0x90	/* PCI interrupts */
+#define SSB_PCI_IRQMASK		0x94	/* PCI IRQ control and mask (pcirev >= 6 only) */
+#define SSB_BACKPLANE_IRQS	0x98	/* Backplane Interrupts */
+#define SSB_GPIO_IN		0xB0	/* GPIO Input (pcirev >= 3 only) */
+#define SSB_GPIO_OUT		0xB4	/* GPIO Output (pcirev >= 3 only) */
+#define SSB_GPIO_OUT_ENABLE	0xB8	/* GPIO Output Enable/Disable (pcirev >= 3 only) */
+
+#define SSB_BAR0_MAX_RETRIES	50
+
+/* Silicon backplane register definitions */
+#define SSB_IPSFLAG		0x0F08
+#define SSB_TPSFLAG		0x0F18
+#define  SSB_TPSFLAG_BPFLAG	0x0000003F /* Backplane flag # */
+#define  SSB_TPSFLAG_ALWAYSIRQ	0x00000040 /* IRQ is always sent on the Backplane */
+#define SSB_TMERRLOGA		0x0F48
+#define SSB_TMERRLOG		0x0F50
+#define SSB_ADMATCH3		0x0F60
+#define SSB_ADMATCH2		0x0F68
+#define SSB_ADMATCH1		0x0F70
+#define SSB_IMSTATE		0x0F90     /* SB Initiator Agent State */
+#define  SSB_IMSTATE_PC		0x0000000f /* Pipe Count */
+#define  SSB_IMSTATE_AP_MASK	0x00000030 /* Arbitration Priority */
+#define  SSB_IMSTATE_AP_BOTH	0x00000000 /* Use both timeslices and token */
+#define  SSB_IMSTATE_AP_TS	0x00000010 /* Use timeslices only */
+#define  SSB_IMSTATE_AP_TK	0x00000020 /* Use token only */
+#define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
+#define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
+#define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
+#define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
+#define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+#define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
+#define  SSB_INTVEC_ILINE20	0x00000004 /* Enable interrupts for iline20 */
+#define  SSB_INTVEC_CODEC	0x00000008 /* Enable interrupts for v90 codec */
+#define  SSB_INTVEC_USB		0x00000010 /* Enable interrupts for usb */
+#define  SSB_INTVEC_EXTIF	0x00000020 /* Enable interrupts for external i/f */
+#define  SSB_INTVEC_ENET1	0x00000040 /* Enable interrupts for enet 1 */
+#define SSB_TMSLOW		0x0F98     /* SB Target State Low */
+#define  SSB_TMSLOW_RESET	0x00000001 /* Reset */
+#define  SSB_TMSLOW_REJECT	0x00000002 /* Reject */
+#define  SSB_TMSLOW_CLOCK	0x00010000 /* Clock Enable */
+#define  SSB_TMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
+#define  SSB_TMSLOW_PE		0x40000000 /* Power Management Enable */
+#define  SSB_TMSLOW_BE		0x80000000 /* BIST Enable */
+#define SSB_TMSHIGH		0x0F9C     /* SB Target State High */
+#define  SSB_TMSHIGH_SERR	0x00000001 /* S-error */
+#define  SSB_TMSHIGH_INT	0x00000002 /* Interrupt */
+#define  SSB_TMSHIGH_BUSY	0x00000004 /* Busy */
+#define  SSB_TMSHIGH_TO		0x00000020 /* Timeout. Backplane rev >= 2.3 only */
+#define  SSB_TMSHIGH_COREFL	0x1FFF0000 /* Core specific flags */
+#define  SSB_TMSHIGH_COREFL_SHIFT	16
+#define  SSB_TMSHIGH_DMA64	0x10000000 /* 64bit DMA supported */
+#define  SSB_TMSHIGH_GCR	0x20000000 /* Gated Clock Request */
+#define  SSB_TMSHIGH_BISTF	0x40000000 /* BIST Failed */
+#define  SSB_TMSHIGH_BISTD	0x80000000 /* BIST Done */
+#define SSB_BWA0		0x0FA0
+#define SSB_IMCFGLO		0x0FA8
+#define  SSB_IMCFGLO_SERTO	0x00000007 /* Service timeout */
+#define  SSB_IMCFGLO_REQTO	0x00000070 /* Request timeout */
+#define  SSB_IMCFGLO_REQTO_SHIFT	4
+#define  SSB_IMCFGLO_CONNID	0x00FF0000 /* Connection ID */
+#define  SSB_IMCFGLO_CONNID_SHIFT	16
+#define SSB_IMCFGHI		0x0FAC
+#define SSB_BCONFIG		0x0FC0
+#define SSB_BSTATE		0x0FC8
+#define SSB_ACTCFG		0x0FD8
+#define SSB_FLAGST		0x0FE8
+#define SSB_IDLOW		0x0FF8
+#define  SSB_IDLOW_CFGSP	0x00000003 /* Config Space */
+#define  SSB_IDLOW_ADDRNGE	0x00000038 /* Address Ranges supported */
+#define  SSB_IDLOW_ADDRNGE_SHIFT	3
+#define  SSB_IDLOW_SYNC		0x00000040
+#define  SSB_IDLOW_INITIATOR	0x00000080
+#define  SSB_IDLOW_MIBL		0x00000F00 /* Minimum Backplane latency */
+#define  SSB_IDLOW_MIBL_SHIFT	8
+#define  SSB_IDLOW_MABL		0x0000F000 /* Maximum Backplane latency */
+#define  SSB_IDLOW_MABL_SHIFT	12
+#define  SSB_IDLOW_TIF		0x00010000 /* This Initiator is first */
+#define  SSB_IDLOW_CCW		0x000C0000 /* Cycle counter width */
+#define  SSB_IDLOW_CCW_SHIFT	18
+#define  SSB_IDLOW_TPT		0x00F00000 /* Target ports */
+#define  SSB_IDLOW_TPT_SHIFT	20
+#define  SSB_IDLOW_INITP	0x0F000000 /* Initiator ports */
+#define  SSB_IDLOW_INITP_SHIFT	24
+#define  SSB_IDLOW_SSBREV	0xF0000000 /* Sonics Backplane Revision code */
+#define  SSB_IDLOW_SSBREV_22	0x00000000 /* <= 2.2 */
+#define  SSB_IDLOW_SSBREV_23	0x10000000 /* 2.3 */
+#define SSB_IDHIGH		0x0FFC     /* SB Identification High */
+#define  SSB_IDHIGH_RC_MASK	0x0000000f /* Revision Code */
+#define  SSB_IDHIGH_CC_MASK	0x0000fff0 /* Core Code */
+#define  SSB_IDHIGH_CC_SHIFT	4
+#define  SSB_IDHIGH_VC_MASK	0xffff0000 /* Vendor Code */
+#define  SSB_IDHIGH_VC_SHIFT	16
+
+/* SPROM shadow area. If not otherwise noted, fields are
+ * two bytes wide. Note that the SPROM can _only_ be read
+ * in two-byte quantinies.
+ */
+#define SSB_SPROMSIZE_WORDS		64
+#define SSB_SPROMSIZE_BYTES		(SSB_SPROMSIZE_WORDS * sizeof(u16))
+#define SSB_SPROM_BASE			0x1000
+#define SSB_SPROM_REVISION		0x107E
+#define  SSB_SPROM_REVISION_REV		0x00FF	/* SPROM Revision number */
+#define  SSB_SPROM_REVISION_CRC		0xFF00	/* SPROM CRC8 value */
+#define  SSB_SPROM_REVISION_CRC_SHIFT	8
+/* SPROM Revision 1 */
+#define SSB_SPROM1_SPID			0x1004	/* Subsystem Product ID for PCI */
+#define SSB_SPROM1_SVID			0x1006	/* Subsystem Vendor ID for PCI */
+#define SSB_SPROM1_PID			0x1008	/* Product ID for PCI */
+#define SSB_SPROM1_IL0MAC		0x1048	/* 6 bytes MAC address for 802.11b/g */
+#define SSB_SPROM1_ET0MAC		0x104E	/* 6 bytes MAC address for Ethernet */
+#define SSB_SPROM1_ET1MAC		0x1054	/* 6 bytes MAC address for 802.11a */
+#define SSB_SPROM1_ETHPHY		0x105A	/* Ethernet PHY settings */
+#define  SSB_SPROM1_ETHPHY_ET0A		0x001F	/* MII Address for enet0 */
+#define  SSB_SPROM1_ETHPHY_ET1A		0x03E0	/* MII Address for enet1 */
+#define  SSB_SPROM1_ETHPHY_ET1A_SHIFT	5
+#define  SSB_SPROM1_ETHPHY_ET0M		(1<<14)	/* MDIO for enet0 */
+#define  SSB_SPROM1_ETHPHY_ET1M		(1<<15)	/* MDIO for enet1 */
+#define SSB_SPROM1_BINF			0x105C	/* Board info */
+#define  SSB_SPROM1_BINF_BREV		0x00FF	/* Board Revision */
+#define  SSB_SPROM1_BINF_CCODE		0x0F00	/* Country Code */
+#define  SSB_SPROM1_BINF_CCODE_SHIFT	8
+#define  SSB_SPROM1_BINF_ANTA		0x3000	/* Available A-PHY antennas */
+#define  SSB_SPROM1_BINF_ANTA_SHIFT	12
+#define  SSB_SPROM1_BINF_ANTBG		0xC000	/* Available B-PHY antennas */
+#define  SSB_SPROM1_BINF_ANTBG_SHIFT	14
+#define SSB_SPROM1_PA0B0		0x105E
+#define SSB_SPROM1_PA0B1		0x1060
+#define SSB_SPROM1_PA0B2		0x1062
+#define SSB_SPROM1_GPIOA		0x1064	/* General Purpose IO pins 0 and 1 */
+#define  SSB_SPROM1_GPIOA_P0		0x00FF	/* Pin 0 */
+#define  SSB_SPROM1_GPIOA_P1		0xFF00	/* Pin 1 */
+#define  SSB_SPROM1_GPIOA_P1_SHIFT	8
+#define SSB_SPROM1_GPIOB		0x1066	/* General Purpuse IO pins 2 and 3 */
+#define  SSB_SPROM1_GPIOB_P2		0x00FF	/* Pin 2 */
+#define  SSB_SPROM1_GPIOB_P3		0xFF00	/* Pin 3 */
+#define  SSB_SPROM1_GPIOB_P3_SHIFT	8
+#define SSB_SPROM1_MAXPWR		0x1068	/* Power Amplifier Max Power */
+#define  SSB_SPROM1_MAXPWR_A		0x00FF	/* A-PHY (in dBm Q5.2) */
+#define  SSB_SPROM1_MAXPWR_BG		0xFF00	/* B-PHY and G-PHY (in dBm Q5.2) */
+#define  SSB_SPROM1_MAXPWR_BG_SHIFT	8
+#define SSB_SPROM1_PA1B0		0x106A
+#define SSB_SPROM1_PA1B1		0x106C
+#define SSB_SPROM1_PA1B2		0x106E
+#define SSB_SPROM1_ITSSI		0x1070	/* Idle TSSI Target */
+#define  SSB_SPROM1_ITSSI_A		0x00FF	/* A-PHY */
+#define  SSB_SPROM1_ITSSI_BG		0xFF00	/* B-PHY and G-PHY */
+#define  SSB_SPROM1_ITSSI_BG_SHIFT	8
+#define SSB_SPROM1_BFLLO		0x1072	/* Boardflags (low 16 bits) */
+#define SSB_SPROM1_AGAIN		0x1074	/* Antenna Gain (in dBm Q5.2) */
+#define  SSB_SPROM1_AGAIN_A		0x00FF	/* A-PHY */
+#define  SSB_SPROM1_AGAIN_BG		0xFF00	/* B-PHY and G-PHY */
+#define  SSB_SPROM1_AGAIN_BG_SHIFT	8
+#define SSB_SPROM1_OEM			0x1076	/* 8 bytes OEM string (rev 1 only) */
+/* SPROM Revision 2 (inherits from rev 1) */
+#define SSB_SPROM2_BFLHI		0x1038	/* Boardflags (high 16 bits) */
+#define SSB_SPROM2_MAXP_A		0x103A	/* A-PHY Max Power */
+#define  SSB_SPROM2_MAXP_A_HI		0x00FF	/* Max Power High */
+#define  SSB_SPROM2_MAXP_A_LO		0x1100	/* Max Power Low */
+#define  SSB_SPROM2_MAXP_A_LO_SHIFT	8
+#define SSB_SPROM2_PA1LOB0		0x103C	/* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1LOB1		0x103E	/* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1LOB2		0x1040	/* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1HIB0		0x1042	/* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_PA1HIB1		0x1044	/* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_PA1HIB2		0x1046	/* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_OPO			0x1078	/* OFDM Power Offset from CCK Level */
+#define  SSB_SPROM2_OPO_VALUE		0x00FF
+#define  SSB_SPROM2_OPO_UNUSED		0xFF00
+#define SSB_SPROM2_CCODE		0x107C	/* Two char Country Code */
+/* SPROM Revision 3 (inherits from rev 2) */
+#define SSB_SPROM3_OFDMAPO		0x102C	/* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMALPO		0x1030	/* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMAHPO		0x1034	/* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_GPIOLDC		0x1042	/* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */
+#define  SSB_SPROM3_GPIOLDC_OFF		0x0000FF00	/* Off Count */
+#define  SSB_SPROM3_GPIOLDC_OFF_SHIFT	8
+#define  SSB_SPROM3_GPIOLDC_ON		0x00FF0000	/* On Count */
+#define  SSB_SPROM3_GPIOLDC_ON_SHIFT	16
+#define SSB_SPROM3_CCKPO		0x1078	/* CCK Power Offset */
+#define  SSB_SPROM3_CCKPO_1M		0x000F	/* 1M Rate PO */
+#define  SSB_SPROM3_CCKPO_2M		0x00F0	/* 2M Rate PO */
+#define  SSB_SPROM3_CCKPO_2M_SHIFT	4
+#define  SSB_SPROM3_CCKPO_55M		0x0F00	/* 5.5M Rate PO */
+#define  SSB_SPROM3_CCKPO_55M_SHIFT	8
+#define  SSB_SPROM3_CCKPO_11M		0xF000	/* 11M Rate PO */
+#define  SSB_SPROM3_CCKPO_11M_SHIFT	12
+#define  SSB_SPROM3_OFDMGPO		0x107A	/* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
+
+/* Values for SSB_SPROM1_BINF_CCODE */
+enum {
+	SSB_SPROM1CCODE_WORLD = 0,
+	SSB_SPROM1CCODE_THAILAND,
+	SSB_SPROM1CCODE_ISRAEL,
+	SSB_SPROM1CCODE_JORDAN,
+	SSB_SPROM1CCODE_CHINA,
+	SSB_SPROM1CCODE_JAPAN,
+	SSB_SPROM1CCODE_USA_CANADA_ANZ,
+	SSB_SPROM1CCODE_EUROPE,
+	SSB_SPROM1CCODE_USA_LOW,
+	SSB_SPROM1CCODE_JAPAN_HIGH,
+	SSB_SPROM1CCODE_ALL,
+	SSB_SPROM1CCODE_NONE,
+};
+
+
+/* Core Code values. */
+#define SSB_CC_CHIPCOMMON	0x800
+#define SSB_CC_ILINE20		0x801
+#define SSB_CC_SDRAM		0x803
+#define SSB_CC_PCI		0x804
+#define SSB_CC_MIPS		0x805
+#define SSB_CC_ETHERNET		0x806
+#define SSB_CC_V90		0x807
+#define SSB_CC_USB11_HOSTDEV	0x808
+#define SSB_CC_ADSL		0x809
+#define SSB_CC_ILINE100		0x80A
+#define SSB_CC_IPSEC		0x80B
+#define SSB_CC_PCMCIA		0x80D
+#define SSB_CC_INTERNAL_MEM	0x80E
+#define SSB_CC_MEMC_SDRAM	0x80F
+#define SSB_CC_EXTIF		0x811
+#define SSB_CC_80211		0x812
+#define SSB_CC_MIPS_3302	0x816
+#define SSB_CC_USB11_HOST	0x817
+#define SSB_CC_USB11_DEV	0x818
+#define SSB_CC_USB20_HOST	0x819
+#define SSB_CC_USB20_DEV	0x81A
+#define SSB_CC_SDIO_HOST	0x81B
+#define SSB_CC_ROBOSWITCH	0x81C
+#define SSB_CC_PARA_ATA		0x81D
+#define SSB_CC_SATA_XORDMA	0x81E
+#define SSB_CC_ETHERNET_GBIT	0x81F
+#define SSB_CC_PCIE		0x820
+#define SSB_CC_MIMO_PHY		0x821
+#define SSB_CC_SRAM_CTRLR	0x822
+#define SSB_CC_MINI_MACPHY	0x823
+#define SSB_CC_ARM_1176		0x824
+#define SSB_CC_ARM_7TDMI	0x825
+
+
+/* ChipCommon core registers. */
+#define SSB_CHIPCOMMON_CHIPID		0x0000
+#define  SSB_CHIPCOMMON_IDMASK		0x0000FFFF
+#define  SSB_CHIPCOMMON_REVMASK		0x000F0000
+#define  SSB_CHIPCOMMON_REVSHIFT	16
+#define  SSB_CHIPCOMMON_PACKMASK	0x00F00000
+#define  SSB_CHIPCOMMON_PACKSHIFT	20
+#define  SSB_CHIPCOMMON_NRCORESMASK	0x0F000000
+#define  SSB_CHIPCOMMON_NRCORESSHIFT	24
+#define SSB_CHIPCOMMON_CAP	 	0x0004		/* Capabilities */
+#define  SSB_CHIPCOMMON_CAP_NRUART	0x00000003	/* # of UARTs */
+#define  SSB_CHIPCOMMON_CAP_MIPSEB	0x00000004	/* MIPS in BigEndian Mode */
+#define  SSB_CHIPCOMMON_CAP_UARTCLK	0x00000018	/* UART clock select */
+#define  SSB_CHIPCOMMON_CAP_UARTGPIO	0x00000020	/* UARTs on GPIO 15-12 */
+#define  SSB_CHIPCOMMON_CAP_EXTBUS	0x000000C0	/* External buses present */
+#define  SSB_CHIPCOMMON_CAP_FLASHT	0x00000700	/* Flash Type */
+#define  SSB_CHIPCOMMON_CAP_PLLT	0x00038000	/* PLL Type */
+#define  SSB_CHIPCOMMON_CAP_PCTL	0x00040000	/* Power Control */
+#define  SSB_CHIPCOMMON_CAP_OTPS	0x00380000	/* OTP size */
+#define  SSB_CHIPCOMMON_CAP_JTAGM	0x00400000	/* JTAG master present */
+#define  SSB_CHIPCOMMON_CAP_BROM	0x00800000	/* Internal boot ROM active */
+#define  SSB_CHIPCOMMON_CAP_64BIT	0x08000000	/* 64-bit Backplane */
+#define SSB_CHIPCOMMON_CORECTL		0x0008
+#define SSB_CHIPCOMMON_BIST		0x000C
+#define SSB_CHIPCOMMON_BCAST_ADDR	0x0050
+#define SSB_CHIPCOMMON_BCAST_DATA	0x0054
+#define SSB_CHIPCOMMON_PLLONDELAY	0x00B0
+#define SSB_CHIPCOMMON_FREFSELDELAY	0x00B4
+#define SSB_CHIPCOMMON_SLOWCLKCTL	0x00B8
+#define SSB_CHIPCOMMON_SYSCLKCTL	0x00C0
+
+/* PCI core registers. */
+#define SSB_PCICORE_CTL		0x0000	/* PCI Control */
+#define SSB_PCICORE_ARBCTL	0x0010	/* PCI Arbiter Control */
+#define SSB_PCICORE_ISTAT	0x0020	/* Interrupt status */
+#define SSB_PCICORE_IMASK	0x0024	/* Interrupt mask */
+#define SSB_PCICORE_MBOX	0x0028	/* Backplane to PCI Mailbox */
+#define SSB_PCICORE_BCAST_ADDR	0x0050	/* Backplane Broadcast Address */
+#define SSB_PCICORE_BCAST_DATA	0x0054	/* Backplane Broadcast Data */
+#define SSB_PCICORE_GPIO_IN	0x0060	/* rev >= 2 only */
+#define SSB_PCICORE_GPIO_OUT	0x0064	/* rev >= 2 only */
+#define SSB_PCICORE_GPIO_ENABLE	0x0068	/* rev >= 2 only */
+#define SSB_PCICORE_GPIO_CTL	0x006C	/* rev >= 2 only */
+#define SSB_PCICORE_TRANS0	0x0100	/* Backplane to PCI translation 0 (sbtopci0) */
+#define SSB_PCICORE_TRANS1	0x0104	/* Backplane to PCI translation 1 (sbtopci1) */
+#define SSB_PCICORE_TRANS2	0x0108	/* Backplane to PCI translation 2 (dbtopci2) */
+#define  SSB_PCICORE_TRANS2_MEM		0x00000000
+#define  SSB_PCICORE_TRANS2_IO		0x00000001
+#define  SSB_PCICORE_TRANS2_CFG0	0x00000002
+#define  SSB_PCICORE_TRANS2_CFG1	0x00000003
+#define  SSB_PCICORE_TRANS2_PREF	0x00000004	/* Prefetch enable */
+#define  SSB_PCICORE_TRANS2_BURST	0x00000008	/* Burst enable */
+#define  SSB_PCICORE_TRANS2_MRM		0x00000020	/* Memory Read Multiple */
+#define  SSB_PCICORE_TRANS2_MASK0	0xfc000000
+#define  SSB_PCICORE_TRANS2_MASK1	0xfc000000
+#define  SSB_PCICORE_TRANS2_MASK2	0xc0000000
+
+
+
+struct pci_dev;
+
+
+struct ssb_sprom_r1 {
+	u16 pci_spid;		/* Subsystem Product ID for PCI */
+	u16 pci_svid;		/* Subsystem Vendor ID for PCI */
+	u16 pci_pid;		/* Product ID for PCI */
+	u8 il0mac[6];		/* MAC address for 802.11b/g */
+	u8 et0mac[6];		/* MAC address for Ethernet */
+	u8 et1mac[6];		/* MAC address for 802.11a */
+	u8 et0phyaddr:5;	/* MII address for enet0 */
+	u8 et1phyaddr:5;	/* MII address for enet1 */
+	u8 et0mdcport:1;	/* MDIO for enet0 */
+	u8 et1mdcport:1;	/* MDIO for enet1 */
+	u8 board_rev;		/* Board revision */
+	u8 country_code:4;	/* Country Code */
+	u8 antenna_a:2;		/* Antenna 0/1 available for A-PHY */
+	u8 antenna_bg:2;	/* Antenna 0/1 available for B-PHY and G-PHY */
+	u16 pa0b0;
+	u16 pa0b1;
+	u16 pa0b2;
+	u16 pa1b0;
+	u16 pa1b1;
+	u16 pa1b2;
+	u8 gpio0;		/* GPIO pin 0 */
+	u8 gpio1;		/* GPIO pin 1 */
+	u8 gpio2;		/* GPIO pin 2 */
+	u8 gpio3;		/* GPIO pin 3 */
+	u16 maxpwr_a;		/* A-PHY Power Amplifier Max Power (in dBm Q5.2) */
+	u16 maxpwr_bg;		/* B/G-PHY Power Amplifier Max Power (in dBm Q5.2) */
+	u8 itssi_a;		/* Idle TSSI Target for A-PHY */
+	u8 itssi_bg;		/* Idle TSSI Target for B/G-PHY */
+	u16 boardflags_lo;	/* Boardflags (low 16 bits) */
+	u8 antenna_gain_a;	/* A-PHY Antenna gain (in dBm Q5.2) */
+	u8 antenna_gain_bg;	/* B/G-PHY Antenna gain (in dBm Q5.2) */
+	u8 oem[8];		/* OEM string (rev 1 only) */
+};
+
+struct ssb_sprom_r2 {
+	u16 boardflags_hi;	/* Boardflags (high 16 bits) */
+	u8 maxpwr_a_lo;		/* A-PHY Max Power Low */
+	u8 maxpwr_a_hi;		/* A-PHY Max Power High */
+	u16 pa1lob0;		/* A-PHY PA Low Settings */
+	u16 pa1lob1;		/* A-PHY PA Low Settings */
+	u16 pa1lob2;		/* A-PHY PA Low Settings */
+	u16 pa1hib0;		/* A-PHY PA High Settings */
+	u16 pa1hib1;		/* A-PHY PA High Settings */
+	u16 pa1hib2;		/* A-PHY PA High Settings */
+	u8 ofdm_pwr_off;	/* OFDM Power Offset from CCK Level */
+	u8 country_str[2];	/* Two char Country Code */
+};
+
+struct ssb_sprom_r3 {
+	u32 ofdmapo;		/* A-PHY OFDM Mid Power Offset */
+	u32 ofdmalpo;		/* A-PHY OFDM Low Power Offset */
+	u32 ofdmahpo;		/* A-PHY OFDM High Power Offset */
+	u8 gpioldc_on_cnt;	/* GPIO LED Powersave Duty Cycle ON count */
+	u8 gpioldc_off_cnt;	/* GPIO LED Powersave Duty Cycle OFF count */
+	u8 cckpo_1M:4;		/* CCK Power Offset for Rate 1M */
+	u8 cckpo_2M:4;		/* CCK Power Offset for Rate 2M */
+	u8 cckpo_55M:4;		/* CCK Power Offset for Rate 5.5M */
+	u8 cckpo_11M:4;		/* CCK Power Offset for Rate 11M */
+	u32 ofdmgpo;		/* G-PHY OFDM Power Offset */
+};
+
+struct ssb_sprom_r4 {
+	/* TODO */
+};
+
+struct ssb_sprom {
+	u8 revision;
+	u8 crc;
+	/* The valid r# fields are selected by the "revision".
+	 * Revision 3 and lower inherit from lower revisions.
+	 */
+	union {
+		struct {
+			struct ssb_sprom_r1 r1;
+			struct ssb_sprom_r2 r2;
+			struct ssb_sprom_r3 r3;
+		};
+		struct ssb_sprom_r4 r4;
+	};
+};
+
+/**
+ * struct ssb_core - Sonics Silicon Backplane core
+ * @cc:		CoreCode ID. See SSB_CC_???
+ * @vendor:	Core vendor ID number.
+ * @rev:	Core revision code.
+ * @index:	Index in the ssb->cores array.
+ * @priv:	Private data for use by the driver.
+ * 		This is not touched by the ssb subsystem (except
+ * 		initialized to NULL in ssb_probe_cores()).
+ */
+struct ssb_core {
+	u16 cc;
+	u16 vendor;
+	u8 rev;
+	u8 index;
+
+	void *priv;
+};
+
+/**
+ * struct ssb - Sonics Silicon Backplane
+ * @chipcommon_capabilities	ChipCommon capabilities are stored here
+ * 				for convenience (if available).
+ * @chip_id:			Chip ID.
+ * @chip_rev:			Chip Revision.
+ * @chip_package:		Chip Package.
+ * @nr_cores:			Arraysize of "cores".
+ * @cores:			Array of all available cores.
+ * @current_core:		Pointer to the currently mapped core. Don't
+ * 				modify directly. Use ssb_switch_core().
+ *
+ * @current_core_offset:	Internal. Use ssb_core_offset().
+ */
+struct ssb {
+	u32 chipcommon_capabilities;
+	u16 chip_id;
+	u8 chip_rev;
+	u8 chip_package;
+
+	u8 nr_cores;
+	struct ssb_core	*cores;
+	struct ssb_core *current_core;
+
+	/* The following stuff is considered
+	 * to be internal to ssb. */
+
+#ifdef CONFIG_BCM947XX
+	u32 current_core_offset;
+#endif
+	struct pci_dev *pci_dev;
+	void __iomem *mmio;
+
+	int (*device_suspend)(struct ssb *ssb);
+	int (*device_resume)(struct ssb *ssb);
+	struct mutex suspend_mutex;
+
+	struct mutex mutex;
+	struct list_head list;
+};
+
+/**
+ * ssb_core_offset - Get the MMIO core-specific offset.
+ * Add this offset to all MMIO offsets on every MMIO
+ * access to the core.
+ * @ssb:	Pointer to struct ssb.
+ */
+static inline u32 ssb_core_offset(struct ssb *ssb)
+{
+#ifdef CONFIG_BCM947XX
+	return ssb->current_core_offset;
+#else
+	return 0;
+#endif
+}
+
+/**
+ * ssb_init - Initialize struct ssb.
+ * This does not init hardware. May fail and return NULL.
+ * @ssb:	Pointer to struct ssb to init. This will usually
+ * 		be embedded in the device's private struct.
+ * @pci_dev:	Pointer to the PCI device.
+ * @mmio:	Pointer to the MMIO area of the device.
+ * @device_suspend:	This callback suspends any device activity (IRQ...)
+ * @device_resume:	This callback resumes the device activity again.
+ */
+int ssb_init(struct ssb *ssb,
+	     struct pci_dev *pci_dev,
+	     void __iomem *mmio,
+	     int (*device_suspend)(struct ssb *ssb),
+	     int (*device_resume)(struct ssb *ssb));
+/** ssb_exit - Clean up and destroy ssb. */
+void ssb_exit(struct ssb *ssb);
+
+/**
+ * struct ssb_nrcores_elem - Array element of the
+ * "number of cores" fallback array.
+ * This array is browsed, if there is no ChipCommon rev >= 4
+ * core available.
+ * @chip_id_key:	The CHIPID key value for browsing the array.
+ * @nr_cores_value:	The number of available cores on this CHIPID.
+ */
+struct ssb_nrcores_elem {
+	u16 chip_id_key;
+	u8 nr_cores_value;
+};
+
+/**
+ * ssb_probe_cores - Search and probe all available cores.
+ * Returns 0 on success or an error code on failure.
+ * @ssb:		Pointer to struct ssb.
+ * @chipid_fallback:	Fallback CHIPID value. This is only used,
+ * 			if there is no ChipCommon to read the
+ * 			CHIPID from.
+ * @nrcores_fallback:	An array of struct ssb_nrcores_elem to determine
+ * 			the number of cores on a given CHIPID, if there
+ * 			is no ChipCommon rev >= 4.
+ * @nrcores_fb_size:	ARRAY_SIZE(nrcores_fallback)
+ */
+int ssb_probe_cores(struct ssb *ssb,
+		    u16 chipid_fallback,
+		    const struct ssb_nrcores_elem *nrcores_fallback,
+		    size_t nrcores_fb_size);
+/**
+ * ssb_switch_core - Switch the "current_core" to another
+ * one out of the ssb->cores array.
+ * Current core IRQs must be disabled when calling this.
+ * Returns 0 on success or an error code on failure.
+ * @ssb:	Pointer to struct ssb.
+ * @new_core:	The new core to switch to.
+ */
+int ssb_switch_core(struct ssb *ssb,
+		    struct ssb_core *new_core);
+
+/**
+ * ssb_core_is_enabled - Check if current_core is enabled in hardware.
+ * Returns a boolean.
+ * @ssb:	Pointer to struct ssb.
+ */
+int ssb_core_is_enabled(struct ssb *ssb);
+/**
+ * ssb_core_enable - Reset and enable current_core.
+ * Current core IRQs must be disabled when calling this.
+ * @ssb:	Pointer to struct ssb.
+ * @core_specific_flags:	Additional SSB_TMSLOW flags for
+ * 				this core. Pass 0 for none.
+ */
+void ssb_core_enable(struct ssb *ssb, u32 core_specific_flags);
+/**
+ * ssb_core_disable - Disable current_core.
+ * Current core IRQs must be disabled when calling this.
+ * @ssb:	Pointer to struct ssb.
+ * @core_specific_flags:	Additional SSB_TMSLOW flags for
+ * 				this core. Pass 0 for none.
+ */
+void ssb_core_disable(struct ssb *ssb, u32 core_specific_flags);
+/**
+ * ssb_cores_connect - Connect I/O cores to the backplane.
+ * Cores need to be connected to the backplane in order
+ * to route interrupts, for example.
+ * Current core IRQs must be disabled when calling this.
+ * Returns 0 on success or an error code on failure.
+ * @ssb:	Pointer to struct ssb.
+ * @coremask:	Bitmask of cores to connect.
+ */
+int ssb_cores_connect(struct ssb *ssb, u32 coremask);
+
+/**
+ * ssb_sprom_read - Read the SPROM from the chip,
+ * interpret the information and put it into "sprom".
+ * This function checks the CRC after reading.
+ * Returns 0 on success or an error code on failure.
+ * @ssb:	Pointer to struct ssb.
+ * @sprom:	Pointer to the buffer.
+ * @force:	If true, don't error out on a bad CRC.
+ */
+int ssb_sprom_read(struct ssb *ssb, struct ssb_sprom *sprom, int force);
+
+#endif /* LINUX__SONICS_SILICON_BACKPLANE_H_ */


-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/2] bcm43xx: convert driver to use ssb
       [not found] ` <200608231158.06178.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>
  2006-08-23  9:59   ` [PATCH 1/2] Add " Michael Buesch
@ 2006-08-23 10:01   ` Michael Buesch
  1 sibling, 0 replies; 7+ messages in thread
From: Michael Buesch @ 2006-08-23 10:01 UTC (permalink / raw)
  To: linville-2XuSBdqkA4R54TAoqtyWWQ
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bcm43xx-dev-0fE9KPoRgkgATYTw5x5z8w

This patch converts the bcm43xx driver to use the new
ssb driver backend.

Signed-off-by: Michael Buesch <mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>

Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h	2006-08-23 11:27:27.000000000 +0200
@@ -11,6 +11,7 @@
 #include <asm/atomic.h>
 #include <asm/io.h>
 
+#include <linux/ssb.h>
 #include <linux/wireless.h>
 #include <net/d80211.h>
 #include <net/d80211_mgmt.h>
@@ -22,18 +23,10 @@
 
 #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_DMA0_REASON	0x20
 #define BCM43xx_MMIO_DMA0_IRQ_MASK	0x24
@@ -104,29 +97,7 @@
 #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 */
+/* SPROM boardflags_lo 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 */
@@ -158,35 +129,6 @@
 #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
@@ -203,67 +145,6 @@
 #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		0x00000001
-#define BCM43xx_SBTMSTATEHIGH_BUSY		0x00000004
-#define BCM43xx_SBTMSTATEHIGH_TIMEOUT		0x00000020
-#define BCM43xx_SBTMSTATEHIGH_COREFLAGS		0x1FFF0000
-#define BCM43xx_SBTMSTATEHIGH_DMA64BIT		0x10000000
-#define BCM43xx_SBTMSTATEHIGH_GATEDCLK		0x20000000
-#define BCM43xx_SBTMSTATEHIGH_BISTFAILED	0x40000000
-#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE	0x80000000
-
-/* sbimstate flags */
-#define BCM43xx_SBIMSTATE_IB_ERROR		0x20000
-#define BCM43xx_SBIMSTATE_TIMEOUT		0x40000
-
 /* PHYVersioning */
 #define BCM43xx_PHYTYPE_A		0x00
 #define BCM43xx_PHYTYPE_B		0x01
@@ -429,54 +310,6 @@
 	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 {
@@ -604,29 +437,9 @@
 
 #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_rev revision number */
-	u8 rev;
-	/** Index number for _switch_core() */
-	u8 index;
-	/** core_id ID number */
-	u16 id;
-	/** Core-specific data. */
-	void *priv;
-};
-
 /* Additional information for each 80211 core. */
-struct bcm43xx_coreinfo_80211 {
+struct bcm43xx_corepriv_80211 {
+	u8 initialized:1;
 	/* PHY device. */
 	struct bcm43xx_phyinfo phy;
 	/* Radio device. */
@@ -641,7 +454,7 @@
 
 /* Context information for a noise calculation (Link Quality). */
 struct bcm43xx_noise_calculation {
-	struct bcm43xx_coreinfo *core_at_start;
+	struct ssb_core *core_at_start;
 	u8 channel_at_start;
 	u8 calculation_running:1;
 	u8 nr_samples;
@@ -711,15 +524,15 @@
  */
 
 struct bcm43xx_private {
+	/* The Sonics Silicon Backplane. */
+	struct ssb ssb;
+
 	struct ieee80211_hw *ieee;
 	struct ieee80211_low_level_stats ieee_stats;
 
 	struct net_device *net_dev;
-	struct pci_dev *pci_dev;
 	unsigned int irq;
 
-	void __iomem *mmio_addr;
-
 	spinlock_t irq_lock;
 	struct mutex mutex;
 
@@ -752,36 +565,24 @@
 	u16 board_type;
 	u16 board_revision;
 
-	u16 chip_id;
-	u8 chip_rev;
-	u8 chip_package;
-
-	struct bcm43xx_sprominfo sprom;
+	struct ssb_sprom sprom;
 #define BCM43xx_NR_LEDS		4
 	struct bcm43xx_led leds[BCM43xx_NR_LEDS];
 	spinlock_t leds_lock;
 
-	/* 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.
+	/* Pointers to the available cores.
+	 * If a core is not available, this is NULL.
 	 */
-	struct bcm43xx_coreinfo core_chipcommon;
-	struct bcm43xx_coreinfo core_pci;
-	struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
+	struct ssb_core *core_80211[ BCM43xx_MAX_80211_CORES ];
+	struct ssb_core *active_80211_core;
+	struct ssb_core *core_chipcommon;
+	struct ssb_core *core_pci;
+
 	/* Additional information, specific to the 80211 cores. */
-	struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
+	struct bcm43xx_corepriv_80211 corepriv_80211[ BCM43xx_MAX_80211_CORES ];
 	/* Number of available 80211 cores. */
 	int nr_80211_available;
 
-	u32 chipcommon_capabilities;
-
 	/* Reason code of the last interrupt. */
 	u32 irq_reason;
 	u32 dma_reason[6];
@@ -801,9 +602,6 @@
 
 	struct work_struct restart_work;
 
-	/* Informational stuff. */
-	char nick[IW_ESSID_MAX_SIZE + 1];
-
 	/* encryption/decryption */
 	u16 security_offset;
 	struct bcm43xx_key key[54];
@@ -825,6 +623,12 @@
 	return ieee80211_dev_hw_data(dev);
 }
 
+static inline
+struct bcm43xx_private * ssb_to_bcm43xx(struct ssb *ssb)
+{
+	return container_of(ssb, struct bcm43xx_private, ssb);
+}
+
 /* Helper function, which returns a boolean.
  * TRUE, if PIO is used; FALSE, if DMA is used.
  */
@@ -855,11 +659,11 @@
  * any of these functions.
  */
 static inline
-struct bcm43xx_coreinfo_80211 *
+struct bcm43xx_corepriv_80211 *
 bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
 {
-	assert(bcm->current_core->id == BCM43xx_COREID_80211);
-	return bcm->current_core->priv;
+	assert(bcm->ssb.current_core->cc == SSB_CC_80211);
+	return bcm->ssb.current_core->priv;
 }
 static inline
 struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
@@ -920,49 +724,49 @@
 static inline
 u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread16(bcm->ssb.mmio + ssb_core_offset(&bcm->ssb) + offset);
 }
 
 static inline
 void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
 {
-	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite16(value, bcm->ssb.mmio + ssb_core_offset(&bcm->ssb) + offset);
 }
 
 static inline
 u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread32(bcm->ssb.mmio + ssb_core_offset(&bcm->ssb) + offset);
 }
 
 static inline
 void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
 {
-	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite32(value, bcm->ssb.mmio + ssb_core_offset(&bcm->ssb) + 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);
+	return pci_read_config_word(bcm->ssb.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);
+	return pci_read_config_dword(bcm->ssb.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);
+	return pci_write_config_word(bcm->ssb.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);
+	return pci_write_config_dword(bcm->ssb.pci_dev, offset, value);
 }
 
 /** Limit a value between two limits */
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c	2006-08-23 11:40:07.000000000 +0200
@@ -118,6 +118,9 @@
 //#define DEBUG_ENABLE_PCILOG
 
 
+static int bcm43xx_net_stop(struct net_device *net_dev);
+static int bcm43xx_net_open(struct net_device *net_dev);
+
 /* Detailed list maintained at:
  * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
  */
@@ -341,7 +344,7 @@
 	 * 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) {
+	if (bcm->ssb.current_core->rev >= 3) {
 		u32 low, high, high2;
 
 		do {
@@ -406,7 +409,7 @@
 	 * First zero out the low register, so we have a full
 	 * register-overflow duration to complete the operation.
 	 */
-	if (bcm->current_core->rev >= 3) {
+	if (bcm->ssb.current_core->rev >= 3) {
 		u32 lo = (tsf & 0x00000000FFFFFFFFULL);
 		u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
 
@@ -609,10 +612,10 @@
 	u16 version;
 	u8 revision;
 
-	if (bcm->chip_id == 0x4317) {
-		if (bcm->chip_rev == 0x00)
+	if (bcm->ssb.chip_id == 0x4317) {
+		if (bcm->ssb.chip_rev == 0x00)
 			radio_id = 0x3205017F;
-		else if (bcm->chip_rev == 0x01)
+		else if (bcm->ssb.chip_rev == 0x01)
 			radio_id = 0x4205017F;
 		else
 			radio_id = 0x5205017F;
@@ -657,140 +660,10 @@
 	return -ENODEV;
 }
 
-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;
-}
-
 #ifdef CONFIG_BCM947XX
-static void bcm43xx_aton(const char *str, char *dest)
+static void bcm43xx_aton(const char *str, u8 *dest)
 {
 	int i = 0;
-	u16 *d = (u16 *)dest;
 
 	for (;;) {
 		dest[i++] = (char)simple_strtoul(str, NULL, 16);
@@ -798,173 +671,76 @@
 		if (!*str++ || i == 6)
 			break;
 	}
-	for (i = 0; i < 3; i++)
-		d[i] = be16_to_cpu(d[i]);
 }
 #endif
 
 static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 {
-	u16 value;
-	u16 *sprom;
-#ifdef CONFIG_BCM947XX
-	const char *c;
-#endif
-
-	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
-			GFP_KERNEL);
-	if (!sprom) {
-		printk(KERN_ERR PFX "sprom_extract OOM\n");
-		return -ENOMEM;
-	}
-
-	bcm43xx_sprom_read(bcm, sprom);
+	int err = 0;
 
 #ifdef CONFIG_BCM947XX
-	/* In the case some settings are found in nvram, use them
-	 * to override those read from sprom.
+	char *c;
+
+	/* Can't read the SPROM on this embedded device.
+	 * (This would result in a bus error). Data is
+	 * stored in nvram instead.
 	 */
-	c = nvram_get("boardflags2");
-	if (c)
-		sprom[BCM43xx_SPROM_BOARDFLAGS2] = simple_strtoul(c, NULL, 0);
         c = nvram_get("boardflags");
 	if (c)
-		sprom[BCM43xx_SPROM_BOARDFLAGS] = simple_strtoul(c, NULL, 0);
+		bcm->sprom.r1.boardflags_lo = simple_strtoul(c, NULL, 0);
 	c = nvram_get("il0macaddr");
 	if (c)
-		bcm43xx_aton(c, (char *)&(sprom[BCM43xx_SPROM_IL0MACADDR]));
+		bcm43xx_aton(c, bcm->sprom.r1.il0mac);
 	c = nvram_get("et1macaddr");
 	if (c)
-		bcm43xx_aton(c, (char *)&(sprom[BCM43xx_SPROM_ET1MACADDR]));
+		bcm43xx_aton(c, bcm->sprom.r1.et1mac);
 	c = nvram_get("pa0b0");
 	if (c)
-		sprom[BCM43xx_SPROM_PA0B0] = simple_strtoul(c, NULL, 0);
+		bcm->sprom.r1.pa0b0 = simple_strtoul(c, NULL, 0);
 	c = nvram_get("pa0b1");
 	if (c)
-		sprom[BCM43xx_SPROM_PA0B1] = simple_strtoul(c, NULL, 0);
+		bcm->sprom.r1.pa0b1 = simple_strtoul(c, NULL, 0);
 	c = nvram_get("pa0b2");
 	if (c)
-		sprom[BCM43xx_SPROM_PA0B2] = simple_strtoul(c, NULL, 0);
+		bcm->sprom.r1.pa0b2 = simple_strtoul(c, NULL, 0);
 	c = nvram_get("pa1b0");
 	if (c)
-		sprom[BCM43xx_SPROM_PA1B0] = simple_strtoul(c, NULL, 0);
+		bcm->sprom.r1.pa1b0 = simple_strtoul(c, NULL, 0);
 	c = nvram_get("pa1b1");
 	if (c)
-		sprom[BCM43xx_SPROM_PA1B1] = simple_strtoul(c, NULL, 0);
+		bcm->sprom.r1.pa1b1 = simple_strtoul(c, NULL, 0);
 	c = nvram_get("pa1b2");
 	if (c)
-		sprom[BCM43xx_SPROM_PA1B2] = simple_strtoul(c, NULL, 0);
+		bcm->sprom.r1.pa1b2 = simple_strtoul(c, NULL, 0);
 	c = nvram_get("boardrev");
 	if (c)
-		sprom[BCM43xx_SPROM_BOARDREV] = simple_strtoul(c, NULL, 0);
-#endif
+		bcm->sprom.r1.board_rev = simple_strtoul(c, NULL, 0);
+	if (0)
+		goto out; /* suppress gcc warning about unused "out" */
+#else /* CONFIG_BCM947XX */
+
+	err = ssb_sprom_read(&bcm->ssb, &bcm->sprom, 0);
+	if (err)
+		goto out;
+
+#endif /* CONFIG_BCM947XX */
 
-	/* 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;
-
-	/* 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->ssb.chip_id == 0x4301 &&
 	    bcm->board_revision == 0x74)
-		bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST;
+		bcm->sprom.r1.boardflags_lo |= 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;
+		bcm->sprom.r1.boardflags_lo |= 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;
+	/* Convert Antennagain values to Q5.2 */
+	bcm->sprom.r1.antenna_gain_a <<= 2;
+	bcm->sprom.r1.antenna_gain_bg <<= 2;
 
-	kfree(sprom);
-
-	return 0;
+out:
+	return err;
 }
 
 /* DummyTransmission function, as documented on 
@@ -1079,7 +855,7 @@
 		return;
 
 	index -= 4;
-	if (bcm->current_core->rev >= 5) {
+	if (bcm->ssb.current_core->rev >= 5) {
 		bcm43xx_shm_write32(bcm,
 				    BCM43xx_SHM_HWMAC,
 				    index * 2,
@@ -1128,7 +904,7 @@
 	unsigned int i,j, nr_keys = 54;
 	u16 offset;
 
-	if (bcm->current_core->rev < 5)
+	if (bcm->ssb.current_core->rev < 5)
 		nr_keys = 16;
 	assert(nr_keys <= ARRAY_SIZE(bcm->key));
 
@@ -1147,194 +923,12 @@
 	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;
-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)) &&
+	if ((ssb_core_is_enabled(&bcm->ssb)) &&
 	    !bcm43xx_using_pio(bcm)) {
 //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
 #if 0
@@ -1345,7 +939,7 @@
 		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)
+		if (bcm->ssb.current_core->rev < 5)
 			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
 #endif
 #endif
@@ -1358,7 +952,7 @@
 		if (connect_phy)
 			flags |= 0x20000000;
 		bcm43xx_phy_connect(bcm, connect_phy);
-		bcm43xx_core_enable(bcm, flags);
+		ssb_core_enable(&bcm->ssb, flags);
 		bcm43xx_write16(bcm, 0x03E6, 0x0000);
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
 				bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
@@ -1370,7 +964,7 @@
 {
 	bcm43xx_radio_turn_off(bcm);
 	bcm43xx_write16(bcm, 0x03E6, 0x00F4);
-	bcm43xx_core_disable(bcm, 0);
+	ssb_core_disable(&bcm->ssb, 0);
 }
 
 /* Mark the current 80211 core inactive. */
@@ -1380,15 +974,15 @@
 
 	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 	bcm43xx_radio_turn_off(bcm);
-	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	sbtmstatelow = bcm43xx_read32(bcm, SSB_TMSLOW);
 	sbtmstatelow &= 0xDFF5FFFF;
 	sbtmstatelow |= 0x000A0000;
-	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	bcm43xx_write32(bcm, SSB_TMSLOW, sbtmstatelow);
 	udelay(1);
-	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	sbtmstatelow = bcm43xx_read32(bcm, SSB_TMSLOW);
 	sbtmstatelow &= 0xFFF5FFFF;
 	sbtmstatelow |= 0x00080000;
-	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	bcm43xx_write32(bcm, SSB_TMSLOW, sbtmstatelow);
 	udelay(1);
 }
 
@@ -1433,7 +1027,7 @@
 	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.core_at_start == bcm->ssb.current_core);
 	assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);
 }
 
@@ -1443,7 +1037,7 @@
 
 	if (bcm->noisecalc.calculation_running)
 		return;
-	bcm->noisecalc.core_at_start = bcm->current_core;
+	bcm->noisecalc.core_at_start = bcm->ssb.current_core;
 	bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;
 	bcm->noisecalc.calculation_running = 1;
 	bcm->noisecalc.nr_samples = 0;
@@ -1462,7 +1056,7 @@
 	/* Bottom half of Link Quality calculation. */
 
 	assert(bcm->noisecalc.calculation_running);
-	if (bcm->noisecalc.core_at_start != bcm->current_core ||
+	if (bcm->noisecalc.core_at_start != bcm->ssb.current_core ||
 	    bcm->noisecalc.channel_at_start != radio->channel)
 		goto drop_calculation;
 	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
@@ -1804,7 +1398,7 @@
 static void bcm43xx_set_beacon_int(struct bcm43xx_private *bcm, u16 beacon_int)
 {
 	bcm43xx_time_lock(bcm);
-	if (bcm->current_core->rev >= 3) {
+	if (bcm->ssb.current_core->rev >= 3) {
 		bcm43xx_write32(bcm, 0x188, (beacon_int << 16));
 	} else {
 		bcm43xx_write16(bcm, 0x606, (beacon_int >> 6));
@@ -1995,7 +1589,7 @@
 static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
 {
 	if (bcm43xx_using_pio(bcm) &&
-	    (bcm->current_core->rev < 3) &&
+	    (bcm->ssb.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);
@@ -2033,7 +1627,7 @@
 	spin_lock(&bcm->irq_lock);
 
 	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
-	assert(bcm->current_core->id == BCM43xx_COREID_80211);
+	assert(bcm->ssb.current_core->cc == SSB_CC_80211);
 
 	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) {
@@ -2090,7 +1684,7 @@
 static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-	u8 rev = bcm->current_core->rev;
+	u8 rev = bcm->ssb.current_core->rev;
 	int err = 0;
 	int nr;
 	char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
@@ -2099,7 +1693,7 @@
 		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
 			 (rev >= 5 ? 5 : rev),
 			 modparam_fwpostfix);
-		err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
+		err = request_firmware(&phy->ucode, buf, &bcm->ssb.pci_dev->dev);
 		if (err) {
 			printk(KERN_ERR PFX 
 			       "Error: Microcode \"%s\" not available or load failed.\n",
@@ -2113,7 +1707,7 @@
 			 "bcm43xx_pcm%d%s.fw",
 			 (rev < 5 ? 4 : 5),
 			 modparam_fwpostfix);
-		err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
+		err = request_firmware(&phy->pcm, buf, &bcm->ssb.pci_dev->dev);
 		if (err) {
 			printk(KERN_ERR PFX
 			       "Error: PCM \"%s\" not available or load failed.\n",
@@ -2153,7 +1747,7 @@
 		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
 			 nr, modparam_fwpostfix);
 
-		err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
+		err = request_firmware(&phy->initvals0, buf, &bcm->ssb.pci_dev->dev);
 		if (err) {
 			printk(KERN_ERR PFX 
 			       "Error: InitVals \"%s\" not available or load failed.\n",
@@ -2172,7 +1766,7 @@
 
 			switch (phy->type) {
 			case BCM43xx_PHYTYPE_A:
-				sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+				sbtmstatehigh = bcm43xx_read32(bcm, SSB_TMSHIGH);
 				if (sbtmstatehigh & 0x00010000)
 					nr = 9;
 				else
@@ -2188,7 +1782,7 @@
 			snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
 				 nr, modparam_fwpostfix);
 
-			err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
+			err = request_firmware(&phy->initvals1, buf, &bcm->ssb.pci_dev->dev);
 			if (err) {
 				printk(KERN_ERR PFX 
 				       "Error: InitVals \"%s\" not available or load failed.\n",
@@ -2298,9 +1892,9 @@
 {
 	int err;
 
-	bcm->irq = bcm->pci_dev->irq;
+	bcm->irq = bcm->ssb.pci_dev->irq;
 #ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0) {
+	if (bcm->ssb.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);
@@ -2322,22 +1916,26 @@
  */
 static int switch_to_gpio_core(struct bcm43xx_private *bcm)
 {
-	int err;
+	int err = -ENODEV;
 
 	/* 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");
-		}
+	if (bcm->core_chipcommon) {
+		err = ssb_switch_core(&bcm->ssb, bcm->core_chipcommon);
+		if (err)
+			goto out;
+	} else if (bcm->core_pci) {
+		err = ssb_switch_core(&bcm->ssb, bcm->core_pci);
+		if (err)
+			goto out;
+	} else {
+		printk(KERN_ERR PFX "gpio error: "
+				    "Neither ChipCommon nor PCI core available!\n");
 	}
-
+out:
 	return err;
 }
 
@@ -2346,7 +1944,7 @@
  */
 static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
 {
-	struct bcm43xx_coreinfo *old_core;
+	struct ssb_core *old_core;
 	int err;
 	u32 mask, set;
 
@@ -2360,7 +1958,7 @@
 
 	mask = 0x0000001F;
 	set = 0x0000000F;
-	if (bcm->chip_id == 0x4301) {
+	if (bcm->ssb.chip_id == 0x4301) {
 		mask |= 0x0060;
 		set |= 0x0060;
 	}
@@ -2371,23 +1969,23 @@
 		mask |= 0x0180;
 		set |= 0x0180;
 	}
-	if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
+	if (bcm->sprom.r1.boardflags_lo & 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)
+	if (bcm->ssb.current_core->rev >= 2)
 		mask  |= 0x0010; /* FIXME: This is redundant. */
 
-	old_core = bcm->current_core;
+	old_core = bcm->ssb.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);
+	err = ssb_switch_core(&bcm->ssb, old_core);
 out:
 	return err;
 }
@@ -2395,15 +1993,15 @@
 /* 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;
+	struct ssb_core *old_core;
 	int err;
 
-	old_core = bcm->current_core;
+	old_core = bcm->ssb.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);
+	err = ssb_switch_core(&bcm->ssb, old_core);
 	assert(err == 0);
 
 	return 0;
@@ -2493,7 +2091,7 @@
 	value = 0x0002;
 	if ((status & BCM43xx_SBF_MODE_NOTADHOC) &&
 	    !(status & BCM43xx_SBF_MODE_AP)) {
-		if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
+		if (bcm->ssb.chip_id == 0x4306 && bcm->ssb.chip_rev == 3)
 			value = 0x0064;
 		else
 			value = 0x0032;
@@ -2615,7 +2213,7 @@
 		bcm43xx_write16(bcm, 0x005E, value16);
 	}
 	bcm43xx_write32(bcm, 0x0100, 0x01000000);
-	if (bcm->current_core->rev < 5)
+	if (bcm->ssb.current_core->rev < 5)
 		bcm43xx_write32(bcm, 0x010C, 0x01000000);
 
 	value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
@@ -2644,7 +2242,7 @@
 	/* Initially set the wireless operation mode. */
 	bcm43xx_select_opmode(bcm);
 
-	if (bcm->current_core->rev < 3) {
+	if (bcm->ssb.current_core->rev < 3) {
 		bcm43xx_write16(bcm, 0x060E, 0x0000);
 		bcm43xx_write16(bcm, 0x0610, 0x8000);
 		bcm43xx_write16(bcm, 0x0604, 0x0000);
@@ -2661,9 +2259,9 @@
 	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
 	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
 
-	value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+	value32 = bcm43xx_read32(bcm, SSB_TMSLOW);
 	value32 |= 0x00100000;
-	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
+	bcm43xx_write32(bcm, SSB_TMSLOW, value32);
 
 	bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
 
@@ -2687,7 +2285,7 @@
 	bcm43xx_pio_free(bcm);
 	bcm43xx_dma_free(bcm);
 
-	bcm->current_core->initialized = 0;
+	bcm43xx_current_80211_priv(bcm)->initialized = 0;
 }
 
 /* http://bcm-specs.sipsolutions.net/80211Init */
@@ -2701,17 +2299,17 @@
 	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->ssb.chip_rev < 5) {
+		sbimconfiglow = bcm43xx_read32(bcm, SSB_IMCFGLO);
+		sbimconfiglow &= ~SSB_IMCFGLO_REQTO;
+		sbimconfiglow &= ~SSB_IMCFGLO_SERTO;
 		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_write32(bcm, SSB_IMCFGLO, sbimconfiglow);
 	}
 
 	bcm43xx_phy_calibrate(bcm);
@@ -2719,7 +2317,7 @@
 	if (err)
 		goto out;
 
-	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->ssb.current_core->rev);
 	ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
 
 	if (0 /*FIXME: which condition has to be used here? */)
@@ -2732,7 +2330,7 @@
 		ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
 		if (phy->rev == 1)
 			ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
-		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+		if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL)
 			ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
 	} else if (phy->type == BCM43xx_PHYTYPE_B) {
 		ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
@@ -2770,7 +2368,7 @@
 
 	bcm43xx_write_mac_bssid_templates(bcm);
 
-	if (bcm->current_core->rev >= 5)
+	if (bcm->ssb.current_core->rev >= 5)
 		bcm43xx_write16(bcm, 0x043C, 0x000C);
 
 	if (active_wlcore) {
@@ -2793,7 +2391,7 @@
 	/* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
 	 * We enable it later.
 	 */
-	bcm->current_core->initialized = 1;
+	bcm43xx_current_80211_priv(bcm)->initialized = 1;
 out:
 	return err;
 
@@ -2817,7 +2415,7 @@
 static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
 {
 	bcm43xx_phy_lo_mark_all_unused(bcm);
-	if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+	if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) {
 		bcm43xx_mac_suspend(bcm);
 		bcm43xx_calc_nrssi_slope(bcm);
 		bcm43xx_mac_enable(bcm);
@@ -2965,15 +2563,16 @@
 {
 	int ret = 0;
 	int i, err;
-	struct bcm43xx_coreinfo *core;
+	struct ssb_core *core;
+	struct bcm43xx_corepriv_80211 *wlpriv;
 
 	bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
 	for (i = 0; i < bcm->nr_80211_available; i++) {
-		core = &(bcm->core_80211[i]);
-		assert(core->available);
-		if (!core->initialized)
+		core = bcm->core_80211[i];
+		wlpriv = core->priv;
+		if (!wlpriv->initialized)
 			continue;
-		err = bcm43xx_switch_core(bcm, core);
+		err = ssb_switch_core(&bcm->ssb, core);
 		if (err) {
 			dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
 					     "switch_core failed (%d)\n", err);
@@ -3057,213 +2656,122 @@
 
 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->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;
+	struct ssb *ssb = &bcm->ssb;
+	int err;
+	u16 chipid_fallback = 0;
+	struct ssb_core *core;
+	struct bcm43xx_corepriv_80211 *priv_80211;
+	int i;
 
-	/* fetch sb_id_hi from core information registers */
-	sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
+	static const struct ssb_nrcores_elem nrcores_fallback[] = {
+		{ .chip_id_key = 0x5365, .nr_cores_value = 7, },
+		{ .chip_id_key = 0x4306, .nr_cores_value = 6, },
+		{ .chip_id_key = 0x4310, .nr_cores_value = 8, },
+		{ .chip_id_key = 0x4307, .nr_cores_value = 5, },
+		{ .chip_id_key = 0x4301, .nr_cores_value = 5, },
+		{ .chip_id_key = 0x4402, .nr_cores_value = 3, },
+		{ .chip_id_key = 0x4710, .nr_cores_value = 9, },
+		{ .chip_id_key = 0x4610, .nr_cores_value = 9, },
+		{ .chip_id_key = 0x4704, .nr_cores_value = 9, },
+	};
 
-	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;
+	switch (bcm->ssb.pci_dev->device) {
+	case 0x4301:
+		chipid_fallback = 0x4301;
+		break;
+	case 0x4305 ... 0x4307:
+		chipid_fallback = 0x4307;
+		break;
+	case 0x4402 ... 0x4403:
+		chipid_fallback = 0x4402;
+		break;
+	case 0x4610 ... 0x4615:
+		chipid_fallback = 0x4610;
+		break;
+	case 0x4710 ... 0x4715:
+		chipid_fallback = 0x4710;
+		break;
 #ifdef CONFIG_BCM947XX
-		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
-			chip_id_16 = 0x4309;
+	case 0x4320 ... 0x4325:
+		chipid_fallback = 0x4309;
+		break;
 #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");
 	}
+	err = ssb_probe_cores(ssb, chipid_fallback,
+			      nrcores_fallback,
+			      ARRAY_SIZE(nrcores_fallback));
+	if (err)
+		goto out;
 
-	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;
+	bcm->nr_80211_available = 0;
+	bcm->active_80211_core = NULL;
+	for (i = 0; i < ssb->nr_cores; i++) {
+		core = &(ssb->cores[i]);
 
-		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) {
+		switch (core->cc) {
+		case SSB_CC_PCI:
+			if (bcm->core_pci) {
 				printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
-				continue;
+				break;
 			}
+			bcm->core_pci = core;
 			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",
+		case SSB_CC_80211:
+			if (bcm->nr_80211_available == BCM43xx_MAX_80211_CORES) {
+				printk(KERN_WARNING PFX "More tham %d cores of "
+							"type 802.11 found.\n",
 				       BCM43xx_MAX_80211_CORES);
-				continue;
+				break;
 			}
-			if (i != 0) {
+			if (bcm->nr_80211_available == 1) {
 				/* 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) {
+				if (bcm->ssb.pci_dev->device != 0x4324) {
 					dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
-					continue;
+					break;
 				}
 			}
-			switch (core_rev) {
-			case 2:
-			case 4:
-			case 5:
-			case 6:
-			case 7:
-			case 9:
+
+			bcm->core_80211[bcm->nr_80211_available] = core;
+			priv_80211 = &(bcm->corepriv_80211[bcm->nr_80211_available]);
+			bcm->nr_80211_available++;
+
+			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);
+				       core->rev);
 				err = -ENODEV;
 				goto out;
 			}
-			bcm->nr_80211_available++;
-			core->priv = ext_80211;
-			bcm43xx_init_struct_phyinfo(&ext_80211->phy);
-			bcm43xx_init_struct_radioinfo(&ext_80211->radio);
+			core->priv = priv_80211;
+			bcm43xx_init_struct_phyinfo(&priv_80211->phy);
+			bcm43xx_init_struct_radioinfo(&priv_80211->radio);
 			break;
-		case BCM43xx_COREID_CHIPCOMMON:
-			printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
+		case SSB_CC_CHIPCOMMON:
+			if (bcm->core_chipcommon) {
+				printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
+				break;
+			}
+			bcm->core_chipcommon = core;
 			break;
 		}
-		if (core) {
-			core->available = 1;
-			core->id = core_id;
-			core->rev = core_rev;
-			core->index = current_core;
-		}
 	}
-
-	if (!bcm->core_80211[0].available) {
+	if (!bcm->core_80211[0]) {
 		printk(KERN_ERR PFX "Error: No 80211 core found!\n");
 		err = -ENODEV;
 		goto out;
 	}
+	err = ssb_switch_core(ssb, bcm->core_80211[0]);
+	if (err)
+		goto out;
 
-	err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
-
-	assert(err == 0);
 out:
 	return err;
 }
@@ -3289,90 +2797,6 @@
 	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_free_modes(struct bcm43xx_private *bcm)
 {
 	struct ieee80211_hw *ieee = bcm->ieee;
@@ -3434,8 +2858,8 @@
 {
 	int err = -ENOMEM;
 	struct ieee80211_hw *ieee = bcm->ieee;
-	struct bcm43xx_coreinfo *core;
-	struct bcm43xx_coreinfo_80211 *wlext;
+	struct ssb_core *core;
+	struct bcm43xx_corepriv_80211 *wlpriv;
 	int i, nr_modes;
 
 	nr_modes = bcm->nr_80211_available;
@@ -3446,10 +2870,10 @@
 	ieee->num_modes = 0;
 
 	for (i = 0; i < bcm->nr_80211_available; i++) {
-		core = &(bcm->core_80211[i]);
-		wlext = core->priv;
+		core = bcm->core_80211[i];
+		wlpriv = core->priv;
 
-		switch (wlext->phy.type) {
+		switch (wlpriv->phy.type) {
 		case BCM43xx_PHYTYPE_A:
 			err = bcm43xx_append_mode(bcm->ieee, MODE_IEEE80211A,
 						  ARRAY_SIZE(bcm43xx_a_chantable),
@@ -3543,8 +2967,8 @@
 static void prepare_priv_for_init(struct bcm43xx_private *bcm)
 {
 	int i;
-	struct bcm43xx_coreinfo *core;
-	struct bcm43xx_coreinfo_80211 *wlext;
+	struct ssb_core *core;
+	struct bcm43xx_corepriv_80211 *wlpriv;
 
 	assert(!bcm->active_80211_core);
 
@@ -3558,16 +2982,13 @@
 	memset(&bcm->stats, 0, sizeof(bcm->stats));
 
 	/* Wireless core data */
-	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
-		core = &(bcm->core_80211[i]);
-		wlext = core->priv;
-
-		if (!core->available)
-			continue;
-		assert(wlext == &(bcm->core_80211_ext[i]));
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		core = bcm->core_80211[i];
+		wlpriv = core->priv;
+		assert(wlpriv == &(bcm->corepriv_80211[i]));
 
-		prepare_phydata_for_init(&wlext->phy);
-		prepare_radiodata_for_init(bcm, &wlext->radio);
+		prepare_phydata_for_init(&wlpriv->phy);
+		prepare_radiodata_for_init(bcm, &wlpriv->radio);
 	}
 
 	/* IRQ related flags */
@@ -3589,7 +3010,7 @@
 {
 	int err;
 
-	if (!bcm43xx_core_enabled(bcm))
+	if (!ssb_core_is_enabled(&bcm->ssb))
 		bcm43xx_wireless_core_reset(bcm, 1);
 	if (!active_wlcore)
 		bcm43xx_wireless_core_mark_inactive(bcm);
@@ -3610,27 +3031,27 @@
 				 int phytype)
 {
 	int i, err;
-	struct bcm43xx_coreinfo *active_core = NULL;
-	struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
-	struct bcm43xx_coreinfo *core;
-	struct bcm43xx_coreinfo_80211 *wlext;
+	struct ssb_core *active_core = NULL;
+	struct bcm43xx_corepriv_80211 *active_wlpriv = NULL;
+	struct ssb_core *core;
+	struct bcm43xx_corepriv_80211 *wlpriv;
 	int adjust_active_sbtmstatelow = 0;
 
 	might_sleep();
 
 	if (phytype < 0) {
 		/* If no phytype is requested, select the first core. */
-		assert(bcm->core_80211[0].available);
-		wlext = bcm->core_80211[0].priv;
-		phytype = wlext->phy.type;
+		assert(bcm->nr_80211_available != 0);
+		wlpriv = bcm->core_80211[0]->priv;
+		phytype = wlpriv->phy.type;
 	}
 	/* Find the requested core. */
 	for (i = 0; i < bcm->nr_80211_available; i++) {
-		core = &(bcm->core_80211[i]);
-		wlext = core->priv;
-		if (wlext->phy.type == phytype) {
+		core = bcm->core_80211[i];
+		wlpriv = core->priv;
+		if (wlpriv->phy.type == phytype) {
 			active_core = core;
-			active_wlext = wlext;
+			active_wlpriv = wlpriv;
 			break;
 		}
 	}
@@ -3667,12 +3088,12 @@
 
 	/* Mark all unused cores "inactive". */
 	for (i = 0; i < bcm->nr_80211_available; i++) {
-		core = &(bcm->core_80211[i]);
-		wlext = core->priv;
+		core = bcm->core_80211[i];
+		wlpriv = core->priv;
 
 		if (core == active_core)
 			continue;
-		err = bcm43xx_switch_core(bcm, core);
+		err = ssb_switch_core(&bcm->ssb, core);
 		if (err) {
 			dprintk(KERN_ERR PFX "Could not switch to inactive "
 					     "802.11 core (%d)\n", err);
@@ -3688,19 +3109,19 @@
 	}
 
 	/* Now initialize the active 802.11 core. */
-	err = bcm43xx_switch_core(bcm, active_core);
+	err = ssb_switch_core(&bcm->ssb, active_core);
 	if (err) {
 		dprintk(KERN_ERR PFX "Could not switch to active "
 				     "802.11 core (%d)\n", err);
 		goto error;
 	}
 	if (adjust_active_sbtmstatelow &&
-	    active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
+	    active_wlpriv->phy.type == BCM43xx_PHYTYPE_G) {
 		u32 sbtmstatelow;
 
-		sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		sbtmstatelow = bcm43xx_read32(bcm, SSB_TMSLOW);
 		sbtmstatelow |= 0x20000000;
-		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+		bcm43xx_write32(bcm, SSB_TMSLOW, sbtmstatelow);
 	}
 	err = wireless_core_up(bcm, 1);
 	if (err) {
@@ -3732,7 +3153,7 @@
 	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
 
 	dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
-		active_wlext->phy.type);
+		active_wlpriv->phy.type);
 
 	return 0;
 
@@ -3778,20 +3199,21 @@
 
 static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
 {
-	struct pci_dev *pci_dev = bcm->pci_dev;
+	struct pci_dev *pci_dev = bcm->ssb.pci_dev;
 	int i;
 
 	bcm43xx_chipset_detach(bcm);
+	ssb_exit(&bcm->ssb);
 	/* Do _not_ access the chip, after it is detached. */
-	pci_iounmap(pci_dev, bcm->mmio_addr);
+	pci_iounmap(pci_dev, bcm->ssb.mmio);
 	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);
+		kfree(bcm->corepriv_80211[i].phy._lo_pairs);
+		if (bcm->corepriv_80211[i].phy.dyn_tssi_tbl)
+			kfree(bcm->corepriv_80211[i].phy.tssi2dbm);
 	}
 	bcm43xx_free_modes(bcm);
 }
@@ -3852,13 +3274,42 @@
 	return 0;
 }
 
-static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
+static int bcm43xx_ssb_suspend(struct ssb *ssb)
+{
+	int i;
+	int err;
+	struct bcm43xx_private *bcm = ssb_to_bcm43xx(ssb);
+
+	for (i = 0; i < bcm->ieee->queues; i++)
+		ieee80211_stop_queue(bcm->net_dev, i);
+	ieee80211_netif_oper(bcm->net_dev, NETIF_DETACH);
+
+	err = bcm43xx_net_stop(bcm->net_dev);
+	if (!err)
+		mutex_lock(&bcm->mutex);
+
+	return err;
+}
+
+static int bcm43xx_ssb_resume(struct ssb *ssb)
+{
+	int err;
+	struct bcm43xx_private *bcm = ssb_to_bcm43xx(ssb);
+
+	mutex_unlock(&bcm->mutex);
+	err = bcm43xx_net_open(bcm->net_dev);
+
+	return err;
+}
+
+static int bcm43xx_attach_board(struct bcm43xx_private *bcm,
+				struct pci_dev *pci_dev)
 {
-	struct pci_dev *pci_dev = bcm->pci_dev;
 	struct net_device *net_dev = bcm->net_dev;
 	int err;
 	int i;
 	u32 coremask;
+	void __iomem *mmio;
 
 	err = pci_enable_device(pci_dev);
 	if (err) {
@@ -3872,13 +3323,19 @@
 	}
 	/* enable PCI bus-mastering */
 	pci_set_master(pci_dev);
-	bcm->mmio_addr = pci_iomap(pci_dev, 0, ~0UL);
-	if (!bcm->mmio_addr) {
+	mmio = pci_iomap(pci_dev, 0, ~0UL);
+	if (!mmio) {
 		printk(KERN_ERR PFX "pci_iomap() failed\n");
 		err = -EIO;
 		goto err_pci_release;
 	}
-	net_dev->base_addr = (unsigned long)bcm->mmio_addr;
+	net_dev->base_addr = (unsigned long)mmio;
+
+	err = ssb_init(&bcm->ssb, pci_dev, mmio,
+		       bcm43xx_ssb_suspend,
+		       bcm43xx_ssb_resume);
+	if (err)
+		goto err_iounmap;
 
 	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
 	                          &bcm->board_vendor);
@@ -3889,22 +3346,23 @@
 
 	err = bcm43xx_chipset_attach(bcm);
 	if (err)
-		goto err_iounmap;
+		goto err_ssb_exit;
 	err = bcm43xx_pctl_init(bcm);
 	if (err)
 		goto err_chipset_detach;
 	err = bcm43xx_probe_cores(bcm);
 	if (err)
 		goto err_chipset_detach;
-	
+
+	printk(KERN_INFO PFX "Broadcom %04X WLAN found\n", bcm->ssb.chip_id);
+
 	/* 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);
+		coremask |= (1 << bcm->core_80211[i]->index);
+	err = ssb_cores_connect(&bcm->ssb, coremask);
 	if (err) {
-		printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
+		printk(KERN_ERR PFX "Could not connect cores\n");
 		goto err_chipset_detach;
 	}
 
@@ -3916,7 +3374,7 @@
 		goto err_chipset_detach;
 
 	for (i = 0; i < bcm->nr_80211_available; i++) {
-		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
+		err = ssb_switch_core(&bcm->ssb, bcm->core_80211[i]);
 		assert(err != -ENODEV);
 		if (err)
 			goto err_80211_unwind;
@@ -3947,29 +3405,28 @@
 	bcm43xx_pctl_set_crystal(bcm, 0);
 
 	/* Set the MAC address in the networking subsystem */
-	if (is_valid_ether_addr(bcm->sprom.et1macaddr))
-		memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
+	if (is_valid_ether_addr(bcm->sprom.r1.et1mac))
+		memcpy(bcm->net_dev->dev_addr, bcm->sprom.r1.et1mac, 6);
 	else
-		memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
+		memcpy(bcm->net_dev->dev_addr, bcm->sprom.r1.il0mac, 6);
 	bcm43xx_setup_modes(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);
+		kfree(bcm->corepriv_80211[i].phy._lo_pairs);
+		if (bcm->corepriv_80211[i].phy.dyn_tssi_tbl)
+			kfree(bcm->corepriv_80211[i].phy.tssi2dbm);
 	}
 err_chipset_detach:
 	bcm43xx_chipset_detach(bcm);
+err_ssb_exit:
+	ssb_exit(&bcm->ssb);
 err_iounmap:
-	pci_iounmap(pci_dev, bcm->mmio_addr);
+	pci_iounmap(pci_dev, mmio);
 err_pci_release:
 	pci_release_regions(pci_dev);
 err_pci_disable:
@@ -4386,7 +3843,6 @@
 
 	bcm->ieee = ieee;
 	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->irq_lock);
@@ -4475,7 +3931,7 @@
 	pci_set_drvdata(pdev, net_dev);
 	SET_NETDEV_DEV(net_dev, &pdev->dev);
 
-	err = bcm43xx_attach_board(bcm);
+	err = bcm43xx_attach_board(bcm, pdev);
 	if (err)
 		goto err_free_netdev;
 	err = ieee80211_register_hw(net_dev, ieee);
@@ -4632,7 +4088,6 @@
 
 static int __init bcm43xx_init(void)
 {
-	printk(KERN_INFO KBUILD_MODNAME " driver\n");
 	bcm43xx_debugfs_init();
 	return pci_register_driver(&bcm43xx_pci_driver);
 }
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_debugfs.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_debugfs.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_debugfs.c	2006-08-23 10:58:41.000000000 +0200
@@ -84,7 +84,7 @@
 		goto out;
 	}
 	net_dev = bcm->net_dev;
-	pci_dev = bcm->pci_dev;
+	pci_dev = bcm->ssb.pci_dev;
 
 	/* This is where the information is written to the "devinfo" file */
 	fappend("*** %s devinfo ***\n", net_dev->name);
@@ -93,23 +93,23 @@
 	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\n", bcm->mmio_addr);
-	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("mmio: 0x%p\n", bcm->ssb.mmio);
+	fappend("chip_id: 0x%04x   chip_rev: 0x%02x\n", bcm->ssb.chip_id, bcm->ssb.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)))
+	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, "	\
+#define fappend_core(name, info) fappend("core \"" name "\" %s, id: 0x%04x, "		\
 					 "rev: 0x%02x, index: 0x%02x\n",		\
-					 (info).available				\
+					 (info)						\
 						? "available" : "nonavailable",		\
-					 (info).enabled					\
-						? "enabled" : "disabled",		\
-					 (info).id, (info).rev, (info).index)
+					 (info) ? (info)->cc : 0,			\
+					 (info) ? (info)->rev : 0,			\
+					 (info) ? (info)->index : 0)
 	fappend_core("CHIPCOMMON", bcm->core_chipcommon);
 	fappend_core("PCI", bcm->core_pci);
 	fappend_core("first 80211", bcm->core_80211[0]);
@@ -149,36 +149,6 @@
 	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);
-	mutex_lock(&bcm->mutex);
-	spin_lock_irqsave(&bcm->irq_lock, flags);
-	if (bcm43xx_status(bcm) != BCM43xx_STAT_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:
-	spin_unlock_irqrestore(&bcm->irq_lock, flags);
-	mutex_unlock(&bcm->mutex);
-	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)
 {
@@ -361,12 +331,6 @@
 	.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,
@@ -429,10 +393,6 @@
 						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)
@@ -456,7 +416,6 @@
 
 	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);
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c	2006-08-23 10:58:41.000000000 +0200
@@ -327,11 +327,11 @@
 	dma_addr_t dmaaddr;
 
 	if (tx) {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+		dmaaddr = dma_map_single(&ring->bcm->ssb.pci_dev->dev,
 					 buf, len,
 					 DMA_TO_DEVICE);
 	} else {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+		dmaaddr = dma_map_single(&ring->bcm->ssb.pci_dev->dev,
 					 buf, len,
 					 DMA_FROM_DEVICE);
 	}
@@ -346,11 +346,11 @@
 		      int tx)
 {
 	if (tx) {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		dma_unmap_single(&ring->bcm->ssb.pci_dev->dev,
 				 addr, len,
 				 DMA_TO_DEVICE);
 	} else {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		dma_unmap_single(&ring->bcm->ssb.pci_dev->dev,
 				 addr, len,
 				 DMA_FROM_DEVICE);
 	}
@@ -363,7 +363,7 @@
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
+	dma_sync_single_for_cpu(&ring->bcm->ssb.pci_dev->dev,
 				addr, len, DMA_FROM_DEVICE);
 }
 
@@ -374,7 +374,7 @@
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
+	dma_sync_single_for_device(&ring->bcm->ssb.pci_dev->dev,
 				   addr, len, DMA_FROM_DEVICE);
 }
 
@@ -393,7 +393,7 @@
 
 static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
 {
-	struct device *dev = &(ring->bcm->pci_dev->dev);
+	struct device *dev = &(ring->bcm->ssb.pci_dev->dev);
 
 	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
 					    &(ring->dmabase), GFP_KERNEL);
@@ -408,7 +408,7 @@
 
 static void free_ringmemory(struct bcm43xx_dmaring *ring)
 {
-	struct device *dev = &(ring->bcm->pci_dev->dev);
+	struct device *dev = &(ring->bcm->ssb.pci_dev->dev);
 
 	dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
 			  ring->descbase, ring->dmabase);
@@ -727,7 +727,7 @@
 	if (dma64)
 		ring->routing = BCM43xx_DMA64_CLIENTTRANS;
 #ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0)
+	if (bcm->ssb.pci_dev->bus->number == 0)
 		ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
 #endif
 
@@ -832,8 +832,8 @@
 	int dma64 = 0;
 	u32 sbtmstatehi;
 
-	sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
-	if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT)
+	sbtmstatehi = bcm43xx_read32(bcm, SSB_TMSHIGH);
+	if (sbtmstatehi & SSB_TMSHIGH_DMA64)
 		dma64 = 1;
 
 	/* setup TX DMA channels. */
@@ -873,7 +873,7 @@
 		goto err_destroy_tx5;
 	dma->rx_ring0 = ring;
 
-	if (bcm->current_core->rev < 5) {
+	if (bcm->ssb.current_core->rev < 5) {
 		ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
 		if (!ring)
 			goto err_destroy_rx0;
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.h	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.h	2006-08-23 10:58:41.000000000 +0200
@@ -128,8 +128,6 @@
 
 void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
 
-int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
-
 int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
 				 int phytype);
 
@@ -140,7 +138,4 @@
 
 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_ */
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_phy.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_phy.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_phy.c	2006-08-23 10:58:41.000000000 +0200
@@ -90,7 +90,7 @@
 		phy->is_locked = 0;
 		return;
 	}
-	if (bcm->current_core->rev < 3) {
+	if (bcm->ssb.current_core->rev < 3) {
 		bcm43xx_mac_suspend(bcm);
 		spin_lock(&phy->lock);
 	} else {
@@ -105,7 +105,7 @@
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 
 	assert(irqs_disabled());
-	if (bcm->current_core->rev < 3) {
+	if (bcm->ssb.current_core->rev < 3) {
 		if (phy->is_locked) {
 			spin_unlock(&phy->lock);
 			bcm43xx_mac_enable(bcm);
@@ -161,22 +161,22 @@
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	u32 flags;
 
-	if (bcm->current_core->rev < 5)
+	if (bcm->ssb.current_core->rev < 5)
 		goto out;
 
-	flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+	flags = bcm43xx_read32(bcm, SSB_TMSHIGH);
 	if (connect) {
 		if (!(flags & 0x00010000))
 			return -ENODEV;
-		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		flags = bcm43xx_read32(bcm, SSB_TMSLOW);
 		flags |= (0x800 << 18);
-		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
+		bcm43xx_write32(bcm, SSB_TMSLOW, flags);
 	} else {
 		if (!(flags & 0x00020000))
 			return -ENODEV;
-		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		flags = bcm43xx_read32(bcm, SSB_TMSHIGH);
 		flags &= ~(0x800 << 18);
-		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
+		bcm43xx_write32(bcm, SSB_TMSLOW, flags);
 	}
 out:
 	phy->connected = connect;
@@ -565,7 +565,7 @@
 		bcm43xx_phy_setupa(bcm);
 	} else {
 		bcm43xx_phy_setupg(bcm);
-		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+		if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL)
 			bcm43xx_phy_write(bcm, 0x046E, 0x03CF);
 		return;
 	}
@@ -715,7 +715,7 @@
 	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) {
+	if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) {
 		bcm43xx_calc_nrssi_slope(bcm);
 		bcm43xx_calc_nrssi_threshold(bcm);
 	}
@@ -895,7 +895,7 @@
 		bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
 		bcm43xx_radio_write16(bcm, 0x005B, 0x006B);
 		bcm43xx_radio_write16(bcm, 0x005C, 0x000F);
-		if (bcm->sprom.boardflags & 0x8000) {
+		if (bcm->sprom.r1.boardflags_lo & 0x8000) {
 			bcm43xx_radio_write16(bcm, 0x005D, 0x00FA);
 			bcm43xx_radio_write16(bcm, 0x005E, 0x00D8);
 		} else {
@@ -985,7 +985,7 @@
 		bcm43xx_phy_write(bcm, 0x0062, 0x0007);
 		(void) bcm43xx_radio_calibrationvalue(bcm);
 		bcm43xx_phy_lo_b_measure(bcm);
-		if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+		if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) {
 			bcm43xx_calc_nrssi_slope(bcm);
 			bcm43xx_calc_nrssi_threshold(bcm);
 		}
@@ -1105,7 +1105,7 @@
 			  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 (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_EXTLNA) {
 		if (phy->rev >= 7) {
 			bcm43xx_phy_write(bcm, 0x0811,
 					  bcm43xx_phy_read(bcm, 0x0811)
@@ -1252,7 +1252,7 @@
 					   & 0xF000) | (FIXME << 12));
 			*/
 		}
-		if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
+		if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL)
 			bcm43xx_phy_write(bcm, 0x002E, 0x8075);
 		else
 			bcm43xx_phy_write(bcm, 0x003E, 0x807F);
@@ -1266,7 +1266,7 @@
 		bcm43xx_phy_write(bcm, 0x080F, 0x8078);
 	}
 
-	if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
+	if (!(bcm->sprom.r1.boardflags_lo & 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.
@@ -1287,7 +1287,7 @@
 	if (radio->revision == 8)
 		bcm43xx_phy_write(bcm, 0x0805, 0x3230);
 	bcm43xx_phy_init_pctl(bcm);
-	if (bcm->chip_id == 0x4306 && bcm->chip_package == 2) {
+	if (bcm->ssb.chip_id == 0x4306 && bcm->ssb.chip_package == 2) {
 		bcm43xx_phy_write(bcm, 0x0429,
 				  bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF);
 		bcm43xx_phy_write(bcm, 0x04C3,
@@ -1985,9 +1985,9 @@
 
 		estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average);
 
-		max_pwr = bcm->sprom.maxpower_bgphy;
+		max_pwr = bcm->sprom.r1.maxpwr_bg;
 
-		if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) &&
+		if ((bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) &&
 		    (phy->type == BCM43xx_PHYTYPE_G))
 			max_pwr -= 0x3;
 
@@ -2043,7 +2043,7 @@
 					txpower = 3;
 					radio_attenuation += 2;
 					baseband_attenuation += 2;
-				} else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
+				} else if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) {
 					baseband_attenuation += 4 * (radio_attenuation - 2);
 					radio_attenuation = 2;
 				}
@@ -2116,16 +2116,16 @@
 	s8 *dyn_tssi2dbm;
 	
 	if (phy->type == BCM43xx_PHYTYPE_A) {
-		pab0 = (s16)(bcm->sprom.pa1b0);
-		pab1 = (s16)(bcm->sprom.pa1b1);
-		pab2 = (s16)(bcm->sprom.pa1b2);
+		pab0 = (s16)(bcm->sprom.r1.pa1b0);
+		pab1 = (s16)(bcm->sprom.r1.pa1b1);
+		pab2 = (s16)(bcm->sprom.r1.pa1b2);
 	} else {
-		pab0 = (s16)(bcm->sprom.pa0b0);
-		pab1 = (s16)(bcm->sprom.pa0b1);
-		pab2 = (s16)(bcm->sprom.pa0b2);
+		pab0 = (s16)(bcm->sprom.r1.pa0b0);
+		pab1 = (s16)(bcm->sprom.r1.pa0b1);
+		pab2 = (s16)(bcm->sprom.r1.pa0b2);
 	}
 
-	if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) {
+	if ((bcm->ssb.chip_id == 0x4301) && (radio->version != 0x2050)) {
 		phy->idle_tssi = 0x34;
 		phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
 		return 0;
@@ -2135,15 +2135,15 @@
 	    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);
+			if ((s8)bcm->sprom.r1.itssi_a != 0 &&
+			    (s8)bcm->sprom.r1.itssi_a != -1)
+				phy->idle_tssi = (s8)(bcm->sprom.r1.itssi_a);
 			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);
+			if ((s8)bcm->sprom.r1.itssi_bg != 0 &&
+			    (s8)bcm->sprom.r1.itssi_bg != -1)
+				phy->idle_tssi = (s8)(bcm->sprom.r1.itssi_bg);
 			else
 				phy->idle_tssi = 62;
 		}
@@ -2329,7 +2329,7 @@
 		}
 		break;
 	case BCM43xx_PHYTYPE_B:
-		if (bcm->current_core->rev == 2)
+		if (bcm->ssb.current_core->rev == 2)
 			value = (3/*automatic*/ << 7);
 		else
 			value = (antennadiv << 7);
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_pio.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_pio.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_pio.c	2006-08-23 10:58:41.000000000 +0200
@@ -315,7 +315,7 @@
 
 	queue->bcm = bcm;
 	queue->mmio_base = pio_mmio_base;
-	queue->need_workarounds = (bcm->current_core->rev < 3);
+	queue->need_workarounds = (bcm->ssb.current_core->rev < 3);
 
 	INIT_LIST_HEAD(&queue->txfree);
 	INIT_LIST_HEAD(&queue->txqueue);
@@ -419,7 +419,7 @@
 		goto err_destroy2;
 	pio->queue3 = queue;
 
-	if (bcm->current_core->rev < 3)
+	if (bcm->ssb.current_core->rev < 3)
 		bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND;
 
 	dprintk(KERN_INFO PFX "PIO initialized\n");
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_power.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_power.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_power.c	2006-08-23 10:58:41.000000000 +0200
@@ -41,8 +41,8 @@
 	u32 tmp;
 	int err;
 
-	assert(bcm->current_core == &bcm->core_chipcommon);
-	if (bcm->current_core->rev < 6) {
+	assert(bcm->ssb.current_core == bcm->core_chipcommon);
+	if (bcm->ssb.current_core->rev < 6) {
 		if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA ||
 		    bcm->bustype == BCM43xx_BUSTYPE_SB)
 			return BCM43xx_PCTL_CLKSRC_XTALOS;
@@ -54,8 +54,8 @@
 			return BCM43xx_PCTL_CLKSRC_XTALOS;
 		}
 	}
-	if (bcm->current_core->rev < 10) {
-		tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+	if (bcm->ssb.current_core->rev < 10) {
+		tmp = bcm43xx_read32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL);
 		tmp &= 0x7;
 		if (tmp == 0)
 			return BCM43xx_PCTL_CLKSRC_LOPWROS;
@@ -79,11 +79,11 @@
 	int divisor;
 	u32 tmp;
 
-	assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL);
-	assert(bcm->current_core == &bcm->core_chipcommon);
+	assert(bcm->ssb.chipcommon_capabilities & SSB_CHIPCOMMON_CAP_PCTL);
+	assert(bcm->ssb.current_core == bcm->core_chipcommon);
 
 	clocksrc = bcm43xx_pctl_get_slowclksrc(bcm);
-	if (bcm->current_core->rev < 6) {
+	if (bcm->ssb.current_core->rev < 6) {
 		switch (clocksrc) {
 		case BCM43xx_PCTL_CLKSRC_PCI:
 			divisor = 64;
@@ -95,14 +95,14 @@
 			assert(0);
 			divisor = 1;
 		}
-	} else if (bcm->current_core->rev < 10) {
+	} else if (bcm->ssb.current_core->rev < 10) {
 		switch (clocksrc) {
 		case BCM43xx_PCTL_CLKSRC_LOPWROS:
 			divisor = 1;
 			break;
 		case BCM43xx_PCTL_CLKSRC_XTALOS:
 		case BCM43xx_PCTL_CLKSRC_PCI:
-			tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+			tmp = bcm43xx_read32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL);
 			divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
 			divisor *= 4;
 			break;
@@ -111,7 +111,7 @@
 			divisor = 1;
 		}
 	} else {
-		tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
+		tmp = bcm43xx_read32(bcm, SSB_CHIPCOMMON_SYSCLKCTL);
 		divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
 		divisor *= 4;
 	}
@@ -151,24 +151,25 @@
 int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
 {
 	int err, maxfreq;
-	struct bcm43xx_coreinfo *old_core;
+	struct ssb_core *old_core;
 
-	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+	if (!(bcm->ssb.chipcommon_capabilities & SSB_CHIPCOMMON_CAP_PCTL))
 		return 0;
-	old_core = bcm->current_core;
-	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
-	if (err == -ENODEV)
+	if (!bcm->core_chipcommon)
 		return 0;
+
+	old_core = bcm->ssb.current_core;
+	err = ssb_switch_core(&bcm->ssb, bcm->core_chipcommon);
 	if (err)
 		goto out;
 
 	maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
-	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
+	bcm43xx_write32(bcm, SSB_CHIPCOMMON_PLLONDELAY,
 			(maxfreq * 150 + 999999) / 1000000);
-	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
+	bcm43xx_write32(bcm, SSB_CHIPCOMMON_FREFSELDELAY,
 			(maxfreq * 15 + 999999) / 1000000);
 
-	err = bcm43xx_switch_core(bcm, old_core);
+	err = ssb_switch_core(&bcm->ssb, old_core);
 	assert(err == 0);
 
 out:
@@ -180,23 +181,26 @@
 	u16 delay = 0;
 	int err;
 	u32 pll_on_delay;
-	struct bcm43xx_coreinfo *old_core;
+	struct ssb_core *old_core;
 	int minfreq;
 
 	if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
 		goto out;
-	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
+	if (!(bcm->ssb.chipcommon_capabilities & SSB_CHIPCOMMON_CAP_PCTL))
 		goto out;
-	old_core = bcm->current_core;
-	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
-	if (err == -ENODEV)
+	if (!bcm->core_chipcommon)
+		goto out;
+
+	old_core = bcm->ssb.current_core;
+	err = ssb_switch_core(&bcm->ssb, bcm->core_chipcommon);
+	if (err)
 		goto out;
 
 	minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
-	pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
+	pll_on_delay = bcm43xx_read32(bcm, SSB_CHIPCOMMON_PLLONDELAY);
 	delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
 
-	err = bcm43xx_switch_core(bcm, old_core);
+	err = ssb_switch_core(&bcm->ssb, old_core);
 	assert(err == 0);
 
 out:
@@ -209,47 +213,48 @@
 int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
 {
 	int err;
-	struct bcm43xx_coreinfo *old_core;
+	struct ssb_core *old_core;
 	u32 tmp;
 
-	old_core = bcm->current_core;
-	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
-	if (err == -ENODEV)
+	if (!bcm->core_chipcommon)
 		return 0;
+
+	old_core = bcm->ssb.current_core;
+	err = ssb_switch_core(&bcm->ssb, bcm->core_chipcommon);
 	if (err)
 		goto out;
-	
-	if (bcm->core_chipcommon.rev < 6) {
+
+	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)) {
+		if ((bcm->ssb.chipcommon_capabilities & SSB_CHIPCOMMON_CAP_PCTL) &&
+		    (bcm->core_chipcommon->rev < 10)) {
 			switch (mode) {
 			case BCM43xx_PCTL_CLK_FAST:
-				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp = bcm43xx_read32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL);
 				tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
-				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+				bcm43xx_write32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL, tmp);
 				break;
 			case BCM43xx_PCTL_CLK_SLOW:
-				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp = bcm43xx_read32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL);
 				tmp |= BCM43xx_PCTL_FORCE_SLOW;
-				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+				bcm43xx_write32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL, tmp);
 				break;
 			case BCM43xx_PCTL_CLK_DYNAMIC:
-				tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
+				tmp = bcm43xx_read32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL);
 				tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
 				tmp |= BCM43xx_PCTL_FORCE_PLL;
 				tmp &= ~BCM43xx_PCTL_DYN_XTAL;
-				bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
+				bcm43xx_write32(bcm, SSB_CHIPCOMMON_SLOWCLKCTL, tmp);
 			}
 		}
 	}
 	
-	err = bcm43xx_switch_core(bcm, old_core);
+	err = ssb_switch_core(&bcm->ssb, old_core);
 	assert(err == 0);
 
 out:
@@ -261,6 +266,8 @@
 	int err;
 	u32 in, out, outenable;
 
+	might_sleep();
+
 	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
 	if (err)
 		goto err_pci;
@@ -285,33 +292,34 @@
 		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
 		if (err)
 			goto err_pci;
-		udelay(1000);
+		msleep(1);
 
 		out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
 		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
 		if (err)
 			goto err_pci;
-		udelay(5000);
+		msleep(5);
 	} else {
-		if (bcm->current_core->rev < 5)
+		if (!bcm->ssb.current_core)
+			return 0;
+		if (bcm->ssb.current_core->rev < 5)
 			return 0;
-		if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
+		if (bcm->sprom.r1.boardflags_lo & 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) &&
+ *		if (((bcm->ssb.current_core->rev >= 3) &&
  *			(bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
- *		      ((bcm->current_core->rev < 3) &&
+ *		      ((bcm->ssb.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;
@@ -369,7 +377,7 @@
 	else
 		status &= ~BCM43xx_SBF_PS2;
 	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
-	if (bit26 && bcm->current_core->rev >= 5) {
+	if (bit26 && bcm->ssb.current_core->rev >= 5) {
 		for (i = 0; i < 100; i++) {
 			if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
 				break;
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_radio.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_radio.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_radio.c	2006-08-23 10:58:41.000000000 +0200
@@ -791,7 +791,7 @@
 	case BCM43xx_PHYTYPE_B: {
 		if (radio->version != 0x2050)
 			return;
-		if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI))
+		if (!(bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI))
 			return;
 
 		if (radio->revision >= 6) {
@@ -819,7 +819,7 @@
 	}
 	case BCM43xx_PHYTYPE_G:
 		if (!phy->connected ||
-		    !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
+		    !(bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI)) {
 			tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20);
 			if (tmp16 >= 0x20)
 				tmp16 -= 0x40;
@@ -1661,7 +1661,7 @@
 				channel2freq_bg(channel));
 
 		if (channel == 14) {
-			if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) {
+			if (bcm->sprom.r1.country_code == SSB_SPROM1CCODE_JAPAN) {
 				bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
 						    BCM43xx_UCODEFLAGS_OFFSET,
 						    bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
@@ -1900,7 +1900,7 @@
 				else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
 					 bcm->board_type == 0x416)
 					att = 5;
-				else if (bcm->chip_id == 0x4320)
+				else if (bcm->ssb.chip_id == 0x4320)
 					att = 4;
 				else
 					att = 3;
@@ -1997,7 +1997,7 @@
 		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) {
+	if (phy->type == BCM43xx_PHYTYPE_G && bcm->ssb.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
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/Kconfig
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/Kconfig	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/Kconfig	2006-08-23 10:58:41.000000000 +0200
@@ -2,6 +2,7 @@
 	tristate "Broadcom BCM43xx wireless support (DeviceScape stack)"
 	depends on PCI && D80211 && NET_RADIO && EXPERIMENTAL
 	select FW_LOADER
+	select SONICS_SILICON_BACKPLANE
 	---help---
 	  This is an experimental driver for the Broadcom 43xx wireless chip,
 	  found in the Apple Airport Extreme and various other devices.
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_debugfs.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_debugfs.h	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_debugfs.h	2006-08-23 10:58:41.000000000 +0200
@@ -17,7 +17,6 @@
 struct bcm43xx_dfsentry {
 	struct dentry *subdir;
 	struct dentry *dentry_devinfo;
-	struct dentry *dentry_spromdump;
 	struct dentry *dentry_tsf;
 	struct dentry *dentry_txstat;
 	struct dentry *dentry_restart;
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_leds.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_leds.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_leds.c	2006-08-23 10:58:41.000000000 +0200
@@ -133,10 +133,10 @@
 	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;
+	sprom[0] = bcm->sprom.r1.gpio0;
+	sprom[1] = bcm->sprom.r1.gpio1;
+	sprom[2] = bcm->sprom.r1.gpio2;
+	sprom[3] = bcm->sprom.r1.gpio3;
 
 	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
 		led = &(bcm->leds[i]);
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_sysfs.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_sysfs.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_sysfs.c	2006-08-23 10:58:41.000000000 +0200
@@ -71,106 +71,6 @@
 	return -EINVAL;
 }
 
-static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
-{
-	int i, pos = 0;
-
-	for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
-		pos += snprintf(buf + pos, buf_len - pos - 1,
-				"%04X", swab16(sprom[i]) & 0xFFFF);
-	}
-	pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
-
-	return pos + 1;
-}
-
-static int hex2sprom(u16 *sprom, const char *dump, size_t len)
-{
-	char tmp[5] = { 0 };
-	int cnt = 0;
-	unsigned long parsed;
-
-	if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
-		return -EINVAL;
-
-	while (cnt < BCM43xx_SPROM_SIZE) {
-		memcpy(tmp, dump, 4);
-		dump += 4;
-		parsed = simple_strtoul(tmp, NULL, 16);
-		sprom[cnt++] = swab16((u16)parsed);
-	}
-
-	return 0;
-}
-
-static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
-				       struct device_attribute *attr,
-				       char *buf)
-{
-	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	u16 *sprom;
-	unsigned long flags;
-	int 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;
-	mutex_lock(&bcm->mutex);
-	spin_lock_irqsave(&bcm->irq_lock, flags);
-	err = bcm43xx_sprom_read(bcm, sprom);
-	if (!err)
-		err = sprom2hex(sprom, buf, PAGE_SIZE);
-	mmiowb();
-	spin_unlock_irqrestore(&bcm->irq_lock, flags);
-	mutex_unlock(&bcm->mutex);
-	kfree(sprom);
-
-	return err;
-}
-
-static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	u16 *sprom;
-	unsigned long flags;
-	int err;
-
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
-			GFP_KERNEL);
-	if (!sprom)
-		return -ENOMEM;
-	err = hex2sprom(sprom, buf, count);
-	if (err)
-		goto out_kfree;
-	mutex_lock(&bcm->mutex);
-	spin_lock_irqsave(&bcm->irq_lock, flags);
-	spin_lock(&bcm->leds_lock);
-	err = bcm43xx_sprom_write(bcm, sprom);
-	mmiowb();
-	spin_unlock(&bcm->leds_lock);
-	spin_unlock_irqrestore(&bcm->irq_lock, flags);
-	mutex_unlock(&bcm->mutex);
-out_kfree:
-	kfree(sprom);
-
-	return err ? err : count;
-
-}
-
-static DEVICE_ATTR(sprom, 0600,
-		   bcm43xx_attr_sprom_show,
-		   bcm43xx_attr_sprom_store);
-
 static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
 					    struct device_attribute *attr,
 					    char *buf)
@@ -311,17 +211,14 @@
 
 int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
 {
-	struct device *dev = &bcm->pci_dev->dev;
+	struct device *dev = &bcm->ssb.pci_dev->dev;
 	int err;
 
 	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
-	err = device_create_file(dev, &dev_attr_sprom);
-	if (err)
-		goto out;
 	err = device_create_file(dev, &dev_attr_interference);
 	if (err)
-		goto err_remove_sprom;
+		goto out;
 	err = device_create_file(dev, &dev_attr_shortpreamble);
 	if (err)
 		goto err_remove_interfmode;
@@ -330,16 +227,13 @@
 	return err;
 err_remove_interfmode:
 	device_remove_file(dev, &dev_attr_interference);
-err_remove_sprom:
-	device_remove_file(dev, &dev_attr_sprom);
 	goto out;
 }
 
 void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
 {
-	struct device *dev = &bcm->pci_dev->dev;
+	struct device *dev = &bcm->ssb.pci_dev->dev;
 
 	device_remove_file(dev, &dev_attr_shortpreamble);
 	device_remove_file(dev, &dev_attr_interference);
-	device_remove_file(dev, &dev_attr_sprom);
 }
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c	2006-08-23 10:58:41.000000000 +0200
@@ -390,7 +390,7 @@
 			else
 				tmp -= 3;
 		} else {
-			if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
+			if (bcm->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) {
 				if (in_rssi > 63)
 					in_rssi = 63;
 				tmp = radio->nrssi_lt[in_rssi];
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_ethtool.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_ethtool.c	2006-08-23 10:47:32.000000000 +0200
+++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_ethtool.c	2006-08-23 10:58:41.000000000 +0200
@@ -42,7 +42,7 @@
 
 	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);
+	strncpy(info->bus_info, pci_name(bcm->ssb.pci_dev), ETHTOOL_BUSINFO_LEN);
 }
 
 struct ethtool_ops bcm43xx_ethtool_ops = {


-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] Add Sonics Silicon Backplane driver
  2006-08-23  9:59   ` [PATCH 1/2] Add " Michael Buesch
@ 2006-08-23 10:59     ` Martin Michlmayr
       [not found]       ` <20060823105955.GB9627-V8GU40kGihUigzW5ZibpNwC/G2K4zDHf@public.gmane.org>
  2006-08-23 11:04       ` Johannes Berg
  0 siblings, 2 replies; 7+ messages in thread
From: Martin Michlmayr @ 2006-08-23 10:59 UTC (permalink / raw)
  To: Michael Buesch; +Cc: linville, netdev, bcm43xx-dev

* Michael Buesch <mb@bu3sch.de> [2006-08-23 11:59]:
> +#define SSB_SPROM1_OEM			0x1076	/* 8 bytes OEM string (rev 1 only) */
> +/* SPROM Revision 2 (inherits from rev 1) */
> +#define SSB_SPROM2_BFLHI		0x1038	/* Boardflags (high 16 bits) */
> +#define SSB_SPROM2_MAXP_A		0x103A	/* A-PHY Max Power */
> +#define  SSB_SPROM2_MAXP_A_HI		0x00FF	/* Max Power High */
> +#define  SSB_SPROM2_MAXP_A_LO		0x1100	/* Max Power Low */
> +#define  SSB_SPROM2_MAXP_A_LO_SHIFT	8
> +#define SSB_SPROM2_PA1LOB0		0x103C	/* A-PHY PowerAmplifier Low Settings */
> +#define SSB_SPROM2_PA1LOB1		0x103E	/* A-PHY PowerAmplifier Low Settings */
> +#define SSB_SPROM2_PA1LOB2		0x1040	/* A-PHY PowerAmplifier Low Settings */
> +#define SSB_SPROM2_PA1HIB0		0x1042	/* A-PHY PowerAmplifier High Settings */
> +#define SSB_SPROM2_PA1HIB1		0x1044	/* A-PHY PowerAmplifier High Settings */
> +#define SSB_SPROM2_PA1HIB2		0x1046	/* A-PHY PowerAmplifier High Settings */
> +#define SSB_SPROM2_OPO			0x1078	/* OFDM Power Offset from CCK Level */
> +#define  SSB_SPROM2_OPO_VALUE		0x00FF
> +#define  SSB_SPROM2_OPO_UNUSED		0xFF00
> +#define SSB_SPROM2_CCODE		0x107C	/* Two char Country Code */

This is badly formated.  Can you repost, please.
-- 
Martin Michlmayr
tbm@cyrius.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] Add Sonics Silicon Backplane driver
       [not found]       ` <20060823105955.GB9627-V8GU40kGihUigzW5ZibpNwC/G2K4zDHf@public.gmane.org>
@ 2006-08-23 11:01         ` Michael Buesch
  0 siblings, 0 replies; 7+ messages in thread
From: Michael Buesch @ 2006-08-23 11:01 UTC (permalink / raw)
  To: Martin Michlmayr
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linville-2XuSBdqkA4R54TAoqtyWWQ,
	bcm43xx-dev-0fE9KPoRgkgATYTw5x5z8w

On Wednesday 23 August 2006 12:59, Martin Michlmayr wrote:
> * Michael Buesch <mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org> [2006-08-23 11:59]:
> > +#define SSB_SPROM1_OEM			0x1076	/* 8 bytes OEM string (rev 1 only) */
> > +/* SPROM Revision 2 (inherits from rev 1) */
> > +#define SSB_SPROM2_BFLHI		0x1038	/* Boardflags (high 16 bits) */
> > +#define SSB_SPROM2_MAXP_A		0x103A	/* A-PHY Max Power */
> > +#define  SSB_SPROM2_MAXP_A_HI		0x00FF	/* Max Power High */
> > +#define  SSB_SPROM2_MAXP_A_LO		0x1100	/* Max Power Low */
> > +#define  SSB_SPROM2_MAXP_A_LO_SHIFT	8
> > +#define SSB_SPROM2_PA1LOB0		0x103C	/* A-PHY PowerAmplifier Low Settings */
> > +#define SSB_SPROM2_PA1LOB1		0x103E	/* A-PHY PowerAmplifier Low Settings */
> > +#define SSB_SPROM2_PA1LOB2		0x1040	/* A-PHY PowerAmplifier Low Settings */
> > +#define SSB_SPROM2_PA1HIB0		0x1042	/* A-PHY PowerAmplifier High Settings */
> > +#define SSB_SPROM2_PA1HIB1		0x1044	/* A-PHY PowerAmplifier High Settings */
> > +#define SSB_SPROM2_PA1HIB2		0x1046	/* A-PHY PowerAmplifier High Settings */
> > +#define SSB_SPROM2_OPO			0x1078	/* OFDM Power Offset from CCK Level */
> > +#define  SSB_SPROM2_OPO_VALUE		0x00FF
> > +#define  SSB_SPROM2_OPO_UNUSED		0xFF00
> > +#define SSB_SPROM2_CCODE		0x107C	/* Two char Country Code */
> 
> This is badly formated.  Can you repost, please.

Uhm, no? I don't think the formating is broken.
Please _apply_ that diff and look again at the resulting file.

(I the issue is the tabs that go crazy, if the additional diff
plus char at the beginning is inserted)

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] Add Sonics Silicon Backplane driver
  2006-08-23 10:59     ` Martin Michlmayr
       [not found]       ` <20060823105955.GB9627-V8GU40kGihUigzW5ZibpNwC/G2K4zDHf@public.gmane.org>
@ 2006-08-23 11:04       ` Johannes Berg
  2006-08-23 11:26         ` Martin Michlmayr
  1 sibling, 1 reply; 7+ messages in thread
From: Johannes Berg @ 2006-08-23 11:04 UTC (permalink / raw)
  To: Martin Michlmayr; +Cc: Michael Buesch, linville, netdev, bcm43xx-dev

On Wed, 2006-08-23 at 11:59 +0100, Martin Michlmayr wrote:
> > +#define SSB_SPROM2_OPO			0x1078	/* OFDM Power Offset from CCK Level */
> > +#define  SSB_SPROM2_OPO_VALUE		0x00FF
> > +#define  SSB_SPROM2_OPO_UNUSED		0xFF00
> > +#define SSB_SPROM2_CCODE		0x107C	/* Two char Country Code */
> 
> This is badly formated.  Can you repost, please.

That's just because of the tabs, if the + in front is removed it's
formatted fine. And the indentation is supposed to be like that I'd
think.

johannes

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] Add Sonics Silicon Backplane driver
  2006-08-23 11:04       ` Johannes Berg
@ 2006-08-23 11:26         ` Martin Michlmayr
  0 siblings, 0 replies; 7+ messages in thread
From: Martin Michlmayr @ 2006-08-23 11:26 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michael Buesch, linville, netdev, bcm43xx-dev

* Johannes Berg <johannes@sipsolutions.net> [2006-08-23 13:04]:
> > > +#define  SSB_SPROM2_OPO_VALUE		0x00FF
> > > +#define  SSB_SPROM2_OPO_UNUSED		0xFF00
> > > +#define SSB_SPROM2_CCODE		0x107C	/* Two char Country Code */
> > 
> > This is badly formated.  Can you repost, please.
> 
> That's just because of the tabs, if the + in front is removed it's
> formatted fine. And the indentation is supposed to be like that I'd
> think.

Yes, sorry, I didn't realize that registers and register values have
different indentation.
-- 
Martin Michlmayr
http://www.cyrius.com/

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2006-08-23 11:27 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-23  9:58 [PATCH 0/2] Sonics Silicon Backplane driver Michael Buesch
     [not found] ` <200608231158.06178.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>
2006-08-23  9:59   ` [PATCH 1/2] Add " Michael Buesch
2006-08-23 10:59     ` Martin Michlmayr
     [not found]       ` <20060823105955.GB9627-V8GU40kGihUigzW5ZibpNwC/G2K4zDHf@public.gmane.org>
2006-08-23 11:01         ` Michael Buesch
2006-08-23 11:04       ` Johannes Berg
2006-08-23 11:26         ` Martin Michlmayr
2006-08-23 10:01   ` [PATCH 2/2] bcm43xx: convert driver to use ssb Michael Buesch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).