Skip to contentSkip to conversation

Consolidate ACPI PCI root common code into ACPI core

PATCH In review Jiang Liu 9 participants 54 messages Oct 14, 2015 – Nov 27, 2015

Subsystems (3)
lore
Share & tools
lore

Jiang Liu

author
#0 lore raw

v7 cover Consolidate ACPI PCI root common code into ACPI core

From: Liu Jiang <[email protected]>

This patch set consolidates common code to support ACPI PCI root on x86 and IA64 platforms into ACPI core, to reproduce duplicated code and simplify maintenance. And a patch set based on previous version to support ACPI based PCIe host bridge on ARM64 has been posted at:
https://lkml.org/lkml/2015/5/26/207

It's based on latest mainstream kernel. It passes Fengguang's 0day test suite and has been tested on two IA64 platforms and one x86 platform.

V6->V7:
1) Improve commit message according to Bjorn's suggestion.
2) Move arch specific logic(code) from ACPI core into arch code according to Bjorn's review comments.

V5->V6:
1) Patch 5 to reset domain number to 0 when pci_ignore_seg is set
2) Remove parameter segment and node from function acpi_pci_root_create(), as suggested by Lorenzo and Bjorn.
V4-V5:
1) As suggested by Lorenzo Pieralisi <[email protected]>, do not introduce "struct pci_controller" into generic drivers/acpi/pci_root.c, so ARM64 doesn't need to define a useless structure. And it simplifies code a little too.

V3->V4:
1) Add patch[05/08] support solve building issue on ARM64
2) Solve an implicitly pointer cast issue.
3) Rebase to latest mainstream kernel

V2->V3:
1. Move memory allocation/free from ACPI core into arch
2. Kill the field 'segment' in struct pci_root_info on x86

Thanks!
Gerry

Jiang Liu (7):
ACPI/PCI: Enhance ACPI core to support sparse IO space ia64/PCI/ACPI: Use common ACPI resource parsing interface for host
bridge
ia64/PCI: Use common struct resource_entry to replace struct
iospace_resource
PCI/ACPI: Add interface acpi_pci_root_create()
ACPI, PCI: Reset acpi_root_dev->domain to 0 when pci_ignore_seg is
set
x86/PCI/ACPI: Use common interface to support PCI host bridge ia64/PCI/ACPI: Use common interface to support PCI host bridge

 arch/ia64/include/asm/pci.h |    5 -
 arch/ia64/pci/pci.c         |  368 ++++++++++++-------------------------------
 arch/x86/pci/acpi.c         |  296 +++++++++++-----------------------
 drivers/acpi/pci_root.c     |  204 ++++++++++++++++++++++++
 drivers/acpi/resource.c     |    9 +-
 include/linux/ioport.h      |    1 +
 include/linux/pci-acpi.h    |   24 +++
 7 files changed, 423 insertions(+), 484 deletions(-)
Signature · 1 line
1.7.10.4
author
#1 lore raw

PATCH v7 1/7 ACPI/PCI: Enhance ACPI core to support sparse IO space

Enhance ACPI resource parsing interfaces to support sparse IO space, which will be used to share common code between x86 and IA64 later.

---
 drivers/acpi/resource.c |    9 ++++++---
 include/linux/ioport.h  |    1 +
 2 files changed, 7 insertions(+), 3 deletions(-)
drivers/acpi/resource.c +6 -3
index 15d22db05054..cdc5c2599beb 100644
@@ -119,7 +119,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
 EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
 
 static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
-				      u8 io_decode)
+				      u8 io_decode, u8 translation_type)
 {
 	res->flags = IORESOURCE_IO;
 
@@ -131,6 +131,8 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
 
 	if (io_decode == ACPI_DECODE_16)
 		res->flags |= IORESOURCE_IO_16BIT_ADDR;
+	if (translation_type == ACPI_SPARSE_TRANSLATION)
+		res->flags |= IORESOURCE_IO_SPARSE;
 }
 
 static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
@@ -138,7 +140,7 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
 {
 	res->start = start;
 	res->end = start + len - 1;
-	acpi_dev_ioresource_flags(res, len, io_decode);
+	acpi_dev_ioresource_flags(res, len, io_decode, 0);
 }
 
 /**
@@ -231,7 +233,8 @@ static bool acpi_decode_space(struct resource_win *win,
 		acpi_dev_memresource_flags(res, len, wp);
 		break;
 	case ACPI_IO_RANGE:
-		acpi_dev_ioresource_flags(res, len, iodec);
+		acpi_dev_ioresource_flags(res, len, iodec,
+					  addr->info.io.translation_type);
 		break;
 	case ACPI_BUS_NUMBER_RANGE:
 		res->flags = IORESOURCE_BUS;
include/linux/ioport.h +1 -0
index 388e3ae94f7a..24bea087e7af 100644
@@ -94,6 +94,7 @@ struct resource {
 /* PnP I/O specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_IO_16BIT_ADDR	(1<<0)
 #define IORESOURCE_IO_FIXED		(1<<1)
+#define IORESOURCE_IO_SPARSE		(1<<2)
 
 /* PCI ROM control bits (IORESOURCE_BITS) */
 #define IORESOURCE_ROM_ENABLE		(1<<0)	/* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
Signature · 1 line
1.7.10.4
author
#2 lore raw

PATCH v7 2/7 ia64/PCI/ACPI: Use common ACPI resource parsing interface for host bridge

In reply to Jiang Liu

Use common ACPI resource parsing interface to parse ACPI resources for PCI host bridge, so we could share more code between IA64 and x86. Later we will consolidate arch specific implementations into ACPI core.

---
 arch/ia64/pci/pci.c |  414 ++++++++++++++++++++++++---------------------------
 1 file changed, 193 insertions(+), 221 deletions(-)
arch/ia64/pci/pci.c +193 -221
index 7cc3be9fa7c6..d20db9e48014 100644
@@ -115,29 +115,12 @@ struct pci_ops pci_root_ops = {
 	.write = pci_write,
 };
 
-/* Called by ACPI when it finds a new root bus.  */
-
-static struct pci_controller *alloc_pci_controller(int seg)
-{
-	struct pci_controller *controller;
-
-	controller = kzalloc(sizeof(*controller), GFP_KERNEL);
-	if (!controller)
-		return NULL;
-
-	controller->segment = seg;
-	return controller;
-}
-
 struct pci_root_info {
+	struct pci_controller controller;
 	struct acpi_device *bridge;
-	struct pci_controller *controller;
 	struct list_head resources;
-	struct resource *res;
-	resource_size_t *res_offset;
-	unsigned int res_num;
 	struct list_head io_resources;
-	char *name;
+	char name[16];
 };
 
 static unsigned int
@@ -168,11 +151,11 @@ new_space (u64 phys_base, int sparse)
 	return i;
 }
 
-static u64 add_io_space(struct pci_root_info *info,
-			struct acpi_resource_address64 *addr)
+static int add_io_space(struct device *dev, struct pci_root_info *info,
+			struct resource_entry *entry)
 {
 	struct iospace_resource *iospace;
-	struct resource *resource;
+	struct resource *resource, *res = entry->res;
 	char *name;
 	unsigned long base, min, max, base_port;
 	unsigned int sparse = 0, space_nr, len;
@@ -180,27 +163,24 @@ static u64 add_io_space(struct pci_root_info *info,
 	len = strlen(info->name) + 32;
 	iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL);
 	if (!iospace) {
-		dev_err(&info->bridge->dev,
-				"PCI: No memory for %s I/O port space\n",
-				info->name);
-		goto out;
+		dev_err(dev, "PCI: No memory for %s I/O port space\n",
+			info->name);
+		return -ENOMEM;
 	}
 
-	name = (char *)(iospace + 1);
-
-	min = addr->address.minimum;
-	max = min + addr->address.address_length - 1;
-	if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION)
+	if (res->flags & IORESOURCE_IO_SPARSE)
 		sparse = 1;
-
-	space_nr = new_space(addr->address.translation_offset, sparse);
+	space_nr = new_space(entry->offset, sparse);
 	if (space_nr == ~0)
 		goto free_resource;
 
+	name = (char *)(iospace + 1);
+	min = res->start - entry->offset;
+	max = res->end - entry->offset;
 	base = __pa(io_space[space_nr].mmio_base);
 	base_port = IO_SPACE_BASE(space_nr);
 	snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name,
-		base_port + min, base_port + max);
+		 base_port + min, base_port + max);
 
 	/*
 	 * The SDM guarantees the legacy 0-64K space is sparse, but if the
@@ -216,153 +196,195 @@ static u64 add_io_space(struct pci_root_info *info,
 	resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
 	resource->end   = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
 	if (insert_resource(&iomem_resource, resource)) {
-		dev_err(&info->bridge->dev,
-				"can't allocate host bridge io space resource  %pR\n",
-				resource);
+		dev_err(dev,
+			"can't allocate host bridge io space resource  %pR\n",
+			resource);
 		goto free_resource;
 	}
 
+	entry->offset = base_port;
+	res->start = min + base_port;
+	res->end = max + base_port;
 	list_add_tail(&iospace->list, &info->io_resources);
-	return base_port;
+
+	return 0;
 
 free_resource:
 	kfree(iospace);
-out:
-	return ~0;
+	return -ENOSPC;
+}
+
+/*
+ * An IO port or MMIO resource assigned to a PCI host bridge may be
+ * consumed by the host bridge itself or available to its child
+ * bus/devices. The ACPI specification defines a bit (Producer/Consumer)
+ * to tell whether the resource is consumed by the host bridge itself,
+ * but firmware hasn't used that bit consistently, so we can't rely on it.
+ *
+ * On x86 and IA64 platforms, all IO port and MMIO resources are assumed
+ * to be available to child bus/devices except one special case:
+ *     IO port [0xCF8-0xCFF] is consumed by the host bridge itself
+ *     to access PCI configuration space.
+ *
+ * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF].
+ */
+static bool resource_is_pcicfg_ioport(struct resource *res)
+{
+	return (res->flags & IORESOURCE_IO) &&
+		res->start == 0xCF8 && res->end == 0xCFF;
 }
 
-static acpi_status resource_to_window(struct acpi_resource *resource,
-				      struct acpi_resource_address64 *addr)
+static int
+probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
+		    int busnum, int domain)
 {
-	acpi_status status;
+	int ret;
+	struct list_head *list = &info->resources;
+	struct resource_entry *entry, *tmp;
 
-	/*
-	 * We're only interested in _CRS descriptors that are
-	 *	- address space descriptors for memory or I/O space
-	 *	- non-zero size
-	 */
-	status = acpi_resource_to_address64(resource, addr);
-	if (ACPI_SUCCESS(status) &&
-	    (addr->resource_type == ACPI_MEMORY_RANGE ||
-	     addr->resource_type == ACPI_IO_RANGE) &&
-	    addr->address.address_length)
-		return AE_OK;
-
-	return AE_ERROR;
-}
-
-static acpi_status count_window(struct acpi_resource *resource, void *data)
-{
-	unsigned int *windows = (unsigned int *) data;
-	struct acpi_resource_address64 addr;
-	acpi_status status;
-
-	status = resource_to_window(resource, &addr);
-	if (ACPI_SUCCESS(status))
-		(*windows)++;
-
-	return AE_OK;
-}
-
-static acpi_status add_window(struct acpi_resource *res, void *data)
-{
-	struct pci_root_info *info = data;
-	struct resource *resource;
-	struct acpi_resource_address64 addr;
-	acpi_status status;
-	unsigned long flags, offset = 0;
-	struct resource *root;
-
-	/* Return AE_OK for non-window resources to keep scanning for more */
-	status = resource_to_window(res, &addr);
-	if (!ACPI_SUCCESS(status))
-		return AE_OK;
-
-	if (addr.resource_type == ACPI_MEMORY_RANGE) {
-		flags = IORESOURCE_MEM;
-		root = &iomem_resource;
-		offset = addr.address.translation_offset;
-	} else if (addr.resource_type == ACPI_IO_RANGE) {
-		flags = IORESOURCE_IO;
-		root = &ioport_resource;
-		offset = add_io_space(info, &addr);
-		if (offset == ~0)
-			return AE_OK;
-	} else
-		return AE_OK;
-
-	resource = &info->res[info->res_num];
-	resource->name = info->name;
-	resource->flags = flags;
-	resource->start = addr.address.minimum + offset;
-	resource->end = resource->start + addr.address.address_length - 1;
-	info->res_offset[info->res_num] = offset;
-
-	if (insert_resource(root, resource)) {
-		dev_err(&info->bridge->dev,
-			"can't allocate host bridge window %pR\n",
-			resource);
-	} else {
-		if (offset)
-			dev_info(&info->bridge->dev, "host bridge window %pR "
-				 "(PCI address [%#llx-%#llx])\n",
-				 resource,
-				 resource->start - offset,
-				 resource->end - offset);
-		else
-			dev_info(&info->bridge->dev,
-				 "host bridge window %pR\n", resource);
-	}
-	/* HP's firmware has a hack to work around a Windows bug.
-	 * Ignore these tiny memory ranges */
-	if (!((resource->flags & IORESOURCE_MEM) &&
-	      (resource->end - resource->start < 16)))
-		pci_add_resource_offset(&info->resources, resource,
-					info->res_offset[info->res_num]);
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)(IORESOURCE_IO | IORESOURCE_MEM));
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if ((entry->res->flags & IORESOURCE_DISABLED) ||
+			    resource_is_pcicfg_ioport(entry->res))
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
 
-	info->res_num++;
-	return AE_OK;
+	return ret;
 }
 
-static void free_pci_root_info_res(struct pci_root_info *info)
-{
-	struct iospace_resource *iospace, *tmp;
+static void validate_resources(struct device *dev, struct list_head *resources,
+			       unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
 
-	list_for_each_entry_safe(iospace, tmp, &info->io_resources, list)
-		kfree(iospace);
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
 
-	kfree(info->name);
-	kfree(info->res);
-	info->res = NULL;
-	kfree(info->res_offset);
-	info->res_offset = NULL;
-	info->res_num = 0;
-	kfree(info->controller);
-	info->controller = NULL;
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+static void add_resources(struct pci_root_info *info, struct device *dev)
+{
+	struct resource_entry *entry, *tmp;
+	struct resource *res, *conflict, *root = NULL;
+	struct list_head *list = &info->resources;
+
+	validate_resources(dev, list, IORESOURCE_MEM);
+	validate_resources(dev, list, IORESOURCE_IO);
+
+	resource_list_for_each_entry_safe(entry, tmp, list) {
+		res = entry->res;
+		if (res->flags & IORESOURCE_MEM) {
+			root = &iomem_resource;
+			/*
+			 * HP's firmware has a hack to work around a Windows
+			 * bug. Ignore these tiny memory ranges.
+			 */
+			if (resource_size(res) <= 16) {
+				resource_list_destroy_entry(entry);
+				continue;
+			}
+		} else if (res->flags & IORESOURCE_IO) {
+			root = &ioport_resource;
+			if (add_io_space(&info->bridge->dev, info, entry)) {
+				resource_list_destroy_entry(entry);
+				continue;
+			}
+		} else {
+			BUG_ON(res);
+		}
+
+		conflict = insert_resource_conflict(root, res);
+		if (conflict) {
+			dev_info(dev,
+				 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
+				 res, conflict->name, conflict);
+			resource_list_destroy_entry(entry);
+		}
+	}
 }
 
 static void __release_pci_root_info(struct pci_root_info *info)
 {
-	int i;
 	struct resource *res;
-	struct iospace_resource *iospace;
+	struct iospace_resource *iospace, *tmp;
+	struct resource_entry *entry, *tentry;
 
-	list_for_each_entry(iospace, &info->io_resources, list)
+	list_for_each_entry_safe(iospace, tmp, &info->io_resources, list) {
 		release_resource(&iospace->res);
+		kfree(iospace);
+	}
 
-	for (i = 0; i < info->res_num; i++) {
-		res = &info->res[i];
-
-		if (!res->parent)
-			continue;
-
-		if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
-			continue;
-
-		release_resource(res);
+	resource_list_for_each_entry_safe(entry, tentry, &info->resources) {
+		res = entry->res;
+		if (res->parent &&
+		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+			release_resource(res);
+		resource_list_destroy_entry(entry);
 	}
 
-	free_pci_root_info_res(info);
 	kfree(info);
 }
 
@@ -373,99 +395,49 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
 	__release_pci_root_info(info);
 }
 
-static int
-probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
-		int busnum, int domain)
-{
-	char *name;
-
-	name = kmalloc(16, GFP_KERNEL);
-	if (!name)
-		return -ENOMEM;
-
-	sprintf(name, "PCI Bus %04x:%02x", domain, busnum);
-	info->bridge = device;
-	info->name = name;
-
-	acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
-			&info->res_num);
-	if (info->res_num) {
-		info->res =
-			kzalloc_node(sizeof(*info->res) * info->res_num,
-				     GFP_KERNEL, info->controller->node);
-		if (!info->res) {
-			kfree(name);
-			return -ENOMEM;
-		}
-
-		info->res_offset =
-			kzalloc_node(sizeof(*info->res_offset) * info->res_num,
-					GFP_KERNEL, info->controller->node);
-		if (!info->res_offset) {
-			kfree(name);
-			kfree(info->res);
-			info->res = NULL;
-			return -ENOMEM;
-		}
-
-		info->res_num = 0;
-		acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-			add_window, info);
-	} else
-		kfree(name);
-
-	return 0;
-}
-
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
 	struct acpi_device *device = root->device;
 	int domain = root->segment;
 	int bus = root->secondary.start;
-	struct pci_controller *controller;
-	struct pci_root_info *info = NULL;
-	int busnum = root->secondary.start;
+	struct pci_root_info *info;
 	struct pci_bus *pbus;
 	int ret;
 
-	controller = alloc_pci_controller(domain);
-	if (!controller)
-		return NULL;
-
-	controller->companion = device;
-	controller->node = acpi_get_node(device->handle);
-
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info) {
 		dev_err(&device->dev,
-				"pci_bus %04x:%02x: ignored (out of memory)\n",
-				domain, busnum);
-		kfree(controller);
+			"pci_bus %04x:%02x: ignored (out of memory)\n",
+			domain, bus);
 		return NULL;
 	}
 
-	info->controller = controller;
-	INIT_LIST_HEAD(&info->io_resources);
+	info->controller.segment = domain;
+	info->controller.companion = device;
+	info->controller.node = acpi_get_node(device->handle);
+	info->bridge = device;
 	INIT_LIST_HEAD(&info->resources);
+	INIT_LIST_HEAD(&info->io_resources);
+	snprintf(info->name, sizeof(info->name),
+		 "PCI Bus %04x:%02x", domain, bus);
 
-	ret = probe_pci_root_info(info, device, busnum, domain);
-	if (ret) {
-		kfree(info->controller);
+	ret = probe_pci_root_info(info, device, bus, domain);
+	if (ret <= 0) {
 		kfree(info);
 		return NULL;
 	}
-	/* insert busn resource at first */
+	add_resources(info, &info->bridge->dev);
 	pci_add_resource(&info->resources, &root->secondary);
+
 	/*
 	 * See arch/x86/pci/acpi.c.
 	 * The desired pci bus might already be scanned in a quirk. We
 	 * should handle the case here, but it appears that IA64 hasn't
 	 * such quirk. So we just ignore the case now.
 	 */
-	pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
-				   &info->resources);
+	pbus = pci_create_root_bus(NULL, bus, &pci_root_ops,
+				   &info->controller, &info->resources);
 	if (!pbus) {
-		pci_free_resource_list(&info->resources);
 		__release_pci_root_info(info);
 		return NULL;
 	}
Signature · 1 line
1.7.10.4
author
#3 lore raw

PATCH v7 3/7 ia64/PCI: Use common struct resource_entry to replace struct iospace_resource

In reply to Jiang Liu

Use common struct resource_entry to replace private struct iospace_resource.

---
 arch/ia64/include/asm/pci.h |    5 -----
 arch/ia64/pci/pci.c         |   17 ++++++++---------
 2 files changed, 8 insertions(+), 14 deletions(-)
arch/ia64/include/asm/pci.h +0 -5
index 36d2c1e3928b..07039d168f37 100644
@@ -64,11 +64,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
 #define pci_legacy_read platform_pci_legacy_read
 #define pci_legacy_write platform_pci_legacy_write
 
