Merge tag 'driver-core-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[platform/kernel/linux-rpi.git] / drivers / base / power / domain.c
index 6ac52a0..78c310d 100644 (file)
@@ -297,6 +297,18 @@ static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,
        return state;
 }
 
+static int genpd_xlate_performance_state(struct generic_pm_domain *genpd,
+                                        struct generic_pm_domain *parent,
+                                        unsigned int pstate)
+{
+       if (!parent->set_performance_state)
+               return pstate;
+
+       return dev_pm_opp_xlate_performance_state(genpd->opp_table,
+                                                 parent->opp_table,
+                                                 pstate);
+}
+
 static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
                                        unsigned int state, int depth)
 {
@@ -311,13 +323,8 @@ static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
        list_for_each_entry(link, &genpd->child_links, child_node) {
                parent = link->parent;
 
-               if (!parent->set_performance_state)
-                       continue;
-
                /* Find parent's performance state */
-               ret = dev_pm_opp_xlate_performance_state(genpd->opp_table,
-                                                        parent->opp_table,
-                                                        state);
+               ret = genpd_xlate_performance_state(genpd, parent, state);
                if (unlikely(ret < 0))
                        goto err;
 
@@ -339,9 +346,11 @@ static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
                        goto err;
        }
 
-       ret = genpd->set_performance_state(genpd, state);
-       if (ret)
-               goto err;
+       if (genpd->set_performance_state) {
+               ret = genpd->set_performance_state(genpd, state);
+               if (ret)
+                       goto err;
+       }
 
        genpd->performance_state = state;
        return 0;
@@ -352,9 +361,6 @@ err:
                                             child_node) {
                parent = link->parent;
 
-               if (!parent->set_performance_state)
-                       continue;
-
                genpd_lock_nested(parent, depth + 1);
 
                parent_state = link->prev_performance_state;
@@ -399,9 +405,6 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
        if (!genpd)
                return -ENODEV;
 
-       if (unlikely(!genpd->set_performance_state))
-               return -EINVAL;
-
        if (WARN_ON(!dev->power.subsys_data ||
                     !dev->power.subsys_data->domain_data))
                return -EINVAL;
@@ -423,6 +426,35 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
 }
 EXPORT_SYMBOL_GPL(dev_pm_genpd_set_performance_state);
 
+/**
+ * dev_pm_genpd_set_next_wakeup - Notify PM framework of an impending wakeup.
+ *
+ * @dev: Device to handle
+ * @next: impending interrupt/wakeup for the device
+ *
+ *
+ * Allow devices to inform of the next wakeup. It's assumed that the users
+ * guarantee that the genpd wouldn't be detached while this routine is getting
+ * called. Additionally, it's also assumed that @dev isn't runtime suspended
+ * (RPM_SUSPENDED)."
+ * Although devices are expected to update the next_wakeup after the end of
+ * their usecase as well, it is possible the devices themselves may not know
+ * about that, so stale @next will be ignored when powering off the domain.
+ */
+void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next)
+{
+       struct generic_pm_domain_data *gpd_data;
+       struct generic_pm_domain *genpd;
+
+       genpd = dev_to_genpd_safe(dev);
+       if (!genpd)
+               return;
+
+       gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+       gpd_data->next_wakeup = next;
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_set_next_wakeup);
+
 static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 {
        unsigned int state_idx = genpd->state_idx;
@@ -934,8 +966,7 @@ static int genpd_runtime_resume(struct device *dev)
 err_stop:
        genpd_stop_dev(genpd, dev);
 err_poweroff:
-       if (!pm_runtime_is_irq_safe(dev) ||
-               (pm_runtime_is_irq_safe(dev) && genpd_is_irq_safe(genpd))) {
+       if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) {
                genpd_lock(genpd);
                genpd_power_off(genpd, true, 0);
                genpd_unlock(genpd);
@@ -1465,6 +1496,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
        gpd_data->td.constraint_changed = true;
        gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
        gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+       gpd_data->next_wakeup = KTIME_MAX;
 
        spin_lock_irq(&dev->power.lock);
 
@@ -2465,7 +2497,7 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,
 out:
        mutex_unlock(&gpd_list_lock);
 
-       return ret;
+       return ret == -ENOENT ? -EPROBE_DEFER : ret;
 }
 EXPORT_SYMBOL_GPL(of_genpd_add_subdomain);
 
@@ -2954,7 +2986,15 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
        else
                WARN_ON(1);
 
-       seq_puts(s, p);
+       seq_printf(s, "%-25s  ", p);
+}
+
+static void perf_status_str(struct seq_file *s, struct device *dev)
+{
+       struct generic_pm_domain_data *gpd_data;
+
+       gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+       seq_put_decimal_ull(s, "", gpd_data->performance_state);
 }
 
 static int genpd_summary_one(struct seq_file *s,
@@ -2982,7 +3022,7 @@ static int genpd_summary_one(struct seq_file *s,
        else
                snprintf(state, sizeof(state), "%s",
                         status_lookup[genpd->status]);
-       seq_printf(s, "%-30s  %-15s ", genpd->name, state);
+       seq_printf(s, "%-30s  %-50s %u", genpd->name, state, genpd->performance_state);
 
        /*
         * Modifications on the list require holding locks on both
@@ -2990,6 +3030,8 @@ static int genpd_summary_one(struct seq_file *s,
         * Also genpd->name is immutable.
         */
        list_for_each_entry(link, &genpd->parent_links, parent_node) {
+               if (list_is_first(&link->parent_node, &genpd->parent_links))
+                       seq_printf(s, "\n%48s", " ");
                seq_printf(s, "%s", link->child->name);
                if (!list_is_last(&link->parent_node, &genpd->parent_links))
                        seq_puts(s, ", ");
@@ -3004,6 +3046,7 @@ static int genpd_summary_one(struct seq_file *s,
 
                seq_printf(s, "\n    %-50s  ", kobj_path);
                rtpm_status_str(s, pm_data->dev);
+               perf_status_str(s, pm_data->dev);
                kfree(kobj_path);
        }
 
@@ -3019,9 +3062,9 @@ static int summary_show(struct seq_file *s, void *data)
        struct generic_pm_domain *genpd;
        int ret = 0;
 
-       seq_puts(s, "domain                          status          children\n");
+       seq_puts(s, "domain                          status          children                           performance\n");
        seq_puts(s, "    /device                                             runtime status\n");
-       seq_puts(s, "----------------------------------------------------------------------\n");
+       seq_puts(s, "----------------------------------------------------------------------------------------------\n");
 
        ret = mutex_lock_interruptible(&gpd_list_lock);
        if (ret)