1 From stable-bounces@linux.kernel.org Sun Jul 11 16:26:25 2010
2 From: Larry Finger <Larry.Finger@lwfinger.net>
3 Date: Sun, 11 Jul 2010 18:26:15 -0500
4 Subject: ssb: Handle Netbook devices where the SPROM address is changed
5 To: Greg KH <gregkh@suse.de>
6 Cc: linux-stable <stable@kernel.org>
7 Message-ID: <4C3A5317.3090603@lwfinger.net>
9 From: Christoph Fritz <chf.fritz@googlemail.com>
11 For some Netbook computers with Broadcom BCM4312 wireless interfaces,
12 the SPROM has been moved to a new location. When the ssb driver tries to
13 read the old location, the systems hangs when trying to read a
14 non-existent location. Such freezes are particularly bad as they do not
17 This patch is modified from commit
18 da1fdb02d9200ff28b6f3a380d21930335fe5429 with some pieces from other
19 mainline changes so that it can be applied to stable 2.6.34.Y.
21 Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
22 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
25 drivers/ssb/driver_chipcommon.c | 3 +
26 drivers/ssb/driver_chipcommon_pmu.c | 17 ++++-------
27 drivers/ssb/pci.c | 46 ++++++++++++++++++++++++++----
28 drivers/ssb/sprom.c | 15 +++++++++
29 include/linux/ssb/ssb.h | 1
30 include/linux/ssb/ssb_driver_chipcommon.h | 2 +
31 include/linux/ssb/ssb_regs.h | 3 +
32 7 files changed, 70 insertions(+), 17 deletions(-)
34 --- a/drivers/ssb/driver_chipcommon.c
35 +++ b/drivers/ssb/driver_chipcommon.c
36 @@ -233,6 +233,9 @@ void ssb_chipcommon_init(struct ssb_chip
39 return; /* We don't have a ChipCommon */
40 + if (cc->dev->id.revision >= 11)
41 + cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
42 + ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
44 chipco_powercontrol_init(cc);
45 ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
46 --- a/drivers/ssb/driver_chipcommon_pmu.c
47 +++ b/drivers/ssb/driver_chipcommon_pmu.c
48 @@ -495,9 +495,9 @@ static void ssb_pmu_resources_init(struc
49 chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
52 +/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
53 void ssb_pmu_init(struct ssb_chipcommon *cc)
55 - struct ssb_bus *bus = cc->dev->bus;
58 if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
59 @@ -509,15 +509,12 @@ void ssb_pmu_init(struct ssb_chipcommon
60 ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
63 - if (cc->pmu.rev >= 1) {
64 - if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
65 - chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
66 - ~SSB_CHIPCO_PMU_CTL_NOILPONW);
68 - chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
69 - SSB_CHIPCO_PMU_CTL_NOILPONW);
72 + if (cc->pmu.rev == 1)
73 + chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
74 + ~SSB_CHIPCO_PMU_CTL_NOILPONW);
76 + chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
77 + SSB_CHIPCO_PMU_CTL_NOILPONW);
79 ssb_pmu_resources_init(cc);
81 --- a/drivers/ssb/pci.c
82 +++ b/drivers/ssb/pci.c
85 #include "ssb_private.h"
87 +bool ssb_is_sprom_available(struct ssb_bus *bus);
89 /* Define the following to 1 to enable a printk on each coreswitch. */
90 #define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
91 @@ -167,7 +168,7 @@ err_pci:
94 /* Get the word-offset for a SSB_SPROM_XXX define. */
95 -#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16))
96 +#define SPOFF(offset) ((offset) / sizeof(u16))
97 /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
98 #define SPEX16(_outvar, _offset, _mask, _shift) \
99 out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
100 @@ -252,8 +253,13 @@ static int sprom_do_read(struct ssb_bus
104 + /* Check if SPROM can be read */
105 + if (ioread16(bus->mmio + bus->sprom_offset) == 0xFFFF) {
106 + ssb_printk(KERN_ERR PFX "Unable to read SPROM\n");
109 for (i = 0; i < bus->sprom_size; i++)
110 - sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
111 + sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
115 @@ -284,7 +290,7 @@ static int sprom_do_write(struct ssb_bus
119 - writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
120 + writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
124 @@ -620,21 +626,49 @@ static int ssb_pci_sprom_get(struct ssb_
128 + if (!ssb_is_sprom_available(bus)) {
129 + ssb_printk(KERN_ERR PFX "No SPROM available!\n");
132 + if (bus->chipco.dev) { /* can be unavailible! */
134 + * get SPROM offset: SSB_SPROM_BASE1 except for
135 + * chipcommon rev >= 31 or chip ID is 0x4312 and
136 + * chipcommon status & 3 == 2
138 + if (bus->chipco.dev->id.revision >= 31)
139 + bus->sprom_offset = SSB_SPROM_BASE31;
140 + else if (bus->chip_id == 0x4312 &&
141 + (bus->chipco.status & 0x03) == 2)
142 + bus->sprom_offset = SSB_SPROM_BASE31;
144 + bus->sprom_offset = SSB_SPROM_BASE1;
146 + bus->sprom_offset = SSB_SPROM_BASE1;
148 + ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
150 buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
153 bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
154 - sprom_do_read(bus, buf);
155 + err = sprom_do_read(bus, buf);
158 err = sprom_check_crc(buf, bus->sprom_size);
160 /* try for a 440 byte SPROM - revision 4 and higher */
162 buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
169 bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
170 - sprom_do_read(bus, buf);
171 + err = sprom_do_read(bus, buf);
174 err = sprom_check_crc(buf, bus->sprom_size);
176 /* All CRC attempts failed.
177 --- a/drivers/ssb/sprom.c
178 +++ b/drivers/ssb/sprom.c
179 @@ -179,3 +179,18 @@ const struct ssb_sprom *ssb_get_fallback
181 return fallback_sprom;
184 +/* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
185 +bool ssb_is_sprom_available(struct ssb_bus *bus)
187 + /* status register only exists on chipcomon rev >= 11 and we need check
189 + /* this routine differs from specs as we do not access SPROM directly
191 + if (bus->bustype == SSB_BUSTYPE_PCI &&
192 + bus->chipco.dev && /* can be unavailible! */
193 + bus->chipco.dev->id.revision >= 31)
194 + return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
198 --- a/include/linux/ssb/ssb.h
199 +++ b/include/linux/ssb/ssb.h
200 @@ -302,6 +302,7 @@ struct ssb_bus {
203 u16 sprom_size; /* number of words in sprom */
207 /* List of devices (cores) on the backplane. */
208 --- a/include/linux/ssb/ssb_driver_chipcommon.h
209 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
211 #define SSB_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */
212 #define SSB_CHIPCO_CAP_PCTL 0x00040000 /* Power Control */
213 #define SSB_CHIPCO_CAP_OTPS 0x00380000 /* OTP size */
214 +#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */
215 #define SSB_CHIPCO_CAP_OTPS_SHIFT 19
216 #define SSB_CHIPCO_CAP_OTPS_BASE 5
217 #define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */
218 @@ -564,6 +565,7 @@ struct ssb_chipcommon_pmu {
219 struct ssb_chipcommon {
220 struct ssb_device *dev;
223 /* Fast Powerup Delay constant */
224 u16 fast_pwrup_delay;
225 struct ssb_chipcommon_pmu pmu;
226 --- a/include/linux/ssb/ssb_regs.h
227 +++ b/include/linux/ssb/ssb_regs.h
229 #define SSB_SPROMSIZE_WORDS_R4 220
230 #define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
231 #define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
232 -#define SSB_SPROM_BASE 0x1000
233 +#define SSB_SPROM_BASE1 0x1000
234 +#define SSB_SPROM_BASE31 0x0800
235 #define SSB_SPROM_REVISION 0x107E
236 #define SSB_SPROM_REVISION_REV 0x00FF /* SPROM Revision number */
237 #define SSB_SPROM_REVISION_CRC 0xFF00 /* SPROM CRC8 value */