]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.32.17/ssb-handle-netbook-devices-where-the-sprom-address-is-changed.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.17 / ssb-handle-netbook-devices-where-the-sprom-address-is-changed.patch
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>
8
9 From: Christoph Fritz <chf.fritz@googlemail.com>
10
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
15 log the failure.
16
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.
20
21 Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
22 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
23
24 ---
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(-)
33
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
37 {
38 if (!cc->dev)
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);
43 ssb_pmu_init(cc);
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);
50 }
51
52 +/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
53 void ssb_pmu_init(struct ssb_chipcommon *cc)
54 {
55 - struct ssb_bus *bus = cc->dev->bus;
56 u32 pmucap;
57
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",
61 cc->pmu.rev, pmucap);
62
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);
67 - } else {
68 - chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
69 - SSB_CHIPCO_PMU_CTL_NOILPONW);
70 - }
71 - }
72 + if (cc->pmu.rev == 1)
73 + chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
74 + ~SSB_CHIPCO_PMU_CTL_NOILPONW);
75 + else
76 + chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
77 + SSB_CHIPCO_PMU_CTL_NOILPONW);
78 ssb_pmu_pll_init(cc);
79 ssb_pmu_resources_init(cc);
80 }
81 --- a/drivers/ssb/pci.c
82 +++ b/drivers/ssb/pci.c
83 @@ -22,6 +22,7 @@
84
85 #include "ssb_private.h"
86
87 +bool ssb_is_sprom_available(struct ssb_bus *bus);
88
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:
92 }
93
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
101 {
102 int i;
103
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");
107 + return -ENODEV;
108 + }
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));
112
113 return 0;
114 }
115 @@ -284,7 +290,7 @@ static int sprom_do_write(struct ssb_bus
116 ssb_printk("75%%");
117 else if (i % 2)
118 ssb_printk(".");
119 - writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
120 + writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
121 mmiowb();
122 msleep(20);
123 }
124 @@ -620,21 +626,49 @@ static int ssb_pci_sprom_get(struct ssb_
125 int err = -ENOMEM;
126 u16 *buf;
127
128 + if (!ssb_is_sprom_available(bus)) {
129 + ssb_printk(KERN_ERR PFX "No SPROM available!\n");
130 + return -ENODEV;
131 + }
132 + if (bus->chipco.dev) { /* can be unavailible! */
133 + /*
134 + * get SPROM offset: SSB_SPROM_BASE1 except for
135 + * chipcommon rev >= 31 or chip ID is 0x4312 and
136 + * chipcommon status & 3 == 2
137 + */
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;
143 + else
144 + bus->sprom_offset = SSB_SPROM_BASE1;
145 + } else {
146 + bus->sprom_offset = SSB_SPROM_BASE1;
147 + }
148 + ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
149 +
150 buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
151 if (!buf)
152 goto out;
153 bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
154 - sprom_do_read(bus, buf);
155 + err = sprom_do_read(bus, buf);
156 + if (err)
157 + goto out_free;
158 err = sprom_check_crc(buf, bus->sprom_size);
159 if (err) {
160 /* try for a 440 byte SPROM - revision 4 and higher */
161 kfree(buf);
162 buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
163 GFP_KERNEL);
164 - if (!buf)
165 + if (!buf) {
166 + err = -ENOMEM;
167 goto out;
168 + }
169 bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
170 - sprom_do_read(bus, buf);
171 + err = sprom_do_read(bus, buf);
172 + if (err)
173 + goto out_free;
174 err = sprom_check_crc(buf, bus->sprom_size);
175 if (err) {
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
180 {
181 return fallback_sprom;
182 }
183 +
184 +/* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
185 +bool ssb_is_sprom_available(struct ssb_bus *bus)
186 +{
187 + /* status register only exists on chipcomon rev >= 11 and we need check
188 + for >= 31 only */
189 + /* this routine differs from specs as we do not access SPROM directly
190 + on PCMCIA */
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;
195 +
196 + return true;
197 +}
198 --- a/include/linux/ssb/ssb.h
199 +++ b/include/linux/ssb/ssb.h
200 @@ -302,6 +302,7 @@ struct ssb_bus {
201 u16 chip_id;
202 u16 chip_rev;
203 u16 sprom_size; /* number of words in sprom */
204 + u16 sprom_offset;
205 u8 chip_package;
206
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
210 @@ -46,6 +46,7 @@
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;
221 u32 capabilities;
222 + u32 status;
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
228 @@ -170,7 +170,8 @@
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 */