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

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

Merge branch 'pm-domains'

* pm-domains:
  PM: Convert dev_pm_put_subsys_data() into a void function
  PM: Update function header for dev_pm_get_subsys_data()
  PM / Domains: Handle errors from genpd's ->attach_dev() callback
  PM / Domains: Re-order initialization of generic_pm_domain_data
  PM / Domains: Free pm_subsys_data in error path in __pm_genpd_add_device()
  PM / Domains: Eliminate the mutex for the generic_pm_domain_data
  PM / Domains: Don't check for an existing device when adding a new
  PM / Domains: Don't allow an existing generic_pm_domain_data
  PM / Domains: Remove reference counting for the generic_pm_domain_data
  PM / Domains: Rename __pm_genpd_alloc|free_dev_data()
  PM / Domains: Remove pm_genpd_dev_need_restore() API
parents 740b68ea 1e95e3b2
Loading
Loading
Loading
Loading
+6 −12
Original line number Diff line number Diff line
@@ -19,8 +19,8 @@
 * @dev: Device to handle.
 *
 * If power.subsys_data is NULL, point it to a new object, otherwise increment
 * its reference counter.  Return 1 if a new object has been created, otherwise
 * return 0 or error code.
 * its reference counter.  Return 0 if new object has been created or refcount
 * increased, otherwise negative error code.
 */
int dev_pm_get_subsys_data(struct device *dev)
{
@@ -56,13 +56,11 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
 * @dev: Device to handle.
 *
 * If the reference counter of power.subsys_data is zero after dropping the
 * reference, power.subsys_data is removed.  Return 1 if that happens or 0
 * otherwise.
 * reference, power.subsys_data is removed.
 */
int dev_pm_put_subsys_data(struct device *dev)
void dev_pm_put_subsys_data(struct device *dev)
{
	struct pm_subsys_data *psd;
	int ret = 1;

	spin_lock_irq(&dev->power.lock);

@@ -70,18 +68,14 @@ int dev_pm_put_subsys_data(struct device *dev)
	if (!psd)
		goto out;

	if (--psd->refcount == 0) {
	if (--psd->refcount == 0)
		dev->power.subsys_data = NULL;
	} else {
	else
		psd = NULL;
		ret = 0;
	}

 out:
	spin_unlock_irq(&dev->power.lock);
	kfree(psd);

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);

+65 −92
Original line number Diff line number Diff line
@@ -344,14 +344,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
	struct device *dev;

	gpd_data = container_of(nb, struct generic_pm_domain_data, nb);

	mutex_lock(&gpd_data->lock);
	dev = gpd_data->base.dev;
	if (!dev) {
		mutex_unlock(&gpd_data->lock);
		return NOTIFY_DONE;
	}
	mutex_unlock(&gpd_data->lock);

	for (;;) {
		struct generic_pm_domain *genpd;
@@ -1384,25 +1377,66 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron);

#endif /* CONFIG_PM_SLEEP */

static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev)
static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
					struct generic_pm_domain *genpd,
					struct gpd_timing_data *td)
{
	struct generic_pm_domain_data *gpd_data;
	int ret;

	ret = dev_pm_get_subsys_data(dev);
	if (ret)
		return ERR_PTR(ret);

	gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
	if (!gpd_data)
		return NULL;
	if (!gpd_data) {
		ret = -ENOMEM;
		goto err_put;
	}

	mutex_init(&gpd_data->lock);
	if (td)
		gpd_data->td = *td;

	gpd_data->base.dev = dev;
	gpd_data->need_restore = -1;
	gpd_data->td.constraint_changed = true;
	gpd_data->td.effective_constraint_ns = -1;
	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
	dev_pm_qos_add_notifier(dev, &gpd_data->nb);

	spin_lock_irq(&dev->power.lock);

	if (dev->power.subsys_data->domain_data) {
		ret = -EINVAL;
		goto err_free;
	}

	dev->power.subsys_data->domain_data = &gpd_data->base;
	dev->pm_domain = &genpd->domain;

	spin_unlock_irq(&dev->power.lock);

	return gpd_data;

 err_free:
	spin_unlock_irq(&dev->power.lock);
	kfree(gpd_data);
 err_put:
	dev_pm_put_subsys_data(dev);
	return ERR_PTR(ret);
}

