ssb: Handle alternate SSPROM location
authorLarry Finger <Larry.Finger@lwfinger.net>
Sat, 15 May 2010 03:08:58 +0000 (22:08 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 10 Aug 2010 17:20:51 +0000 (10:20 -0700)
commit 9d1ac34ec3a67713308ae0883c3359c557f14d17 upstream.

In kernel Bugzilla #15825 (2 users), in a wireless mailing list thread
(http://lists.infradead.org/pipermail/b43-dev/2010-May/000124.html), and on a
netbook owned by John Linville
(http://marc.info/?l=linux-wireless&m=127230751408818&w=4), there are reports
of ssb failing to detect an SPROM at the normal location. After studying the
MMIO trace dump for the Broadcom wl driver, it was determined that the affected
boxes had a relocated SPROM.

This patch fixes all systems that have reported this problem.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/ssb/driver_chipcommon.c
drivers/ssb/pci.c

index a55cff8524c7a8dd87ce56a78bec7d9aa18fb528..bbf1cb21a7d3509d00d1461a29759927ee157e1a 100644 (file)
@@ -235,6 +235,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
                return; /* We don't have a ChipCommon */
        if (cc->dev->id.revision >= 11)
                cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
+       ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
        ssb_pmu_init(cc);
        chipco_powercontrol_init(cc);
        ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
index 243db85dbdb8181382f1c8f9035b7f601ae1c1a8..321d9ef17b965a252f6f385c80347238ed3d70ff 100644 (file)
@@ -625,11 +625,22 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
                return -ENODEV;
        }
        if (bus->chipco.dev) {  /* can be unavailible! */
-               bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ?
-                       SSB_SPROM_BASE1 : SSB_SPROM_BASE31;
+               /*
+                * get SPROM offset: SSB_SPROM_BASE1 except for
+                * chipcommon rev >= 31 or chip ID is 0x4312 and
+                * chipcommon status & 3 == 2
+                */
+               if (bus->chipco.dev->id.revision >= 31)
+                       bus->sprom_offset = SSB_SPROM_BASE31;
+               else if (bus->chip_id == 0x4312 &&
+                        (bus->chipco.status & 0x03) == 2)
+                       bus->sprom_offset = SSB_SPROM_BASE31;
+               else
+                       bus->sprom_offset = SSB_SPROM_BASE1;
        } else {
                bus->sprom_offset = SSB_SPROM_BASE1;
        }
+       ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
 
        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
        if (!buf)