aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/device_pm.c8
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/scan.c46
3 files changed, 40 insertions, 16 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 717afcdb5f4a..08dc3ec7e892 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1123,6 +1123,14 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
1123 if (dev->pm_domain) 1123 if (dev->pm_domain)
1124 return -EEXIST; 1124 return -EEXIST;
1125 1125
1126 /*
1127 * Only attach the power domain to the first device if the
1128 * companion is shared by multiple. This is to prevent doing power
1129 * management twice.
1130 */
1131 if (!acpi_device_is_first_physical_node(adev, dev))
1132 return -EBUSY;
1133
1126 acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); 1134 acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
1127 dev->pm_domain = &acpi_general_pm_domain; 1135 dev->pm_domain = &acpi_general_pm_domain;
1128 if (power_on) { 1136 if (power_on) {
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 4683a96932b9..f6aefe984941 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -97,6 +97,8 @@ void acpi_device_add_finalize(struct acpi_device *device);
97void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); 97void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
98bool acpi_device_is_present(struct acpi_device *adev); 98bool acpi_device_is_present(struct acpi_device *adev);
99bool acpi_device_is_battery(struct acpi_device *adev); 99bool acpi_device_is_battery(struct acpi_device *adev);
100bool acpi_device_is_first_physical_node(struct acpi_device *adev,
101 const struct device *dev);
100 102
101/* -------------------------------------------------------------------------- 103/* --------------------------------------------------------------------------
102 Power Resource 104 Power Resource
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ec256352f423..89ff6d2eef8a 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -226,6 +226,35 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
226 return len; 226 return len;
227} 227}
228 228
229/**
230 * acpi_device_is_first_physical_node - Is given dev first physical node
231 * @adev: ACPI companion device
232 * @dev: Physical device to check
233 *
234 * Function checks if given @dev is the first physical devices attached to
235 * the ACPI companion device. This distinction is needed in some cases
236 * where the same companion device is shared between many physical devices.
237 *
238 * Note that the caller have to provide valid @adev pointer.
239 */
240bool acpi_device_is_first_physical_node(struct acpi_device *adev,
241 const struct device *dev)
242{
243 bool ret = false;
244
245 mutex_lock(&adev->physical_node_lock);
246 if (!list_empty(&adev->physical_node_list)) {
247 const struct acpi_device_physical_node *node;
248
249 node = list_first_entry(&adev->physical_node_list,
250 struct acpi_device_physical_node, node);
251 ret = node->dev == dev;
252 }
253 mutex_unlock(&adev->physical_node_lock);
254
255 return ret;
256}
257
229/* 258/*
230 * acpi_companion_match() - Can we match via ACPI companion device 259 * acpi_companion_match() - Can we match via ACPI companion device
231 * @dev: Device in question 260 * @dev: Device in question
@@ -250,7 +279,6 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
250static struct acpi_device *acpi_companion_match(const struct device *dev) 279static struct acpi_device *acpi_companion_match(const struct device *dev)
251{ 280{
252 struct acpi_device *adev; 281 struct acpi_device *adev;
253 struct mutex *physical_node_lock;
254 282
255 adev = ACPI_COMPANION(dev); 283 adev = ACPI_COMPANION(dev);
256 if (!adev) 284 if (!adev)
@@ -259,21 +287,7 @@ static struct acpi_device *acpi_companion_match(const struct device *dev)
259 if (list_empty(&adev->pnp.ids)) 287 if (list_empty(&adev->pnp.ids))
260 return NULL; 288 return NULL;
261 289
262 physical_node_lock = &adev->physical_node_lock; 290 return acpi_device_is_first_physical_node(adev, dev) ? adev : NULL;
263 mutex_lock(physical_node_lock);
264 if (list_empty(&adev->physical_node_list)) {
265 adev = NULL;
266 } else {
267 const struct acpi_device_physical_node *node;
268
269 node = list_first_entry(&adev->physical_node_list,
270 struct acpi_device_physical_node, node);
271 if (node->dev != dev)
272 adev = NULL;
273 }
274 mutex_unlock(physical_node_lock);
275
276 return adev;
277} 291}
278 292
279static int __acpi_device_uevent_modalias(struct acpi_device *adev, 293static int __acpi_device_uevent_modalias(struct acpi_device *adev,