xref: /openbmc/linux/drivers/acpi/glue.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
155716d26SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24e10d12aSDavid Shaohua Li /*
34e10d12aSDavid Shaohua Li  * Link physical devices with ACPI devices support
44e10d12aSDavid Shaohua Li  *
54e10d12aSDavid Shaohua Li  * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
64e10d12aSDavid Shaohua Li  * Copyright (c) 2005 Intel Corp.
74e10d12aSDavid Shaohua Li  */
8d4f54a18SHanjun Guo 
9e2935abbSHanjun Guo #define pr_fmt(fmt) "ACPI: " fmt
10e2935abbSHanjun Guo 
11d4f54a18SHanjun Guo #include <linux/acpi_iort.h>
12214f2c90SPaul Gortmaker #include <linux/export.h>
134e10d12aSDavid Shaohua Li #include <linux/init.h>
144e10d12aSDavid Shaohua Li #include <linux/list.h>
154e10d12aSDavid Shaohua Li #include <linux/device.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
174e10d12aSDavid Shaohua Li #include <linux/rwsem.h>
184e10d12aSDavid Shaohua Li #include <linux/acpi.h>
19d0562674SSuthikulpanit, Suravee #include <linux/dma-mapping.h>
2047954481SRafael J. Wysocki #include <linux/pci.h>
2147954481SRafael J. Wysocki #include <linux/pci-acpi.h>
22d4f54a18SHanjun Guo #include <linux/platform_device.h>
234e10d12aSDavid Shaohua Li 
24a192a958SLen Brown #include "internal.h"
25a192a958SLen Brown 
264e10d12aSDavid Shaohua Li static LIST_HEAD(bus_type_list);
274e10d12aSDavid Shaohua Li static DECLARE_RWSEM(bus_type_sem);
284e10d12aSDavid Shaohua Li 
291033f904SLan Tianyu #define PHYSICAL_NODE_STRING "physical_node"
30007ccfcfSRafael J. Wysocki #define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
311033f904SLan Tianyu 
register_acpi_bus_type(struct acpi_bus_type * type)324e10d12aSDavid Shaohua Li int register_acpi_bus_type(struct acpi_bus_type *type)
334e10d12aSDavid Shaohua Li {
344e10d12aSDavid Shaohua Li 	if (acpi_disabled)
354e10d12aSDavid Shaohua Li 		return -ENODEV;
36e3f02c52SRafael J. Wysocki 	if (type && type->match && type->find_companion) {
374e10d12aSDavid Shaohua Li 		down_write(&bus_type_sem);
384e10d12aSDavid Shaohua Li 		list_add_tail(&type->list, &bus_type_list);
394e10d12aSDavid Shaohua Li 		up_write(&bus_type_sem);
40e2935abbSHanjun Guo 		pr_info("bus type %s registered\n", type->name);
414e10d12aSDavid Shaohua Li 		return 0;
424e10d12aSDavid Shaohua Li 	}
434e10d12aSDavid Shaohua Li 	return -ENODEV;
444e10d12aSDavid Shaohua Li }
4591e4d5a1SJeff Garzik EXPORT_SYMBOL_GPL(register_acpi_bus_type);
464e10d12aSDavid Shaohua Li 
unregister_acpi_bus_type(struct acpi_bus_type * type)474e10d12aSDavid Shaohua Li int unregister_acpi_bus_type(struct acpi_bus_type *type)
484e10d12aSDavid Shaohua Li {
494e10d12aSDavid Shaohua Li 	if (acpi_disabled)
504e10d12aSDavid Shaohua Li 		return 0;
514e10d12aSDavid Shaohua Li 	if (type) {
524e10d12aSDavid Shaohua Li 		down_write(&bus_type_sem);
534e10d12aSDavid Shaohua Li 		list_del_init(&type->list);
544e10d12aSDavid Shaohua Li 		up_write(&bus_type_sem);
55e2935abbSHanjun Guo 		pr_info("bus type %s unregistered\n", type->name);
564e10d12aSDavid Shaohua Li 		return 0;
574e10d12aSDavid Shaohua Li 	}
584e10d12aSDavid Shaohua Li 	return -ENODEV;
594e10d12aSDavid Shaohua Li }
6091e4d5a1SJeff Garzik EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
614e10d12aSDavid Shaohua Li 
acpi_get_bus_type(struct device * dev)6253540098SRafael J. Wysocki static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
634e10d12aSDavid Shaohua Li {
644e10d12aSDavid Shaohua Li 	struct acpi_bus_type *tmp, *ret = NULL;
654e10d12aSDavid Shaohua Li 
664e10d12aSDavid Shaohua Li 	down_read(&bus_type_sem);
674e10d12aSDavid Shaohua Li 	list_for_each_entry(tmp, &bus_type_list, list) {
6853540098SRafael J. Wysocki 		if (tmp->match(dev)) {
694e10d12aSDavid Shaohua Li 			ret = tmp;
704e10d12aSDavid Shaohua Li 			break;
714e10d12aSDavid Shaohua Li 		}
724e10d12aSDavid Shaohua Li 	}
734e10d12aSDavid Shaohua Li 	up_read(&bus_type_sem);
744e10d12aSDavid Shaohua Li 	return ret;
754e10d12aSDavid Shaohua Li }
764e10d12aSDavid Shaohua Li 
7711b88ee2SRafael J. Wysocki #define FIND_CHILD_MIN_SCORE	1
78*f64e4275SHans de Goede #define FIND_CHILD_MID_SCORE	2
79*f64e4275SHans de Goede #define FIND_CHILD_MAX_SCORE	3
8011b88ee2SRafael J. Wysocki 
match_any(struct acpi_device * adev,void * not_used)81f5122be8SRafael J. Wysocki static int match_any(struct acpi_device *adev, void *not_used)
82f5122be8SRafael J. Wysocki {
83f5122be8SRafael J. Wysocki 	return 1;
84f5122be8SRafael J. Wysocki }
85f5122be8SRafael J. Wysocki 
acpi_dev_has_children(struct acpi_device * adev)86f5122be8SRafael J. Wysocki static bool acpi_dev_has_children(struct acpi_device *adev)
87f5122be8SRafael J. Wysocki {
88f5122be8SRafael J. Wysocki 	return acpi_dev_for_each_child(adev, match_any, NULL) > 0;
89f5122be8SRafael J. Wysocki }
90f5122be8SRafael J. Wysocki 
find_child_checks(struct acpi_device * adev,bool check_children)91d9fef0c4SRafael J. Wysocki static int find_child_checks(struct acpi_device *adev, bool check_children)
924e10d12aSDavid Shaohua Li {
9360f75b8eSRafael J. Wysocki 	unsigned long long sta;
9460f75b8eSRafael J. Wysocki 	acpi_status status;
954e10d12aSDavid Shaohua Li 
96f5122be8SRafael J. Wysocki 	if (check_children && !acpi_dev_has_children(adev))
9711b88ee2SRafael J. Wysocki 		return -ENODEV;
984e10d12aSDavid Shaohua Li 
99b7fbf4ceSRafael J. Wysocki 	status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
100*f64e4275SHans de Goede 	if (status == AE_NOT_FOUND) {
101*f64e4275SHans de Goede 		/*
102*f64e4275SHans de Goede 		 * Special case: backlight device objects without _STA are
103*f64e4275SHans de Goede 		 * preferred to other objects with the same _ADR value, because
104*f64e4275SHans de Goede 		 * it is more likely that they are actually useful.
105*f64e4275SHans de Goede 		 */
106*f64e4275SHans de Goede 		if (adev->pnp.type.backlight)
107*f64e4275SHans de Goede 			return FIND_CHILD_MID_SCORE;
108*f64e4275SHans de Goede 
109b7fbf4ceSRafael J. Wysocki 		return FIND_CHILD_MIN_SCORE;
110*f64e4275SHans de Goede 	}
111b7fbf4ceSRafael J. Wysocki 
112b7fbf4ceSRafael J. Wysocki 	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
11311b88ee2SRafael J. Wysocki 		return -ENODEV;
114d9fef0c4SRafael J. Wysocki 
115c2a6bbafSRafael J. Wysocki 	/*
116fdad4e7aSRafael J. Wysocki 	 * If the device has a _HID returning a valid ACPI/PNP device ID, it is
117fdad4e7aSRafael J. Wysocki 	 * better to make it look less attractive here, so that the other device
118fdad4e7aSRafael J. Wysocki 	 * with the same _ADR value (that may not have a valid device ID) can be
119fdad4e7aSRafael J. Wysocki 	 * matched going forward.  [This means a second spec violation in a row,
120fdad4e7aSRafael J. Wysocki 	 * so whatever we do here is best effort anyway.]
121c2a6bbafSRafael J. Wysocki 	 */
122b7fbf4ceSRafael J. Wysocki 	if (adev->pnp.type.platform_id)
123b7fbf4ceSRafael J. Wysocki 		return FIND_CHILD_MIN_SCORE;
124b7fbf4ceSRafael J. Wysocki 
125b7fbf4ceSRafael J. Wysocki 	return FIND_CHILD_MAX_SCORE;
12660f75b8eSRafael J. Wysocki }
12760f75b8eSRafael J. Wysocki 
128d21b5700SRafael J. Wysocki struct find_child_walk_data {
129d21b5700SRafael J. Wysocki 	struct acpi_device *adev;
130d21b5700SRafael J. Wysocki 	u64 address;
131d21b5700SRafael J. Wysocki 	int score;
1322f6fe93fSRafael J. Wysocki 	bool check_sta;
133d21b5700SRafael J. Wysocki 	bool check_children;
134d21b5700SRafael J. Wysocki };
135d21b5700SRafael J. Wysocki 
check_one_child(struct acpi_device * adev,void * data)136d21b5700SRafael J. Wysocki static int check_one_child(struct acpi_device *adev, void *data)
137d21b5700SRafael J. Wysocki {
138d21b5700SRafael J. Wysocki 	struct find_child_walk_data *wd = data;
139d21b5700SRafael J. Wysocki 	int score;
140d21b5700SRafael J. Wysocki 
141d21b5700SRafael J. Wysocki 	if (!adev->pnp.type.bus_address || acpi_device_adr(adev) != wd->address)
142d21b5700SRafael J. Wysocki 		return 0;
143d21b5700SRafael J. Wysocki 
144d21b5700SRafael J. Wysocki 	if (!wd->adev) {
1452f6fe93fSRafael J. Wysocki 		/*
1462f6fe93fSRafael J. Wysocki 		 * This is the first matching object, so save it.  If it is not
1472f6fe93fSRafael J. Wysocki 		 * necessary to look for any other matching objects, stop the
1482f6fe93fSRafael J. Wysocki 		 * search.
1492f6fe93fSRafael J. Wysocki 		 */
150d21b5700SRafael J. Wysocki 		wd->adev = adev;
1512f6fe93fSRafael J. Wysocki 		return !(wd->check_sta || wd->check_children);
152d21b5700SRafael J. Wysocki 	}
153d21b5700SRafael J. Wysocki 
154d21b5700SRafael J. Wysocki 	/*
155d21b5700SRafael J. Wysocki 	 * There is more than one matching device object with the same _ADR
156d21b5700SRafael J. Wysocki 	 * value.  That really is unexpected, so we are kind of beyond the scope
157d21b5700SRafael J. Wysocki 	 * of the spec here.  We have to choose which one to return, though.
158d21b5700SRafael J. Wysocki 	 *
159d21b5700SRafael J. Wysocki 	 * First, get the score for the previously found object and terminate
160d21b5700SRafael J. Wysocki 	 * the walk if it is maximum.
161d21b5700SRafael J. Wysocki 	*/
162d21b5700SRafael J. Wysocki 	if (!wd->score) {
163d21b5700SRafael J. Wysocki 		score = find_child_checks(wd->adev, wd->check_children);
164d21b5700SRafael J. Wysocki 		if (score == FIND_CHILD_MAX_SCORE)
165d21b5700SRafael J. Wysocki 			return 1;
166d21b5700SRafael J. Wysocki 
167d21b5700SRafael J. Wysocki 		wd->score = score;
168d21b5700SRafael J. Wysocki 	}
169d21b5700SRafael J. Wysocki 	/*
170d21b5700SRafael J. Wysocki 	 * Second, if the object that has just been found has a better score,
171d21b5700SRafael J. Wysocki 	 * replace the previously found one with it and terminate the walk if
172d21b5700SRafael J. Wysocki 	 * the new score is maximum.
173d21b5700SRafael J. Wysocki 	 */
174d21b5700SRafael J. Wysocki 	score = find_child_checks(adev, wd->check_children);
175d21b5700SRafael J. Wysocki 	if (score > wd->score) {
176d21b5700SRafael J. Wysocki 		wd->adev = adev;
177d21b5700SRafael J. Wysocki 		if (score == FIND_CHILD_MAX_SCORE)
178d21b5700SRafael J. Wysocki 			return 1;
179d21b5700SRafael J. Wysocki 
180d21b5700SRafael J. Wysocki 		wd->score = score;
181d21b5700SRafael J. Wysocki 	}
182d21b5700SRafael J. Wysocki 
183d21b5700SRafael J. Wysocki 	/* Continue, because there may be better matches. */
184d21b5700SRafael J. Wysocki 	return 0;
185d21b5700SRafael J. Wysocki }
186d21b5700SRafael J. Wysocki 
acpi_find_child(struct acpi_device * parent,u64 address,bool check_children,bool check_sta)1872f6fe93fSRafael J. Wysocki static struct acpi_device *acpi_find_child(struct acpi_device *parent,
1882f6fe93fSRafael J. Wysocki 					   u64 address, bool check_children,
1892f6fe93fSRafael J. Wysocki 					   bool check_sta)
19060f75b8eSRafael J. Wysocki {
191d21b5700SRafael J. Wysocki 	struct find_child_walk_data wd = {
192d21b5700SRafael J. Wysocki 		.address = address,
193d21b5700SRafael J. Wysocki 		.check_children = check_children,
1942f6fe93fSRafael J. Wysocki 		.check_sta = check_sta,
195d21b5700SRafael J. Wysocki 		.adev = NULL,
196d21b5700SRafael J. Wysocki 		.score = 0,
197d21b5700SRafael J. Wysocki 	};
198d9fef0c4SRafael J. Wysocki 
199d21b5700SRafael J. Wysocki 	if (parent)
200d21b5700SRafael J. Wysocki 		acpi_dev_for_each_child(parent, check_one_child, &wd);
2015ce79d20SRafael J. Wysocki 
202d21b5700SRafael J. Wysocki 	return wd.adev;
20360f75b8eSRafael J. Wysocki }
2042f6fe93fSRafael J. Wysocki 
acpi_find_child_device(struct acpi_device * parent,u64 address,bool check_children)2052f6fe93fSRafael J. Wysocki struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
2062f6fe93fSRafael J. Wysocki 					   u64 address, bool check_children)
2072f6fe93fSRafael J. Wysocki {
2082f6fe93fSRafael J. Wysocki 	return acpi_find_child(parent, address, check_children, true);
2092f6fe93fSRafael J. Wysocki }
2109c5ad36dSRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_find_child_device);
21160f75b8eSRafael J. Wysocki 
acpi_find_child_by_adr(struct acpi_device * adev,acpi_bus_address adr)2122f6fe93fSRafael J. Wysocki struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,
2132f6fe93fSRafael J. Wysocki 					   acpi_bus_address adr)
2142f6fe93fSRafael J. Wysocki {
2152f6fe93fSRafael J. Wysocki 	return acpi_find_child(adev, adr, false, false);
2162f6fe93fSRafael J. Wysocki }
2172f6fe93fSRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_find_child_by_adr);
2182f6fe93fSRafael J. Wysocki 
acpi_physnode_link_name(char * buf,unsigned int node_id)219bdbdbf91SRafael J. Wysocki static void acpi_physnode_link_name(char *buf, unsigned int node_id)
220bdbdbf91SRafael J. Wysocki {
221bdbdbf91SRafael J. Wysocki 	if (node_id > 0)
222bdbdbf91SRafael J. Wysocki 		snprintf(buf, PHYSICAL_NODE_NAME_SIZE,
223bdbdbf91SRafael J. Wysocki 			 PHYSICAL_NODE_STRING "%u", node_id);
224bdbdbf91SRafael J. Wysocki 	else
225bdbdbf91SRafael J. Wysocki 		strcpy(buf, PHYSICAL_NODE_STRING);
226bdbdbf91SRafael J. Wysocki }
227bdbdbf91SRafael J. Wysocki 
acpi_bind_one(struct device * dev,struct acpi_device * acpi_dev)22824dee1fcSRafael J. Wysocki int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
2294e10d12aSDavid Shaohua Li {
230f3fd0c8aSRafael J. Wysocki 	struct acpi_device_physical_node *physical_node, *pn;
231007ccfcfSRafael J. Wysocki 	char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
232007ccfcfSRafael J. Wysocki 	struct list_head *physnode_list;
233007ccfcfSRafael J. Wysocki 	unsigned int node_id;
2341033f904SLan Tianyu 	int retval = -EINVAL;
2354e10d12aSDavid Shaohua Li 
236ca5b74d2SRafael J. Wysocki 	if (has_acpi_companion(dev)) {
23724dee1fcSRafael J. Wysocki 		if (acpi_dev) {
2387b199811SRafael J. Wysocki 			dev_warn(dev, "ACPI companion already set\n");
2394e10d12aSDavid Shaohua Li 			return -EINVAL;
240f3fd0c8aSRafael J. Wysocki 		} else {
2417b199811SRafael J. Wysocki 			acpi_dev = ACPI_COMPANION(dev);
2424e10d12aSDavid Shaohua Li 		}
243f3fd0c8aSRafael J. Wysocki 	}
2447b199811SRafael J. Wysocki 	if (!acpi_dev)
245f3fd0c8aSRafael J. Wysocki 		return -EINVAL;
2461033f904SLan Tianyu 
2474cbaba4eSAndy Shevchenko 	acpi_dev_get(acpi_dev);
2484e10d12aSDavid Shaohua Li 	get_device(dev);
249f3fd0c8aSRafael J. Wysocki 	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
2501033f904SLan Tianyu 	if (!physical_node) {
2511033f904SLan Tianyu 		retval = -ENOMEM;
2521033f904SLan Tianyu 		goto err;
2534e10d12aSDavid Shaohua Li 	}
2541033f904SLan Tianyu 
2551033f904SLan Tianyu 	mutex_lock(&acpi_dev->physical_node_lock);
256f3fd0c8aSRafael J. Wysocki 
257007ccfcfSRafael J. Wysocki 	/*
258007ccfcfSRafael J. Wysocki 	 * Keep the list sorted by node_id so that the IDs of removed nodes can
259007ccfcfSRafael J. Wysocki 	 * be recycled easily.
260007ccfcfSRafael J. Wysocki 	 */
261007ccfcfSRafael J. Wysocki 	physnode_list = &acpi_dev->physical_node_list;
262007ccfcfSRafael J. Wysocki 	node_id = 0;
263007ccfcfSRafael J. Wysocki 	list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
264f3fd0c8aSRafael J. Wysocki 		/* Sanity check. */
265f3fd0c8aSRafael J. Wysocki 		if (pn->dev == dev) {
2663342c753SRafael J. Wysocki 			mutex_unlock(&acpi_dev->physical_node_lock);
2673fe444adSRafael J. Wysocki 
2683342c753SRafael J. Wysocki 			dev_warn(dev, "Already associated with ACPI node\n");
2693342c753SRafael J. Wysocki 			kfree(physical_node);
2707b199811SRafael J. Wysocki 			if (ACPI_COMPANION(dev) != acpi_dev)
2713342c753SRafael J. Wysocki 				goto err;
2723342c753SRafael J. Wysocki 
2733342c753SRafael J. Wysocki 			put_device(dev);
2744cbaba4eSAndy Shevchenko 			acpi_dev_put(acpi_dev);
2753342c753SRafael J. Wysocki 			return 0;
276f3fd0c8aSRafael J. Wysocki 		}
277007ccfcfSRafael J. Wysocki 		if (pn->node_id == node_id) {
278007ccfcfSRafael J. Wysocki 			physnode_list = &pn->node;
279007ccfcfSRafael J. Wysocki 			node_id++;
280007ccfcfSRafael J. Wysocki 		}
2811033f904SLan Tianyu 	}
2821033f904SLan Tianyu 
283007ccfcfSRafael J. Wysocki 	physical_node->node_id = node_id;
2841033f904SLan Tianyu 	physical_node->dev = dev;
285007ccfcfSRafael J. Wysocki 	list_add(&physical_node->node, physnode_list);
2861033f904SLan Tianyu 	acpi_dev->physical_node_count++;
287f3fd0c8aSRafael J. Wysocki 
288ca5b74d2SRafael J. Wysocki 	if (!has_acpi_companion(dev))
2897b199811SRafael J. Wysocki 		ACPI_COMPANION_SET(dev, acpi_dev);
2904e10d12aSDavid Shaohua Li 
291bdbdbf91SRafael J. Wysocki 	acpi_physnode_link_name(physical_node_name, node_id);
2921033f904SLan Tianyu 	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
2931033f904SLan Tianyu 				   physical_node_name);
294464c1147SRafael J. Wysocki 	if (retval)
295464c1147SRafael J. Wysocki 		dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
296464c1147SRafael J. Wysocki 			physical_node_name, retval);
297464c1147SRafael J. Wysocki 
2981033f904SLan Tianyu 	retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
2991071695fSDavid Brownell 				   "firmware_node");
300464c1147SRafael J. Wysocki 	if (retval)
301464c1147SRafael J. Wysocki 		dev_err(dev, "Failed to create link firmware_node (%d)\n",
302464c1147SRafael J. Wysocki 			retval);
3031033f904SLan Tianyu 
30440055206SRafael J. Wysocki 	mutex_unlock(&acpi_dev->physical_node_lock);
30540055206SRafael J. Wysocki 
3067fa69bafSRafael J. Wysocki 	if (acpi_dev->wakeup.flags.valid)
307eb9d0fe4SRafael J. Wysocki 		device_set_wakeup_capable(dev, true);
3081071695fSDavid Brownell 
3094e10d12aSDavid Shaohua Li 	return 0;
3101033f904SLan Tianyu 
3111033f904SLan Tianyu  err:
3127b199811SRafael J. Wysocki 	ACPI_COMPANION_SET(dev, NULL);
3131033f904SLan Tianyu 	put_device(dev);
3144cbaba4eSAndy Shevchenko 	acpi_dev_put(acpi_dev);
3151033f904SLan Tianyu 	return retval;
3164e10d12aSDavid Shaohua Li }
317ac212b69SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_bind_one);
3184e10d12aSDavid Shaohua Li 
acpi_unbind_one(struct device * dev)319ac212b69SRafael J. Wysocki int acpi_unbind_one(struct device *dev)
3204e10d12aSDavid Shaohua Li {
3217b199811SRafael J. Wysocki 	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
3221033f904SLan Tianyu 	struct acpi_device_physical_node *entry;
3231033f904SLan Tianyu 
3247b199811SRafael J. Wysocki 	if (!acpi_dev)
3254e10d12aSDavid Shaohua Li 		return 0;
3261071695fSDavid Brownell 
3271033f904SLan Tianyu 	mutex_lock(&acpi_dev->physical_node_lock);
3281033f904SLan Tianyu 
3293e332783SRafael J. Wysocki 	list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
3303e332783SRafael J. Wysocki 		if (entry->dev == dev) {
3313e332783SRafael J. Wysocki 			char physnode_name[PHYSICAL_NODE_NAME_SIZE];
3321033f904SLan Tianyu 
3333e332783SRafael J. Wysocki 			list_del(&entry->node);
3341033f904SLan Tianyu 			acpi_dev->physical_node_count--;
3351033f904SLan Tianyu 
3363e332783SRafael J. Wysocki 			acpi_physnode_link_name(physnode_name, entry->node_id);
3373e332783SRafael J. Wysocki 			sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
3381071695fSDavid Brownell 			sysfs_remove_link(&dev->kobj, "firmware_node");
3397b199811SRafael J. Wysocki 			ACPI_COMPANION_SET(dev, NULL);
340a104b4d4SRafael J. Wysocki 			/* Drop references taken by acpi_bind_one(). */
3414e10d12aSDavid Shaohua Li 			put_device(dev);
3424cbaba4eSAndy Shevchenko 			acpi_dev_put(acpi_dev);
3431033f904SLan Tianyu 			kfree(entry);
3443e332783SRafael J. Wysocki 			break;
3454e10d12aSDavid Shaohua Li 		}
3463e332783SRafael J. Wysocki 
3471033f904SLan Tianyu 	mutex_unlock(&acpi_dev->physical_node_lock);
3484e10d12aSDavid Shaohua Li 	return 0;
3494e10d12aSDavid Shaohua Li }
350ac212b69SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_unbind_one);
3514e10d12aSDavid Shaohua Li 
acpi_device_notify(struct device * dev)352d0b8e398SRafael J. Wysocki void acpi_device_notify(struct device *dev)
3534e10d12aSDavid Shaohua Li {
3549cb32acfSRafael J. Wysocki 	struct acpi_device *adev;
35511909ca1SRafael J. Wysocki 	int ret;
3564e10d12aSDavid Shaohua Li 
357f3fd0c8aSRafael J. Wysocki 	ret = acpi_bind_one(dev, NULL);
35842878a9fSRafael J. Wysocki 	if (ret) {
3592ef52366SRafael J. Wysocki 		struct acpi_bus_type *type = acpi_get_bus_type(dev);
3602ef52366SRafael J. Wysocki 
36142878a9fSRafael J. Wysocki 		if (!type)
36242878a9fSRafael J. Wysocki 			goto err;
363e3f02c52SRafael J. Wysocki 
364e3f02c52SRafael J. Wysocki 		adev = type->find_companion(dev);
365e3f02c52SRafael J. Wysocki 		if (!adev) {
36642878a9fSRafael J. Wysocki 			dev_dbg(dev, "ACPI companion not found\n");
36742878a9fSRafael J. Wysocki 			goto err;
36811909ca1SRafael J. Wysocki 		}
36924dee1fcSRafael J. Wysocki 		ret = acpi_bind_one(dev, adev);
37011909ca1SRafael J. Wysocki 		if (ret)
37142878a9fSRafael J. Wysocki 			goto err;
3722ef52366SRafael J. Wysocki 
3732ef52366SRafael J. Wysocki 		if (type->setup) {
3742ef52366SRafael J. Wysocki 			type->setup(dev);
3752ef52366SRafael J. Wysocki 			goto done;
37611909ca1SRafael J. Wysocki 		}
3772ef52366SRafael J. Wysocki 	} else {
3789cb32acfSRafael J. Wysocki 		adev = ACPI_COMPANION(dev);
37911909ca1SRafael J. Wysocki 
38047954481SRafael J. Wysocki 		if (dev_is_pci(dev)) {
38147954481SRafael J. Wysocki 			pci_acpi_setup(dev, adev);
3822ef52366SRafael J. Wysocki 			goto done;
3832ef52366SRafael J. Wysocki 		} else if (dev_is_platform(dev)) {
384d4f54a18SHanjun Guo 			acpi_configure_pmsi_domain(dev);
3852ef52366SRafael J. Wysocki 		}
38647954481SRafael J. Wysocki 	}
387d4f54a18SHanjun Guo 
3882ef52366SRafael J. Wysocki 	if (adev->handler && adev->handler->bind)
3899cb32acfSRafael J. Wysocki 		adev->handler->bind(dev);
3904e10d12aSDavid Shaohua Li 
3912ef52366SRafael J. Wysocki done:
39242878a9fSRafael J. Wysocki 	acpi_handle_debug(ACPI_HANDLE(dev), "Bound to device %s\n",
39342878a9fSRafael J. Wysocki 			  dev_name(dev));
3944e10d12aSDavid Shaohua Li 
3957d625e5bSRafael J. Wysocki 	return;
39642878a9fSRafael J. Wysocki 
39742878a9fSRafael J. Wysocki err:
39842878a9fSRafael J. Wysocki 	dev_dbg(dev, "No ACPI support\n");
3994e10d12aSDavid Shaohua Li }
4004e10d12aSDavid Shaohua Li 
acpi_device_notify_remove(struct device * dev)401d0b8e398SRafael J. Wysocki void acpi_device_notify_remove(struct device *dev)
4024e10d12aSDavid Shaohua Li {
4039cb32acfSRafael J. Wysocki 	struct acpi_device *adev = ACPI_COMPANION(dev);
40411909ca1SRafael J. Wysocki 
4059cb32acfSRafael J. Wysocki 	if (!adev)
4067d625e5bSRafael J. Wysocki 		return;
4079cb32acfSRafael J. Wysocki 
408c4d19838SRafael J. Wysocki 	if (dev_is_pci(dev))
40947954481SRafael J. Wysocki 		pci_acpi_cleanup(dev, adev);
4109cb32acfSRafael J. Wysocki 	else if (adev->handler && adev->handler->unbind)
4119cb32acfSRafael J. Wysocki 		adev->handler->unbind(dev);
41211909ca1SRafael J. Wysocki 
4134e10d12aSDavid Shaohua Li 	acpi_unbind_one(dev);
4144e10d12aSDavid Shaohua Li }
415