-struct iospace_resource {
-	struct list_head list;
-	struct resource res;
-};
-
 struct pci_controller {
 	struct acpi_device *companion;
 	void *iommu;
arch/ia64/pci/pci.c +8 -9
index d20db9e48014..b1846b891ea5 100644
@@ -154,14 +154,14 @@ new_space (u64 phys_base, int sparse)
 static int add_io_space(struct device *dev, struct pci_root_info *info,
 			struct resource_entry *entry)
 {
-	struct iospace_resource *iospace;
+	struct resource_entry *iospace;
 	struct resource *resource, *res = entry->res;
 	char *name;
 	unsigned long base, min, max, base_port;
 	unsigned int sparse = 0, space_nr, len;
 
 	len = strlen(info->name) + 32;
-	iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL);
+	iospace = resource_list_create_entry(NULL, len);
 	if (!iospace) {
 		dev_err(dev, "PCI: No memory for %s I/O port space\n",
 			info->name);
@@ -190,7 +190,7 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
 	if (space_nr == 0)
 		sparse = 1;
 
-	resource = &iospace->res;
+	resource = iospace->res;
 	resource->name  = name;
 	resource->flags = IORESOURCE_MEM;
 	resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
@@ -205,12 +205,12 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
 	entry->offset = base_port;
 	res->start = min + base_port;
 	res->end = max + base_port;
-	list_add_tail(&iospace->list, &info->io_resources);
+	resource_list_add_tail(iospace, &info->io_resources);
 
 	return 0;
 
 free_resource:
-	kfree(iospace);
+	resource_list_free_entry(iospace);
 	return -ENOSPC;
 }
 
@@ -369,12 +369,11 @@ static void add_resources(struct pci_root_info *info, struct device *dev)
 static void __release_pci_root_info(struct pci_root_info *info)
 {
 	struct resource *res;
-	struct iospace_resource *iospace, *tmp;
 	struct resource_entry *entry, *tentry;
 
-	list_for_each_entry_safe(iospace, tmp, &info->io_resources, list) {
-		release_resource(&iospace->res);
-		kfree(iospace);
+	resource_list_for_each_entry_safe(entry, tentry, &info->io_resources) {
+		release_resource(entry->res);
+		resource_list_destroy_entry(entry);
 	}
 
 	resource_list_for_each_entry_safe(entry, tentry, &info->resources) {
Signature · 1 line
1.7.10.4
author
#4 lore raw

PATCH v7 4/7 PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
 drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h |   24 ++++++
 2 files changed, 228 insertions(+)
drivers/acpi/pci_root.c +204 -0
index 393706a5261b..850d7bf0c873 100644
@@ -652,6 +652,210 @@ static void acpi_pci_root_remove(struct acpi_device *device)
 	kfree(root);
 }
 
+/*
+ * Following code to support acpi_pci_root_create() is copied from
+ * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64
+ * and ARM64.
+ */
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);
+	}
+
+	return ret;
+}
+
+static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info)
+{
+	struct resource_entry *entry, *tmp;
+	struct resource *res, *conflict, *root = NULL;
+
+	resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
+		res = entry->res;
+		if (res->flags & IORESOURCE_MEM)
+			root = &iomem_resource;
+		else if (res->flags & IORESOURCE_IO)
+			root = &ioport_resource;
+		else
+			continue;
+
+		conflict = insert_resource_conflict(root, res);
+		if (conflict) {
+			dev_info(&info->bridge->dev,
+				 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
+				 res, conflict->name, conflict);
+			resource_list_destroy_entry(entry);
+		}
+	}
+}
+
+static void __acpi_pci_root_release_info(struct acpi_pci_root_info *info)
+{
+	struct resource *res;
+	struct resource_entry *entry, *tmp;
+
+	if (!info)
+		return;
+
+	resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
+		res = entry->res;
+		if (res->parent &&
+		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+			release_resource(res);
+		resource_list_destroy_entry(entry);
+	}
+
+	info->ops->release_info(info);
+}
+
+static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
+{
+	struct resource *res;
+	struct resource_entry *entry;
+
+	resource_list_for_each_entry(entry, &bridge->windows) {
+		res = entry->res;
+		if (res->parent &&
+		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+			release_resource(res);
+	}
+	__acpi_pci_root_release_info(bridge->release_data);
+}
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);
+	if (!bus)
+		goto out_release_info;
+
+	pci_scan_child_bus(bus);
+	pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
+				    acpi_pci_root_release_info, info);
+	if (node != NUMA_NO_NODE)
+		dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
+	return bus;
+
+out_release_info:
+	__acpi_pci_root_release_info(info);
+	return NULL;
+}
+
 void __init acpi_pci_root_init(void)
 {
 	acpi_hest_init();
include/linux/pci-acpi.h +24 -0
index a965efa52152..89ab0572dbc6 100644
@@ -52,6 +52,30 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 	return ACPI_HANDLE(dev);
 }
 
+struct acpi_pci_root;
+struct acpi_pci_root_ops;
+
+struct acpi_pci_root_info {
+	struct acpi_pci_root		*root;
+	struct acpi_device		*bridge;
+	struct acpi_pci_root_ops	*ops;
+	struct list_head		resources;
+	char				name[16];
+};
+
+struct acpi_pci_root_ops {
+	struct pci_ops *pci_ops;
+	int (*init_info)(struct acpi_pci_root_info *info);
+	void (*release_info)(struct acpi_pci_root_info *info);
+	int (*prepare_resources)(struct acpi_pci_root_info *info);
+};
+
+extern int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info);
+extern struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+					    struct acpi_pci_root_ops *ops,
+					    struct acpi_pci_root_info *info,
+					    void *sd);
+
 void acpi_pci_add_bus(struct pci_bus *bus);
 void acpi_pci_remove_bus(struct pci_bus *bus);
 
Signature · 1 line
1.7.10.4
Acked-by on v7 4/7
#5 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 9 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

Quoted 262 lines
---
 drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h |   24 ++++++
 2 files changed, 228 insertions(+)
drivers/acpi/pci_root.c +204 -0
index 393706a5261b..850d7bf0c873 100644
@@ -652,6 +652,210 @@ static void acpi_pci_root_remove(struct acpi_device *device)
 	kfree(root);
 }
 
+/*
+ * Following code to support acpi_pci_root_create() is copied from
+ * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64
+ * and ARM64.
+ */
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);
+	}
+
+	return ret;
+}
+
+static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info)
+{
+	struct resource_entry *entry, *tmp;
+	struct resource *res, *conflict, *root = NULL;
+
+	resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
+		res = entry->res;
+		if (res->flags & IORESOURCE_MEM)
+			root = &iomem_resource;
+		else if (res->flags & IORESOURCE_IO)
+			root = &ioport_resource;
+		else
+			continue;
+
+		conflict = insert_resource_conflict(root, res);
+		if (conflict) {
+			dev_info(&info->bridge->dev,
+				 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
+				 res, conflict->name, conflict);
+			resource_list_destroy_entry(entry);
+		}
+	}
+}
+
+static void __acpi_pci_root_release_info(struct acpi_pci_root_info *info)
+{
+	struct resource *res;
+	struct resource_entry *entry, *tmp;
+
+	if (!info)
+		return;
+
+	resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
+		res = entry->res;
+		if (res->parent &&
+		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+			release_resource(res);
+		resource_list_destroy_entry(entry);
+	}
+
+	info->ops->release_info(info);
+}
+
+static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
+{
+	struct resource *res;
+	struct resource_entry *entry;
+
+	resource_list_for_each_entry(entry, &bridge->windows) {
+		res = entry->res;
+		if (res->parent &&
+		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+			release_resource(res);
+	}
+	__acpi_pci_root_release_info(bridge->release_data);
+}
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);
+	if (!bus)
+		goto out_release_info;
+
+	pci_scan_child_bus(bus);
+	pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
+				    acpi_pci_root_release_info, info);
+	if (node != NUMA_NO_NODE)
+		dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
+	return bus;
+
+out_release_info:
+	__acpi_pci_root_release_info(info);
+	return NULL;
+}
+
 void __init acpi_pci_root_init(void)
 {
 	acpi_hest_init();
include/linux/pci-acpi.h +24 -0
index a965efa52152..89ab0572dbc6 100644
@@ -52,6 +52,30 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 	return ACPI_HANDLE(dev);
 }
 
+struct acpi_pci_root;
+struct acpi_pci_root_ops;
+
+struct acpi_pci_root_info {
+	struct acpi_pci_root		*root;
+	struct acpi_device		*bridge;
+	struct acpi_pci_root_ops	*ops;
+	struct list_head		resources;
+	char				name[16];
+};
+
+struct acpi_pci_root_ops {
+	struct pci_ops *pci_ops;
+	int (*init_info)(struct acpi_pci_root_info *info);
+	void (*release_info)(struct acpi_pci_root_info *info);
+	int (*prepare_resources)(struct acpi_pci_root_info *info);
+};
+
+extern int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info);
+extern struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+					    struct acpi_pci_root_ops *ops,
+					    struct acpi_pci_root_info *info,
+					    void *sd);
+
 void acpi_pci_add_bus(struct pci_bus *bus);
 void acpi_pci_remove_bus(struct pci_bus *bus);
 
Signature · 6 lines
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#6 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Jiang Liu
Quoted 14 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
  drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
  include/linux/pci-acpi.h |   24 ++++++
  2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);

Thank a lot for this cleanup!!

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the part of pci_create_root_bus.

Regards,
Tomasz

#7 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 52 lines · Tomasz Nowicki
Quoted 14 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
 drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h |   24 ++++++
 2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);

Thank a lot for this cleanup!!

Quoted 7 lines

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the part of pci_create_root_bus.

Not sure I fully understand your question, but pci_bus_assign_domain_nr() will put the assigned domain number in bus->domain_nr if you chose PCI_DOMAINS_GENERIC. Do you want to override that value with the segment nr from MCFG?

Best regards,
Liviu

Quoted 4 lines

Regards,
Tomasz

Signature · 8 lines
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
#8 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 56 lines · Liviu Dudau
Quoted 55 lines · Tomasz Nowicki
Quoted 14 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
  drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
  include/linux/pci-acpi.h |   24 ++++++
  2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);

Thank a lot for this cleanup!!

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

Quoted 9 lines
Quoted 4 lines

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the part of pci_create_root_bus.

Not sure I fully understand your question, but pci_bus_assign_domain_nr() will put the assigned domain number in bus->domain_nr if you chose PCI_DOMAINS_GENERIC. Do you want to override that value with the segment nr from MCFG?

Let me give ACPI ARM64 example:

1. We parse MCFG table and get segment nr assigned to root bridge
2. Then PCI host bridge calls acpi_pci_root_create -> pci_create_root_bus -> pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPI

So I would like to assign MCFG segment nr to bus->domain_nr being in pci_bus_assign_domain_nr giving we have scenario above.

Thanks,
Tomasz

#9 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 69 lines · Tomasz Nowicki
Quoted 56 lines · Liviu Dudau
Quoted 55 lines · Tomasz Nowicki
Quoted 14 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
 drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h |   24 ++++++
 2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);

Thank a lot for this cleanup!!

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

Quoted 9 lines
Quoted 4 lines

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the part of pci_create_root_bus.

Not sure I fully understand your question, but pci_bus_assign_domain_nr() will put the assigned domain number in bus->domain_nr if you chose PCI_DOMAINS_GENERIC. Do you want to override that value with the segment nr from MCFG?

Let me give ACPI ARM64 example:

Quoted 7 lines

1. We parse MCFG table and get segment nr assigned to root bridge
2. Then PCI host bridge calls acpi_pci_root_create -> pci_create_root_bus -> pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPI

So I would like to assign MCFG segment nr to bus->domain_nr being in pci_bus_assign_domain_nr giving we have scenario above.

I do not understand what you mean by "assign MCFG segment" here, please explain. The MCFG segment group number is used to look-up the configuration space for a given host bridge, not to assign a domain number to it.

The domain_nr above is the value returned by the _SEG object for the host bridge device.

Lorenzo

#10 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 78 lines · Lorenzo Pieralisi
Quoted 69 lines · Tomasz Nowicki
Quoted 56 lines · Liviu Dudau
Quoted 55 lines · Tomasz Nowicki
Quoted 14 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
  drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
  include/linux/pci-acpi.h |   24 ++++++
  2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);

Thank a lot for this cleanup!!

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

Quoted 9 lines
Quoted 4 lines

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the part of pci_create_root_bus.

Not sure I fully understand your question, but pci_bus_assign_domain_nr() will put the assigned domain number in bus->domain_nr if you chose PCI_DOMAINS_GENERIC. Do you want to override that value with the segment nr from MCFG?

Let me give ACPI ARM64 example:

Quoted 7 lines

1. We parse MCFG table and get segment nr assigned to root bridge
2. Then PCI host bridge calls acpi_pci_root_create -> pci_create_root_bus -> pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPI

So I would like to assign MCFG segment nr to bus->domain_nr being in pci_bus_assign_domain_nr giving we have scenario above.

Quoted 6 lines

I do not understand what you mean by "assign MCFG segment" here, please explain. The MCFG segment group number is used to look-up the configuration space for a given host bridge, not to assign a domain number to it.

The domain_nr above is the value returned by the _SEG object for the host bridge device.

If I read the code correctly, MCFG region assigned to PCI host bridge X should have the same value for its segment field and corresponding _SEG object. Anyway, you are right, the MCFG segment group number should be used to look-up the configuration space and _SEG object to retrieve domain nr.

To evaluate _SEG object being in pci_bus_assign_domain_nr we still miss there the PCI host bridge device. So I should change my previous question, can we pass down the PCI host bridge device to be able to call _SEG object being in pci_bus_assign_domain_nr?

Thanks,
Tomasz

#11 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Tomasz Nowicki
Quoted 69 lines · Tomasz Nowicki
Quoted 56 lines · Liviu Dudau
Quoted 55 lines · Tomasz Nowicki
Quoted 14 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
 drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h |   24 ++++++
 2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+				     struct acpi_pci_root_ops *ops,
+				     struct acpi_pci_root_info *info,
+				     void *sysdata)
+{
+	int ret, busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
+	struct pci_bus *bus;
+
+	info->root = root;
+	info->bridge = device;
+	info->ops = ops;
+	INIT_LIST_HEAD(&info->resources);
+	snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+		 root->segment, busnum);
+
+	if (ops->init_info && ops->init_info(info))
+		goto out_release_info;
+	if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		ret = ops->prepare_resources(info);
+	else
+		ret = acpi_pci_probe_root_resources(info);
+	if (ret < 0)
+		goto out_release_info;
+
+	pci_acpi_root_add_resources(info);
+	pci_add_resource(&info->resources, &root->secondary);
+	bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+				  sysdata, &info->resources);

Thank a lot for this cleanup!!

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

Quoted 9 lines
Quoted 4 lines

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the part of pci_create_root_bus.

Not sure I fully understand your question, but pci_bus_assign_domain_nr() will put the assigned domain number in bus->domain_nr if you chose PCI_DOMAINS_GENERIC. Do you want to override that value with the segment nr from MCFG?

Let me give ACPI ARM64 example:

Quoted 7 lines

1. We parse MCFG table and get segment nr assigned to root bridge
2. Then PCI host bridge calls acpi_pci_root_create -> pci_create_root_bus -> pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPI

So I would like to assign MCFG segment nr to bus->domain_nr being in pci_bus_assign_domain_nr giving we have scenario above.

I thought so. What about adding code to pci_bus_assign_domain_nr() to get the segment nr from MCFG table? I know the function looks scary and the comments don't seem to acknowledge that use_dt_domain static variable has actually 3 possible values (-1, 0, 1) but you can use -1 to mean "try ACPI segment nr first" (just a suggestion, you or others might have a better idea).

Best regards,
Liviu

Quoted 4 lines

Thanks,
Tomasz

Signature · 8 lines
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
author
#12 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Tomasz Nowicki
Quoted 74 lines · Tomasz Nowicki
Quoted 64 lines · Liviu Dudau
Quoted 57 lines · Tomasz Nowicki
Quoted 15 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
  drivers/acpi/pci_root.c  |  204
++++++++++++++++++++++++++++++++++++++++++++++
  include/linux/pci-acpi.h |   24 ++++++
  2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+                     struct acpi_pci_root_ops *ops,
+                     struct acpi_pci_root_info *info,
+                     void *sysdata)
+{
+    int ret, busnum = root->secondary.start;
+    struct acpi_device *device = root->device;
+    int node = acpi_get_node(device->handle);
+    struct pci_bus *bus;
+
+    info->root = root;
+    info->bridge = device;
+    info->ops = ops;
+    INIT_LIST_HEAD(&info->resources);
+    snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+         root->segment, busnum);
+
+    if (ops->init_info && ops->init_info(info))
+        goto out_release_info;
+    if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+        ret = ops->prepare_resources(info);
+    else
+        ret = acpi_pci_probe_root_resources(info);
+    if (ret < 0)
+        goto out_release_info;
+
+    pci_acpi_root_add_resources(info);
+    pci_add_resource(&info->resources, &root->secondary);
+    bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+                  sysdata, &info->resources);

Thank a lot for this cleanup!!

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

Quoted 5 lines

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the
part of pci_create_root_bus.

Quoted 6 lines

Not sure I fully understand your question, but pci_bus_assign_domain_nr() will
put the assigned domain number in bus->domain_nr if you chose PCI_DOMAINS_GENERIC.
Do you want to override that value with the segment nr from MCFG?

Let me give ACPI ARM64 example:

Quoted 7 lines

1. We parse MCFG table and get segment nr assigned to root bridge
2. Then PCI host bridge calls acpi_pci_root_create -> pci_create_root_bus -> pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPI

So I would like to assign MCFG segment nr to bus->domain_nr being in pci_bus_assign_domain_nr giving we have scenario above.

Please use sysdata for that, IA64 and x86 are making use of sysdata to store such information:
struct pci_sysdata {

        int             domain;         /* PCI domain */
        int             node;           /* NUMA node */

#ifdef CONFIG_ACPI
struct acpi_device *companion; /* ACPI companion device */
#endif
#ifdef CONFIG_X86_64
void *iommu; /* IOMMU private data */
#endif
};

Hanjun once tried to introduce struct pci_sysdata for ARM64, but seems it has been rejected.

Quoted 8 lines

Thanks,
Tomasz

Signature · 4 lines
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
#13 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 95 lines · Jiang Liu
Quoted 74 lines · Tomasz Nowicki
Quoted 64 lines · Liviu Dudau
Quoted 57 lines · Tomasz Nowicki
Quoted 15 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
  drivers/acpi/pci_root.c  |  204
++++++++++++++++++++++++++++++++++++++++++++++
  include/linux/pci-acpi.h |   24 ++++++
  2 files changed, 228 insertions(+)

[...]

Quoted 21 lines
drivers/acpi/pci_root.c +21 -0
+
+struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+                     struct acpi_pci_root_ops *ops,
+                     struct acpi_pci_root_info *info,
+                     void *sysdata)
+{
+    int ret, busnum = root->secondary.start;
+    struct acpi_device *device = root->device;
+    int node = acpi_get_node(device->handle);
+    struct pci_bus *bus;
+
+    info->root = root;
+    info->bridge = device;
+    info->ops = ops;
+    INIT_LIST_HEAD(&info->resources);
+    snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
+         root->segment, busnum);
+
+    if (ops->init_info && ops->init_info(info))
+        goto out_release_info;
+    if (ops->prepare_resources)

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 843

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+        ret = ops->prepare_resources(info);
+    else
+        ret = acpi_pci_probe_root_resources(info);
+    if (ret < 0)
+        goto out_release_info;
+
+    pci_acpi_root_add_resources(info);
+    pci_add_resource(&info->resources, &root->secondary);
+    bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
+                  sysdata, &info->resources);

Thank a lot for this cleanup!!

I recall you already considered passing segment (domain nr) to pci_create_root_bus, right? Can you please remind me why we gave up on this?

Quoted 5 lines

I am asking because currently I can not find the way to retrieve domain number from pci_bus_assign_domain_nr (for those platforms which choose PCI_DOMAINS_GENERIC and want to use segment nr from MCFG table) which is the
part of pci_create_root_bus.

Quoted 6 lines

Not sure I fully understand your question, but pci_bus_assign_domain_nr() will
put the assigned domain number in bus->domain_nr if you chose PCI_DOMAINS_GENERIC.
Do you want to override that value with the segment nr from MCFG?

Let me give ACPI ARM64 example:

Quoted 7 lines

1. We parse MCFG table and get segment nr assigned to root bridge
2. Then PCI host bridge calls acpi_pci_root_create -> pci_create_root_bus -> pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPI

So I would like to assign MCFG segment nr to bus->domain_nr being in pci_bus_assign_domain_nr giving we have scenario above.

Please use sysdata for that, IA64 and x86 are making use of sysdata to store such information:
struct pci_sysdata {

        int             domain;         /* PCI domain */
        int             node;           /* NUMA node */

#ifdef CONFIG_ACPI
struct acpi_device *companion; /* ACPI companion device */
#endif
#ifdef CONFIG_X86_64
void *iommu; /* IOMMU private data */
#endif
};

Quoted 2 lines

Hanjun once tried to introduce struct pci_sysdata for ARM64, but seems it has been rejected.

For good reason! There is a lot of duplication between different arches notion of the pci_sysdata and they can be moved into pci_bus or pci_host_bridge structures. The goal is to get rid of multiple pci_sysdata structures, not to add more.

Best regards,
Liviu

Quoted 10 lines
Quoted 9 lines

Thanks,
Tomasz

Signature · 4 lines
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Signature · 8 lines
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
#14 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Jiang Liu
Quoted 109 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
  drivers/acpi/pci_root.c  |  204 ++++++++++++++++++++++++++++++++++++++++++++++
  include/linux/pci-acpi.h |   24 ++++++
  2 files changed, 228 insertions(+)
drivers/acpi/pci_root.c +87 -0
index 393706a5261b..850d7bf0c873 100644
@@ -652,6 +652,210 @@ static void acpi_pci_root_remove(struct acpi_device *device)
  	kfree(root);
  }
 
+/*
+ * Following code to support acpi_pci_root_create() is copied from
+ * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64
+ * and ARM64.
+ */
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

				 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

Thanks,
Tomasz

#15 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 1 line · Tomasz Nowicki

On 14.10.2015 08:29, Jiang Liu wrote:

[...]

Quoted 100 lines
Quoted 82 lines
drivers/acpi/pci_root.c +82 -0
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
				 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Confusing, to say the least. Jiang, did I get it right ?

Lorenzo

author
#16 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 127 lines · Lorenzo Pieralisi
Quoted 1 line · Tomasz Nowicki

On 14.10.2015 08:29, Jiang Liu wrote:

[...]

Quoted 100 lines
Quoted 82 lines
drivers/acpi/pci_root.c +82 -0
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
				 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

Quoted 7 lines

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Confusing, to say the least. Jiang, did I get it right ?

Yes, you are right, but seems I have done something wrong here. Currently res->start = acpi_des->start + acpi_des->translation_offset, which seems wrong. I will try to check IA64 side again and find a fix for this.

author
#17 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Lorenzo Pieralisi
Quoted 127 lines · Lorenzo Pieralisi
Quoted 1 line · Tomasz Nowicki

On 14.10.2015 08:29, Jiang Liu wrote:

[...]

Quoted 100 lines
Quoted 82 lines
drivers/acpi/pci_root.c +82 -0
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
				 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

Quoted 7 lines

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Confusing, to say the least. Jiang, did I get it right ?

Hi Lorenzo and Tomasz,
With a cup of coffee, I got myself awake eventually:)
Now we are going to talk about IO port on IA64, really a little complex:( Actually there are two types of translation.
1) A PCI domain has a 24-bit IO port address space, there may be multiple IO port address spaces in systems with multiple PCI domains. So the first type of translation is to translate domain specific IO port address into system global IO port address (iomem_resource) by
res->start = acpi_des->start + acpi_des->translation_offset

2) IA64 needs to map IO port address spaces into MMIO address space because it has no instructions to access IO ports directly. So IA64 has reserved a MMIO range to map IO port address spaces. This type of translation relies on architecture specific information instead of ACPI descriptors.

On the other hand, ACPI specification has defined "I/O to Memory Translation" flag and "Memory to I/O Translation" flag in ACPI Extended Address Space Descriptor, but current implementation doesn't really support such a use case. So we need to find a way out here. Could you please help to provide more information about PCI host bridge resource descriptor implementation details on ARM64?

Quoted 3 lines

Lorenzo

#18 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 152 lines · Jiang Liu
Quoted 127 lines · Lorenzo Pieralisi
Quoted 1 line · Tomasz Nowicki

On 14.10.2015 08:29, Jiang Liu wrote:

[...]

Quoted 100 lines
Quoted 82 lines
drivers/acpi/pci_root.c +82 -0
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
				 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

Quoted 7 lines

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Confusing, to say the least. Jiang, did I get it right ?

Hi Lorenzo and Tomasz,
With a cup of coffee, I got myself awake eventually:)
Now we are going to talk about IO port on IA64, really a little complex:( Actually there are two types of translation.
1) A PCI domain has a 24-bit IO port address space, there may be multiple IO port address spaces in systems with multiple PCI domains. So the first type of translation is to translate domain specific IO port address into system global IO port address (iomem_resource) by
res->start = acpi_des->start + acpi_des->translation_offset

2) IA64 needs to map IO port address spaces into MMIO address space because it has no instructions to access IO ports directly. So IA64 has reserved a MMIO range to map IO port address spaces. This type of translation relies on architecture specific information instead of ACPI descriptors.

Quoted 3 lines

On the other hand, ACPI specification has defined "I/O to Memory Translation" flag and "Memory to I/O Translation" flag in ACPI Extended Address Space Descriptor,

Based on 2) and above, does it mean IA64 should use "ACPI Extended Address Space Descriptor" for its PCI bridge IO windows only?

but current implementation

Quoted 5 lines

doesn't really support such a use case. So we need to find a way out here. Could you please help to provide more information about PCI host bridge resource descriptor implementation details on ARM64?

Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

         0x00000000,         // Granularity
         0x00000000,         // Range Minimum
         0x0000FFFF,         // Range Maximum
         0x3EFF0000,         // Translation Offset
         0x00010000,         // Length

,, , TypeStatic)

You can also have a look at my implementation example in mail to Lorenzo.

Thanks,
Tomasz

author
#19 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 175 lines · Tomasz Nowicki
Quoted 160 lines · Jiang Liu
Quoted 135 lines · Lorenzo Pieralisi
Quoted 1 line · Tomasz Nowicki

On 14.10.2015 08:29, Jiang Liu wrote:

[...]

Quoted 106 lines
Quoted 88 lines
drivers/acpi/pci_root.c +10 -0
+static void acpi_pci_root_validate_resources(struct device *dev,
+                         struct list_head *resources,
+                         unsigned long type)
+{
+    LIST_HEAD(list);
+    struct resource *res1, *res2, *root = NULL;
+    struct resource_entry *tmp, *entry, *entry2;
+
+    BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+    root = (type & IORESOURCE_MEM) ? &iomem_resource :

&ioport_resource;

drivers/acpi/pci_root.c +11 -0
+
+    list_splice_init(resources, &list);
+    resource_list_for_each_entry_safe(entry, tmp, &list) {
+        bool free = false;
+        resource_size_t end;
+
+        res1 = entry->res;
+        if (!(res1->flags & type))
+            goto next;
+
+        /* Exclude non-addressable range or non-addressable

portion */

drivers/acpi/pci_root.c +3 -0
+        end = min(res1->end, root->end);
+        if (end <= res1->start) {
+            dev_info(dev, "host bridge window %pR (ignored, not

CPU addressable)\n",

drivers/acpi/pci_root.c +5 -0
+                 res1);
+            free = true;
+            goto next;
+        } else if (res1->end != end) {
+            dev_info(dev, "host bridge window %pR ([%#llx-%#llx]

ignored, not CPU addressable)\n",

drivers/acpi/pci_root.c +19 -0
+                 res1, (unsigned long long)end + 1,
+                 (unsigned long long)res1->end);
+            res1->end = end;
+        }
+
+        resource_list_for_each_entry(entry2, resources) {
+            res2 = entry2->res;
+            if (!(res2->flags & type))
+                continue;
+
+            /*
+             * I don't like throwing away windows because then
+             * our resources no longer match the ACPI _CRS, but
+             * the kernel resource tree doesn't allow overlaps.
+             */
+            if (resource_overlaps(res1, res2)) {
+                res2->start = min(res1->start, res2->start);
+                res2->end = max(res1->end, res2->end);
+                dev_info(dev, "host bridge window expanded to %pR;

%pR ignored\n",

drivers/acpi/pci_root.c +24 -0
+                     res2, res1);
+                free = true;
+                goto next;
+            }
+        }
+
+next:
+        resource_list_del(entry);
+        if (free)
+            resource_list_free_entry(entry);
+        else
+            resource_list_add_tail(entry, resources);
+    }
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+    int ret;
+    struct list_head *list = &info->resources;
+    struct acpi_device *device = info->bridge;
+    struct resource_entry *entry, *tmp;
+    unsigned long flags;
+
+    flags = IORESOURCE_IO | IORESOURCE_MEM |

IORESOURCE_MEM_8AND16BIT;

drivers/acpi/pci_root.c +10 -0
+    ret = acpi_dev_get_resources(device, list,
+                     acpi_dev_filter_resource_type_cb,
+                     (void *)flags);
+    if (ret < 0)
+        dev_warn(&device->dev,
+             "failed to parse _CRS method, error code %d\n", ret);
+    else if (ret == 0)
+        dev_dbg(&device->dev,
+            "no IO and memory resources present in _CRS\n");
+    else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+        resource_list_for_each_entry_safe(entry, tmp, list) {
+            if (entry->res->flags & IORESOURCE_DISABLED)
+                resource_list_destroy_entry(entry);
+            else
+                entry->res->name = info->name;
+        }
+        acpi_pci_root_validate_resources(&device->dev, list,
+                         IORESOURCE_MEM);
+        acpi_pci_root_validate_resources(&device->dev, list,
+                         IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
                 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

Quoted 7 lines

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Confusing, to say the least. Jiang, did I get it right ?

Hi Lorenzo and Tomasz,
With a cup of coffee, I got myself awake eventually:)
Now we are going to talk about IO port on IA64, really a little complex:( Actually there are two types of translation.
1) A PCI domain has a 24-bit IO port address space, there may be multiple IO port address spaces in systems with multiple PCI domains. So the first type of translation is to translate domain specific IO port address into system global IO port address (iomem_resource) by
res->start = acpi_des->start + acpi_des->translation_offset

2) IA64 needs to map IO port address spaces into MMIO address space because it has no instructions to access IO ports directly. So IA64 has reserved a MMIO range to map IO port address spaces. This type of translation relies on architecture specific information instead of ACPI descriptors.

Quoted 3 lines

On the other hand, ACPI specification has defined "I/O to Memory Translation" flag and "Memory to I/O Translation" flag in ACPI Extended Address Space Descriptor,

Based on 2) and above, does it mean IA64 should use "ACPI Extended Address Space Descriptor" for its PCI bridge IO windows only?

but current implementation

Quoted 5 lines

doesn't really support such a use case. So we need to find a way out here. Could you please help to provide more information about PCI host bridge resource descriptor implementation details on ARM64?

Quoted 8 lines

Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

         0x00000000,         // Granularity
         0x00000000,         // Range Minimum
         0x0000FFFF,         // Range Maximum
         0x3EFF0000,         // Translation Offset
         0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it. Thanks,
Gerry

Quoted 5 lines

You can also have a look at my implementation example in mail to Lorenzo.

Thanks,
Tomasz

#20 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 184 lines · Jiang Liu
Quoted 175 lines · Tomasz Nowicki
Quoted 160 lines · Jiang Liu
Quoted 135 lines · Lorenzo Pieralisi
Quoted 1 line · Tomasz Nowicki

On 14.10.2015 08:29, Jiang Liu wrote:

[...]

Quoted 106 lines
Quoted 88 lines
drivers/acpi/pci_root.c +10 -0
+static void acpi_pci_root_validate_resources(struct device *dev,
+                         struct list_head *resources,
+                         unsigned long type)
+{
+    LIST_HEAD(list);
+    struct resource *res1, *res2, *root = NULL;
+    struct resource_entry *tmp, *entry, *entry2;
+
+    BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+    root = (type & IORESOURCE_MEM) ? &iomem_resource :

&ioport_resource;

drivers/acpi/pci_root.c +11 -0
+
+    list_splice_init(resources, &list);
+    resource_list_for_each_entry_safe(entry, tmp, &list) {
+        bool free = false;
+        resource_size_t end;
+
+        res1 = entry->res;
+        if (!(res1->flags & type))
+            goto next;
+
+        /* Exclude non-addressable range or non-addressable

portion */

drivers/acpi/pci_root.c +3 -0
+        end = min(res1->end, root->end);
+        if (end <= res1->start) {
+            dev_info(dev, "host bridge window %pR (ignored, not

CPU addressable)\n",

drivers/acpi/pci_root.c +5 -0
+                 res1);
+            free = true;
+            goto next;
+        } else if (res1->end != end) {
+            dev_info(dev, "host bridge window %pR ([%#llx-%#llx]

ignored, not CPU addressable)\n",

drivers/acpi/pci_root.c +19 -0
+                 res1, (unsigned long long)end + 1,
+                 (unsigned long long)res1->end);
+            res1->end = end;
+        }
+
+        resource_list_for_each_entry(entry2, resources) {
+            res2 = entry2->res;
+            if (!(res2->flags & type))
+                continue;
+
+            /*
+             * I don't like throwing away windows because then
+             * our resources no longer match the ACPI _CRS, but
+             * the kernel resource tree doesn't allow overlaps.
+             */
+            if (resource_overlaps(res1, res2)) {
+                res2->start = min(res1->start, res2->start);
+                res2->end = max(res1->end, res2->end);
+                dev_info(dev, "host bridge window expanded to %pR;

%pR ignored\n",

drivers/acpi/pci_root.c +24 -0
+                     res2, res1);
+                free = true;
+                goto next;
+            }
+        }
+
+next:
+        resource_list_del(entry);
+        if (free)
+            resource_list_free_entry(entry);
+        else
+            resource_list_add_tail(entry, resources);
+    }
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+    int ret;
+    struct list_head *list = &info->resources;
+    struct acpi_device *device = info->bridge;
+    struct resource_entry *entry, *tmp;
+    unsigned long flags;
+
+    flags = IORESOURCE_IO | IORESOURCE_MEM |

IORESOURCE_MEM_8AND16BIT;

drivers/acpi/pci_root.c +10 -0
+    ret = acpi_dev_get_resources(device, list,
+                     acpi_dev_filter_resource_type_cb,
+                     (void *)flags);
+    if (ret < 0)
+        dev_warn(&device->dev,
+             "failed to parse _CRS method, error code %d\n", ret);
+    else if (ret == 0)
+        dev_dbg(&device->dev,
+            "no IO and memory resources present in _CRS\n");
+    else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+        resource_list_for_each_entry_safe(entry, tmp, list) {
+            if (entry->res->flags & IORESOURCE_DISABLED)
+                resource_list_destroy_entry(entry);
+            else
+                entry->res->name = info->name;
+        }
+        acpi_pci_root_validate_resources(&device->dev, list,
+                         IORESOURCE_MEM);
+        acpi_pci_root_validate_resources(&device->dev, list,
+                         IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
                  IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

Quoted 7 lines

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Confusing, to say the least. Jiang, did I get it right ?

Hi Lorenzo and Tomasz,
With a cup of coffee, I got myself awake eventually:)
Now we are going to talk about IO port on IA64, really a little complex:( Actually there are two types of translation.
1) A PCI domain has a 24-bit IO port address space, there may be multiple IO port address spaces in systems with multiple PCI domains. So the first type of translation is to translate domain specific IO port address into system global IO port address (iomem_resource) by

    res->start = acpi_des->start + acpi_des->translation_offset

2) IA64 needs to map IO port address spaces into MMIO address space because it has no instructions to access IO ports directly. So IA64 has reserved a MMIO range to map IO port address spaces. This type of translation relies on architecture specific information instead of ACPI descriptors.

Quoted 3 lines

On the other hand, ACPI specification has defined "I/O to Memory Translation" flag and "Memory to I/O Translation" flag in ACPI Extended Address Space Descriptor,

Based on 2) and above, does it mean IA64 should use "ACPI Extended Address Space Descriptor" for its PCI bridge IO windows only?

but current implementation

Quoted 5 lines

doesn't really support such a use case. So we need to find a way out here. Could you please help to provide more information about PCI host bridge resource descriptor implementation details on ARM64?

Quoted 8 lines

Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

Quoted 8 lines

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

Thanks,
Tomasz

author
#21 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 20 lines · Tomasz Nowicki
Quoted 10 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

Quoted 8 lines

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Quoted 4 lines

Thanks,
Tomasz
From 51f5cddd8c4301b731805074ebc3e3a6c7dbaf59 Mon Sep 17 00:00:00 2001

From: Liu Jiang <[email protected]>
Date: Fri, 6 Nov 2015 20:01:59 +0800
Subject: [PATCH]

---
 drivers/acpi/resource.c      |   25 +++++++++++++++++++++++--
 include/linux/resource_ext.h |    7 +++++++
 2 files changed, 30 insertions(+), 2 deletions(-)
drivers/acpi/resource.c +23 -2
index cdc5c2599beb..1bd3e21f56fe 100644
@@ -215,8 +215,29 @@ static bool acpi_decode_space(struct resource_win *win,
 	else if (attr->translation_offset)
 		pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n",
 			 attr->translation_offset);
-	start = attr->minimum + offset;
-	end = attr->maximum + offset;
+	start = attr->minimum;
+	end = attr->maximum;
+
+	/*
+	 * Convert bus local address into system global address if it's an
+	 * IO Port->IO Port or MMIO->MMIO translation.
+	 */
+	switch (addr->resource_type) {
+	case ACPI_MEMORY_RANGE:
+		if (addr->info.mem.translation)
+			win->translation_type = RESOURCE_TRANS_MMIO_TO_IOPORT;
+		else
+			start += offset;
+		break;
+	case ACPI_IO_RANGE:
+		if (addr->info.io.translation)
+			win->translation_type = RESOURCE_TRANS_IOPORT_TO_MMIO;
+		else
+			start += offset;
+		break;
+	default:
+		break;
+	}
 
 	win->offset = offset;
 	res->start = start;
include/linux/resource_ext.h +7 -0
index e2bf63d881d4..f06d358c1f22 100644
@@ -22,8 +22,15 @@
 struct resource_win {
 	struct resource res;		/* In master (CPU) address space */
 	resource_size_t offset;		/* Translation offset for bridge */
+	int translation_type;		/* Translation type for bridge */
 };
 
