summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-07-29 23:49:22 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-07-29 23:49:22 +0200
commit5af310a8ee70dd6a588c8ee1d4487a230a7b7b65 (patch)
tree38ba23a3b51ab577ea1ddc09772a8556d8957df9 /drivers/acpi
parentaa57aca8e15a4e11749640e16ac9814f14be24d2 (diff)
parent4b45efe8526359a11ca60a299bef3aebf413fd77 (diff)
downloadop-kernel-dev-5af310a8ee70dd6a588c8ee1d4487a230a7b7b65.zip
op-kernel-dev-5af310a8ee70dd6a588c8ee1d4487a230a7b7b65.tar.gz
Merge tag 'ib-mfd-base-acpi-dma-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into acpi-pm
Pull MFD-related material including ACPI device power management changes (in addition to MFD, driver core and DMA changes) for v4.3 from Lee Jones. * tag 'ib-mfd-base-acpi-dma-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: mfd: Add support for Intel Sunrisepoint LPSS devices dmaengine: add a driver for Intel integrated DMA 64-bit mfd: make mfd_remove_devices() iterate in reverse order driver core: implement device_for_each_child_reverse() klist: implement klist_prev() Driver core: wakeup the parent device before trying probe ACPI / PM: Attach ACPI power domain only once PM / QoS: Make it possible to expose device latency tolerance to userspace
Diffstat (limited to 'drivers/acpi')
-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 717afcd..08dc3ec 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)
if (dev->pm_domain)
return -EEXIST;
+ /*
+ * Only attach the power domain to the first device if the
+ * companion is shared by multiple. This is to prevent doing power
+ * management twice.
+ */
+ if (!acpi_device_is_first_physical_node(adev, dev))
+ return -EBUSY;
+
acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
dev->pm_domain = &acpi_general_pm_domain;
if (power_on) {
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 4683a96..f6aefe9 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -97,6 +97,8 @@ void acpi_device_add_finalize(struct acpi_device *device);
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
bool acpi_device_is_present(struct acpi_device *adev);
bool acpi_device_is_battery(struct acpi_device *adev);
+bool acpi_device_is_first_physical_node(struct acpi_device *adev,
+ const struct device *dev);
/* --------------------------------------------------------------------------
Power Resource
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ec25635..89ff6d2 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,
return len;
}
+/**
+ * acpi_device_is_first_physical_node - Is given dev first physical node
+ * @adev: ACPI companion device
+ * @dev: Physical device to check
+ *
+ * Function checks if given @dev is the first physical devices attached to
+ * the ACPI companion device. This distinction is needed in some cases
+ * where the same companion device is shared between many physical devices.
+ *
+ * Note that the caller have to provide valid @adev pointer.
+ */
+bool acpi_device_is_first_physical_node(struct acpi_device *adev,
+ const struct device *dev)
+{
+ bool ret = false;
+
+ mutex_lock(&adev->physical_node_lock);
+ if (!list_empty(&adev->physical_node_list)) {
+ const struct acpi_device_physical_node *node;
+
+ node = list_first_entry(&adev->physical_node_list,
+ struct acpi_device_physical_node, node);
+ ret = node->dev == dev;
+ }
+ mutex_unlock(&adev->physical_node_lock);
+
+ return ret;
+}
+
/*
* acpi_companion_match() - Can we match via ACPI companion device
* @dev: Device in question
@@ -250,7 +279,6 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
static struct acpi_device *acpi_companion_match(const struct device *dev)
{
struct acpi_device *adev;
- struct mutex *physical_node_lock;
adev = ACPI_COMPANION(dev);
if (!adev)
@@ -259,21 +287,7 @@ static struct acpi_device *acpi_companion_match(const struct device *dev)
if (list_empty(&adev->pnp.ids))
return NULL;
- physical_node_lock = &adev->physical_node_lock;
- mutex_lock(physical_node_lock);
- if (list_empty(&adev->physical_node_list)) {
- adev = NULL;
- } else {
- const struct acpi_device_physical_node *node;
-
- node = list_first_entry(&adev->physical_node_list,
- struct acpi_device_physical_node, node);
- if (node->dev != dev)
- adev = NULL;
- }
- mutex_unlock(physical_node_lock);
-
- return adev;
+ return acpi_device_is_first_physical_node(adev, dev) ? adev : NULL;
}
static int __acpi_device_uevent_modalias(struct acpi_device *adev,
OpenPOWER on IntegriCloud