diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 109 |
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 | ||
346 | static ssize_t | ||
347 | pci_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 | |||
372 | static ssize_t | ||
373 | pci_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 | ||
612 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | 664 | int __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 | ||
658 | err_rom_file: | 729 | err_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); |
661 | err_rom: | 732 | err_rom: |
662 | kfree(rom_attr); | 733 | kfree(pdev->rom_attr); |
663 | err_resource_files: | 734 | err_resource_files: |
664 | pci_remove_resource_files(pdev); | 735 | pci_remove_resource_files(pdev); |
665 | err_bin_file: | 736 | err_vpd_file: |
737 | if (pdev->vpd) { | ||
738 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr); | ||
739 | err_vpd: | ||
740 | kfree(pdev->vpd->attr); | ||
741 | } | ||
742 | err_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 |