Re: [Update 2][PATCH] ACPI / PCI: Set root bridge ACPI handle in advance

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wednesday, December 19, 2012 06:00:18 AM Zheng, Lv wrote:
> Will future implementation move _REG evaluations from ACPICA core to a place before
> driver->probe as all of the physical devices will know their "acpi_handle" soon after
> it is created.

We may do that, although quite frankly I haven't been considering that.

> This seems to be a solution to solve problems can be found like:
> Orphan _REG / _DEP support...
> I'm not sure though this sounds better to make ones operational regions ready
> only if a driver is going to be "attached" to the physical device.

Well, they may be accessed by unrelated AML in theory.

Thanks,
Rafael


> > -----Original Message-----
> > From: linux-acpi-owner@xxxxxxxxxxxxxxx
> > [mailto:linux-acpi-owner@xxxxxxxxxxxxxxx] On Behalf Of Rafael J. Wysocki
> > Sent: Tuesday, December 18, 2012 7:30 AM
> > To: ACPI Devel Maling List
> > Cc: Greg Kroah-Hartman; LKML; Bjorn Helgaas; Benjamin Herrenschmidt;
> > David Miller; Luck, Tony; H. Peter Anvin; Yinghai Lu; Jiang Liu; Martin
> > Schwidefsky; Jan Glauber
> > Subject: [Update 2][PATCH] ACPI / PCI: Set root bridge ACPI handle in advance
> > 
> > From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
> > 
> > The ACPI handles of PCI root bridges need to be known to
> > acpi_bind_one(), so that it can create the appropriate
> > "firmware_node" and "physical_node" files for them, but currently
> > the way it gets to know those handles is not exactly straightforward
> > (to put it lightly).
> > 
> > This is how it works, roughly:
> > 
> >   1. acpi_bus_scan() finds the handle of a PCI root bridge,
> >      creates a struct acpi_device object for it and passes that
> >      object to acpi_pci_root_add().
> > 
> >   2. acpi_pci_root_add() creates a struct acpi_pci_root object,
> >      populates its "device" field with its argument's address
> >      (device->handle is the ACPI handle found in step 1).
> > 
> >   3. The struct acpi_pci_root object created in step 2 is passed
> >      to pci_acpi_scan_root() and used to get resources that are
> >      passed to pci_create_root_bus().
> > 
> >   4. pci_create_root_bus() creates a struct pci_host_bridge object
> >      and passes its "dev" member to device_register().
> > 
> >   5. platform_notify(), which for systems with ACPI is set to
> >      acpi_platform_notify(), is called.
> > 
> > So far, so good.  Now it starts to be "interesting".
> > 
> >   6. acpi_find_bridge_device() is used to find the ACPI handle of
> >      the given device (which is the PCI root bridge) and executes
> >      acpi_pci_find_root_bridge(), among other things, for the
> >      given device object.
> > 
> >   7. acpi_pci_find_root_bridge() uses the name (sic!) of the given
> >      device object to extract the segment and bus numbers of the PCI
> >      root bridge and passes them to acpi_get_pci_rootbridge_handle().
> > 
> >   8. acpi_get_pci_rootbridge_handle() browses the list of ACPI PCI
> >      root bridges and finds the one that matches the given segment
> >      and bus numbers.  Its handle is then used to initialize the
> >      ACPI handle of the PCI root bridge's device object by
> >      acpi_bind_one().  However, this is *exactly* the ACPI handle we
> >      started with in step 1.
> > 
> > Needless to say, this is quite embarassing, but it may be avoided
> > thanks to commit f3fd0c8 (ACPI: Allow ACPI handles of devices to be
> > initialized in advance), which makes it possible to initialize the
> > ACPI handle of a device before passing it to device_register().
> > 
> > Accordingly, make pci_acpi_scan_root() pass the root bridge's ACPI
> > handle to pci_create_root_bus() and make the latter set the ACPI
> > handle in its struct pci_host_bridge object's "dev" member before
> > passing it to device_register(), so that steps 6-8 above aren't
> > necessary any more.
> > 
> > To implement that, I decided to repurpose the 4th argument of
> > pci_create_root_bus(), because that allowed me to avoid defining
> > additional callbacks or similar things and didn't seem to impact
> > architectures without ACPI substantially.
> > 
> > All architectures using pci_create_root_bus() directly are updated
> > as needed, but only x86 and ia64 are affected as far as the behavior
> > is concerned (no one else uses ACPI).  There should be no changes in
> > behavior resulting from this on the other architectures.
> > 
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
> > Acked-by: Yinghai Lu <yinghai@xxxxxxxxxx>
> > Acked-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
> > Acked-by: H. Peter Anvin <hpa@xxxxxxxxx>
> > ---
> > 
> > Peter Anvin pointed out to me that it's better to make it clear in the
> > changelog what the patch actually does versus what might be left as future
> > work, so here's another update with a slightly modified (and hopefully better)
> > changelog.  The patch itself hasn't been changed.
> > 
> > Thanks,
> > Rafael
> > 
> > ---
> >  arch/ia64/pci/pci.c              |    5 ++++-
> >  arch/powerpc/kernel/pci-common.c |    3 ++-
> >  arch/s390/pci/pci.c              |    3 ++-
> >  arch/sparc/kernel/pci.c          |    3 ++-
> >  arch/x86/pci/acpi.c              |    5 ++++-
> >  drivers/acpi/pci_root.c          |   18 ------------------
> >  drivers/pci/pci-acpi.c           |   19 -------------------
> >  drivers/pci/probe.c              |   17 ++++++++++++-----
> >  include/acpi/acpi_bus.h          |    1 -
> >  include/linux/pci.h              |    9 ++++++++-
> >  10 files changed, 34 insertions(+), 49 deletions(-)
> > 
> > Index: linux-pm/arch/x86/pci/acpi.c
> > ================================================================
> > ===
> > --- linux-pm.orig/arch/x86/pci/acpi.c
> > +++ linux-pm/arch/x86/pci/acpi.c
> > @@ -483,6 +483,7 @@ struct pci_bus * __devinit pci_acpi_scan
> >  	LIST_HEAD(resources);
> >  	struct pci_bus *bus = NULL;
> >  	struct pci_sysdata *sd;
> > +	struct pci_root_sys_info si;
> >  	int node;
> >  #ifdef CONFIG_ACPI_NUMA
> >  	int pxm;
> > @@ -522,6 +523,8 @@ struct pci_bus * __devinit pci_acpi_scan
> >  	sd = &info->sd;
> >  	sd->domain = domain;
> >  	sd->node = node;
> > +	si.acpi_node.handle = device->handle;
> > +	si.sysdata = sd;
> >  	/*
> >  	 * Maybe the desired pci bus has been already scanned. In such case
> >  	 * it is unnecessary to scan the pci bus with the given domain,busnum.
> > @@ -553,7 +556,7 @@ struct pci_bus * __devinit pci_acpi_scan
> >  		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);
> > +						  &si, &resources);
> > 
> >  		if (bus) {
> >  			pci_scan_child_bus(bus);
> > Index: linux-pm/drivers/pci/probe.c
> > ================================================================
> > ===
> > --- linux-pm.orig/drivers/pci/probe.c
> > +++ linux-pm/drivers/pci/probe.c
> > @@ -1634,7 +1634,9 @@ unsigned int pci_scan_child_bus(struct p
> >  }
> > 
> >  struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> > -		struct pci_ops *ops, void *sysdata, struct list_head *resources)
> > +				    struct pci_ops *ops,
> > +				    struct pci_root_sys_info *sys_info,
> > +				    struct list_head *resources)
> >  {
> >  	int error;
> >  	struct pci_host_bridge *bridge;
> > @@ -1650,7 +1652,7 @@ struct pci_bus *pci_create_root_bus(stru
> >  	if (!b)
> >  		return NULL;
> > 
> > -	b->sysdata = sysdata;
> > +	b->sysdata = sys_info ? sys_info->sysdata : NULL;
> >  	b->ops = ops;
> >  	b2 = pci_find_bus(pci_domain_nr(b), bus);
> >  	if (b2) {
> > @@ -1666,6 +1668,8 @@ struct pci_bus *pci_create_root_bus(stru
> >  	bridge->dev.parent = parent;
> >  	bridge->dev.release = pci_release_bus_bridge_dev;
> >  	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
> > +	ACPI_HANDLE_SET(&bridge->dev,
> > +			sys_info ? sys_info->acpi_node.handle : NULL);
> >  	error = device_register(&bridge->dev);
> >  	if (error)
> >  		goto bridge_dev_reg_err;
> > @@ -1798,6 +1802,7 @@ struct pci_bus *pci_scan_root_bus(struct
> >  		struct pci_ops *ops, void *sysdata, struct list_head *resources)
> >  {
> >  	struct pci_host_bridge_window *window;
> > +	struct pci_root_sys_info si = { .sysdata = sysdata, };
> >  	bool found = false;
> >  	struct pci_bus *b;
> >  	int max;
> > @@ -1808,7 +1813,7 @@ struct pci_bus *pci_scan_root_bus(struct
> >  			break;
> >  		}
> > 
> > -	b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
> > +	b = pci_create_root_bus(parent, bus, ops, &si, resources);
> >  	if (!b)
> >  		return NULL;
> > 
> > @@ -1833,13 +1838,14 @@ EXPORT_SYMBOL(pci_scan_root_bus);
> >  struct pci_bus *pci_scan_bus_parented(struct device *parent,
> >  		int bus, struct pci_ops *ops, void *sysdata)
> >  {
> > +	struct pci_root_sys_info si = { .sysdata = sysdata, };
> >  	LIST_HEAD(resources);
> >  	struct pci_bus *b;
> > 
> >  	pci_add_resource(&resources, &ioport_resource);
> >  	pci_add_resource(&resources, &iomem_resource);
> >  	pci_add_resource(&resources, &busn_resource);
> > -	b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
> > +	b = pci_create_root_bus(parent, bus, ops, &si, &resources);
> >  	if (b)
> >  		pci_scan_child_bus(b);
> >  	else
> > @@ -1851,13 +1857,14 @@ EXPORT_SYMBOL(pci_scan_bus_parented);
> >  struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
> >  					void *sysdata)
> >  {
> > +	struct pci_root_sys_info si = { .sysdata = sysdata, };
> >  	LIST_HEAD(resources);
> >  	struct pci_bus *b;
> > 
> >  	pci_add_resource(&resources, &ioport_resource);
> >  	pci_add_resource(&resources, &iomem_resource);
> >  	pci_add_resource(&resources, &busn_resource);
> > -	b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
> > +	b = pci_create_root_bus(NULL, bus, ops, &si, &resources);
> >  	if (b) {
> >  		pci_scan_child_bus(b);
> >  		pci_bus_add_devices(b);
> > Index: linux-pm/include/linux/pci.h
> > ================================================================
> > ===
> > --- linux-pm.orig/include/linux/pci.h
> > +++ linux-pm/include/linux/pci.h
> > @@ -700,8 +700,15 @@ void pci_bus_add_devices(const struct pc
> >  struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
> >  				      struct pci_ops *ops, void *sysdata);
> >  struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
> > +
> > +struct pci_root_sys_info {
> > +	void *sysdata;
> > +	struct acpi_dev_node acpi_node;
> > +};
> > +
> >  struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> > -				    struct pci_ops *ops, void *sysdata,
> > +				    struct pci_ops *ops,
> > +				    struct pci_root_sys_info *sys_info,
> >  				    struct list_head *resources);
> >  int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
> >  int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
> > Index: linux-pm/arch/ia64/pci/pci.c
> > ================================================================
> > ===
> > --- linux-pm.orig/arch/ia64/pci/pci.c
> > +++ linux-pm/arch/ia64/pci/pci.c
> > @@ -333,6 +333,7 @@ pci_acpi_scan_root(struct acpi_pci_root
> >  	struct pci_controller *controller;
> >  	unsigned int windows = 0;
> >  	struct pci_root_info info;
> > +	struct pci_root_sys_info si;
> >  	struct pci_bus *pbus;
> >  	char *name;
> >  	int pxm;
> > @@ -378,7 +379,9 @@ pci_acpi_scan_root(struct acpi_pci_root
> >  	 * 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,
> > +	si.sysdata = controller;
> > +	si.acpi_node.handle = controller->acpi_handle;
> > +	pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, &si,
> >  				   &info.resources);
> >  	if (!pbus) {
> >  		pci_free_resource_list(&info.resources);
> > Index: linux-pm/arch/powerpc/kernel/pci-common.c
> > ================================================================
> > ===
> > --- linux-pm.orig/arch/powerpc/kernel/pci-common.c
> > +++ linux-pm/arch/powerpc/kernel/pci-common.c
> > @@ -1644,6 +1644,7 @@ void __devinit pcibios_scan_phb(struct p
> >  	LIST_HEAD(resources);
> >  	struct pci_bus *bus;
> >  	struct device_node *node = hose->dn;
> > +	struct pci_root_sys_info si = { .sysdata = hose, };
> >  	int mode;
> > 
> >  	pr_debug("PCI: Scanning PHB %s\n", of_node_full_name(node));
> > @@ -1661,7 +1662,7 @@ void __devinit pcibios_scan_phb(struct p
> > 
> >  	/* Create an empty bus for the toplevel */
> >  	bus = pci_create_root_bus(hose->parent, hose->first_busno,
> > -				  hose->ops, hose, &resources);
> > +				  hose->ops, &si, &resources);
> >  	if (bus == NULL) {
> >  		pr_err("Failed to create bus for PCI domain %04x\n",
> >  			hose->global_number);
> > Index: linux-pm/arch/sparc/kernel/pci.c
> > ================================================================
> > ===
> > --- linux-pm.orig/arch/sparc/kernel/pci.c
> > +++ linux-pm/arch/sparc/kernel/pci.c
> > @@ -590,6 +590,7 @@ struct pci_bus * __devinit pci_scan_one_
> >  {
> >  	LIST_HEAD(resources);
> >  	struct device_node *node = pbm->op->dev.of_node;
> > +	struct pci_root_sys_info si = { .sysdata = pbm, };
> >  	struct pci_bus *bus;
> > 
> >  	printk("PCI: Scanning PBM %s\n", node->full_name);
> > @@ -603,7 +604,7 @@ struct pci_bus * __devinit pci_scan_one_
> >  	pbm->busn.flags	= IORESOURCE_BUS;
> >  	pci_add_resource(&resources, &pbm->busn);
> >  	bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
> > -				  pbm, &resources);
> > +				  &si, &resources);
> >  	if (!bus) {
> >  		printk(KERN_ERR "Failed to create bus for %s\n",
> >  		       node->full_name);
> > Index: linux-pm/drivers/pci/pci-acpi.c
> > ================================================================
> > ===
> > --- linux-pm.orig/drivers/pci/pci-acpi.c
> > +++ linux-pm/drivers/pci/pci-acpi.c
> > @@ -303,28 +303,9 @@ static int acpi_pci_find_device(struct d
> >  	return 0;
> >  }
> > 
> > -static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
> > -{
> > -	int num;
> > -	unsigned int seg, bus;
> > -
> > -	/*
> > -	 * The string should be the same as root bridge's name
> > -	 * Please look at 'pci_scan_bus_parented'
> > -	 */
> > -	num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus);
> > -	if (num != 2)
> > -		return -ENODEV;
> > -	*handle = acpi_get_pci_rootbridge_handle(seg, bus);
> > -	if (!*handle)
> > -		return -ENODEV;
> > -	return 0;
> > -}
> > -
> >  static struct acpi_bus_type acpi_pci_bus = {
> >  	.bus = &pci_bus_type,
> >  	.find_device = acpi_pci_find_device,
> > -	.find_bridge = acpi_pci_find_root_bridge,
> >  };
> > 
> >  static int __init acpi_pci_init(void)
> > Index: linux-pm/drivers/acpi/pci_root.c
> > ================================================================
> > ===
> > --- linux-pm.orig/drivers/acpi/pci_root.c
> > +++ linux-pm/drivers/acpi/pci_root.c
> > @@ -107,24 +107,6 @@ void acpi_pci_unregister_driver(struct a
> >  }
> >  EXPORT_SYMBOL(acpi_pci_unregister_driver);
> > 
> > -acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int
> > bus)
> > -{
> > -	struct acpi_pci_root *root;
> > -	acpi_handle handle = NULL;
> > -
> > -	mutex_lock(&acpi_pci_root_lock);
> > -	list_for_each_entry(root, &acpi_pci_roots, node)
> > -		if ((root->segment == (u16) seg) &&
> > -		    (root->secondary.start == (u16) bus)) {
> > -			handle = root->device->handle;
> > -			break;
> > -		}
> > -	mutex_unlock(&acpi_pci_root_lock);
> > -	return handle;
> > -}
> > -
> > -EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
> > -
> >  /**
> >   * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root
> > bridge
> >   * @handle - the ACPI CA node in question.
> > Index: linux-pm/include/acpi/acpi_bus.h
> > ================================================================
> > ===
> > --- linux-pm.orig/include/acpi/acpi_bus.h
> > +++ linux-pm/include/acpi/acpi_bus.h
> > @@ -443,7 +443,6 @@ struct acpi_pci_root {
> >  /* helper */
> >  acpi_handle acpi_get_child(acpi_handle, u64);
> >  int acpi_is_root_bridge(acpi_handle);
> > -acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
> >  struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
> >  #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev))
> > 
> > Index: linux-pm/arch/s390/pci/pci.c
> > ================================================================
> > ===
> > --- linux-pm.orig/arch/s390/pci/pci.c
> > +++ linux-pm/arch/s390/pci/pci.c
> > @@ -852,6 +852,7 @@ static void zpci_free_iomap(struct zpci_
> > 
> >  static int zpci_create_device_bus(struct zpci_dev *zdev)
> >  {
> > +	struct pci_root_sys_info si = { .sysdata = zdev, };
> >  	struct resource *res;
> >  	LIST_HEAD(resources);
> >  	int i;
> > @@ -888,7 +889,7 @@ static int zpci_create_device_bus(struct
> >  	}
> > 
> >  	zdev->bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
> > -					zdev, &resources);
> > +					&si, &resources);
> >  	if (!zdev->bus)
> >  		return -EIO;
> > 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> > the body of a message to majordomo@xxxxxxxxxxxxxxx
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux