diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-12-09 01:14:38 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-12-09 01:14:38 -0500 |
commit | bcd6acd51f3d4d1ada201e9bc5c40a31d6d80c71 (patch) | |
tree | 2f6dffd2d3e4dd67355a224de7e7a960335a92fd /drivers/ssb | |
parent | 11c34c7deaeeebcee342cbc35e1bb2a6711b2431 (diff) | |
parent | 3ff6a468b45b5dfeb0e903e56f4eb27d34b2437c (diff) |
Merge commit 'origin/master' into next
Conflicts:
include/linux/kvm.h
Diffstat (limited to 'drivers/ssb')
-rw-r--r-- | drivers/ssb/driver_pcicore.c | 4 | ||||
-rw-r--r-- | drivers/ssb/main.c | 126 | ||||
-rw-r--r-- | drivers/ssb/pcmcia.c | 232 | ||||
-rw-r--r-- | drivers/ssb/scan.c | 2 | ||||
-rw-r--r-- | drivers/ssb/sprom.c | 30 | ||||
-rw-r--r-- | drivers/ssb/ssb_private.h | 12 |
6 files changed, 215 insertions, 191 deletions
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 538c570df337..f1dcd7969a5c 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c | |||
@@ -551,13 +551,13 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, | |||
551 | might_sleep_if(pdev->id.coreid != SSB_DEV_PCI); | 551 | might_sleep_if(pdev->id.coreid != SSB_DEV_PCI); |
552 | 552 | ||
553 | /* Enable interrupts for this device. */ | 553 | /* Enable interrupts for this device. */ |
554 | if (bus->host_pci && | 554 | 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; | 555 | u32 coremask; |
557 | 556 | ||
558 | /* Calculate the "coremask" for the device. */ | 557 | /* Calculate the "coremask" for the device. */ |
559 | coremask = (1 << dev->core_index); | 558 | coremask = (1 << dev->core_index); |
560 | 559 | ||
560 | SSB_WARN_ON(bus->bustype != SSB_BUSTYPE_PCI); | ||
561 | err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); | 561 | err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); |
562 | if (err) | 562 | if (err) |
563 | goto out; | 563 | goto out; |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 579b114be412..5681ebed9c65 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -140,6 +140,19 @@ static void ssb_device_put(struct ssb_device *dev) | |||
140 | put_device(dev->dev); | 140 | put_device(dev->dev); |
141 | } | 141 | } |
142 | 142 | ||
143 | static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv) | ||
144 | { | ||
145 | if (drv) | ||
146 | get_driver(&drv->drv); | ||
147 | return drv; | ||
148 | } | ||
149 | |||
150 | static inline void ssb_driver_put(struct ssb_driver *drv) | ||
151 | { | ||
152 | if (drv) | ||
153 | put_driver(&drv->drv); | ||
154 | } | ||
155 | |||
143 | static int ssb_device_resume(struct device *dev) | 156 | static int ssb_device_resume(struct device *dev) |
144 | { | 157 | { |
145 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | 158 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); |
@@ -210,90 +223,81 @@ int ssb_bus_suspend(struct ssb_bus *bus) | |||
210 | EXPORT_SYMBOL(ssb_bus_suspend); | 223 | EXPORT_SYMBOL(ssb_bus_suspend); |
211 | 224 | ||
212 | #ifdef CONFIG_SSB_SPROM | 225 | #ifdef CONFIG_SSB_SPROM |
213 | int ssb_devices_freeze(struct ssb_bus *bus) | 226 | /** ssb_devices_freeze - Freeze all devices on the bus. |
227 | * | ||
228 | * After freezing no device driver will be handling a device | ||
229 | * on this bus anymore. ssb_devices_thaw() must be called after | ||
230 | * a successful freeze to reactivate the devices. | ||
231 | * | ||
232 | * @bus: The bus. | ||
233 | * @ctx: Context structure. Pass this to ssb_devices_thaw(). | ||
234 | */ | ||
235 | int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx) | ||
214 | { | 236 | { |
215 | struct ssb_device *dev; | 237 | struct ssb_device *sdev; |
216 | struct ssb_driver *drv; | 238 | struct ssb_driver *sdrv; |
217 | int err = 0; | 239 | unsigned int i; |
218 | int i; | 240 | |
219 | pm_message_t state = PMSG_FREEZE; | 241 | memset(ctx, 0, sizeof(*ctx)); |
242 | ctx->bus = bus; | ||
243 | SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen)); | ||
220 | 244 | ||
221 | /* First check that we are capable to freeze all devices. */ | ||
222 | for (i = 0; i < bus->nr_devices; i++) { | 245 | for (i = 0; i < bus->nr_devices; i++) { |
223 | dev = &(bus->devices[i]); | 246 | sdev = ssb_device_get(&bus->devices[i]); |
224 | if (!dev->dev || | 247 | |
225 | !dev->dev->driver || | 248 | if (!sdev->dev || !sdev->dev->driver || |
226 | !device_is_registered(dev->dev)) | 249 | !device_is_registered(sdev->dev)) { |
227 | continue; | 250 | ssb_device_put(sdev); |
228 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
229 | if (!drv) | ||
230 | continue; | 251 | continue; |
231 | if (!drv->suspend) { | ||
232 | /* Nope, can't suspend this one. */ | ||
233 | return -EOPNOTSUPP; | ||
234 | } | 252 | } |
235 | } | 253 | sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver)); |
236 | /* Now suspend all devices */ | 254 | if (!sdrv || SSB_WARN_ON(!sdrv->remove)) { |
237 | for (i = 0; i < bus->nr_devices; i++) { | 255 | 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; | ||
243 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
244 | if (!drv) | ||
245 | continue; | 256 | 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 | } | 257 | } |
258 | sdrv->remove(sdev); | ||
259 | ctx->device_frozen[i] = 1; | ||
252 | } | 260 | } |
253 | 261 | ||
254 | return 0; | 262 | return 0; |
255 | err_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 | } | 263 | } |
270 | 264 | ||
271 | int ssb_devices_thaw(struct ssb_bus *bus) | 265 | /** ssb_devices_thaw - Unfreeze all devices on the bus. |
266 | * | ||
267 | * This will re-attach the device drivers and re-init the devices. | ||
268 | * | ||
269 | * @ctx: The context structure from ssb_devices_freeze() | ||
270 | */ | ||
271 | int ssb_devices_thaw(struct ssb_freeze_context *ctx) | ||
272 | { | 272 | { |
273 | struct ssb_device *dev; | 273 | struct ssb_bus *bus = ctx->bus; |
274 | struct ssb_driver *drv; | 274 | struct ssb_device *sdev; |
275 | int err; | 275 | struct ssb_driver *sdrv; |
276 | int i; | 276 | unsigned int i; |
277 | int err, result = 0; | ||
277 | 278 | ||
278 | for (i = 0; i < bus->nr_devices; i++) { | 279 | for (i = 0; i < bus->nr_devices; i++) { |
279 | dev = &(bus->devices[i]); | 280 | if (!ctx->device_frozen[i]) |
280 | if (!dev->dev || | ||
281 | !dev->dev->driver || | ||
282 | !device_is_registered(dev->dev)) | ||
283 | continue; | 281 | continue; |
284 | drv = drv_to_ssb_drv(dev->dev->driver); | 282 | sdev = &bus->devices[i]; |
285 | if (!drv) | 283 | |
284 | if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver)) | ||
286 | continue; | 285 | continue; |
287 | if (SSB_WARN_ON(!drv->resume)) | 286 | sdrv = drv_to_ssb_drv(sdev->dev->driver); |
287 | if (SSB_WARN_ON(!sdrv || !sdrv->probe)) | ||
288 | continue; | 288 | continue; |
289 | err = drv->resume(dev); | 289 | |
290 | err = sdrv->probe(sdev, &sdev->id); | ||
290 | if (err) { | 291 | if (err) { |
291 | ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", | 292 | ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", |
292 | dev_name(dev->dev)); | 293 | dev_name(sdev->dev)); |
294 | result = err; | ||
293 | } | 295 | } |
296 | ssb_driver_put(sdrv); | ||
297 | ssb_device_put(sdev); | ||
294 | } | 298 | } |
295 | 299 | ||
296 | return 0; | 300 | return result; |
297 | } | 301 | } |
298 | #endif /* CONFIG_SSB_SPROM */ | 302 | #endif /* CONFIG_SSB_SPROM */ |
299 | 303 | ||
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 | ||
620 | int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | 620 | static 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 | |||
636 | static 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 | |||
718 | error: | ||
719 | ssb_printk(KERN_ERR PFX | ||
720 | "PCMCIA: Failed to fetch device invariants: %s\n", | ||
721 | error_description); | ||
722 | return -ENODEV; | ||
723 | } | ||
724 | |||
725 | |||
726 | int 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; | ||
746 | error: | ||
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..d0e6762fec50 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c | |||
@@ -13,6 +13,8 @@ | |||
13 | 13 | ||
14 | #include "ssb_private.h" | 14 | #include "ssb_private.h" |
15 | 15 | ||
16 | #include <linux/ctype.h> | ||
17 | |||
16 | 18 | ||
17 | static const struct ssb_sprom *fallback_sprom; | 19 | static const struct ssb_sprom *fallback_sprom; |
18 | 20 | ||
@@ -33,17 +35,27 @@ static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, | |||
33 | static int hex2sprom(u16 *sprom, const char *dump, size_t len, | 35 | static int hex2sprom(u16 *sprom, const char *dump, size_t len, |
34 | size_t sprom_size_words) | 36 | size_t sprom_size_words) |
35 | { | 37 | { |
36 | char tmp[5] = { 0 }; | 38 | char c, tmp[5] = { 0 }; |
37 | int cnt = 0; | 39 | int err, cnt = 0; |
38 | unsigned long parsed; | 40 | unsigned long parsed; |
39 | 41 | ||
40 | if (len < sprom_size_words * 2) | 42 | /* Strip whitespace at the end. */ |
43 | while (len) { | ||
44 | c = dump[len - 1]; | ||
45 | if (!isspace(c) && c != '\0') | ||
46 | break; | ||
47 | len--; | ||
48 | } | ||
49 | /* Length must match exactly. */ | ||
50 | if (len != sprom_size_words * 4) | ||
41 | return -EINVAL; | 51 | return -EINVAL; |
42 | 52 | ||
43 | while (cnt < sprom_size_words) { | 53 | while (cnt < sprom_size_words) { |
44 | memcpy(tmp, dump, 4); | 54 | memcpy(tmp, dump, 4); |
45 | dump += 4; | 55 | dump += 4; |
46 | parsed = simple_strtoul(tmp, NULL, 16); | 56 | err = strict_strtoul(tmp, 16, &parsed); |
57 | if (err) | ||
58 | return err; | ||
47 | sprom[cnt++] = swab16((u16)parsed); | 59 | sprom[cnt++] = swab16((u16)parsed); |
48 | } | 60 | } |
49 | 61 | ||
@@ -90,6 +102,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, | |||
90 | u16 *sprom; | 102 | u16 *sprom; |
91 | int res = 0, err = -ENOMEM; | 103 | int res = 0, err = -ENOMEM; |
92 | size_t sprom_size_words = bus->sprom_size; | 104 | size_t sprom_size_words = bus->sprom_size; |
105 | struct ssb_freeze_context freeze; | ||
93 | 106 | ||
94 | sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); | 107 | sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); |
95 | if (!sprom) | 108 | if (!sprom) |
@@ -111,18 +124,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, | |||
111 | err = -ERESTARTSYS; | 124 | err = -ERESTARTSYS; |
112 | if (mutex_lock_interruptible(&bus->sprom_mutex)) | 125 | if (mutex_lock_interruptible(&bus->sprom_mutex)) |
113 | goto out_kfree; | 126 | goto out_kfree; |
114 | err = ssb_devices_freeze(bus); | 127 | 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) { | 128 | if (err) { |
121 | ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); | 129 | ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); |
122 | goto out_unlock; | 130 | goto out_unlock; |
123 | } | 131 | } |
124 | res = sprom_write(bus, sprom); | 132 | res = sprom_write(bus, sprom); |
125 | err = ssb_devices_thaw(bus); | 133 | err = ssb_devices_thaw(&freeze); |
126 | if (err) | 134 | if (err) |
127 | ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); | 135 | ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); |
128 | out_unlock: | 136 | out_unlock: |
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 25433565dfda..56054be4d113 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h | |||
@@ -176,13 +176,21 @@ extern const struct ssb_sprom *ssb_get_fallback_sprom(void); | |||
176 | 176 | ||
177 | /* core.c */ | 177 | /* core.c */ |
178 | extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); | 178 | extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); |
179 | extern int ssb_devices_freeze(struct ssb_bus *bus); | ||
180 | extern int ssb_devices_thaw(struct ssb_bus *bus); | ||
181 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); | 179 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); |
182 | int ssb_for_each_bus_call(unsigned long data, | 180 | int 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)); |
184 | extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev); | 182 | extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev); |
185 | 183 | ||
184 | struct 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 | }; | ||
190 | extern int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx); | ||
191 | extern 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 |