+#define RESOURCE_TRANS_SAME		0x0
+/* Translate from IO port on slave into MMIO on master */
+#define RESOURCE_TRANS_IOPORT_TO_MMIO	0x1
+/* Translate from MMIO on slave into IO port on master */
+#define RESOURCE_TRANS_MMIO_TO_IOPORT	0x2
+
 /*
  * Common resource list management data structure and interfaces to support
  * ACPI, PNP and PCI host bridge etc.
Signature · 1 line
1.7.10.4
#22 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Eh, hopefully there are not any ACPI tables out there with that bit set that work _today_ and would not work with the patch attached :)

My question is still there: do we want to handle the same problem as ia64 has in a different manner ? Certainly we won't be able to update ia64 platforms ACPI tables, so we would end up with two platforms handling IO resources in different ways unless I am missing something here.

BTW, why would we add offset to res->start only if TypeTranslation is clear ? Is not that something we would do just to make things "work" ? That flag has no bearing on the offset, only on the resource type AFAIK.

This without taking into account ARM64 systems shipping with ACPI tables that does not set the TypeTranslation at present.

On top of that, I noticed that core ACPI code handles Sparse Translation (ie _TRS), that should be considered meaningful only if _TTP is set (and that's not checked).

Thoughts ?

Thanks,
Lorenzo

author
#23 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 27 lines · Lorenzo Pieralisi
Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Quoted 8 lines

Eh, hopefully there are not any ACPI tables out there with that bit set that work _today_ and would not work with the patch attached :)

My question is still there: do we want to handle the same problem as ia64 has in a different manner ? Certainly we won't be able to update ia64 platforms ACPI tables, so we would end up with two platforms handling IO resources in different ways unless I am missing something here.

There are some difference between IA64 and ARM64.
On IA64, it supports 16M IO address space per PCI domain and 256 PCI domains at max. So the system IO address space is 16M * 256 = 4G. So it does two level translations to support IO port
1) translate PCI bus local IO port address into system global IO port address by adding acpi_des->translation_offset.
2) translate the 4G system IO port address space into MMIO address. IA64 has reserved a 4G space for IO port mapping. This translation is done by arch specific method.
In other word, IA64 needs two level translation, but ACPI only provides on (trans_type, trans_offset) pair for encoding, so it's used for step 1).

For ARM64, I think currently it only needs step 2).

Quoted 4 lines

BTW, why would we add offset to res->start only if TypeTranslation is clear ? Is not that something we would do just to make things "work" ? That flag has no bearing on the offset, only on the resource type AFAIK.

It's not a hack, but a way to interpret ACPI spec:)

With current linux resource management framework, we need to allocate both MMIO and IO port address space range for an ACPI resource of type 'TypeTranslation'. And struct resource could be either IO port or MMIO, not both. So the choice is to keep the resource as IO port, and let arch code to build the special MMIO mapping for it. Otherwise it will break too many things if we convert the resource as MMIO.

That said, we need to add translation_offset to convert bus local IO port address into system global IO port address if it's type of TypeStatic, because ioresource_ioport uses system global IO port address.

For an ACPI resource of type TypeTranslation, system global IO port address equals bus local IO port address, and the translation_offset is used to translate IO port address into MMIO address, so we shouldn't add translation_offset to the IO port resource descriptor.

Thanks,
Gerry

Quoted 7 lines

This without taking into account ARM64 systems shipping with ACPI tables that does not set the TypeTranslation at present.

On top of that, I noticed that core ACPI code handles Sparse Translation (ie _TRS), that should be considered meaningful only if _TTP is set (and that's not checked).

Yes, that's a flaw:(

Quoted 6 lines

Thoughts ?

Thanks,
Lorenzo

author
#24 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 68 lines · Jiang Liu
Quoted 27 lines · Lorenzo Pieralisi
Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Quoted 8 lines

Eh, hopefully there are not any ACPI tables out there with that bit set that work _today_ and would not work with the patch attached :)

My question is still there: do we want to handle the same problem as ia64 has in a different manner ? Certainly we won't be able to update ia64 platforms ACPI tables, so we would end up with two platforms handling IO resources in different ways unless I am missing something here.

There are some difference between IA64 and ARM64.
On IA64, it supports 16M IO address space per PCI domain and 256 PCI domains at max. So the system IO address space is 16M * 256 = 4G. So it does two level translations to support IO port
1) translate PCI bus local IO port address into system global IO port address by adding acpi_des->translation_offset.
2) translate the 4G system IO port address space into MMIO address. IA64 has reserved a 4G space for IO port mapping. This translation is done by arch specific method.
In other word, IA64 needs two level translation, but ACPI only provides on (trans_type, trans_offset) pair for encoding, so it's used for step 1).

For ARM64, I think currently it only needs step 2).

Quoted 4 lines

BTW, why would we add offset to res->start only if TypeTranslation is clear ? Is not that something we would do just to make things "work" ? That flag has no bearing on the offset, only on the resource type AFAIK.

It's not a hack, but a way to interpret ACPI spec:)

With current linux resource management framework, we need to allocate both MMIO and IO port address space range for an ACPI resource of type 'TypeTranslation'. And struct resource could be either IO port or MMIO, not both. So the choice is to keep the resource as IO port, and let arch code to build the special MMIO mapping for it. Otherwise it will break too many things if we convert the resource as MMIO.

That said, we need to add translation_offset to convert bus local IO port address into system global IO port address if it's type of TypeStatic, because ioresource_ioport uses system global IO port address.

Quoted 4 lines

For an ACPI resource of type TypeTranslation, system global IO port address equals bus local IO port address, and the translation_offset is used to translate IO port address into MMIO address, so we shouldn't add translation_offset to the IO port resource descriptor.

One note for the TypeTranslation case, the arch code needs to reset resource_win->offset to zero after setting up the MMIO map. Sample code as below:
va = ioremap(resource_win->offset + res->start, resource_size(res)); resource_win->offset = 0;

Otherwise it will break pcibios_resource_to_bus() etc.

Quoted 25 lines

Thanks,
Gerry

Quoted 7 lines

This without taking into account ARM64 systems shipping with ACPI tables that does not set the TypeTranslation at present.

On top of that, I noticed that core ACPI code handles Sparse Translation (ie _TRS), that should be considered meaningful only if _TTP is set (and that's not checked).

Yes, that's a flaw:(

Quoted 6 lines

Thoughts ?

Thanks,
Lorenzo

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#25 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 106 lines · Jiang Liu
Quoted 68 lines · Jiang Liu
Quoted 27 lines · Lorenzo Pieralisi
Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Quoted 8 lines

Eh, hopefully there are not any ACPI tables out there with that bit set that work _today_ and would not work with the patch attached :)

My question is still there: do we want to handle the same problem as ia64 has in a different manner ? Certainly we won't be able to update ia64 platforms ACPI tables, so we would end up with two platforms handling IO resources in different ways unless I am missing something here.

There are some difference between IA64 and ARM64.
On IA64, it supports 16M IO address space per PCI domain and 256 PCI domains at max. So the system IO address space is 16M * 256 = 4G. So it does two level translations to support IO port
1) translate PCI bus local IO port address into system global IO port address by adding acpi_des->translation_offset.
2) translate the 4G system IO port address space into MMIO address. IA64 has reserved a 4G space for IO port mapping. This translation is done by arch specific method.
In other word, IA64 needs two level translation, but ACPI only provides on (trans_type, trans_offset) pair for encoding, so it's used for step 1).

For ARM64, I think currently it only needs step 2).

Quoted 4 lines

BTW, why would we add offset to res->start only if TypeTranslation is clear ? Is not that something we would do just to make things "work" ? That flag has no bearing on the offset, only on the resource type AFAIK.

It's not a hack, but a way to interpret ACPI spec:)

With current linux resource management framework, we need to allocate both MMIO and IO port address space range for an ACPI resource of type 'TypeTranslation'. And struct resource could be either IO port or MMIO, not both. So the choice is to keep the resource as IO port, and let arch code to build the special MMIO mapping for it. Otherwise it will break too many things if we convert the resource as MMIO.

That said, we need to add translation_offset to convert bus local IO port address into system global IO port address if it's type of TypeStatic, because ioresource_ioport uses system global IO port address.

Quoted 4 lines

For an ACPI resource of type TypeTranslation, system global IO port address equals bus local IO port address, and the translation_offset is used to translate IO port address into MMIO address, so we shouldn't add translation_offset to the IO port resource descriptor.

One note for the TypeTranslation case, the arch code needs to reset resource_win->offset to zero after setting up the MMIO map. Sample code as below:
va = ioremap(resource_win->offset + res->start, resource_size(res)); resource_win->offset = 0;

Otherwise it will break pcibios_resource_to_bus() etc.

Quoted 16 lines

Thanks,
Gerry

Quoted 7 lines

This without taking into account ARM64 systems shipping with ACPI tables that does not set the TypeTranslation at present.

On top of that, I noticed that core ACPI code handles Sparse Translation (ie _TRS), that should be considered meaningful only if _TTP is set (and that's not checked).

Yes, that's a flaw:(

Quoted 3 lines

Thoughts ?

Quoted 9 lines
Quoted 3 lines

Thanks,
Lorenzo

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Tomasz, Lorenzo;
I have an ARMv8 platform with IO address support where I can test this implementation. Let me know if there is any patch that I can try. Sinan

Signature · 4 lines
Sinan Kaya
Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a
Linux Foundation Collaborative Project
#26 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Jiang Liu
Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

           0x00000000,         // Granularity
           0x00000000,         // Range Minimum
           0x0000FFFF,         // Range Maximum
           0x3EFF0000,         // Translation Offset
           0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Based on the further discussion, your draft patch looks good to me. Lorenzo, do you agree?

Gerry, what would be the best way to approach with this, extra patch of your set? or keep it separately, might be part of my set.

Thanks,
Tomasz

#27 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

[CC'ing Arnd]

Quoted 22 lines · Tomasz Nowicki
Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Based on the further discussion, your draft patch looks good to me. Lorenzo, do you agree?

No, because I still do not understand the difference between ia64 and arm64 (they both drive IO ports cycles through MMIO so the resource descriptors content must be the same or better they must mean the same thing). On top of that, this is something that was heavily debated for DT:

http://www.spinics.net/lists/arm-kernel/msg345633.html

and I would like to get Arnd and Bjorn opinion on this because we should not "interpret" ACPI specifications, we should understand what they are supposed to describe and write kernel code accordingly.

In particular, I would like to understand, for an eg DWordIO descriptor, what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge map the IO space transactions), I do not think ia64 is any different from arm64 in this respect, if it is please provide an HW description here from the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge tables would help).

Thanks,
Lorenzo

#28 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 38 lines · On Monday 09 November 2015 17:10:43 Lorenzo Pieralisi wrote:
Quoted 22 lines · Tomasz Nowicki
Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Based on the further discussion, your draft patch looks good to me. Lorenzo, do you agree?

No, because I still do not understand the difference between ia64 and arm64 (they both drive IO ports cycles through MMIO so the resource descriptors content must be the same or better they must mean the same thing). On top of that, this is something that was heavily debated for DT:

http://www.spinics.net/lists/arm-kernel/msg345633.html

Quoted 8 lines

and I would like to get Arnd and Bjorn opinion on this because we should not "interpret" ACPI specifications, we should understand what they are supposed to describe and write kernel code accordingly.

In particular, I would like to understand, for an eg DWordIO descriptor, what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB) range of CPU addresses that gets translated into PCI I/O space the same way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 6 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge map the IO space transactions), I do not think ia64 is any different from arm64 in this respect, if it is please provide an HW description here from the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge tables would help).

The main difference between ia64 and a lot of the other architectures (e.g. sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
        struct io_space *space = &io_space[IO_SPACE_NR(port)];
        return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
        return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
        return readl(PCI_IOBASE + addr);
}

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual address window at the correct io_offset;

Arnd

author
#29 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 87 lines · Arnd Bergmann
Quoted 38 lines · On Monday 09 November 2015 17:10:43 Lorenzo Pieralisi wrote:
Quoted 22 lines · Tomasz Nowicki
Quoted 21 lines · Jiang Liu
Quoted 20 lines · Tomasz Nowicki
Quoted 18 lines · Jiang Liu
Quoted 9 lines · Tomasz Nowicki

On 06.11.2015 09:52, Jiang Liu wrote:
Sure, ARM64 (0-16M IO space) QEMU example:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

          0x00000000,         // Granularity
          0x00000000,         // Range Minimum
          0x0000FFFF,         // Range Maximum
          0x3EFF0000,         // Translation Offset
          0x00010000,         // Length

,, , TypeStatic)

The above DWordIO resource descriptor doesn't confirm to the ACPI spec. According to my understanding, ARM/ARM64 has no concept of IO port address space, so the PCI host bridge will map IO port on PCI side onto MMIO on host side. In other words, PCI host bridge on ARM64 implement a IO Port->MMIO translation instead of a IO Port->IO Port translation. If that's true, it should use 'TypeTranslation' instead of 'TypeStatic'. And kernel ACPI resource parsing interface doesn't support 'TypeTranslation' yet, so we need to find a solution for it.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

I think you are right, we need TypeTranslation flag for ARM64 DWordIO descriptors and an extra kernel patch to support it.

How about the attached to patch to support TypeTranslation? It only passes compilation:)

Based on the further discussion, your draft patch looks good to me. Lorenzo, do you agree?

No, because I still do not understand the difference between ia64 and arm64 (they both drive IO ports cycles through MMIO so the resource descriptors content must be the same or better they must mean the same thing). On top of that, this is something that was heavily debated for DT:

http://www.spinics.net/lists/arm-kernel/msg345633.html

Quoted 8 lines

and I would like to get Arnd and Bjorn opinion on this because we should not "interpret" ACPI specifications, we should understand what they are supposed to describe and write kernel code accordingly.

In particular, I would like to understand, for an eg DWordIO descriptor, what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB) range of CPU addresses that gets translated into PCI I/O space the same way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 6 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge map the IO space transactions), I do not think ia64 is any different from arm64 in this respect, if it is please provide an HW description here from the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge tables would help).

The main difference between ia64 and a lot of the other architectures (e.g. sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
        struct io_space *space = &io_space[IO_SPACE_NR(port)];
        return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
        return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
        return readl(PCI_IOBASE + addr);
}
Quoted 6 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual address window at the correct io_offset;

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested yet).
Thanks,
Gerry

Quoted 1 line

From 6521d3c5303b1d9830eecede4c1b778deffe17b0 Mon Sep 17 00:00:00 2001

From: Liu Jiang <[email protected]>
Date: Tue, 10 Nov 2015 10:59:11 +0800
Subject: [PATCH] ACPI, PCI: Refine the way to handle translation_offset for
ACPI resources

Some architectures, such as IA64 and ARM64, have no instructions to directly access PCI IO ports, so they map PCI IO ports into PCI MMIO address space. Typically PCI host bridges on those architectures take the responsibility to map (translate) PCI IO port transactions into Memory-Mapped IO transactions. ACPI specification provides support of such a usage case by using resource translation_offset.

But current ACPI resource parsing interface isn't neutral enough, it still has some special logic for IA64. So refine the ACPI resource parsing interface and IA64 code to neutrally handle translation_offset by:
1) ACPI resource parsing interface doesn't do any translation, it just save the translation_offset to be used by arch code.
2) Arch code will do the mapping(translation) based on arch specific information. Typically it does:
2.a) Translate per PCI domain IO port address space into system global
IO port address space.
2.b) Setup MMIO address mapping for IO ports.
void handle_io_resource(struct resource_entry *io_entry)

{
	struct resource *mmio_res;

	mmio_res = kzalloc(sizeof(*mmio_res), GFP_KERNEL);
	mmio_res->flags = IORESOURCE_MEM;
	mmio_res->start = io_entry->offset + io_entry->res->start;
	mmio_res->end = io_entry->offset + io_entry->res->end;
	insert_resource(&iomem_resource, mmio_res)

	base = map_to_system_ioport_address(entry);
	io_entry->offset = base;
	io_entry->res->start += base;
	io_entry->res->end += base;
}
---
 arch/ia64/pci/pci.c     |   26 ++++++++++++++++----------
 drivers/acpi/resource.c |   12 +++++-------
 2 files changed, 21 insertions(+), 17 deletions(-)
arch/ia64/pci/pci.c +16 -10
index 8f6ac2f8ae4c..ee84300797d8 100644
@@ -154,7 +154,7 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
 	struct resource_entry *iospace;
 	struct resource *resource, *res = entry->res;
 	char *name;
-	unsigned long base, min, max, base_port;
+	unsigned long base_mmio, base_port;
 	unsigned int sparse = 0, space_nr, len;
 
 	len = strlen(info->common.name) + 32;
@@ -172,12 +172,10 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
 		goto free_resource;
 
 	name = (char *)(iospace + 1);
-	min = res->start - entry->offset;
-	max = res->end - entry->offset;
-	base = __pa(io_space[space_nr].mmio_base);
+	base_mmio = __pa(io_space[space_nr].mmio_base);
 	base_port = IO_SPACE_BASE(space_nr);
 	snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->common.name,
-		 base_port + min, base_port + max);
+		 base_port + res->start, base_port + res->end);
 
 	/*
 	 * The SDM guarantees the legacy 0-64K space is sparse, but if the
@@ -190,19 +188,27 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
 	resource = iospace->res;
 	resource->name  = name;
 	resource->flags = IORESOURCE_MEM;
-	resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
-	resource->end   = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
+	resource->start = base_mmio;
+	resource->end = base_mmio;
+	if (sparse) {
+		resource->start += IO_SPACE_SPARSE_ENCODING(res->start);
+		resource->end += IO_SPACE_SPARSE_ENCODING(res->end);
+	} else {
+		resource->start += res->start;
+		resource->end += res->end;
+	}
 	if (insert_resource(&iomem_resource, resource)) {
 		dev_err(dev,
 			"can't allocate host bridge io space resource  %pR\n",
 			resource);
 		goto free_resource;
 	}
+	resource_list_add_tail(iospace, &info->io_resources);
 
+	/* Adjust base of original IO port resource descriptor */
 	entry->offset = base_port;
-	res->start = min + base_port;
-	res->end = max + base_port;
-	resource_list_add_tail(iospace, &info->io_resources);
+	res->start += base_port;
+	res->end += base_port;
 
 	return 0;
 
drivers/acpi/resource.c +5 -7
index cdc5c2599beb..6578f68b17be 100644
@@ -190,8 +190,7 @@ static bool acpi_decode_space(struct resource_win *win,
 {
 	u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16;
 	bool wp = addr->info.mem.write_protect;
-	u64 len = attr->address_length;
-	u64 start, end, offset = 0;
+	u64 len = attr->address_length, offset = 0;
 	struct resource *res = &win->res;
 
 	/*
@@ -215,14 +214,13 @@ static bool acpi_decode_space(struct resource_win *win,
 	else if (attr->translation_offset)
 		pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n",
 			 attr->translation_offset);
-	start = attr->minimum + offset;
-	end = attr->maximum + offset;
 
 	win->offset = offset;
-	res->start = start;
-	res->end = end;
+	res->start = attr->minimum;
+	res->end = attr->maximum;
 	if (sizeof(resource_size_t) < sizeof(u64) &&
-	    (offset != win->offset || start != res->start || end != res->end)) {
+	    (offset != win->offset || attr->minimum != res->start ||
+	     attr->maximum != res->end)) {
 		pr_warn("acpi resource window ([%#llx-%#llx] ignored, not CPU addressable)\n",
 			attr->minimum, attr->maximum);
 		return false;
Signature · 1 line
1.7.10.4
#30 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 50 lines
Quoted 44 lines
Quoted 4 lines

In particular, I would like to understand, for an eg DWordIO descriptor, what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB) range of CPU addresses that gets translated into PCI I/O space the same way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 6 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge map the IO space transactions), I do not think ia64 is any different from arm64 in this respect, if it is please provide an HW description here from the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge tables would help).

The main difference between ia64 and a lot of the other architectures (e.g. sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
        struct io_space *space = &io_space[IO_SPACE_NR(port)];
        return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
        return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
        return readl(PCI_IOBASE + addr);
}
Quoted 6 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual address window at the correct io_offset;

Quoted 5 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI, am I wrong ?

Overall I think the point is related to ioport_resource and its check in acpi_pci_root_validate_resources() which basically that's the problem that started this thread.

On arm64, IO_SPACE_LIMIT is 16M, which, AFAIK is a kernel limit, not a HW one. Comparing the resources parsed from the PCI bridge _CRS against the range 0..IO_SPACE_LIMIT is not necessarily meaningful (or at least not meaningful in its current form), on ia64 it works because IO_SPACE_LIMIT is bumped up to 4G, that's the reason why adding the offset to the ACPI IO resources work on ia64 as far as I understand.

And that's why I pulled Arnd in this discussion since he knows better than me: what does ioport_resource _really_ represent on ARM64 ? It seems to me that it is a range of IO ports values (ie a window that defines the allowed offset in the virtual address space allocated to PCI IO) that has _nothing_ to do with the CPU physical address at which the IO space is actually mapped.

To sum it up for a, say, DWordIo/Memory descriptor:

- AddressMinimum, AddressMaximum represent the PCI bus addresses defining the resource start..end
- AddressTranslation is the offset that has to be added to AddressMinimum and AddressMaximum to get the window in CPU physical address space

So:

- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patch acpi_pci_root_validate_resources() to amend the way IORESOURCE_IO is currently checked against ioport_resource, it can't work on arm64 at present, I described why above

Thoughts appreciated it is time we got this sorted and thanks for the patch.

Thanks,
Lorenzo

#31 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 77 lines · Lorenzo Pieralisi

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 50 lines
Quoted 44 lines
Quoted 4 lines

In particular, I would like to understand, for an eg DWordIO descriptor, what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB) range of CPU addresses that gets translated into PCI I/O space the same way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 6 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge map the IO space transactions), I do not think ia64 is any different from arm64 in this respect, if it is please provide an HW description here from the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge tables would help).

The main difference between ia64 and a lot of the other architectures (e.g. sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
        struct io_space *space = &io_space[IO_SPACE_NR(port)];
        return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
        return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
        return readl(PCI_IOBASE + addr);
}
Quoted 6 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual address window at the correct io_offset;

Quoted 5 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI, am I wrong ?

Quoted 6 lines

Overall I think the point is related to ioport_resource and its check in acpi_pci_root_validate_resources() which basically that's the problem that started this thread.

On arm64, IO_SPACE_LIMIT is 16M, which, AFAIK is a kernel limit, not a HW one.

You're right, it is a kernel limit. There is no HW limit for IO on arm64.

Quoted 6 lines

Comparing the resources parsed from the PCI bridge _CRS against the range 0..IO_SPACE_LIMIT is not necessarily meaningful (or at least not meaningful in its current form), on ia64 it works because IO_SPACE_LIMIT is bumped up to 4G, that's the reason why adding the offset to the ACPI IO resources work on ia64 as far as I understand.

Quoted 6 lines

And that's why I pulled Arnd in this discussion since he knows better than me: what does ioport_resource _really_ represent on ARM64 ? It seems to me that it is a range of IO ports values (ie a window that defines the allowed offset in the virtual address space allocated to PCI IO) that has _nothing_ to do with the CPU physical address at which the IO space is actually mapped.

Correct. The idea is that you can have any number of host bridges and what you get back for an ioport_resource is a window inside the host bridge IO space. That space is also offset-ed inside the kernel's IO port space (0..IO_SPACE_LIMIT) by the amount of space already taken by preceeding host bridges, so that two ioport_resources comming from two different host bridges don't overlap in the CPU address space.

Best regards,
Liviu

Quoted 22 lines

To sum it up for a, say, DWordIo/Memory descriptor:

- AddressMinimum, AddressMaximum represent the PCI bus addresses defining the resource start..end
- AddressTranslation is the offset that has to be added to AddressMinimum and AddressMaximum to get the window in CPU physical address space

So:

- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patch acpi_pci_root_validate_resources() to amend the way IORESOURCE_IO is currently checked against ioport_resource, it can't work on arm64 at present, I described why above

Thoughts appreciated it is time we got this sorted and thanks for the patch.

Thanks,
Lorenzo

Signature · 8 lines
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
#32 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Lorenzo Pieralisi
Quoted 10 lines · On Wednesday 11 November 2015 17:46:47 Lorenzo Pieralisi wrote:

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:
If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

Quoted 7 lines

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI, am I wrong ?

Sinan Kaya pointed out that SBSA mandates a 1:1 mapping for memory space.

Quoted 7 lines

On arm64, IO_SPACE_LIMIT is 16M, which, AFAIK is a kernel limit, not a HW one. Comparing the resources parsed from the PCI bridge _CRS against the range 0..IO_SPACE_LIMIT is not necessarily meaningful (or at least not meaningful in its current form), on ia64 it works because IO_SPACE_LIMIT is bumped up to 4G, that's the reason why adding the offset to the ACPI IO resources work on ia64 as far as I understand.

Quoted 6 lines

And that's why I pulled Arnd in this discussion since he knows better than me: what does ioport_resource _really_ represent on ARM64 ? It seems to me that it is a range of IO ports values (ie a window that defines the allowed offset in the virtual address space allocated to PCI IO) that has _nothing_ to do with the CPU physical address at which the IO space is actually mapped.

Right, the ioport_resource uses the same space as the CPU virtual address, with an offset of PCI_IOBASE that is defined as

#define PCI_IOBASE ((void __iomem *)PCI_IO_VIRT_BASE)

#define PCI_IO_START            (PCI_IO_END - PCI_IO_SIZE)
#define PCI_IO_END              (MODULES_VADDR - SZ_2M)
#define PCI_IO_SIZE             SZ_16M
Quoted 9 lines

To sum it up for a, say, DWordIo/Memory descriptor:

- AddressMinimum, AddressMaximum represent the PCI bus addresses defining the resource start..end
- AddressTranslation is the offset that has to be added to AddressMinimum and AddressMaximum to get the window in CPU physical address space

So:

Quoted 8 lines

- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patch acpi_pci_root_validate_resources() to amend the way IORESOURCE_IO is currently checked against ioport_resource, it can't work on arm64 at present, I described why above

Thoughts appreciated it is time we got this sorted and thanks for the patch.

The easiest way would be to assume that nobody is building a server system that has multiple I/O spaces. SBSA explicitly makes I/O space optional, and really the only reason anyone includes that feature these days is for initializing GPUs through the BIOS POST method, so that is not relevant for servers. Even when you do have multiple PCIe host controllers that all support I/O space, the most logical implementation would be to share one common space.

If that fails, there are still two cases you have to care about, and it really depends on what hardware makers decide to use here (and whether we have any influence over them). The easier way for us to do this is if every hardware sets up the mapping between CPU physical and PCI I/O in a way that the I/O space numbers are non-overlapping between the host controllers. That way we can still make Linux ioport_resource addresses the same as PCI I/O space addresses (using io_offset=0), with the downside being that only the first PCIe host (as enumerated by the bootloader) can have I/O space addresses below 1024 that may be required for ISA compatibility on some hardware.

Arnd

#33 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 14 lines · Arnd Bergmann
Quoted 13 lines · On Wednesday 11 November 2015 17:46:47 Lorenzo Pieralisi wrote:

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:
If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

Quoted 6 lines
Quoted 4 lines

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI, am I wrong ?

Sinan Kaya pointed out that SBSA mandates a 1:1 mapping for memory space.

acpi_decode_space() is generic code though, it has to work on all arches, I was worried about triggering regressions on x86 and ia64 here.

[...]

Quoted 26 lines
Quoted 9 lines

To sum it up for a, say, DWordIo/Memory descriptor:

- AddressMinimum, AddressMaximum represent the PCI bus addresses defining the resource start..end
- AddressTranslation is the offset that has to be added to AddressMinimum and AddressMaximum to get the window in CPU physical address space

So:

Quoted 8 lines

- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patch acpi_pci_root_validate_resources() to amend the way IORESOURCE_IO is currently checked against ioport_resource, it can't work on arm64 at present, I described why above

Thoughts appreciated it is time we got this sorted and thanks for the patch.

The easiest way would be to assume that nobody is building a server system that has multiple I/O spaces. SBSA explicitly makes I/O space optional, and really the only reason anyone includes that feature these days is for initializing GPUs through the BIOS POST method, so that is not relevant for servers. Even when you do have multiple PCIe host controllers that all support I/O space, the most logical implementation would be to share one common space.

Quoted 10 lines

If that fails, there are still two cases you have to care about, and it really depends on what hardware makers decide to use here (and whether we have any influence over them). The easier way for us to do this is if every hardware sets up the mapping between CPU physical and PCI I/O in a way that the I/O space numbers are non-overlapping between the host controllers. That way we can still make Linux ioport_resource addresses the same as PCI I/O space addresses (using io_offset=0), with the downside being that only the first PCIe host (as enumerated by the bootloader) can have I/O space addresses below 1024 that may be required for ISA compatibility on some hardware.

Yes, I think the approach we have in place on arm64 sound, I will work with Jiang to make sure we interpret and manage IO space on arm64 the same way we do with DT, I do not expect any issue on that side, I was more worried about the interpretation of ACPI tables, I really really do not want to end up with ACPI tables that are set-up in a way that can cause regressions, we have to agree (and make it crystal clear in the ACPI specs) what the resource descriptors define and how, then the ACPI kernel resource layer should be made compliant.

Thanks,
Lorenzo

author
#34 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Lorenzo Pieralisi
Quoted 69 lines · Lorenzo Pieralisi

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 50 lines
Quoted 44 lines
Quoted 4 lines

In particular, I would like to understand, for an eg DWordIO descriptor, what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB) range of CPU addresses that gets translated into PCI I/O space the same way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 6 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge map the IO space transactions), I do not think ia64 is any different from arm64 in this respect, if it is please provide an HW description here from the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge tables would help).

The main difference between ia64 and a lot of the other architectures (e.g. sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
        struct io_space *space = &io_space[IO_SPACE_NR(port)];
        return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
        return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
        return readl(PCI_IOBASE + addr);
}
Quoted 6 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual address window at the correct io_offset;

Quoted 5 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

Quoted 7 lines

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI, am I wrong ?

Hi Lorenzo,
I may have found the divergence between us about the design here. You
treat it as a one-stage translation but I treat it as a
two-stage translation as below:
stage 1: map(translate) per-PCI-domain IO port address[0, 16M) into system global IO port address. Here system global IO port address is ioport_resource[0, IO_SPACE_LIMIT).
stage 2: map system IO port address into system memory address.

We need two objects of struct resource_win to support above two-stage translation. One object, type of IORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type of IORESOURCE_MMIO, is used to allocate resource from iomem_resource and setup MMIO mapping to actually access IO ports.

For ARM64, it doesn't support multiple per-PCI-domain(bus local) IO port address space yet, so stage one seems to be optional becomes the offset between bus local IO port address and system IO port address is always 0. But we still need two objects of struct resource_win. The first object is

	{
		offset:0,
		start:AddressMinimum,
		end:AddressMaximum,
		flags:IORESOURCE_IO
	}

Here it's type of IORESOURCE_IO and offset must be zero because pcibios_resource_to_bus() will access it translate system IO port address into bus local IO port address. With my patch, the struct resource_win object created by the ACPI core will be reused for this.

The second object is:

	{
		offset:Translation_Offset,
		start:AddressMinimum + Translation_Offset,
		end:AddressMaximum + Translation_Offset,
		flags:IORESOURCE_MMIO
	}

Arch code need to create the second struct resource_win object and actually setup the MMIO mapping.

But there's really another bug need to get fixed, funciton acpi_dev_ioresource_flags() assumes bus local IO port address space is size of 64K, which is wrong for IA64 and ARM64.

Thanks,
Gerry

Quoted 45 lines

Overall I think the point is related to ioport_resource and its check in acpi_pci_root_validate_resources() which basically that's the problem that started this thread.

On arm64, IO_SPACE_LIMIT is 16M, which, AFAIK is a kernel limit, not a HW one. Comparing the resources parsed from the PCI bridge _CRS against the range 0..IO_SPACE_LIMIT is not necessarily meaningful (or at least not meaningful in its current form), on ia64 it works because IO_SPACE_LIMIT is bumped up to 4G, that's the reason why adding the offset to the ACPI IO resources work on ia64 as far as I understand.

And that's why I pulled Arnd in this discussion since he knows better than me: what does ioport_resource _really_ represent on ARM64 ? It seems to me that it is a range of IO ports values (ie a window that defines the allowed offset in the virtual address space allocated to PCI IO) that has _nothing_ to do with the CPU physical address at which the IO space is actually mapped.

To sum it up for a, say, DWordIo/Memory descriptor:

- AddressMinimum, AddressMaximum represent the PCI bus addresses defining the resource start..end
- AddressTranslation is the offset that has to be added to AddressMinimum and AddressMaximum to get the window in CPU physical address space

So:

- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patch acpi_pci_root_validate_resources() to amend the way IORESOURCE_IO is currently checked against ioport_resource, it can't work on arm64 at present, I described why above

Thoughts appreciated it is time we got this sorted and thanks for the patch.

Thanks,
Lorenzo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#35 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 117 lines · Jiang Liu
Quoted 69 lines · Lorenzo Pieralisi

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 50 lines
Quoted 44 lines
Quoted 4 lines

In particular, I would like to understand, for an eg DWordIO descriptor, what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB) range of CPU addresses that gets translated into PCI I/O space the same way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 6 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge map the IO space transactions), I do not think ia64 is any different from arm64 in this respect, if it is please provide an HW description here from the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge tables would help).

The main difference between ia64 and a lot of the other architectures (e.g. sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
         struct io_space *space = &io_space[IO_SPACE_NR(port)];
         return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
         return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
         return readl(PCI_IOBASE + addr);
}
Quoted 6 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual address window at the correct io_offset;

Quoted 5 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

Quoted 7 lines

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI, am I wrong ?

Hi Lorenzo,
I may have found the divergence between us about the design here. You
treat it as a one-stage translation but I treat it as a
two-stage translation as below:
stage 1: map(translate) per-PCI-domain IO port address[0, 16M) into system global IO port address. Here system global IO port address is ioport_resource[0, IO_SPACE_LIMIT).
stage 2: map system IO port address into system memory address.

We need two objects of struct resource_win to support above two-stage translation. One object, type of IORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type of IORESOURCE_MMIO, is used to allocate resource from iomem_resource and setup MMIO mapping to actually access IO ports.

For ARM64, it doesn't support multiple per-PCI-domain(bus local) IO port address space yet, so stage one seems to be optional becomes the offset between bus local IO port address and system IO port address is always 0. But we still need two objects of struct resource_win. The first object is

	{
		offset:0,
		start:AddressMinimum,
		end:AddressMaximum,
		flags:IORESOURCE_IO
	}

Here it's type of IORESOURCE_IO and offset must be zero because pcibios_resource_to_bus() will access it translate system IO port address into bus local IO port address. With my patch, the struct resource_win object created by the ACPI core will be reused for this.

The second object is:

	{
		offset:Translation_Offset,
		start:AddressMinimum + Translation_Offset,
		end:AddressMaximum + Translation_Offset,
		flags:IORESOURCE_MMIO
	}
Quoted 7 lines

Arch code need to create the second struct resource_win object and actually setup the MMIO mapping.

But there's really another bug need to get fixed, funciton acpi_dev_ioresource_flags() assumes bus local IO port address space is size of 64K, which is wrong for IA64 and ARM64.

So what would be the Translation_Offset meaning for two cases DWordIo (....,TypeTranslation) vs DWordIo (....,TypeStatic)? And why we did not use TypeTranslation for IA64 so far?

I am worried that TypeTranslation fall into the IA64 category but ACPI tables were already written incorrectly.

Tomasz

author
#36 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 136 lines · Tomasz Nowicki
Quoted 135 lines · Jiang Liu
Quoted 85 lines · Lorenzo Pieralisi

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 61 lines
Quoted 53 lines
Quoted 5 lines

In particular, I would like to understand, for an eg DWordIO descriptor,
what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB)
range of CPU addresses that gets translated into PCI I/O space the same
way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 10 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge
map the IO space transactions), I do not think ia64 is any different from
arm64 in this respect, if it is please provide an HW description here from
the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge
tables would help).

The main difference between ia64 and a lot of the other architectures (e.g.
sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function
that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
         struct io_space *space = &io_space[IO_SPACE_NR(port)];
         return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
         return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
         return readl(PCI_IOBASE + addr);
}
Quoted 8 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified
definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual
address window at the correct io_offset;

Quoted 6 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested
yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we
sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

Quoted 6 lines

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space
that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI,
am I wrong ?

Hi Lorenzo,
I may have found the divergence between us about the design here. You
treat it as a one-stage translation but I treat it as a two-stage translation as below:
stage 1: map(translate) per-PCI-domain IO port address[0, 16M) into system global IO port address. Here system global IO port address is ioport_resource[0, IO_SPACE_LIMIT).
stage 2: map system IO port address into system memory address.

We need two objects of struct resource_win to support above two-stage translation. One object, type of IORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type of IORESOURCE_MMIO, is used to allocate resource from iomem_resource and setup MMIO mapping to actually access IO ports.

For ARM64, it doesn't support multiple per-PCI-domain(bus local) IO port address space yet, so stage one seems to be optional becomes the offset between bus local IO port address and system IO port address is always 0. But we still need two objects of struct resource_win. The first object is

    {
        offset:0,
        start:AddressMinimum,
        end:AddressMaximum,
        flags:IORESOURCE_IO
    }

Here it's type of IORESOURCE_IO and offset must be zero because pcibios_resource_to_bus() will access it translate system IO port address into bus local IO port address. With my patch, the struct resource_win object created by the ACPI core will be reused for this.

The second object is:
{
offset:Translation_Offset, start:AddressMinimum + Translation_Offset, end:AddressMaximum + Translation_Offset, flags:IORESOURCE_MMIO
}
Arch code need to create the second struct resource_win object and actually setup the MMIO mapping.

Quoted 8 lines
Quoted 4 lines

But there's really another bug need to get fixed, funciton acpi_dev_ioresource_flags() assumes bus local IO port address space is size of 64K, which is wrong for IA64 and ARM64.

So what would be the Translation_Offset meaning for two cases DWordIo (....,TypeTranslation) vs DWordIo (....,TypeStatic)? And why we did not use TypeTranslation for IA64 so far?

IA64 actually ignores the translation type flag and just assume it's TypeTranslation, so there may be some IA64 BIOS implementations accidentally using TypeStatic. That's why we parsing SparseTranslation flag without checking TranslationType flag. I feel ARM64 may face the same situation as IA64:(

We may expect (TypeStatic, 0-offset) and (TypeTranslation, non-0-offset) in real word. For other two combinations, I haven't found a real usage yet, though theoretically they are possible.

Thanks,
Gerry

Quoted 11 lines

I am worried that TypeTranslation fall into the IA64 category but ACPI tables were already written incorrectly.

Tomasz

Signature · 4 lines
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
#37 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 152 lines · Jiang Liu
Quoted 136 lines · Tomasz Nowicki
Quoted 135 lines · Jiang Liu
Quoted 85 lines · Lorenzo Pieralisi

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 61 lines
Quoted 53 lines
Quoted 5 lines

In particular, I would like to understand, for an eg DWordIO descriptor,
what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB)
range of CPU addresses that gets translated into PCI I/O space the same
way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses different CPU instructions for I/O space compared to the other spaces.

Quoted 10 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so basically that's the CPU physical address at which the PCI host bridge
map the IO space transactions), I do not think ia64 is any different from
arm64 in this respect, if it is please provide an HW description here from
the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge
tables would help).

The main difference between ia64 and a lot of the other architectures (e.g.
sparc is different again) is that ia64 defines a logical address range in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function
that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
          struct io_space *space = &io_space[IO_SPACE_NR(port)];
          return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
          return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
          return readl(PCI_IOBASE + addr);
}
Quoted 8 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified
definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual
address window at the correct io_offset;

Quoted 6 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested
yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we
sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

Quoted 6 lines

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space
that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI,
am I wrong ?

Hi Lorenzo,
I may have found the divergence between us about the design here. You
treat it as a one-stage translation but I treat it as a two-stage translation as below:
stage 1: map(translate) per-PCI-domain IO port address[0, 16M) into system global IO port address. Here system global IO port address is ioport_resource[0, IO_SPACE_LIMIT).
stage 2: map system IO port address into system memory address.

We need two objects of struct resource_win to support above two-stage translation. One object, type of IORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type of IORESOURCE_MMIO, is used to allocate resource from iomem_resource and setup MMIO mapping to actually access IO ports.

For ARM64, it doesn't support multiple per-PCI-domain(bus local) IO port address space yet, so stage one seems to be optional becomes the offset between bus local IO port address and system IO port address is always 0. But we still need two objects of struct resource_win. The first object is

     {
         offset:0,
         start:AddressMinimum,
         end:AddressMaximum,
         flags:IORESOURCE_IO
     }

Here it's type of IORESOURCE_IO and offset must be zero because pcibios_resource_to_bus() will access it translate system IO port address into bus local IO port address. With my patch, the struct resource_win object created by the ACPI core will be reused for this.

The second object is:
{
offset:Translation_Offset, start:AddressMinimum + Translation_Offset, end:AddressMaximum + Translation_Offset, flags:IORESOURCE_MMIO
}
Arch code need to create the second struct resource_win object and actually setup the MMIO mapping.

Quoted 8 lines
Quoted 4 lines

But there's really another bug need to get fixed, funciton acpi_dev_ioresource_flags() assumes bus local IO port address space is size of 64K, which is wrong for IA64 and ARM64.

So what would be the Translation_Offset meaning for two cases DWordIo (....,TypeTranslation) vs DWordIo (....,TypeStatic)? And why we did not use TypeTranslation for IA64 so far?

IA64 actually ignores the translation type flag and just assume it's TypeTranslation, so there may be some IA64 BIOS implementations accidentally using TypeStatic. That's why we parsing SparseTranslation flag without checking TranslationType flag. I feel ARM64 may face the same situation as IA64:(

Quoted 4 lines

We may expect (TypeStatic, 0-offset) and (TypeTranslation, non-0-offset) in real word. For other two combinations, I haven't found a real usage yet, though theoretically they are possible.

I think we should not bend the generic code for IA64 only and expose other platforms to the same issue. Instead, lets interpret spec correctly and create IA64 quirk for the sake of backward compatibility. Thoughts?

Regards,
Tomasz

author
#38 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 164 lines · Tomasz Nowicki
Quoted 158 lines · Jiang Liu
Quoted 142 lines · Tomasz Nowicki
Quoted 141 lines · Jiang Liu
Quoted 90 lines · Lorenzo Pieralisi

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 66 lines
Quoted 58 lines
Quoted 5 lines

In particular, I would like to understand, for an eg DWordIO descriptor,
what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB)
range of CPU addresses that gets translated into PCI I/O space the same
way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses
different CPU instructions for I/O space compared to the other spaces.

Quoted 11 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so
basically that's the CPU physical address at which the PCI host bridge
map the IO space transactions), I do not think ia64 is any different from
arm64 in this respect, if it is please provide an HW description here from
the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge
tables would help).

The main difference between ia64 and a lot of the other architectures (e.g.
sparc is different again) is that ia64 defines a logical address range
in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function
that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
          struct io_space *space = &io_space[IO_SPACE_NR(port)];
          return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
          return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed
virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
          return readl(PCI_IOBASE + addr);
}
Quoted 8 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified
definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual
address window at the correct io_offset;

Quoted 6 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested
yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we
sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

Quoted 6 lines

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space
that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI,
am I wrong ?

Hi Lorenzo,
I may have found the divergence between us about the design
here. You
treat it as a one-stage translation but I treat it as a two-stage translation as below:
stage 1: map(translate) per-PCI-domain IO port address[0, 16M) into system global IO port address. Here system global IO port address is ioport_resource[0, IO_SPACE_LIMIT).
stage 2: map system IO port address into system memory address.

We need two objects of struct resource_win to support above two-stage translation. One object, type of IORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type of IORESOURCE_MMIO, is used to allocate resource from iomem_resource and setup MMIO mapping to actually access IO ports.

For ARM64, it doesn't support multiple per-PCI-domain(bus local) IO port address space yet, so stage one seems to be optional becomes the offset between bus local IO port address and system IO port address is always 0. But we still need two objects of struct resource_win. The first object is

     {
         offset:0,
         start:AddressMinimum,
         end:AddressMaximum,
         flags:IORESOURCE_IO
     }

Here it's type of IORESOURCE_IO and offset must be zero because pcibios_resource_to_bus() will access it translate system IO port address into bus local IO port address. With my patch, the struct resource_win object created by the ACPI core will be reused for this.

The second object is:
{
offset:Translation_Offset, start:AddressMinimum + Translation_Offset, end:AddressMaximum + Translation_Offset, flags:IORESOURCE_MMIO
}
Arch code need to create the second struct resource_win object and actually setup the MMIO mapping.

Quoted 8 lines
Quoted 4 lines

But there's really another bug need to get fixed, funciton acpi_dev_ioresource_flags() assumes bus local IO port address space is size of 64K, which is wrong for IA64 and ARM64.

So what would be the Translation_Offset meaning for two cases DWordIo (....,TypeTranslation) vs DWordIo (....,TypeStatic)? And why we did not use TypeTranslation for IA64 so far?

IA64 actually ignores the translation type flag and just assume it's TypeTranslation, so there may be some IA64 BIOS implementations accidentally using TypeStatic. That's why we parsing SparseTranslation flag without checking TranslationType flag. I feel ARM64 may face the same situation as IA64:(

Quoted 4 lines

We may expect (TypeStatic, 0-offset) and (TypeTranslation, non-0-offset) in real word. For other two combinations, I haven't found a real usage yet, though theoretically they are possible.

Quoted 4 lines

I think we should not bend the generic code for IA64 only and expose other platforms to the same issue. Instead, lets interpret spec correctly and create IA64 quirk for the sake of backward compatibility. Thoughts?

I think there are at least two factors related to this issue.

First we still lack of a way/framework to fix errors in ACPI resource descriptors. Recently we have refined ACPI resource parsing interfaces and enforced strictly sanity check. This brings us some regressions which are really BIOS flaws, but it used to work and now breaks:( I'm still struggling to get those regressions fixed. So we may run into the same situation if we enforce strict check for TranslationType:(

Second enforcing strict check doesn't bring us too much benifits. Translation type is almost platform specific, and we haven't found a platform support both TypeTranslation and TypeStatic, so arch code may assume the correct translation type no matter what BIOS reports. So it won't hurt us even BIOS reports wrong translation type.

So I'm tending to keep current implementation with looser checking, otherwise it may cause regressions.
Thanks,
Gerry

#39 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 178 lines · Jiang Liu
Quoted 164 lines · Tomasz Nowicki
Quoted 158 lines · Jiang Liu
Quoted 142 lines · Tomasz Nowicki
Quoted 141 lines · Jiang Liu
Quoted 90 lines · Lorenzo Pieralisi

On Tue, Nov 10, 2015 at 01:50:46PM +0800, Jiang Liu wrote:

[...]

Quoted 66 lines
Quoted 58 lines
Quoted 5 lines

In particular, I would like to understand, for an eg DWordIO descriptor,
what Range Minimum, Range Maximum and Translation Offset represent, they can't mean different things depending on the SW parsing them, this totally defeats the purpose.

I have no clue about what those mean in ACPI though.

Generally speaking, each PCI domain is expected to have a (normally 64KB)
range of CPU addresses that gets translated into PCI I/O space the same
way that config space and memory space are handled.
This is true for almost every architecture except for x86, which uses
different CPU instructions for I/O space compared to the other spaces.

Quoted 11 lines

By the way, ia64 ioremaps the translation_offset (ie new_space()), so
basically that's the CPU physical address at which the PCI host bridge
map the IO space transactions), I do not think ia64 is any different from
arm64 in this respect, if it is please provide an HW description here from
the PCI bus perspective here (also an example of ia64 ACPI PCI host bridge
tables would help).

The main difference between ia64 and a lot of the other architectures (e.g.
sparc is different again) is that ia64 defines a logical address range
in terms of having a small number for each I/O space followed by the offset within that space as a 'port number' and uses a mapping function
that is defined as

static inline void *__ia64_mk_io_addr (unsigned long port)

{
           struct io_space *space = &io_space[IO_SPACE_NR(port)];
           return (space->mmio_base | IO_SPACE_PORT(port););
}
static inline unsigned int inl(unsigned long port)
{
           return *__ia64_mk_io_addr(port);
}

Most architectures allow only one I/O port range and put it at a fixed
virtual address so that inl() simply becomes

static inline u32 inl(unsigned long addr)

{
           return readl(PCI_IOBASE + addr);
}
Quoted 8 lines

which noticeably reduces code size.

On some architectures (powerpc, arm, arm64), we then get the same simplified
definition with a fixed virtual address, and use pci_ioremap_io() or something like that to to map a physical address range into this virtual
address window at the correct io_offset;

Quoted 6 lines

Hi all,
Thanks for explanation, I found a way to make the ACPI resource
parsing interface arch neutral, it should help to address Lorenzo's concern. Please refer to the attached patch. (It's still RFC, not tested
yet).

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we
sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

Quoted 6 lines

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space
that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI,
am I wrong ?

Hi Lorenzo,
I may have found the divergence between us about the design
here. You
treat it as a one-stage translation but I treat it as a two-stage translation as below:
stage 1: map(translate) per-PCI-domain IO port address[0, 16M) into system global IO port address. Here system global IO port address is ioport_resource[0, IO_SPACE_LIMIT).
stage 2: map system IO port address into system memory address.

We need two objects of struct resource_win to support above two-stage translation. One object, type of IORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type of IORESOURCE_MMIO, is used to allocate resource from iomem_resource and setup MMIO mapping to actually access IO ports.

For ARM64, it doesn't support multiple per-PCI-domain(bus local) IO port address space yet, so stage one seems to be optional becomes the offset between bus local IO port address and system IO port address is always 0. But we still need two objects of struct resource_win. The first object is

      {
          offset:0,
          start:AddressMinimum,
          end:AddressMaximum,
          flags:IORESOURCE_IO
      }

Here it's type of IORESOURCE_IO and offset must be zero because pcibios_resource_to_bus() will access it translate system IO port address into bus local IO port address. With my patch, the struct resource_win object created by the ACPI core will be reused for this.

The second object is:
{
offset:Translation_Offset, start:AddressMinimum + Translation_Offset, end:AddressMaximum + Translation_Offset, flags:IORESOURCE_MMIO
}
Arch code need to create the second struct resource_win object and actually setup the MMIO mapping.

Quoted 8 lines
Quoted 4 lines

But there's really another bug need to get fixed, funciton acpi_dev_ioresource_flags() assumes bus local IO port address space is size of 64K, which is wrong for IA64 and ARM64.

So what would be the Translation_Offset meaning for two cases DWordIo (....,TypeTranslation) vs DWordIo (....,TypeStatic)? And why we did not use TypeTranslation for IA64 so far?

IA64 actually ignores the translation type flag and just assume it's TypeTranslation, so there may be some IA64 BIOS implementations accidentally using TypeStatic. That's why we parsing SparseTranslation flag without checking TranslationType flag. I feel ARM64 may face the same situation as IA64:(

Quoted 4 lines

We may expect (TypeStatic, 0-offset) and (TypeTranslation, non-0-offset) in real word. For other two combinations, I haven't found a real usage yet, though theoretically they are possible.

Quoted 4 lines

I think we should not bend the generic code for IA64 only and expose other platforms to the same issue. Instead, lets interpret spec correctly and create IA64 quirk for the sake of backward compatibility. Thoughts?

I think there are at least two factors related to this issue.

First we still lack of a way/framework to fix errors in ACPI resource descriptors. Recently we have refined ACPI resource parsing interfaces and enforced strictly sanity check. This brings us some regressions which are really BIOS flaws, but it used to work and now breaks:( I'm still struggling to get those regressions fixed. So we may run into the same situation if we enforce strict check for TranslationType:(

Quoted 6 lines

Second enforcing strict check doesn't bring us too much benifits. Translation type is almost platform specific, and we haven't found a platform support both TypeTranslation and TypeStatic, so arch code may assume the correct translation type no matter what BIOS reports. So it won't hurt us even BIOS reports wrong translation type.

That is my point, lets pass down all we need from resource range descriptors to arch code, then archs with known quirks can whatever is needed to make it works. However, generic code like acpi_decode_space cannot play with offsets with silent IA64 assumption.

To sum it up, your last patch looks ok to me modulo Lorenzo's concern:

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we
sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU physical address) and secondary bus (ie PCI bus address).

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space
that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI,
am I wrong ?

His concern is that your patch will cause:
acpi_pci_root_validate_resources(&device->dev, list,

				 IORESOURCE_MEM);

to fail now.

Regards,
Tomasz

#40 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Please trim your emails, thanks.

Quoted 1 line · Tomasz Nowicki

On 12.11.2015 16:05, Jiang Liu wrote:

[...]

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

IA64 actually ignores the translation type flag and just assume it's TypeTranslation, so there may be some IA64 BIOS implementations accidentally using TypeStatic. That's why we parsing SparseTranslation flag without checking TranslationType flag. I feel ARM64 may face the same situation as IA64:(

We may expect (TypeStatic, 0-offset) and (TypeTranslation, non-0-offset) in real word. For other two combinations, I haven't found a real usage yet, though theoretically they are possible.

I do not understand why (TypeStatic, non-0-offset) is not a valid option. Aren't there any (x86) platforms with a CPU<->PCI _physical_ address space offset out there (I am talking about memory space) ?

Quoted 13 lines
Quoted 13 lines
Quoted 4 lines

I think we should not bend the generic code for IA64 only and expose other platforms to the same issue. Instead, lets interpret spec correctly and create IA64 quirk for the sake of backward compatibility. Thoughts?

I think there are at least two factors related to this issue.

First we still lack of a way/framework to fix errors in ACPI resource descriptors. Recently we have refined ACPI resource parsing interfaces and enforced strictly sanity check. This brings us some regressions which are really BIOS flaws, but it used to work and now breaks:( I'm still struggling to get those regressions fixed. So we may run into the same situation if we enforce strict check for TranslationType:(

Quoted 5 lines
Quoted 5 lines

Second enforcing strict check doesn't bring us too much benifits. Translation type is almost platform specific, and we haven't found a platform support both TypeTranslation and TypeStatic, so arch code may assume the correct translation type no matter what BIOS reports. So it won't hurt us even BIOS reports wrong translation type.

TBH I still do not understand what TranslationType actually means, I will ask whoever added that to the specification to understand it.

Quoted 27 lines

That is my point, lets pass down all we need from resource range descriptors to arch code, then archs with known quirks can whatever is needed to make it works. However, generic code like acpi_decode_space cannot play with offsets with silent IA64 assumption.

To sum it up, your last patch looks ok to me modulo Lorenzo's concern:

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we
sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU

physical

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

address) and secondary bus (ie PCI bus address).

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space
that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI,
am I wrong ?

Quoted 4 lines

His concern is that your patch will cause:
acpi_pci_root_validate_resources(&device->dev, list,

				 IORESOURCE_MEM);

to fail now.

Not really. My concern is that there might be platforms out there with an offset between the CPU and PCI physical address spaces, and if we remove the offset value in acpi_decode_space we can break them, because in the kernel struct resource data we have to have CPU physical addresses, not PCI ones. If offset == 0, we are home and dry, I do not understand why that's a given, which is what we would assume if Jiang's patch is merged as-is unless I am mistaken.

Thanks,
Lorenzo

author
#41 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 13 lines · Lorenzo Pieralisi

Please trim your emails, thanks.

Quoted 1 line · Tomasz Nowicki

On 12.11.2015 16:05, Jiang Liu wrote:

[...]

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

IA64 actually ignores the translation type flag and just assume it's TypeTranslation, so there may be some IA64 BIOS implementations accidentally using TypeStatic. That's why we parsing SparseTranslation flag without checking TranslationType flag. I feel ARM64 may face the same situation as IA64:(

Quoted 7 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

We may expect (TypeStatic, 0-offset) and (TypeTranslation, non-0-offset) in real word. For other two combinations, I haven't found a real usage yet, though theoretically they are possible.

I do not understand why (TypeStatic, non-0-offset) is not a valid option. Aren't there any (x86) platforms with a CPU<->PCI _physical_ address space offset out there (I am talking about memory space) ?

It's possible, but we have found such a design yet. If we eventually encounter such a case, we need to enhance x86 specific code to support it.

Quoted 55 lines
Quoted 14 lines
Quoted 14 lines
Quoted 5 lines

I think we should not bend the generic code for IA64 only and expose other platforms to the same issue. Instead, lets interpret spec correctly and create IA64 quirk for the sake of backward compatibility. Thoughts?

I think there are at least two factors related to this issue.

First we still lack of a way/framework to fix errors in ACPI resource descriptors. Recently we have refined ACPI resource parsing interfaces and enforced strictly sanity check. This brings us some regressions which are really BIOS flaws, but it used to work and now breaks:( I'm still struggling to get those regressions fixed. So we may run into the same situation if we enforce strict check for TranslationType:(

Quoted 5 lines
Quoted 5 lines

Second enforcing strict check doesn't bring us too much benifits. Translation type is almost platform specific, and we haven't found a platform support both TypeTranslation and TypeStatic, so arch code may assume the correct translation type no matter what BIOS reports. So it won't hurt us even BIOS reports wrong translation type.

TBH I still do not understand what TranslationType actually means, I will ask whoever added that to the specification to understand it.

Quoted 27 lines

That is my point, lets pass down all we need from resource range descriptors to arch code, then archs with known quirks can whatever is needed to make it works. However, generic code like acpi_decode_space cannot play with offsets with silent IA64 assumption.

To sum it up, your last patch looks ok to me modulo Lorenzo's concern:

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

If we go with this approach though, you are not adding the offset to the resource when parsing the memory spaces in acpi_decode_space(), are we
sure that's what we really want ?

In DT, a host bridge range has a:

- CPU physical address
- PCI bus address

We use that to compute the offset between primary bus (ie CPU

physical

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

address) and secondary bus (ie PCI bus address).

The value ending up in the PCI resource struct (for memory space) is the CPU physical address, if you do not add the offset in acpi_decode_space
that does not hold true on platforms where CPU<->PCI offset != 0 on ACPI,
am I wrong ?

Quoted 4 lines

His concern is that your patch will cause:
acpi_pci_root_validate_resources(&device->dev, list,

				 IORESOURCE_MEM);

to fail now.

Quoted 7 lines

Not really. My concern is that there might be platforms out there with an offset between the CPU and PCI physical address spaces, and if we remove the offset value in acpi_decode_space we can break them, because in the kernel struct resource data we have to have CPU physical addresses, not PCI ones. If offset == 0, we are home and dry, I do not understand why that's a given, which is what we would assume if Jiang's patch is merged as-is unless I am mistaken.

We try to exclude offset from struct resource in generic ACPI code, and it's the arch's responsibility to decide how to manipulate struct resource object if offset is not zero.

Currently offset is always zero for x86, and IA64 has arch specific code to handle non-zero offset. So we should be safe without breaking existing code. For ARM64, it's a little different from IA64 so it's hard to share code between IA64 and ARM64.

Quoted 4 lines

Thanks,
Lorenzo

#42 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Hi Jiang,

On Sat, Nov 14, 2015 at 01:49:08AM +0800, Jiang Liu wrote:

[...]

Quoted 7 lines
Quoted 7 lines

Not really. My concern is that there might be platforms out there with an offset between the CPU and PCI physical address spaces, and if we remove the offset value in acpi_decode_space we can break them, because in the kernel struct resource data we have to have CPU physical addresses, not PCI ones. If offset == 0, we are home and dry, I do not understand why that's a given, which is what we would assume if Jiang's patch is merged as-is unless I am mistaken.

Quoted 8 lines

We try to exclude offset from struct resource in generic ACPI code, and it's the arch's responsibility to decide how to manipulate struct resource object if offset is not zero.

Currently offset is always zero for x86, and IA64 has arch specific code to handle non-zero offset. So we should be safe without breaking existing code. For ARM64, it's a little different from IA64 so it's hard to share code between IA64 and ARM64.

Can you drop the patch on the mailing lists please, we actually need it to get ACPI ARM64 PCIe support in the kernel, please let me know how you want to handle this and if you need any help.

Thanks,
Lorenzo

#43 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

Quoted 17 lines · Lorenzo Pieralisi

Hi Jiang,

On Sat, Nov 14, 2015 at 01:49:08AM +0800, Jiang Liu wrote:

[...]

Quoted 11 lines
Quoted 7 lines

Not really. My concern is that there might be platforms out there with an offset between the CPU and PCI physical address spaces, and if we remove the offset value in acpi_decode_space we can break them, because in the kernel struct resource data we have to have CPU physical addresses, not PCI ones. If offset == 0, we are home and dry, I do not understand why that's a given, which is what we would assume if Jiang's patch is merged as-is unless I am mistaken.

We try to exclude offset from struct resource in generic ACPI code, and it's the arch's responsibility to decide how to manipulate struct resource object if offset is not zero.

Quoted 9 lines
Quoted 4 lines

Currently offset is always zero for x86, and IA64 has arch specific code to handle non-zero offset. So we should be safe without breaking existing code. For ARM64, it's a little different from IA64 so it's hard to share code between IA64 and ARM64.

Can you drop the patch on the mailing lists please, we actually need it to get ACPI ARM64 PCIe support in the kernel, please let me know how you want to handle this and if you need any help.

Kindly reminder.

Regards,
Tomasz

#44 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Jiang Liu

On Fri, Nov 06, 2015 at 04:52:47PM +0800, Jiang Liu wrote:

[...]

Quoted 66 lines
Quoted 59 lines
Quoted 37 lines
Quoted 19 lines
drivers/acpi/pci_root.c +19 -0
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
				 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

Quoted 7 lines

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Confusing, to say the least. Jiang, did I get it right ?

Quoted 10 lines

Hi Lorenzo and Tomasz,
With a cup of coffee, I got myself awake eventually:)
Now we are going to talk about IO port on IA64, really a little complex:( Actually there are two types of translation.
1) A PCI domain has a 24-bit IO port address space, there may be multiple IO port address spaces in systems with multiple PCI domains. So the first type of translation is to translate domain specific IO port address into system global IO port address (iomem_resource) by
res->start = acpi_des->start + acpi_des->translation_offset

And that's what I do not understand, or better I do not understand why the acpi_pci_root_validate_resources (for IO) does not fail on ia64, since that should work as arm64, namely IO ports are mapped through MMIO.

I think the check in acpi_pci_root_validate_resources() (for IORESOURCE_IO) fails at present on ia64 too, correct ?

If not, how can it work ? res->start definitely contains the CPU physical address mapping IO space after adding the translation_offset, so the check in acpi_pci_root_validate_resources() for IO can't succeed.

In add_io_space() ia64 does the same thing as Tomasz has to do, namely overwriting the res->start and end with the offset into the virtual address space allocated for IO, which is different from the CPU physical address allocated to IO space.

Please correct me if I am wrong.

Quoted 5 lines

2) IA64 needs to map IO port address spaces into MMIO address space because it has no instructions to access IO ports directly. So IA64 has reserved a MMIO range to map IO port address spaces. This type of translation relies on architecture specific information instead of ACPI descriptors.

That's how ARM64 works too, the IO space resources are an offset into a chunk of virtual address space allocated to PCI IO memory, so it seems to me that arm64 and ia64 should work the same way, and that at present acpi_pci_root_validate_resources() should fail on ia64 too.

Thanks,
Lorenzo

Quoted 13 lines

On the other hand, ACPI specification has defined "I/O to Memory Translation" flag and "Memory to I/O Translation" flag in ACPI Extended Address Space Descriptor, but current implementation doesn't really support such a use case. So we need to find a way out here. Could you please help to provide more information about PCI host bridge resource descriptor implementation details on ARM64?

Quoted 3 lines

Lorenzo

#45 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Lorenzo Pieralisi
Quoted 121 lines · Lorenzo Pieralisi
Quoted 1 line · Tomasz Nowicki

On 14.10.2015 08:29, Jiang Liu wrote:

[...]

Quoted 100 lines
Quoted 82 lines
drivers/acpi/pci_root.c +82 -0
+static void acpi_pci_root_validate_resources(struct device *dev,
+					     struct list_head *resources,
+					     unsigned long type)
+{
+	LIST_HEAD(list);
+	struct resource *res1, *res2, *root = NULL;
+	struct resource_entry *tmp, *entry, *entry2;
+
+	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+	list_splice_init(resources, &list);
+	resource_list_for_each_entry_safe(entry, tmp, &list) {
+		bool free = false;
+		resource_size_t end;
+
+		res1 = entry->res;
+		if (!(res1->flags & type))
+			goto next;
+
+		/* Exclude non-addressable range or non-addressable portion */
+		end = min(res1->end, root->end);
+		if (end <= res1->start) {
+			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
+				 res1);
+			free = true;
+			goto next;
+		} else if (res1->end != end) {
+			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
+				 res1, (unsigned long long)end + 1,
+				 (unsigned long long)res1->end);
+			res1->end = end;
+		}
+
+		resource_list_for_each_entry(entry2, resources) {
+			res2 = entry2->res;
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_overlaps(res1, res2)) {
+				res2->start = min(res1->start, res2->start);
+				res2->end = max(res1->end, res2->end);
+				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
+					 res2, res1);
+				free = true;
+				goto next;
+			}
+		}
+
+next:
+		resource_list_del(entry);
+		if (free)
+			resource_list_free_entry(entry);
+		else
+			resource_list_add_tail(entry, resources);
+	}
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+	int ret;
+	struct list_head *list = &info->resources;
+	struct acpi_device *device = info->bridge;
+	struct resource_entry *entry, *tmp;
+	unsigned long flags;
+
+	flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+	ret = acpi_dev_get_resources(device, list,
+				     acpi_dev_filter_resource_type_cb,
+				     (void *)flags);
+	if (ret < 0)
+		dev_warn(&device->dev,
+			 "failed to parse _CRS method, error code %d\n", ret);
+	else if (ret == 0)
+		dev_dbg(&device->dev,
+			"no IO and memory resources present in _CRS\n");
+	else {

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 10 lines
drivers/acpi/pci_root.c +10 -0
+		resource_list_for_each_entry_safe(entry, tmp, list) {
+			if (entry->res->flags & IORESOURCE_DISABLED)
+				resource_list_destroy_entry(entry);
+			else
+				entry->res->name = info->name;
+		}
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_MEM);
+		acpi_pci_root_validate_resources(&device->dev, list,
+						 IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

Quoted 5 lines
				 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

IIUC, you _have_ to have the proper translation_offset to map the bridge window into the IO address space:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-June/348708.html

Then, using the offset, you should do something ia64 does, namely, retrieve the CPU address corresponding to IO space (see arch/ia64/pci/pci.c
- add_io_space()) and map it in the physical address space by using pci_remap_iospace(), it is similar to what we have to do with DT.

Quoted 5 lines

It is extremely confusing and I am not sure I got it right myself, I am still grokking ia64 code to understand what it really does.

So basically, the IO bridge window coming from acpi_dev_get_resource() should represent the IO space in 0 - 16M, IIUC.

Yes, you are right IMO.

Quoted 7 lines

By using the offset (that was initialized using translation_offset) and the resource->start, you can retrieve the cpu address that you need to actually map the IO space, since that's what we do on ARM (ie the IO resource is an offset into the virtual address space set aside for IO).

Right, that is clear to me, below my current implementation example which works for ARM64 now:

static struct acpi_pci_root_ops acpi_pci_root_ops = { [...]
.prepare_resources = pci_acpi_root_prepare_resources,
};

static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)

