Jesse Keating 2f82dda
From 380bed7aa858cbe2d4eeb783e2bed7d01828518d Mon Sep 17 00:00:00 2001
Jesse Keating 2f82dda
From: John W. Linville <linville@tuxdriver.com>
Jesse Keating 2f82dda
Date: Fri, 19 Mar 2010 14:58:01 -0400
Jesse Keating 2f82dda
Subject: [PATCH v4] ssb: do not read SPROM if it does not exist
Jesse Keating 2f82dda
Jesse Keating 2f82dda
Attempting to read registers that don't exist on the SSB bus can cause
Jesse Keating 2f82dda
hangs on some boxes.  At least some b43 devices are 'in the wild' that
Jesse Keating 2f82dda
don't have SPROMs at all.  When the SSB bus support loads, it attempts
Jesse Keating 2f82dda
to read these (non-existant) SPROMs and causes hard hangs on the box --
Jesse Keating 2f82dda
no console output, etc.
Jesse Keating 2f82dda
Jesse Keating 2f82dda
This patch adds some intelligence to determine whether or not the SPROM
Jesse Keating 2f82dda
is present before attempting to read it.  This avoids those hard hangs
Jesse Keating 2f82dda
on those devices with no SPROM attached to their SSB bus.  The
Jesse Keating 2f82dda
SSB-attached devices (e.g. b43, et al.) won't work, but at least the box
Jesse Keating 2f82dda
will survive to test further patches. :-)
Jesse Keating 2f82dda
Jesse Keating 2f82dda
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Jesse Keating 2f82dda
Cc: Larry Finger <Larry.Finger@lwfinger.net>
Jesse Keating 2f82dda
Cc: Michael Buesch <mb@bu3sch.de>
Jesse Keating 2f82dda
Cc: stable@kernel.org
Jesse Keating 2f82dda
---
Jesse Keating 2f82dda
Version 4, move read of ChipCommon status register to ssb_chipcommon_init
Jesse Keating 2f82dda
Version 3, add missing semi-colon... :-(
Jesse Keating 2f82dda
Version 2, check the correct place for ChipCommon core revision... :-)
Jesse Keating 2f82dda
Jesse Keating 2f82dda
 drivers/ssb/driver_chipcommon.c           |    3 +++
Jesse Keating 2f82dda
 drivers/ssb/pci.c                         |    3 +++
Jesse Keating 2f82dda
 drivers/ssb/sprom.c                       |   22 ++++++++++++++++++++++
Jesse Keating 2f82dda
 include/linux/ssb/ssb.h                   |    3 +++
Jesse Keating 2f82dda
 include/linux/ssb/ssb_driver_chipcommon.h |   15 +++++++++++++++
Jesse Keating 2f82dda
 5 files changed, 46 insertions(+), 0 deletions(-)
Jesse Keating 2f82dda
Jesse Keating 2f82dda
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
Jesse Keating 2f82dda
index 9681536..6cf288d 100644
Jesse Keating 2f82dda
--- a/drivers/ssb/driver_chipcommon.c
Jesse Keating 2f82dda
+++ b/drivers/ssb/driver_chipcommon.c
Jesse Keating 2f82dda
@@ -233,6 +233,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
 	if (!cc->dev)
Jesse Keating 2f82dda
 		return; /* We don't have a ChipCommon */
Jesse Keating 2f82dda
+	if (cc->dev->id.revision >= 11) {
Jesse Keating 2f82dda
+		cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
Jesse Keating 2f82dda
+	}
Jesse Keating 2f82dda
 	ssb_pmu_init(cc);
Jesse Keating 2f82dda
 	chipco_powercontrol_init(cc);
Jesse Keating 2f82dda
 	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
Jesse Keating 2f82dda
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
Jesse Keating 2f82dda
index 9e50896..2f7b16d 100644
Jesse Keating 2f82dda
--- a/drivers/ssb/pci.c
Jesse Keating 2f82dda
+++ b/drivers/ssb/pci.c
Jesse Keating 2f82dda
@@ -620,6 +620,9 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
Jesse Keating 2f82dda
 	int err = -ENOMEM;
