aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy S. Nelson <wayland@wayland.id.au>2009-01-30 06:12:47 +1100
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-02-04 16:58:41 -0800
commit97c44836cdec1ea713a15d84098a1a908157e68f (patch)
treebc544c64ed8eeb3feb2f0b210ae7db04a40e1bae
parent3419c75e15f82c3ab09bd944fddbde72c9e4b3ea (diff)
PCI: return error on failure to read PCI ROMs
This patch makes the ROM reading code return an error to user space if the size of the ROM read is equal to 0. The patch also emits a warnings if the contents of the ROM are invalid, and documents the effects of the "enable" file on ROM reading. Signed-off-by: Timothy S. Nelson <wayland@wayland.id.au> Acked-by: Alex Villacis-Lasso <a_villacis@palosanto.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--Documentation/filesystems/sysfs-pci.txt13
-rw-r--r--arch/ia64/sn/kernel/io_acpi_init.c2
-rw-r--r--arch/ia64/sn/kernel/io_init.c2
-rw-r--r--drivers/pci/pci-sysfs.c4
-rw-r--r--drivers/pci/rom.c8
-rw-r--r--include/linux/pci.h2
6 files changed, 22 insertions, 9 deletions
diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index 68ef48839c0..9f8740ca3f3 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -9,6 +9,7 @@ that support it. For example, a given bus might look like this:
| |-- class
| |-- config
| |-- device
+ | |-- enable
| |-- irq
| |-- local_cpus
| |-- resource
@@ -32,6 +33,7 @@ files, each with their own function.
class PCI class (ascii, ro)
config PCI config space (binary, rw)
device PCI device (ascii, ro)
+ enable Whether the device is enabled (ascii, rw)
irq IRQ number (ascii, ro)
local_cpus nearby CPU mask (cpumask, ro)
resource PCI resource host addresses (ascii, ro)
@@ -57,10 +59,19 @@ used to do actual device programming from userspace. Note that some platforms
don't support mmapping of certain resources, so be sure to check the return
value from any attempted mmap.
+The 'enable' file provides a counter that indicates how many times the device
+has been enabled. If the 'enable' file currently returns '4', and a '1' is
+echoed into it, it will then return '5'. Echoing a '0' into it will decrease
+the count. Even when it returns to 0, though, some of the initialisation
+may not be reversed.
+
The 'rom' file is special in that it provides read-only access to the device's
ROM file, if available. It's disabled by default, however, so applications
should write the string "1" to the file to enable it before attempting a read
-call, and disable it following the access by writing "0" to the file.
+call, and disable it following the access by writing "0" to the file. Note
+that the device must be enabled for a rom read to return data succesfully.
+In the event a driver is not bound to the device, it can be enabled using the
+'enable' file, documented above.
Accessing legacy resources through sysfs
----------------------------------------
diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c
index c5a214026a7..d0223abbbbd 100644
--- a/arch/ia64/sn/kernel/io_acpi_init.c
+++ b/arch/ia64/sn/kernel/io_acpi_init.c
@@ -443,7 +443,7 @@ sn_acpi_slot_fixup(struct pci_dev *dev)
size = pci_resource_len(dev, PCI_ROM_RESOURCE);
addr = ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE],
size);
- image_size = pci_get_rom_size(addr, size);
+ image_size = pci_get_rom_size(dev, addr, size);
dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr;
dev->resource[PCI_ROM_RESOURCE].end =
(unsigned long) addr + image_size - 1;
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 4e1801bad83..e2eb2da60f9 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -269,7 +269,7 @@ sn_io_slot_fixup(struct pci_dev *dev)
rom = ioremap(pci_resource_start(dev, PCI_ROM_RESOURCE),
size + 1);
- image_size = pci_get_rom_size(rom, size + 1);
+ image_size = pci_get_rom_size(dev, rom, size + 1);
dev->resource[PCI_ROM_RESOURCE].end =
dev->resource[PCI_ROM_RESOURCE].start +
image_size - 1;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index db7ec14fa71..dfc4e0ddf24 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -768,8 +768,8 @@ pci_read_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
return -EINVAL;
rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */
- if (!rom)
- return 0;
+ if (!rom || !size)
+ return -EIO;
if (off >= size)
count = 0;
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 132a78159b6..29cbe47f219 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -63,7 +63,7 @@ void pci_disable_rom(struct pci_dev *pdev)
* The PCI window size could be much larger than the
* actual image size.
*/
-size_t pci_get_rom_size(void __iomem *rom, size_t size)
+size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
{
void __iomem *image;
int last_image;
@@ -72,8 +72,10 @@ size_t pci_get_rom_size(void __iomem *rom, size_t size)
do {
void __iomem *pds;
/* Standard PCI ROMs start out with these bytes 55 AA */
- if (readb(image) != 0x55)
+ if (readb(image) != 0x55) {
+ dev_err(&pdev->dev, "Invalid ROM contents\n");
break;
+ }
if (readb(image + 1) != 0xAA)
break;
/* get the PCI data structure and check its signature */
@@ -159,7 +161,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
* size is much larger than the actual size of the ROM.
* True size is important if the ROM is going to be copied.
*/
- *size = pci_get_rom_size(rom, *size);
+ *size = pci_get_rom_size(pdev, rom, *size);
return rom;
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 48890cf3f96..7bd624bfdcf 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -684,7 +684,7 @@ int pci_enable_rom(struct pci_dev *pdev);
void pci_disable_rom(struct pci_dev *pdev);
void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
-size_t pci_get_rom_size(void __iomem *rom, size_t size);
+size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
/* Power management related routines */
int pci_save_state(struct pci_dev *dev);