+@@ -838,9 +878,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+ #endif /* CONFIG_SSB_PCIHOST */
+
+ #ifdef CONFIG_SSB_PCMCIAHOST
+-int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
+- struct pcmcia_device *pcmcia_dev,
+- unsigned long baseaddr)
++int __devinit ssb_bus_pcmciabus_register(struct ssb_bus *bus,
++ struct pcmcia_device *pcmcia_dev,
++ unsigned long baseaddr)
+ {
+ int err;
+
+@@ -860,8 +900,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+
+ #ifdef CONFIG_SSB_SDIOHOST
+-int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
+- unsigned int quirks)
++int __devinit ssb_bus_sdiobus_register(struct ssb_bus *bus,
++ struct sdio_func *func,
++ unsigned int quirks)
+ {
+ int err;
+
+@@ -881,9 +922,9 @@ int ssb_bus_sdiobus_register(struct ssb_
+ EXPORT_SYMBOL(ssb_bus_sdiobus_register);
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+
+-int ssb_bus_ssbbus_register(struct ssb_bus *bus,
+- unsigned long baseaddr,
+- ssb_invariants_func_t get_invariants)
++int __devinit ssb_bus_ssbbus_register(struct ssb_bus *bus,
++ unsigned long baseaddr,
++ ssb_invariants_func_t get_invariants)
+ {
+ int err;
+
+@@ -964,8 +1005,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+ switch (plltype) {
+ case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+ if (m & SSB_CHIPCO_CLK_T6_MMASK)
+- return SSB_CHIPCO_CLK_T6_M0;
+- return SSB_CHIPCO_CLK_T6_M1;
++ return SSB_CHIPCO_CLK_T6_M1;
++ return SSB_CHIPCO_CLK_T6_M0;
+ case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+@@ -1080,23 +1121,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+ {
+ u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
+
+- /* The REJECT bit changed position in TMSLOW between
+- * Backplane revisions. */
++ /* The REJECT bit seems to be different for Backplane rev 2.3 */
+ switch (rev) {
+ case SSB_IDLOW_SSBREV_22:
+- return SSB_TMSLOW_REJECT_22;
++ case SSB_IDLOW_SSBREV_24:
++ case SSB_IDLOW_SSBREV_26:
++ return SSB_TMSLOW_REJECT;
+ case SSB_IDLOW_SSBREV_23:
+ return SSB_TMSLOW_REJECT_23;
+- case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */
+- case SSB_IDLOW_SSBREV_25: /* same here */
+- case SSB_IDLOW_SSBREV_26: /* same here */
++ case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */
+ case SSB_IDLOW_SSBREV_27: /* same here */
+- return SSB_TMSLOW_REJECT_23; /* this is a guess */
++ return SSB_TMSLOW_REJECT; /* this is a guess */
+ default:
+ printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
+ WARN_ON(1);
+ }
+- return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
++ return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
+ }
+
+ int ssb_device_is_enabled(struct ssb_device *dev)
+@@ -1155,10 +1195,10 @@ void ssb_device_enable(struct ssb_device
+ }
+ EXPORT_SYMBOL(ssb_device_enable);
+
+-/* Wait for a bit in a register to get set or unset.
++/* Wait for bitmask in a register to get set or cleared.
+ * timeout is in units of ten-microseconds */
+-static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+- int timeout, int set)
++static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
++ int timeout, int set)
+ {
+ int i;
+ u32 val;
+@@ -1166,7 +1206,7 @@ static int ssb_wait_bit(struct ssb_devic
+ for (i = 0; i < timeout; i++) {
+ val = ssb_read32(dev, reg);
+ if (set) {
+- if (val & bitmask)
++ if ((val & bitmask) == bitmask)
+ return 0;
+ } else {
+ if (!(val & bitmask))
+@@ -1183,20 +1223,38 @@ static int ssb_wait_bit(struct ssb_devic
+
+ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+ {
+- u32 reject;
++ u32 reject, val;
+
+ if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ return;
+
+ reject = ssb_tmslow_reject_bitmask(dev);
+- ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+- ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+- ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+- ssb_write32(dev, SSB_TMSLOW,
+- SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+- reject | SSB_TMSLOW_RESET |
+- core_specific_flags);
+- ssb_flush_tmslow(dev);
++
++ if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
++ ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
++ ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
++ ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
++
++ if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++ val = ssb_read32(dev, SSB_IMSTATE);
++ val |= SSB_IMSTATE_REJECT;
++ ssb_write32(dev, SSB_IMSTATE, val);
++ ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
++ 0);
++ }
++
++ ssb_write32(dev, SSB_TMSLOW,
++ SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
++ reject | SSB_TMSLOW_RESET |
++ core_specific_flags);
++ ssb_flush_tmslow(dev);
++
++ if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++ val = ssb_read32(dev, SSB_IMSTATE);
++ val &= ~SSB_IMSTATE_REJECT;
++ ssb_write32(dev, SSB_IMSTATE, val);
++ }
++ }
+
+ ssb_write32(dev, SSB_TMSLOW,
+ reject | SSB_TMSLOW_RESET |
+@@ -1205,13 +1263,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
+
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++ u16 chip_id = dev->bus->chip_id;
++
++ if (dev->id.coreid == SSB_DEV_80211) {
++ return (chip_id == 0x4322 || chip_id == 43221 ||
++ chip_id == 43231 || chip_id == 43222);
++ }
++
++ return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+ switch (dev->bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ return 0;
+ case SSB_BUSTYPE_PCI:
+- return SSB_PCI_DMA;
++ if (dev->bus->host_pci->is_pcie &&
++ ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
++ return SSB_PCIE_DMA_H32;
++ } else {
++ if (ssb_dma_translation_special_bit(dev))
++ return SSB_PCIE_DMA_H32;
++ else
++ return SSB_PCI_DMA;
++ }
+ default:
+ __ssb_dma_not_implemented(dev);
+ }
+@@ -1328,20 +1407,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+
+ int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
+ {
+- struct ssb_chipcommon *cc;
+ int err;
+ enum ssb_clkmode mode;
+
+ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+ if (err)
+ goto error;
+- cc = &bus->chipco;
+- mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
+- ssb_chipco_set_clockmode(cc, mode);
+
+ #ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 1;
+ #endif
++
++ mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
++ ssb_chipco_set_clockmode(&bus->chipco, mode);
++
+ return 0;
+ error:
+ ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
+@@ -1349,6 +1428,37 @@ error:
+ }
+ EXPORT_SYMBOL(ssb_bus_powerup);
+
++static void ssb_broadcast_value(struct ssb_device *dev,
++ u32 address, u32 data)
++{
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++ /* This is used for both, PCI and ChipCommon core, so be careful. */
++ BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
++ BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
++#endif
++
++ ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address);
++ ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */
++ ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data);
++ ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */
++}
++
++void ssb_commit_settings(struct ssb_bus *bus)
++{
++ struct ssb_device *dev;
++
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++ dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
++#else
++ dev = bus->chipco.dev;
++#endif
++ if (WARN_ON(!dev))
++ return;
++ /* This forces an update of the cached registers. */
++ ssb_broadcast_value(dev, 0xFD8, 0);
++}
++EXPORT_SYMBOL(ssb_commit_settings);
++
+ u32 ssb_admatch_base(u32 adm)
+ {
+ u32 base = 0;
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -1,7 +1,7 @@
+ /*
+ * Sonics Silicon Backplane PCI-Hostbus related functions.
+ *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+@@ -17,6 +17,7 @@
+
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
++#include <linux/slab.h>
+ #include <linux/pci.h>
+ #include <linux/delay.h>
+
+@@ -167,7 +168,7 @@ err_pci:
+ }
+
+ /* Get the word-offset for a SSB_SPROM_XXX define. */
+-#define SPOFF(offset) (((offset) - SSB_SPROM_BASE1) / sizeof(u16))
++#define SPOFF(offset) ((offset) / sizeof(u16))
+ /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
+ #define SPEX16(_outvar, _offset, _mask, _shift) \
+ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
+@@ -405,6 +406,46 @@ static void sprom_extract_r123(struct ss
+ out->antenna_gain.ghz5.a3 = gain;
+ }
+
++/* Revs 4 5 and 8 have partially shared layout */
++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
++{
++ SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
++ SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
++ SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
++ SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
++ SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
++ SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
++ SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
++ SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
++
++ SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
++ SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
++ SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
++ SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
++ SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
++ SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
++ SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
++ SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
++
++ SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
++ SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
++ SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
++ SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
++ SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
++ SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
++ SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
++ SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
++
++ SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
++ SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
++ SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
++ SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
++ SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
++ SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
++ SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
++ SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
++}
++
+ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
+ {
+ int i;
+@@ -427,10 +468,14 @@ static void sprom_extract_r45(struct ssb
+ SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+ SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++ SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
++ SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
+ } else {
+ SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+ SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
++ SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
++ SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
+ }
+ SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+ SSB_SPROM4_ANTAVAIL_A_SHIFT);
+@@ -470,13 +515,21 @@ static void sprom_extract_r45(struct ssb
+ memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ sizeof(out->antenna_gain.ghz5));
+
++ sprom_extract_r458(out, in);
++
+ /* TODO - get remaining rev 4 stuff needed */
+ }
+
+ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
+ {
+ int i;
+- u16 v;
++ u16 v, o;
++ u16 pwr_info_offset[] = {
++ SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
++ SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
++ };
++ BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
++ ARRAY_SIZE(out->core_pwr_info));
+
+ /* extract the MAC address */
+ for (i = 0; i < 3; i++) {
+@@ -560,6 +613,63 @@ static void sprom_extract_r8(struct ssb_
+ memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ sizeof(out->antenna_gain.ghz5));
+
++ /* Extract cores power info info */
++ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
++ o = pwr_info_offset[i];
++ SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
++ SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
++ SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
++ SSB_SPROM8_2G_MAXP, 0);
++
++ SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
++ SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
++ SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
++
++ SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
++ SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
++ SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
++ SSB_SPROM8_5G_MAXP, 0);
++ SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
++ SSB_SPROM8_5GH_MAXP, 0);
++ SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
++ SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
++
++ SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
++ SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
++ }
++
++ /* Extract FEM info */
++ SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++ SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++ SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++ SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++ SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++ SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++ SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++ SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++ SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++ SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++ SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++ SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++ SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++ SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++ SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++ SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++ SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++ SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++ SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++ SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++ sprom_extract_r458(out, in);
++
+ /* TODO - get remaining rev 8 stuff needed */
+ }
+
+@@ -572,37 +682,34 @@ static int sprom_extract(struct ssb_bus
+ ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */
+ memset(out->et1mac, 0xFF, 6);
++
+ if ((bus->chip_id & 0xFF00) == 0x4400) {
+ /* Workaround: The BCM44XX chip has a stupid revision
+ * number stored in the SPROM.
+ * Always extract r1. */
+ out->revision = 1;
++ ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
++ }
++
++ switch (out->revision) {
++ case 1:
++ case 2:
++ case 3:
+ sprom_extract_r123(out, in);
+- } else if (bus->chip_id == 0x4321) {
+- /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
+- out->revision = 4;
++ break;
++ case 4:
++ case 5:
+ sprom_extract_r45(out, in);
+- } else {
+- switch (out->revision) {
+- case 1:
+- case 2:
+- case 3:
+- sprom_extract_r123(out, in);
+- break;
+- case 4:
+- case 5:
+- sprom_extract_r45(out, in);
+- break;
+- case 8:
+- sprom_extract_r8(out, in);
+- break;
+- default:
+- ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+- " revision %d detected. Will extract"
+- " v1\n", out->revision);
+- out->revision = 1;
+- sprom_extract_r123(out, in);
+- }
++ break;
++ case 8:
++ sprom_extract_r8(out, in);
++ break;
++ default:
++ ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
++ " revision %d detected. Will extract"
++ " v1\n", out->revision);
++ out->revision = 1;
++ sprom_extract_r123(out, in);
+ }
+
+ if (out->boardflags_lo == 0xFFFF)
+@@ -616,15 +723,14 @@ static int sprom_extract(struct ssb_bus
+ static int ssb_pci_sprom_get(struct ssb_bus *bus,
+ struct ssb_sprom *sprom)
+ {
+- const struct ssb_sprom *fallback;
+- int err = -ENOMEM;
++ int err;
+ u16 *buf;
+
+ if (!ssb_is_sprom_available(bus)) {
+ ssb_printk(KERN_ERR PFX "No SPROM available!\n");
+ return -ENODEV;
+ }
+- if (bus->chipco.dev) { /* can be unavailible! */
++ if (bus->chipco.dev) { /* can be unavailable! */
+ /*
+ * get SPROM offset: SSB_SPROM_BASE1 except for
+ * chipcommon rev >= 31 or chip ID is 0x4312 and
+@@ -644,7 +750,7 @@ static int ssb_pci_sprom_get(struct ssb_
+
+ buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+ if (!buf)
+- goto out;
++ return -ENOMEM;
+ bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
+ sprom_do_read(bus, buf);
+ err = sprom_check_crc(buf, bus->sprom_size);
+@@ -654,17 +760,24 @@ static int ssb_pci_sprom_get(struct ssb_
+ buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL);
+ if (!buf)
+- goto out;
++ return -ENOMEM;
+ bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+ sprom_do_read(bus, buf);
+ err = sprom_check_crc(buf, bus->sprom_size);
+ if (err) {
+ /* All CRC attempts failed.
+ * Maybe there is no SPROM on the device?
+- * If we have a fallback, use that. */
+- fallback = ssb_get_fallback_sprom();
+- if (fallback) {
+- memcpy(sprom, fallback, sizeof(*sprom));
++ * Now we ask the arch code if there is some sprom
++ * available for this device in some other storage */
++ err = ssb_fill_sprom_with_fallback(bus, sprom);
++ if (err) {
++ ssb_printk(KERN_WARNING PFX "WARNING: Using"
++ " fallback SPROM failed (err %d)\n",
++ err);
++ } else {
++ ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
++ " revision %d provided by"
++ " platform.\n", sprom->revision);
+ err = 0;
+ goto out_free;
+ }
+@@ -676,19 +789,15 @@ static int ssb_pci_sprom_get(struct ssb_
+
+ out_free:
+ kfree(buf);
+-out:
+ return err;
+ }
+
+ static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
+ struct ssb_boardinfo *bi)
+ {
+- pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
+- &bi->vendor);
+- pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
+- &bi->type);
+- pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+- &bi->rev);
++ bi->vendor = bus->host_pci->subsystem_vendor;
++ bi->type = bus->host_pci->subsystem_device;
++ bi->rev = bus->host_pci->revision;
+ }
+
+ int ssb_pci_get_invariants(struct ssb_bus *bus,