aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/ssb
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/ssb')
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c7
-rw-r--r--drivers/ssb/driver_gige.c1
-rw-r--r--drivers/ssb/driver_mipscore.c5
-rw-r--r--drivers/ssb/driver_pcicore.c33
-rw-r--r--drivers/ssb/main.c130
-rw-r--r--drivers/ssb/pci.c1
-rw-r--r--drivers/ssb/pcihost_wrapper.c1
-rw-r--r--drivers/ssb/pcmcia.c232
-rw-r--r--drivers/ssb/scan.c2
-rw-r--r--drivers/ssb/sprom.c31
-rw-r--r--drivers/ssb/ssb_private.h16
11 files changed, 234 insertions, 225 deletions
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 64abd11f6fbb..3d551245a4e2 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -332,6 +332,12 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
332 case 0x5354: 332 case 0x5354:
333 ssb_pmu0_pllinit_r0(cc, crystalfreq); 333 ssb_pmu0_pllinit_r0(cc, crystalfreq);
334 break; 334 break;
335 case 0x4322:
336 if (cc->pmu.rev == 2) {
337 chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, 0x0000000A);
338 chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
339 }
340 break;
335 default: 341 default:
336 ssb_printk(KERN_ERR PFX 342 ssb_printk(KERN_ERR PFX
337 "ERROR: PLL init unknown for device %04X\n", 343 "ERROR: PLL init unknown for device %04X\n",
@@ -417,6 +423,7 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
417 423
418 switch (bus->chip_id) { 424 switch (bus->chip_id) {
419 case 0x4312: 425 case 0x4312:
426 case 0x4322:
420 /* We keep the default settings: 427 /* We keep the default settings:
421 * min_msk = 0xCBB 428 * min_msk = 0xCBB
422 * max_msk = 0x7FFFF 429 * max_msk = 0x7FFFF
diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c
index 172f90407b93..5ba92a2719a4 100644
--- a/drivers/ssb/driver_gige.c
+++ b/drivers/ssb/driver_gige.c
@@ -12,6 +12,7 @@
12#include <linux/ssb/ssb_driver_gige.h> 12#include <linux/ssb/ssb_driver_gige.h>
13#include <linux/pci.h> 13#include <linux/pci.h>
14#include <linux/pci_regs.h> 14#include <linux/pci_regs.h>
15#include <linux/slab.h>
15 16
16 17
17/* 18/*
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
index 3c6feed46f6e..97efce184a8f 100644
--- a/drivers/ssb/driver_mipscore.c
+++ b/drivers/ssb/driver_mipscore.c
@@ -270,7 +270,6 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
270 set_irq(dev, irq++); 270 set_irq(dev, irq++);
271 } 271 }
272 break; 272 break;
273 /* fallthrough */
274 case SSB_DEV_PCI: 273 case SSB_DEV_PCI:
275 case SSB_DEV_ETHERNET: 274 case SSB_DEV_ETHERNET:
276 case SSB_DEV_ETHERNET_GBIT: 275 case SSB_DEV_ETHERNET_GBIT:
@@ -281,6 +280,10 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
281 set_irq(dev, irq++); 280 set_irq(dev, irq++);
282 break; 281 break;
283 } 282 }
283 /* fallthrough */
284 case SSB_DEV_EXTIF:
285 set_irq(dev, 0);
286 break;
284 } 287 }
285 } 288 }
286 ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n"); 289 ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 538c570df337..0e8d35224614 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -246,20 +246,12 @@ static struct pci_controller ssb_pcicore_controller = {
246 .pci_ops = &ssb_pcicore_pciops, 246 .pci_ops = &ssb_pcicore_pciops,
247 .io_resource = &ssb_pcicore_io_resource, 247 .io_resource = &ssb_pcicore_io_resource,
248 .mem_resource = &ssb_pcicore_mem_resource, 248 .mem_resource = &ssb_pcicore_mem_resource,
249 .mem_offset = 0x24000000,
250}; 249};
251 250
252static u32 ssb_pcicore_pcibus_iobase = 0x100;
253static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
254
255/* This function is called when doing a pci_enable_device(). 251/* This function is called when doing a pci_enable_device().
256 * We must first check if the device is a device on the PCI-core bridge. */ 252 * We must first check if the device is a device on the PCI-core bridge. */
257int ssb_pcicore_plat_dev_init(struct pci_dev *d) 253int ssb_pcicore_plat_dev_init(struct pci_dev *d)
258{ 254{
259 struct resource *res;
260 int pos, size;
261 u32 *base;
262
263 if (d->bus->ops != &ssb_pcicore_pciops) { 255 if (d->bus->ops != &ssb_pcicore_pciops) {
264 /* This is not a device on the PCI-core bridge. */ 256 /* This is not a device on the PCI-core bridge. */
265 return -ENODEV; 257 return -ENODEV;
@@ -268,27 +260,6 @@ int ssb_pcicore_plat_dev_init(struct pci_dev *d)
268 ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", 260 ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
269 pci_name(d)); 261 pci_name(d));
270 262
271 /* Fix up resource bases */
272 for (pos = 0; pos < 6; pos++) {
273 res = &d->resource[pos];
274 if (res->flags & IORESOURCE_IO)
275 base = &ssb_pcicore_pcibus_iobase;
276 else
277 base = &ssb_pcicore_pcibus_membase;
278 res->flags |= IORESOURCE_PCI_FIXED;
279 if (res->end) {
280 size = res->end - res->start + 1;
281 if (*base & (size - 1))
282 *base = (*base + size) & ~(size - 1);
283 res->start = *base;
284 res->end = res->start + size - 1;
285 *base += size;
286 pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
287 }
288 /* Fix up PCI bridge BAR0 only */
289 if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
290 break;
291 }
292 /* Fix up interrupt lines */ 263 /* Fix up interrupt lines */
293 d->irq = ssb_mips_irq(extpci_core->dev) + 2; 264 d->irq = ssb_mips_irq(extpci_core->dev) + 2;
294 pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); 265 pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
@@ -551,13 +522,13 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
551 might_sleep_if(pdev->id.coreid != SSB_DEV_PCI); 522 might_sleep_if(pdev->id.coreid != SSB_DEV_PCI);
552 523
553 /* Enable interrupts for this device. */ 524 /* Enable interrupts for this device. */
554 if (bus->host_pci && 525 if ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE)) {
555 ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
556 u32 coremask; 526 u32 coremask;
557 527
558 /* Calculate the "coremask" for the device. */ 528 /* Calculate the "coremask" for the device. */
559 coremask = (1 << dev->core_index); 529 coremask = (1 << dev->core_index);
560 530
531 SSB_WARN_ON(bus->bustype != SSB_BUSTYPE_PCI);
561 err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); 532 err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
562 if (err) 533 if (err)
563 goto out; 534 goto out;
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 579b114be412..80ff7d9e60de 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -18,6 +18,7 @@
18#include <linux/dma-mapping.h> 18#include <linux/dma-mapping.h>
19#include <linux/pci.h> 19#include <linux/pci.h>
20#include <linux/mmc/sdio_func.h> 20#include <linux/mmc/sdio_func.h>
21#include <linux/slab.h>
21 22
22#include <pcmcia/cs_types.h> 23#include <pcmcia/cs_types.h>
23#include <pcmcia/cs.h> 24#include <pcmcia/cs.h>
@@ -140,6 +141,19 @@ static void ssb_device_put(struct ssb_device *dev)
140 put_device(dev->dev); 141 put_device(dev->dev);
141} 142}
142 143
144static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv)
145{
146 if (drv)
147 get_driver(&drv->drv);
148 return drv;
149}
150
151static inline void ssb_driver_put(struct ssb_driver *drv)
152{
153 if (drv)
154 put_driver(&drv->drv);
155}
156
143static int ssb_device_resume(struct device *dev) 157static int ssb_device_resume(struct device *dev)
144{ 158{
145 struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 159 struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
@@ -210,90 +224,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
210EXPORT_SYMBOL(ssb_bus_suspend); 224EXPORT_SYMBOL(ssb_bus_suspend);
211 225
212#ifdef CONFIG_SSB_SPROM 226#ifdef CONFIG_SSB_SPROM
213int ssb_devices_freeze(struct ssb_bus *bus) 227/** ssb_devices_freeze - Freeze all devices on the bus.
228 *
229 * After freezing no device driver will be handling a device
230 * on this bus anymore. ssb_devices_thaw() must be called after
231 * a successful freeze to reactivate the devices.
232 *
233 * @bus: The bus.
234 * @ctx: Context structure. Pass this to ssb_devices_thaw().
235 */
236int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx)
214{ 237{
215 struct ssb_device *dev; 238 struct ssb_device *sdev;
216 struct ssb_driver *drv; 239 struct ssb_driver *sdrv;
217 int err = 0; 240 unsigned int i;
218 int i; 241
219 pm_message_t state = PMSG_FREEZE; 242 memset(ctx, 0, sizeof(*ctx));
243 ctx->bus = bus;
244 SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen));
220 245
221 /* First check that we are capable to freeze all devices. */
222 for (i = 0; i < bus->nr_devices; i++) { 246 for (i = 0; i < bus->nr_devices; i++) {
223 dev = &(bus->devices[i]); 247 sdev = ssb_device_get(&bus->devices[i]);
224 if (!dev->dev || 248
225 !dev->dev->driver || 249 if (!sdev->dev || !sdev->dev->driver ||
226 !device_is_registered(dev->dev)) 250 !device_is_registered(sdev->dev)) {
227 continue; 251 ssb_device_put(sdev);
228 drv = drv_to_ssb_drv(dev->dev->driver);
229 if (!drv)
230 continue; 252 continue;
231 if (!drv->suspend) {
232 /* Nope, can't suspend this one. */
233 return -EOPNOTSUPP;
234 } 253 }
235 } 254 sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
236 /* Now suspend all devices */ 255 if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
237 for (i = 0; i < bus->nr_devices; i++) { 256 ssb_device_put(sdev);
238 dev = &(bus->devices[i]);
239 if (!dev->dev ||
240 !dev->dev->driver ||
241 !device_is_registered(dev->dev))
242 continue; 257 continue;
243 drv = drv_to_ssb_drv(dev->dev->driver);
244 if (!drv)
245 continue;
246 err = drv->suspend(dev, state);
247 if (err) {
248 ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
249 dev_name(dev->dev));
250 goto err_unwind;
251 } 258 }
259 sdrv->remove(sdev);
260 ctx->device_frozen[i] = 1;
252 } 261 }
253 262
254 return 0; 263 return 0;
255err_unwind:
256 for (i--; i >= 0; i--) {
257 dev = &(bus->devices[i]);
258 if (!dev->dev ||
259 !dev->dev->driver ||
260 !device_is_registered(dev->dev))
261 continue;
262 drv = drv_to_ssb_drv(dev->dev->driver);
263 if (!drv)
264 continue;
265 if (drv->resume)
266 drv->resume(dev);
267 }
268 return err;
269} 264}
270 265
271int ssb_devices_thaw(struct ssb_bus *bus) 266/** ssb_devices_thaw - Unfreeze all devices on the bus.
267 *
268 * This will re-attach the device drivers and re-init the devices.
269 *
270 * @ctx: The context structure from ssb_devices_freeze()
271 */
272int ssb_devices_thaw(struct ssb_freeze_context *ctx)
272{ 273{
273 struct ssb_device *dev; 274 struct ssb_bus *bus = ctx->bus;
274 struct ssb_driver *drv; 275 struct ssb_device *sdev;
275 int err; 276 struct ssb_driver *sdrv;
276 int i; 277 unsigned int i;
278 int err, result = 0;
277 279
278 for (i = 0; i < bus->nr_devices; i++) { 280 for (i = 0; i < bus->nr_devices; i++) {
279 dev = &(bus->devices[i]); 281 if (!ctx->device_frozen[i])
280 if (!dev->dev ||
281 !dev->dev->driver ||
282 !device_is_registered(dev->dev))
283 continue; 282 continue;
284 drv = drv_to_ssb_drv(dev->dev->driver); 283 sdev = &bus->devices[i];
285 if (!drv) 284
285 if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver))
286 continue; 286 continue;
287 if (SSB_WARN_ON(!drv->resume)) 287 sdrv = drv_to_ssb_drv(sdev->dev->driver);
288 if (SSB_WARN_ON(!sdrv || !sdrv->probe))
288 continue; 289 continue;
289 err = drv->resume(dev); 290
291 err = sdrv->probe(sdev, &sdev->id);
290 if (err) { 292 if (err) {
291 ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", 293 ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
292 dev_name(dev->dev)); 294 dev_name(sdev->dev));
295 result = err;
293 } 296 }
297 ssb_driver_put(sdrv);
298 ssb_device_put(sdev);
294 } 299 }
295 300
296 return 0; 301 return result;
297} 302}
298#endif /* CONFIG_SSB_SPROM */ 303#endif /* CONFIG_SSB_SPROM */
299 304
@@ -490,8 +495,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
490#endif 495#endif
491 break; 496 break;
492 case SSB_BUSTYPE_SDIO: 497 case SSB_BUSTYPE_SDIO:
493#ifdef CONFIG_SSB_SDIO 498#ifdef CONFIG_SSB_SDIOHOST
494 sdev->irq = bus->host_sdio->dev.irq;
495 dev->parent = &bus->host_sdio->dev; 499 dev->parent = &bus->host_sdio->dev;
496#endif 500#endif
497 break; 501 break;
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 9e50896233aa..a8dbb06623c9 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -17,6 +17,7 @@
17 17
18#include <linux/ssb/ssb.h> 18#include <linux/ssb/ssb.h>
19#include <linux/ssb/ssb_regs.h> 19#include <linux/ssb/ssb_regs.h>
20#include <linux/slab.h>
20#include <linux/pci.h> 21#include <linux/pci.h>
21#include <linux/delay.h> 22#include <linux/delay.h>
22 23
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
index 26737a010c6d..6536a041d90d 100644
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -12,6 +12,7 @@
12 */ 12 */
13 13
14#include <linux/pci.h> 14#include <linux/pci.h>
15#include <linux/slab.h>
15#include <linux/ssb/ssb.h> 16#include <linux/ssb/ssb.h>
16 17
17 18
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index 100e7a5c5ea1..e72f4046a5e0 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -617,136 +617,140 @@ static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size)
617 } \ 617 } \
618 } while (0) 618 } while (0)
619 619
620int ssb_pcmcia_get_invariants(struct ssb_bus *bus, 620static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,
621 struct ssb_init_invariants *iv) 621 tuple_t *tuple,
622 void *priv)
622{ 623{
623 tuple_t tuple; 624 struct ssb_sprom *sprom = priv;
624 int res; 625
625 unsigned char buf[32]; 626 if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
627 return -EINVAL;
628 if (tuple->TupleDataLen != ETH_ALEN + 2)
629 return -EINVAL;
630 if (tuple->TupleData[1] != ETH_ALEN)
631 return -EINVAL;
632 memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN);
633 return 0;
634};
635
636static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
637 tuple_t *tuple,
638 void *priv)
639{
640 struct ssb_init_invariants *iv = priv;
626 struct ssb_sprom *sprom = &iv->sprom; 641 struct ssb_sprom *sprom = &iv->sprom;
627 struct ssb_boardinfo *bi = &iv->boardinfo; 642 struct ssb_boardinfo *bi = &iv->boardinfo;
628 const char *error_description; 643 const char *error_description;
629 644
645 GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1");
646 switch (tuple->TupleData[0]) {
647 case SSB_PCMCIA_CIS_ID:
648 GOTO_ERROR_ON((tuple->TupleDataLen != 5) &&
649 (tuple->TupleDataLen != 7),
650 "id tpl size");
651 bi->vendor = tuple->TupleData[1] |
652 ((u16)tuple->TupleData[2] << 8);
653 break;
654 case SSB_PCMCIA_CIS_BOARDREV:
655 GOTO_ERROR_ON(tuple->TupleDataLen != 2,
656 "boardrev tpl size");
657 sprom->board_rev = tuple->TupleData[1];
658 break;
659 case SSB_PCMCIA_CIS_PA:
660 GOTO_ERROR_ON((tuple->TupleDataLen != 9) &&
661 (tuple->TupleDataLen != 10),
662 "pa tpl size");
663 sprom->pa0b0 = tuple->TupleData[1] |
664 ((u16)tuple->TupleData[2] << 8);
665 sprom->pa0b1 = tuple->TupleData[3] |
666 ((u16)tuple->TupleData[4] << 8);
667 sprom->pa0b2 = tuple->TupleData[5] |
668 ((u16)tuple->TupleData[6] << 8);
669 sprom->itssi_a = tuple->TupleData[7];
670 sprom->itssi_bg = tuple->TupleData[7];
671 sprom->maxpwr_a = tuple->TupleData[8];
672 sprom->maxpwr_bg = tuple->TupleData[8];
673 break;
674 case SSB_PCMCIA_CIS_OEMNAME:
675 /* We ignore this. */
676 break;
677 case SSB_PCMCIA_CIS_CCODE:
678 GOTO_ERROR_ON(tuple->TupleDataLen != 2,
679 "ccode tpl size");
680 sprom->country_code = tuple->TupleData[1];
681 break;
682 case SSB_PCMCIA_CIS_ANTENNA:
683 GOTO_ERROR_ON(tuple->TupleDataLen != 2,
684 "ant tpl size");
685 sprom->ant_available_a = tuple->TupleData[1];
686 sprom->ant_available_bg = tuple->TupleData[1];
687 break;
688 case SSB_PCMCIA_CIS_ANTGAIN:
689 GOTO_ERROR_ON(tuple->TupleDataLen != 2,
690 "antg tpl size");
691 sprom->antenna_gain.ghz24.a0 = tuple->TupleData[1];
692 sprom->antenna_gain.ghz24.a1 = tuple->TupleData[1];
693 sprom->antenna_gain.ghz24.a2 = tuple->TupleData[1];
694 sprom->antenna_gain.ghz24.a3 = tuple->TupleData[1];
695 sprom->antenna_gain.ghz5.a0 = tuple->TupleData[1];
696 sprom->antenna_gain.ghz5.a1 = tuple->TupleData[1];
697 sprom->antenna_gain.ghz5.a2 = tuple->TupleData[1];
698 sprom->antenna_gain.ghz5.a3 = tuple->TupleData[1];
699 break;
700 case SSB_PCMCIA_CIS_BFLAGS:
701 GOTO_ERROR_ON((tuple->TupleDataLen != 3) &&
702 (tuple->TupleDataLen != 5),
703 "bfl tpl size");
704 sprom->boardflags_lo = tuple->TupleData[1] |
705 ((u16)tuple->TupleData[2] << 8);
706 break;
707 case SSB_PCMCIA_CIS_LEDS:
708 GOTO_ERROR_ON(tuple->TupleDataLen != 5,
709 "leds tpl size");
710 sprom->gpio0 = tuple->TupleData[1];
711 sprom->gpio1 = tuple->TupleData[2];
712 sprom->gpio2 = tuple->TupleData[3];
713 sprom->gpio3 = tuple->TupleData[4];
714 break;
715 }
716 return -ENOSPC; /* continue with next entry */
717
718error:
719 ssb_printk(KERN_ERR PFX
720 "PCMCIA: Failed to fetch device invariants: %s\n",
721 error_description);
722 return -ENODEV;
723}
724
725
726int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
727 struct ssb_init_invariants *iv)
728{
729 struct ssb_sprom *sprom = &iv->sprom;
730 int res;
731
630 memset(sprom, 0xFF, sizeof(*sprom)); 732 memset(sprom, 0xFF, sizeof(*sprom));
631 sprom->revision = 1; 733 sprom->revision = 1;
632 sprom->boardflags_lo = 0; 734 sprom->boardflags_lo = 0;
633 sprom->boardflags_hi = 0; 735 sprom->boardflags_hi = 0;
634 736
635 /* First fetch the MAC address. */ 737 /* First fetch the MAC address. */
636 memset(&tuple, 0, sizeof(tuple)); 738 res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,
637 tuple.DesiredTuple = CISTPL_FUNCE; 739 ssb_pcmcia_get_mac, sprom);
638 tuple.TupleData = buf; 740 if (res != 0) {
639 tuple.TupleDataMax = sizeof(buf); 741 ssb_printk(KERN_ERR PFX
640 res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple); 742 "PCMCIA: Failed to fetch MAC address\n");
641 GOTO_ERROR_ON(res != 0, "MAC first tpl"); 743 return -ENODEV;
642 res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
643 GOTO_ERROR_ON(res != 0, "MAC first tpl data");
644 while (1) {
645 GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1");
646 if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID)
647 break;
648 res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
649 GOTO_ERROR_ON(res != 0, "MAC next tpl");
650 res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
651 GOTO_ERROR_ON(res != 0, "MAC next tpl data");
652 } 744 }
653 GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size");
654 memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN);
655 745
656 /* Fetch the vendor specific tuples. */ 746 /* Fetch the vendor specific tuples. */
657 memset(&tuple, 0, sizeof(tuple)); 747 res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
658 tuple.DesiredTuple = SSB_PCMCIA_CIS; 748 ssb_pcmcia_do_get_invariants, sprom);
659 tuple.TupleData = buf; 749 if ((res == 0) || (res == -ENOSPC))
660 tuple.TupleDataMax = sizeof(buf); 750 return 0;
661 res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
662 GOTO_ERROR_ON(res != 0, "VEN first tpl");
663 res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
664 GOTO_ERROR_ON(res != 0, "VEN first tpl data");
665 while (1) {
666 GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1");
667 switch (tuple.TupleData[0]) {
668 case SSB_PCMCIA_CIS_ID:
669 GOTO_ERROR_ON((tuple.TupleDataLen != 5) &&
670 (tuple.TupleDataLen != 7),
671 "id tpl size");
672 bi->vendor = tuple.TupleData[1] |
673 ((u16)tuple.TupleData[2] << 8);
674 break;
675 case SSB_PCMCIA_CIS_BOARDREV:
676 GOTO_ERROR_ON(tuple.TupleDataLen != 2,
677 "boardrev tpl size");
678 sprom->board_rev = tuple.TupleData[1];
679 break;
680 case SSB_PCMCIA_CIS_PA:
681 GOTO_ERROR_ON((tuple.TupleDataLen != 9) &&
682 (tuple.TupleDataLen != 10),
683 "pa tpl size");
684 sprom->pa0b0 = tuple.TupleData[1] |
685 ((u16)tuple.TupleData[2] << 8);
686 sprom->pa0b1 = tuple.TupleData[3] |
687 ((u16)tuple.TupleData[4] << 8);
688 sprom->pa0b2 = tuple.TupleData[5] |
689 ((u16)tuple.TupleData[6] << 8);
690 sprom->itssi_a = tuple.TupleData[7];
691 sprom->itssi_bg = tuple.TupleData[7];
692 sprom->maxpwr_a = tuple.TupleData[8];
693 sprom->maxpwr_bg = tuple.TupleData[8];
694 break;
695 case SSB_PCMCIA_CIS_OEMNAME:
696 /* We ignore this. */
697 break;
698 case SSB_PCMCIA_CIS_CCODE:
699 GOTO_ERROR_ON(tuple.TupleDataLen != 2,
700 "ccode tpl size");
701 sprom->country_code = tuple.TupleData[1];
702 break;
703 case SSB_PCMCIA_CIS_ANTENNA:
704 GOTO_ERROR_ON(tuple.TupleDataLen != 2,
705 "ant tpl size");
706 sprom->ant_available_a = tuple.TupleData[1];
707 sprom->ant_available_bg = tuple.TupleData[1];
708 break;
709 case SSB_PCMCIA_CIS_ANTGAIN:
710 GOTO_ERROR_ON(tuple.TupleDataLen != 2,
711 "antg tpl size");
712 sprom->antenna_gain.ghz24.a0 = tuple.TupleData[1];
713 sprom->antenna_gain.ghz24.a1 = tuple.TupleData[1];
714 sprom->antenna_gain.ghz24.a2 = tuple.TupleData[1];
715 sprom->antenna_gain.ghz24.a3 = tuple.TupleData[1];
716 sprom->antenna_gain.ghz5.a0 = tuple.TupleData[1];
717 sprom->antenna_gain.ghz5.a1 = tuple.TupleData[1];
718 sprom->antenna_gain.ghz5.a2 = tuple.TupleData[1];
719 sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1];
720 break;
721 case SSB_PCMCIA_CIS_BFLAGS:
722 GOTO_ERROR_ON((tuple.TupleDataLen != 3) &&
723 (tuple.TupleDataLen != 5),
724 "bfl tpl size");
725 sprom->boardflags_lo = tuple.TupleData[1] |
726 ((u16)tuple.TupleData[2] << 8);
727 break;
728 case SSB_PCMCIA_CIS_LEDS:
729 GOTO_ERROR_ON(tuple.TupleDataLen != 5,
730 "leds tpl size");
731 sprom->gpio0 = tuple.TupleData[1];
732 sprom->gpio1 = tuple.TupleData[2];
733 sprom->gpio2 = tuple.TupleData[3];
734 sprom->gpio3 = tuple.TupleData[4];
735 break;
736 }
737 res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
738 if (res == -ENOSPC)
739 break;
740 GOTO_ERROR_ON(res != 0, "VEN next tpl");
741 res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
742 GOTO_ERROR_ON(res != 0, "VEN next tpl data");
743 }
744 751
745 return 0;
746error:
747 ssb_printk(KERN_ERR PFX 752 ssb_printk(KERN_ERR PFX
748 "PCMCIA: Failed to fetch device invariants: %s\n", 753 "PCMCIA: Failed to fetch device invariants\n");
749 error_description);
750 return -ENODEV; 754 return -ENODEV;
751} 755}
752 756
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index e8b89e8ac9bd..0d6c0280eb34 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -354,7 +354,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
354 dev->bus = bus; 354 dev->bus = bus;
355 dev->ops = bus->ops; 355 dev->ops = bus->ops;
356 356
357 ssb_dprintk(KERN_INFO PFX 357 printk(KERN_DEBUG PFX
358 "Core %d found: %s " 358 "Core %d found: %s "
359 "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n", 359 "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
360 i, ssb_core_name(dev->id.coreid), 360 i, ssb_core_name(dev->id.coreid),
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
index 8943015a3eef..f2f920fef10d 100644
--- a/drivers/ssb/sprom.c
+++ b/drivers/ssb/sprom.c
@@ -13,6 +13,9 @@
13 13
14#include "ssb_private.h" 14#include "ssb_private.h"
15 15
16#include <linux/ctype.h>
17#include <linux/slab.h>
18
16 19
17static const struct ssb_sprom *fallback_sprom; 20static const struct ssb_sprom *fallback_sprom;
18 21
@@ -33,17 +36,27 @@ static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
33static int hex2sprom(u16 *sprom, const char *dump, size_t len, 36static int hex2sprom(u16 *sprom, const char *dump, size_t len,
34 size_t sprom_size_words) 37 size_t sprom_size_words)
35{ 38{
36 char tmp[5] = { 0 }; 39 char c, tmp[5] = { 0 };
37 int cnt = 0; 40 int err, cnt = 0;
38 unsigned long parsed; 41 unsigned long parsed;
39 42
40 if (len < sprom_size_words * 2) 43 /* Strip whitespace at the end. */
44 while (len) {
45 c = dump[len - 1];
46 if (!isspace(c) && c != '\0')
47 break;
48 len--;
49 }
50 /* Length must match exactly. */
51 if (len != sprom_size_words * 4)
41 return -EINVAL; 52 return -EINVAL;
42 53
43 while (cnt < sprom_size_words) { 54 while (cnt < sprom_size_words) {
44 memcpy(tmp, dump, 4); 55 memcpy(tmp, dump, 4);
45 dump += 4; 56 dump += 4;
46 parsed = simple_strtoul(tmp, NULL, 16); 57 err = strict_strtoul(tmp, 16, &parsed);
58 if (err)
59 return err;
47 sprom[cnt++] = swab16((u16)parsed); 60 sprom[cnt++] = swab16((u16)parsed);
48 } 61 }
49 62
@@ -90,6 +103,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
90 u16 *sprom; 103 u16 *sprom;
91 int res = 0, err = -ENOMEM; 104 int res = 0, err = -ENOMEM;
92 size_t sprom_size_words = bus->sprom_size; 105 size_t sprom_size_words = bus->sprom_size;
106 struct ssb_freeze_context freeze;
93 107
94 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); 108 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
95 if (!sprom) 109 if (!sprom)
@@ -111,18 +125,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
111 err = -ERESTARTSYS; 125 err = -ERESTARTSYS;
112 if (mutex_lock_interruptible(&bus->sprom_mutex)) 126 if (mutex_lock_interruptible(&bus->sprom_mutex))
113 goto out_kfree; 127 goto out_kfree;
114 err = ssb_devices_freeze(bus); 128 err = ssb_devices_freeze(bus, &freeze);
115 if (err == -EOPNOTSUPP) {
116 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
117 "No suspend support. Is CONFIG_PM enabled?\n");
118 goto out_unlock;
119 }
120 if (err) { 129 if (err) {
121 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); 130 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
122 goto out_unlock; 131 goto out_unlock;
123 } 132 }
124 res = sprom_write(bus, sprom); 133 res = sprom_write(bus, sprom);
125 err = ssb_devices_thaw(bus); 134 err = ssb_devices_thaw(&freeze);
126 if (err) 135 if (err)
127 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); 136 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
128out_unlock: 137out_unlock:
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index 25433565dfda..0331139a726f 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -176,19 +176,27 @@ extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
176 176
177/* core.c */ 177/* core.c */
178extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); 178extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
179extern int ssb_devices_freeze(struct ssb_bus *bus);
180extern int ssb_devices_thaw(struct ssb_bus *bus);
181extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); 179extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
182int ssb_for_each_bus_call(unsigned long data, 180int ssb_for_each_bus_call(unsigned long data,
183 int (*func)(struct ssb_bus *bus, unsigned long data)); 181 int (*func)(struct ssb_bus *bus, unsigned long data));
184extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev); 182extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev);
185 183
184struct ssb_freeze_context {
185 /* Pointer to the bus */
186 struct ssb_bus *bus;
187 /* Boolean list to indicate whether a device is frozen on this bus. */
188 bool device_frozen[SSB_MAX_NR_CORES];
189};
190extern int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx);
191extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
192
193
186 194
187/* b43_pci_bridge.c */ 195/* b43_pci_bridge.c */
188#ifdef CONFIG_SSB_B43_PCI_BRIDGE 196#ifdef CONFIG_SSB_B43_PCI_BRIDGE
189extern int __init b43_pci_ssb_bridge_init(void); 197extern int __init b43_pci_ssb_bridge_init(void);
190extern void __exit b43_pci_ssb_bridge_exit(void); 198extern void __exit b43_pci_ssb_bridge_exit(void);
191#else /* CONFIG_SSB_B43_PCI_BRIDGR */ 199#else /* CONFIG_SSB_B43_PCI_BRIDGE */
192static inline int b43_pci_ssb_bridge_init(void) 200static inline int b43_pci_ssb_bridge_init(void)
193{ 201{
194 return 0; 202 return 0;
@@ -196,6 +204,6 @@ static inline int b43_pci_ssb_bridge_init(void)
196static inline void b43_pci_ssb_bridge_exit(void) 204static inline void b43_pci_ssb_bridge_exit(void)
197{ 205{
198} 206}
199#endif /* CONFIG_SSB_PCIHOST */ 207#endif /* CONFIG_SSB_B43_PCI_BRIDGE */
200 208
201#endif /* LINUX_SSB_PRIVATE_H_ */ 209#endif /* LINUX_SSB_PRIVATE_H_ */