Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2dc3c72c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-domains'

* pm-domains:
  PM / Domains: Rename pm_genpd_sync_poweron|poweroff()
  PM / Domains: Don't measure latency of ->power_on|off() during system PM
  PM / Domains: Remove redundant system PM callbacks
  PM / Domains: Simplify detaching a device from its genpd
  PM / Domains: Allow holes in genpd_data.domains array
  PM / Domains: Add support for removing nested PM domains by provider
  PM / Domains: Add support for removing PM domains
  PM / Domains: Store the provider in the PM domain structure
  PM / Domains: Prepare for adding support to remove PM domains
  PM / Domains: Verify the PM domain is present when adding a provider
  PM / Domains: Don't expose xlate and provider helper functions
  PM / Domains: Don't expose generic_pm_domain structure to clients
  staging: board: Remove calls to of_genpd_get_from_provider()
  ARM: EXYNOS: Remove calls to of_genpd_get_from_provider()
  PM / Domains: Add new helper functions for device-tree
  PM / Domains: Always enable debugfs support if available
parents 08895a8b eefdee07
Loading
Loading
Loading
Loading
+352 −78
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ static DEFINE_MUTEX(gpd_list_lock);
 * and checks that the PM domain pointer is a real generic PM domain.
 * Any failure results in NULL being returned.
 */
struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev)
static struct generic_pm_domain *genpd_lookup_dev(struct device *dev)
{
	struct generic_pm_domain *genpd = NULL, *gpd;

@@ -586,7 +586,7 @@ static int __init genpd_poweroff_unused(void)
}
late_initcall(genpd_poweroff_unused);

#ifdef CONFIG_PM_SLEEP
#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF)

/**
 * pm_genpd_present - Check if the given PM domain has been initialized.
@@ -606,6 +606,10 @@ static bool pm_genpd_present(const struct generic_pm_domain *genpd)
	return false;
}

#endif

#ifdef CONFIG_PM_SLEEP

static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
				    struct device *dev)
{
@@ -613,9 +617,8 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
}

/**
 * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
 * genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
 * @genpd: PM domain to power off, if possible.
 * @timed: True if latency measurements are allowed.
 *
 * Check if the given PM domain can be powered off (during system suspend or
 * hibernation) and do that if so.  Also, in that case propagate to its masters.
@@ -625,8 +628,7 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
 * executed sequentially, so it is guaranteed that it will never run twice in
 * parallel).
 */
static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
				   bool timed)
static void genpd_sync_poweroff(struct generic_pm_domain *genpd)
{
	struct gpd_link *link;

@@ -639,28 +641,26 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,

	/* Choose the deepest state when suspending */
	genpd->state_idx = genpd->state_count - 1;
	genpd_power_off(genpd, timed);
	genpd_power_off(genpd, false);

	genpd->status = GPD_STATE_POWER_OFF;

	list_for_each_entry(link, &genpd->slave_links, slave_node) {
		genpd_sd_counter_dec(link->master);
		pm_genpd_sync_poweroff(link->master, timed);
		genpd_sync_poweroff(link->master);
	}
}

/**
 * pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters.
 * genpd_sync_poweron - Synchronously power on a PM domain and its masters.
 * @genpd: PM domain to power on.
 * @timed: True if latency measurements are allowed.
 *
 * This function is only called in "noirq" and "syscore" stages of system power
 * transitions, so it need not acquire locks (all of the "noirq" callbacks are
 * executed sequentially, so it is guaranteed that it will never run twice in
 * parallel).
 */
static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd,
				  bool timed)
static void genpd_sync_poweron(struct generic_pm_domain *genpd)
{
	struct gpd_link *link;

@@ -668,11 +668,11 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd,
		return;

	list_for_each_entry(link, &genpd->slave_links, slave_node) {
		pm_genpd_sync_poweron(link->master, timed);
		genpd_sync_poweron(link->master);
		genpd_sd_counter_inc(link->master);
	}

	genpd_power_on(genpd, timed);
	genpd_power_on(genpd, false);

	genpd->status = GPD_STATE_ACTIVE;
}
@@ -784,7 +784,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
	 * the same PM domain, so it is not necessary to use locking here.
	 */
	genpd->suspended_count++;
	pm_genpd_sync_poweroff(genpd, true);
	genpd_sync_poweroff(genpd);

	return 0;
}
@@ -814,7 +814,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
	 * guaranteed that this function will never run twice in parallel for
	 * the same PM domain, so it is not necessary to use locking here.
	 */
	pm_genpd_sync_poweron(genpd, true);
	genpd_sync_poweron(genpd);
	genpd->suspended_count--;

	if (genpd->dev_ops.stop && genpd->dev_ops.start)
