pci_root: track downstream bus range for _CBA
Subsystems (4)
v2 cover pci_root: track downstream bus range for _CBA
The PCI Firmware Spec requires BIOS to use _CBA, not MCFG, to report MMCONFIG regions of hot-pluggable host bridges. Therefore, if the hardware and firmware support host bridge hotplug, we will encounter _CBA even if Linux itself doesn't support hotplug.
These patches make the pci_root driver keep track of the downstream bus range and make it available so arch-specific code can register MMCONFIG regions if necessary.
The first patch merely *prints* the downstream range, without saving it. I posted that patch alone previously, before I realized that we actually need to save the range for _CBA.
---
Bjorn Helgaas (3):
ACPI: pci_root: show entire downstream bus range
ACPI: pci_root: save downstream bus range
ACPI: pci_root: pass acpi_pci_root to arch-specific scan
arch/ia64/pci/pci.c | 5 ++++- arch/x86/pci/acpi.c | 5 ++++- drivers/acpi/pci_root.c | 46 ++++++++++++++++++++++++++----------------- include/acpi/acpi_bus.h | 1 + include/acpi/acpi_drivers.h | 3 +-- 5 files changed, 38 insertions(+), 22 deletions(-)
Signature · 1 line
Bjorn
PATCH v2 1/3 ACPI: pci_root: show entire downstream bus range
Previously, we only printed the immediately downstream bus number, but a host bridge claims a range of bus numbers. _CRS tells us the range, and it helps understand the system topology, so let's show it.
--- drivers/acpi/pci_root.c | 33 ++++++++++++++++++--------------- 1 files changed, 18 insertions(+), 15 deletions(-)
drivers/acpi/pci_root.c +18 -15
@@ -152,7 +152,7 @@ EXPORT_SYMBOL_GPL(acpi_is_root_bridge);static acpi_status get_root_bridge_busnr_callback (struct acpi_resource *resource,void *data) { -int *busnr = data; +struct resource *res = data;struct acpi_resource_address64 address; if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
@@ -162,28 +162,27 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)acpi_resource_to_address64 (resource, &address);if ((address.address_length >0 ) && - (address.resource_type ==ACPI_BUS_NUMBER_RANGE )) - *busnr = address.minimum; + (address.resource_type ==ACPI_BUS_NUMBER_RANGE )) { + res->start = address.minimum; + res->end = address.minimum + address.address_length -1 ; + }return AE_OK ; }static acpi_status try_get_root_bridge_busnr (acpi_handle handle, -unsigned long long *bus) +struct resource *res) {acpi_status status; -int busnum; - busnum =-1 ; + res->start =-1 ; status =acpi_walk_resources (handle,METHOD_NAME__CRS , - get_root_bridge_busnr_callback, &busnum); + get_root_bridge_busnr_callback, res);if (ACPI_FAILURE (status))return status; -/* Check if we really get a bus number from _CRS */ -if (busnum ==-1 ) +if (res->start ==-1 )return AE_ERROR ; - *bus = busnum;return AE_OK ; }
@@ -474,6 +473,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)acpi_handle handle;struct acpi_device *child;u32 flags, base_flags; +struct resource secondary; segment =0 ; status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
@@ -484,9 +484,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) }/* Check _CRS first, then _BBN. If no _BBN, default to zero. */ - bus =0 ; - status =try_get_root_bridge_busnr (device->handle, &bus); -if (ACPI_FAILURE (status)) { + secondary.start =0 ; + status =try_get_root_bridge_busnr (device->handle, &secondary); +if (ACPI_SUCCESS (status)) { + bus = secondary.start; + }else { status =acpi_evaluate_integer (device->handle,METHOD_NAME__BBN ,NULL , &bus);if (ACPI_FAILURE (status) && status !=AE_NOT_FOUND ) { printk(KERN_ERR PREFIX
@@ -521,9 +523,10 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)/* TBD: Locking */ list_add_tail (&root->node, &acpi_pci_roots); - printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n", + printk(KERN_INFO PREFIX "%s [%s] (domain %04x [bus %02x-%02x])\n",acpi_device_name (device),acpi_device_bid (device), - root->segment, root->bus_nr); + root->segment, + (unsigned int) secondary.start, (unsigned int) secondary.end);/* * Scan the Root Bridge
PATCH v2 2/3 ACPI: pci_root: save downstream bus range
In reply to Bjorn HelgaasWe need the entire downstream bus range, not just the base bus number, to support _CBA. See the PCI Firmware spec, rev 3.0, sec 4.1.3. It's clear that the bus range is supposed to be in _CRS, but if we don't find it there, we'll assume [_BBN - 0xFF].
--- drivers/acpi/pci_root.c | 19 +++++++++++++------ include/acpi/acpi_bus.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-)
drivers/acpi/pci_root.c +13 -6
@@ -485,16 +485,22 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)/* Check _CRS first, then _BBN. If no _BBN, default to zero. */ secondary.start =0 ; + secondary.end =0xFF ; status =try_get_root_bridge_busnr (device->handle, &secondary); -if (ACPI_SUCCESS (status)) { - bus = secondary.start; - }else { +if (ACPI_FAILURE (status)) { +/* +* We need both the start and end of the downstream bus range +* to interpret _CBA (MMCONFIG base address), so it really is +* supposed to be in _CRS. +*/ + printk(KERN_WARNING FW_BUG PREFIX + "no secondary bus range in _CRS\n"); status =acpi_evaluate_integer (device->handle,METHOD_NAME__BBN ,NULL , &bus);if (ACPI_FAILURE (status) && status !=AE_NOT_FOUND ) { - printk(KERN_ERR PREFIX - "no bus number in _CRS and can't evaluate _BBN\n"); + printk(KERN_ERR PREFIX "can't evaluate _BBN\n");return -ENODEV ; } + secondary.start = bus; } root =kzalloc (sizeof (struct acpi_pci_root ),GFP_KERNEL );
@@ -504,7 +510,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)INIT_LIST_HEAD (&root->node); root->device = device; root->segment = segment &0xFFFF ; - root->bus_nr = bus &0xFF ; + root->bus_nr = secondary.start &0xFF ; + root->subordinate_bus_nr = secondary.end &0xFF ;strcpy (acpi_device_name (device),ACPI_PCI_ROOT_DEVICE_NAME );strcpy (acpi_device_class (device),ACPI_PCI_ROOT_CLASS ); device->driver_data = root;
include/acpi/acpi_bus.h +1 -0
@@ -371,6 +371,7 @@ struct acpi_pci_root {struct pci_bus *bus;u16 segment;u8 bus_nr; +u8 subordinate_bus_nr;u32 osc_support_set;/* _OSC state of support bits */ u32 osc_control_set;/* _OSC state of control bits */
PATCH v2 3/3 ACPI: pci_root: pass acpi_pci_root to arch-specific scan
In reply to Bjorn HelgaasThe acpi_pci_root structure contains all the individual items (acpi_device, domain, bus number) we pass to pci_acpi_scan_root(), so just pass the single acpi_pci_root pointer directly.
This will make it easier to add _CBA support later. For _CBA, we need the entire downstream bus range, not just the base bus number. We have that in the acpi_pci_root structure, so passing the pointer makes it available to the arch-specific code.
--- arch/ia64/pci/pci.c | 5 ++++- arch/x86/pci/acpi.c | 5 ++++- drivers/acpi/pci_root.c | 2 +- include/acpi/acpi_drivers.h | 3 +-- 4 files changed, 10 insertions(+), 5 deletions(-)
arch/ia64/pci/pci.c +4 -1
@@ -341,8 +341,11 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl) }struct pci_bus *__devinit -pci_acpi_scan_root (struct acpi_device *device,int domain,int bus) +pci_acpi_scan_root (struct acpi_pci_root *root) { +struct acpi_device *device = root->device; +int domain = root->segment; +int bus = root->bus_nr;struct pci_controller *controller;unsigned int windows =0 ;struct pci_bus *pbus;
arch/x86/pci/acpi.c +4 -1
@@ -199,8 +199,11 @@ res_alloc_fail:return ; } -struct pci_bus *__devinit pci_acpi_scan_root (struct acpi_device *device,int domain,int busnum) +struct pci_bus *__devinit pci_acpi_scan_root (struct acpi_pci_root *root) { +struct acpi_device *device = root->device; +int domain = root->segment; +int busnum = root->bus_nr;struct pci_bus *bus;struct pci_sysdata *sd;int node;
drivers/acpi/pci_root.c +1 -1
@@ -542,7 +542,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)* PCI namespace does not get created until this call is made (and * thus the root bridge's pci_dev does not exist). */ - root->bus =pci_acpi_scan_root (device, segment, bus); + root->bus =pci_acpi_scan_root (root);if (!root->bus) { printk(KERN_ERR PREFIX "Bus %04x:%02x not present in PCI namespace\n",
include/acpi/acpi_drivers.h +1 -2
@@ -102,8 +102,7 @@ int acpi_pci_bind_root(struct acpi_device *device);/* Arch-defined function to add a bus to the system */ -struct pci_bus *pci_acpi_scan_root (struct acpi_device *device,int domain, -int bus); +struct pci_bus *pci_acpi_scan_root (struct acpi_pci_root *root);/* -------------------------------------------------------------------------- Processor
Quoted 8 lines · Bjorn Helgaas
The PCI Firmware Spec requires BIOS to use
_CBA, not MCFG, to report MMCONFIG regions of hot-pluggable host bridges. Therefore, if the hardware and firmware support host bridge hotplug, we will encounter_CBAeven if Linux itself doesn't support hotplug.These patches make the
pci_rootdriver keep track of the downstream bus range and make it available so arch-specific code can register MMCONFIG regions if necessary.
I think these patches got forgotten, but I still think they're worthwhile. I'd be glad to refresh them if necessary.
Bjorn
Quoted 5 lines · Bjorn Helgaas
The PCI Firmware Spec requires BIOS to use
_CBA, not MCFG, to report MMCONFIG regions of hot-pluggable host bridges. Therefore, if the hardware and firmware support host bridge hotplug, we will encounter_CBAeven if Linux itself doesn't support hotplug.
Quoted 7 lines
These patches make the
pci_rootdriver keep track of the downstream bus range and make it available so arch-specific code can register MMCONFIG regions if necessary.The first patch merely *prints* the downstream range, without saving it. I posted that patch alone previously, before I realized that we actually need to save the range for
_CBA.
Len,
Since you put the IORESOURCE_BUS patches in acpi-test, let me rework this series to use that instead of faking it.
Bjorn