Altix: Initial ACPI support - ROM shadowing.
authorJohn Keller <jpk@sgi.com>
Wed, 4 Oct 2006 21:49:52 +0000 (16:49 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 1 Dec 2006 22:36:58 +0000 (14:36 -0800)
Support a shadowed ROM when running with an ACPI capable PROM.

Define a new dev.resource flag IORESOURCE_ROM_BIOS_COPY to
describe the case of a BIOS shadowed ROM, which can then
be used to avoid pci_map_rom() making an unneeded call to
pci_enable_rom().

Signed-off-by: John Keller <jpk@sgi.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
arch/ia64/sn/kernel/io_acpi_init.c
arch/ia64/sn/kernel/io_common.c
arch/ia64/sn/kernel/io_init.c
drivers/pci/rom.c
include/linux/ioport.h

index a9dc369..99d7f27 100644 (file)
@@ -169,6 +169,39 @@ sn_acpi_bus_fixup(struct pci_bus *bus)
        }
 }
 
+/*
+ * sn_acpi_slot_fixup - Perform any SN specific slot fixup.
+ *                     At present there does not appear to be
+ *                     any generic way to handle a ROM image
+ *                     that has been shadowed by the PROM, so
+ *                     we pass a pointer to it within the
+ *                     pcidev_info structure.
+ */
+
+void
+sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
+{
+       void __iomem *addr;
+       size_t size;
+
+       if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
+               /*
+                * A valid ROM image exists and has been shadowed by the
+                * PROM. Setup the pci_dev ROM resource to point to
+                * the shadowed copy.
+                */
+               size = dev->resource[PCI_ROM_RESOURCE].end -
+                               dev->resource[PCI_ROM_RESOURCE].start;
+               addr =
+                    ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE],
+                            size);
+               dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr;
+               dev->resource[PCI_ROM_RESOURCE].end =
+                                               (unsigned long) addr + size;
+               dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY;
+       }
+}
+
 static struct acpi_driver acpi_sn_hubdev_driver = {
        .name = "SGI HUBDEV Driver",
        .ids = "SGIHUB,SGITIO",
index 12531de..d4dd8f4 100644 (file)
@@ -286,9 +286,10 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
        list_add_tail(&pcidev_info->pdi_list,
                      &(SN_PLATFORM_DATA(dev->bus)->pcidev_info));
 
-       if (!SN_ACPI_BASE_SUPPORT())
+       if (SN_ACPI_BASE_SUPPORT())
+               sn_acpi_slot_fixup(dev, pcidev_info);
+       else
                sn_more_slot_fixup(dev, pcidev_info);
-
        /*
         * Using the PROMs values for the PCI host bus, get the Linux
         * PCI host_pci_dev struct and set up host bus linkages
index 990224a..9ad843e 100644 (file)
@@ -210,6 +210,9 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
                        dev->resource[idx].parent = &ioport_resource;
                else
                        dev->resource[idx].parent = &iomem_resource;
+               /* If ROM, mark as shadowed in PROM */
+               if (idx == PCI_ROM_RESOURCE)
+                       dev->resource[idx].flags |= IORESOURCE_ROM_BIOS_COPY;
        }
        /* Create a pci_window in the pci_controller struct for
         * each device resource.
index e1dcefc..d087e08 100644 (file)
@@ -81,7 +81,8 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
                start = (loff_t)0xC0000;
                *size = 0x20000; /* cover C000:0 through E000:0 */
        } else {
-               if (res->flags & IORESOURCE_ROM_COPY) {
+               if (res->flags &
+                       (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) {
                        *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
                        return (void __iomem *)(unsigned long)
                                pci_resource_start(pdev, PCI_ROM_RESOURCE);
@@ -165,7 +166,8 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
        if (!rom)
                return NULL;
 
-       if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW))
+       if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW |
+                         IORESOURCE_ROM_BIOS_COPY))
                return rom;
 
        res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
@@ -191,7 +193,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
 {
        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 
-       if (res->flags & IORESOURCE_ROM_COPY)
+       if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
                return;
 
        iounmap(rom);
@@ -215,6 +217,7 @@ void pci_remove_rom(struct pci_dev *pdev)
                sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
        if (!(res->flags & (IORESOURCE_ROM_ENABLE |
                            IORESOURCE_ROM_SHADOW |
+                           IORESOURCE_ROM_BIOS_COPY |
                            IORESOURCE_ROM_COPY)))
                pci_disable_rom(pdev);
 }
index d42c833..cf8696d 100644 (file)
@@ -89,6 +89,7 @@ struct resource_list {
 #define IORESOURCE_ROM_ENABLE          (1<<0)  /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
 #define IORESOURCE_ROM_SHADOW          (1<<1)  /* ROM is copy at C000:0 */
 #define IORESOURCE_ROM_COPY            (1<<2)  /* ROM is alloc'd copy, resource field overlaid */
+#define IORESOURCE_ROM_BIOS_COPY       (1<<3)  /* ROM is BIOS copy, resource field overlaid */
 
 /* PC/ISA/whatever - the normal PC address spaces: IO and memory */
 extern struct resource ioport_resource;