@@ -902,12 +902,12 @@ static int pm_genpd_restore_noirq(struct device *dev)
	if (genpd->suspended_count++ == 0)
		/*
		 * The boot kernel might put the domain into arbitrary state,
		 * so make it appear as powered off to pm_genpd_sync_poweron(),
		 * so make it appear as powered off to genpd_sync_poweron(),
		 * so that it tries to power it on in case it was really off.
		 */
		genpd->status = GPD_STATE_POWER_OFF;

	pm_genpd_sync_poweron(genpd, true);
	genpd_sync_poweron(genpd);

	if (genpd->dev_ops.stop && genpd->dev_ops.start)
		ret = pm_runtime_force_resume(dev);
@@ -962,9 +962,9 @@ static void genpd_syscore_switch(struct device *dev, bool suspend)

	if (suspend) {
		genpd->suspended_count++;
		pm_genpd_sync_poweroff(genpd, false);
		genpd_sync_poweroff(genpd);
	} else {
		pm_genpd_sync_poweron(genpd, false);
		genpd_sync_poweron(genpd);
		genpd->suspended_count--;
	}
}
@@ -1056,13 +1056,7 @@ static void genpd_free_dev_data(struct device *dev,
	dev_pm_put_subsys_data(dev);
}

/**
 * __pm_genpd_add_device - Add a device to an I/O PM domain.
 * @genpd: PM domain to add the device to.
 * @dev: Device to be added.
 * @td: Set of PM QoS timing parameters to attach to the device.
 */
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
			    struct gpd_timing_data *td)
{
	struct generic_pm_domain_data *gpd_data;
@@ -1103,14 +1097,27 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,

	return ret;
}
EXPORT_SYMBOL_GPL(__pm_genpd_add_device);

/**
 * pm_genpd_remove_device - Remove a device from an I/O PM domain.
 * @genpd: PM domain to remove the device from.
 * @dev: Device to be removed.
 * __pm_genpd_add_device - Add a device to an I/O PM domain.
 * @genpd: PM domain to add the device to.
 * @dev: Device to be added.
 * @td: Set of PM QoS timing parameters to attach to the device.
 */
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
			  struct gpd_timing_data *td)
{
	int ret;

	mutex_lock(&gpd_list_lock);
	ret = genpd_add_device(genpd, dev, td);
	mutex_unlock(&gpd_list_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(__pm_genpd_add_device);

static int genpd_remove_device(struct generic_pm_domain *genpd,
			       struct device *dev)
{
	struct generic_pm_domain_data *gpd_data;
@@ -1119,10 +1126,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,

	dev_dbg(dev, "%s()\n", __func__);

	if (!genpd || genpd != pm_genpd_lookup_dev(dev))
		return -EINVAL;

	/* The above validation also means we have existing domain_data. */
	pdd = dev->power.subsys_data->domain_data;
	gpd_data = to_gpd_data(pdd);
	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
@@ -1154,14 +1157,23 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,

	return ret;
}
EXPORT_SYMBOL_GPL(pm_genpd_remove_device);

/**
 * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
 * @genpd: Master PM domain to add the subdomain to.
 * @subdomain: Subdomain to be added.
 * pm_genpd_remove_device - Remove a device from an I/O PM domain.
 * @genpd: PM domain to remove the device from.
 * @dev: Device to be removed.
 */
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
			   struct device *dev)
{
	if (!genpd || genpd != genpd_lookup_dev(dev))
		return -EINVAL;

	return genpd_remove_device(genpd, dev);
}
EXPORT_SYMBOL_GPL(pm_genpd_remove_device);

static int genpd_add_subdomain(struct generic_pm_domain *genpd,
			       struct generic_pm_domain *subdomain)
{
	struct gpd_link *link, *itr;
@@ -1205,6 +1217,23 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
		kfree(link);
	return ret;
}

/**
 * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
 * @genpd: Master PM domain to add the subdomain to.
 * @subdomain: Subdomain to be added.
 */
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
			   struct generic_pm_domain *subdomain)
{
	int ret;

