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

Merge tag 'opp-updates-6.10' of...

Merge tag 'opp-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm into pm-opp

Merge OPP updates for v6.10 from Viresh Kumar:

"- Fix required_opp_tables for multiple genpds using same table (Viresh
   Kumar)."

* tag 'opp-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  OPP: Fix required_opp_tables for multiple genpds using same table
parents 0c181b1d 2a56c462
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -2394,7 +2394,8 @@ static void _opp_detach_genpd(struct opp_table *opp_table)
static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
			const char * const *names, struct device ***virt_devs)
{
	struct device *virt_dev;
	struct device *virt_dev, *gdev;
	struct opp_table *genpd_table;
	int index = 0, ret = -EINVAL;
	const char * const *name = names;

@@ -2427,6 +2428,34 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
			goto err;
		}

		/*
		 * The required_opp_tables parsing is not perfect, as the OPP
		 * core does the parsing solely based on the DT node pointers.
		 * The core sets the required_opp_tables entry to the first OPP
		 * table in the "opp_tables" list, that matches with the node
		 * pointer.
		 *
		 * If the target DT OPP table is used by multiple devices and
		 * they all create separate instances of 'struct opp_table' from
		 * it, then it is possible that the required_opp_tables entry
		 * may be set to the incorrect sibling device.
		 *
		 * Cross check it again and fix if required.
		 */
		gdev = dev_to_genpd_dev(virt_dev);
		if (IS_ERR(gdev))
			return PTR_ERR(gdev);

		genpd_table = _find_opp_table(gdev);
		if (!IS_ERR(genpd_table)) {
			if (genpd_table != opp_table->required_opp_tables[index]) {
				dev_pm_opp_put_opp_table(opp_table->required_opp_tables[index]);
				opp_table->required_opp_tables[index] = genpd_table;
			} else {
				dev_pm_opp_put_opp_table(genpd_table);
			}
		}

		/*
		 * Add the virtual genpd device as a user of the OPP table, so
		 * we can call dev_pm_opp_set_opp() on it directly.
+10 −0
Original line number Diff line number Diff line
@@ -184,6 +184,16 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
	return pd_to_genpd(dev->pm_domain);
}

struct device *dev_to_genpd_dev(struct device *dev)
{
	struct generic_pm_domain *genpd = dev_to_genpd(dev);

	if (IS_ERR(genpd))
		return ERR_CAST(genpd);

	return &genpd->dev;
}

static int genpd_stop_dev(const struct generic_pm_domain *genpd,
			  struct device *dev)
{
+6 −0
Original line number Diff line number Diff line
@@ -260,6 +260,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
int pm_genpd_init(struct generic_pm_domain *genpd,
		  struct dev_power_governor *gov, bool is_off);
int pm_genpd_remove(struct generic_pm_domain *genpd);
struct device *dev_to_genpd_dev(struct device *dev);
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
int dev_pm_genpd_remove_notifier(struct device *dev);
@@ -307,6 +308,11 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
	return -EOPNOTSUPP;
}

static inline struct device *dev_to_genpd_dev(struct device *dev)
{
	return ERR_PTR(-EOPNOTSUPP);
}

static inline int dev_pm_genpd_set_performance_state(struct device *dev,
						     unsigned int state)
{