lkml.org 
[lkml]   [2005]   [Jun]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[patch 2/2] i386/x86_64: collect host bridge resources v2
This patch reads and stores host bridge resources reported by
ACPI BIOS for i386 and x86_64 systems. This is needed since
ACPI hotplug code now uses the PCI core for resource management.

Signed-off-by: Rajesh Shah <rajesh.shah@intel.com>

Index: linux-2.6.12-rc5/arch/i386/pci/acpi.c
===================================================================
--- linux-2.6.12-rc5.orig/arch/i386/pci/acpi.c
+++ linux-2.6.12-rc5/arch/i386/pci/acpi.c
@@ -5,14 +5,165 @@
#include <asm/hw_irq.h>
#include "pci.h"

+static void inline
+add_resource_range(int idx, struct pci_bus *bus,
+ struct acpi_resource_address64 *addr, unsigned long flags)
+{
+ memset(bus->resource[idx], 0, sizeof(*(bus->resource[idx])));
+ bus->resource[idx]->name = bus->name;
+ bus->resource[idx]->start = addr->min_address_range;
+ bus->resource[idx]->end = addr->max_address_range;
+ bus->resource[idx]->flags = flags;
+}
+
+static acpi_status
+add_resources(struct acpi_resource *acpi_res, void *context)
+{
+ struct acpi_resource_address64 address;
+ struct pci_bus *bus = context;
+ int idx;
+ unsigned long flags = 0;
+ struct resource *busr;
+
+ if (acpi_res->id != ACPI_RSTYPE_ADDRESS16 &&
+ acpi_res->id != ACPI_RSTYPE_ADDRESS32 &&
+ acpi_res->id != ACPI_RSTYPE_ADDRESS64)
+ return AE_OK;
+
+ if (ACPI_FAILURE(acpi_resource_to_address64(acpi_res, &address)))
+ return AE_OK;
+
+ /*
+ * Per the ACPI spec, we should pick up only ACPI_PRODUCER type
+ * resources. However, many BIOSs get this wrong and report
+ * resources they pass down as ACPI_CONSUMER type resources. For now,
+ * pick up all resources here.
+ */
+ if (address.address_length <= 0)
+ return AE_OK;
+
+ switch (address.resource_type) {
+ case ACPI_IO_RANGE:
+ flags = IORESOURCE_IO;
+ break;
+ case ACPI_MEMORY_RANGE:
+ flags = IORESOURCE_MEM;
+ if (address.attribute.memory.cache_attribute ==
+ ACPI_PREFETCHABLE_MEMORY)
+ flags |= IORESOURCE_PREFETCH;
+ break;
+ default:
+ return AE_OK;
+ break;
+ }
+ for (idx = 0; idx < PCI_BUS_NUM_RESOURCES; idx++) {
+ if (!bus->resource[idx]) {
+ bus->resource[idx] = kmalloc(
+ sizeof(*(bus->resource[idx])),
+ GFP_KERNEL);
+ if (!bus->resource[idx])
+ break;
+ add_resource_range(idx, bus, &address, flags);
+ return AE_OK;
+ }
+ busr = bus->resource[idx];
+ if (busr->flags != flags)
+ continue;
+ /* Consolidate adjacent resource ranges */
+ if (busr->end + 1 == address.min_address_range) {
+ busr->end = address.max_address_range;
+ return AE_OK;
+ }
+ if (address.max_address_range + 1 == busr->start) {
+ busr->start = address.min_address_range;
+ return AE_OK;
+ }
+ /* Consolidate overlapping resource ranges */
+ if (address.max_address_range < busr->start)
+ continue;
+ if (address.min_address_range > busr->end)
+ continue;
+ if (address.min_address_range < busr->start)
+ busr->start = address.min_address_range;
+ if (address.max_address_range > busr->end)
+ busr->end = address.max_address_range;
+ return AE_OK;
+ }
+ printk(KERN_WARNING
+ "PCI: Cannot add host bridge range %Lx-%Lx, type %x\n",
+ address.min_address_range, address.max_address_range,
+ address.resource_type);
+ return AE_ERROR;
+}
+
+static int __devinit
+verify_root_windows(struct pci_bus *bus)
+{
+ int i, num_io = 0, num_mem = 0;
+ int type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ if (!bus->resource[i])
+ continue;
+ switch (bus->resource[i]->flags & type_mask) {
+ case IORESOURCE_IO:
+ num_io++;
+ break;
+ case IORESOURCE_MEM:
+ num_mem++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (num_io || num_mem)
+ return 1;
+ else
+ printk(KERN_WARNING
+ "PCI: BIOS reported bogus host bridge resources\n");
+ return 0;
+}
+
+static void __devinit
+pcibios_setup_root_windows(struct pci_bus *bus, acpi_handle handle)
+{
+ int i;
+ acpi_status status;
+ struct resource *bres[PCI_BUS_NUM_RESOURCES];
+
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ bres[i] = bus->resource[i];
+ bus->resource[i] = NULL;
+ }
+
+ sprintf(bus->name, "PCI Bus #%02x", bus->number);
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ add_resources, bus);
+ if (ACPI_FAILURE(status) || !verify_root_windows(bus)) {
+ printk(KERN_WARNING
+ "PCI: Falling back to default host bridge resources\n");
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ kfree(bus->resource[i]);
+ bus->resource[i] = bres[i];
+ }
+ }
+}
+
+
struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
{
+ struct pci_bus *bus;
+
if (domain != 0) {
printk(KERN_WARNING "PCI: Multiple domains not supported\n");
return NULL;
}

- return pcibios_scan_root(busnum);
+ bus = pcibios_scan_root(busnum);
+ if (bus)
+ pcibios_setup_root_windows(bus, device->handle);
+ return bus;
}

extern int pci_routeirq;
--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-06-03 00:38    [W:0.076 / U:0.992 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site