{
	struct list_head *list = &ci->resources;
	struct acpi_device *device = ci->bridge;
	struct resource_entry *entry, *tmp;
	unsigned long flags;
	int ret;

	flags = IORESOURCE_IO | IORESOURCE_MEM;
	ret = acpi_dev_get_resources(device, list,
				     acpi_dev_filter_resource_type_cb,
				     (void *)flags);
	if (ret < 0) {
		dev_warn(&device->dev,
			 "failed to parse _CRS method, error code %d\n", ret);
		return ret;
	} else if (ret == 0)
		dev_dbg(&device->dev,
			"no IO and memory resources present in _CRS\n");

	resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
		struct resource *res = entry->res;

		if (entry->res->flags & IORESOURCE_DISABLED)
			resource_list_destroy_entry(entry);
		else
			res->name = ci->name;

		/*
		 * TODO: need to move pci_register_io_range() function out
		 * of drivers/of/address.c for both used by DT and ACPI
		 */
		if (res->flags & IORESOURCE_IO) {
			unsigned long port;
			int err;
			resource_size_t length = res->end - res->start;
			resource_size_t start = res->start;

			err = pci_register_io_range(res->start, length);
			if (err) {
				resource_list_destroy_entry(entry);
				continue;
			}

			port = pci_address_to_pio(res->start);
			if (port == (unsigned long)-1) {
				resource_list_destroy_entry(entry);
				continue;
			}

			res->start = port;
			res->end = res->start + length;
			entry->offset = port - (start - entry->offset);

			if (pci_remap_iospace(res, start) < 0)
				resource_list_destroy_entry(entry);
		}
	}
	return ret;
}

As you see acpi_dev_get_resources returns:
res->start = acpi_des->start + acpi_des->translation_offset (CPU address) which then must be adjusted as you described to get io port and call pci_remap_iospace.

This is also why I can not use acpi_pci_probe_root_resources here. Lets assume we have IO range like that DSDT table form QEMU:
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,

         0x00000000,         // Granularity
         0x00000000,         // Range Minimum
         0x0000FFFF,         // Range Maximum
         0x3EFF0000,         // Translation Offset
         0x00010000,         // Length

,, , TypeStatic)
so see acpi_dev_get_resources returns res->start = acpi_des->start (0x0) + acpi_des->translation_offset(0x3EFF0000) = 0x3EFF0000. This will be rejected in acpi_pci_root_validate_resources() as 0x3EFF0000 does not fit within 0-16M.

My question is if acpi_pci_probe_root_resources is handling translation_offset properly and if we have some silent assumption specific for e.g. ia64 here.

Thanks for help in looking at it.

Tomasz

author
#46 lore raw

Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()

In reply to Tomasz Nowicki
Quoted 120 lines · Tomasz Nowicki
Quoted 119 lines · Jiang Liu

Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future.

---
  drivers/acpi/pci_root.c  |  204
++++++++++++++++++++++++++++++++++++++++++++++
  include/linux/pci-acpi.h |   24 ++++++
  2 files changed, 228 insertions(+)
drivers/acpi/pci_root.c +53 -0
index 393706a5261b..850d7bf0c873 100644
@@ -652,6 +652,210 @@ static void acpi_pci_root_remove(struct
 acpi_device *device)
      kfree(root);
  }
 
