From 4acbfb6c116be5989d5a0e38a48deca2d5b8bb92 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Sep 2025 10:21:06 +0800 Subject: PM: wakeup: Add out-of-band system wakeup support for devices Some devices can wake up the system from suspend even when their power domains are turned off. This is possible because their system-wakeup logic resides in an always-on power domain - indicating that they support out-of-band system wakeup. Currently, PM domain core doesn't power off such devices if they are marked as system wakeup sources. To better represent devices with out-of-band wakeup capability, this patch introduces a new flag out_band_wakeup in 'struct dev_pm_info'. Two helper APIs are added: - device_set_out_band_wakeup() - to mark a device as having out-of-band wakeup capability. - device_out_band_wakeup() - to query the flag. Allow the PM core and drivers to distinguish between regular and out-of-band wakeup sources, enable more accurate power management decision. Signed-off-by: Peng Fan Reviewed-by: Dhruva Gole Signed-off-by: Ulf Hansson --- include/linux/pm.h | 1 + include/linux/pm_wakeup.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pm.h b/include/linux/pm.h index cc7b2dc28574..5b28a4f2e87e 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -684,6 +684,7 @@ struct dev_pm_info { bool smart_suspend:1; /* Owned by the PM core */ bool must_resume:1; /* Owned by the PM core */ bool may_skip_resume:1; /* Set by subsystems */ + bool out_band_wakeup:1; bool strict_midlayer:1; #else bool should_wakeup:1; diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index c838b4a30f87..41e8f344a205 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -94,6 +94,16 @@ static inline void device_set_wakeup_path(struct device *dev) dev->power.wakeup_path = true; } +static inline void device_set_out_band_wakeup(struct device *dev) +{ + dev->power.out_band_wakeup = true; +} + +static inline bool device_out_band_wakeup(struct device *dev) +{ + return dev->power.out_band_wakeup; +} + /* drivers/base/power/wakeup.c */ extern struct wakeup_source *wakeup_source_register(struct device *dev, const char *name); @@ -162,6 +172,13 @@ static inline bool device_wakeup_path(struct device *dev) static inline void device_set_wakeup_path(struct device *dev) {} +static inline void device_set_out_band_wakeup(struct device *dev) {} + +static inline bool device_out_band_wakeup(struct device *dev) +{ + return false; +} + static inline void __pm_stay_awake(struct wakeup_source *ws) {} static inline void pm_stay_awake(struct device *dev) {} -- cgit v1.2.3 From 854825367a1d28b3b6c757134460d0fe29a0b4a6 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Sep 2025 10:21:09 +0800 Subject: usb: chipidea: ci_hdrc_imx: Set out of band wakeup for i.MX95 i.MX95 USB2 inside HSIOMIX could still wakeup Linux, even if HSIOMIX power domain(Digital logic) is off. There is still always on logic have the wakeup capability which is out band wakeup capbility. So use device_set_out_band_wakeup for i.MX95 to make sure usb2 could wakeup system even if HSIOMIX power domain is in off state. Tested-by: Xu Yang Reviewed-by: Xu Yang Signed-off-by: Peng Fan Acked-by: Peter Chen Signed-off-by: Ulf Hansson --- drivers/usb/chipidea/ci_hdrc_imx.c | 11 ++++++++++- include/linux/usb/chipidea.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index d7c2a1a3c271..d4ee9e16332f 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -79,6 +79,10 @@ static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = { CI_HDRC_HAS_PORTSC_PEC_MISSED, }; +static const struct ci_hdrc_imx_platform_flag imx95_usb_data = { + .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | CI_HDRC_OUT_BAND_WAKEUP, +}; + static const struct ci_hdrc_imx_platform_flag s32g_usb_data = { .flags = CI_HDRC_DISABLE_HOST_STREAMING, }; @@ -94,6 +98,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = { { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data}, { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data}, { .compatible = "fsl,imx8ulp-usb", .data = &imx8ulp_usb_data}, + { .compatible = "fsl,imx95-usb", .data = &imx95_usb_data}, { .compatible = "nxp,s32g2-usb", .data = &s32g_usb_data}, { /* sentinel */ } }; @@ -704,9 +709,13 @@ static int ci_hdrc_imx_suspend(struct device *dev) pinctrl_pm_select_sleep_state(dev); - if (data->wakeup_irq > 0 && device_may_wakeup(dev)) + if (data->wakeup_irq > 0 && device_may_wakeup(dev)) { enable_irq_wake(data->wakeup_irq); + if (data->plat_data->flags & CI_HDRC_OUT_BAND_WAKEUP) + device_set_out_band_wakeup(dev); + } + return ret; } diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index e17ebeee24e3..c6451191d2de 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -66,6 +66,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_HAS_PORTSC_PEC_MISSED BIT(17) #define CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS BIT(18) #define CI_HDRC_HAS_SHORT_PKT_LIMIT BIT(19) +#define CI_HDRC_OUT_BAND_WAKEUP BIT(20) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 -- cgit v1.2.3 From ccde6525183c5489de293cf91a441585fff3c847 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 5 Nov 2025 10:54:07 +0100 Subject: smp: Introduce a helper function to check for pending IPIs When governors used during cpuidle try to find the most optimal idle state for a CPU or a group of CPUs, they are known to quite often fail. One reason for this is, that they are not taking into account whether there has been an IPI scheduled for any of the CPUs that are affected by the selected idle state. To enable pending IPIs to be taken into account for cpuidle decisions, introduce a new helper function, cpus_peek_for_pending_ipi(). Suggested-by: Thomas Gleixner Reviewed-by: Thomas Gleixner Signed-off-by: Ulf Hansson --- include/linux/smp.h | 5 +++++ kernel/smp.c | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'include/linux') diff --git a/include/linux/smp.h b/include/linux/smp.h index 18e9c918325e..91d0ecf3b8d3 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -168,6 +168,7 @@ int smp_call_function_any(const struct cpumask *mask, void kick_all_cpus_sync(void); void wake_up_all_idle_cpus(void); +bool cpus_peek_for_pending_ipi(const struct cpumask *mask); /* * Generic and arch helpers @@ -216,6 +217,10 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, static inline void kick_all_cpus_sync(void) { } static inline void wake_up_all_idle_cpus(void) { } +static inline bool cpus_peek_for_pending_ipi(const struct cpumask *mask) +{ + return false; +} #define setup_max_cpus 0 diff --git a/kernel/smp.c b/kernel/smp.c index 02f52291fae4..f349960f79ca 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -1087,6 +1087,28 @@ void wake_up_all_idle_cpus(void) } EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus); +/** + * cpus_peek_for_pending_ipi - Check for pending IPI for CPUs + * @mask: The CPU mask for the CPUs to check. + * + * This function walks through the @mask to check if there are any pending IPIs + * scheduled, for any of the CPUs in the @mask. It does not guarantee + * correctness as it only provides a racy snapshot. + * + * Returns true if there is a pending IPI scheduled and false otherwise. + */ +bool cpus_peek_for_pending_ipi(const struct cpumask *mask) +{ + unsigned int cpu; + + for_each_cpu(cpu, mask) { + if (!llist_empty(per_cpu_ptr(&call_single_queue, cpu))) + return true; + } + + return false; +} + /** * struct smp_call_on_cpu_struct - Call a function on a specific CPU * @work: &work_struct -- cgit v1.2.3