* [PATCH V3] ssb: do not read SPROM if it does not exist
@ 2010-03-31 19:39 John W. Linville
2010-03-31 19:42 ` Rafał Miłecki
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: John W. Linville @ 2010-03-31 19:39 UTC (permalink / raw)
To: linux-wireless
Cc: John W. Linville, Rafał Miłecki, Larry Finger,
Michael Buesch
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>
---
V2: adapt to updated specs, drop some warning-causing braces
V3: updated specs again, drop PCMCIA part
OK, so hopefully we have it figured out now.
However I have no idea what PCMCIA tuples are. Do we need similar check for
some PCMCIA code?
I feel badly pretending to be John. Did I really get your tip correct, Larry?
---
drivers/ssb/driver_chipcommon.c | 2 ++
drivers/ssb/pci.c | 5 +++++
drivers/ssb/sprom.c | 14 ++++++++++++++
include/linux/ssb/ssb.h | 3 +++
include/linux/ssb/ssb_driver_chipcommon.h | 15 +++++++++++++++
5 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 59c3c0f..59ae76b 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 9e50896..a4b2b99 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 d0e6762..83bc088 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;
+}
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 24f9885..3b4da23 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -394,6 +394,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
extern void ssb_bus_unregister(struct ssb_bus *bus);
+/* Does the device have an SPROM? */
+extern bool ssb_is_sprom_available(struct ssb_bus *bus);
+
/* Set a fallback SPROM.
* See kdoc at the function definition for complete documentation. */
extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index 4e27acf..2cdf249 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -53,6 +53,7 @@
#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */
#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */
#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */
+#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */
#define SSB_CHIPCO_CORECTL 0x0008
#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
@@ -385,6 +386,7 @@
/** Chip specific Chip-Status register contents. */
+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS 0x00000040 /* SPROM present */
#define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003
#define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */
#define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */
@@ -398,6 +400,18 @@
#define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4
#define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */
+/** Macros to determine SPROM presence based on Chip-Status register. */
+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_OTP_SEL)
+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \
+ (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS)
+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \
+ (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_OTP_SEL))
+
/** Clockcontrol masks and values **/
@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu {
struct ssb_chipcommon {
struct ssb_device *dev;
u32 capabilities;
+ u32 status;
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
struct ssb_chipcommon_pmu pmu;
--
1.6.4.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH V3] ssb: do not read SPROM if it does not exist
2010-03-31 19:39 [PATCH V3] ssb: do not read SPROM if it does not exist John W. Linville
@ 2010-03-31 19:42 ` Rafał Miłecki
2010-04-01 14:23 ` Michael Buesch
2010-04-01 14:28 ` Michael Buesch
2 siblings, 0 replies; 7+ messages in thread
From: Rafał Miłecki @ 2010-03-31 19:42 UTC (permalink / raw)
To: linux-wireless
Cc: John W. Linville, Rafał Miłecki, Larry Finger,
Michael Buesch
Oh, great, git used John's name and my address as "From" of... email :/
I'm sorry John :|
--
Rafał
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH V3] ssb: do not read SPROM if it does not exist
2010-03-31 19:39 [PATCH V3] ssb: do not read SPROM if it does not exist John W. Linville
2010-03-31 19:42 ` Rafał Miłecki
@ 2010-04-01 14:23 ` Michael Buesch
2010-04-01 14:28 ` Michael Buesch
2 siblings, 0 replies; 7+ messages in thread
From: Michael Buesch @ 2010-04-01 14:23 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, John W. Linville, Larry Finger
On Wednesday 31 March 2010 21:39:35 John W. Linville wrote:
> However I have no idea what PCMCIA tuples are. Do we need similar check for
> some PCMCIA code?
The PCMCIA subsystem fetches the data for us through some mechanism similar
to PCI config space and provides the data via tuples.
See ssb/pcmcia.c -> ssb_pcmcia_get_invariants()
For now I would not recommend touching that code unless we have a device
that needs it.
--
Greetings, Michael.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH V3] ssb: do not read SPROM if it does not exist
2010-03-31 19:39 [PATCH V3] ssb: do not read SPROM if it does not exist John W. Linville
2010-03-31 19:42 ` Rafał Miłecki
2010-04-01 14:23 ` Michael Buesch
@ 2010-04-01 14:28 ` Michael Buesch
2 siblings, 0 replies; 7+ messages in thread
From: Michael Buesch @ 2010-04-01 14:28 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, John W. Linville, Larry Finger
On Wednesday 31 March 2010 21:39:35 John W. Linville wrote:
> diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
> index 9e50896..a4b2b99 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;
> + }
Note that in ssb_pci_init() you might also want to add such a check to avoid
registering the "sprom" sysfs file in case there's no sprom. Otherwise root is
able to crash the machine via that file. Same goes for ssb_pci_exit(), of course.
--
Greetings, Michael.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2] ssb: do not read SPROM if it does not exist
@ 2010-03-19 20:33 John W. Linville
2010-03-19 20:41 ` [PATCH v3] " John W. Linville
0 siblings, 1 reply; 7+ messages in thread
From: John W. Linville @ 2010-03-19 20:33 UTC (permalink / raw)
To: linux-wireless; +Cc: John W. Linville, Larry Finger, Michael Buesch, stable
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>
Cc: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Michael Buesch <mb@bu3sch.de>
Cc: stable@kernel.org
---
Version 2, check the correct place for ChipCommon core revision... :-)
drivers/ssb/pci.c | 3 +++
drivers/ssb/scan.c | 4 ++++
drivers/ssb/sprom.c | 22 ++++++++++++++++++++++
include/linux/ssb/ssb.h | 3 +++
include/linux/ssb/ssb_driver_chipcommon.h | 15 +++++++++++++++
5 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 9e50896..2f7b16d 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -620,6 +620,9 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
int err = -ENOMEM;
u16 *buf;
+ if (!ssb_is_sprom_available(bus))
+ return -ENODEV;
+
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
goto out;
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 0d6c028..c4944b9 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -306,6 +306,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
}
tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
bus->chipco.capabilities = tmp;
+ if (bus->chipco.dev->id.revision >= 11)
+ tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPSTAT);
+ bus->chipco.status = tmp;
+ }
} else {
if (bus->bustype == SSB_BUSTYPE_PCI) {
bus->chip_id = pcidev_to_chipid(bus->host_pci);
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
index d0e6762..55eb9b0 100644
--- a/drivers/ssb/sprom.c
+++ b/drivers/ssb/sprom.c
@@ -175,3 +175,25 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void)
{
return fallback_sprom;
}
+
+bool ssb_is_sprom_available(struct ssb_bus *bus)
+{
+ /* status register only exists on chipcomon rev >= 11 */
+ if (bus->chipco.dev->id.revision < 11)
+ return true;
+
+ switch (bus->chip_id) {
+ case 0x4312:
+ return SSB_CHIPCO_CHST_4312_SPROM_PRESENT(bus->chipco.status);
+ case 0x4322:
+ return SSB_CHIPCO_CHST_4322_SPROM_PRESENT(bus->chipco.status);
+ case 0x4325:
+ return SSB_CHIPCO_CHST_4325_SPROM_PRESENT(bus->chipco.status);
+ default:
+ break;
+ }
+ if (bus->chipco.dev->id.revision >= 31)
+ return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
+
+ return true;
+}
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 24f9885..3b4da23 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -394,6 +394,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
extern void ssb_bus_unregister(struct ssb_bus *bus);
+/* Does the device have an SPROM? */
+extern bool ssb_is_sprom_available(struct ssb_bus *bus);
+
/* Set a fallback SPROM.
* See kdoc at the function definition for complete documentation. */
extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index 4e27acf..2cdf249 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -53,6 +53,7 @@
#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */
#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */
#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */
+#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */
#define SSB_CHIPCO_CORECTL 0x0008
#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
@@ -385,6 +386,7 @@
/** Chip specific Chip-Status register contents. */
+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS 0x00000040 /* SPROM present */
#define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003
#define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */
#define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */
@@ -398,6 +400,18 @@
#define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4
#define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */
+/** Macros to determine SPROM presence based on Chip-Status register. */
+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_OTP_SEL)
+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \
+ (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS)
+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \
+ (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_OTP_SEL))
+
/** Clockcontrol masks and values **/
@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu {
struct ssb_chipcommon {
struct ssb_device *dev;
u32 capabilities;
+ u32 status;
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
struct ssb_chipcommon_pmu pmu;
--
1.6.2.5
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v3] ssb: do not read SPROM if it does not exist
2010-03-19 20:33 [PATCH v2] " John W. Linville
@ 2010-03-19 20:41 ` John W. Linville
2010-03-19 21:12 ` Michael Buesch
0 siblings, 1 reply; 7+ messages in thread
From: John W. Linville @ 2010-03-19 20:41 UTC (permalink / raw)
To: linux-wireless; +Cc: John W. Linville, Larry Finger, Michael Buesch, stable
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>
Cc: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Michael Buesch <mb@bu3sch.de>
Cc: stable@kernel.org
---
Version 3, add missing semi-colon... :-(
Version 2, check the correct place for ChipCommon core revision... :-)
drivers/ssb/pci.c | 3 +++
drivers/ssb/scan.c | 4 ++++
drivers/ssb/sprom.c | 22 ++++++++++++++++++++++
include/linux/ssb/ssb.h | 3 +++
include/linux/ssb/ssb_driver_chipcommon.h | 15 +++++++++++++++
5 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 9e50896..2f7b16d 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -620,6 +620,9 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
int err = -ENOMEM;
u16 *buf;
+ if (!ssb_is_sprom_available(bus))
+ return -ENODEV;
+
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
goto out;
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 0d6c028..6d51895 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -306,6 +306,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
}
tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
bus->chipco.capabilities = tmp;
+ if (bus->chipco.dev->id.revision >= 11) {
+ tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPSTAT);
+ bus->chipco.status = tmp;
+ }
} else {
if (bus->bustype == SSB_BUSTYPE_PCI) {
bus->chip_id = pcidev_to_chipid(bus->host_pci);
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
index d0e6762..55eb9b0 100644
--- a/drivers/ssb/sprom.c
+++ b/drivers/ssb/sprom.c
@@ -175,3 +175,25 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void)
{
return fallback_sprom;
}
+
+bool ssb_is_sprom_available(struct ssb_bus *bus)
+{
+ /* status register only exists on chipcomon rev >= 11 */
+ if (bus->chipco.dev->id.revision < 11)
+ return true;
+
+ switch (bus->chip_id) {
+ case 0x4312:
+ return SSB_CHIPCO_CHST_4312_SPROM_PRESENT(bus->chipco.status);
+ case 0x4322:
+ return SSB_CHIPCO_CHST_4322_SPROM_PRESENT(bus->chipco.status);
+ case 0x4325:
+ return SSB_CHIPCO_CHST_4325_SPROM_PRESENT(bus->chipco.status);
+ default:
+ break;
+ }
+ if (bus->chipco.dev->id.revision >= 31)
+ return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
+
+ return true;
+}
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 24f9885..3b4da23 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -394,6 +394,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
extern void ssb_bus_unregister(struct ssb_bus *bus);
+/* Does the device have an SPROM? */
+extern bool ssb_is_sprom_available(struct ssb_bus *bus);
+
/* Set a fallback SPROM.
* See kdoc at the function definition for complete documentation. */
extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index 4e27acf..2cdf249 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -53,6 +53,7 @@
#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */
#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */
#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */
+#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */
#define SSB_CHIPCO_CORECTL 0x0008
#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
@@ -385,6 +386,7 @@
/** Chip specific Chip-Status register contents. */
+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS 0x00000040 /* SPROM present */
#define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003
#define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */
#define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */
@@ -398,6 +400,18 @@
#define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4
#define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */
+/** Macros to determine SPROM presence based on Chip-Status register. */
+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_OTP_SEL)
+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \
+ (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS)
+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \
+ (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \
+ ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+ SSB_CHIPCO_CHST_4325_OTP_SEL))
+
/** Clockcontrol masks and values **/
@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu {
struct ssb_chipcommon {
struct ssb_device *dev;
u32 capabilities;
+ u32 status;
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
struct ssb_chipcommon_pmu pmu;
--
1.6.2.5
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v3] ssb: do not read SPROM if it does not exist
2010-03-19 20:41 ` [PATCH v3] " John W. Linville
@ 2010-03-19 21:12 ` Michael Buesch
2010-03-19 22:10 ` John W. Linville
0 siblings, 1 reply; 7+ messages in thread
From: Michael Buesch @ 2010-03-19 21:12 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Larry Finger, stable
On Friday 19 March 2010 21:41:49 John W. Linville wrote:
> 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>
> Cc: Larry Finger <Larry.Finger@lwfinger.net>
> Cc: Michael Buesch <mb@bu3sch.de>
> Cc: stable@kernel.org
> ---
> Version 3, add missing semi-colon... :-(
> Version 2, check the correct place for ChipCommon core revision... :-)
>
> drivers/ssb/pci.c | 3 +++
> drivers/ssb/scan.c | 4 ++++
> drivers/ssb/sprom.c | 22 ++++++++++++++++++++++
> include/linux/ssb/ssb.h | 3 +++
> include/linux/ssb/ssb_driver_chipcommon.h | 15 +++++++++++++++
> 5 files changed, 47 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
> index 9e50896..2f7b16d 100644
> --- a/drivers/ssb/pci.c
> +++ b/drivers/ssb/pci.c
> @@ -620,6 +620,9 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
> int err = -ENOMEM;
> u16 *buf;
>
> + if (!ssb_is_sprom_available(bus))
> + return -ENODEV;
> +
> buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
> if (!buf)
> goto out;
> diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
> index 0d6c028..6d51895 100644
> --- a/drivers/ssb/scan.c
> +++ b/drivers/ssb/scan.c
> @@ -306,6 +306,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
> }
> tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
> bus->chipco.capabilities = tmp;
> + if (bus->chipco.dev->id.revision >= 11) {
> + tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPSTAT);
> + bus->chipco.status = tmp;
> + }
Hm, Ok. There's another issue here. We're that early in the scan that
id.xxxx is not assigned, yet. I think chipco.dev might even be NULL here, so
it'd crash.
This gets a little bit ugly. The revisions are read later in the scan function.
And as you can see there the actual read is pretty ugly, too.
What if we do not read the status _that_ early? We're really very very
early here. If you move the read into the chipcommon driver init, it will be much
easier.
--
Greetings, Michael.
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v3] ssb: do not read SPROM if it does not exist
2010-03-19 21:12 ` Michael Buesch
@ 2010-03-19 22:10 ` John W. Linville
0 siblings, 0 replies; 7+ messages in thread
From: John W. Linville @ 2010-03-19 22:10 UTC (permalink / raw)
To: Michael Buesch; +Cc: linux-wireless, Larry Finger, stable
On Fri, Mar 19, 2010 at 10:12:55PM +0100, Michael Buesch wrote:
> On Friday 19 March 2010 21:41:49 John W. Linville wrote:
> > diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
> > index 0d6c028..6d51895 100644
> > --- a/drivers/ssb/scan.c
> > +++ b/drivers/ssb/scan.c
> > @@ -306,6 +306,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
> > }
> > tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
> > bus->chipco.capabilities = tmp;
> > + if (bus->chipco.dev->id.revision >= 11) {
> > + tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPSTAT);
> > + bus->chipco.status = tmp;
> > + }
>
> Hm, Ok. There's another issue here. We're that early in the scan that
> id.xxxx is not assigned, yet. I think chipco.dev might even be NULL here, so
> it'd crash.
> This gets a little bit ugly. The revisions are read later in the scan function.
> And as you can see there the actual read is pretty ugly, too.
>
> What if we do not read the status _that_ early? We're really very very
> early here. If you move the read into the chipcommon driver init, it will be much
> easier.
Yeah, that makes sense. Patch to follow...
John
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2010-04-01 14:28 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-31 19:39 [PATCH V3] ssb: do not read SPROM if it does not exist John W. Linville
2010-03-31 19:42 ` Rafał Miłecki
2010-04-01 14:23 ` Michael Buesch
2010-04-01 14:28 ` Michael Buesch
-- strict thread matches above, loose matches on Subject: below --
2010-03-19 20:33 [PATCH v2] " John W. Linville
2010-03-19 20:41 ` [PATCH v3] " John W. Linville
2010-03-19 21:12 ` Michael Buesch
2010-03-19 22:10 ` John W. Linville
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).