Jesse Keating 2f82dda
 	u16 *buf;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+	if (!ssb_is_sprom_available(bus))
Jesse Keating 2f82dda
+		return -ENODEV;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
Jesse Keating 2f82dda
 	if (!buf)
Jesse Keating 2f82dda
 		goto out;
Jesse Keating 2f82dda
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
Jesse Keating 2f82dda
index d0e6762..55eb9b0 100644
Jesse Keating 2f82dda
--- a/drivers/ssb/sprom.c
Jesse Keating 2f82dda
+++ b/drivers/ssb/sprom.c
Jesse Keating 2f82dda
@@ -175,3 +175,25 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
 	return fallback_sprom;
Jesse Keating 2f82dda
 }
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+bool ssb_is_sprom_available(struct ssb_bus *bus)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+	/* status register only exists on chipcomon rev >= 11 */
Jesse Keating 2f82dda
+	if (bus->chipco.dev->id.revision < 11)
Jesse Keating 2f82dda
+		return true;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	switch (bus->chip_id) {
Jesse Keating 2f82dda
+	case 0x4312:
Jesse Keating 2f82dda
+		return SSB_CHIPCO_CHST_4312_SPROM_PRESENT(bus->chipco.status);
Jesse Keating 2f82dda
+	case 0x4322:
Jesse Keating 2f82dda
+		return SSB_CHIPCO_CHST_4322_SPROM_PRESENT(bus->chipco.status);
Jesse Keating 2f82dda
+	case 0x4325:
Jesse Keating 2f82dda
+		return SSB_CHIPCO_CHST_4325_SPROM_PRESENT(bus->chipco.status);
Jesse Keating 2f82dda
+	default:
Jesse Keating 2f82dda
+		break;
Jesse Keating 2f82dda
+	}
Jesse Keating 2f82dda
+	if (bus->chipco.dev->id.revision >= 31)
Jesse Keating 2f82dda
+		return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	return true;
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
Jesse Keating 2f82dda
index 24f9885..3b4da23 100644
Jesse Keating 2f82dda
--- a/include/linux/ssb/ssb.h
Jesse Keating 2f82dda
+++ b/include/linux/ssb/ssb.h
Jesse Keating 2f82dda
@@ -394,6 +394,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 extern void ssb_bus_unregister(struct ssb_bus *bus);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+/* Does the device have an SPROM? */
Jesse Keating 2f82dda
+extern bool ssb_is_sprom_available(struct ssb_bus *bus);
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 /* Set a fallback SPROM.
Jesse Keating 2f82dda
  * See kdoc at the function definition for complete documentation. */
Jesse Keating 2f82dda
 extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
Jesse Keating 2f82dda
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
Jesse Keating 2f82dda
index 4e27acf..2cdf249 100644
Jesse Keating 2f82dda
--- a/include/linux/ssb/ssb_driver_chipcommon.h
Jesse Keating 2f82dda
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
Jesse Keating 2f82dda
@@ -53,6 +53,7 @@
Jesse Keating 2f82dda
 #define  SSB_CHIPCO_CAP_64BIT		0x08000000	/* 64-bit Backplane */
Jesse Keating 2f82dda
 #define  SSB_CHIPCO_CAP_PMU		0x10000000	/* PMU available (rev >= 20) */
Jesse Keating 2f82dda
 #define  SSB_CHIPCO_CAP_ECI		0x20000000	/* ECI available (rev >= 20) */
Jesse Keating 2f82dda
+#define  SSB_CHIPCO_CAP_SPROM		0x40000000	/* SPROM present */
Jesse Keating 2f82dda
 #define SSB_CHIPCO_CORECTL		0x0008
Jesse Keating 2f82dda
 #define  SSB_CHIPCO_CORECTL_UARTCLK0	0x00000001	/* Drive UART with internal clock */
Jesse Keating 2f82dda
 #define	 SSB_CHIPCO_CORECTL_SE		0x00000002	/* sync clk out enable (corerev >= 3) */
