diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-03-31 21:39:35 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-26 13:50:54 -0400 |
commit | d53cdbb94a52a920d5420ed64d986c3523a56743 (patch) | |
tree | 39b1026c953de14ce6b14417cf9bcb66992909f0 /drivers/ssb | |
parent | 672724403b42da1d276c6cf811e8e34d15efd964 (diff) | |
download | linux-d53cdbb94a52a920d5420ed64d986c3523a56743.tar.gz linux-d53cdbb94a52a920d5420ed64d986c3523a56743.tar.bz2 linux-d53cdbb94a52a920d5420ed64d986c3523a56743.zip |
ssb: do not read SPROM if it does not exist
Attempting to read registers that don't exist on the SSB bus can cause
hangs on some boxes. At least some b43 devices are 'in the wild' that
don't have SPROMs at all. When the SSB bus support loads, it attempts
to read these (non-existant) SPROMs and causes hard hangs on the box --
no console output, etc.
This patch adds some intelligence to determine whether or not the SPROM
is present before attempting to read it. This avoids those hard hangs
on those devices with no SPROM attached to their SSB bus. The
SSB-attached devices (e.g. b43, et al.) won't work, but at least the box
will survive to test further patches. :-)
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Cc: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Michael Buesch <mb@bu3sch.de>
Diffstat (limited to 'drivers/ssb')
-rw-r--r-- | drivers/ssb/driver_chipcommon.c | 2 | ||||
-rw-r--r-- | drivers/ssb/pci.c | 5 | ||||
-rw-r--r-- | drivers/ssb/sprom.c | 14 |
3 files changed, 21 insertions, 0 deletions
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 59c3c0fdbecd..59ae76bace14 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -233,6 +233,8 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) { if (!cc->dev) return; /* We don't have a ChipCommon */ + if (cc->dev->id.revision >= 11) + cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); ssb_pmu_init(cc); chipco_powercontrol_init(cc); ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 9e50896233aa..a4b2b99f2c80 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -620,6 +620,11 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, int err = -ENOMEM; u16 *buf; + if (!ssb_is_sprom_available(bus)) { + ssb_printk(KERN_ERR PFX "No SPROM available!\n"); + return -ENODEV; + } + buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); if (!buf) goto out; diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index d0e6762fec50..83bc088b941d 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c @@ -175,3 +175,17 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void) { return fallback_sprom; } + +/* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ +bool ssb_is_sprom_available(struct ssb_bus *bus) +{ + /* status register only exists on chipcomon rev >= 11 and we need check + for >= 31 only */ + /* this routine differs from specs as we do not access SPROM directly + on PCMCIA */ + if (bus->bustype == SSB_BUSTYPE_PCI && + bus->chipco.dev->id.revision >= 31) + return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM; + + return true; +} |