All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.