+/*
+ * Following code to support acpi_pci_root_create() is copied from
+ * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64
+ * and ARM64.
+ */
+static void acpi_pci_root_validate_resources(struct device *dev,
+                         struct list_head *resources,
+                         unsigned long type)
+{
+    LIST_HEAD(list);
+    struct resource *res1, *res2, *root = NULL;
+    struct resource_entry *tmp, *entry, *entry2;
+
+    BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
+    root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
+
+    list_splice_init(resources, &list);
+    resource_list_for_each_entry_safe(entry, tmp, &list) {
+        bool free = false;
+        resource_size_t end;
+
+        res1 = entry->res;
+        if (!(res1->flags & type))
+            goto next;
+
+        /* Exclude non-addressable range or non-addressable portion */
+        end = min(res1->end, root->end);
+        if (end <= res1->start) {
+            dev_info(dev, "host bridge window %pR (ignored, not CPU
 addressable)\n",
+                 res1);
+            free = true;
+            goto next;
+        } else if (res1->end != end) {
+            dev_info(dev, "host bridge window %pR ([%#llx-%#llx]
 ignored, not CPU addressable)\n",
+                 res1, (unsigned long long)end + 1,
+                 (unsigned long long)res1->end);
+            res1->end = end;
+        }
+
+        resource_list_for_each_entry(entry2, resources) {
+            res2 = entry2->res;
+            if (!(res2->flags & type))
+                continue;
+
+            /*
+             * I don't like throwing away windows because then
+             * our resources no longer match the ACPI _CRS, but
+             * the kernel resource tree doesn't allow overlaps.
+             */
+            if (resource_overlaps(res1, res2)) {
+                res2->start = min(res1->start, res2->start);
+                res2->end = max(res1->end, res2->end);
+                dev_info(dev, "host bridge window expanded to %pR;

%pR ignored\n",

drivers/acpi/pci_root.c +39 -0
+                     res2, res1);
+                free = true;
+                goto next;
+            }
+        }
+
+next:
+        resource_list_del(entry);
+        if (free)
+            resource_list_free_entry(entry);
+        else
+            resource_list_add_tail(entry, resources);
+    }
+}
+
+int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+{
+    int ret;
+    struct list_head *list = &info->resources;
+    struct acpi_device *device = info->bridge;
+    struct resource_entry *entry, *tmp;
+    unsigned long flags;
+
+    flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
+    ret = acpi_dev_get_resources(device, list,
+                     acpi_dev_filter_resource_type_cb,
+                     (void *)flags);
+    if (ret < 0)
+        dev_warn(&device->dev,
+             "failed to parse _CRS method, error code %d\n", ret);
+    else if (ret == 0)
+        dev_dbg(&device->dev,
+            "no IO and memory resources present in _CRS\n");
+    else {
+        resource_list_for_each_entry_safe(entry, tmp, list) {
+            if (entry->res->flags & IORESOURCE_DISABLED)
+                resource_list_destroy_entry(entry);
+            else
+                entry->res->name = info->name;
Quoted 8 lines

drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 751

Quoted 5 lines
drivers/acpi/pci_root.c +5 -0
+        }
+        acpi_pci_root_validate_resources(&device->dev, list,
+                         IORESOURCE_MEM);
+        acpi_pci_root_validate_resources(&device->dev, list,
+                         IORESOURCE_IO);

It is not clear to me why we need these two calls above ^^^. We are using pci_acpi_root_add_resources(info) later. Is it not enough?

Hi Tomasz,
acpi_pci_root_validate_resources() will try adjust (or fix)
conflicting resources among all resources of the PCI host bridge, but pci_acpi_root_add_resources() only rejects conflicting resources.

Quoted 10 lines

Also, I cannot use acpi_pci_probe_root_resources() in my ARM64 PCI driver. It is because acpi_dev_get_resources is adding translation_offset to IO ranges start address and then:
acpi_pci_root_validate_resources(&device->dev, list,

                 IORESOURCE_IO);

rejects that IO regions as it is out of my 0x0-SZ_16M window.

Does acpi_pci_probe_root_resources meant to be x86 specific and I should avoid using it?

It should be generic, but we have some issue in support of translation_offset. I'm trying to get this fixed. Thanks,
Gerry

Quoted 3 lines

Thanks,
Tomasz

author
#47 lore raw

PATCH v7 5/7 ACPI, PCI: Reset acpi_root_dev->domain to 0 when pci_ignore_seg is set

In reply to Jiang Liu

Reset acpi_root_dev->domain to 0 when pci_ignore_seg is set to keep consistence between ACPI PCI root device and PCI host bridge device.

---
 arch/x86/pci/acpi.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/pci/acpi.c +1 -1
index ff9911707160..5bc018559cc4 100644
@@ -401,7 +401,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 	int node;
 
 	if (pci_ignore_seg)
-		domain = 0;
+		root->segment = domain = 0;
 
 	if (domain && !pci_domains_supported) {
 		printk(KERN_WARNING "pci_bus %04x:%02x: "
Signature · 1 line
1.7.10.4
author
#48 lore raw

PATCH v7 6/7 x86/PCI/ACPI: Use common interface to support PCI host bridge

In reply to Jiang Liu

Use common interface to simplify ACPI PCI host bridge implementation.

---
 arch/x86/pci/acpi.c |  294 +++++++++++++++------------------------------------
 1 file changed, 87 insertions(+), 207 deletions(-)
arch/x86/pci/acpi.c +87 -207
index 5bc018559cc4..3cd69832d7f4 100644
@@ -4,16 +4,15 @@
 #include <linux/irq.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/pci-acpi.h>
 #include <asm/numa.h>
 #include <asm/pci_x86.h>
 
 struct pci_root_info {
-	struct acpi_device *bridge;
-	char name[16];
+	struct acpi_pci_root_info common;
 	struct pci_sysdata sd;
 #ifdef	CONFIG_PCI_MMCONFIG
 	bool mcfg_added;
-	u16 segment;
 	u8 start_bus;
 	u8 end_bus;
 #endif
@@ -178,15 +177,18 @@ static int check_segment(u16 seg, struct device *dev, char *estr)
 	return 0;
 }
 
-static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
-			  u8 end, phys_addr_t addr)
+static int setup_mcfg_map(struct acpi_pci_root_info *ci)
 {
-	int result;
-	struct device *dev = &info->bridge->dev;
+	int result, seg;
+	struct pci_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+	struct device *dev = &ci->bridge->dev;
 
-	info->start_bus = start;
-	info->end_bus = end;
+	info = container_of(ci, struct pci_root_info, common);
+	info->start_bus = (u8)root->secondary.start;
+	info->end_bus = (u8)root->secondary.end;
 	info->mcfg_added = false;
+	seg = info->sd.domain;
 
 	/* return success if MMCFG is not in use */
 	if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
@@ -195,7 +197,8 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
 	if (!(pci_probe & PCI_PROBE_MMCONF))
 		return check_segment(seg, dev, "MMCONFIG is disabled,");
 
-	result = pci_mmconfig_insert(dev, seg, start, end, addr);
+	result = pci_mmconfig_insert(dev, seg, info->start_bus, info->end_bus,
+				     root->mcfg_addr);
 	if (result == 0) {
 		/* enable MMCFG if it hasn't been enabled yet */
 		if (raw_pci_ext_ops == NULL)
@@ -208,134 +211,55 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
 	return 0;
 }
 
-static void teardown_mcfg_map(struct pci_root_info *info)
+static void teardown_mcfg_map(struct acpi_pci_root_info *ci)
 {
+	struct pci_root_info *info;
+
+	info = container_of(ci, struct pci_root_info, common);
 	if (info->mcfg_added) {
-		pci_mmconfig_delete(info->segment, info->start_bus,
-				    info->end_bus);
+		pci_mmconfig_delete(info->sd.domain,
+				    info->start_bus, info->end_bus);
 		info->mcfg_added = false;
 	}
 }
 #else
-static int setup_mcfg_map(struct pci_root_info *info,
-				    u16 seg, u8 start, u8 end,
-				    phys_addr_t addr)
+static int setup_mcfg_map(struct acpi_pci_root_info *ci)
 {
 	return 0;
 }
-static void teardown_mcfg_map(struct pci_root_info *info)
+
+static void teardown_mcfg_map(struct acpi_pci_root_info *ci)
 {
 }
 #endif
 
-static void validate_resources(struct device *dev, struct list_head *crs_res,
-			       unsigned long type)
+static int pci_acpi_root_get_node(struct acpi_pci_root *root)
 {
-	LIST_HEAD(list);
-	struct resource *res1, *res2, *root = NULL;
-	struct resource_entry *tmp, *entry, *entry2;
-
-	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
-	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
-
-	list_splice_init(crs_res, &list);
-	resource_list_for_each_entry_safe(entry, tmp, &list) {
-		bool free = false;
-		resource_size_t end;
-
-		res1 = entry->res;
-		if (!(res1->flags & type))
-			goto next;
-
-		/* Exclude non-addressable range or non-addressable portion */
-		end = min(res1->end, root->end);
-		if (end <= res1->start) {
-			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
-				 res1);
-			free = true;
-			goto next;
-		} else if (res1->end != end) {
-			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
-				 res1, (unsigned long long)end + 1,
-				 (unsigned long long)res1->end);
-			res1->end = end;
-		}
-
-		resource_list_for_each_entry(entry2, crs_res) {
-			res2 = entry2->res;
-			if (!(res2->flags & type))
-				continue;
-
-			/*
-			 * I don't like throwing away windows because then
-			 * our resources no longer match the ACPI _CRS, but
-			 * the kernel resource tree doesn't allow overlaps.
-			 */
-			if (resource_overlaps(res1, res2)) {
-				res2->start = min(res1->start, res2->start);
-				res2->end = max(res1->end, res2->end);
-				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
-					 res2, res1);
-				free = true;
-				goto next;
-			}
-		}
+	int busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
 
-next:
-		resource_list_del(entry);
-		if (free)
-			resource_list_free_entry(entry);
-		else
-			resource_list_add_tail(entry, crs_res);
+	if (node == NUMA_NO_NODE) {
+		node = x86_pci_root_bus_node(busnum);
+		if (node != 0 && node != NUMA_NO_NODE)
+			dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n",
+				node);
 	}
+	if (node != NUMA_NO_NODE && !node_online(node))
+		node = NUMA_NO_NODE;
+
+	return node;
 }
 
-static void add_resources(struct pci_root_info *info,
-			  struct list_head *resources,
-			  struct list_head *crs_res)
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
 {
-	struct resource_entry *entry, *tmp;
-	struct resource *res, *conflict, *root = NULL;
-
-	validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM);
-	validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO);
-
-	resource_list_for_each_entry_safe(entry, tmp, crs_res) {
-		res = entry->res;
-		if (res->flags & IORESOURCE_MEM)
-			root = &iomem_resource;
-		else if (res->flags & IORESOURCE_IO)
-			root = &ioport_resource;
-		else
-			BUG_ON(res);
-
-		conflict = insert_resource_conflict(root, res);
-		if (conflict) {
-			dev_info(&info->bridge->dev,
-				 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
-				 res, conflict->name, conflict);
-			resource_list_destroy_entry(entry);
-		}
-	}
-
-	list_splice_tail(crs_res, resources);
+	return setup_mcfg_map(ci);
 }
 
-static void release_pci_root_info(struct pci_host_bridge *bridge)
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
 {
-	struct resource *res;
-	struct resource_entry *entry;
-	struct pci_root_info *info = bridge->release_data;
-
-	resource_list_for_each_entry(entry, &bridge->windows) {
-		res = entry->res;
-		if (res->parent &&
-		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
-			release_resource(res);
-	}
-
-	teardown_mcfg_map(info);
-	kfree(info);
+	teardown_mcfg_map(ci);
+	kfree(container_of(ci, struct pci_root_info, common));
 }
 
 /*
@@ -358,47 +282,44 @@ static bool resource_is_pcicfg_ioport(struct resource *res)
 		res->start == 0xCF8 && res->end == 0xCFF;
 }
 
-static void probe_pci_root_info(struct pci_root_info *info,
-				struct acpi_device *device,
-				int busnum, int domain,
-				struct list_head *list)
+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
 {
-	int ret;
+	struct acpi_device *device = ci->bridge;
+	int busnum = ci->root->secondary.start;
 	struct resource_entry *entry, *tmp;
+	int status;
 
-	sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
-	info->bridge = device;
-	ret = acpi_dev_get_resources(device, list,
-				     acpi_dev_filter_resource_type_cb,
-				     (void *)(IORESOURCE_IO | IORESOURCE_MEM));
-	if (ret < 0)
-		dev_warn(&device->dev,
-			 "failed to parse _CRS method, error code %d\n", ret);
-	else if (ret == 0)
-		dev_dbg(&device->dev,
-			"no IO and memory resources present in _CRS\n");
-	else
-		resource_list_for_each_entry_safe(entry, tmp, list) {
-			if ((entry->res->flags & IORESOURCE_DISABLED) ||
-			    resource_is_pcicfg_ioport(entry->res))
+	status = acpi_pci_probe_root_resources(ci);
+	if (pci_use_crs) {
+		resource_list_for_each_entry_safe(entry, tmp, &ci->resources)
+			if (resource_is_pcicfg_ioport(entry->res))
 				resource_list_destroy_entry(entry);
-			else
-				entry->res->name = info->name;
-		}
+		return status;
+	}
+
+	resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
+		dev_printk(KERN_DEBUG, &device->dev,
+			   "host bridge window %pR (ignored)\n", entry->res);
+		resource_list_destroy_entry(entry);
+	}
+	x86_pci_root_bus_resources(busnum, &ci->resources);
+
+	return 0;
 }
 
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
+	.pci_ops = &pci_root_ops,
+	.init_info = pci_acpi_root_init_info,
+	.release_info = pci_acpi_root_release_info,
+	.prepare_resources = pci_acpi_root_prepare_resources,
+};
+
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-	struct acpi_device *device = root->device;
-	struct pci_root_info *info;
 	int domain = root->segment;
 	int busnum = root->secondary.start;
-	struct resource_entry *res_entry;
-	LIST_HEAD(crs_res);
-	LIST_HEAD(resources);
+	int node = pci_acpi_root_get_node(root);
 	struct pci_bus *bus;
-	struct pci_sysdata *sd;
-	int node;
 
 	if (pci_ignore_seg)
 		root->segment = domain = 0;
@@ -410,71 +331,33 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 		return NULL;
 	}
 
-	node = acpi_get_node(device->handle);
-	if (node == NUMA_NO_NODE) {
-		node = x86_pci_root_bus_node(busnum);
-		if (node != 0 && node != NUMA_NO_NODE)
-			dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n",
-				node);
-	}
-
-	if (node != NUMA_NO_NODE && !node_online(node))
-		node = NUMA_NO_NODE;
-
-	info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
-	if (!info) {
-		printk(KERN_WARNING "pci_bus %04x:%02x: "
-		       "ignored (out of memory)\n", domain, busnum);
-		return NULL;
-	}
-
-	sd = &info->sd;
-	sd->domain = domain;
-	sd->node = node;
-	sd->companion = device;
-
 	bus = pci_find_bus(domain, busnum);
 	if (bus) {
 		/*
 		 * If the desired bus has been scanned already, replace
 		 * its bus->sysdata.
 		 */
-		memcpy(bus->sysdata, sd, sizeof(*sd));
-		kfree(info);
-	} else {
-		/* insert busn res at first */
-		pci_add_resource(&resources,  &root->secondary);
+		struct pci_sysdata sd = {
+			.domain = domain,
+			.node = node,
+			.companion = root->device
+		};
 
-		/*
-		 * _CRS with no apertures is normal, so only fall back to
-		 * defaults or native bridge info if we're ignoring _CRS.
-		 */
-		probe_pci_root_info(info, device, busnum, domain, &crs_res);
-		if (pci_use_crs) {
-			add_resources(info, &resources, &crs_res);
-		} else {
-			resource_list_for_each_entry(res_entry, &crs_res)
-				dev_printk(KERN_DEBUG, &device->dev,
-					   "host bridge window %pR (ignored)\n",
-					   res_entry->res);
-			resource_list_free(&crs_res);
-			x86_pci_root_bus_resources(busnum, &resources);
-		}
-
-		if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
-				    (u8)root->secondary.end, root->mcfg_addr))
-			bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
-						  sd, &resources);
-
-		if (bus) {
-			pci_scan_child_bus(bus);
-			pci_set_host_bridge_release(
-				to_pci_host_bridge(bus->bridge),
-				release_pci_root_info, info);
-		} else {
-			resource_list_free(&resources);
-			teardown_mcfg_map(info);
-			kfree(info);
+		memcpy(bus->sysdata, &sd, sizeof(sd));
+	} else {
+		struct pci_root_info *info;
+
+		info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
+		if (!info)
+			dev_err(&root->device->dev,
+				"pci_bus %04x:%02x: ignored (out of memory)\n",
+				domain, busnum);
+		else {
+			info->sd.domain = domain;
+			info->sd.node = node;
+			info->sd.companion = root->device;
+			bus = acpi_pci_root_create(root, &acpi_pci_root_ops,
+						   &info->common, &info->sd);
 		}
 	}
 
@@ -487,9 +370,6 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 			pcie_bus_configure_settings(child);
 	}
 
-	if (bus && node != NUMA_NO_NODE)
-		dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
-
 	return bus;
 }
 
Signature · 1 line
1.7.10.4
Acked-by on v7 6/7
#49 lore raw

Re: [Patch v7 6/7] x86/PCI/ACPI: Use common interface to support PCI host bridge

Quoted 5 lines · Jiang Liu

Use common interface to simplify ACPI PCI host bridge implementation.

Quoted 408 lines
---
 arch/x86/pci/acpi.c |  294 +++++++++++++++------------------------------------
 1 file changed, 87 insertions(+), 207 deletions(-)
arch/x86/pci/acpi.c +87 -207
index 5bc018559cc4..3cd69832d7f4 100644
@@ -4,16 +4,15 @@
 #include <linux/irq.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/pci-acpi.h>
 #include <asm/numa.h>
 #include <asm/pci_x86.h>
 
 struct pci_root_info {
-	struct acpi_device *bridge;
-	char name[16];
+	struct acpi_pci_root_info common;
 	struct pci_sysdata sd;
 #ifdef	CONFIG_PCI_MMCONFIG
 	bool mcfg_added;
-	u16 segment;
 	u8 start_bus;
 	u8 end_bus;
 #endif
@@ -178,15 +177,18 @@ static int check_segment(u16 seg, struct device *dev, char *estr)
 	return 0;
 }
 
-static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
-			  u8 end, phys_addr_t addr)
+static int setup_mcfg_map(struct acpi_pci_root_info *ci)
 {
-	int result;
-	struct device *dev = &info->bridge->dev;
+	int result, seg;
+	struct pci_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+	struct device *dev = &ci->bridge->dev;
 
-	info->start_bus = start;
-	info->end_bus = end;
+	info = container_of(ci, struct pci_root_info, common);
+	info->start_bus = (u8)root->secondary.start;
+	info->end_bus = (u8)root->secondary.end;
 	info->mcfg_added = false;
+	seg = info->sd.domain;
 
 	/* return success if MMCFG is not in use */
 	if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
@@ -195,7 +197,8 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
 	if (!(pci_probe & PCI_PROBE_MMCONF))
 		return check_segment(seg, dev, "MMCONFIG is disabled,");
 
-	result = pci_mmconfig_insert(dev, seg, start, end, addr);
+	result = pci_mmconfig_insert(dev, seg, info->start_bus, info->end_bus,
+				     root->mcfg_addr);
 	if (result == 0) {
 		/* enable MMCFG if it hasn't been enabled yet */
 		if (raw_pci_ext_ops == NULL)
@@ -208,134 +211,55 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
 	return 0;
 }
 
-static void teardown_mcfg_map(struct pci_root_info *info)
+static void teardown_mcfg_map(struct acpi_pci_root_info *ci)
 {
+	struct pci_root_info *info;
+
+	info = container_of(ci, struct pci_root_info, common);
 	if (info->mcfg_added) {
-		pci_mmconfig_delete(info->segment, info->start_bus,
-				    info->end_bus);
+		pci_mmconfig_delete(info->sd.domain,
+				    info->start_bus, info->end_bus);
 		info->mcfg_added = false;
 	}
 }
 #else
-static int setup_mcfg_map(struct pci_root_info *info,
-				    u16 seg, u8 start, u8 end,
-				    phys_addr_t addr)
+static int setup_mcfg_map(struct acpi_pci_root_info *ci)
 {
 	return 0;
 }
-static void teardown_mcfg_map(struct pci_root_info *info)
+
+static void teardown_mcfg_map(struct acpi_pci_root_info *ci)
 {
 }
 #endif
 
-static void validate_resources(struct device *dev, struct list_head *crs_res,
-			       unsigned long type)
+static int pci_acpi_root_get_node(struct acpi_pci_root *root)
 {
-	LIST_HEAD(list);
-	struct resource *res1, *res2, *root = NULL;
-	struct resource_entry *tmp, *entry, *entry2;
-
-	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
-	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
-
-	list_splice_init(crs_res, &list);
-	resource_list_for_each_entry_safe(entry, tmp, &list) {
-		bool free = false;
-		resource_size_t end;
-
-		res1 = entry->res;
-		if (!(res1->flags & type))
-			goto next;
-
-		/* Exclude non-addressable range or non-addressable portion */
-		end = min(res1->end, root->end);
-		if (end <= res1->start) {
-			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
-				 res1);
-			free = true;
-			goto next;
-		} else if (res1->end != end) {
-			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
-				 res1, (unsigned long long)end + 1,
-				 (unsigned long long)res1->end);
-			res1->end = end;
-		}
-
-		resource_list_for_each_entry(entry2, crs_res) {
-			res2 = entry2->res;
-			if (!(res2->flags & type))
-				continue;
-
-			/*
-			 * I don't like throwing away windows because then
-			 * our resources no longer match the ACPI _CRS, but
-			 * the kernel resource tree doesn't allow overlaps.
-			 */
-			if (resource_overlaps(res1, res2)) {
-				res2->start = min(res1->start, res2->start);
-				res2->end = max(res1->end, res2->end);
-				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
-					 res2, res1);
-				free = true;
-				goto next;
-			}
-		}
+	int busnum = root->secondary.start;
+	struct acpi_device *device = root->device;
+	int node = acpi_get_node(device->handle);
 
-next:
-		resource_list_del(entry);
-		if (free)
-			resource_list_free_entry(entry);
-		else
-			resource_list_add_tail(entry, crs_res);
+	if (node == NUMA_NO_NODE) {
+		node = x86_pci_root_bus_node(busnum);
+		if (node != 0 && node != NUMA_NO_NODE)
+			dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n",
+				node);
 	}
+	if (node != NUMA_NO_NODE && !node_online(node))
+		node = NUMA_NO_NODE;
+
+	return node;
 }
 
-static void add_resources(struct pci_root_info *info,
-			  struct list_head *resources,
-			  struct list_head *crs_res)
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
 {
-	struct resource_entry *entry, *tmp;
-	struct resource *res, *conflict, *root = NULL;
-
-	validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM);
-	validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO);
-
-	resource_list_for_each_entry_safe(entry, tmp, crs_res) {
-		res = entry->res;
-		if (res->flags & IORESOURCE_MEM)
-			root = &iomem_resource;
-		else if (res->flags & IORESOURCE_IO)
-			root = &ioport_resource;
-		else
-			BUG_ON(res);
-
-		conflict = insert_resource_conflict(root, res);
-		if (conflict) {
-			dev_info(&info->bridge->dev,
-				 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
-				 res, conflict->name, conflict);
-			resource_list_destroy_entry(entry);
-		}
-	}
-
-	list_splice_tail(crs_res, resources);
+	return setup_mcfg_map(ci);
 }
 
-static void release_pci_root_info(struct pci_host_bridge *bridge)
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
 {
-	struct resource *res;
-	struct resource_entry *entry;
-	struct pci_root_info *info = bridge->release_data;
-
-	resource_list_for_each_entry(entry, &bridge->windows) {
-		res = entry->res;
-		if (res->parent &&
-		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
-			release_resource(res);
-	}
-
-	teardown_mcfg_map(info);
-	kfree(info);
+	teardown_mcfg_map(ci);
+	kfree(container_of(ci, struct pci_root_info, common));
 }
 
 /*
@@ -358,47 +282,44 @@ static bool resource_is_pcicfg_ioport(struct resource *res)
 		res->start == 0xCF8 && res->end == 0xCFF;
 }
 
-static void probe_pci_root_info(struct pci_root_info *info,
-				struct acpi_device *device,
-				int busnum, int domain,
-				struct list_head *list)
+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
 {
-	int ret;
+	struct acpi_device *device = ci->bridge;
+	int busnum = ci->root->secondary.start;
 	struct resource_entry *entry, *tmp;
+	int status;
 
-	sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
-	info->bridge = device;
-	ret = acpi_dev_get_resources(device, list,
-				     acpi_dev_filter_resource_type_cb,
-				     (void *)(IORESOURCE_IO | IORESOURCE_MEM));
-	if (ret < 0)
-		dev_warn(&device->dev,
-			 "failed to parse _CRS method, error code %d\n", ret);
-	else if (ret == 0)
-		dev_dbg(&device->dev,
-			"no IO and memory resources present in _CRS\n");
-	else
-		resource_list_for_each_entry_safe(entry, tmp, list) {
-			if ((entry->res->flags & IORESOURCE_DISABLED) ||
-			    resource_is_pcicfg_ioport(entry->res))
+	status = acpi_pci_probe_root_resources(ci);
+	if (pci_use_crs) {
+		resource_list_for_each_entry_safe(entry, tmp, &ci->resources)
+			if (resource_is_pcicfg_ioport(entry->res))
 				resource_list_destroy_entry(entry);
-			else
-				entry->res->name = info->name;
-		}
+		return status;
+	}
+
+	resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
+		dev_printk(KERN_DEBUG, &device->dev,
+			   "host bridge window %pR (ignored)\n", entry->res);
+		resource_list_destroy_entry(entry);
+	}
+	x86_pci_root_bus_resources(busnum, &ci->resources);
+
+	return 0;
 }
 
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
+	.pci_ops = &pci_root_ops,
+	.init_info = pci_acpi_root_init_info,
+	.release_info = pci_acpi_root_release_info,
+	.prepare_resources = pci_acpi_root_prepare_resources,
+};
+
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-	struct acpi_device *device = root->device;
-	struct pci_root_info *info;
 	int domain = root->segment;
 	int busnum = root->secondary.start;
-	struct resource_entry *res_entry;
-	LIST_HEAD(crs_res);
-	LIST_HEAD(resources);
+	int node = pci_acpi_root_get_node(root);
 	struct pci_bus *bus;
-	struct pci_sysdata *sd;
-	int node;
 
 	if (pci_ignore_seg)
 		root->segment = domain = 0;
@@ -410,71 +331,33 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 		return NULL;
 	}
 
-	node = acpi_get_node(device->handle);
-	if (node == NUMA_NO_NODE) {
-		node = x86_pci_root_bus_node(busnum);
-		if (node != 0 && node != NUMA_NO_NODE)
-			dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n",
-				node);
-	}
-
-	if (node != NUMA_NO_NODE && !node_online(node))
-		node = NUMA_NO_NODE;
-
-	info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
-	if (!info) {
-		printk(KERN_WARNING "pci_bus %04x:%02x: "
-		       "ignored (out of memory)\n", domain, busnum);
-		return NULL;
-	}
-
-	sd = &info->sd;
-	sd->domain = domain;
-	sd->node = node;
-	sd->companion = device;
-
 	bus = pci_find_bus(domain, busnum);
 	if (bus) {
 		/*
 		 * If the desired bus has been scanned already, replace
 		 * its bus->sysdata.
 		 */
-		memcpy(bus->sysdata, sd, sizeof(*sd));
-		kfree(info);
-	} else {
-		/* insert busn res at first */
-		pci_add_resource(&resources,  &root->secondary);
+		struct pci_sysdata sd = {
+			.domain = domain,
+			.node = node,
+			.companion = root->device
+		};
 
-		/*
-		 * _CRS with no apertures is normal, so only fall back to
-		 * defaults or native bridge info if we're ignoring _CRS.
-		 */
-		probe_pci_root_info(info, device, busnum, domain, &crs_res);
-		if (pci_use_crs) {
-			add_resources(info, &resources, &crs_res);
-		} else {
-			resource_list_for_each_entry(res_entry, &crs_res)
-				dev_printk(KERN_DEBUG, &device->dev,
-					   "host bridge window %pR (ignored)\n",
-					   res_entry->res);
-			resource_list_free(&crs_res);
-			x86_pci_root_bus_resources(busnum, &resources);
-		}
-
-		if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
-				    (u8)root->secondary.end, root->mcfg_addr))
-			bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
-						  sd, &resources);
-
-		if (bus) {
-			pci_scan_child_bus(bus);
-			pci_set_host_bridge_release(
-				to_pci_host_bridge(bus->bridge),
-				release_pci_root_info, info);
-		} else {
-			resource_list_free(&resources);
-			teardown_mcfg_map(info);
-			kfree(info);
+		memcpy(bus->sysdata, &sd, sizeof(sd));
+	} else {
+		struct pci_root_info *info;
+
+		info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
+		if (!info)
+			dev_err(&root->device->dev,
+				"pci_bus %04x:%02x: ignored (out of memory)\n",
+				domain, busnum);
+		else {
+			info->sd.domain = domain;
+			info->sd.node = node;
+			info->sd.companion = root->device;
+			bus = acpi_pci_root_create(root, &acpi_pci_root_ops,
+						   &info->common, &info->sd);
 		}
 	}
 
@@ -487,9 +370,6 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 			pcie_bus_configure_settings(child);
 	}
 
-	if (bus && node != NUMA_NO_NODE)
-		dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
-
 	return bus;
 }
 
Signature · 6 lines
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author
#50 lore raw

PATCH v7 7/7 ia64/PCI/ACPI: Use common interface to support PCI host bridge

In reply to Jiang Liu

Use common interface to simplify PCI host bridge implementation.

---
 arch/ia64/pci/pci.c |  235 +++++++++++----------------------------------------
 1 file changed, 48 insertions(+), 187 deletions(-)
arch/ia64/pci/pci.c +48 -187
index b1846b891ea5..8f6ac2f8ae4c 100644
@@ -116,15 +116,12 @@ struct pci_ops pci_root_ops = {
 };
 
 struct pci_root_info {
+	struct acpi_pci_root_info common;
 	struct pci_controller controller;
-	struct acpi_device *bridge;
-	struct list_head resources;
 	struct list_head io_resources;
-	char name[16];
 };
 
-static unsigned int
-new_space (u64 phys_base, int sparse)
+static unsigned int new_space(u64 phys_base, int sparse)
 {
 	u64 mmio_base;
 	int i;
@@ -160,11 +157,11 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
 	unsigned long base, min, max, base_port;
 	unsigned int sparse = 0, space_nr, len;
 
-	len = strlen(info->name) + 32;
+	len = strlen(info->common.name) + 32;
 	iospace = resource_list_create_entry(NULL, len);
 	if (!iospace) {
 		dev_err(dev, "PCI: No memory for %s I/O port space\n",
-			info->name);
+			info->common.name);
 		return -ENOMEM;
 	}
 
@@ -179,7 +176,7 @@ static int add_io_space(struct device *dev, struct pci_root_info *info,
 	max = res->end - entry->offset;
 	base = __pa(io_space[space_nr].mmio_base);
 	base_port = IO_SPACE_BASE(space_nr);
-	snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name,
+	snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->common.name,
 		 base_port + min, base_port + max);
 
 	/*
@@ -234,217 +231,81 @@ static bool resource_is_pcicfg_ioport(struct resource *res)
 		res->start == 0xCF8 && res->end == 0xCFF;
 }
 
-static int
-probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
-		    int busnum, int domain)
+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
 {
-	int ret;
-	struct list_head *list = &info->resources;
+	struct device *dev = &ci->bridge->dev;
+	struct pci_root_info *info;
+	struct resource *res;
 	struct resource_entry *entry, *tmp;
-
-	ret = acpi_dev_get_resources(device, list,
-				     acpi_dev_filter_resource_type_cb,
-				     (void *)(IORESOURCE_IO | IORESOURCE_MEM));
-	if (ret < 0)
-		dev_warn(&device->dev,
-			 "failed to parse _CRS method, error code %d\n", ret);
-	else if (ret == 0)
-		dev_dbg(&device->dev,
-			"no IO and memory resources present in _CRS\n");
-	else
-		resource_list_for_each_entry_safe(entry, tmp, list) {
-			if ((entry->res->flags & IORESOURCE_DISABLED) ||
-			    resource_is_pcicfg_ioport(entry->res))
-				resource_list_destroy_entry(entry);
-			else
-				entry->res->name = info->name;
-		}
-
-	return ret;
-}
-
-static void validate_resources(struct device *dev, struct list_head *resources,
-			       unsigned long type)
-{
-	LIST_HEAD(list);
-	struct resource *res1, *res2, *root = NULL;
-	struct resource_entry *tmp, *entry, *entry2;
-
-	BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
-	root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
-
-	list_splice_init(resources, &list);
-	resource_list_for_each_entry_safe(entry, tmp, &list) {
-		bool free = false;
-		resource_size_t end;
-
-		res1 = entry->res;
-		if (!(res1->flags & type))
-			goto next;
-
-		/* Exclude non-addressable range or non-addressable portion */
-		end = min(res1->end, root->end);
-		if (end <= res1->start) {
-			dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
-				 res1);
-			free = true;
-			goto next;
-		} else if (res1->end != end) {
-			dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
-				 res1, (unsigned long long)end + 1,
-				 (unsigned long long)res1->end);
-			res1->end = end;
-		}
-
-		resource_list_for_each_entry(entry2, resources) {
-			res2 = entry2->res;
-			if (!(res2->flags & type))
-				continue;
-
-			/*
-			 * I don't like throwing away windows because then
-			 * our resources no longer match the ACPI _CRS, but
-			 * the kernel resource tree doesn't allow overlaps.
-			 */
-			if (resource_overlaps(res1, res2)) {
-				res2->start = min(res1->start, res2->start);
-				res2->end = max(res1->end, res2->end);
-				dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
-					 res2, res1);
-				free = true;
-				goto next;
+	int status;
+
+	status = acpi_pci_probe_root_resources(ci);
+	if (status > 0) {
+		info = container_of(ci, struct pci_root_info, common);
+		resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
+			res = entry->res;
+			if (res->flags & IORESOURCE_MEM) {
+				/*
+				 * HP's firmware has a hack to work around a
+				 * Windows bug. Ignore these tiny memory ranges.
+				 */
+				if (resource_size(res) <= 16) {
+					resource_list_del(entry);
+					insert_resource(&iomem_resource,
+							entry->res);
+					resource_list_add_tail(entry,
+							&info->io_resources);
+				}
+			} else if (res->flags & IORESOURCE_IO) {
+				if (resource_is_pcicfg_ioport(entry->res))
+					resource_list_destroy_entry(entry);
+				else if (add_io_space(dev, info, entry))
+					resource_list_destroy_entry(entry);
 			}
 		}
-
-next:
-		resource_list_del(entry);
-		if (free)
-			resource_list_free_entry(entry);
-		else
-			resource_list_add_tail(entry, resources);
 	}
-}
 
-static void add_resources(struct pci_root_info *info, struct device *dev)
-{
-	struct resource_entry *entry, *tmp;
-	struct resource *res, *conflict, *root = NULL;
-	struct list_head *list = &info->resources;
-
-	validate_resources(dev, list, IORESOURCE_MEM);
-	validate_resources(dev, list, IORESOURCE_IO);
-
-	resource_list_for_each_entry_safe(entry, tmp, list) {
-		res = entry->res;
-		if (res->flags & IORESOURCE_MEM) {
-			root = &iomem_resource;
-			/*
-			 * HP's firmware has a hack to work around a Windows
-			 * bug. Ignore these tiny memory ranges.
-			 */
-			if (resource_size(res) <= 16) {
-				resource_list_destroy_entry(entry);
-				continue;
-			}
-		} else if (res->flags & IORESOURCE_IO) {
-			root = &ioport_resource;
-			if (add_io_space(&info->bridge->dev, info, entry)) {
-				resource_list_destroy_entry(entry);
-				continue;
-			}
-		} else {
-			BUG_ON(res);
-		}
-
-		conflict = insert_resource_conflict(root, res);
-		if (conflict) {
-			dev_info(dev,
-				 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
-				 res, conflict->name, conflict);
-			resource_list_destroy_entry(entry);
-		}
-	}
+	return status;
 }
 
-static void __release_pci_root_info(struct pci_root_info *info)
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
 {
-	struct resource *res;
-	struct resource_entry *entry, *tentry;
+	struct pci_root_info *info;
+	struct resource_entry *entry, *tmp;
 
-	resource_list_for_each_entry_safe(entry, tentry, &info->io_resources) {
+	info = container_of(ci, struct pci_root_info, common);
+	resource_list_for_each_entry_safe(entry, tmp, &info->io_resources) {
 		release_resource(entry->res);
 		resource_list_destroy_entry(entry);
 	}
-
-	resource_list_for_each_entry_safe(entry, tentry, &info->resources) {
-		res = entry->res;
-		if (res->parent &&
-		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
-			release_resource(res);
-		resource_list_destroy_entry(entry);
-	}
-
 	kfree(info);
 }
 
-static void release_pci_root_info(struct pci_host_bridge *bridge)
-{
-	struct pci_root_info *info = bridge->release_data;
-
-	__release_pci_root_info(info);
-}
+static struct acpi_pci_root_ops pci_acpi_root_ops = {
+	.pci_ops = &pci_root_ops,
+	.release_info = pci_acpi_root_release_info,
+	.prepare_resources = pci_acpi_root_prepare_resources,
+};
 
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
 	struct acpi_device *device = root->device;
-	int domain = root->segment;
-	int bus = root->secondary.start;
 	struct pci_root_info *info;
-	struct pci_bus *pbus;
-	int ret;
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info) {
 		dev_err(&device->dev,
 			"pci_bus %04x:%02x: ignored (out of memory)\n",
-			domain, bus);
+			root->segment, (int)root->secondary.start);
 		return NULL;
 	}
 
-	info->controller.segment = domain;
+	info->controller.segment = root->segment;
 	info->controller.companion = device;
 	info->controller.node = acpi_get_node(device->handle);
-	info->bridge = device;
-	INIT_LIST_HEAD(&info->resources);
 	INIT_LIST_HEAD(&info->io_resources);
-	snprintf(info->name, sizeof(info->name),
-		 "PCI Bus %04x:%02x", domain, bus);
-
-	ret = probe_pci_root_info(info, device, bus, domain);
-	if (ret <= 0) {
-		kfree(info);
-		return NULL;
-	}
-	add_resources(info, &info->bridge->dev);
-	pci_add_resource(&info->resources, &root->secondary);
-
-	/*
-	 * See arch/x86/pci/acpi.c.
-	 * The desired pci bus might already be scanned in a quirk. We
-	 * should handle the case here, but it appears that IA64 hasn't
-	 * such quirk. So we just ignore the case now.
-	 */
-	pbus = pci_create_root_bus(NULL, bus, &pci_root_ops,
-				   &info->controller, &info->resources);
-	if (!pbus) {
-		__release_pci_root_info(info);
-		return NULL;
-	}
-
-	pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge),
-			release_pci_root_info, info);
-	pci_scan_child_bus(pbus);
-	return pbus;
+	return acpi_pci_root_create(root, &pci_acpi_root_ops,
+				    &info->common, &info->controller);
 }
 
 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
Signature · 1 line
1.7.10.4
#51 lore raw
In reply to Jiang Liu
Quoted 8 lines · Jiang Liu

From: Liu Jiang <[email protected]>

This patch set consolidates common code to support ACPI PCI root on x86 and IA64 platforms into ACPI core, to reproduce duplicated code and simplify maintenance. And a patch set based on previous version to support ACPI based PCIe host bridge on ARM64 has been posted at:
https://lkml.org/lkml/2015/5/26/207

Quoted 7 lines

It's based on latest mainstream kernel. It passes Fengguang's 0day test suite and has been tested on two IA64 platforms and one x86 platform.

V6->V7:
1) Improve commit message according to Bjorn's suggestion.
2) Move arch specific logic(code) from ACPI core into arch code according to Bjorn's review comments.

Thanks for cleaning this up; I think it looks much better.

As far as I'm concerned, this series is ready to go. I assume Rafael will merge it.

Quoted 51 lines

V5->V6:
1) Patch 5 to reset domain number to 0 when pci_ignore_seg is set
2) Remove parameter segment and node from function acpi_pci_root_create(), as suggested by Lorenzo and Bjorn.
V4-V5:
1) As suggested by Lorenzo Pieralisi <[email protected]>, do not introduce "struct pci_controller" into generic drivers/acpi/pci_root.c, so ARM64 doesn't need to define a useless structure. And it simplifies code a little too.

V3->V4:
1) Add patch[05/08] support solve building issue on ARM64
2) Solve an implicitly pointer cast issue.
3) Rebase to latest mainstream kernel

V2->V3:
1. Move memory allocation/free from ACPI core into arch
2. Kill the field 'segment' in struct pci_root_info on x86

Thanks!
Gerry

Jiang Liu (7):
ACPI/PCI: Enhance ACPI core to support sparse IO space ia64/PCI/ACPI: Use common ACPI resource parsing interface for host
bridge
ia64/PCI: Use common struct resource_entry to replace struct
iospace_resource
PCI/ACPI: Add interface acpi_pci_root_create()
ACPI, PCI: Reset acpi_root_dev->domain to 0 when pci_ignore_seg is
set
x86/PCI/ACPI: Use common interface to support PCI host bridge ia64/PCI/ACPI: Use common interface to support PCI host bridge

 arch/ia64/include/asm/pci.h |    5 -
 arch/ia64/pci/pci.c         |  368 ++++++++++++-------------------------------
 arch/x86/pci/acpi.c         |  296 +++++++++++-----------------------
 drivers/acpi/pci_root.c     |  204 ++++++++++++++++++++++++
 drivers/acpi/resource.c     |    9 +-
 include/linux/ioport.h      |    1 +
 include/linux/pci-acpi.h    |   24 +++
 7 files changed, 423 insertions(+), 484 deletions(-)
Signature · 7 lines
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
#52 lore raw
Quoted 17 lines · Bjorn Helgaas
Quoted 8 lines · Jiang Liu

From: Liu Jiang <[email protected]>

This patch set consolidates common code to support ACPI PCI root on x86 and IA64 platforms into ACPI core, to reproduce duplicated code and simplify maintenance. And a patch set based on previous version to support ACPI based PCIe host bridge on ARM64 has been posted at:
https://lkml.org/lkml/2015/5/26/207

Quoted 7 lines

It's based on latest mainstream kernel. It passes Fengguang's 0day test suite and has been tested on two IA64 platforms and one x86 platform.

V6->V7:
1) Improve commit message according to Bjorn's suggestion.
2) Move arch specific logic(code) from ACPI core into arch code according to Bjorn's review comments.

Quoted 4 lines

Thanks for cleaning this up; I think it looks much better.

As far as I'm concerned, this series is ready to go. I assume Rafael will merge it.

Yes, I'm going to do that.

Thanks a lot for your help with the review!

Rafael

author
#53 lore raw
Quoted 18 lines · Rafael J. Wysocki
Quoted 17 lines · Bjorn Helgaas
Quoted 15 lines · Jiang Liu

From: Liu Jiang <[email protected]>

This patch set consolidates common code to support ACPI PCI root on x86 and IA64 platforms into ACPI core, to reproduce duplicated code and simplify maintenance. And a patch set based on previous version to support ACPI based PCIe host bridge on ARM64 has been posted at:
https://lkml.org/lkml/2015/5/26/207

It's based on latest mainstream kernel. It passes Fengguang's 0day test suite and has been tested on two IA64 platforms and one x86 platform.

V6->V7:
1) Improve commit message according to Bjorn's suggestion.
2) Move arch specific logic(code) from ACPI core into arch code according to Bjorn's review comments.

Quoted 8 lines
Quoted 4 lines

Thanks for cleaning this up; I think it looks much better.

As far as I'm concerned, this series is ready to go. I assume Rafael will merge it.

Yes, I'm going to do that.

Thanks a lot for your help with the review!

Thanks Bjorn and Rafael for review!