aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-12-09 01:14:38 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-12-09 01:14:38 -0500
commitbcd6acd51f3d4d1ada201e9bc5c40a31d6d80c71 (patch)
tree2f6dffd2d3e4dd67355a224de7e7a960335a92fd /drivers/ssb
parent11c34c7deaeeebcee342cbc35e1bb2a6711b2431 (diff)
parent3ff6a468b45b5dfeb0e903e56f4eb27d34b2437c (diff)
Merge commit 'origin/master' into next
Conflicts: include/linux/kvm.h
Diffstat (limited to 'drivers/ssb')
-rw-r--r--drivers/ssb/driver_pcicore.c4
-rw-r--r--drivers/ssb/main.c126
-rw-r--r--drivers/ssb/pcmcia.c232
-rw-r--r--drivers/ssb/scan.c2
-rw-r--r--drivers/ssb/sprom.c30
-rw-r--r--drivers/ssb/ssb_private.h12
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
143static 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
150static inline void ssb_driver_put(struct ssb_driver *drv)
151{
152 if (drv)
153 put_driver(&drv->drv);
154}
155
143static int ssb_device_resume(struct device *dev) 156static 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)
210EXPORT_SYMBOL(ssb_bus_suspend); 223EXPORT_SYMBOL(ssb_bus_suspend);
211 224
212#ifdef CONFIG_SSB_SPROM 225#ifdef CONFIG_SSB_SPROM
213int 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 */
235int 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;
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} 263}
270 264
271int 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 */
271int 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
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..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
17static const struct ssb_sprom *fallback_sprom; 19static const struct ssb_sprom *fallback_sprom;
18 20
@@ -33,17 +35,27 @@ static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
33static int hex2sprom(u16 *sprom, const char *dump, size_t len, 35static 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");
128out_unlock: 136out_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 */
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