static void __pm_genpd_free_dev_data(struct device *dev,
static void genpd_free_dev_data(struct device *dev,
				struct generic_pm_domain_data *gpd_data)
{
	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
	spin_lock_irq(&dev->power.lock);

	dev->pm_domain = NULL;
	dev->power.subsys_data->domain_data = NULL;

	spin_unlock_irq(&dev->power.lock);

	kfree(gpd_data);
	dev_pm_put_subsys_data(dev);
}

/**
@@ -1414,8 +1448,7 @@ static void __pm_genpd_free_dev_data(struct device *dev,
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
			  struct gpd_timing_data *td)
{
	struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
	struct pm_domain_data *pdd;
	struct generic_pm_domain_data *gpd_data;
	int ret = 0;

	dev_dbg(dev, "%s()\n", __func__);
@@ -1423,9 +1456,9 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
		return -EINVAL;

	gpd_data_new = __pm_genpd_alloc_dev_data(dev);
	if (!gpd_data_new)
		return -ENOMEM;
	gpd_data = genpd_alloc_dev_data(dev, genpd, td);
	if (IS_ERR(gpd_data))
		return PTR_ERR(gpd_data);

	genpd_acquire_lock(genpd);

@@ -1434,50 +1467,22 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
		goto out;
	}

	list_for_each_entry(pdd, &genpd->dev_list, list_node)
		if (pdd->dev == dev) {
			ret = -EINVAL;
			goto out;
		}

	ret = dev_pm_get_subsys_data(dev);
	ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0;
	if (ret)
		goto out;

	genpd->device_count++;
	genpd->max_off_time_changed = true;

	spin_lock_irq(&dev->power.lock);

	dev->pm_domain = &genpd->domain;
	if (dev->power.subsys_data->domain_data) {
		gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
	} else {
		gpd_data = gpd_data_new;
		dev->power.subsys_data->domain_data = &gpd_data->base;
	}
	gpd_data->refcount++;
	if (td)
		gpd_data->td = *td;

	spin_unlock_irq(&dev->power.lock);

	if (genpd->attach_dev)
		genpd->attach_dev(genpd, dev);

	mutex_lock(&gpd_data->lock);
	gpd_data->base.dev = dev;
	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
	gpd_data->need_restore = -1;
	gpd_data->td.constraint_changed = true;
	gpd_data->td.effective_constraint_ns = -1;
	mutex_unlock(&gpd_data->lock);

 out:
	genpd_release_lock(genpd);

	if (gpd_data != gpd_data_new)
		__pm_genpd_free_dev_data(dev, gpd_data_new);
	if (ret)
		genpd_free_dev_data(dev, gpd_data);
	else
		dev_pm_qos_add_notifier(dev, &gpd_data->nb);

	return ret;
}
@@ -1504,7 +1509,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
{
	struct generic_pm_domain_data *gpd_data;
	struct pm_domain_data *pdd;
	bool remove = false;
	int ret = 0;

	dev_dbg(dev, "%s()\n", __func__);
@@ -1514,6 +1518,11 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
	    ||  pd_to_genpd(dev->pm_domain) != genpd)
		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);

	genpd_acquire_lock(genpd);

	if (genpd->prepared_count > 0) {
@@ -1527,57 +1536,21 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
	if (genpd->detach_dev)
		genpd->detach_dev(genpd, dev);

	spin_lock_irq(&dev->power.lock);

	dev->pm_domain = NULL;
	pdd = dev->power.subsys_data->domain_data;
	list_del_init(&pdd->list_node);
	gpd_data = to_gpd_data(pdd);
	if (--gpd_data->refcount == 0) {
		dev->power.subsys_data->domain_data = NULL;
		remove = true;
	}

	spin_unlock_irq(&dev->power.lock);

	mutex_lock(&gpd_data->lock);
	pdd->dev = NULL;
	mutex_unlock(&gpd_data->lock);

	genpd_release_lock(genpd);

	dev_pm_put_subsys_data(dev);
	if (remove)
		__pm_genpd_free_dev_data(dev, gpd_data);
	genpd_free_dev_data(dev, gpd_data);

	return 0;

 out:
	genpd_release_lock(genpd);
	dev_pm_qos_add_notifier(dev, &gpd_data->nb);

	return ret;
}

/**
 * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
 * @dev: Device to set/unset the flag for.
 * @val: The new value of the device's "need restore" flag.
 */
void pm_genpd_dev_need_restore(struct device *dev, bool val)
{
	struct pm_subsys_data *psd;
	unsigned long flags;

	spin_lock_irqsave(&dev->power.lock, flags);

	psd = dev_to_psd(dev);
	if (psd && psd->domain_data)
		to_gpd_data(psd->domain_data)->need_restore = val ? 1 : 0;

	spin_unlock_irqrestore(&dev->power.lock, flags);
}
EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);

/**
 * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
 * @genpd: Master PM domain to add the subdomain to.
+1 −1
Original line number Diff line number Diff line
@@ -597,7 +597,7 @@ struct dev_pm_info {

extern void update_pm_runtime_accounting(struct device *dev);
extern int dev_pm_get_subsys_data(struct device *dev);
extern int dev_pm_put_subsys_data(struct device *dev);
extern void dev_pm_put_subsys_data(struct device *dev);

/*
 * Power domains provide callbacks that are executed during system suspend,
+0 −4
Original line number Diff line number Diff line
@@ -113,8 +113,6 @@ struct generic_pm_domain_data {
	struct pm_domain_data base;
	struct gpd_timing_data td;
	struct notifier_block nb;
	struct mutex lock;
	unsigned int refcount;
	int need_restore;
};

@@ -140,7 +138,6 @@ extern int __pm_genpd_name_add_device(const char *domain_name,

extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
				  struct device *dev);
extern void pm_genpd_dev_need_restore(struct device *dev, bool val);
extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
				  struct generic_pm_domain *new_subdomain);
extern int pm_genpd_add_subdomain_names(const char *master_name,
@@ -187,7 +184,6 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd,
{
	return -ENOSYS;
}
static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {}
static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
					 struct generic_pm_domain *new_sd)
{