aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb/pci.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2008-03-10 12:26:32 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-03-13 19:32:32 -0400
commite7ec2e3230633a858af1b0b359f6c4670dbeb997 (patch)
treec43dbd7f6cab0ac066c039697528312d802617ef /drivers/ssb/pci.c
parent068edceb7e73c05f77e204442ea8f86e238575da (diff)
ssb: Add SPROM/invariants support for PCMCIA devices
This adds support for reading/writing the SPROM invariants for PCMCIA based devices. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb/pci.c')
-rw-r--r--drivers/ssb/pci.c113
1 files changed, 10 insertions, 103 deletions
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 1facc7620fc8..f1514b33cfae 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -227,7 +227,7 @@ static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
227 return crc; 227 return crc;
228} 228}
229 229
230static int sprom_check_crc(const u16 *sprom, u16 size) 230static int sprom_check_crc(const u16 *sprom, size_t size)
231{ 231{
232 u8 crc; 232 u8 crc;
233 u8 expected_crc; 233 u8 expected_crc;
@@ -242,12 +242,14 @@ static int sprom_check_crc(const u16 *sprom, u16 size)
242 return 0; 242 return 0;
243} 243}
244 244
245static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) 245static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
246{ 246{
247 int i; 247 int i;
248 248
249 for (i = 0; i < bus->sprom_size; i++) 249 for (i = 0; i < bus->sprom_size; i++)
250 sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2)); 250 sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
251
252 return 0;
251} 253}
252 254
253static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) 255static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
@@ -660,71 +662,18 @@ const struct ssb_bus_ops ssb_pci_ops = {
660 .write32 = ssb_pci_write32, 662 .write32 = ssb_pci_write32,
661}; 663};
662 664
663static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
664{
665 int i, pos = 0;
666
667 for (i = 0; i < size; i++)
668 pos += snprintf(buf + pos, buf_len - pos - 1,
669 "%04X", swab16(sprom[i]) & 0xFFFF);
670 pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
671
672 return pos + 1;
673}
674
675static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
676{
677 char tmp[5] = { 0 };
678 int cnt = 0;
679 unsigned long parsed;
680
681 if (len < size * 2)
682 return -EINVAL;
683
684 while (cnt < size) {
685 memcpy(tmp, dump, 4);
686 dump += 4;
687 parsed = simple_strtoul(tmp, NULL, 16);
688 sprom[cnt++] = swab16((u16)parsed);
689 }
690
691 return 0;
692}
693
694static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, 665static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
695 struct device_attribute *attr, 666 struct device_attribute *attr,
696 char *buf) 667 char *buf)
697{ 668{
698 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 669 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
699 struct ssb_bus *bus; 670 struct ssb_bus *bus;
700 u16 *sprom;
701 int err = -ENODEV;
702 ssize_t count = 0;
703 671
704 bus = ssb_pci_dev_to_bus(pdev); 672 bus = ssb_pci_dev_to_bus(pdev);
705 if (!bus) 673 if (!bus)
706 goto out; 674 return -ENODEV;
707 err = -ENOMEM;
708 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
709 if (!sprom)
710 goto out;
711 675
712 /* Use interruptible locking, as the SPROM write might 676 return ssb_attr_sprom_show(bus, buf, sprom_do_read);
713 * be holding the lock for several seconds. So allow userspace
714 * to cancel operation. */
715 err = -ERESTARTSYS;
716 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
717 goto out_kfree;
718 sprom_do_read(bus, sprom);
719 mutex_unlock(&bus->pci_sprom_mutex);
720
721 count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
722 err = 0;
723
724out_kfree:
725 kfree(sprom);
726out:
727 return err ? err : count;
728} 677}
729 678
730static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, 679static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
@@ -733,55 +682,13 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
733{ 682{
734 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); 683 struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
735 struct ssb_bus *bus; 684 struct ssb_bus *bus;
736 u16 *sprom;
737 int res = 0, err = -ENODEV;
738 685
739 bus = ssb_pci_dev_to_bus(pdev); 686 bus = ssb_pci_dev_to_bus(pdev);
740 if (!bus) 687 if (!bus)
741 goto out; 688 return -ENODEV;
742 err = -ENOMEM;
743 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
744 if (!sprom)
745 goto out;
746 err = hex2sprom(sprom, buf, count, bus->sprom_size);
747 if (err) {
748 err = -EINVAL;
749 goto out_kfree;
750 }
751 err = sprom_check_crc(sprom, bus->sprom_size);
752 if (err) {
753 err = -EINVAL;
754 goto out_kfree;
755 }
756 689
757 /* Use interruptible locking, as the SPROM write might 690 return ssb_attr_sprom_store(bus, buf, count,
758 * be holding the lock for several seconds. So allow userspace 691 sprom_check_crc, sprom_do_write);
759 * to cancel operation. */
760 err = -ERESTARTSYS;
761 if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
762 goto out_kfree;
763 err = ssb_devices_freeze(bus);
764 if (err == -EOPNOTSUPP) {
765 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
766 "No suspend support. Is CONFIG_PM enabled?\n");
767 goto out_unlock;
768 }
769 if (err) {
770 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
771 goto out_unlock;
772 }
773 res = sprom_do_write(bus, sprom);
774 err = ssb_devices_thaw(bus);
775 if (err)
776 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
777out_unlock:
778 mutex_unlock(&bus->pci_sprom_mutex);
779out_kfree:
780 kfree(sprom);
781out:
782 if (res)
783 return res;
784 return err ? err : count;
785} 692}
786 693
787static DEVICE_ATTR(ssb_sprom, 0600, 694static DEVICE_ATTR(ssb_sprom, 0600,
@@ -808,7 +715,7 @@ int ssb_pci_init(struct ssb_bus *bus)
808 return 0; 715 return 0;
809 716
810 pdev = bus->host_pci; 717 pdev = bus->host_pci;
811 mutex_init(&bus->pci_sprom_mutex); 718 mutex_init(&bus->sprom_mutex);
812 err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); 719 err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
813 if (err) 720 if (err)
814 goto out; 721 goto out;