Consolidate ACPI PCI root common code into ACPI core
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
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
@@ -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
@@ -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
PATCH v7 2/7 ia64/PCI/ACPI: Use common ACPI resource parsing interface for host bridge
In reply to Jiang LiuUse 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
@@ -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
PATCH v7 3/7 ia64/PCI: Use common struct resource_entry to replace struct iospace_resource
In reply to Jiang LiuUse 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
@@ -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
@@ -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
PATCH v7 4/7 PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Jiang LiuIntroduce 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
@@ -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
@@ -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
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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>
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@@ -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@@ -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
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Jiang LiuQuoted 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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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
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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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 choosePCI_DOMAINS_GENERICand want to use segment nr from MCFG table) which is the part ofpci_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! /
---------------
¯\_(ツ)_/¯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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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 choosePCI_DOMAINS_GENERICand want to use segment nr from MCFG table) which is the part ofpci_create_root_bus.Not sure I fully understand your question, but
pci_bus_assign_domain_nr()will put the assigned domain number inbus->domain_nrif you chosePCI_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
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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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 choosePCI_DOMAINS_GENERICand want to use segment nr from MCFG table) which is the part ofpci_create_root_bus.Not sure I fully understand your question, but
pci_bus_assign_domain_nr()will put the assigned domain number inbus->domain_nrif you chosePCI_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 callsacpi_pci_root_create->pci_create_root_bus->pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPISo I would like to assign MCFG segment nr to
bus->domain_nrbeing inpci_bus_assign_domain_nrgiving 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
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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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 choosePCI_DOMAINS_GENERICand want to use segment nr from MCFG table) which is the part ofpci_create_root_bus.Not sure I fully understand your question, but
pci_bus_assign_domain_nr()will put the assigned domain number inbus->domain_nrif you chosePCI_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 callsacpi_pci_root_create->pci_create_root_bus->pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPISo I would like to assign MCFG segment nr to
bus->domain_nrbeing inpci_bus_assign_domain_nrgiving 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_nrabove is the value returned by the_SEGobject 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
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Tomasz NowickiQuoted 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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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 choosePCI_DOMAINS_GENERICand want to use segment nr from MCFG table) which is the part ofpci_create_root_bus.Not sure I fully understand your question, but
pci_bus_assign_domain_nr()will put the assigned domain number inbus->domain_nrif you chosePCI_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 callsacpi_pci_root_create->pci_create_root_bus->pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPISo I would like to assign MCFG segment nr to
bus->domain_nrbeing inpci_bus_assign_domain_nrgiving 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! /
---------------
¯\_(ツ)_/¯Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Tomasz NowickiQuoted 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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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 choosePCI_DOMAINS_GENERICand want to use segment nr from MCFG table) which is the
part ofpci_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 inbus->domain_nrif you chosePCI_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 callsacpi_pci_root_create->pci_create_root_bus->pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPISo I would like to assign MCFG segment nr to
bus->domain_nrbeing inpci_bus_assign_domain_nrgiving 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,
TomaszSignature · 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/
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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- 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 choosePCI_DOMAINS_GENERICand want to use segment nr from MCFG table) which is the
part ofpci_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 inbus->domain_nrif you chosePCI_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 callsacpi_pci_root_create->pci_create_root_bus->pci_bus_assign_domain_nr
3. At this point we cannot get segment nr for ACPISo I would like to assign MCFG segment nr to
bus->domain_nrbeing inpci_bus_assign_domain_nrgiving we have scenario above.Please use sysdata for that, IA64 and x86 are making use of sysdata to store such information:
structpci_sysdata{int domain; /* PCI domain */ int node; /* NUMA node */#ifdef
CONFIG_ACPI
structacpi_device*companion; /* ACPI companion device */
#endif
#ifdefCONFIG_X86_64
void *iommu; /* IOMMU private data */
#endif
};
Quoted 2 lines
Hanjun once tried to introduce struct
pci_sysdatafor 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,
TomaszSignature · 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! /
---------------
¯\_(ツ)_/¯Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Jiang LiuQuoted 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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- drivers/acpi/pci_root.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci-acpi.h | 24 ++++++ 2 files changed, 228 insertions(+)drivers/acpi/pci_root.c +87
-0@@ -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
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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant 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
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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant to be x86 specific and I should avoid using it?IIUC, you _have_ to have the proper
translation_offsetto 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 usingpci_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 theresource->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.
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Lorenzo PieralisiQuoted 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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant to be x86 specific and I should avoid using it?IIUC, you _have_ to have the proper
translation_offsetto 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 usingpci_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 theresource->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
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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant to be x86 specific and I should avoid using it?IIUC, you _have_ to have the proper
translation_offsetto 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 usingpci_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 theresource->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_offset2) 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
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, notCPU 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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant to be x86 specific and I should avoid using it?IIUC, you _have_ to have the proper
translation_offsetto 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 usingpci_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 theresource->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_offset2) 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
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, notCPU 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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant to be x86 specific and I should avoid using it?IIUC, you _have_ to have the proper
translation_offsetto 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 usingpci_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 theresource->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) byres->start = acpi_des->start + acpi_des->translation_offset2) 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->MMIOtranslation instead of a IOPort->IOPort 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
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->MMIOtranslation instead of a IOPort->IOPort 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
From51f5cddd8c4301b731805074ebc3e3a6c7dbaf59Mon 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
@@ -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
@@ -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
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->MMIOtranslation instead of a IOPort->IOPort 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
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->MMIOtranslation instead of a IOPort->IOPort 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->startonly 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_TTPis set (and that's not checked).
Yes, that's a flaw:(
Quoted 6 lines
Thoughts ?
Thanks,
Lorenzo
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->MMIOtranslation instead of a IOPort->IOPort 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 addingacpi_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->startonly 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_offsetto convert bus local IO port address into system global IO port address if it's type of TypeStatic, becauseioresource_ioportuses 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_offsetis used to translate IO port address into MMIO address, so we shouldn't addtranslation_offsetto 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,
GerryQuoted 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_TTPis 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/
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->MMIOtranslation instead of a IOPort->IOPort 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 addingacpi_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->startonly 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_offsetto convert bus local IO port address into system global IO port address if it's type of TypeStatic, becauseioresource_ioportuses 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_offsetis used to translate IO port address into MMIO address, so we shouldn't addtranslation_offsetto the IO port resource descriptor.One note for the TypeTranslation case, the arch code needs to reset
resource_win->offsetto 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,
GerryQuoted 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_TTPis 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
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Jiang LiuQuoted 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->MMIOtranslation instead of a IOPort->IOPort 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
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->MMIOtranslation instead of a IOPort->IOPort 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
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->MMIOtranslation instead of a IOPort->IOPort 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:
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(ienew_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
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->MMIOtranslation instead of a IOPort->IOPort 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:
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(ienew_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 becomesstatic 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 correctio_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
6521d3c5303b1d9830eecede4c1b778deffe17b0Mon 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
@@ -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
@@ -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
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(ienew_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 becomesstatic 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 correctio_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
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(ienew_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 becomesstatic 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 correctio_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 addressWe 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_spacethat 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_resourceand its check inacpi_pci_root_validate_resources()which basically that's the problem that started this thread.On arm64,
IO_SPACE_LIMITis 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
_CRSagainst the range 0..IO_SPACE_LIMIT is not necessarily meaningful (or at least not meaningful in its current form), on ia64 it works becauseIO_SPACE_LIMITis 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 spaceSo:
- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patchacpi_pci_root_validate_resources()to amend the wayIORESOURCE_IOis currently checked againstioport_resource, it can't work on arm64 at present, I described why aboveThoughts 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! /
---------------
¯\_(ツ)_/¯Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Lorenzo PieralisiQuoted 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 inacpi_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_spacethat 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_LIMITis 16M, which, AFAIK is a kernel limit, not a HW one. Comparing the resources parsed from the PCI bridge_CRSagainst the range 0..IO_SPACE_LIMIT is not necessarily meaningful (or at least not meaningful in its current form), on ia64 it works becauseIO_SPACE_LIMITis 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 spaceSo:
Quoted 8 lines
- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patchacpi_pci_root_validate_resources()to amend the wayIORESOURCE_IOis currently checked againstioport_resource, it can't work on arm64 at present, I described why aboveThoughts 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
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 inacpi_decode_space(), are we sure that's what we really want ?In DT, a host bridge range has a:
- CPU physical address
- PCI bus addressWe 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_spacethat 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 spaceSo:
Quoted 8 lines
- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patchacpi_pci_root_validate_resources()to amend the wayIORESOURCE_IOis currently checked againstioport_resource, it can't work on arm64 at present, I described why aboveThoughts 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_resourceaddresses 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
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Lorenzo PieralisiQuoted 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(ienew_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 becomesstatic 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 correctio_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_spacethat 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_resourceand its check inacpi_pci_root_validate_resources()which basically that's the problem that started this thread.On arm64,
IO_SPACE_LIMITis 16M, which, AFAIK is a kernel limit, not a HW one. Comparing the resources parsed from the PCI bridge_CRSagainst the range 0..IO_SPACE_LIMIT is not necessarily meaningful (or at least not meaningful in its current form), on ia64 it works becauseIO_SPACE_LIMITis 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 spaceSo:
- Either we go with the patch attached (but please check my comment on the memory spaces)
- Or we patchacpi_pci_root_validate_resources()to amend the wayIORESOURCE_IOis currently checked againstioport_resource, it can't work on arm64 at present, I described why aboveThoughts 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/
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(ienew_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 becomesstatic 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 correctio_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 addressQuoted 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_spacethat 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_winto support above two-stage translation. One object, type ofIORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type ofIORESOURCE_MMIO, is used to allocate resource fromiomem_resourceand 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_IOand offset must be zero becausepcibios_resource_to_bus()will access it translate system IO port address into bus local IO port address. With my patch, the structresource_winobject 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_winobject 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
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(ienew_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 asstatic 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 becomesstatic 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 usepci_ioremap_io()or something like that to to map a physical address range into this virtual
address window at the correctio_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 addressWe 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_winto support above two-stage translation. One object, type ofIORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type ofIORESOURCE_MMIO, is used to allocate resource fromiomem_resourceand 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_IOand offset must be zero becausepcibios_resource_to_bus()will access it translate system IO port address into bus local IO port address. With my patch, the structresource_winobject 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 structresource_winobject 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_Offsetmeaning 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/
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(ienew_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 asstatic 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 becomesstatic 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 usepci_ioremap_io()or something like that to to map a physical address range into this virtual
address window at the correctio_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 addressWe 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_winto support above two-stage translation. One object, type ofIORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type ofIORESOURCE_MMIO, is used to allocate resource fromiomem_resourceand 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_IOand offset must be zero becausepcibios_resource_to_bus()will access it translate system IO port address into bus local IO port address. With my patch, the structresource_winobject 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 structresource_winobject 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_Offsetmeaning 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
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(ienew_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 asstatic 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 thatinl()simply becomesstatic 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 usepci_ioremap_io()or something like that to to map a physical address range into this virtual
address window at the correctio_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 addressWe 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_winto support above two-stage translation. One object, type ofIORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type ofIORESOURCE_MMIO, is used to allocate resource fromiomem_resourceand 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_IOand offset must be zero becausepcibios_resource_to_bus()will access it translate system IO port address into bus local IO port address. With my patch, the structresource_winobject 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 structresource_winobject 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_Offsetmeaning 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
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(ienew_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 asstatic 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 thatinl()simply becomesstatic 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 usepci_ioremap_io()or something like that to to map a physical address range into this virtual
address window at the correctio_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 addressWe 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_winto support above two-stage translation. One object, type ofIORESOURCE_IO, is used to support stage one, and it will also used to allocate IO port resources for PCI devices. Another object, type ofIORESOURCE_MMIO, is used to allocate resource fromiomem_resourceand 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_IOand offset must be zero becausepcibios_resource_to_bus()will access it translate system IO port address into bus local IO port address. With my patch, the structresource_winobject 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 structresource_winobject 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_Offsetmeaning 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 addressWe 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
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_spacecannot 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 addressWe 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
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_spacecannot 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 addressWe 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_spacewe 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
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_spacewe 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
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_spacewe 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
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Jiang LiuOn 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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant to be x86 specific and I should avoid using it?IIUC, you _have_ to have the proper
translation_offsetto 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 usingpci_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 theresource->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
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Lorenzo PieralisiQuoted 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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant to be x86 specific and I should avoid using it?IIUC, you _have_ to have the proper
translation_offsetto 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 usingpci_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 theresource->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
Re: [Patch v7 4/7] PCI/ACPI: Add interface acpi_pci_root_create()
In reply to Tomasz NowickiQuoted 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.Reviewed-by Lorenzo Pieralisi <[email protected]>Tested-by Tony Luck <[email protected]>Signed-off-by Jiang Liu <[email protected]>Signed-off-by Liu Jiang <[email protected]>--- drivers/acpi/pci_root.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci-acpi.h | 24 ++++++ 2 files changed, 228 insertions(+)drivers/acpi/pci_root.c +53
-0@@ -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 becauseacpi_dev_get_resourcesis addingtranslation_offsetto 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_resourcesmeant 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
PATCH v7 5/7 ACPI, PCI: Reset acpi_root_dev->domain to 0 when pci_ignore_seg is set
In reply to Jiang LiuReset 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
@@ -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
PATCH v7 6/7 x86/PCI/ACPI: Use common interface to support PCI host bridge
In reply to Jiang LiuUse 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
@@ -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
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.
Signed-off-by Jiang Liu <[email protected]>Reviewed-by Hanjun Guo <[email protected]>Signed-off-by Liu Jiang <[email protected]>
Quoted 408 lines
--- arch/x86/pci/acpi.c | 294 +++++++++++++++------------------------------------ 1 file changed, 87 insertions(+), 207 deletions(-)arch/x86/pci/acpi.c +87
-207@@ -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
PATCH v7 7/7 ia64/PCI/ACPI: Use common interface to support PCI host bridge
In reply to Jiang LiuUse 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
@@ -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
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 whenpci_ignore_segis set
2) Remove parameter segment and node from functionacpi_pci_root_create(), as suggested by Lorenzo and Bjorn.
V4-V5:
1) As suggested by Lorenzo Pieralisi <[email protected]>, do not introduce "structpci_controller" into genericdrivers/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 structpci_root_infoon x86Thanks!
GerryJiang 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 structresource_entryto replace struct
iospace_resource
PCI/ACPI: Add interfaceacpi_pci_root_create()
ACPI, PCI: Resetacpi_root_dev->domainto 0 whenpci_ignore_segis
set
x86/PCI/ACPI: Use common interface to support PCI host bridge ia64/PCI/ACPI: Use common interface to support PCI host bridgearch/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/
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/207Quoted 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
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/207It'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!