Consolidate ACPI PCI root common code into ACPI core
v6 cover Consolidate ACPI PCI root common code into ACPI core
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.
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: Consolidate common PCI host bridge code into ACPI core 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 | 367 ++++++++++++------------------------------- arch/x86/pci/acpi.c | 295 ++++++++++------------------------ drivers/acpi/pci_root.c | 199 +++++++++++++++++++++++ drivers/acpi/resource.c | 9 +- include/linux/ioport.h | 1 + include/linux/pci-acpi.h | 23 +++ 7 files changed, 415 insertions(+), 484 deletions(-)
Signature · 1 line
1.7.10.4
PATCH v6 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 v6 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 v6 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 v6 4/7 PCI/ACPI: Consolidate common PCI host bridge code into ACPI core
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 | 23 ++++++ 2 files changed, 227 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); + } +} + +static 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; + ret =acpi_pci_probe_root_resources (info); +if (ops->prepare_resources) + ret = ops->prepare_resources (info, ret); +if (ret <0 ) + goto out_release_info; +else if (ret >0 ) +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) { +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 +23 -0
@@ -52,6 +52,29 @@ 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,int status); +}; + +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 v6 4/7] PCI/ACPI: Consolidate common PCI host bridge code into ACPI core
Hi Jiang,
Strictly speaking, this patch by itself doesn't actually "consolidate" anything because it only adds acpi_pci_root_create() (which isn't called by anything yet), but doesn't remove the original x86 copy.
Quoted 8 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]>
Some minor structuring comments below, but my ack is valid even if you don't address them.
Quoted 188 lines
--- drivers/acpi/pci_root.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci-acpi.h | 23 ++++++ 2 files changed, 227 insertions(+)drivers/acpi/pci_root.c +175
-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); + } +} + +static 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);
drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 839
Quoted 10 lines
drivers/acpi/pci_root.c +10
-0+ +if (ops->init_info && ops->init_info (info)) + goto out_release_info; + ret =acpi_pci_probe_root_resources (info); +if (ops->prepare_resources) + ret = ops->prepare_resources (info, ret); +if (ret <0 ) + goto out_release_info; +else if (ret >0 ) +pci_acpi_root_add_resources (info);
This is unnecessarily complicated: you set "ret", then overwrite it if ops->prepare_resources. By the time you test "ret", it's messy to figure out what it means.
Both ops->prepare_resources() and pci_acpi_root_add_resources() should be able to deal with empty resource lists, so can you do the following instead?
ret = acpi_pci_probe_root_resources(info);
if (ret < 0)
goto out_release_info;
if (ops->prepare_resources) {
ret = ops->prepare_resources(info, ret);
if (ret < 0)
goto out_release_info;
}
pci_acpi_root_add_resources(info);drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 844
Quoted 5 lines
drivers/acpi/pci_root.c +5
-0+pci_add_resource (&info->resources, &root->secondary); + + bus =pci_create_root_bus (NULL , busnum, ops->pci_ops, + sysdata, &info->resources); +if (bus) {
if (!bus)
goto out_release_info;Then it looks like the other error paths above, and you can un-indent the following code, which is the normal path:
Quoted 59 lines
drivers/acpi/pci_root.c +14
-0+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 +23
-0@@ -52,6 +52,29 @@ 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,int status); +}; + +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 · 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/
Re: [Patch v6 4/7] PCI/ACPI: Consolidate common PCI host bridge code into ACPI core
Quoted 6 lines · Bjorn Helgaas
Hi Jiang,
Strictly speaking, this patch by itself doesn't actually "consolidate" anything because it only adds
acpi_pci_root_create()(which isn't called by anything yet), but doesn't remove the original x86 copy.
<snit>
Quoted 31 lines
Quoted 16 lines
drivers/acpi/pci_root.c +16
-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);drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 839
Quoted 10 lines
drivers/acpi/pci_root.c +10
-0+ +if (ops->init_info && ops->init_info (info)) + goto out_release_info; + ret =acpi_pci_probe_root_resources (info); +if (ops->prepare_resources) + ret = ops->prepare_resources (info, ret); +if (ret <0 ) + goto out_release_info; +else if (ret >0 ) +pci_acpi_root_add_resources (info);This is unnecessarily complicated: you set "ret", then overwrite it if
ops->prepare_resources. By the time you test "ret", it's messy to figure out what it means.
Quoted 7 lines
Both
ops->prepare_resources()andpci_acpi_root_add_resources()should be able to deal with empty resource lists, so can you do the following instead?ret = acpi_pci_probe_root_resources(info); if (ret < 0) goto out_release_info;
Hi Bjorn,
Thanks for review:)
The original code is used to handle a special case for x86,
where acpi_pci_probe_root_resources() fails but ops->prepare_resources() succeeds. For x86, PCI host bridge resources may probed by means other than ACPI when pci_use_crs is true (AMD and Broadcom hostbridges). So we can't return failure when acpi_pci_probe_root_resources() fails.
+ ret = acpi_pci_probe_root_resources(info);
+ if (ops->prepare_resources)
+ ret = ops->prepare_resources(info, ret);
+ if (ret < 0)
+ goto out_release_info;
Quoted 6 lines
if (ops->prepare_resources) {
ret = ops->prepare_resources(info, ret);
if (ret < 0)
goto out_release_info;
}
pci_acpi_root_add_resources(info);I will remove the redundant check of (ret > 0) in:
+ else if (ret > 0)
+ pci_acpi_root_add_resources(info);
Quoted 10 lines
drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 844
Quoted 6 lines
drivers/acpi/pci_root.c +5
-0+pci_add_resource (&info->resources, &root->secondary); + + bus =pci_create_root_bus (NULL , busnum, ops->pci_ops, + sysdata, &info->resources); +if (bus) {if (!bus) goto out_release_info;
Quoted 2 lines
Then it looks like the other error paths above, and you can un-indent the following code, which is the normal path:
Will do this.
Thanks!
Gerry
Re: [Patch v6 4/7] PCI/ACPI: Consolidate common PCI host bridge code into ACPI core
Quoted 40 lines · Jiang Liu
Quoted 31 lines · Bjorn Helgaas
Quoted 16 lines
drivers/acpi/pci_root.c +16
-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);drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 839
Quoted 10 lines
drivers/acpi/pci_root.c +10
-0+ +if (ops->init_info && ops->init_info (info)) + goto out_release_info; + ret =acpi_pci_probe_root_resources (info); +if (ops->prepare_resources) + ret = ops->prepare_resources (info, ret); +if (ret <0 ) + goto out_release_info; +else if (ret >0 ) +pci_acpi_root_add_resources (info);This is unnecessarily complicated: you set "ret", then overwrite it if
ops->prepare_resources. By the time you test "ret", it's messy to figure out what it means.Quoted 7 lines
Both
ops->prepare_resources()andpci_acpi_root_add_resources()should be able to deal with empty resource lists, so can you do the following instead?ret = acpi_pci_probe_root_resources(info); if (ret < 0) goto out_release_info;
Quoted 5 lines
The original code is used to handle a special case for x86,
whereacpi_pci_probe_root_resources()fails butops->prepare_resources()succeeds. For x86, PCI host bridge resources may probed by means other than ACPI whenpci_use_crsis true (AMD and Broadcom hostbridges). So we can't return failure whenacpi_pci_probe_root_resources()fails.
That's even worse than I thought. I take back my ack; I think this really needs to be restructured so it does the right thing *and* reads clearly. Having convoluted generic code to deal with an arch-specific special case is a recipe for breakage in the future.
Maybe you can move the non-ACPI resource probing from prepare_resources() into acpi_pci_probe_root_resources() (you could rename it to something more generic if that helps).
Quoted 15 lines
drivers/acpi/pci_root.c +5
-0+ ret =acpi_pci_probe_root_resources (info); +if (ops->prepare_resources) + ret = ops->prepare_resources (info, ret); +if (ret <0 ) + goto out_release_info;Quoted 7 lines
if (ops->prepare_resources) { ret = ops->prepare_resources(info, ret); if (ret < 0) goto out_release_info; } pci_acpi_root_add_resources(info);I will remove the redundant check of (ret > 0) in:
drivers/acpi/pci_root.c +2
-0+else if (ret >0 ) +pci_acpi_root_add_resources (info);
Re: [Patch v6 4/7] PCI/ACPI: Consolidate common PCI host bridge code into ACPI core
Quoted 47 lines · Bjorn Helgaas
Quoted 40 lines · Jiang Liu
Quoted 31 lines · Bjorn Helgaas
Quoted 16 lines
drivers/acpi/pci_root.c +16
-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);drivers/acpi/pci_root.c static void acpi_pci_root_remove(struct acpi_device *device) · line 839
Quoted 10 lines
drivers/acpi/pci_root.c +10
-0+ +if (ops->init_info && ops->init_info (info)) + goto out_release_info; + ret =acpi_pci_probe_root_resources (info); +if (ops->prepare_resources) + ret = ops->prepare_resources (info, ret); +if (ret <0 ) + goto out_release_info; +else if (ret >0 ) +pci_acpi_root_add_resources (info);This is unnecessarily complicated: you set "ret", then overwrite it if
ops->prepare_resources. By the time you test "ret", it's messy to figure out what it means.Quoted 7 lines
Both
ops->prepare_resources()andpci_acpi_root_add_resources()should be able to deal with empty resource lists, so can you do the following instead?ret = acpi_pci_probe_root_resources(info); if (ret < 0) goto out_release_info;Quoted 5 lines
The original code is used to handle a special case for x86,
whereacpi_pci_probe_root_resources()fails butops->prepare_resources()succeeds. For x86, PCI host bridge resources may probed by means other than ACPI whenpci_use_crsis true (AMD and Broadcom hostbridges). So we can't return failure whenacpi_pci_probe_root_resources()fails.
Quoted 8 lines
That's even worse than I thought. I take back my ack; I think this really needs to be restructured so it does the right thing *and* reads clearly. Having convoluted generic code to deal with an arch-specific special case is a recipe for breakage in the future.
Maybe you can move the non-ACPI resource probing from
prepare_resources()intoacpi_pci_probe_root_resources()(you could rename it to something more generic if that helps).
Hi Bjorn,
How about this solution?
1) export acpi_pci_probe_root_resources() as a helper to arch code
2) change ACPI core code as below
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;By this way, if arch has special requirement, it could implement prepare_resources callback and make use of acpi_pci_probe_root_resources() if needed.
Thanks!
Gerry
PATCH v6 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
Re: [Patch v6 5/7] ACPI, PCI: Reset acpi_root_dev->domain to 0 when pci_ignore_seg is set
Quoted 4 lines · Jiang Liu
Reset
acpi_root_dev->domainto 0 whenpci_ignore_segis set to keep consistence between ACPI PCI root device and PCI host bridge device.Signed-off-by Jiang Liu <[email protected]>
Quoted 25 lines
--- 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 · 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/
PATCH v6 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 | 293 +++++++++++++++------------------------------------ 1 file changed, 86 insertions(+), 207 deletions(-)
arch/x86/pci/acpi.c +86 -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,43 @@ 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 status) { -int ret; +struct acpi_device *device = ci->bridge; +int busnum = ci->root->secondary.start;struct resource_entry *entry, *tmp; -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)) +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 +330,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 +369,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 v6 6/7] x86/PCI/ACPI: Use common interface to support PCI host bridge
Quoted 4 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]>
Is there a corresponding ia64 patch? If we're really consolidating this code (which I completely support), we need to do the whole job.
Quoted 3 lines
--- arch/x86/pci/acpi.c | 293 +++++++++++++++------------------------------------ 1 file changed, 86 insertions(+), 207 deletions(-)
Re: [Patch v6 6/7] x86/PCI/ACPI: Use common interface to support PCI host bridge
Quoted 8 lines · Bjorn Helgaas
Quoted 4 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]>Is there a corresponding ia64 patch? If we're really consolidating this code (which I completely support), we need to do the whole job.
Yes, there is a patch for it:
[Patch v6 7/7] ia64/PCI/ACPI: Use common interface to support PCI host bridge
which has lots of code simplification [1],
arch/ia64/pci/pci.c | 232 ++++++++++----------------------------------------- 1 file changed, 46 insertions(+), 186 deletions(-)
[1]: https://lkml.org/lkml/2015/9/14/84
Thanks
Hanjun
Re: [Patch v6 6/7] x86/PCI/ACPI: Use common interface to support PCI host bridge
Quoted 15 lines · Hanjun Guo
Quoted 8 lines · Bjorn Helgaas
Quoted 4 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]>Is there a corresponding ia64 patch? If we're really consolidating this code (which I completely support), we need to do the whole job.
Yes, there is a patch for it:
[Patch v6 7/7] ia64/PCI/ACPI: Use common interface to support PCI host bridge
Quoted 7 lines
which has lots of code simplification [1],
arch/ia64/pci/pci.c | 232 ++++++++++----------------------------------------- 1 file changed, 46 insertions(+), 186 deletions(-)
Oh, sorry I missed that. I review things that appear on linux-pci, and several patches in this series weren't posted there, so I didn't see them.
Bjorn
PATCH v6 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 | 232 ++++++++++----------------------------------------- 1 file changed, 46 insertions(+), 186 deletions(-)
arch/ia64/pci/pci.c +46 -186
@@ -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,80 @@ 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 status) { -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; +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