Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * Sonics Silicon Backplane PCI-Hostbus related functions.
  3  *
  4  * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
  5  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
  6  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
  7  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
  8  * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
  9  *
 10  * Derived from the Broadcom 4400 device driver.
 11  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
 12  * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
 13  * Copyright (C) 2006 Broadcom Corporation.
 14  *
 15  * Licensed under the GNU/GPL. See COPYING for details.
 16  */
 17 
 18 #include <linux/ssb/ssb.h>
 19 #include <linux/ssb/ssb_regs.h>
 20 #include <linux/pci.h>
 21 #include <linux/delay.h>
 22 
 23 #include "ssb_private.h"
 24 
 25 
 26 /* Define the following to 1 to enable a printk on each coreswitch. */
 27 #define SSB_VERBOSE_PCICORESWITCH_DEBUG         0
 28 
 29 
 30 /* Lowlevel coreswitching */
 31 int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
 32 {
 33         int err;
 34         int attempts = 0;
 35         u32 cur_core;
 36 
 37         while (1) {
 38                 err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
 39                                              (coreidx * SSB_CORE_SIZE)
 40                                              + SSB_ENUM_BASE);
 41                 if (err)
 42                         goto error;
 43                 err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
 44                                             &cur_core);
 45                 if (err)
 46                         goto error;
 47                 cur_core = (cur_core - SSB_ENUM_BASE)
 48                            / SSB_CORE_SIZE;
 49                 if (cur_core == coreidx)
 50                         break;
 51 
 52                 if (attempts++ > SSB_BAR0_MAX_RETRIES)
 53                         goto error;
 54                 udelay(10);
 55         }
 56         return 0;
 57 error:
 58         ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
 59         return -ENODEV;
 60 }
 61 
 62 int ssb_pci_switch_core(struct ssb_bus *bus,
 63                         struct ssb_device *dev)
 64 {
 65         int err;
 66         unsigned long flags;
 67 
 68 #if SSB_VERBOSE_PCICORESWITCH_DEBUG
 69         ssb_printk(KERN_INFO PFX
 70                    "Switching to %s core, index %d\n",
 71                    ssb_core_name(dev->id.coreid),
 72                    dev->core_index);
 73 #endif
 74 
 75         spin_lock_irqsave(&bus->bar_lock, flags);
 76         err = ssb_pci_switch_coreidx(bus, dev->core_index);
 77         if (!err)
 78                 bus->mapped_device = dev;
 79         spin_unlock_irqrestore(&bus->bar_lock, flags);
 80 
 81         return err;
 82 }
 83 
 84 /* Enable/disable the on board crystal oscillator and/or PLL. */
 85 int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
 86 {
 87         int err;
 88         u32 in, out, outenable;
 89         u16 pci_status;
 90 
 91         if (bus->bustype != SSB_BUSTYPE_PCI)
 92                 return 0;
 93 
 94         err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
 95         if (err)
 96                 goto err_pci;
 97         err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
 98         if (err)
 99                 goto err_pci;
100         err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
101         if (err)
102                 goto err_pci;
103 
104         outenable |= what;
105 
106         if (turn_on) {
107                 /* Avoid glitching the clock if GPRS is already using it.
108                  * We can't actually read the state of the PLLPD so we infer it
109                  * by the value of XTAL_PU which *is* readable via gpioin.
110                  */
111                 if (!(in & SSB_GPIO_XTAL)) {
112                         if (what & SSB_GPIO_XTAL) {
113                                 /* Turn the crystal on */
114                                 out |= SSB_GPIO_XTAL;
115                                 if (what & SSB_GPIO_PLL)
116                                         out |= SSB_GPIO_PLL;
117                                 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
118                                 if (err)
119                                         goto err_pci;
120                                 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
121                                                              outenable);
122                                 if (err)
123                                         goto err_pci;
124                                 msleep(1);
125                         }
126                         if (what & SSB_GPIO_PLL) {
127                                 /* Turn the PLL on */
128                                 out &= ~SSB_GPIO_PLL;
129                                 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
130                                 if (err)
131                                         goto err_pci;
132                                 msleep(5);
133                         }
134                 }
135 
136                 err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
137                 if (err)
138                         goto err_pci;
139                 pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
140                 err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
141                 if (err)
142                         goto err_pci;
143         } else {
144                 if (what & SSB_GPIO_XTAL) {
145                         /* Turn the crystal off */
146                         out &= ~SSB_GPIO_XTAL;
147                 }
148                 if (what & SSB_GPIO_PLL) {
149                         /* Turn the PLL off */
150                         out |= SSB_GPIO_PLL;
151                 }
152                 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
153                 if (err)
154                         goto err_pci;
155                 err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
156                 if (err)
157                         goto err_pci;
158         }
159 
160 out:
161         return err;
162 
163 err_pci:
164         printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
165         err = -EBUSY;
166         goto out;
167 }
168 
169 /* Get the word-offset for a SSB_SPROM_XXX define. */
170 #define SPOFF(offset)   (((offset) - SSB_SPROM_BASE) / sizeof(u16))
171 /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
172 #define SPEX(_outvar, _offset, _mask, _shift)   \
173         out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
174 
175 static inline u8 ssb_crc8(u8 crc, u8 data)
176 {
177         /* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
178         static const u8 t[] = {
179                 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
180                 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
181                 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
182                 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
183                 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
184                 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
185                 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
186                 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
187                 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
188                 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
189                 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
190                 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
191                 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
192                 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
193                 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
194                 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
195                 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
196                 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
197                 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
198                 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
199                 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
200                 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
201                 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
202                 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
203                 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
204                 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
205                 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
206                 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
207                 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
208                 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
209                 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
210                 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
211         };
212         return t[crc ^ data];
213 }
214 
215 static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
216 {
217         int word;
218         u8 crc = 0xFF;
219 
220         for (word = 0; word < size - 1; word++) {
221                 crc = ssb_crc8(crc, sprom[word] & 0x00FF);
222                 crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
223         }
224         crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
225         crc ^= 0xFF;
226 
227         return crc;
228 }
229 
230 static int sprom_check_crc(const u16 *sprom, u16 size)
231 {
232         u8 crc;
233         u8 expected_crc;
234         u16 tmp;
235 
236         crc = ssb_sprom_crc(sprom, size);
237         tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
238         expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
239         if (crc != expected_crc)
240                 return -EPROTO;
241 
242         return 0;
243 }
244 
245 static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
246 {
247         int i;
248 
249         for (i = 0; i < bus->sprom_size; i++)
250                 sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
251 }
252 
253 static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
254 {
255         struct pci_dev *pdev = bus->host_pci;
256         int i, err;
257         u32 spromctl;
258         u16 size = bus->sprom_size;
259 
260         ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
261         err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
262         if (err)
263                 goto err_ctlreg;
264         spromctl |= SSB_SPROMCTL_WE;
265         err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
266         if (err)
267                 goto err_ctlreg;
268         ssb_printk(KERN_NOTICE PFX "[ 0%%");
269         msleep(500);
270         for (i = 0; i < size; i++) {
271                 if (i == size / 4)
272                         ssb_printk("25%%");
273                 else if (i == size / 2)
274                         ssb_printk("50%%");
275                 else if (i == (size * 3) / 4)
276                         ssb_printk("75%%");
277                 else if (i % 2)
278                         ssb_printk(".");
279                 writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
280                 mmiowb();
281                 msleep(20);
282         }
283         err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
284         if (err)
285                 goto err_ctlreg;
286         spromctl &= ~SSB_SPROMCTL_WE;
287         err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
288         if (err)
289                 goto err_ctlreg;
290         msleep(500);
291         ssb_printk("100%% ]\n");
292         ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
293 
294         return 0;
295 err_ctlreg:
296         ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
297         return err;
298 }
299 
300 static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
301                                u16 mask, u16 shift)
302 {
303         u16 v;
304         u8 gain;
305 
306         v = in[SPOFF(SSB_SPROM1_AGAIN)];
307         gain = (v & mask) >> shift;
308         if (gain == 0xFF)
309                 gain = 2; /* If unset use 2dBm */
310         if (sprom_revision == 1) {
311                 /* Convert to Q5.2 */
312                 gain <<= 2;
313         } else {
314                 /* Q5.2 Fractional part is stored in 0xC0 */
315                 gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
316         }
317 
318         return (s8)gain;
319 }
320 
321 static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
322 {
323         int i;
324         u16 v;
325         s8 gain;
326         u16 loc[3];
327 
328         if (out->revision == 3) {                       /* rev 3 moved MAC */
329                 loc[0] = SSB_SPROM3_IL0MAC;
330                 loc[1] = SSB_SPROM3_ET0MAC;
331                 loc[2] = SSB_SPROM3_ET1MAC;
332         } else {
333                 loc[0] = SSB_SPROM1_IL0MAC;
334                 loc[1] = SSB_SPROM1_ET0MAC;
335                 loc[2] = SSB_SPROM1_ET1MAC;
336         }
337         for (i = 0; i < 3; i++) {
338                 v = in[SPOFF(loc[0]) + i];
339                 *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
340         }
341         for (i = 0; i < 3; i++) {
342                 v = in[SPOFF(loc[1]) + i];
343                 *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
344         }
345         for (i = 0; i < 3; i++) {
346                 v = in[SPOFF(loc[2]) + i];
347                 *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
348         }
349         SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
350         SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
351              SSB_SPROM1_ETHPHY_ET1A_SHIFT);
352         SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
353         SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
354         SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
355         SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
356              SSB_SPROM1_BINF_CCODE_SHIFT);
357         SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
358              SSB_SPROM1_BINF_ANTA_SHIFT);
359         SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
360              SSB_SPROM1_BINF_ANTBG_SHIFT);
361         SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
362         SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
363         SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
364         SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
365         SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
366         SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
367         SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
368         SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
369              SSB_SPROM1_GPIOA_P1_SHIFT);
370         SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
371         SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
372              SSB_SPROM1_GPIOB_P3_SHIFT);
373         SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
374              SSB_SPROM1_MAXPWR_A_SHIFT);
375         SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
376         SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
377              SSB_SPROM1_ITSSI_A_SHIFT);
378         SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
379         SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
380         if (out->revision >= 2)
381                 SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
382 
383         /* Extract the antenna gain values. */
384         gain = r123_extract_antgain(out->revision, in,
385                                     SSB_SPROM1_AGAIN_BG,
386                                     SSB_SPROM1_AGAIN_BG_SHIFT);
387         out->antenna_gain.ghz24.a0 = gain;
388         out->antenna_gain.ghz24.a1 = gain;
389         out->antenna_gain.ghz24.a2 = gain;
390         out->antenna_gain.ghz24.a3 = gain;
391         gain = r123_extract_antgain(out->revision, in,
392                                     SSB_SPROM1_AGAIN_A,
393                                     SSB_SPROM1_AGAIN_A_SHIFT);
394         out->antenna_gain.ghz5.a0 = gain;
395         out->antenna_gain.ghz5.a1 = gain;
396         out->antenna_gain.ghz5.a2 = gain;
397         out->antenna_gain.ghz5.a3 = gain;
398 }
399 
400 static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
401 {
402         int i;
403         u16 v;
404 
405         /* extract the equivalent of the r1 variables */
406         for (i = 0; i < 3; i++) {
407                 v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
408                 *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
409         }
410         for (i = 0; i < 3; i++) {
411                 v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
412                 *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
413         }
414         for (i = 0; i < 3; i++) {
415                 v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
416                 *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
417         }
418         SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
419         SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
420              SSB_SPROM4_ETHPHY_ET1A_SHIFT);
421         SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
422         SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
423         SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
424         SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
425              SSB_SPROM4_ANTAVAIL_A_SHIFT);
426         SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
427              SSB_SPROM4_ANTAVAIL_BG_SHIFT);
428         SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
429         SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
430              SSB_SPROM4_ITSSI_BG_SHIFT);
431         SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
432         SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
433              SSB_SPROM4_ITSSI_A_SHIFT);
434         SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
435         SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
436              SSB_SPROM4_GPIOA_P1_SHIFT);
437         SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
438         SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
439              SSB_SPROM4_GPIOB_P3_SHIFT);
440 
441         /* Extract the antenna gain values. */
442         SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
443              SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
444         SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01,
445              SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
446         SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23,
447              SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
448         SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23,
449              SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
450         memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
451                sizeof(out->antenna_gain.ghz5));
452 
453         /* TODO - get remaining rev 4 stuff needed */
454 }
455 
456 static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
457                          const u16 *in, u16 size)
458 {
459         memset(out, 0, sizeof(*out));
460 
461         out->revision = in[size - 1] & 0x00FF;
462         ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
463         if ((bus->chip_id & 0xFF00) == 0x4400) {
464                 /* Workaround: The BCM44XX chip has a stupid revision
465                  * number stored in the SPROM.
466                  * Always extract r1. */
467                 out->revision = 1;
468                 sprom_extract_r123(out, in);
469         } else if (bus->chip_id == 0x4321) {
470                 /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
471                 out->revision = 4;
472                 sprom_extract_r4(out, in);
473         } else {
474                 if (out->revision == 0)
475                         goto unsupported;
476                 if (out->revision >= 1 && out->revision <= 3) {
477                         sprom_extract_r123(out, in);
478                 }
479                 if (out->revision == 4)
480                         sprom_extract_r4(out, in);
481                 if (out->revision >= 5)
482                         goto unsupported;
483         }
484 
485         if (out->boardflags_lo == 0xFFFF)
486                 out->boardflags_lo = 0;  /* per specs */
487         if (out->boardflags_hi == 0xFFFF)
488                 out->boardflags_hi = 0;  /* per specs */
489 
490         return 0;
491 unsupported:
492         ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
493                    "detected. Will extract v1\n", out->revision);
494         sprom_extract_r123(out, in);
495         return 0;
496 }
497 
498 static int ssb_pci_sprom_get(struct ssb_bus *bus,
499                              struct ssb_sprom *sprom)
500 {
501         int err = -ENOMEM;
502         u16 *buf;
503 
504         buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
505         if (!buf)
506                 goto out;
507         bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
508         sprom_do_read(bus, buf);
509         err = sprom_check_crc(buf, bus->sprom_size);
510         if (err) {
511                 /* check for rev 4 sprom - has special signature */
512                 if (buf[32] == 0x5372) {
513                         kfree(buf);
514                         buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
515                                       GFP_KERNEL);
516                         if (!buf)
517                                 goto out;
518                         bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
519                         sprom_do_read(bus, buf);
520                         err = sprom_check_crc(buf, bus->sprom_size);
521                 }
522                 if (err)
523                         ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
524                                    " SPROM CRC (corrupt SPROM)\n");
525         }
526         err = sprom_extract(bus, sprom, buf, bus->sprom_size);
527 
528         kfree(buf);
529 out:
530         return err;
531 }
532 
533 static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
534                                   struct ssb_boardinfo *bi)
535 {
536         pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
537                              &bi->vendor);
538         pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
539                              &bi->type);
540         pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
541                              &bi->rev);
542 }
543 
544 int ssb_pci_get_invariants(struct ssb_bus *bus,
545                            struct ssb_init_invariants *iv)
546 {
547         int err;
548 
549         err = ssb_pci_sprom_get(bus, &iv->sprom);
550         if (err)
551                 goto out;
552         ssb_pci_get_boardinfo(bus, &iv->boardinfo);
553 
554 out:
555         return err;
556 }
557 
558 #ifdef CONFIG_SSB_DEBUG
559 static int ssb_pci_assert_buspower(struct ssb_bus *bus)
560 {
561         if (likely(bus->powered_up))
562                 return 0;
563 
564         printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
565                "while accessing PCI MMIO space\n");
566         if (bus->power_warn_count <= 10) {
567                 bus->power_warn_count++;
568                 dump_stack();
569         }
570 
571         return -ENODEV;
572 }
573 #else /* DEBUG */
574 static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
575 {
576         return 0;
577 }
578 #endif /* DEBUG */
579 
580 static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
581 {
582         struct ssb_bus *bus = dev->bus;
583 
584         if (unlikely(ssb_pci_assert_buspower(bus)))
585                 return 0xFFFF;
586         if (unlikely(bus->mapped_device != dev)) {
587                 if (unlikely(ssb_pci_switch_core(bus, dev)))
588                         return 0xFFFF;
589         }
590         return ioread16(bus->mmio + offset);
591 }
592 
593 static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
594 {
595         struct ssb_bus *bus = dev->bus;
596 
597         if (unlikely(ssb_pci_assert_buspower(bus)))
598                 return 0xFFFFFFFF;
599         if (unlikely(bus->mapped_device != dev)) {
600                 if (unlikely(ssb_pci_switch_core(bus, dev)))
601                         return 0xFFFFFFFF;
602         }
603         return ioread32(bus->mmio + offset);
604 }
605 
606 static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
607 {
608         struct ssb_bus *bus = dev->bus;
609 
610         if (unlikely(ssb_pci_assert_buspower(bus)))
611                 return;
612         if (unlikely(bus->mapped_device != dev)) {
613                 if (unlikely(ssb_pci_switch_core(bus, dev)))
614                         return;
615         }
616         iowrite16(value, bus->mmio + offset);
617 }
618 
619 static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
620 {
621         struct ssb_bus *bus = dev->bus;
622 
623         if (unlikely(ssb_pci_assert_buspower(bus)))
624                 return;
625         if (unlikely(bus->mapped_device != dev)) {
626                 if (unlikely(ssb_pci_switch_core(bus, dev)))
627                         return;
628         }
629         iowrite32(value, bus->mmio + offset);
630 }
631 
632 /* Not "static", as it's used in main.c */
633 const struct ssb_bus_ops ssb_pci_ops = {
634         .read16         = ssb_pci_read16,
635         .read32         = ssb_pci_read32,
636         .write16        = ssb_pci_write16,
637         .write32        = ssb_pci_write32,
638 };
639 
640 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
641 {
642         int i, pos = 0;
643 
644         for (i = 0; i < size; i++)
645                 pos += snprintf(buf + pos, buf_len - pos - 1,
646                                 "%04X", swab16(sprom[i]) & 0xFFFF);
647         pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
648 
649         return pos + 1;
650 }
651 
652 static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
653 {
654         char tmp[5] = { 0 };
655         int cnt = 0;
656         unsigned long parsed;
657 
658         if (len < size * 2)
659                 return -EINVAL;
660 
661         while (cnt < size) {
662                 memcpy(tmp, dump, 4);
663                 dump += 4;
664                 parsed = simple_strtoul(tmp, NULL, 16);
665                 sprom[cnt++] = swab16((u16)parsed);
666         }
667 
668         return 0;
669 }
670 
671 static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
672                                        struct device_attribute *attr,
673                                        char *buf)
674 {
675         struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
676         struct ssb_bus *bus;
677         u16 *sprom;
678         int err = -ENODEV;
679         ssize_t count = 0;
680 
681         bus = ssb_pci_dev_to_bus(pdev);
682         if (!bus)
683                 goto out;
684         err = -ENOMEM;
685         sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
686         if (!sprom)
687                 goto out;
688 
689         /* Use interruptible locking, as the SPROM write might
690          * be holding the lock for several seconds. So allow userspace
691          * to cancel operation. */
692         err = -ERESTARTSYS;
693         if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
694                 goto out_kfree;
695         sprom_do_read(bus, sprom);
696         mutex_unlock(&bus->pci_sprom_mutex);
697 
698         count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
699         err = 0;
700 
701 out_kfree:
702         kfree(sprom);
703 out:
704         return err ? err : count;
705 }
706 
707 static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
708                                         struct device_attribute *attr,
709                                         const char *buf, size_t count)
710 {
711         struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
712         struct ssb_bus *bus;
713         u16 *sprom;
714         int res = 0, err = -ENODEV;
715 
716         bus = ssb_pci_dev_to_bus(pdev);
717         if (!bus)
718                 goto out;
719         err = -ENOMEM;
720         sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
721         if (!sprom)
722                 goto out;
723         err = hex2sprom(sprom, buf, count, bus->sprom_size);
724         if (err) {
725                 err = -EINVAL;
726                 goto out_kfree;
727         }
728         err = sprom_check_crc(sprom, bus->sprom_size);
729         if (err) {
730                 err = -EINVAL;
731                 goto out_kfree;
732         }
733 
734         /* Use interruptible locking, as the SPROM write might
735          * be holding the lock for several seconds. So allow userspace
736          * to cancel operation. */
737         err = -ERESTARTSYS;
738         if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
739                 goto out_kfree;
740         err = ssb_devices_freeze(bus);
741         if (err == -EOPNOTSUPP) {
742                 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
743                            "No suspend support. Is CONFIG_PM enabled?\n");
744                 goto out_unlock;
745         }
746         if (err) {
747                 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
748                 goto out_unlock;
749         }
750         res = sprom_do_write(bus, sprom);
751         err = ssb_devices_thaw(bus);
752         if (err)
753                 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
754 out_unlock:
755         mutex_unlock(&bus->pci_sprom_mutex);
756 out_kfree:
757         kfree(sprom);
758 out:
759         if (res)
760                 return res;
761         return err ? err : count;
762 }
763 
764 static DEVICE_ATTR(ssb_sprom, 0600,
765                    ssb_pci_attr_sprom_show,
766                    ssb_pci_attr_sprom_store);
767 
768 void ssb_pci_exit(struct ssb_bus *bus)
769 {
770         struct pci_dev *pdev;
771 
772         if (bus->bustype != SSB_BUSTYPE_PCI)
773                 return;
774 
775         pdev = bus->host_pci;
776         device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
777 }
778 
779 int ssb_pci_init(struct ssb_bus *bus)
780 {
781         struct pci_dev *pdev;
782         int err;
783 
784         if (bus->bustype != SSB_BUSTYPE_PCI)
785                 return 0;
786 
787         pdev = bus->host_pci;
788         mutex_init(&bus->pci_sprom_mutex);
789         err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
790         if (err)
791                 goto out;
792 
793 out:
794         return err;
795 }
796 
  This page was automatically generated by the LXR engine.