diff options
-rw-r--r-- | drivers/acpi/device_pm.c | 8 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 46 |
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); | |||
97 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); | 97 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); |
98 | bool acpi_device_is_present(struct acpi_device *adev); | 98 | bool acpi_device_is_present(struct acpi_device *adev); |
99 | bool acpi_device_is_battery(struct acpi_device *adev); | 99 | bool acpi_device_is_battery(struct acpi_device *adev); |
100 | bool 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 | */ | ||
240 | bool 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, | |||
250 | static struct acpi_device *acpi_companion_match(const struct device *dev) | 279 | static 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 | ||
279 | static int __acpi_device_uevent_modalias(struct acpi_device *adev, | 293 | static int __acpi_device_uevent_modalias(struct acpi_device *adev, |