From 8ea6091f500162e97687d7acf925f84202066b8d Mon Sep 17 00:00:00 2001 From: John Keller Date: Wed, 4 Oct 2006 16:49:25 -0500 Subject: Altix: Add initial ACPI IO support First phase in introducing ACPI support to SN. In this phase, when running with an ACPI capable PROM, the DSDT will define the root busses and all SN nodes (SGIHUB, SGITIO). An ACPI bus driver will be registered for the node devices, with the acpi_pci_root_driver being used for the root busses. An ACPI vendor descriptor is now used to pass platform specific information for both nodes and busses, eliminating the need for the current SAL calls. Also, with ACPI support, SN fixup code is no longer needed to initiate the PCI bus scans, as the acpi_pci_root_driver does that. However, to maintain backward compatibility with non-ACPI capable PROMs, none of the current 'fixup' code can been deleted, though much restructuring has been done. For example, the bulk of the code in io_common.c is relocated code that is now common regardless of what PROM is running, while io_acpi_init.c and io_init.c contain routines specific to an ACPI or non ACPI capable PROM respectively. A new pci bus fixup platform vector has been created to provide a hook for invoking platform specific bus fixup from pcibios_fixup_bus(). The size of io_space[] has been increased to support systems with large IO configurations. Signed-off-by: John Keller Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/io_acpi_init.c | 198 +++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 arch/ia64/sn/kernel/io_acpi_init.c (limited to 'arch/ia64/sn/kernel/io_acpi_init.c') diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c new file mode 100644 index 00000000000..a9dc36901b1 --- /dev/null +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -0,0 +1,198 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "xtalk/hubdev.h" +#include + + +/* + * The code in this file will only be executed when running with + * a PROM that has ACPI IO support. (i.e., SN_ACPI_BASE_SUPPORT() == 1) + */ + + +/* + * This value must match the UUID the PROM uses + * (io/acpi/defblk.c) when building a vendor descriptor. + */ +struct acpi_vendor_uuid sn_uuid = { + .subtype = 0, + .data = { 0x2c, 0xc6, 0xa6, 0xfe, 0x9c, 0x44, 0xda, 0x11, + 0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 }, +}; + +/* + * Perform the early IO init in PROM. + */ +static s64 +sal_ioif_init(u64 *result) +{ + struct ia64_sal_retval isrv = {0,0,0,0}; + + SAL_CALL_NOLOCK(isrv, + SN_SAL_IOIF_INIT, 0, 0, 0, 0, 0, 0, 0); + *result = isrv.v0; + return isrv.status; +} + +/* + * sn_hubdev_add - The 'add' function of the acpi_sn_hubdev_driver. + * Called for every "SGIHUB" or "SGITIO" device defined + * in the ACPI namespace. + */ +static int __init +sn_hubdev_add(struct acpi_device *device) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + u64 addr; + struct hubdev_info *hubdev; + struct hubdev_info *hubdev_ptr; + int i; + u64 nasid; + struct acpi_resource *resource; + int ret = 0; + acpi_status status; + struct acpi_resource_vendor_typed *vendor; + extern void sn_common_hubdev_init(struct hubdev_info *); + + status = acpi_get_vendor_resource(device->handle, METHOD_NAME__CRS, + &sn_uuid, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR + "sn_hubdev_add: acpi_get_vendor_resource() failed: %d\n", + status); + return 1; + } + + resource = buffer.pointer; + vendor = &resource->data.vendor_typed; + if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != + sizeof(struct hubdev_info *)) { + printk(KERN_ERR + "sn_hubdev_add: Invalid vendor data length: %d\n", + vendor->byte_length); + ret = 1; + goto exit; + } + + memcpy(&addr, vendor->byte_data, sizeof(struct hubdev_info *)); + hubdev_ptr = __va((struct hubdev_info *) addr); + + nasid = hubdev_ptr->hdi_nasid; + i = nasid_to_cnodeid(nasid); + hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); + *hubdev = *hubdev_ptr; + sn_common_hubdev_init(hubdev); + +exit: + kfree(buffer.pointer); + return ret; +} + +/* + * sn_get_bussoft_ptr() - The pcibus_bussoft pointer is found in + * the ACPI Vendor resource for this bus. + */ +static struct pcibus_bussoft * +sn_get_bussoft_ptr(struct pci_bus *bus) +{ + u64 addr; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_handle handle; + struct pcibus_bussoft *prom_bussoft_ptr; + struct acpi_resource *resource; + acpi_status status; + struct acpi_resource_vendor_typed *vendor; + + + handle = PCI_CONTROLLER(bus)->acpi_handle; + status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, + &sn_uuid, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "get_acpi_pcibus_ptr: " + "get_acpi_bussoft_info() failed: %d\n", + status); + return NULL; + } + resource = buffer.pointer; + vendor = &resource->data.vendor_typed; + + if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != + sizeof(struct pcibus_bussoft *)) { + printk(KERN_ERR + "get_acpi_bussoft_ptr: Invalid vendor data " + "length %d\n", vendor->byte_length); + kfree(buffer.pointer); + return NULL; + } + memcpy(&addr, vendor->byte_data, sizeof(struct pcibus_bussoft *)); + prom_bussoft_ptr = __va((struct pcibus_bussoft *) addr); + kfree(buffer.pointer); + + return prom_bussoft_ptr; +} + +/* + * sn_acpi_bus_fixup + */ +void +sn_acpi_bus_fixup(struct pci_bus *bus) +{ + struct pci_dev *pci_dev = NULL; + struct pcibus_bussoft *prom_bussoft_ptr; + extern void sn_common_bus_fixup(struct pci_bus *, + struct pcibus_bussoft *); + + if (!bus->parent) { /* If root bus */ + prom_bussoft_ptr = sn_get_bussoft_ptr(bus); + if (prom_bussoft_ptr == NULL) { + printk(KERN_ERR + "sn_pci_fixup_bus: 0x%04x:0x%02x Unable to " + "obtain prom_bussoft_ptr\n", + pci_domain_nr(bus), bus->number); + return; + } + sn_common_bus_fixup(bus, prom_bussoft_ptr); + } + list_for_each_entry(pci_dev, &bus->devices, bus_list) { + sn_pci_fixup_slot(pci_dev); + } +} + +static struct acpi_driver acpi_sn_hubdev_driver = { + .name = "SGI HUBDEV Driver", + .ids = "SGIHUB,SGITIO", + .ops = { + .add = sn_hubdev_add, + }, +}; + + +/* + * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the + * nodes and root buses in the DSDT. As a result, bus scanning + * will be initiated by the Linux ACPI code. + */ + +void __init +sn_io_acpi_init(void) +{ + u64 result; + s64 status; + + acpi_bus_register_driver(&acpi_sn_hubdev_driver); + status = sal_ioif_init(&result); + if (status || result) + panic("sal_ioif_init failed: [%lx] %s\n", + status, ia64_sal_strerror(status)); +} -- cgit v1.2.3-70-g09d2 From a2302c68d923537436b1114aa207787c1a31bd50 Mon Sep 17 00:00:00 2001 From: John Keller Date: Wed, 4 Oct 2006 16:49:52 -0500 Subject: Altix: Initial ACPI support - ROM shadowing. 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 Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/io_acpi_init.c | 33 +++++++++++++++++++++++++++++++++ arch/ia64/sn/kernel/io_common.c | 5 +++-- arch/ia64/sn/kernel/io_init.c | 3 +++ drivers/pci/rom.c | 9 ++++++--- include/linux/ioport.h | 1 + 5 files changed, 46 insertions(+), 5 deletions(-) (limited to 'arch/ia64/sn/kernel/io_acpi_init.c') diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index a9dc36901b1..99d7f278612 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -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", diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c index 12531de6754..d4dd8f4b6b8 100644 --- a/arch/ia64/sn/kernel/io_common.c +++ b/arch/ia64/sn/kernel/io_common.c @@ -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 diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 990224a4412..9ad843e0383 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -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. diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index e1dcefc69bb..d087e081771 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -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); } diff --git a/include/linux/ioport.h b/include/linux/ioport.h index d42c8339907..cf8696d4a13 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -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; -- cgit v1.2.3-70-g09d2 From 3948ec9406f9a60a43d63f23f6f5284db6529b9c Mon Sep 17 00:00:00 2001 From: John Keller Date: Fri, 22 Dec 2006 11:50:04 -0600 Subject: ACPI: Altix: ACPI _PRT support Provide ACPI _PRT support for SN Altix systems. The SN Altix platform does not conform to the IOSAPIC IRQ routing model, so a new acpi_irq_model (ACPI_IRQ_MODEL_PLATFORM) has been defined. The SN platform specific code sets acpi_irq_model to this new value, and keys off of it in acpi_register_gsi() to avoid the iosapic code path. Signed-off-by: John Keller Signed-off-by: Len Brown --- arch/ia64/kernel/acpi.c | 3 +++ arch/ia64/sn/kernel/io_acpi_init.c | 3 +++ drivers/acpi/bus.c | 3 +++ include/linux/acpi.h | 1 + 4 files changed, 10 insertions(+) (limited to 'arch/ia64/sn/kernel/io_acpi_init.c') diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 73ef4a85b86..ef2fe474f10 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -590,6 +590,9 @@ void __init acpi_numa_arch_fixup(void) */ int acpi_register_gsi(u32 gsi, int triggering, int polarity) { + if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM) + return gsi; + if (has_8259 && gsi < 16) return isa_irq_to_vector(gsi); diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index 99d7f278612..cb96b4ea7df 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -223,6 +223,9 @@ sn_io_acpi_init(void) u64 result; s64 status; + /* SN Altix does not follow the IOSAPIC IRQ routing model */ + acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM; + acpi_bus_register_driver(&acpi_sn_hubdev_driver); status = sal_ioif_init(&result); if (status || result) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 279c4bac92e..766332e4559 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -561,6 +561,9 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_IOSAPIC: message = "IOSAPIC"; break; + case ACPI_IRQ_MODEL_PLATFORM: + message = "platform specific model"; + break; default: printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n"); return -ENODEV; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 2b0c955590f..91f1f236387 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -47,6 +47,7 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_PIC = 0, ACPI_IRQ_MODEL_IOAPIC, ACPI_IRQ_MODEL_IOSAPIC, + ACPI_IRQ_MODEL_PLATFORM, ACPI_IRQ_MODEL_COUNT }; -- cgit v1.2.3-70-g09d2