forked from mirrors/linux
		
	ACPI: Allow ACPI handles of devices to be initialized in advance
Currently, the ACPI handles of devices are initialized from within device_add(), by acpi_bind_one() called from acpi_platform_notify() which first uses the .find_device() routine provided by the device's bus type to find the matching device node in the ACPI namespace. This is a source of some computational overhead and, moreover, the correctness of the result depends on the implementation of .find_device() which is known to fail occasionally for some bus types (e.g. PCI). In some cases, however, the corresponding ACPI device node is known already before calling device_add() for the given struct device object and the whole .find_device() dance in acpi_platform_notify() is then simply unnecessary. For this reason, make it possible to initialize the ACPI handles of devices before calling device_add() for them. Modify acpi_platform_notify() to call acpi_bind_one() in advance to check the device's existing ACPI handle and skip the .find_device() search if that is successful. Change acpi_bind_one() accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
		
							parent
							
								
									8a66790b78
								
							
						
					
					
						commit
						f3fd0c8a7f
					
				
					 1 changed files with 34 additions and 10 deletions
				
			
		| 
						 | 
					@ -130,46 +130,59 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct acpi_device *acpi_dev;
 | 
						struct acpi_device *acpi_dev;
 | 
				
			||||||
	acpi_status status;
 | 
						acpi_status status;
 | 
				
			||||||
	struct acpi_device_physical_node *physical_node;
 | 
						struct acpi_device_physical_node *physical_node, *pn;
 | 
				
			||||||
	char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
 | 
						char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
 | 
				
			||||||
	int retval = -EINVAL;
 | 
						int retval = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev->acpi_handle) {
 | 
						if (dev->acpi_handle) {
 | 
				
			||||||
		dev_warn(dev, "Drivers changed 'acpi_handle'\n");
 | 
							if (handle) {
 | 
				
			||||||
		return -EINVAL;
 | 
								dev_warn(dev, "ACPI handle is already set\n");
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								handle = dev->acpi_handle;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!handle)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	get_device(dev);
 | 
						get_device(dev);
 | 
				
			||||||
	status = acpi_bus_get_device(handle, &acpi_dev);
 | 
						status = acpi_bus_get_device(handle, &acpi_dev);
 | 
				
			||||||
	if (ACPI_FAILURE(status))
 | 
						if (ACPI_FAILURE(status))
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	physical_node = kzalloc(sizeof(struct acpi_device_physical_node),
 | 
						physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
 | 
				
			||||||
		GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!physical_node) {
 | 
						if (!physical_node) {
 | 
				
			||||||
		retval = -ENOMEM;
 | 
							retval = -ENOMEM;
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&acpi_dev->physical_node_lock);
 | 
						mutex_lock(&acpi_dev->physical_node_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Sanity check. */
 | 
				
			||||||
 | 
						list_for_each_entry(pn, &acpi_dev->physical_node_list, node)
 | 
				
			||||||
 | 
							if (pn->dev == dev) {
 | 
				
			||||||
 | 
								dev_warn(dev, "Already associated with ACPI node\n");
 | 
				
			||||||
 | 
								goto err_free;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* allocate physical node id according to physical_node_id_bitmap */
 | 
						/* allocate physical node id according to physical_node_id_bitmap */
 | 
				
			||||||
	physical_node->node_id =
 | 
						physical_node->node_id =
 | 
				
			||||||
		find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
 | 
							find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
 | 
				
			||||||
		ACPI_MAX_PHYSICAL_NODE);
 | 
							ACPI_MAX_PHYSICAL_NODE);
 | 
				
			||||||
	if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
 | 
						if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
 | 
				
			||||||
		retval = -ENOSPC;
 | 
							retval = -ENOSPC;
 | 
				
			||||||
		mutex_unlock(&acpi_dev->physical_node_lock);
 | 
							goto err_free;
 | 
				
			||||||
		kfree(physical_node);
 | 
					 | 
				
			||||||
		goto err;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
 | 
						set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
 | 
				
			||||||
	physical_node->dev = dev;
 | 
						physical_node->dev = dev;
 | 
				
			||||||
	list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
 | 
						list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
 | 
				
			||||||
	acpi_dev->physical_node_count++;
 | 
						acpi_dev->physical_node_count++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&acpi_dev->physical_node_lock);
 | 
						mutex_unlock(&acpi_dev->physical_node_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev->acpi_handle = handle;
 | 
						if (!dev->acpi_handle)
 | 
				
			||||||
 | 
							dev->acpi_handle = handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!physical_node->node_id)
 | 
						if (!physical_node->node_id)
 | 
				
			||||||
		strcpy(physical_node_name, PHYSICAL_NODE_STRING);
 | 
							strcpy(physical_node_name, PHYSICAL_NODE_STRING);
 | 
				
			||||||
| 
						 | 
					@ -187,8 +200,14 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 err:
 | 
					 err:
 | 
				
			||||||
 | 
						dev->acpi_handle = NULL;
 | 
				
			||||||
	put_device(dev);
 | 
						put_device(dev);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 err_free:
 | 
				
			||||||
 | 
						mutex_unlock(&acpi_dev->physical_node_lock);
 | 
				
			||||||
 | 
						kfree(physical_node);
 | 
				
			||||||
 | 
						goto err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int acpi_unbind_one(struct device *dev)
 | 
					static int acpi_unbind_one(struct device *dev)
 | 
				
			||||||
| 
						 | 
					@ -247,6 +266,10 @@ static int acpi_platform_notify(struct device *dev)
 | 
				
			||||||
	acpi_handle handle;
 | 
						acpi_handle handle;
 | 
				
			||||||
	int ret = -EINVAL;
 | 
						int ret = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = acpi_bind_one(dev, NULL);
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dev->bus || !dev->parent) {
 | 
						if (!dev->bus || !dev->parent) {
 | 
				
			||||||
		/* bridge devices genernally haven't bus or parent */
 | 
							/* bridge devices genernally haven't bus or parent */
 | 
				
			||||||
		ret = acpi_find_bridge_device(dev, &handle);
 | 
							ret = acpi_find_bridge_device(dev, &handle);
 | 
				
			||||||
| 
						 | 
					@ -260,10 +283,11 @@ static int acpi_platform_notify(struct device *dev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ((ret = type->find_device(dev, &handle)) != 0)
 | 
						if ((ret = type->find_device(dev, &handle)) != 0)
 | 
				
			||||||
		DBG("Can't get handler for %s\n", dev_name(dev));
 | 
							DBG("Can't get handler for %s\n", dev_name(dev));
 | 
				
			||||||
      end:
 | 
					 end:
 | 
				
			||||||
	if (!ret)
 | 
						if (!ret)
 | 
				
			||||||
		acpi_bind_one(dev, handle);
 | 
							acpi_bind_one(dev, handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 out:
 | 
				
			||||||
#if ACPI_GLUE_DEBUG
 | 
					#if ACPI_GLUE_DEBUG
 | 
				
			||||||
	if (!ret) {
 | 
						if (!ret) {
 | 
				
			||||||
		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 | 
							struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue