Skip to contentSkip to conversation

pci_root: track downstream bus range for _CBA

PATCH Superseded Bjorn Helgaas 1 participant 6 messages Nov 10, 2009 – Mar 9, 2010

Subsystems (4)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
index 1af8081..aa9eeee 100644
@@ -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
#2 lore raw

PATCH v2 2/3 ACPI: pci_root: save downstream bus range

In reply to Bjorn Helgaas

We 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
index aa9eeee..a3e6f0e 100644
@@ -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
index 3cd9ccd..3d6e6e8 100644
@@ -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 */
#3 lore raw

PATCH v2 3/3 ACPI: pci_root: pass acpi_pci_root to arch-specific scan

In reply to Bjorn Helgaas

The 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
index 7d51bf4..21c80bc 100644
@@ -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
index 959e548..419b36d 100644
@@ -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
index a3e6f0e..cc237a3 100644
@@ -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
index f4906f6..0c0522f 100644
@@ -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
#4 lore raw
In reply to Bjorn Helgaas
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 _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.

I think these patches got forgotten, but I still think they're worthwhile. I'd be glad to refresh them if necessary.

Bjorn

#5 lore raw
In reply to Bjorn Helgaas
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 _CBA even if Linux itself doesn't support hotplug.

Quoted 7 lines

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.

Len,

Since you put the IORESOURCE_BUS patches in acpi-test, let me rework this series to use that instead of faking it.

Bjorn