aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-sysfs.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2008-03-05 11:52:39 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-21 00:47:07 -0400
commit94e6108803469a37ee1e3c92dafdd1d59298602f (patch)
tree7f3ee30721411cca238f8eea5971d5bebbb70a55 /drivers/pci/pci-sysfs.c
parent5e0d2a6fc094a9b5047998deefeb1254c66856ee (diff)
PCI: Expose PCI VPD through sysfs
Vital Product Data (VPD) may be exposed by PCI devices in several ways. It is generally unsafe to read this information through the existing interfaces to user-land because of stateful interfaces. This adds: - abstract operations for VPD access (struct pci_vpd_ops) - VPD state information in struct pci_dev (struct pci_vpd) - an implementation of the VPD access method specified in PCI 2.2 (in access.c) - a 'vpd' binary file in sysfs directories for PCI devices with VPD operations defined It adds a probe for PCI 2.2 VPD in pci_scan_device() and release of VPD state in pci_release_dev(). Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r--drivers/pci/pci-sysfs.c109
1 files changed, 95 insertions, 14 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index f5b0b622c189..ae9a7695be97 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -343,6 +343,58 @@ pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
343 return count; 343 return count;
344} 344}
345 345
346static ssize_t
347pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
348 char *buf, loff_t off, size_t count)
349{
350 struct pci_dev *dev =
351 to_pci_dev(container_of(kobj, struct device, kobj));
352 int end;
353 int ret;
354
355 if (off > bin_attr->size)
356 count = 0;
357 else if (count > bin_attr->size - off)
358 count = bin_attr->size - off;
359 end = off + count;
360
361 while (off < end) {
362 ret = dev->vpd->ops->read(dev, off, end - off, buf);
363 if (ret < 0)
364 return ret;
365 buf += ret;
366 off += ret;
367 }
368
369 return count;
370}
371
372static ssize_t
373pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
374 char *buf, loff_t off, size_t count)
375{
376 struct pci_dev *dev =
377 to_pci_dev(container_of(kobj, struct device, kobj));
378 int end;
379 int ret;
380
381 if (off > bin_attr->size)
382 count = 0;
383 else if (count > bin_attr->size - off)
384 count = bin_attr->size - off;
385 end = off + count;
386
387 while (off < end) {
388 ret = dev->vpd->ops->write(dev, off, end - off, buf);
389 if (ret < 0)
390 return ret;
391 buf += ret;
392 off += ret;
393 }
394
395 return count;
396}
397
346#ifdef HAVE_PCI_LEGACY 398#ifdef HAVE_PCI_LEGACY
347/** 399/**
348 * pci_read_legacy_io - read byte(s) from legacy I/O port space 400 * pci_read_legacy_io - read byte(s) from legacy I/O port space
@@ -611,7 +663,7 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
611 663
612int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) 664int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
613{ 665{
614 struct bin_attribute *rom_attr = NULL; 666 struct bin_attribute *attr = NULL;
615 int retval; 667 int retval;
616 668
617 if (!sysfs_initialized) 669 if (!sysfs_initialized)
@@ -624,22 +676,41 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
624 if (retval) 676 if (retval)
625 goto err; 677 goto err;
626 678
679 /* If the device has VPD, try to expose it in sysfs. */
680 if (pdev->vpd) {
681 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
682 if (attr) {
683 pdev->vpd->attr = attr;
684 attr->size = pdev->vpd->ops->get_size(pdev);
685 attr->attr.name = "vpd";
686 attr->attr.mode = S_IRUGO | S_IWUSR;
687 attr->read = pci_read_vpd;
688 attr->write = pci_write_vpd;
689 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
690 if (retval)
691 goto err_vpd;
692 } else {
693 retval = -ENOMEM;
694 goto err_config_file;
695 }
696 }
697
627 retval = pci_create_resource_files(pdev); 698 retval = pci_create_resource_files(pdev);
628 if (retval) 699 if (retval)
629 goto err_bin_file; 700 goto err_vpd_file;
630 701
631 /* If the device has a ROM, try to expose it in sysfs. */ 702 /* If the device has a ROM, try to expose it in sysfs. */
632 if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || 703 if (pci_resource_len(pdev, PCI_ROM_RESOURCE) ||
633 (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) { 704 (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) {
634 rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); 705 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
635 if (rom_attr) { 706 if (attr) {
636 pdev->rom_attr = rom_attr; 707 pdev->rom_attr = attr;
637 rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE); 708 attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
638 rom_attr->attr.name = "rom"; 709 attr->attr.name = "rom";
639 rom_attr->attr.mode = S_IRUSR; 710 attr->attr.mode = S_IRUSR;
640 rom_attr->read = pci_read_rom; 711 attr->read = pci_read_rom;
641 rom_attr->write = pci_write_rom; 712 attr->write = pci_write_rom;
642 retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); 713 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
643 if (retval) 714 if (retval)
644 goto err_rom; 715 goto err_rom;
645 } else { 716 } else {
@@ -657,12 +728,18 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
657 728
658err_rom_file: 729err_rom_file:
659 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) 730 if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
660 sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr); 731 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
661err_rom: 732err_rom:
662 kfree(rom_attr); 733 kfree(pdev->rom_attr);
663err_resource_files: 734err_resource_files:
664 pci_remove_resource_files(pdev); 735 pci_remove_resource_files(pdev);
665err_bin_file: 736err_vpd_file:
737 if (pdev->vpd) {
738 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
739err_vpd:
740 kfree(pdev->vpd->attr);
741 }
742err_config_file:
666 if (pdev->cfg_size < 4096) 743 if (pdev->cfg_size < 4096)
667 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); 744 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
668 else 745 else
@@ -684,6 +761,10 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
684 761
685 pcie_aspm_remove_sysfs_dev_files(pdev); 762 pcie_aspm_remove_sysfs_dev_files(pdev);
686 763
764 if (pdev->vpd) {
765 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
766 kfree(pdev->vpd->attr);
767 }
687 if (pdev->cfg_size < 4096) 768 if (pdev->cfg_size < 4096)
688 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); 769 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
689 else 770 else