From d53cdbb94a52a920d5420ed64d986c3523a56743 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 31 Mar 2010 21:39:35 +0200 Subject: ssb: do not read SPROM if it does not exist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Rafał Miłecki Cc: Larry Finger Cc: Michael Buesch --- drivers/ssb/driver_chipcommon.c | 2 ++ drivers/ssb/pci.c | 5 +++++ drivers/ssb/sprom.c | 14 ++++++++++++++ 3 files changed, 21 insertions(+) (limited to 'drivers/ssb') 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; +} -- cgit v1.2.2 From ea2db495f92ad2cf3301623e60cb95b4062bc484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 31 Mar 2010 21:59:21 +0200 Subject: ssb: Look for SPROM at different offset on higher rev CC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our offset handling becomes even a little more hackish now. For some reason I do not understand all offsets as inrelative. It assumes base offset is 0x1000 but it will work for now as we make offsets relative anyway by removing base 0x1000. Should be cleaner however. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/ssb') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index a4b2b99f2c80..5bb1278759c1 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -167,7 +167,7 @@ err_pci: } /* Get the word-offset for a SSB_SPROM_XXX define. */ -#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16)) +#define SPOFF(offset) (((offset) - SSB_SPROM_BASE1) / 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)) @@ -253,7 +253,7 @@ static int sprom_do_read(struct ssb_bus *bus, u16 *sprom) int i; for (i = 0; i < bus->sprom_size; i++) - sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2)); + sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2)); return 0; } @@ -284,7 +284,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) ssb_printk("75%%"); else if (i % 2) ssb_printk("."); - writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2)); + writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2)); mmiowb(); msleep(20); } @@ -625,6 +625,9 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, return -ENODEV; } + bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ? + SSB_SPROM_BASE1 : SSB_SPROM_BASE31; + buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); if (!buf) goto out; -- cgit v1.2.2 From 0a182fd88f8180b342f753f04c7d5507b5891c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 31 Mar 2010 22:54:18 +0200 Subject: ssb: Use relative offsets for SPROM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ssb') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 5bb1278759c1..3f556d6ec4c2 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -167,7 +167,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)) -- cgit v1.2.2 From ce9626eae243b788993fedc03f30e2d1cb178c7a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 23 Apr 2010 13:17:21 -0500 Subject: ssb: Make bus registration failure not be silent In kernel Bugzilla #15825, a case where routine ssb_bus_pcibus_register() fails silently is reported. The cause for the failure is still being investigated; however, the diagnosis would be easier if the failure had been reported. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/ssb/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/ssb') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 03dfd27c4bfb..009e3204caac 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -833,6 +833,9 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus, if (!err) { ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " "PCI device %s\n", dev_name(&host_pci->dev)); + } else { + ssb_printk(KERN_ERR PFX "Failed to register PCI version" + " of SSB with error %d\n", err); } return err; -- cgit v1.2.2