	mutex_lock(&gpd_list_lock);
	ret = genpd_add_subdomain(genpd, subdomain);
	mutex_unlock(&gpd_list_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain);

/**
@@ -1278,27 +1307,17 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
	genpd->device_count = 0;
	genpd->max_off_time_ns = -1;
	genpd->max_off_time_changed = true;
	genpd->provider = NULL;
	genpd->has_provider = false;
	genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
	genpd->domain.ops.runtime_resume = genpd_runtime_resume;
	genpd->domain.ops.prepare = pm_genpd_prepare;
	genpd->domain.ops.suspend = pm_generic_suspend;
	genpd->domain.ops.suspend_late = pm_generic_suspend_late;
	genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
	genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
	genpd->domain.ops.resume_early = pm_generic_resume_early;
	genpd->domain.ops.resume = pm_generic_resume;
	genpd->domain.ops.freeze = pm_generic_freeze;
	genpd->domain.ops.freeze_late = pm_generic_freeze_late;
	genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
	genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
	genpd->domain.ops.thaw_early = pm_generic_thaw_early;
	genpd->domain.ops.thaw = pm_generic_thaw;
	genpd->domain.ops.poweroff = pm_generic_poweroff;
	genpd->domain.ops.poweroff_late = pm_generic_poweroff_late;
	genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq;
	genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
	genpd->domain.ops.restore_early = pm_generic_restore_early;
	genpd->domain.ops.restore = pm_generic_restore;
	genpd->domain.ops.complete = pm_genpd_complete;

	if (genpd->flags & GENPD_FLAG_PM_CLK) {
@@ -1328,7 +1347,71 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
}
EXPORT_SYMBOL_GPL(pm_genpd_init);

static int genpd_remove(struct generic_pm_domain *genpd)
{
	struct gpd_link *l, *link;

	if (IS_ERR_OR_NULL(genpd))
		return -EINVAL;

	mutex_lock(&genpd->lock);

	if (genpd->has_provider) {
		mutex_unlock(&genpd->lock);
		pr_err("Provider present, unable to remove %s\n", genpd->name);
		return -EBUSY;
	}

	if (!list_empty(&genpd->master_links) || genpd->device_count) {
		mutex_unlock(&genpd->lock);
		pr_err("%s: unable to remove %s\n", __func__, genpd->name);
		return -EBUSY;
	}

	list_for_each_entry_safe(link, l, &genpd->slave_links, slave_node) {
		list_del(&link->master_node);
		list_del(&link->slave_node);
		kfree(link);
	}

	list_del(&genpd->gpd_list_node);
	mutex_unlock(&genpd->lock);
	cancel_work_sync(&genpd->power_off_work);
	pr_debug("%s: removed %s\n", __func__, genpd->name);

	return 0;
}

/**
 * pm_genpd_remove - Remove a generic I/O PM domain
 * @genpd: Pointer to PM domain that is to be removed.
 *
 * To remove the PM domain, this function:
 *  - Removes the PM domain as a subdomain to any parent domains,
 *    if it was added.
 *  - Removes the PM domain from the list of registered PM domains.
 *
 * The PM domain will only be removed, if the associated provider has
 * been removed, it is not a parent to any other PM domain and has no
 * devices associated with it.
 */
int pm_genpd_remove(struct generic_pm_domain *genpd)
{
	int ret;

	mutex_lock(&gpd_list_lock);
	ret = genpd_remove(genpd);
	mutex_unlock(&gpd_list_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(pm_genpd_remove);

#ifdef CONFIG_PM_GENERIC_DOMAINS_OF

typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
						   void *data);

/*
 * Device Tree based PM domain providers.
 *
@@ -1340,8 +1423,8 @@ EXPORT_SYMBOL_GPL(pm_genpd_init);
 * maps a PM domain specifier retrieved from the device tree to a PM domain.
 *
 * Two simple mapping functions have been provided for convenience:
 *  - __of_genpd_xlate_simple() for 1:1 device tree node to PM domain mapping.
 *  - __of_genpd_xlate_onecell() for mapping of multiple PM domains per node by
 *  - genpd_xlate_simple() for 1:1 device tree node to PM domain mapping.
 *  - genpd_xlate_onecell() for mapping of multiple PM domains per node by
 *    index.
 */

@@ -1366,7 +1449,7 @@ static LIST_HEAD(of_genpd_providers);
static DEFINE_MUTEX(of_genpd_mutex);

/**
 * __of_genpd_xlate_simple() - Xlate function for direct node-domain mapping
 * genpd_xlate_simple() - Xlate function for direct node-domain mapping
 * @genpdspec: OF phandle args to map into a PM domain
 * @data: xlate function private data - pointer to struct generic_pm_domain
 *
@@ -1374,7 +1457,7 @@ static DEFINE_MUTEX(of_genpd_mutex);
 * have their own device tree nodes. The private data of xlate function needs
 * to be a valid pointer to struct generic_pm_domain.
 */
struct generic_pm_domain *__of_genpd_xlate_simple(
static struct generic_pm_domain *genpd_xlate_simple(
					struct of_phandle_args *genpdspec,
					void *data)
{
@@ -1382,10 +1465,9 @@ struct generic_pm_domain *__of_genpd_xlate_simple(
		return ERR_PTR(-EINVAL);
	return data;
}
EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple);

/**
 * __of_genpd_xlate_onecell() - Xlate function using a single index.
 * genpd_xlate_onecell() - Xlate function using a single index.
 * @genpdspec: OF phandle args to map into a PM domain
 * @data: xlate function private data - pointer to struct genpd_onecell_data
 *
@@ -1394,7 +1476,7 @@ EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple);
 * A single cell is used as an index into an array of PM domains specified in
 * the genpd_onecell_data struct when registering the provider.
 */
struct generic_pm_domain *__of_genpd_xlate_onecell(
static struct generic_pm_domain *genpd_xlate_onecell(
					struct of_phandle_args *genpdspec,
					void *data)
{
@@ -1414,15 +1496,14 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(

	return genpd_data->domains[idx];
}
EXPORT_SYMBOL_GPL(__of_genpd_xlate_onecell);

/**
 * __of_genpd_add_provider() - Register a PM domain provider for a node
 * genpd_add_provider() - Register a PM domain provider for a node
 * @np: Device node pointer associated with the PM domain provider.
 * @xlate: Callback for decoding PM domain from phandle arguments.
 * @data: Context pointer for @xlate callback.
 */
int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
			      void *data)
{
	struct of_genpd_provider *cp;
@@ -1442,7 +1523,83 @@ int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,

	return 0;
}
EXPORT_SYMBOL_GPL(__of_genpd_add_provider);

/**
 * of_genpd_add_provider_simple() - Register a simple PM domain provider
 * @np: Device node pointer associated with the PM domain provider.
 * @genpd: Pointer to PM domain associated with the PM domain provider.
 */
int of_genpd_add_provider_simple(struct device_node *np,
				 struct generic_pm_domain *genpd)
{
	int ret = -EINVAL;

	if (!np || !genpd)
		return -EINVAL;

	mutex_lock(&gpd_list_lock);

	if (pm_genpd_present(genpd))
		ret = genpd_add_provider(np, genpd_xlate_simple, genpd);

	if (!ret) {
		genpd->provider = &np->fwnode;
		genpd->has_provider = true;
	}

	mutex_unlock(&gpd_list_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);

/**
 * of_genpd_add_provider_onecell() - Register a onecell PM domain provider
 * @np: Device node pointer associated with the PM domain provider.
 * @data: Pointer to the data associated with the PM domain provider.
 */
int of_genpd_add_provider_onecell(struct device_node *np,
				  struct genpd_onecell_data *data)
{
	unsigned int i;
	int ret = -EINVAL;

	if (!np || !data)
		return -EINVAL;

	mutex_lock(&gpd_list_lock);

	for (i = 0; i < data->num_domains; i++) {
		if (!data->domains[i])
			continue;
		if (!pm_genpd_present(data->domains[i]))
			goto error;

		data->domains[i]->provider = &np->fwnode;
		data->domains[i]->has_provider = true;
	}

	ret = genpd_add_provider(np, genpd_xlate_onecell, data);
	if (ret < 0)
		goto error;

	mutex_unlock(&gpd_list_lock);

	return 0;

error:
	while (i--) {
		if (!data->domains[i])
			continue;
		data->domains[i]->provider = NULL;
		data->domains[i]->has_provider = false;
	}

	mutex_unlock(&gpd_list_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell);

/**
 * of_genpd_del_provider() - Remove a previously registered PM domain provider
@@ -1451,10 +1608,21 @@ EXPORT_SYMBOL_GPL(__of_genpd_add_provider);
void of_genpd_del_provider(struct device_node *np)
{
	struct of_genpd_provider *cp;
	struct generic_pm_domain *gpd;

	mutex_lock(&gpd_list_lock);
	mutex_lock(&of_genpd_mutex);
	list_for_each_entry(cp, &of_genpd_providers, link) {
		if (cp->node == np) {
			/*
			 * For each PM domain associated with the
			 * provider, set the 'has_provider' to false
			 * so that the PM domain can be safely removed.
			 */
			list_for_each_entry(gpd, &gpd_list, gpd_list_node)
				if (gpd->provider == &np->fwnode)
					gpd->has_provider = false;

			list_del(&cp->link);
			of_node_put(cp->node);
			kfree(cp);
@@ -1462,11 +1630,12 @@ void of_genpd_del_provider(struct device_node *np)
		}
	}
	mutex_unlock(&of_genpd_mutex);
	mutex_unlock(&gpd_list_lock);
}
EXPORT_SYMBOL_GPL(of_genpd_del_provider);

/**
 * of_genpd_get_from_provider() - Look-up PM domain
 * genpd_get_from_provider() - Look-up PM domain
 * @genpdspec: OF phandle args to use for look-up
 *
 * Looks for a PM domain provider under the node specified by @genpdspec and if
@@ -1476,7 +1645,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
 * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
 * on failure.
 */
struct generic_pm_domain *of_genpd_get_from_provider(
static struct generic_pm_domain *genpd_get_from_provider(
					struct of_phandle_args *genpdspec)
{
	struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
@@ -1499,7 +1668,109 @@ struct generic_pm_domain *of_genpd_get_from_provider(

	return genpd;
}
EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);

/**
 * of_genpd_add_device() - Add a device to an I/O PM domain
 * @genpdspec: OF phandle args to use for look-up PM domain
 * @dev: Device to be added.
 *
 * Looks-up an I/O PM domain based upon phandle args provided and adds
 * the device to the PM domain. Returns a negative error code on failure.
 */
int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev)
{
	struct generic_pm_domain *genpd;
	int ret;

	mutex_lock(&gpd_list_lock);

	genpd = genpd_get_from_provider(genpdspec);
	if (IS_ERR(genpd)) {
		ret = PTR_ERR(genpd);
		goto out;
	}

	ret = genpd_add_device(genpd, dev, NULL);

out:
	mutex_unlock(&gpd_list_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(of_genpd_add_device);

/**
 * of_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
 * @parent_spec: OF phandle args to use for parent PM domain look-up
 * @subdomain_spec: OF phandle args to use for subdomain look-up
 *
 * Looks-up a parent PM domain and subdomain based upon phandle args
 * provided and adds the subdomain to the parent PM domain. Returns a
 * negative error code on failure.
 */
int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,
			   struct of_phandle_args *subdomain_spec)
{
	struct generic_pm_domain *parent, *subdomain;
	int ret;

	mutex_lock(&gpd_list_lock);

	parent = genpd_get_from_provider(parent_spec);
	if (IS_ERR(parent)) {
		ret = PTR_ERR(parent);
		goto out;
	}

	subdomain = genpd_get_from_provider(subdomain_spec);
	if (IS_ERR(subdomain)) {
		ret = PTR_ERR(subdomain);
		goto out;
	}

	ret = genpd_add_subdomain(parent, subdomain);

out:
	mutex_unlock(&gpd_list_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(of_genpd_add_subdomain);

/**
 * of_genpd_remove_last - Remove the last PM domain registered for a provider
 * @provider: Pointer to device structure associated with provider
 *
 * Find the last PM domain that was added by a particular provider and
 * remove this PM domain from the list of PM domains. The provider is
 * identified by the 'provider' device structure that is passed. The PM
 * domain will only be removed, if the provider associated with domain
 * has been removed.
 *
 * Returns a valid pointer to struct generic_pm_domain on success or
 * ERR_PTR() on failure.
 */
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
{
	struct generic_pm_domain *gpd, *genpd = ERR_PTR(-ENOENT);
	int ret;

	if (IS_ERR_OR_NULL(np))
		return ERR_PTR(-EINVAL);

	mutex_lock(&gpd_list_lock);
	list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
		if (gpd->provider == &np->fwnode) {
			ret = genpd_remove(gpd);
			genpd = ret ? ERR_PTR(ret) : gpd;
			break;
		}
	}
	mutex_unlock(&gpd_list_lock);

	return genpd;
}
EXPORT_SYMBOL_GPL(of_genpd_remove_last);

/**
 * genpd_dev_pm_detach - Detach a device from its PM domain.
@@ -1515,14 +1786,14 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
	unsigned int i;
	int ret = 0;

	pd = pm_genpd_lookup_dev(dev);
	if (!pd)
	pd = dev_to_genpd(dev);
	if (IS_ERR(pd))
		return;

	dev_dbg(dev, "removing from PM domain %s\n", pd->name);

	for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
		ret = pm_genpd_remove_device(pd, dev);
		ret = genpd_remove_device(pd, dev);
		if (ret != -EAGAIN)
			break;

@@ -1596,9 +1867,11 @@ int genpd_dev_pm_attach(struct device *dev)
			return -ENOENT;
	}

	pd = of_genpd_get_from_provider(&pd_args);
	mutex_lock(&gpd_list_lock);
	pd = genpd_get_from_provider(&pd_args);
	of_node_put(pd_args.np);
	if (IS_ERR(pd)) {
		mutex_unlock(&gpd_list_lock);
		dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
			__func__, PTR_ERR(pd));
		return -EPROBE_DEFER;
@@ -1607,13 +1880,14 @@ int genpd_dev_pm_attach(struct device *dev)
	dev_dbg(dev, "adding to PM domain %s\n", pd->name);

	for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
		ret = pm_genpd_add_device(pd, dev);
		ret = genpd_add_device(pd, dev, NULL);
		if (ret != -EAGAIN)
			break;

		mdelay(i);
		cond_resched();
	}
	mutex_unlock(&gpd_list_lock);

	if (ret < 0) {
		dev_err(dev, "failed to add to PM domain %s: %d",
@@ -1636,7 +1910,7 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);

/***        debugfs support        ***/

#ifdef CONFIG_PM_ADVANCED_DEBUG
#ifdef CONFIG_DEBUG_FS
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/debugfs.h>
@@ -1784,4 +2058,4 @@ static void __exit pm_genpd_debug_exit(void)
	debugfs_remove_recursive(pm_genpd_debugfs_dir);
}
__exitcall(pm_genpd_debug_exit);
#endif /* CONFIG_PM_ADVANCED_DEBUG */
#endif /* CONFIG_DEBUG_FS */
+8 −15
Original line number Diff line number Diff line
@@ -215,29 +215,22 @@ static __init int exynos4_pm_init_power_domain(void)

	/* Assign the child power domains to their parents */
	for_each_matching_node(np, exynos_pm_domain_of_match) {
		struct generic_pm_domain *child_domain, *parent_domain;
		struct of_phandle_args args;
		struct of_phandle_args child, parent;

		args.np = np;
		args.args_count = 0;
		child_domain = of_genpd_get_from_provider(&args);
		if (IS_ERR(child_domain))
			continue;
		child.np = np;
		child.args_count = 0;

		if (of_parse_phandle_with_args(np, "power-domains",
					 "#power-domain-cells", 0, &args) != 0)
			continue;

		parent_domain = of_genpd_get_from_provider(&args);
		if (IS_ERR(parent_domain))
					       "#power-domain-cells", 0,
					       &parent) != 0)
			continue;

		if (pm_genpd_add_subdomain(parent_domain, child_domain))
		if (of_genpd_add_subdomain(&parent, &child))
			pr_warn("%s failed to add subdomain: %s\n",
				parent_domain->name, child_domain->name);
				parent.np->name, child.np->name);
		else
			pr_info("%s has as child subdomain: %s.\n",
				parent_domain->name, child_domain->name);
				parent.np->name, child.np->name);
	}

	return 0;
+1 −8
Original line number Diff line number Diff line
@@ -140,7 +140,6 @@ static int board_staging_add_dev_domain(struct platform_device *pdev,
					const char *domain)
{
	struct of_phandle_args pd_args;
	struct generic_pm_domain *pd;
	struct device_node *np;

	np = of_find_node_by_path(domain);
@@ -151,14 +150,8 @@ static int board_staging_add_dev_domain(struct platform_device *pdev,

	pd_args.np = np;
	pd_args.args_count = 0;
	pd = of_genpd_get_from_provider(&pd_args);
	if (IS_ERR(pd)) {
		pr_err("Cannot find genpd %s (%ld)\n", domain, PTR_ERR(pd));
		return PTR_ERR(pd);
	}
	pr_debug("Found genpd %s for device %s\n", pd->name, pdev->name);

	return pm_genpd_add_device(pd, &pdev->dev);
	return of_genpd_add_device(&pd_args, &pdev->dev);
}
#else
static inline int board_staging_add_dev_domain(struct platform_device *pdev,
+38 −36

File changed.

Preview size limit exceeded, changes collapsed.