Jesse Keating 2f82dda
@@ -385,6 +386,7 @@
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 /** Chip specific Chip-Status register contents. */
Jesse Keating 2f82dda
+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS	0x00000040 /* SPROM present */
Jesse Keating 2f82dda
 #define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL	0x00000003
Jesse Keating 2f82dda
 #define SSB_CHIPCO_CHST_4325_DEFCIS_SEL		0 /* OTP is powered up, use def. CIS, no SPROM */
Jesse Keating 2f82dda
 #define SSB_CHIPCO_CHST_4325_SPROM_SEL		1 /* OTP is powered up, SPROM is present */
Jesse Keating 2f82dda
@@ -398,6 +400,18 @@
Jesse Keating 2f82dda
 #define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT	4
Jesse Keating 2f82dda
 #define SSB_CHIPCO_CHST_4325_PMUTOP_2B 		0x00000200 /* 1 for 2b, 0 for to 2a */
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+/** Macros to determine SPROM presence based on Chip-Status register. */
Jesse Keating 2f82dda
+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \
Jesse Keating 2f82dda
+	((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
Jesse Keating 2f82dda
+		SSB_CHIPCO_CHST_4325_OTP_SEL)
Jesse Keating 2f82dda
+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \
Jesse Keating 2f82dda
+	(status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS)
Jesse Keating 2f82dda
+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \
Jesse Keating 2f82dda
+	(((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
Jesse Keating 2f82dda
+		SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \
Jesse Keating 2f82dda
+	 ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
Jesse Keating 2f82dda
+		SSB_CHIPCO_CHST_4325_OTP_SEL))
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 /** Clockcontrol masks and values **/
Jesse Keating 2f82dda
@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu {
Jesse Keating 2f82dda
 struct ssb_chipcommon {
Jesse Keating 2f82dda
 	struct ssb_device *dev;
Jesse Keating 2f82dda
 	u32 capabilities;
Jesse Keating 2f82dda
+	u32 status;
Jesse Keating 2f82dda
 	/* Fast Powerup Delay constant */
Jesse Keating 2f82dda
 	u16 fast_pwrup_delay;
Jesse Keating 2f82dda
 	struct ssb_chipcommon_pmu pmu;
Jesse Keating 2f82dda
-- 
Jesse Keating 2f82dda
1.6.2.5
Jesse Keating 2f82dda
Jesse Keating 2f82dda
From ec032742062ad1b01dfe75cfccdbc5b850837c23 Mon Sep 17 00:00:00 2001
Jesse Keating 2f82dda
From: John W. Linville <linville@tuxdriver.com>
Jesse Keating 2f82dda
Date: Tue, 30 Mar 2010 13:47:39 -0400
Jesse Keating 2f82dda
Subject: [PATCH] ssb: avoid null ptr deref in ssb_is_sprom_available
Jesse Keating 2f82dda
Jesse Keating 2f82dda
Some older devices don't have chipcommon, but they do have SPROM.
Jesse Keating 2f82dda
Jesse Keating 2f82dda
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Jesse Keating 2f82dda
---
Jesse Keating 2f82dda
 drivers/ssb/sprom.c |    4 ++++
Jesse Keating 2f82dda
 1 files changed, 4 insertions(+), 0 deletions(-)
Jesse Keating 2f82dda
Jesse Keating 2f82dda
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
Jesse Keating 2f82dda
index 55eb9b0..874d8f1 100644
Jesse Keating 2f82dda
--- a/drivers/ssb/sprom.c
Jesse Keating 2f82dda
+++ b/drivers/ssb/sprom.c
Jesse Keating 2f82dda
@@ -178,6 +178,10 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void)
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 bool ssb_is_sprom_available(struct ssb_bus *bus)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
+	/* some older devices don't have chipcommon, but they have sprom */
Jesse Keating 2f82dda
+	if (!bus->chipco.dev)
Jesse Keating 2f82dda
+		return true;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 	/* status register only exists on chipcomon rev >= 11 */
Jesse Keating 2f82dda
 	if (bus->chipco.dev->id.revision < 11)
Jesse Keating 2f82dda
 		return true;
Jesse Keating 2f82dda
-- 
Jesse Keating 2f82dda
1.6.2.5
Jesse Keating 2f82dda