[PATCH] PCI: Add disabling pm async quirk for JMicron chips
Some history from commit e6b7e41cdd8c ("ata: Disabling the async PM for JMicron chip 363/361") == Since v3.15, the PM feature of async noirq commit 76569faa62c4 ("PM / sleep: Asynchronous threads for resume_noirq") is introduced. Then Jay hit one system resuming issue that one of the JMicron controller can not be powered up successfully. His device tree is like below: +-1c.4-[02]--+-00.0 JMicron Technology Corp. JMB363 SATA/IDE Controller |\-00.1 JMicron Technology Corp. JMB363 SATA/IDE Controller After investigation, we found the the Micron chip 363 included one SATA controller(:02:00.0) and one PATA controller(:02:00.1), these two controllers do not have parent-children relationship, but the PATA controller only can be powered on after the SATA controller has finished the powering on. If we enabled the async noirq(), then the below error is hit during noirq phase: pata_jmicron :02:00.1: Refused to change power state, currently in D3 Here for JMicron chip 363/361, we need forcedly to disable the async method. Bug detail: https://bugzilla.kernel.org/show_bug.cgi?id=81551 == After that, Barto reported the same issue, but his Jmicron chip is JMB368, so it can not be covered by commit e6b7e41cdd8c ("ata: Disabling the async PM for JMicron chip 363/361"). Bug link: https://bugzilla.kernel.org/show_bug.cgi?id=84861 Here we think Jmicron chips have the same issue as describled in commit e6b7e41cdd8c ("ata: Disabling the async PM for JMicron chip 363/361"), so here add one quirk to disable the JMicron chips' PM async feature. Cc: sta...@vger.kernel.org # 3.15+ Signed-off-by: Chuansheng Liu --- drivers/pci/quirks.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 90acb32..1963080 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1501,6 +1501,21 @@ static void quirk_jmicron_ata(struct pci_dev *pdev) pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class); pdev->class = class >> 8; } + +/* + * For JMicron chips, we need to disable the async_suspend method, otherwise + * they will hit the power-on issue when doing device resume, add one quirk + * solution to disable the async_suspend method. + */ +static void pci_async_suspend_fixup(struct pci_dev *pdev) +{ + /* +* disabling the async_suspend method for JMicron chips to +* avoid device resuming issue. +*/ + device_disable_async_suspend(&pdev->dev); +} + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata); @@ -1519,6 +1534,8 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB3 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB369, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, + pci_async_suspend_fixup); #endif -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] PCI: Do not enable async suspend for JMicron chips
The JMicron chip 361/363/368 contains one SATA controller and one PATA controller, they are brother-relation ship in PCI tree, but for powering on these both controller, we must follow the sequence one by one, otherwise one of them can not be powered on successfully. So here we disable the async suspend method for Jmicron chip. Bug link: https://bugzilla.kernel.org/show_bug.cgi?id=81551 https://bugzilla.kernel.org/show_bug.cgi?id=84861 And we can revert the below commit after this patch is applied: e6b7e41(ata: Disabling the async PM for JMicron chip 363/361) Cc: sta...@vger.kernel.org # 3.15+ Acked-by: Aaron Lu Signed-off-by: Chuansheng Liu --- drivers/pci/pci.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 625a4ac..53128f0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2046,7 +2046,17 @@ void pci_pm_init(struct pci_dev *dev) pm_runtime_forbid(&dev->dev); pm_runtime_set_active(&dev->dev); pm_runtime_enable(&dev->dev); - device_enable_async_suspend(&dev->dev); + + /* +* The JMicron chip 361/363/368 contains one SATA controller and +* one PATA controller, they are brother-relation ship in PCI tree, +* but for powering on these both controller, we must follow the +* sequence one by one, otherwise one of them can not be powered on +* successfully, so here we disable the async suspend method for +* Jmicron chip. +*/ + if (dev->vendor != PCI_VENDOR_ID_JMICRON) + device_enable_async_suspend(&dev->dev); dev->wakeup_prepared = false; dev->pm_cap = 0; -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] PCI: Do not enable async suspend for JMicron chips
The JMicron chip 361/363/368 contains one SATA controller and one PATA controller, they are brother-relation ship in PCI tree, but for powering on these both controller, we must follow the sequence one by one, otherwise one of them can not be powered on successfully. So here we disable the async suspend method for Jmicron chip. Cc: sta...@vger.kernel.org # 3.15+ Signed-off-by: Chuansheng Liu --- drivers/pci/pci.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 625a4ac..53128f0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2046,7 +2046,17 @@ void pci_pm_init(struct pci_dev *dev) pm_runtime_forbid(&dev->dev); pm_runtime_set_active(&dev->dev); pm_runtime_enable(&dev->dev); - device_enable_async_suspend(&dev->dev); + + /* +* The JMicron chip 361/363/368 contains one SATA controller and +* one PATA controller, they are brother-relation ship in PCI tree, +* but for powering on these both controller, we must follow the +* sequence one by one, otherwise one of them can not be powered on +* successfully, so here we disable the async suspend method for +* Jmicron chip. +*/ + if (dev->vendor != PCI_VENDOR_ID_JMICRON) + device_enable_async_suspend(&dev->dev); dev->wakeup_prepared = false; dev->pm_cap = 0; -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] ata: Disabling the async PM for JMicron chips
Like the commit e6b7e41cdd8c ("ata: Disabling the async PM for JMicron chip 363/361"), Barto found the similar issue for JMicron chip 368, that 363/368 has no parent-children relationship, but they have the power dependency. So here we can exclude the JMicron chips out of pm_async method directly, to avoid further similar issues. Details in: https://bugzilla.kernel.org/show_bug.cgi?id=84861 Reported-and-tested-by: Barto Signed-off-by: Chuansheng Liu --- drivers/ata/ahci.c | 11 +-- drivers/ata/pata_jmicron.c | 11 +-- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a0cc0ed..85aa6ec 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1340,15 +1340,14 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS; /* -* The JMicron chip 361/363 contains one SATA controller and one +* The JMicron chip 361/363/368 contains one SATA controller and one * PATA controller,for powering on these both controllers, we must * follow the sequence one by one, otherwise one of them can not be -* powered on successfully, so here we disable the async suspend -* method for these chips. +* powered on successfully. +* Here we can exclude the Jmicron family directly out of pm_async +* method to follow the power-on sequence. */ - if (pdev->vendor == PCI_VENDOR_ID_JMICRON && - (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 || - pdev->device == PCI_DEVICE_ID_JMICRON_JMB361)) + if (pdev->vendor == PCI_VENDOR_ID_JMICRON) device_disable_async_suspend(&pdev->dev); /* acquire resources */ diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 47e418b..1d685b6 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -144,15 +144,14 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i const struct ata_port_info *ppi[] = { &info, NULL }; /* -* The JMicron chip 361/363 contains one SATA controller and one +* The JMicron chip 361/363/368 contains one SATA controller and one * PATA controller,for powering on these both controllers, we must * follow the sequence one by one, otherwise one of them can not be -* powered on successfully, so here we disable the async suspend -* method for these chips. +* powered on successfully. +* Here we can exclude the Jmicron family directly out of pm_async +* method to follow the power-on sequence. */ - if (pdev->vendor == PCI_VENDOR_ID_JMICRON && - (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 || - pdev->device == PCI_DEVICE_ID_JMICRON_JMB361)) + if (pdev->vendor == PCI_VENDOR_ID_JMICRON) device_disable_async_suspend(&pdev->dev); return ata_pci_bmdma_init_one(pdev, ppi, &jmicron_sht, NULL, 0); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ata: Disabling the async PM for JMicron chips
Be similar with commit (ata: Disabling the async PM for JMicron chip 363/361), Barto found the similar issue for JMicron chip 368, that 363/368 has no parent-children relationship, but they have the power dependency. So here we can exclude the JMicron chips out of pm_async method directly, to avoid further similar issues. Details in: https://bugzilla.kernel.org/show_bug.cgi?id=84861 Reported-and-tested-by: Barto Signed-off-by: Chuansheng Liu --- drivers/ata/ahci.c |6 +++--- drivers/ata/pata_jmicron.c |6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a0cc0ed..c096d49 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1345,10 +1345,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * follow the sequence one by one, otherwise one of them can not be * powered on successfully, so here we disable the async suspend * method for these chips. +* Jmicron chip 368 has been found has the similar issue, here we can +* exclude the Jmicron family directly to avoid other similar issues. */ - if (pdev->vendor == PCI_VENDOR_ID_JMICRON && - (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 || - pdev->device == PCI_DEVICE_ID_JMICRON_JMB361)) + if (pdev->vendor == PCI_VENDOR_ID_JMICRON) device_disable_async_suspend(&pdev->dev); /* acquire resources */ diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 47e418b..48c993b 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -149,10 +149,10 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i * follow the sequence one by one, otherwise one of them can not be * powered on successfully, so here we disable the async suspend * method for these chips. +* Jmicron chip 368 has been found has the similar issue, here we can +* exclude the Jmicron family directly to avoid other similar issues. */ - if (pdev->vendor == PCI_VENDOR_ID_JMICRON && - (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 || - pdev->device == PCI_DEVICE_ID_JMICRON_JMB361)) + if (pdev->vendor == PCI_VENDOR_ID_JMICRON) device_disable_async_suspend(&pdev->dev); return ata_pci_bmdma_init_one(pdev, ppi, &jmicron_sht, NULL, 0); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:sched/core] cpuidle: Use wake_up_all_idle_cpus() to wake up all idle cpus
Commit-ID: 2ed903c5485bad0eafdd3d59ff993598736e4f31 Gitweb: http://git.kernel.org/tip/2ed903c5485bad0eafdd3d59ff993598736e4f31 Author: Chuansheng Liu AuthorDate: Thu, 4 Sep 2014 15:17:55 +0800 Committer: Ingo Molnar CommitDate: Fri, 19 Sep 2014 12:35:16 +0200 cpuidle: Use wake_up_all_idle_cpus() to wake up all idle cpus Currently kick_all_cpus_sync() or smp_call_function() can not break the polling idle cpu immediately. Instead using wake_up_all_idle_cpus() which can wake up the polling idle cpu quickly is much more helpful for power. Signed-off-by: Chuansheng Liu Signed-off-by: Peter Zijlstra (Intel) Cc: linux...@vger.kernel.org Cc: changcheng@intel.com Cc: xiaoming.w...@intel.com Cc: souvik.k.chakrava...@intel.com Cc: l...@amacapital.net Cc: Daniel Lezcano Cc: Linus Torvalds Cc: Rafael J. Wysocki Cc: linux...@vger.kernel.org Link: http://lkml.kernel.org/r/1409815075-4180-3-git-send-email-chuansheng@intel.com Signed-off-by: Ingo Molnar --- drivers/cpuidle/cpuidle.c | 9 ++--- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index ee9df5e..d31e04c 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -223,7 +223,7 @@ void cpuidle_uninstall_idle_handler(void) { if (enabled_devices) { initialized = 0; - kick_all_cpus_sync(); + wake_up_all_idle_cpus(); } } @@ -530,11 +530,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register); #ifdef CONFIG_SMP -static void smp_callback(void *v) -{ - /* we already woke the CPU up, nothing more to do */ -} - /* * This function gets called when a part of the kernel has a new latency * requirement. This means we need to get all processors out of their C-state, @@ -544,7 +539,7 @@ static void smp_callback(void *v) static int cpuidle_latency_notify(struct notifier_block *b, unsigned long l, void *v) { - smp_call_function(smp_callback, NULL, 1); + wake_up_all_idle_cpus(); return NOTIFY_OK; } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:sched/core] smp: Add new wake_up_all_idle_cpus() function
Commit-ID: c6f4459fc3ba532e896cb678e29b45cb985f82bf Gitweb: http://git.kernel.org/tip/c6f4459fc3ba532e896cb678e29b45cb985f82bf Author: Chuansheng Liu AuthorDate: Thu, 4 Sep 2014 15:17:54 +0800 Committer: Ingo Molnar CommitDate: Fri, 19 Sep 2014 12:35:15 +0200 smp: Add new wake_up_all_idle_cpus() function Currently kick_all_cpus_sync() can break non-polling idle cpus thru IPI interrupts. But sometimes we need to break the polling idle cpus immediately to reselect the suitable c-state, also for non-idle cpus, we need to do nothing if we try to wake up them. Here adding one new function wake_up_all_idle_cpus() to let all cpus out of idle based on function wake_up_if_idle(). Signed-off-by: Chuansheng Liu Signed-off-by: Peter Zijlstra (Intel) Cc: daniel.lezc...@linaro.org Cc: r...@rjwysocki.net Cc: linux...@vger.kernel.org Cc: changcheng@intel.com Cc: xiaoming.w...@intel.com Cc: souvik.k.chakrava...@intel.com Cc: l...@amacapital.net Cc: Andrew Morton Cc: Christoph Hellwig Cc: Frederic Weisbecker Cc: Geert Uytterhoeven Cc: Jan Kara Cc: Jens Axboe Cc: Jens Axboe Cc: Linus Torvalds Cc: Michal Hocko Cc: Paul Gortmaker Cc: Roman Gushchin Cc: Srivatsa S. Bhat Link: http://lkml.kernel.org/r/1409815075-4180-2-git-send-email-chuansheng@intel.com Signed-off-by: Ingo Molnar --- include/linux/smp.h | 2 ++ kernel/smp.c| 22 ++ 2 files changed, 24 insertions(+) diff --git a/include/linux/smp.h b/include/linux/smp.h index 34347f2..93dff5f 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -100,6 +100,7 @@ int smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, void *info, int wait); void kick_all_cpus_sync(void); +void wake_up_all_idle_cpus(void); /* * Generic and arch helpers @@ -148,6 +149,7 @@ 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) { } #endif /* !SMP */ diff --git a/kernel/smp.c b/kernel/smp.c index aff8aa1..9e0d0b2 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "smpboot.h" @@ -699,3 +700,24 @@ void kick_all_cpus_sync(void) smp_call_function(do_nothing, NULL, 1); } EXPORT_SYMBOL_GPL(kick_all_cpus_sync); + +/** + * wake_up_all_idle_cpus - break all cpus out of idle + * wake_up_all_idle_cpus try to break all cpus which is in idle state even + * including idle polling cpus, for non-idle cpus, we will do nothing + * for them. + */ +void wake_up_all_idle_cpus(void) +{ + int cpu; + + preempt_disable(); + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + + wake_up_if_idle(cpu); + } + preempt_enable(); +} +EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:sched/core] sched: Add new API wake_up_if_idle() to wake up the idle cpu
Commit-ID: f6be8af1c95de4a46e325e728900a70ceadb52cf Gitweb: http://git.kernel.org/tip/f6be8af1c95de4a46e325e728900a70ceadb52cf Author: Chuansheng Liu AuthorDate: Thu, 4 Sep 2014 15:17:53 +0800 Committer: Ingo Molnar CommitDate: Fri, 19 Sep 2014 12:35:14 +0200 sched: Add new API wake_up_if_idle() to wake up the idle cpu Implementing one new API wake_up_if_idle(), which is used to wake up the idle CPU. Suggested-by: Andy Lutomirski Signed-off-by: Chuansheng Liu Signed-off-by: Peter Zijlstra (Intel) Cc: daniel.lezc...@linaro.org Cc: r...@rjwysocki.net Cc: linux...@vger.kernel.org Cc: changcheng@intel.com Cc: xiaoming.w...@intel.com Cc: souvik.k.chakrava...@intel.com Cc: chuansheng@intel.com Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1409815075-4180-1-git-send-email-chuansheng@intel.com Signed-off-by: Ingo Molnar --- include/linux/sched.h | 1 + kernel/sched/core.c | 19 +++ 2 files changed, 20 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index dd9eb48..82ff3d6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1024,6 +1024,7 @@ struct sched_domain_topology_level { extern struct sched_domain_topology_level *sched_domain_topology; extern void set_sched_topology(struct sched_domain_topology_level *tl); +extern void wake_up_if_idle(int cpu); #ifdef CONFIG_SCHED_DEBUG # define SD_INIT_NAME(type).name = #type diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 78e5c83..f7c6ed2 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1634,6 +1634,25 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu) } } +void wake_up_if_idle(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + if (!is_idle_task(rq->curr)) + return; + + if (set_nr_if_polling(rq->idle)) { + trace_sched_wake_idle_without_ipi(cpu); + } else { + raw_spin_lock_irqsave(&rq->lock, flags); + if (is_idle_task(rq->curr)) + smp_send_reschedule(cpu); + /* Else cpu is not in idle, do nothing here */ + raw_spin_unlock_irqrestore(&rq->lock, flags); + } +} + bool cpus_share_cache(int this_cpu, int that_cpu) { return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/3] cpuidle: Using the wake_up_all_idle_cpus() to wake up all idle cpus
Currently kick_all_cpus_sync() or smp_call_function() can not break the polling idle cpu immediately. Here using wake_up_all_idle_cpus() which can wake up the polling idle cpu quickly is much helpful for power. Signed-off-by: Chuansheng Liu --- drivers/cpuidle/cpuidle.c |9 ++--- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index ee9df5e..d31e04c 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -223,7 +223,7 @@ void cpuidle_uninstall_idle_handler(void) { if (enabled_devices) { initialized = 0; - kick_all_cpus_sync(); + wake_up_all_idle_cpus(); } } @@ -530,11 +530,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register); #ifdef CONFIG_SMP -static void smp_callback(void *v) -{ - /* we already woke the CPU up, nothing more to do */ -} - /* * This function gets called when a part of the kernel has a new latency * requirement. This means we need to get all processors out of their C-state, @@ -544,7 +539,7 @@ static void smp_callback(void *v) static int cpuidle_latency_notify(struct notifier_block *b, unsigned long l, void *v) { - smp_call_function(smp_callback, NULL, 1); + wake_up_all_idle_cpus(); return NOTIFY_OK; } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] sched: Add new API wake_up_if_idle() to wake up the idle cpu
Implementing one new API wake_up_if_idle(), which is used to wake up the idle CPU. Suggested-by: Andy Lutomirski Signed-off-by: Chuansheng Liu --- include/linux/sched.h |1 + kernel/sched/core.c | 19 +++ 2 files changed, 20 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index 857ba40..3f89ac1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1024,6 +1024,7 @@ struct sched_domain_topology_level { extern struct sched_domain_topology_level *sched_domain_topology; extern void set_sched_topology(struct sched_domain_topology_level *tl); +extern void wake_up_if_idle(int cpu); #ifdef CONFIG_SCHED_DEBUG # define SD_INIT_NAME(type).name = #type diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1211575..b818548 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1620,6 +1620,25 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu) } } +void wake_up_if_idle(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + if (!is_idle_task(rq->curr)) + return; + + if (set_nr_if_polling(rq->idle)) { + trace_sched_wake_idle_without_ipi(cpu); + } else { + raw_spin_lock_irqsave(&rq->lock, flags); + if (is_idle_task(rq->curr)) + smp_send_reschedule(cpu); + /* Else cpu is not in idle, do nothing here */ + raw_spin_unlock_irqrestore(&rq->lock, flags); + } +} + bool cpus_share_cache(int this_cpu, int that_cpu) { return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] smp: Adding new function wake_up_all_idle_cpus()
Currently kick_all_cpus_sync() can break non-polling idle cpus thru IPI interrupts. But sometimes we need to break the polling idle cpus immediately to reselect the suitable c-state, also for non-idle cpus, we need to do nothing if we try to wake up them. Here adding one new function wake_up_all_idle_cpus() to let all cpus out of idle based on function wake_up_if_idle(). Signed-off-by: Chuansheng Liu --- include/linux/smp.h |2 ++ kernel/smp.c| 22 ++ 2 files changed, 24 insertions(+) diff --git a/include/linux/smp.h b/include/linux/smp.h index 34347f2..93dff5f 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -100,6 +100,7 @@ int smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, void *info, int wait); void kick_all_cpus_sync(void); +void wake_up_all_idle_cpus(void); /* * Generic and arch helpers @@ -148,6 +149,7 @@ 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) { } #endif /* !SMP */ diff --git a/kernel/smp.c b/kernel/smp.c index aff8aa1..9e0d0b2 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "smpboot.h" @@ -699,3 +700,24 @@ void kick_all_cpus_sync(void) smp_call_function(do_nothing, NULL, 1); } EXPORT_SYMBOL_GPL(kick_all_cpus_sync); + +/** + * wake_up_all_idle_cpus - break all cpus out of idle + * wake_up_all_idle_cpus try to break all cpus which is in idle state even + * including idle polling cpus, for non-idle cpus, we will do nothing + * for them. + */ +void wake_up_all_idle_cpus(void) +{ + int cpu; + + preempt_disable(); + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + + wake_up_if_idle(cpu); + } + preempt_enable(); +} +EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ata: Disabling the async PM for JMicron chip 363/361
After enabled the PM feature that supporting async noirq(76569faa62 (PM / sleep: Asynchronous threads for resume_noirq)), Jay hit the system resuming issue, that one of the JMicron controller can not be powered up. His device tree is like below: +-1c.4-[02]--+-00.0 JMicron Technology Corp. JMB363 SATA/IDE Controller |\-00.1 JMicron Technology Corp. JMB363 SATA/IDE Controller After investigation, we found the the Micron chip 363 included one SATA controller(:02:00.0) and one PATA controller(:02:00.1), these two controllers do not have parent-children relationship, but the PATA controller only can be powered on after the SATA controller has finished the powering on. If we enabled the async noirq(), then the below error is hit during noirq phase: pata_jmicron :02:00.1: Refused to change power state, currently in D3 Here for JMicron chip 363/361, we need forcedly to disable the async method. Bug detail: https://bugzilla.kernel.org/show_bug.cgi?id=81551 Reported-by: Jay Signed-off-by: Chuansheng Liu --- drivers/ata/ahci.c | 11 +++ drivers/ata/pata_jmicron.c | 11 +++ 2 files changed, 22 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a29f801..f5634cd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1329,6 +1329,17 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000) ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS; + /* The JMicron chip 361/363 contains one SATA controller and +* one PATA controller,for powering on these both controllers, +* we must follow the sequence one by one, otherwise one of them +* can not be powered on successfully. +* So here we disabled the async suspend method for these chips. + */ + if (pdev->vendor == PCI_VENDOR_ID_JMICRON && + (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 || + pdev->device == PCI_DEVICE_ID_JMICRON_JMB361)) + device_disable_async_suspend(&pdev->dev); + /* acquire resources */ rc = pcim_enable_device(pdev); if (rc) diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 4d1a5d2..6b7aa77 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -143,6 +143,17 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i }; const struct ata_port_info *ppi[] = { &info, NULL }; + /* The JMicron chip 361/363 contains one SATA controller and +* one PATA controller,for powering on these both controllers, +* we must follow the sequence one by one, otherwise one of them +* can not be powered on successfully. +* So here we disabled the async suspend method for these chips. +*/ + if (pdev->vendor == PCI_VENDOR_ID_JMICRON && + (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 || + pdev->device == PCI_DEVICE_ID_JMICRON_JMB361)) + device_disable_async_suspend(&pdev->dev); + return ata_pci_bmdma_init_one(pdev, ppi, &jmicron_sht, NULL, 0); } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] sched: Add new API wake_up_if_idle() to wake up the idle cpu
Implementing one new API wake_up_if_idle(), which is used to wake up the idle CPU. Suggested-by: Andy Lutomirski Signed-off-by: Chuansheng Liu --- include/linux/sched.h |1 + kernel/sched/core.c | 16 2 files changed, 17 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index 857ba40..3f89ac1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1024,6 +1024,7 @@ struct sched_domain_topology_level { extern struct sched_domain_topology_level *sched_domain_topology; extern void set_sched_topology(struct sched_domain_topology_level *tl); +extern void wake_up_if_idle(int cpu); #ifdef CONFIG_SCHED_DEBUG # define SD_INIT_NAME(type).name = #type diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1211575..adf104f 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1620,6 +1620,22 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu) } } +void wake_up_if_idle(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + if (set_nr_if_polling(rq->idle)) { + trace_sched_wake_idle_without_ipi(cpu); + } else { + raw_spin_lock_irqsave(&rq->lock, flags); + if (rq->curr == rq->idle) + smp_send_reschedule(cpu); + /* Else cpu is not in idle, do nothing here */ + raw_spin_unlock_irqrestore(&rq->lock, flags); + } +} + bool cpus_share_cache(int this_cpu, int that_cpu) { return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] smp: Adding new function wake_up_all_cpus()
Currently kick_all_cpus_sync() can break non-polling idle cpus thru IPI interrupts. But sometimes we need to break the polling idle cpus immediately to reselect the suitable c-state, also for non-idle cpus, we need to do nothing if we try to wake up them. Here adding one new function wake_up_all_cpus() to let all cpus out of idle based on function wake_up_if_idle(). Signed-off-by: Chuansheng Liu --- include/linux/smp.h |2 ++ kernel/smp.c| 22 ++ 2 files changed, 24 insertions(+) diff --git a/include/linux/smp.h b/include/linux/smp.h index 34347f2..1cfb1fd 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -100,6 +100,7 @@ int smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, void *info, int wait); void kick_all_cpus_sync(void); +void wake_up_all_cpus(void); /* * Generic and arch helpers @@ -148,6 +149,7 @@ 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_cpus(void) { } #endif /* !SMP */ diff --git a/kernel/smp.c b/kernel/smp.c index aff8aa1..1e69507 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "smpboot.h" @@ -699,3 +700,24 @@ void kick_all_cpus_sync(void) smp_call_function(do_nothing, NULL, 1); } EXPORT_SYMBOL_GPL(kick_all_cpus_sync); + +/** + * wake_up_all_cpus - break all cpus out of idle + * wake_up_all_cpus try to break all cpus which is in idle state even + * including idle polling cpus, for non-idle cpus, we will do nothing + * for them. + */ +void wake_up_all_cpus(void) +{ + int cpu; + + preempt_disable(); + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + + wake_up_if_idle(cpu); + } + preempt_enable(); +} +EXPORT_SYMBOL_GPL(wake_up_all_cpus); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/3] cpuidle: Using the wake_up_all_cpus() to wake up all idle cpus
Currently kick_all_cpus_sync() or smp_call_function() can not break the polling idle cpu immediately. Here using wake_up_all_cpus() which can wake up the polling idle cpu quickly is much helpful for power. Signed-off-by: Chuansheng Liu --- drivers/cpuidle/cpuidle.c |9 ++--- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index ee9df5e..56d5c4d 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -223,7 +223,7 @@ void cpuidle_uninstall_idle_handler(void) { if (enabled_devices) { initialized = 0; - kick_all_cpus_sync(); + wake_up_all_cpus(); } } @@ -530,11 +530,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register); #ifdef CONFIG_SMP -static void smp_callback(void *v) -{ - /* we already woke the CPU up, nothing more to do */ -} - /* * This function gets called when a part of the kernel has a new latency * requirement. This means we need to get all processors out of their C-state, @@ -544,7 +539,7 @@ static void smp_callback(void *v) static int cpuidle_latency_notify(struct notifier_block *b, unsigned long l, void *v) { - smp_call_function(smp_callback, NULL, 1); + wake_up_all_cpus(); return NOTIFY_OK; } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] sched: Add new API wake_up_if_idle() to wake up the idle cpu
Implementing one new API wake_up_if_idle(), which is used to wake up the idle CPU. Suggested-by: Andy Lutomirski Signed-off-by: Chuansheng Liu --- include/linux/sched.h |1 + kernel/sched/core.c | 16 2 files changed, 17 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index 857ba40..3f89ac1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1024,6 +1024,7 @@ struct sched_domain_topology_level { extern struct sched_domain_topology_level *sched_domain_topology; extern void set_sched_topology(struct sched_domain_topology_level *tl); +extern void wake_up_if_idle(int cpu); #ifdef CONFIG_SCHED_DEBUG # define SD_INIT_NAME(type).name = #type diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1211575..adf104f 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1620,6 +1620,22 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu) } } +void wake_up_if_idle(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + if (set_nr_if_polling(rq->idle)) { + trace_sched_wake_idle_without_ipi(cpu); + } else { + raw_spin_lock_irqsave(&rq->lock, flags); + if (rq->curr == rq->idle) + smp_send_reschedule(cpu); + /* Else cpu is not in idle, do nothing here */ + raw_spin_unlock_irqrestore(&rq->lock, flags); + } +} + bool cpus_share_cache(int this_cpu, int that_cpu) { return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] smp: re-implement the kick_all_cpus_sync() with wake_up_if_idle()
Currently using smp_call_function() just woke up the corresponding cpu, but can not break the polling idle loop. Here using the new sched API wake_up_if_idle() to implement it. Signed-off-by: Chuansheng Liu --- kernel/smp.c | 18 +++--- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index aff8aa1..0b647c3 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "smpboot.h" @@ -677,10 +678,6 @@ void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), } EXPORT_SYMBOL(on_each_cpu_cond); -static void do_nothing(void *unused) -{ -} - /** * kick_all_cpus_sync - Force all cpus out of idle * @@ -694,8 +691,15 @@ static void do_nothing(void *unused) */ void kick_all_cpus_sync(void) { - /* Make sure the change is visible before we kick the cpus */ - smp_mb(); - smp_call_function(do_nothing, NULL, 1); + int cpu; + + preempt_disable(); + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + + wake_up_if_idle(cpu); + } + preempt_enable(); } EXPORT_SYMBOL_GPL(kick_all_cpus_sync); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/3] cpuidle: Using the kick_all_cpus_sync() to wake up all cpus
Current latency notify callback has the same function with kick_all_cpus_sync(). Here use it directly to remove the redundant code. Signed-off-by: Chuansheng Liu --- drivers/cpuidle/cpuidle.c |7 +-- 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index ee9df5e..7827375 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -530,11 +530,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register); #ifdef CONFIG_SMP -static void smp_callback(void *v) -{ - /* we already woke the CPU up, nothing more to do */ -} - /* * This function gets called when a part of the kernel has a new latency * requirement. This means we need to get all processors out of their C-state, @@ -544,7 +539,7 @@ static void smp_callback(void *v) static int cpuidle_latency_notify(struct notifier_block *b, unsigned long l, void *v) { - smp_call_function(smp_callback, NULL, 1); + kick_all_cpus_sync(); return NOTIFY_OK; } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] cpuidle: Fix the CPU stuck at C0 for 2-3s after PM_QOS back to DEFAULT
We found sometimes even after we let PM_QOS back to DEFAULT, the CPU still stuck at C0 for 2-3s, don't do the new suitable C-state selection immediately after received the IPI interrupt. The code model is simply like below: { pm_qos_update_request(&pm_qos, C1 - 1); < == Here keep all cores at C0 ...; pm_qos_update_request(&pm_qos, PM_QOS_DEFAULT_VALUE); < == Here some cores still stuck at C0 for 2-3s } The reason is when pm_qos come back to DEFAULT, there is IPI interrupt to wake up the core, but when core is in poll idle state, the IPI interrupt can not break the polling loop. So here in the IPI callback interrupt, when currently the idle task is running, we need to forcedly set reschedule bit to break the polling loop, as for other non-polling idle state, IPI interrupt can break them directly, and setting reschedule bit has no harm for them too. With this fix, we saved about 30mV power in our android platform. Signed-off-by: Chuansheng Liu --- drivers/cpuidle/cpuidle.c |8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index ee9df5e..9e28a13 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -532,7 +532,13 @@ EXPORT_SYMBOL_GPL(cpuidle_register); static void smp_callback(void *v) { - /* we already woke the CPU up, nothing more to do */ + /* we already woke the CPU up, and when the corresponding +* CPU is at polling idle state, we need to set the sched +* bit to trigger reselect the new suitable C-state, it +* will be helpful for power. + */ + if (is_idle_task(current)) + set_tsk_need_resched(current); } /* -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2] usb: gadget: return the right length in ffs_epfile_io()
When the request length is aligned to maxpacketsize, sometimes the return length ret > the user space requested len. At that time, we will use min_t(size_t, ret, len) to limit the size in case of user data buffer overflow. But we need return the min_t(size_t, ret, len) to tell the user space rightly also. Acked-by: Michal Nazarewicz Reviewed-by: David Cohen Signed-off-by: Chuansheng Liu --- drivers/usb/gadget/f_fs.c | 14 -- 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 42f7a0e..780f877 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -845,12 +845,14 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * we may end up with more data then user space has * space for. */ - ret = ep->status; - if (io_data->read && ret > 0 && - unlikely(copy_to_user(io_data->buf, data, - min_t(size_t, ret, - io_data->len - ret = -EFAULT; + ret = ep->status; + if (io_data->read && ret > 0) { + ret = min_t(size_t, ret, io_data->len); + + if (unlikely(copy_to_user(io_data->buf, + data, ret))) + ret = -EFAULT; + } } kfree(data); } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:irq/urgent] genirq: Remove racy waitqueue_active check
Commit-ID: c685689fd24d310343ac33942e9a54a974ae9c43 Gitweb: http://git.kernel.org/tip/c685689fd24d310343ac33942e9a54a974ae9c43 Author: Chuansheng Liu AuthorDate: Mon, 24 Feb 2014 11:29:50 +0800 Committer: Thomas Gleixner CommitDate: Thu, 27 Feb 2014 10:54:16 +0100 genirq: Remove racy waitqueue_active check We hit one rare case below: T1 calling disable_irq(), but hanging at synchronize_irq() always; The corresponding irq thread is in sleeping state; And all CPUs are in idle state; After analysis, we found there is one possible scenerio which causes T1 is waiting there forever: CPU0 CPU1 synchronize_irq() wait_event() spin_lock() atomic_dec_and_test(&threads_active) insert the __wait into queue spin_unlock() if(waitqueue_active) atomic_read(&threads_active) wake_up() Here after inserted the __wait into queue on CPU0, and before test if queue is empty on CPU1, there is no barrier, it maybe cause it is not visible for CPU1 immediately, although CPU0 has updated the queue list. It is similar for CPU0 atomic_read() threads_active also. So we'd need one smp_mb() before waitqueue_active.that, but removing the waitqueue_active() check solves it as wel l and it makes things simple and clear. Signed-off-by: Chuansheng Liu Cc: Xiaoming Wang Link: http://lkml.kernel.org/r/1393212590-32543-1-git-send-email-chuansheng@intel.com Cc: sta...@vger.kernel.org Signed-off-by: Thomas Gleixner --- kernel/irq/manage.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 481a13c..d3bf660 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -802,8 +802,7 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc, static void wake_threads_waitq(struct irq_desc *desc) { - if (atomic_dec_and_test(&desc->threads_active) && - waitqueue_active(&desc->wait_for_threads)) + if (atomic_dec_and_test(&desc->threads_active)) wake_up(&desc->wait_for_threads); } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] usb: gadget: return the right length in ffs_epfile_io()
When the request length is aligned to maxpacketsize, sometimes the return length ret > the user space requested len. At that time, we will use min_t(size_t, ret, len) to limit the size in case of user data buffer overflow. But we need return the min_t(size_t, ret, len) to tell the user space rightly also. Signed-off-by: Chuansheng Liu --- drivers/usb/gadget/f_fs.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 2b43343..31ee7af 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -687,10 +687,12 @@ static ssize_t ffs_epfile_io(struct file *file, * space for. */ ret = ep->status; - if (read && ret > 0 && - unlikely(copy_to_user(buf, data, - min_t(size_t, ret, len - ret = -EFAULT; + if (read && ret > 0) { + ret = min_t(size_t, ret, len); + + if (unlikely(copy_to_user(buf, data, ret))) + ret = -EFAULT; + } } } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] genirq: Fix the possible synchronize_irq() wait-forever
We hit one rare case below: T1 calling disable_irq(), but hanging at synchronize_irq() always; The corresponding irq thread is in sleeping state; And all CPUs are in idle state; After analysis, we found there is one possible scenerio which causes T1 is waiting there forever: CPU0 CPU1 synchronize_irq() wait_event() spin_lock() atomic_dec_and_test(&threads_active) insert the __wait into queue spin_unlock() if(waitqueue_active) atomic_read(&threads_active) wait_up() Here after inserted the __wait into queue on CPU0, and before test if queue is empty on CPU1, there is no barrier, it maybe cause it is not visible for CPU1 immediately, although CPU0 has updated the queue list. It is similar for CPU0 atomic_read() threads_active also. So we need one smp_mb() before waitqueue_active or something like that. Thomas shared one good option that removing waitqueue_active() judgement directly, it will make things to be simple and clear. Cc: Thomas Gleixner Cc: Xiaoming Wang Signed-off-by: Chuansheng Liu --- kernel/irq/manage.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 481a13c..d3bf660 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -802,8 +802,7 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc, static void wake_threads_waitq(struct irq_desc *desc) { - if (atomic_dec_and_test(&desc->threads_active) && - waitqueue_active(&desc->wait_for_threads)) + if (atomic_dec_and_test(&desc->threads_active)) wake_up(&desc->wait_for_threads); } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:irq/core] genirq: Update the a comment typo
Commit-ID: b04c644e670f79417f1728e6be310cfd8e6a921b Gitweb: http://git.kernel.org/tip/b04c644e670f79417f1728e6be310cfd8e6a921b Author: Chuansheng Liu AuthorDate: Mon, 10 Feb 2014 16:13:57 +0800 Committer: Thomas Gleixner CommitDate: Wed, 19 Feb 2014 17:26:34 +0100 genirq: Update the a comment typo Change the comment "chasnge" to "change". Signed-off-by: Chuansheng Liu Link: http://lkml.kernel.org/r/1392020037-5484-2-git-send-email-chuansheng@intel.com Signed-off-by: Thomas Gleixner --- kernel/irq/manage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 54eb5c9..ada0c54 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -757,7 +757,7 @@ out_unlock: #ifdef CONFIG_SMP /* - * Check whether we need to chasnge the affinity of the interrupt thread. + * Check whether we need to change the affinity of the interrupt thread. */ static void irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v4 5/5] PM / sleep: Asynchronous threads for suspend_late
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_late time significantly. This patch is for suspend_late phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 66 ++- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9335b32..42355e4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1127,16 +1127,26 @@ static int dpm_suspend_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_suspend_late(struct device *dev, pm_message_t state) +static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; __pm_runtime_disable(dev, false); + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } + if (dev->power.syscore) - return 0; + goto Complete; + + dpm_wait_for_children(dev, async); if (dev->pm_domain) { info = "late power domain "; @@ -1160,10 +1170,40 @@ static int device_suspend_late(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_late_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_late(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_late(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + put_device(dev); +} + +static int device_suspend_late(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_late, dev); + return 0; + } + + return __device_suspend_late(dev, pm_transition, false); +} + /** * dpm_suspend_late - Execute "late suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1174,19 +1214,20 @@ static int dpm_suspend_late(pm_message_t state) int error = 0; mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_suspended_list)) { struct device *dev = to_device(dpm_suspended_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_late(dev, state); + error = device_suspend_late(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " late", error); - suspend_stats.failed_suspend_late++; - dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1195,17 +1236,18 @@ static int dpm_suspend_late(pm_message_t state) list_move(&dev->power.entry, &dpm_late_early_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (error) { + suspend_stats.failed_suspend_late++; + dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_resume_early(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "late"); - + } return error; } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v4 3/5] PM / sleep: Asynchronous threads for resume_early
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_early time significantly. This patch is for resume_early phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 55 +-- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index ea3f1d2..6d41165 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -595,7 +595,7 @@ static void dpm_resume_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_resume_early(struct device *dev, pm_message_t state) +static int device_resume_early(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -610,6 +610,8 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (!dev->power.is_late_suspended) goto Out; + dpm_wait(dev->parent, async); + if (dev->pm_domain) { info = "early power domain "; callback = pm_late_early_op(&dev->pm_domain->ops, state); @@ -636,38 +638,69 @@ static int device_resume_early(struct device *dev, pm_message_t state) TRACE_RESUME(error); pm_runtime_enable(dev); + complete_all(&dev->power.completion); return error; } +static void async_resume_early(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_early(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_early - Execute "early resume" callbacks for all devices. * @state: PM transition of the system being carried out. */ static void dpm_resume_early(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_late_early_list)) { - struct device *dev = to_device(dpm_late_early_list.next); - int error; + pm_transition = state; + + /* +* Advanced the async threads upfront, +* in case the starting of async threads is +* delayed by non-async resuming devices. +*/ + list_for_each_entry(dev, &dpm_late_early_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_early, dev); + } + } + while (!list_empty(&dpm_late_early_list)) { + dev = to_device(dpm_late_early_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_suspended_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_early(dev, state); - if (error) { - suspend_stats.failed_resume_early++; - dpm_save_failed_step(SUSPEND_RESUME_EARLY); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " early", error); - } + if (!is_async(dev)) { + int error; + error = device_resume_early(dev, state, false); + if (error) { + suspend_stats.failed_resume_early++; + dpm_save_failed_step(SUSPEND_RESUME_EARLY); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " early", error); + } + } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "early"); } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v4 4/5] PM / sleep: Asynchronous threads for suspend_noirq
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_noirq time significantly. This patch is for suspend_noirq phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 68 +++ 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6d41165..9335b32 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -990,14 +990,24 @@ static pm_message_t resume_event(pm_message_t sleep_state) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_suspend_noirq(struct device *dev, pm_message_t state) +static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; + + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } if (dev->power.syscore) - return 0; + goto Complete; + + dpm_wait_for_children(dev, async); if (dev->pm_domain) { info = "noirq power domain "; @@ -1021,10 +1031,40 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_noirq_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_noirq(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + + put_device(dev); +} + +static int device_suspend_noirq(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_noirq, dev); + return 0; + } + return __device_suspend_noirq(dev, pm_transition, false); +} + /** * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1040,19 +1080,20 @@ static int dpm_suspend_noirq(pm_message_t state) cpuidle_pause(); suspend_device_irqs(); mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_late_early_list)) { struct device *dev = to_device(dpm_late_early_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_noirq(dev, state); + error = device_suspend_noirq(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " noirq", error); - suspend_stats.failed_suspend_noirq++; - dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1061,16 +1102,21 @@ static int dpm_suspend_noirq(pm_message_t state) list_move(&dev->power.entry, &dpm_noirq_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (!error) + error = async_error; + + if (error) { + suspend_stats.failed_suspend_noirq++; + dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_resume_noirq(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "noirq"); + } return error; } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v4 1/5] PM / sleep: Two flags for async suspend_noirq and suspend_late
The patch is a helper adding two new flags for implementing async threads for suspend_noirq and suspend_late. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 24 ++-- include/linux/pm.h| 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b41fca..00c53eb 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -91,6 +91,8 @@ void device_pm_sleep_init(struct device *dev) { dev->power.is_prepared = false; dev->power.is_suspended = false; + dev->power.is_noirq_suspended = false; + dev->power.is_late_suspended = false; init_completion(&dev->power.completion); complete_all(&dev->power.completion); dev->power.wakeup = NULL; @@ -479,6 +481,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_noirq_suspended) + goto Out; + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -499,6 +504,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_noirq_suspended = false; Out: TRACE_RESUME(error); @@ -561,6 +567,9 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_late_suspended) + goto Out; + if (dev->pm_domain) { info = "early power domain "; callback = pm_late_early_op(&dev->pm_domain->ops, state); @@ -581,6 +590,7 @@ static int device_resume_early(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_late_suspended = false; Out: TRACE_RESUME(error); @@ -917,6 +927,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; if (dev->power.syscore) return 0; @@ -940,7 +951,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) callback = pm_noirq_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_noirq_suspended = true; + + return error; } /** @@ -1003,6 +1018,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; __pm_runtime_disable(dev, false); @@ -1028,7 +1044,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state) callback = pm_late_early_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_late_suspended = true; + + return error; } /** diff --git a/include/linux/pm.h b/include/linux/pm.h index 8c6583a..f23a4f1 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -542,6 +542,8 @@ struct dev_pm_info { unsigned intasync_suspend:1; boolis_prepared:1; /* Owned by the PM core */ boolis_suspended:1; /* Ditto */ + boolis_noirq_suspended:1; + boolis_late_suspended:1; boolignore_children:1; boolearly_init:1; /* Owned by the PM core */ spinlock_t lock; -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v4 2/5] PM / sleep: Asynchronous threads for resume_noirq
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_noirq time significantly. One typical case is: In resume_noirq phase and for the PCI devices, the function pci_pm_resume_noirq() will be called, and there is one d3_delay (10ms) at least. With the way of asynchronous threads, we just need wait d3_delay time once in parallel for each calling, which saves much time to resume quickly. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 66 +++ 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 00c53eb..ea3f1d2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -469,7 +469,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_resume_noirq(struct device *dev, pm_message_t state) +static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -484,6 +484,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (!dev->power.is_noirq_suspended) goto Out; + dpm_wait(dev->parent, async); + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -507,10 +509,29 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) dev->power.is_noirq_suspended = false; Out: + complete_all(&dev->power.completion); TRACE_RESUME(error); return error; } +static bool is_async(struct device *dev) +{ + return dev->power.async_suspend && pm_async_enabled + && !pm_trace_is_enabled(); +} + +static void async_resume_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_noirq(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -520,29 +541,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) */ static void dpm_resume_noirq(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_noirq_list)) { - struct device *dev = to_device(dpm_noirq_list.next); - int error; + pm_transition = state; + + /* +* Advanced the async threads upfront, +* in case the starting of async threads is +* delayed by non-async resuming devices. +*/ + list_for_each_entry(dev, &dpm_noirq_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_noirq, dev); + } + } + while (!list_empty(&dpm_noirq_list)) { + dev = to_device(dpm_noirq_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); - if (error) { - suspend_stats.failed_resume_noirq++; - dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " noirq", error); + if (!is_async(dev)) { + int error; + + error = device_resume_noirq(dev, state, false); + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " noirq", error); + } } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); cpuidle_resume(); @@ -742,12 +782,6 @@ static void async_resume(void *data, async_cookie_t cookie) put_device(dev); } -static bool is_async(struct device *dev) -{ - return de
[PATCH v4 0/5] Enabling the asynchronous threads for other phases
Hello, This patch series are for enabling the asynchronous threads for the phases resume_noirq, resume_early, suspend_noirq and suspend_late. Just like commit 5af84b82701a and 97df8c12995, with async threads it will reduce the system suspending and resuming time significantly. With these patches, in my test platform, it saved 80% time in resume_noirq phase. Best Regards, --- V2: -- Based on Rafael's minor changes related to coding style, white space etc; -- Rafael pointed out the v1 series break the device parent-children suspending/resuming order when enabling asyncing, here using the dev completion to sync parent-children order; V3: -- In patch v2 5/5, there is one missing "dpm_wait_for_children"; V4: -- Rafael pointed out that dpm_wait_for_children()/dpm_wait() should be put after some simple returning statement; --- [PATCH v4 1/5] PM / sleep: Two flags for async suspend_noirq and [PATCH v4 2/5] PM / sleep: Asynchronous threads for resume_noirq [PATCH v4 3/5] PM / sleep: Asynchronous threads for resume_early [PATCH v4 4/5] PM / sleep: Asynchronous threads for suspend_noirq [PATCH v4 5/5] PM / sleep: Asynchronous threads for suspend_late drivers/base/power/main.c | 275 ++ include/linux/pm.h| 2 ++ 2 files changed, 227 insertions(+), 50 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v3 2/5] PM / sleep: Asynchronous threads for resume_noirq
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_noirq time significantly. One typical case is: In resume_noirq phase and for the PCI devices, the function pci_pm_resume_noirq() will be called, and there is one d3_delay (10ms) at least. With the way of asynchronous threads, we just need wait d3_delay time once in parallel for each calling, which saves much time to resume quickly. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 66 +++ 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 00c53eb..89172aa 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -469,7 +469,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_resume_noirq(struct device *dev, pm_message_t state) +static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -481,6 +481,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + dpm_wait(dev->parent, async); + if (!dev->power.is_noirq_suspended) goto Out; @@ -507,10 +509,29 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) dev->power.is_noirq_suspended = false; Out: + complete_all(&dev->power.completion); TRACE_RESUME(error); return error; } +static bool is_async(struct device *dev) +{ + return dev->power.async_suspend && pm_async_enabled + && !pm_trace_is_enabled(); +} + +static void async_resume_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_noirq(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -520,29 +541,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) */ static void dpm_resume_noirq(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_noirq_list)) { - struct device *dev = to_device(dpm_noirq_list.next); - int error; + pm_transition = state; + + /* +* Advanced the async threads upfront, +* in case the starting of async threads is +* delayed by non-async resuming devices. +*/ + list_for_each_entry(dev, &dpm_noirq_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_noirq, dev); + } + } + while (!list_empty(&dpm_noirq_list)) { + dev = to_device(dpm_noirq_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); - if (error) { - suspend_stats.failed_resume_noirq++; - dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " noirq", error); + if (!is_async(dev)) { + int error; + + error = device_resume_noirq(dev, state, false); + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " noirq", error); + } } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); cpuidle_resume(); @@ -742,12 +782,6 @@ static void async_resume(void *data, async_cookie_t cookie) put_device(dev); } -static bool is_async(struct device *dev) -{ - return dev->power.async_suspend && pm_async_enabled - && !pm_trace_is_enabled(); -}
[PATCH v3 5/5] PM / sleep: Asynchronous threads for suspend_late
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_late time significantly. This patch is for suspend_late phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 66 ++- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 72b4c9c..c031050 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1127,16 +1127,26 @@ static int dpm_suspend_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_suspend_late(struct device *dev, pm_message_t state) +static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; + + dpm_wait_for_children(dev, async); __pm_runtime_disable(dev, false); + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } + if (dev->power.syscore) - return 0; + goto Complete; if (dev->pm_domain) { info = "late power domain "; @@ -1160,10 +1170,40 @@ static int device_suspend_late(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_late_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_late(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_late(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + put_device(dev); +} + +static int device_suspend_late(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_late, dev); + return 0; + } + + return __device_suspend_late(dev, pm_transition, false); +} + /** * dpm_suspend_late - Execute "late suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1174,19 +1214,20 @@ static int dpm_suspend_late(pm_message_t state) int error = 0; mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_suspended_list)) { struct device *dev = to_device(dpm_suspended_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_late(dev, state); + error = device_suspend_late(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " late", error); - suspend_stats.failed_suspend_late++; - dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1195,17 +1236,18 @@ static int dpm_suspend_late(pm_message_t state) list_move(&dev->power.entry, &dpm_late_early_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (error) { + suspend_stats.failed_suspend_late++; + dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_resume_early(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "late"); - + } return error; } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v3 3/5] PM / sleep: Asynchronous threads for resume_early
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_early time significantly. This patch is for resume_early phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 55 +-- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 89172aa..2f2d110 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -595,7 +595,7 @@ static void dpm_resume_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_resume_early(struct device *dev, pm_message_t state) +static int device_resume_early(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -607,6 +607,8 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + dpm_wait(dev->parent, async); + if (!dev->power.is_late_suspended) goto Out; @@ -636,38 +638,69 @@ static int device_resume_early(struct device *dev, pm_message_t state) TRACE_RESUME(error); pm_runtime_enable(dev); + complete_all(&dev->power.completion); return error; } +static void async_resume_early(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_early(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_early - Execute "early resume" callbacks for all devices. * @state: PM transition of the system being carried out. */ static void dpm_resume_early(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_late_early_list)) { - struct device *dev = to_device(dpm_late_early_list.next); - int error; + pm_transition = state; + + /* +* Advanced the async threads upfront, +* in case the starting of async threads is +* delayed by non-async resuming devices. +*/ + list_for_each_entry(dev, &dpm_late_early_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_early, dev); + } + } + while (!list_empty(&dpm_late_early_list)) { + dev = to_device(dpm_late_early_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_suspended_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_early(dev, state); - if (error) { - suspend_stats.failed_resume_early++; - dpm_save_failed_step(SUSPEND_RESUME_EARLY); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " early", error); - } + if (!is_async(dev)) { + int error; + error = device_resume_early(dev, state, false); + if (error) { + suspend_stats.failed_resume_early++; + dpm_save_failed_step(SUSPEND_RESUME_EARLY); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " early", error); + } + } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "early"); } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v3 1/5] PM / sleep: Two flags for async suspend_noirq and suspend_late
The patch is a helper adding two new flags for implementing async threads for suspend_noirq and suspend_late. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 24 ++-- include/linux/pm.h| 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b41fca..00c53eb 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -91,6 +91,8 @@ void device_pm_sleep_init(struct device *dev) { dev->power.is_prepared = false; dev->power.is_suspended = false; + dev->power.is_noirq_suspended = false; + dev->power.is_late_suspended = false; init_completion(&dev->power.completion); complete_all(&dev->power.completion); dev->power.wakeup = NULL; @@ -479,6 +481,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_noirq_suspended) + goto Out; + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -499,6 +504,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_noirq_suspended = false; Out: TRACE_RESUME(error); @@ -561,6 +567,9 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_late_suspended) + goto Out; + if (dev->pm_domain) { info = "early power domain "; callback = pm_late_early_op(&dev->pm_domain->ops, state); @@ -581,6 +590,7 @@ static int device_resume_early(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_late_suspended = false; Out: TRACE_RESUME(error); @@ -917,6 +927,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; if (dev->power.syscore) return 0; @@ -940,7 +951,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) callback = pm_noirq_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_noirq_suspended = true; + + return error; } /** @@ -1003,6 +1018,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; __pm_runtime_disable(dev, false); @@ -1028,7 +1044,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state) callback = pm_late_early_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_late_suspended = true; + + return error; } /** diff --git a/include/linux/pm.h b/include/linux/pm.h index 8c6583a..f23a4f1 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -542,6 +542,8 @@ struct dev_pm_info { unsigned intasync_suspend:1; boolis_prepared:1; /* Owned by the PM core */ boolis_suspended:1; /* Ditto */ + boolis_noirq_suspended:1; + boolis_late_suspended:1; boolignore_children:1; boolearly_init:1; /* Owned by the PM core */ spinlock_t lock; -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v3 4/5] PM / sleep: Asynchronous threads for suspend_noirq
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_noirq time significantly. This patch is for suspend_noirq phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 68 +++ 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2f2d110..72b4c9c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -990,14 +990,24 @@ static pm_message_t resume_event(pm_message_t sleep_state) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_suspend_noirq(struct device *dev, pm_message_t state) +static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; + + dpm_wait_for_children(dev, async); + + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } if (dev->power.syscore) - return 0; + goto Complete; if (dev->pm_domain) { info = "noirq power domain "; @@ -1021,10 +1031,40 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_noirq_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_noirq(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + + put_device(dev); +} + +static int device_suspend_noirq(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_noirq, dev); + return 0; + } + return __device_suspend_noirq(dev, pm_transition, false); +} + /** * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1040,19 +1080,20 @@ static int dpm_suspend_noirq(pm_message_t state) cpuidle_pause(); suspend_device_irqs(); mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_late_early_list)) { struct device *dev = to_device(dpm_late_early_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_noirq(dev, state); + error = device_suspend_noirq(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " noirq", error); - suspend_stats.failed_suspend_noirq++; - dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1061,16 +1102,21 @@ static int dpm_suspend_noirq(pm_message_t state) list_move(&dev->power.entry, &dpm_noirq_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (!error) + error = async_error; + + if (error) { + suspend_stats.failed_suspend_noirq++; + dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_resume_noirq(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "noirq"); + } return error; } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v3 0/5] Enabling the asynchronous threads for other phases
Hello, This patch series are for enabling the asynchronous threads for the phases resume_noirq, resume_early, suspend_noirq and suspend_late. Just like commit 5af84b82701a and 97df8c12995, with async threads it will reduce the system suspending and resuming time significantly. With these patches, in my test platform, it saved 80% time in resume_noirq phase. Best Regards, --- V2: -- Based on Rafael's minor changes related to coding style, white space etc; -- Rafael pointed out the v1 series break the device parent-children suspending/resuming order when enabling asyncing, here using the dev completion to sync parent-children order; V3: -- In patch v2 5/5, there is one missing "dpm_wait_for_children"; --- [PATCH v3 1/5] PM / sleep: Two flags for async suspend_noirq and [PATCH v3 2/5] PM / sleep: Asynchronous threads for resume_noirq [PATCH v3 3/5] PM / sleep: Asynchronous threads for resume_early [PATCH v3 4/5] PM / sleep: Asynchronous threads for suspend_noirq [PATCH v3 5/5] PM / sleep: Asynchronous threads for suspend_late drivers/base/power/main.c | 275 ++ include/linux/pm.h| 2 ++ 2 files changed, 227 insertions(+), 50 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2 5/5] PM / sleep: Asynchronous threads for suspend_late
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_late time significantly. This patch is for suspend_late phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 64 ++- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 72b4c9c..0c5fad0 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1127,16 +1127,24 @@ static int dpm_suspend_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_suspend_late(struct device *dev, pm_message_t state) +static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; __pm_runtime_disable(dev, false); + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } + if (dev->power.syscore) - return 0; + goto Complete; if (dev->pm_domain) { info = "late power domain "; @@ -1160,10 +1168,40 @@ static int device_suspend_late(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_late_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_late(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_late(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + put_device(dev); +} + +static int device_suspend_late(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_late, dev); + return 0; + } + + return __device_suspend_late(dev, pm_transition, false); +} + /** * dpm_suspend_late - Execute "late suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1174,19 +1212,20 @@ static int dpm_suspend_late(pm_message_t state) int error = 0; mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_suspended_list)) { struct device *dev = to_device(dpm_suspended_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_late(dev, state); + error = device_suspend_late(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " late", error); - suspend_stats.failed_suspend_late++; - dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1195,17 +1234,18 @@ static int dpm_suspend_late(pm_message_t state) list_move(&dev->power.entry, &dpm_late_early_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (error) { + suspend_stats.failed_suspend_late++; + dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_resume_early(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "late"); - + } return error; } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2 4/5] PM / sleep: Asynchronous threads for suspend_noirq
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_noirq time significantly. This patch is for suspend_noirq phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 68 +++ 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2f2d110..72b4c9c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -990,14 +990,24 @@ static pm_message_t resume_event(pm_message_t sleep_state) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_suspend_noirq(struct device *dev, pm_message_t state) +static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; + + dpm_wait_for_children(dev, async); + + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } if (dev->power.syscore) - return 0; + goto Complete; if (dev->pm_domain) { info = "noirq power domain "; @@ -1021,10 +1031,40 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_noirq_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_noirq(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + + put_device(dev); +} + +static int device_suspend_noirq(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_noirq, dev); + return 0; + } + return __device_suspend_noirq(dev, pm_transition, false); +} + /** * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1040,19 +1080,20 @@ static int dpm_suspend_noirq(pm_message_t state) cpuidle_pause(); suspend_device_irqs(); mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_late_early_list)) { struct device *dev = to_device(dpm_late_early_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_noirq(dev, state); + error = device_suspend_noirq(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " noirq", error); - suspend_stats.failed_suspend_noirq++; - dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1061,16 +1102,21 @@ static int dpm_suspend_noirq(pm_message_t state) list_move(&dev->power.entry, &dpm_noirq_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (!error) + error = async_error; + + if (error) { + suspend_stats.failed_suspend_noirq++; + dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_resume_noirq(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "noirq"); + } return error; } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2 3/5] PM / sleep: Asynchronous threads for resume_early
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_early time significantly. This patch is for resume_early phase. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 55 +-- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 89172aa..2f2d110 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -595,7 +595,7 @@ static void dpm_resume_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_resume_early(struct device *dev, pm_message_t state) +static int device_resume_early(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -607,6 +607,8 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + dpm_wait(dev->parent, async); + if (!dev->power.is_late_suspended) goto Out; @@ -636,38 +638,69 @@ static int device_resume_early(struct device *dev, pm_message_t state) TRACE_RESUME(error); pm_runtime_enable(dev); + complete_all(&dev->power.completion); return error; } +static void async_resume_early(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_early(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_early - Execute "early resume" callbacks for all devices. * @state: PM transition of the system being carried out. */ static void dpm_resume_early(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_late_early_list)) { - struct device *dev = to_device(dpm_late_early_list.next); - int error; + pm_transition = state; + + /* +* Advanced the async threads upfront, +* in case the starting of async threads is +* delayed by non-async resuming devices. +*/ + list_for_each_entry(dev, &dpm_late_early_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_early, dev); + } + } + while (!list_empty(&dpm_late_early_list)) { + dev = to_device(dpm_late_early_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_suspended_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_early(dev, state); - if (error) { - suspend_stats.failed_resume_early++; - dpm_save_failed_step(SUSPEND_RESUME_EARLY); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " early", error); - } + if (!is_async(dev)) { + int error; + error = device_resume_early(dev, state, false); + if (error) { + suspend_stats.failed_resume_early++; + dpm_save_failed_step(SUSPEND_RESUME_EARLY); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " early", error); + } + } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "early"); } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2 2/5] PM / sleep: Asynchronous threads for resume_noirq
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_noirq time significantly. One typical case is: In resume_noirq phase and for the PCI devices, the function pci_pm_resume_noirq() will be called, and there is one d3_delay (10ms) at least. With the way of asynchronous threads, we just need wait d3_delay time once in parallel for each calling, which saves much time to resume quickly. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 66 +++ 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 00c53eb..89172aa 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -469,7 +469,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_resume_noirq(struct device *dev, pm_message_t state) +static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -481,6 +481,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + dpm_wait(dev->parent, async); + if (!dev->power.is_noirq_suspended) goto Out; @@ -507,10 +509,29 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) dev->power.is_noirq_suspended = false; Out: + complete_all(&dev->power.completion); TRACE_RESUME(error); return error; } +static bool is_async(struct device *dev) +{ + return dev->power.async_suspend && pm_async_enabled + && !pm_trace_is_enabled(); +} + +static void async_resume_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_noirq(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -520,29 +541,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) */ static void dpm_resume_noirq(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_noirq_list)) { - struct device *dev = to_device(dpm_noirq_list.next); - int error; + pm_transition = state; + + /* +* Advanced the async threads upfront, +* in case the starting of async threads is +* delayed by non-async resuming devices. +*/ + list_for_each_entry(dev, &dpm_noirq_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_noirq, dev); + } + } + while (!list_empty(&dpm_noirq_list)) { + dev = to_device(dpm_noirq_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); - if (error) { - suspend_stats.failed_resume_noirq++; - dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " noirq", error); + if (!is_async(dev)) { + int error; + + error = device_resume_noirq(dev, state, false); + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " noirq", error); + } } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); cpuidle_resume(); @@ -742,12 +782,6 @@ static void async_resume(void *data, async_cookie_t cookie) put_device(dev); } -static bool is_async(struct device *dev) -{ - return dev->power.async_suspend && pm_async_enabled - && !pm_trace_is_enabled(); -}
[PATCH v2 1/5] PM / sleep: Two flags for async suspend_noirq and suspend_late
The patch is a helper adding two new flags for implementing async threads for suspend_noirq and suspend_late. Signed-off-by: Chuansheng Liu --- drivers/base/power/main.c | 24 ++-- include/linux/pm.h| 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b41fca..00c53eb 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -91,6 +91,8 @@ void device_pm_sleep_init(struct device *dev) { dev->power.is_prepared = false; dev->power.is_suspended = false; + dev->power.is_noirq_suspended = false; + dev->power.is_late_suspended = false; init_completion(&dev->power.completion); complete_all(&dev->power.completion); dev->power.wakeup = NULL; @@ -479,6 +481,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_noirq_suspended) + goto Out; + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -499,6 +504,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_noirq_suspended = false; Out: TRACE_RESUME(error); @@ -561,6 +567,9 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_late_suspended) + goto Out; + if (dev->pm_domain) { info = "early power domain "; callback = pm_late_early_op(&dev->pm_domain->ops, state); @@ -581,6 +590,7 @@ static int device_resume_early(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_late_suspended = false; Out: TRACE_RESUME(error); @@ -917,6 +927,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; if (dev->power.syscore) return 0; @@ -940,7 +951,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) callback = pm_noirq_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_noirq_suspended = true; + + return error; } /** @@ -1003,6 +1018,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; __pm_runtime_disable(dev, false); @@ -1028,7 +1044,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state) callback = pm_late_early_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_late_suspended = true; + + return error; } /** diff --git a/include/linux/pm.h b/include/linux/pm.h index 8c6583a..f23a4f1 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -542,6 +542,8 @@ struct dev_pm_info { unsigned intasync_suspend:1; boolis_prepared:1; /* Owned by the PM core */ boolis_suspended:1; /* Ditto */ + boolis_noirq_suspended:1; + boolis_late_suspended:1; boolignore_children:1; boolearly_init:1; /* Owned by the PM core */ spinlock_t lock; -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2 0/5] Enabling the asynchronous threads for other phases
Hello, This patch series are for enabling the asynchronous threads for the phases resume_noirq, resume_early, suspend_noirq and suspend_late. Just like commit 5af84b82701a and 97df8c12995, with async threads it will reduce the system suspending and resuming time significantly. With these patches, in my test platform, it saved 80% time in resume_noirq phase. Best Regards, --- V2: -- Based on Rafael's minor changes related to coding style, white space etc; -- Rafael pointed out the v1 series break the device parent-children suspending/resuming order when enabling asyncing, here using the dev completion to sync parent-children order; --- [PATCH 1/5] PM / sleep: Two flags for async suspend_noirq and [PATCH 2/5] PM / sleep: Asynchronous threads for resume_noirq [PATCH 3/5] PM / sleep: Asynchronous threads for resume_early [PATCH 4/5] PM / sleep: Asynchronous threads for suspend_noirq [PATCH 5/5] PM / sleep: Asynchronous threads for suspend_late drivers/base/power/main.c | 273 ++ include/linux/pm.h| 2 ++ 2 files changed, 225 insertions(+), 50 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/2] genirq: Fix the possible synchronize_irq() wait-forever
There is below race between irq handler and irq thread: irq handler irq thread irq_wake_thread() irq_thread() set bit RUNTHREAD ...clear bit RUNTHREAD thread_fn() [A]test_and_decrease thread_active [B]increase thread_active If action A is before action B, after that the thread_active will be always > 0, and for synchronize_irq() calling, which will be waiting there forever. Here put the increasing thread-active before setting bit RUNTHREAD, which can resolve such race. Signed-off-by: xiaoming wang Signed-off-by: Chuansheng Liu --- kernel/irq/handle.c | 21 - 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 131ca17..5f9fbb7 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -65,7 +65,7 @@ static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action) * Wake up the handler thread for this action. If the * RUNTHREAD bit is already set, nothing to do. */ - if (test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags)) + if (test_bit(IRQTF_RUNTHREAD, &action->thread_flags)) return; /* @@ -126,6 +126,25 @@ static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action) */ atomic_inc(&desc->threads_active); + /* +* set the RUNTHREAD bit after increasing the threads_active, +* it can avoid the below race: +* irq handler irq thread in case it is in +*running state +* +* set RUNTHREAD bit +* clear the RUNTHREAD bit +*... thread_fn() +* +* due to threads_active==0, +* no waking up wait_for_threads +* +* threads_active ++ +* After that, the threads_active will be always > 0, which +* will block the synchronize_irq(). +*/ + set_bit(IRQTF_RUNTHREAD, &action->thread_flags); + wake_up_process(action->thread); } -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/2] genirq: Fix one typo chasnge
Change the comment "chasnge" to "change". Signed-off-by: Chuansheng Liu --- kernel/irq/manage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 481a13c..4802295 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -727,7 +727,7 @@ out_unlock: #ifdef CONFIG_SMP /* - * Check whether we need to chasnge the affinity of the interrupt thread. + * Check whether we need to change the affinity of the interrupt thread. */ static void irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) -- 1.9.rc0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] PM: Enable asynchronous threads for suspend/resume_noirq/late/early phases
Current code has implemented asynchronous threads for dpm_suspend() and dpm_resume(), which saved much time. As commit 5af84b82701a and 97df8c12995 said, the total time can be reduced significantly by running suspend and resume callbacks of device drivers in parallel with each other. For the suspend_late/suspend_noirq/resume_noirq/resume_early phases, sometimes they often taken much time without asynchronous threads, following the idea of the above commits, implemented it with async threads too. One example below for my test platform: Without this patch: [ 1411.272218] PM: noirq resume of devices complete after 92.223 msecs with this patch: [ 110.616735] PM: noirq resume of devices complete after 10.544 msecs Normally 80% time is saved, which is helpful for the user experience specially for mobile platform. Signed-off-by: Liu, Chuansheng --- drivers/base/power/main.c | 189 +++-- include/linux/pm.h|2 + 2 files changed, 166 insertions(+), 25 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6a33dd8..62648b2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -72,6 +72,8 @@ void device_pm_sleep_init(struct device *dev) { dev->power.is_prepared = false; dev->power.is_suspended = false; + dev->power.is_late_suspended = false; + dev->power.is_noirq_suspended = false; init_completion(&dev->power.completion); complete_all(&dev->power.completion); dev->power.wakeup = NULL; @@ -452,7 +454,7 @@ static void dpm_wd_clear(struct dpm_watchdog *wd) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_resume_noirq(struct device *dev, pm_message_t state) +static int __device_resume_noirq(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; @@ -464,6 +466,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_noirq_suspended) + goto Out; + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -484,12 +489,41 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_noirq_suspended = false; Out: TRACE_RESUME(error); return error; } +static bool is_async(struct device *dev) +{ + return dev->power.async_suspend && pm_async_enabled + && !pm_trace_is_enabled(); +} + +static void async_resume_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_resume_noirq(dev, pm_transition); + if (error) + pm_dev_err(dev, pm_transition, " noirq", error); + put_device(dev); +} + +static int device_resume_noirq(struct device *dev) +{ + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_noirq, dev); + return 0; + } + + return __device_resume_noirq(dev, pm_transition); +} + /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -500,6 +534,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) static void dpm_resume_noirq(pm_message_t state) { ktime_t starttime = ktime_get(); + pm_transition = state; mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_noirq_list)) { @@ -510,18 +545,18 @@ static void dpm_resume_noirq(pm_message_t state) list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); + error = device_resume_noirq(dev); if (error) { suspend_stats.failed_resume_noirq++; dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); dpm_save_failed_dev(dev_name(dev)); pm_dev_err(dev, state, " noirq", error); } - mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); cpuidle_resume(); @@ -534,7 +569,7 @@ static void dpm_resume_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_resume_early(struct device *dev, pm_message_t state) +static int __device_resume_early(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *in
[PATCH] PM: Enable asynchronous noirq resume threads to save the resuming time
Currently, the dpm_resume_noirq() is done synchronously, and for PCI devices pci_pm_resume_noirq(): pci_pm_resume_noirq() pci_pm_default_resume_early() pci_power_up() pci_raw_set_power_state() Which set the device from D3hot to D0 mostly, for every device, there will be one 10ms(pci_pm_d3_delay) to wait. Hence normally dpm_resume_noirq() will cost > 100ms, which is bigger for mobile platform. Here implementing it with asynchronous way which will reduce much. For example below, The 80% time is saved. With synchronous way: [ 1411.272218] PM: noirq resume of devices complete after 92.223 msecs With asynchronous way: [ 110.616735] PM: noirq resume of devices complete after 10.544 msecs Signed-off-by: Liu, Chuansheng --- drivers/base/power/main.c | 42 +- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b41fca..1b9d774 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -505,6 +505,19 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) return error; } +static bool is_async(struct device *dev); + +static void async_resume_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_noirq(dev, pm_transition); + if (error) + pm_dev_err(dev, pm_transition, " noirq", error); + put_device(dev); +} + /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -514,29 +527,40 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) */ static void dpm_resume_noirq(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); + pm_transition = state; + + list_for_each_entry(dev, &dpm_noirq_list, power.entry) { + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_noirq, dev); + } + } mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_noirq_list)) { - struct device *dev = to_device(dpm_noirq_list.next); - int error; + dev = to_device(dpm_noirq_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); - if (error) { - suspend_stats.failed_resume_noirq++; - dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " noirq", error); + if (!is_async(dev)) { + int error; + error = device_resume_noirq(dev, state); + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " noirq", error); + } } - mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); cpuidle_resume(); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/3] dm snapshot: Calling destroy_work_on_stack() to pair with INIT_WORK_ONSTACK()
In case CONFIG_DEBUG_OBJECTS_WORK is defined, it is needed to call destroy_work_on_stack() which frees the debug object to pair with INIT_WORK_ONSTACK(). Signed-off-by: Liu, Chuansheng --- drivers/md/dm-snap-persistent.c |1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 2d2b1b7..2f5a9f8 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -257,6 +257,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw, INIT_WORK_ONSTACK(&req.work, do_metadata); queue_work(ps->metadata_wq, &req.work); flush_workqueue(ps->metadata_wq); + destroy_work_on_stack(&req.work); return req.result; } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] workqueue: Calling destroy_work_on_stack() to pair with INIT_WORK_ONSTACK()
In case CONFIG_DEBUG_OBJECTS_WORK is defined, it is needed to call destroy_work_on_stack() which frees the debug object to pair with INIT_WORK_ONSTACK(). Signed-off-by: Liu, Chuansheng --- kernel/workqueue.c |2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index b010eac..82ef9f3 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4789,6 +4789,7 @@ static int workqueue_cpu_down_callback(struct notifier_block *nfb, /* wait for per-cpu unbinding to finish */ flush_work(&unbind_work); + destroy_work_on_stack(&unbind_work); break; } return NOTIFY_OK; @@ -4828,6 +4829,7 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg) INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn); schedule_work_on(cpu, &wfc.work); flush_work(&wfc.work); + destroy_work_on_stack(&wfc.work); return wfc.ret; } EXPORT_SYMBOL_GPL(work_on_cpu); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] xfs: Calling destroy_work_on_stack() to pair with INIT_WORK_ONSTACK()
In case CONFIG_DEBUG_OBJECTS_WORK is defined, it is needed to call destroy_work_on_stack() which frees the debug object to pair with INIT_WORK_ONSTACK(). Signed-off-by: Liu, Chuansheng --- fs/xfs/xfs_bmap_util.c |1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 1394106..82e0dab 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -287,6 +287,7 @@ xfs_bmapi_allocate( INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker); queue_work(xfs_alloc_wq, &args->work); wait_for_completion(&done); + destroy_work_on_stack(&args->work); return args->result; } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:core/locking] mutexes: Give more informative mutex warning in the !lock->owner case
Commit-ID: 91f30a17024ff0d8345e11228af33ee938b13426 Gitweb: http://git.kernel.org/tip/91f30a17024ff0d8345e11228af33ee938b13426 Author: Chuansheng Liu AuthorDate: Wed, 4 Dec 2013 13:58:13 +0800 Committer: Ingo Molnar CommitDate: Tue, 17 Dec 2013 15:35:10 +0100 mutexes: Give more informative mutex warning in the !lock->owner case When mutex debugging is enabled and an imbalanced mutex_unlock() is called, we get the following, slightly confusing warning: [ 364.208284] DEBUG_LOCKS_WARN_ON(lock->owner != current) But in that case the warning is due to an imbalanced mutex_unlock() call, and the lock->owner is NULL - so the message is misleading. So improve the message by testing for this case specifically: DEBUG_LOCKS_WARN_ON(!lock->owner) Signed-off-by: Liu, Chuansheng Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Cc: Thomas Gleixner Cc: Paul E. McKenney Link: http://lkml.kernel.org/r/1386136693.3650.48.camel@cliu38-desktop-build [ Improved the changelog, changed the patch to use !lock->owner consistently. ] Signed-off-by: Ingo Molnar --- kernel/locking/mutex-debug.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c index 7e3443f..faf6f5b 100644 --- a/kernel/locking/mutex-debug.c +++ b/kernel/locking/mutex-debug.c @@ -75,7 +75,12 @@ void debug_mutex_unlock(struct mutex *lock) return; DEBUG_LOCKS_WARN_ON(lock->magic != lock); - DEBUG_LOCKS_WARN_ON(lock->owner != current); + + if (!lock->owner) + DEBUG_LOCKS_WARN_ON(!lock->owner); + else + DEBUG_LOCKS_WARN_ON(lock->owner != current); + DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); mutex_clear_owner(lock); } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
tty: Removing the deprecated function tty_vhangup_locked()
The function tty_vhangup_locked() was deprecated, removed it from the tty.h also. Signed-off-by: Liu, Chuansheng --- include/linux/tty.h |1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 97d660e..a98c85f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -422,7 +422,6 @@ extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); extern void tty_hangup(struct tty_struct *tty); extern void tty_vhangup(struct tty_struct *tty); -extern void tty_vhangup_locked(struct tty_struct *tty); extern void tty_unhangup(struct file *filp); extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
TTY/n_gsm: Removing the wrong tty_unlock/lock() in gsm_dlci_release()
Commit 4d9b109060f690f5c835(tty: Prevent deadlock in n_gsm driver) tried to close all the virtual ports synchronously before closing the phycial ports, so the tty_vhangup() is used. But the tty_unlock/lock() is wrong: tty_release tty_ldisc_release tty_lock_pair(tty, o_tty) < == Here the tty is for physical port tty_ldisc_kill gsmld_close gsm_cleanup_mux gsm_dlci_release tty = tty_port_tty_get(&dlci->port) < == Here the tty(s) are for virtual port They are different ttys, so before tty_vhangup(virtual tty), do not need to call the tty_unlock(virtual tty) at all which causes unbalanced unlock warning. When enabling mutex debugging option, we will hit the below warning also: [ 99.276903] = [ 99.282172] [ BUG: bad unlock balance detected! ] [ 99.287442] 3.10.20-261976-gaec5ba0 #44 Tainted: G O [ 99.293972] - [ 99.299240] mmgr/152 is trying to release lock (&tty->legacy_mutex) at: [ 99.306693] [] mutex_unlock+0xd/0x10 [ 99.311669] but there are no more locks to release! [ 99.317131] [ 99.317131] other info that might help us debug this: [ 99.324440] 3 locks held by mmgr/152: [ 99.328542] #0: (&tty->legacy_mutex/1){..}, at: [] tty_lock_nested+0x40/0x90 [ 99.338116] #1: (&tty->ldisc_mutex){..}, at: [] tty_ldisc_kill+0x22/0xd0 [ 99.347284] #2: (&gsm->mutex){..}, at: [] gsm_cleanup_mux+0x73/0x170 [ 99.356060] [ 99.356060] stack backtrace: [ 99.360932] CPU: 0 PID: 152 Comm: mmgr Tainted: G O 3.10.20-261976-gaec5ba0 #44 [ 99.370086] ef4a4de0 ef4a4de0 ef4c1d98 c1b27b91 ef4c1db8 c1292655 c1dd10f5 c1b2dcad [ 99.378921] c1b2dcad ef4a4de0 ef4a528c ef4c1dfc c12930dd 0246 [ 99.387754] c15e1926 0001 ddfa7530 0003 c1b2dcad [ 99.396588] Call Trace: [ 99.399326] [] dump_stack+0x16/0x18 [ 99.404307] [] print_unlock_imbalance_bug+0xe5/0xf0 [ 99.410840] [] ? mutex_unlock+0xd/0x10 [ 99.416110] [] ? mutex_unlock+0xd/0x10 [ 99.421382] [] lock_release_non_nested+0x1cd/0x210 [ 99.427818] [] ? gsm_destroy_network+0x36/0x130 [ 99.433964] [] ? mutex_unlock+0xd/0x10 [ 99.439235] [] lock_release+0x82/0x1c0 [ 99.444505] [] ? mutex_unlock+0xd/0x10 [ 99.449776] [] ? mutex_unlock+0xd/0x10 [ 99.455047] [] __mutex_unlock_slowpath+0x5f/0xd0 [ 99.461288] [] mutex_unlock+0xd/0x10 [ 99.466365] [] tty_unlock+0x21/0x50 [ 99.471345] [] gsm_cleanup_mux+0xc1/0x170 [ 99.476906] [] gsmld_close+0x52/0x90 [ 99.481983] [] tty_ldisc_close.isra.1+0x35/0x50 [ 99.488127] [] tty_ldisc_kill+0x2c/0xd0 [ 99.493494] [] tty_ldisc_release+0x2f/0x50 [ 99.499152] [] tty_release+0x37c/0x4b0 [ 99.504424] [] ? mutex_unlock+0xd/0x10 [ 99.509695] [] ? mutex_unlock+0xd/0x10 [ 99.514967] [] ? eventpoll_release_file+0x7e/0x90 [ 99.521307] [] __fput+0xd9/0x200 [ 99.525996] [] fput+0xd/0x10 [ 99.530685] [] task_work_run+0x81/0xb0 [ 99.535957] [] do_notify_resume+0x49/0x70 [ 99.541520] [] work_notifysig+0x29/0x31 [ 99.546897] [ cut here ] So here we can call tty_vhangup() directly which is for virtual port. Reviewed-by: Chao Bi Signed-off-by: Liu, Chuansheng --- drivers/tty/n_gsm.c |5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c0f76da..8187ae6 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1704,11 +1704,8 @@ static void gsm_dlci_release(struct gsm_dlci *dlci) gsm_destroy_network(dlci); mutex_unlock(&dlci->mutex); - /* tty_vhangup needs the tty_lock, so unlock and - relock after doing the hangup. */ - tty_unlock(tty); tty_vhangup(tty); - tty_lock(tty); + tty_port_tty_set(&dlci->port, NULL); tty_kref_put(tty); } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] locking: Giving mutex warning more precisely in case of !lock->owner
When enabling mutex debugging, in case the imbalanced mutex_unlock() is called, we still get the warning like below: [ 364.208284] DEBUG_LOCKS_WARN_ON(lock->owner != current) But in that case, it is due to imbalanced mutex_unlock calling, and the lock->owner is NULL. Here we can enhance the case to give the warning as below: DEBUG_LOCKS_WARN_ON(lock->owner == NULL) Signed-off-by: Liu, Chuansheng --- kernel/locking/mutex-debug.c |7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c index 7e3443f..b2a1b96 100644 --- a/kernel/locking/mutex-debug.c +++ b/kernel/locking/mutex-debug.c @@ -75,7 +75,12 @@ void debug_mutex_unlock(struct mutex *lock) return; DEBUG_LOCKS_WARN_ON(lock->magic != lock); - DEBUG_LOCKS_WARN_ON(lock->owner != current); + + if (!lock->owner) + DEBUG_LOCKS_WARN_ON(lock->owner == NULL); + else + DEBUG_LOCKS_WARN_ON(lock->owner != current); + DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); mutex_clear_owner(lock); } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] devres: Freeing the drs after all release() are called
In release_nodes(), it will call dr->node.release() and kfree dr one by one. But sometimes the previous dr maybe be used by next .release(), such as: [50314.855534] [] ? synchronize_irq+0x3f/0xb0 [50314.861193] [] __free_irq+0x149/0x200 [50314.866367] [] free_irq+0x43/0xa0 [50314.871152] [] devm_irq_release+0x14/0x20 [50314.876713] [] release_nodes+0x136/0x1b0 [50314.882178] [] devres_release_all+0x39/0x60 [50314.887935] [] __device_release_driver+0x71/0xd0 the free_irq() will sync the last irq handling, which maybe use freed dr, then it will cause memory corruption. Here split the dr kfreeing actions after all dr->node.release(). Signed-off-by: Liu, Chuansheng --- drivers/base/devres.c |4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 507379e..66ff0be 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -490,9 +490,11 @@ static int release_nodes(struct device *dev, struct list_head *first, list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) { devres_log(dev, &dr->node, "REL"); dr->node.release(dev, dr->data); - kfree(dr); } + list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) + kfree(dr); + return cnt; } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] mmc: sdhci: Setting the host->mrq to NULL before executing tuning
In function sdhci_request(), it is possible to do the tuning execution like below: sdhci_request() { spin_lock_irqsave(&host->lock, flags); host->mrq = mrq; ... spin_unlock_irqrestore(&host->lock, flags); <=== Here it is possible one pending finish_tasklet get running and it will operate the original mrq, and notified the mrq is done, and causes memory corruption. sdhci_execute_tuning(mmc, tuning_opcode); spin_lock_irqsave(&host->lock, flags); host->mrq = mrq; ... } In the above race place, the original mrq should not be finished wrongly, so here before unlock the spinlock, we need to set the host->mrq to NULL to avoid this case. Signed-off-by: Liu, Chuansheng --- drivers/mmc/host/sdhci.c |7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7a7fb4f..c7a001a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1391,6 +1391,13 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) mmc->card->type == MMC_TYPE_MMC ? MMC_SEND_TUNING_BLOCK_HS200 : MMC_SEND_TUNING_BLOCK; + + /* Here we need to set the host->mrq to NULL, +* in case the penging finish_tasklet +* operates it wrongly. +*/ + host->mrq = NULL; + spin_unlock_irqrestore(&host->lock, flags); sdhci_execute_tuning(mmc, tuning_opcode); spin_lock_irqsave(&host->lock, flags); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
drm/i915: Avoid accessing the stolen address when it is unavailable
In our platform, we hit the the stolen region initialization failure case, such as below log: [drm:i915_stolen_to_physical] *ERROR* conflict detected with stolen region: [0x7b00] And it causes the dev_priv->mm.stolen_base is NULL, in this case, we should avoid accessing it any more. Here is possible call trace: intel_enable_gt_powersave -- > valleyview_enable_rps -- > valleyview_setup_pctx Cc: Li Fei Signed-off-by: Liu, Chuansheng --- drivers/gpu/drm/i915/intel_pm.c |3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 26c2ea3..1069b24 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3735,6 +3735,9 @@ static void valleyview_setup_pctx(struct drm_device *dev) u32 pcbr; int pctx_size = 24*1024; + if (!dev_priv->mm.stolen_base) + return; + pcbr = I915_READ(VLV_PCBR); if (pcbr) { /* BIOS set it up already, grab the pre-alloc'd space */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[SCSI] scsi_lib: avoid the "rejecting I/O to offline device" print storm
When handling the scsi_request_fn(), when the sd offline happened, sometimes we will hit the print storm as below: <3>[ 95.365837] sd 0:0:0:0: rejecting I/O to offline device <3>[ 95.368633] sd 0:0:0:0: rejecting I/O to offline device <3>[ 95.369881] sd 0:0:0:0: rejecting I/O to offline device <3>[ 95.371088] sd 0:0:0:0: rejecting I/O to offline device ... <3>[ 99.026230] sd 0:0:0:0: rejecting I/O to offline device <3>[ 99.027196] sd 0:0:0:0: rejecting I/O to offline device <3>[ 99.028240] sd 0:0:0:0: rejecting I/O to offline device In our case, the print last almost 4s, and it causes irq is disbled for 4s, bring system unstable. Here we create sd_printk_ratelimited to replace it. Signed-off-by: Liu, Chuansheng --- drivers/scsi/scsi_lib.c|2 +- include/scsi/scsi_device.h | 10 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d1549b7..7d8d476 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1570,7 +1570,7 @@ static void scsi_request_fn(struct request_queue *q) break; if (unlikely(!scsi_device_online(sdev))) { - sdev_printk(KERN_ERR, sdev, + sdev_printk_ratelimited(KERN_ERR, sdev, "rejecting I/O to offline device\n"); scsi_kill_request(req, q); continue; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index d65fbec..0d7d1be 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -7,6 +7,7 @@ #include #include #include +#include struct device; struct request_queue; @@ -235,6 +236,15 @@ struct scsi_dh_data { #define sdev_printk(prefix, sdev, fmt, a...) \ dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a) +#define sdev_printk_ratelimited(prefix, sdev, fmt, a...) \ +do { \ + static DEFINE_RATELIMIT_STATE(_rs, \ + DEFAULT_RATELIMIT_INTERVAL, \ + DEFAULT_RATELIMIT_BURST); \ + if (__ratelimit(&_rs)) \ + dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a); \ +} while (0) + #define scmd_printk(prefix, scmd, fmt, a...) \ (scmd)->request->rq_disk ? \ sdev_printk(prefix, (scmd)->device, "[%s] " fmt,\ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
sched/rt: Pick up the throttled rt tasks in case no other non-rt tasks
Meet the case that on CPU2, there are just two tasks to be run, one is one rt task A, another is idle task, but at this time, and the rt_rq is throttled. CPU1 CPU2 staying in idle task; waking up rt task A on target CPU 2; exiting from idle task; DO schedule() pick up RT next task pick_next_task_rt() _pick_next_task_rt() rt_rq is throttled return NULL rt task to be picked CPU2 then went into idle task AGAIN; after 2s, CPU2 is waken up again; rt task A is get running; Here rt task A is delayed for some time, even when CPU2 is in idle state. so in case there are just rt tasks running, we can pick up one of them even rt_rq is throttled. Signed-off-by: Liu, Chuansheng --- kernel/sched/rt.c | 12 ++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 01970c8..d521050 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1305,8 +1305,16 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) if (!rt_rq->rt_nr_running) return NULL; - if (rt_rq_throttled(rt_rq)) - return NULL; + if (rt_rq_throttled(rt_rq)) { + /* +* If in current rq, expects for idle task, the other tasks +* are rt tasks, we should continue to pick one of the rt tasks. +* Otherwise, the rt tasks will be delayed while current +* CPU is in idle. + */ + if ((rt_rq->rt_nr_running + 1) != rq->nr_running) + return NULL; + } do { rt_se = pick_next_rt_entity(rq, rt_rq); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] ahci: Changing two module params with static and __read_mostly
Here module parameters ahci_em_messages and devslp_idle_timeout can be set as static and __read_mostly. Signed-off-by: Liu, Chuansheng --- drivers/ata/libahci.c |7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index acfd0f7..b67086f 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -189,14 +189,15 @@ struct ata_port_operations ahci_pmp_retry_srst_ops = { }; EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); -int ahci_em_messages = 1; +static bool ahci_em_messages __read_mostly = true; EXPORT_SYMBOL_GPL(ahci_em_messages); -module_param(ahci_em_messages, int, 0444); +module_param(ahci_em_messages, bool, 0444); /* add other LED protocol types when they become supported */ MODULE_PARM_DESC(ahci_em_messages, "AHCI Enclosure Management Message control (0 = off, 1 = on)"); -int devslp_idle_timeout = 1000;/* device sleep idle timeout in ms */ +/* device sleep idle timeout in ms */ +static int devslp_idle_timeout __read_mostly = 1000; module_param(devslp_idle_timeout, int, 0644); MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout"); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ahci: Changing two module params with static and __read_mostly
Here module parameters ahci_em_messages and devslp_idle_timeout can be set as static and __read_mostly. Signed-off-by: Liu, Chuansheng --- drivers/ata/libahci.c |5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index acfd0f7..1757631 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -189,14 +189,15 @@ struct ata_port_operations ahci_pmp_retry_srst_ops = { }; EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); -int ahci_em_messages = 1; +static int ahci_em_messages __read_mostly = 1; EXPORT_SYMBOL_GPL(ahci_em_messages); module_param(ahci_em_messages, int, 0444); /* add other LED protocol types when they become supported */ MODULE_PARM_DESC(ahci_em_messages, "AHCI Enclosure Management Message control (0 = off, 1 = on)"); -int devslp_idle_timeout = 1000;/* device sleep idle timeout in ms */ +/* device sleep idle timeout in ms */ +static int devslp_idle_timeout __read_mostly = 1000; module_param(devslp_idle_timeout, int, 0644); MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout"); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ACPI / osl: implement acpi_os_sleep() with msleep()
Currently the acpi_os_sleep() is using the schedule_timeout_interruptible(), which can be interrupted by signal, which causes the real sleep time is shorter. According to the ACPI spec: The Sleep term is used to implement long-term timing requirements. Execution is delayed for at least the required number of milliseconds. The sleeping time should be at least of the required number msecs, here using msleep() to implement it. Also if the real time is shorter, we meet the device POWER ON issue. CC: lizhuangzhi CC: Li Fei Signed-off-by: liu chuansheng --- drivers/acpi/osl.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e5f416c..b1629b5 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -820,7 +820,7 @@ acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) void acpi_os_sleep(u64 ms) { - schedule_timeout_interruptible(msecs_to_jiffies(ms)); + msleep(ms); } void acpi_os_stall(u32 us) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:x86/reboot] reboot: Re-enable the function of variable reboot_default
Commit-ID: e635be963eb2e9883e8124b75dff0c2e29857a6e Gitweb: http://git.kernel.org/tip/e635be963eb2e9883e8124b75dff0c2e29857a6e Author: Chuansheng Liu AuthorDate: Mon, 9 Sep 2013 19:49:40 +0800 Committer: H. Peter Anvin CommitDate: Tue, 10 Sep 2013 08:48:40 -0700 reboot: Re-enable the function of variable reboot_default Commit 1b3a5d02ee070c (reboot: move arch/x86 reboot= handling to generic kernel) did some cleanup for reboot= command line, but it made the reboot_default to be invalidated. The default value of variable reboot_default should be 1, and if command line reboot= is not set, system will use the default reboot mode. Signed-off-by: Li Fei Link: http://lkml.kernel.org/r/1378727380.26153.8.camel@cliu38-desktop-build Signed-off-by: liu chuansheng Acked-by: Robin Holt Signed-off-by: H. Peter Anvin --- kernel/reboot.c | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/reboot.c b/kernel/reboot.c index 269ed93..d82eb6e 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -32,7 +32,14 @@ EXPORT_SYMBOL(cad_pid); #endif enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE; -int reboot_default; +/* + * This variable is used privately to keep track of whether or not + * reboot_type is still set to its default value (i.e., reboot= hasn't + * been set on the command line). This is needed so that we can + * suppress DMI scanning for reboot quirks. Without it, it's + * impossible to override a faulty reboot quirk without recompiling. +*/ +int reboot_default = 1; int reboot_cpu; enum reboot_type reboot_type = BOOT_ACPI; int reboot_force; -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] PCI/PM: Removing the function pci_pm_complete()
Commit(88d2613) removed the pm_runtime_put_sync() from pci_pm_complete() to PM core code device_complete(). Here the pci_pm_complete() is doing the same work which can be done in device_complete(), so we can remove it directly. Signed-off-by: liu chuansheng --- drivers/pci/pci-driver.c |9 - 1 files changed, 0 insertions(+), 9 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 98f7b9b..736ef3f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -599,18 +599,10 @@ static int pci_pm_prepare(struct device *dev) return error; } -static void pci_pm_complete(struct device *dev) -{ - struct device_driver *drv = dev->driver; - - if (drv && drv->pm && drv->pm->complete) - drv->pm->complete(dev); -} #else /* !CONFIG_PM_SLEEP */ #define pci_pm_prepare NULL -#define pci_pm_completeNULL #endif /* !CONFIG_PM_SLEEP */ @@ -1123,7 +1115,6 @@ static int pci_pm_runtime_idle(struct device *dev) const struct dev_pm_ops pci_dev_pm_ops = { .prepare = pci_pm_prepare, - .complete = pci_pm_complete, .suspend = pci_pm_suspend, .resume = pci_pm_resume, .freeze = pci_pm_freeze, -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] reboot: re-enable the function of variable reboot_default
commit b3a5d02ee070c(reboot: move arch/x86 reboot= handling to generic kernel) did some cleanup for reboot= command line, but it made the reboot_default to be invalidated. The default value of variable reboot_default should be 1, and if command line reboot= is not set, system will use the default reboot mode. Signed-off-by: Li Fei Signed-off-by: liu chuansheng --- kernel/reboot.c |9 - 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/kernel/reboot.c b/kernel/reboot.c index 269ed93..d82eb6e 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -32,7 +32,14 @@ EXPORT_SYMBOL(cad_pid); #endif enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE; -int reboot_default; +/* + * This variable is used privately to keep track of whether or not + * reboot_type is still set to its default value (i.e., reboot= hasn't + * been set on the command line). This is needed so that we can + * suppress DMI scanning for reboot quirks. Without it, it's + * impossible to override a faulty reboot quirk without recompiling. +*/ +int reboot_default = 1; int reboot_cpu; enum reboot_type reboot_type = BOOT_ACPI; int reboot_force; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] Fix the race between the fget() and close()
When one thread is calling sys_ioctl(), and another thread is calling sys_close(), current code has protected most cases. But for the below case, it will cause issue: T1T2 T3 sys_close(oldfile)sys_open(newfile) sys_ioctl(oldfile) -> __close_fd() lock file_lock assign NULL file put fd to be unused unlock file_lock get new fd is same as old assign newfile to same fd fget_flight() get the newfile!!! decrease file->f_count file->f_count == 0 --> try to release file The race is when T1 try to close one oldFD, T3 is trying to ioctl the oldFD, if currently the new T2 is trying to open a newfile, it maybe get the newFD is same as oldFD. And normal case T3 should get NULL file pointer due to released by T1, but T3 get the newfile pointer, and continue the ioctl accessing. It maybe causes unexpectable error, we hit one system panic at do_vfs_ioctl(). Here we can fix it that putting "put_unused_fd()" after filp_close(), it can avoid this case. Signed-off-by: liu chuansheng --- fs/file.c | 11 ++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/fs/file.c b/fs/file.c index 4a78f98..3f9b825 100644 --- a/fs/file.c +++ b/fs/file.c @@ -590,6 +590,7 @@ int __close_fd(struct files_struct *files, unsigned fd) { struct file *file; struct fdtable *fdt; + int ret; spin_lock(&files->file_lock); fdt = files_fdtable(files); @@ -600,9 +601,17 @@ int __close_fd(struct files_struct *files, unsigned fd) goto out_unlock; rcu_assign_pointer(fdt->fd[fd], NULL); __clear_close_on_exec(fd, fdt); + spin_unlock(&files->file_lock); + ret = filp_close(file, files); + + /* Delaying put_unused_fd after flip_close, otherwise +* when race happening between fget() and close(), +* the fget() may get one wrong file pointer. +*/ + spin_lock(&files->file_lock); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); - return filp_close(file, files); + return ret; out_unlock: spin_unlock(&files->file_lock); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
mfd, arizona: Fix the deadlock between interrupt handler and dpm_suspend
When system try to do the suspend: T1:suspend_thread T2: interrupt thread handler enter_state() arizona_irq_thread() suspend_devices_and_enter()regmap_read() __device_suspend() regmap_spi_read() spi_write_then_read() spi_sync() __spi_sync() wait_for_completion() T2 <== Blocked here due to spi suspended suspend_enter() dpm_suspend_end() dpm_suspend_noirq() suspend_device_irqs() synchronize_irq() T1 <== Blocked here due waiting for T2 finished Then T1 and T2 is deadlocked there. Here the arizona irq is not NOSUSPEND irq, so when doing device suspend, we can disable the arizona irq, and enable it until devices resuming finished. Signed-off-by: liu chuansheng --- drivers/mfd/arizona-core.c | 11 --- 1 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index b562c7b..b11bd01 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -264,11 +264,11 @@ static int arizona_runtime_suspend(struct device *dev) #endif #ifdef CONFIG_PM_SLEEP -static int arizona_resume_noirq(struct device *dev) +static int arizona_suspend(struct device *dev) { struct arizona *arizona = dev_get_drvdata(dev); - dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); + dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); disable_irq(arizona->irq); return 0; @@ -278,7 +278,7 @@ static int arizona_resume(struct device *dev) { struct arizona *arizona = dev_get_drvdata(dev); - dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); + dev_dbg(arizona->dev, "Resume, reenabling IRQ\n"); enable_irq(arizona->irq); return 0; @@ -289,10 +289,7 @@ const struct dev_pm_ops arizona_pm_ops = { SET_RUNTIME_PM_OPS(arizona_runtime_suspend, arizona_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume) -#ifdef CONFIG_PM_SLEEP - .resume_noirq = arizona_resume_noirq, -#endif + SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) }; EXPORT_SYMBOL_GPL(arizona_pm_ops); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] genirq: Do not consider the irqs with IRQF_NO_SUSPEND in check_wakeup_irqs()
According to commit 9c6079aa1bf(genirq: Do not consider disabled wakeup irqs), we should not break the suspend when one interrupt has been disabled before suspending and is pending there. But there is another case missed: If an interrupt which is marked IRQF_NO_SUSPEND has been disabled before suspend invocation then desc->depth is 1 and therefor it should not be checked for IRQS_PENDING in check_wakeup_irqs(). Here also checking if the desc->istate & IRQS_SUSPENDED is true to avoid this case. Signed-off-by: liu chuansheng --- kernel/irq/pm.c |9 - 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index cb228bf..f02a03d 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -107,9 +107,16 @@ int check_wakeup_irqs(void) * Only interrupts which are marked as wakeup source * and have not been disabled before the suspend check * can abort suspend. +* +* Meanwhile, if an interrupt which is marked IRQF_NO_SUSPEND +* has been disabled before suspend invocation then +* desc->depth is 1 and therefor it should not be checked +* for IRQS_PENDING, so also adding the checking of +* desc->istate & IRQS_SUSPENDED for this case. */ if (irqd_is_wakeup_set(&desc->irq_data)) { - if (desc->depth == 1 && desc->istate & IRQS_PENDING) + if (desc->depth == 1 && (desc->istate & IRQS_PENDING) + && (desc->istate & IRQS_SUSPENDED)) return -EBUSY; continue; } -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/3] genirq: Give warning in case calling irq_set_irq_wake with _NO_SUSPEND flag
When one irq is setup with flag IRQF_NO_SUSPEND, it is pointless to call irq_set_irq_wake(). Because check_wakeup_irqs() is just checking the irq which has pending but is in IRQS_SUSPENDED state when do syscore_suspend(). Signed-off-by: liu chuansheng --- kernel/irq/manage.c |8 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index fa17855..94c5af9 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -513,6 +513,14 @@ int irq_set_irq_wake(unsigned int irq, unsigned int on) if (!desc) return -EINVAL; + /* Checking if the flag IRQF_NO_SUSPEND is set, +* if set, drivers do not need to call irq_set_irq_wake(), +* it is pointless. +*/ + if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) + WARN(1, "IRQ %d with flag IRQF_NO_SUSPEND, no need to call here\n", + irq); + /* wakeup-capable irqs can be shared between drivers that * don't need to have the same sleep mode behaviors. */ -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] genirq: Do not consider the irqs with disabling and IRQF_NO_SUSPEND
According to commit 9c6079aa1bf(genirq: Do not consider disabled wakeup irqs), we should not break the suspend when one irq is pending but has been disabled before suspending. But there is another case missed, that one irq with flag IRQF_NO_SUSPEND, which has been disabled before suspending, and irq pending there, in this case, we still should not break the suspending, otherwise, the suspend abort over and over. Here also checking if the desc->istate & IRQS_SUSPENDED is true. Signed-off-by: liu chuansheng --- kernel/irq/pm.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index cb228bf..1470c1b 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -109,7 +109,8 @@ int check_wakeup_irqs(void) * can abort suspend. */ if (irqd_is_wakeup_set(&desc->irq_data)) { - if (desc->depth == 1 && desc->istate & IRQS_PENDING) + if (desc->depth == 1 && (desc->istate & IRQS_PENDING) + && (desc->istate & IRQS_SUSPENDED)) return -EBUSY; continue; } -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] x86, io_apic: Adding the flag IRQCHIP_SKIP_SET_WAKE
Currently for an ioapic chip irq, if we call irq_set_irq_wake() we will get the ENXIO returning error, but some drivers need the wake-up interrupts pending mechanism. Here adding the flag IRQCHIP_SKIP_SET_WAKE instead of emtpy callback. Signed-off-by: liu chuansheng --- arch/x86/kernel/apic/io_apic.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 9ed796c..7d0baf7 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2520,6 +2520,7 @@ static struct irq_chip ioapic_chip __read_mostly = { .irq_eoi= ack_apic_level, .irq_set_affinity = native_ioapic_set_affinity, .irq_retrigger = ioapic_retrigger_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, }; static inline void init_IO_APIC_traps(void) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 0/3] genirq: Do not consider the irqs with disabling and IRQF_NO_SUSPEND
Meet some issues when operating one ioapic chip irq which is set with _NO_SUSPEND flag and calling irq_set_irq_wake(). Written the below patches, thanks your time to review. [PATCH 1/3] x86, io_apic: Adding the flag IRQCHIP_SKIP_SET_WAKE [PATCH 2/3] genirq: Do not consider the irqs with disabling and IRQF_NO_SUSPEND [PATCH 3/3] genirq: Give warning in case calling irq_set_irq_wake with _NO_SUSPEND flag -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3 V2] intel_idle: Removing the redundant calculating for dev->state_count
In function intel_idle_cpu_init() and intel_idle_cpuidle_driver_init(), they are having the same for(;;) loop to count the ->state_count. Although intel_idle_cpu_init() can be called at runtime CPU HOTPLUG case, but max_cstate can not be changed at runtime. So the dev->state_count should be == drv->state_count, in the function cpuidle_register_device() has done the initialization. Here we can clean up these pieces of code. Signed-off-by: liu chuansheng --- drivers/idle/intel_idle.c | 29 - 1 files changed, 0 insertions(+), 29 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 17c9cf9..bb0ae0b 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -599,39 +599,10 @@ static int intel_idle_cpuidle_driver_init(void) */ static int intel_idle_cpu_init(int cpu) { - int cstate; struct cpuidle_device *dev; dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); - dev->state_count = 1; - - for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { - int num_substates, mwait_hint, mwait_cstate, mwait_substate; - - if (cpuidle_state_table[cstate].enter == NULL) - break; - - if (cstate + 1 > max_cstate) { - printk(PREFIX "max_cstate %d reached\n", max_cstate); - break; - } - - mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); - mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); - mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); - - /* does the state exist in CPUID.MWAIT? */ - num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) - & MWAIT_SUBSTATE_MASK; - - /* if sub-state in table is not enumerated by CPUID */ - if ((mwait_substate + 1) > num_substates) - continue; - - dev->state_count += 1; - } - dev->cpu = cpu; if (cpuidle_register_device(dev)) { -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/3] intel_idle: set the state_tables array as __initdata to save mem
Currently, in intel_idle.c, there are 5 state_tables array, every array size is sizeof(struct cpuidle_state) * CPUIDLE_STATE_MAX. As in intel_idle_cpuidle_driver_init(), we have copied the data into intel_idle_driver->state[], so do not need to keep state_tables[] there any more after system init. It will save about 3~4k memory, also benefits mobile devices. Here changing them as __initdata, also removing global var cpuidle_state_table pointer. Signed-off-by: liu chuansheng --- drivers/idle/intel_idle.c | 18 -- 1 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 503b401..cbdc952 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -99,8 +99,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); static int intel_idle_cpu_init(int cpu); -static struct cpuidle_state *cpuidle_state_table; - /* * Set this flag for states where the HW flushes the TLB for us * and so we don't need cross-calls to keep it consistent. @@ -124,7 +122,7 @@ static struct cpuidle_state *cpuidle_state_table; * which is also the index into the MWAIT hint array. * Thus C0 is a dummy. */ -static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-NHM", .desc = "MWAIT 0x00", @@ -157,7 +155,7 @@ static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-SNB", .desc = "MWAIT 0x00", @@ -197,7 +195,7 @@ static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-IVB", .desc = "MWAIT 0x00", @@ -237,7 +235,7 @@ static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-HSW", .desc = "MWAIT 0x00", @@ -277,7 +275,7 @@ static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1E-ATM", .desc = "MWAIT 0x00", @@ -472,7 +470,7 @@ MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids); /* * intel_idle_probe() */ -static int intel_idle_probe(void) +static int __init intel_idle_probe(void) { unsigned int eax, ebx, ecx; const struct x86_cpu_id *id; @@ -504,7 +502,6 @@ static int intel_idle_probe(void) pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); icpu = (const struct idle_cpu *)id->driver_data; - cpuidle_state_table = icpu->state_table; if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; @@ -540,10 +537,11 @@ static void intel_idle_cpuidle_devices_uninit(void) * intel_idle_cpuidle_driver_init() * allocate, initialize cpuidle_states */ -static int intel_idle_cpuidle_driver_init(void) +static int __init intel_idle_cpuidle_driver_init(void) { int cstate; struct cpuidle_driver *drv = &intel_idle_driver; + struct cpuidle_state *cpuidle_state_table = icpu->state_table; drv->state_count = 1; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] intel_idle: Removing the redundant calculating for dev->state_count
In function intel_idle_cpu_init() and intel_idle_cpuidle_driver_init(), they are having the same for(;;) loop. Here in intel_idle_cpu_init(), the dev->state_count can be assigned by drv->state_count directly. Signed-off-by: liu chuansheng --- drivers/idle/intel_idle.c | 30 ++ 1 files changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 17c9cf9..503b401 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -599,38 +599,12 @@ static int intel_idle_cpuidle_driver_init(void) */ static int intel_idle_cpu_init(int cpu) { - int cstate; struct cpuidle_device *dev; + struct cpuidle_driver *drv = &intel_idle_driver; dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); - dev->state_count = 1; - - for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { - int num_substates, mwait_hint, mwait_cstate, mwait_substate; - - if (cpuidle_state_table[cstate].enter == NULL) - break; - - if (cstate + 1 > max_cstate) { - printk(PREFIX "max_cstate %d reached\n", max_cstate); - break; - } - - mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); - mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); - mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); - - /* does the state exist in CPUID.MWAIT? */ - num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) - & MWAIT_SUBSTATE_MASK; - - /* if sub-state in table is not enumerated by CPUID */ - if ((mwait_substate + 1) > num_substates) - continue; - - dev->state_count += 1; - } + dev->state_count = drv->state_count; dev->cpu = cpu; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] intel_idle: changing the continue to break in intel_idle_cpu_init()
According to commit e022e7eb9, the .enter == NULL is the last one in state_tables[]. So just like intel_idle_cpuidle_driver_init(), in case of .enter == NULL, breaking the for(;;) loop directly. Signed-off-by: liu chuansheng --- drivers/idle/intel_idle.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 5d66750..17c9cf9 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -610,7 +610,7 @@ static int intel_idle_cpu_init(int cpu) int num_substates, mwait_hint, mwait_cstate, mwait_substate; if (cpuidle_state_table[cstate].enter == NULL) - continue; + break; if (cstate + 1 > max_cstate) { printk(PREFIX "max_cstate %d reached\n", max_cstate); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 0/3] intel_idle: set the state_tables array into __initdata to save mem
As Daniel suggested, I did some cleanup before setting the state_tables array into __initdata. Thanks your help to review them. [PATCH 1/3] intel_idle: changing the continue to break in intel_idle_cpu_init() [PATCH 2/3] intel_idle: Removing the redundant calculating for dev->state_count [PATCH 3/3] intel_idle: set the state_tables array as __initdata to save mem -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] intel_idle: set the state_tables array into __initdata to save mem
Currently, in intel_idle.c, there are 5 state_tables array, every array size is sizeof(struct cpuidle_state) * CPUIDLE_STATE_MAX. But after intel_idle_probe(), just only one array is useful. Here we can just define one static state_table, and initialize it in intel_idle_probe(), and set other data state_tables as __initdata. It can save about 3K, which also benefits mobile devices. Signed-off-by: liu chuansheng --- drivers/idle/intel_idle.c | 19 --- 1 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 5d66750..0642bfe 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -99,7 +99,7 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); static int intel_idle_cpu_init(int cpu); -static struct cpuidle_state *cpuidle_state_table; +static struct cpuidle_state cpuidle_state_table[CPUIDLE_STATE_MAX]; /* * Set this flag for states where the HW flushes the TLB for us @@ -124,7 +124,7 @@ static struct cpuidle_state *cpuidle_state_table; * which is also the index into the MWAIT hint array. * Thus C0 is a dummy. */ -static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-NHM", .desc = "MWAIT 0x00", @@ -157,7 +157,7 @@ static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-SNB", .desc = "MWAIT 0x00", @@ -197,7 +197,7 @@ static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-IVB", .desc = "MWAIT 0x00", @@ -237,7 +237,7 @@ static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1-HSW", .desc = "MWAIT 0x00", @@ -277,7 +277,7 @@ static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { .enter = NULL } }; -static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = { +static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] __initdata = { { .name = "C1E-ATM", .desc = "MWAIT 0x00", @@ -504,7 +504,12 @@ static int intel_idle_probe(void) pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); icpu = (const struct idle_cpu *)id->driver_data; - cpuidle_state_table = icpu->state_table; + /* Copy the icpu->state_table into cpuidle_state_table, +* The pointing array by icpu->state_table is with __initdata, +* which will be freed after kernel init ending. +*/ + memcpy(cpuidle_state_table, icpu->state_table, + sizeof(cpuidle_state_table)); if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] smp: Give WARN()ing when calling smp_call_function_many()/single() in serving irq
Currently the functions smp_call_function_many()/single() will give a WARN()ing only in the case of irqs_disabled(), but that check is not enough to guarantee execution of the SMP cross-calls. In many other cases such as softirq handling/interrupt handling, the two APIs still can not be called, just as the smp_call_function_many() comments say: * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. Preemption * must be disabled when calling this function. There is a real case for softirq DEADLOCK case: CPUACPUB spin_lock(&spinlock) Any irq coming, call the irq handler irq_exit() spin_lock_irq(&spinlock) <== Blocking here due to CPUB hold it __do_softirq() run_timer_softirq() timer_cb() call smp_call_function_many() send IPI interrupt to CPUA wait_csd() Then both CPUA and CPUB will be deadlocked here. So we should give a warning in the nmi, hardirq or softirq context as well. Moreover, adding one new macro in_serving_irq() which indicates we are processing nmi, hardirq or sofirq. Signed-off-by: liu chuansheng --- include/linux/hardirq.h |5 + kernel/smp.c| 11 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 624ef3f..e07663f 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -94,6 +94,11 @@ */ #define in_nmi() (preempt_count() & NMI_MASK) +/* + * Are we in nmi,irq context, or softirq context? + */ +#define in_serving_irq() (in_nmi() || in_irq() || in_serving_softirq()) + #if defined(CONFIG_PREEMPT_COUNT) # define PREEMPT_CHECK_OFFSET 1 #else diff --git a/kernel/smp.c b/kernel/smp.c index 69f38bd..b0a5d21 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "smpboot.h" @@ -323,8 +324,9 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() -&& !oops_in_progress); + WARN_ON_ONCE(cpu_online(this_cpu) + && (irqs_disabled() || in_serving_irq()) + && !oops_in_progress); if (cpu == this_cpu) { local_irq_save(flags); @@ -462,8 +464,9 @@ void smp_call_function_many(const struct cpumask *mask, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() -&& !oops_in_progress && !early_boot_irqs_disabled); + WARN_ON_ONCE(cpu_online(this_cpu) + && (irqs_disabled() || in_serving_irq()) + && !oops_in_progress && !early_boot_irqs_disabled); /* Try to fastpath. So, what's a CPU they want? Ignoring this one. */ cpu = cpumask_first_and(mask, cpu_online_mask); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] smp: Give WARN()ing when calling smp_call_function_many()/single() in serving irq
Currently the functions smp_call_function_many()/single() will give a WARN()ing only in the case of irqs_disabled(), but that check is not enough to guarantee execution of the SMP cross-calls. In many other cases such as softirq handling/interrupt handling, the two APIs still can not be called, just as the smp_call_function_many() comments say: * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. Preemption * must be disabled when calling this function. There is a real case for softirq DEADLOCK case: CPUACPUB spin_lock(&spinlock) Any irq coming, call the irq handler irq_exit() spin_lock_irq(&spinlock) <== Blocking here due to CPUB hold it __do_softirq() run_timer_softirq() timer_cb() call smp_call_function_many() send IPI interrupt to CPUA wait_csd() Then both CPUA and CPUB will be deadlocked here. So we should give a warning in the nmi, hardirq or softirq context as well. Moreover, adding one new macro in_serving_irq() which indicates we are processing nmi, hardirq or sofirq. Signed-off-by: liu chuansheng --- include/linux/hardirq.h |5 + kernel/smp.c| 10 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 624ef3f..e07663f 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -94,6 +94,11 @@ */ #define in_nmi() (preempt_count() & NMI_MASK) +/* + * Are we in nmi,irq context, or softirq context? + */ +#define in_serving_irq() (in_nmi() || in_irq() || in_serving_softirq()) + #if defined(CONFIG_PREEMPT_COUNT) # define PREEMPT_CHECK_OFFSET 1 #else diff --git a/kernel/smp.c b/kernel/smp.c index 69f38bd..ba43dd7 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -323,8 +323,9 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() -&& !oops_in_progress); + WARN_ON_ONCE(cpu_online(this_cpu) + && (irqs_disabled() || in_serving_irq()) + && !oops_in_progress); if (cpu == this_cpu) { local_irq_save(flags); @@ -462,8 +463,9 @@ void smp_call_function_many(const struct cpumask *mask, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() -&& !oops_in_progress && !early_boot_irqs_disabled); + WARN_ON_ONCE(cpu_online(this_cpu) + && (irqs_disabled() || in_serving_irq()) + && !oops_in_progress && !early_boot_irqs_disabled); /* Try to fastpath. So, what's a CPU they want? Ignoring this one. */ cpu = cpumask_first_and(mask, cpu_online_mask); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:core/locking] smp: Give WARN()ing if in_interrupt() when calling smp_call_function_many()/single()
Commit-ID: b29f39c7c3e75a741a7da88244ec707f293ec04c Gitweb: http://git.kernel.org/tip/b29f39c7c3e75a741a7da88244ec707f293ec04c Author: Chuansheng Liu AuthorDate: Wed, 6 Feb 2013 23:18:21 +0800 Committer: Ingo Molnar CommitDate: Wed, 6 Feb 2013 12:00:30 +0100 smp: Give WARN()ing if in_interrupt() when calling smp_call_function_many()/single() Currently the functions smp_call_function_many()/single() will give a WARN()ing only in the case of irqs_disabled(), but that check is not enough to guarantee execution of the SMP cross-calls. In many other cases such as softirq handling/interrupt handling, the two APIs still can not be called, just as the smp_call_function_many() comments say: * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. Preemption * must be disabled when calling this function. There is a real case for softirq DEADLOCK case: CPUACPUB spin_lock(&spinlock) Any irq coming, call the irq handler irq_exit() spin_lock_irq(&spinlock) <== Blocking here due to CPUB hold it __do_softirq() run_timer_softirq() timer_cb() call smp_call_function_many() send IPI interrupt to CPUA wait_csd() Then both CPUA and CPUB will be deadlocked here. So we should give a warning in the in_interrupt() case as well. Signed-off-by: liu chuansheng Cc: jun.zh...@intel.com Cc: pet...@infradead.org Cc: jbeul...@suse.com Cc: paul...@linux.vnet.ibm.com Cc: min...@mina86.org Cc: srivatsa.b...@linux.vnet.ibm.com Cc: Linus Torvalds Cc: Andrew Morton Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1360163901.24670.13.camel@cliu38-desktop-build Signed-off-by: Ingo Molnar --- kernel/smp.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index 29dd40a..fec45aa 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "smpboot.h" @@ -318,7 +319,7 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() + WARN_ON_ONCE(cpu_online(this_cpu) && (irqs_disabled() || in_interrupt()) && !oops_in_progress); if (cpu == this_cpu) { @@ -416,8 +417,9 @@ void __smp_call_function_single(int cpu, struct call_single_data *data, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled() -&& !oops_in_progress); + WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait + && (irqs_disabled() || in_interrupt()) + && !oops_in_progress); if (cpu == this_cpu) { local_irq_save(flags); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] smp: give WARN in case of in_interrupt() when calling smp_call_function_many/single
Currently, in function smp_call_function_many/single, it will give WARN just in case of irqs_disabled(), but it is not enough. In many other cases such as softirq handling/interrupt handling, the two APIs still can not be called, just as the smp_call_function_many() comments said: * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. Preemption * must be disabled when calling this function. There is a real case for softirq DEADLOCK case: CPUACPUB spin_lock(&spinlock) Any irq coming, call the irq handler irq_exit() spin_lock_irq(&spinlock) <== Blocking here due to CPUB hold it __do_softirq() run_timer_softirq() timer_cb() call smp_call_function_many() send IPI interrupt to CPUA wait_csd() Then both CPUA and CPUB will be DEADLOCK here. So we should give WARN in case of in_interrupt(), not only irqd_disabled(). Signed-off-by: liu chuansheng --- kernel/smp.c |8 +--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index 69f38bd..a2f0b2c 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "smpboot.h" @@ -323,7 +324,7 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() + WARN_ON_ONCE(cpu_online(this_cpu) && (irqs_disabled() || in_interrupt()) && !oops_in_progress); if (cpu == this_cpu) { @@ -421,8 +422,9 @@ void __smp_call_function_single(int cpu, struct call_single_data *data, * send smp call function interrupt to this cpu and as such deadlocks * can't happen. */ - WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled() -&& !oops_in_progress); + WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait + && (irqs_disabled() || in_interrupt()) + && !oops_in_progress); if (cpu == this_cpu) { local_irq_save(flags); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] x86/io_apic: Do not unmask the masked-irq when migrating irq in ack_apic_level()
In ack_apic_level(), when there is pending affinity setting for current irq, ioapic_irqd_mask()/ioapic_irqd_unmask() will try to mask the irq and do the irq affinity setting. But at this time, it is possibility that the irq has been masked, in this case, we should not unmask it directly in ioapic_irqd_unmask(). One real case is one threaded interrupt with ONE_SHOT, the irq has been masked in handle_fasteoi_irq(). Signed-off-by: liu chuansheng --- arch/x86/kernel/apic/io_apic.c | 11 +-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index b739d39..5c0fe25 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2429,7 +2429,8 @@ static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg) { /* If we are moving the irq we need to mask it */ if (unlikely(irqd_is_setaffinity_pending(data))) { - mask_ioapic(cfg); + if (!irqd_irq_masked(data)) + mask_ioapic(cfg); return true; } return false; @@ -2467,7 +2468,13 @@ static inline void ioapic_irqd_unmask(struct irq_data *data, */ if (!io_apic_level_ack_pending(cfg)) irq_move_masked_irq(data); - unmask_ioapic(cfg); + /* +* For the threaded interrupt with ONE_SHOT flag, +* the irq has been masked in handle_fasteoi_irq(). +* We should be careful not to unmask it here. +*/ + if (!irqd_irq_masked(data)) + unmask_ioapic(cfg); } } #else -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] PM / Runtime: return the right value when deferred_resume is true in rpm_suspend()
For the case that in rpm_suspend() and deferred_resume is true, the rpm_resume() will be called, and if rpm_resume() return error, at this time, the device is still in SUSPENDED state. In this case it is still an suspend succeeding case, we should return non-error instead of EAGAIN. An example like below for this case: CPU1: CPU2: pm_runtime_get_sync() pm_runtime_put_sync_suspend() rpm_suspend() __update_runtime_status(dev, RPM_SUSPENDING) rpm_callback() spin_unlock_irq() ... pm_runtime_get() spin_lock_irqsave() cb()rpm_resume() ... dev->power.deferred_resume = true spin_unlock_irqrestore() spin_lock_irq() __update_runtime_status(dev, RPM_SUSPENDED) rpm_resume() is called due to deferred_resume is true Here if rpm_resume() failed in CPU1, the runtime_status is still SUSPENDED, we should return 0 in this case. Signed-off-by: liu chuansheng --- drivers/base/power/runtime.c |8 +--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3148b10..0adc713 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -436,9 +436,11 @@ static int rpm_suspend(struct device *dev, int rpmflags) if (dev->power.deferred_resume) { dev->power.deferred_resume = false; - rpm_resume(dev, 0); - retval = -EAGAIN; - goto out; + if (rpm_resume(dev, 0) >= 0) { + /* In case resuming succeeded, return EAGAIN error */ + retval = -EAGAIN; + goto out; + } } /* Maybe the parent is now able to suspend. */ -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] PM / Runtime: Fix the twice judgement in rpm_suspend/resume()
In function rpm_suspend/resume(), when going into the for(;;), the pre-condition judgement has been done, and the variable runtime_status are always protected by &power.lock, so it is not necessary to judge them again before unlock_irq &power.lock in for(;;). This patch clean them up. Signed-off-by: liu chuansheng --- drivers/base/power/runtime.c | 18 +- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3148b10..32d6497 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -377,14 +377,14 @@ static int rpm_suspend(struct device *dev, int rpmflags) for (;;) { prepare_to_wait(&dev->power.wait_queue, &wait, TASK_UNINTERRUPTIBLE); - if (dev->power.runtime_status != RPM_SUSPENDING) - break; spin_unlock_irq(&dev->power.lock); schedule(); spin_lock_irq(&dev->power.lock); + if (dev->power.runtime_status != RPM_SUSPENDING) + break; } finish_wait(&dev->power.wait_queue, &wait); goto repeat; @@ -557,15 +557,15 @@ static int rpm_resume(struct device *dev, int rpmflags) for (;;) { prepare_to_wait(&dev->power.wait_queue, &wait, TASK_UNINTERRUPTIBLE); - if (dev->power.runtime_status != RPM_RESUMING - && dev->power.runtime_status != RPM_SUSPENDING) - break; spin_unlock_irq(&dev->power.lock); schedule(); spin_lock_irq(&dev->power.lock); + if (dev->power.runtime_status != RPM_RESUMING + && dev->power.runtime_status != RPM_SUSPENDING) + break; } finish_wait(&dev->power.wait_queue, &wait); goto repeat; @@ -989,15 +989,15 @@ static void __pm_runtime_barrier(struct device *dev) for (;;) { prepare_to_wait(&dev->power.wait_queue, &wait, TASK_UNINTERRUPTIBLE); - if (dev->power.runtime_status != RPM_SUSPENDING - && dev->power.runtime_status != RPM_RESUMING - && !dev->power.idle_notification) - break; spin_unlock_irq(&dev->power.lock); schedule(); spin_lock_irq(&dev->power.lock); + if (dev->power.runtime_status != RPM_SUSPENDING + && dev->power.runtime_status != RPM_RESUMING + && !dev->power.idle_notification) + break; } finish_wait(&dev->power.wait_queue, &wait); } -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] genirq: Give warning when setup an already-setup non-shared irq
Meet the case when the request_threaded_irq() with the same irq is called twice continually, get the below mismatch info: "IRQ handler type mismatch for IRQ 323" Here give a right warning that like below: "Trying to setup already-setup non-shared IRQ 323" Signed-off-by: liu chuansheng --- kernel/irq/manage.c | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index e49a288..6802ce1 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -999,6 +999,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) old_ptr = &desc->action; old = *old_ptr; if (old) { + /* Give warning when setup an irq which has been setup +* already. +*/ + if (!(old->flags & IRQF_SHARED)) { + ret = -EINVAL; + WARN(1, "Trying to setup already-setup non-shared IRQ %d\n", + irq); + goto out_mask; + } + /* * Can't share interrupts unless both agree to and are * the same type (level, edge, polarity). So both flag -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/2] ASoC: core: fix the memory leak in case of remove_aux_dev()
When probing aux_dev, initializing is as below: device_initialize() device_add() So when remove aux_dev, we need do as below: device_del() device_put() Otherwise, the rtd_release() will not be called. So here using device_unregister() to replace device_del(), like the action in soc_remove_link_dais(). Signed-off-by: liu chuansheng --- sound/soc/soc-core.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9689411..2270f8f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1556,7 +1556,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) /* unregister the rtd device */ if (rtd->dev_registered) { device_remove_file(rtd->dev, &dev_attr_codec_reg); - device_del(rtd->dev); + device_unregister(rtd->dev); rtd->dev_registered = 0; } -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/2] ASoC: core: fix the memory leak in case of device_add() failure
After called device_initialize(), even device_add() returns error, we still need use the put_device() to release the reference to call rtd_release(), which will do the free() action. Signed-off-by: liu chuansheng --- sound/soc/soc-core.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 91d592f..9689411 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1255,6 +1255,8 @@ static int soc_post_component_init(struct snd_soc_card *card, INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); ret = device_add(rtd->dev); if (ret < 0) { + /* calling put_device() here to free the rtd->dev */ + put_device(rtd->dev); dev_err(card->dev, "ASoC: failed to register runtime device: %d\n", ret); return ret; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] Bluetooth: fix the oops due to conn->hcon == NULL in shutdown case
Meet one panic issue as below stack: <1>[11340.226404] BUG: unable to handle kernel NULL pointer dereference at 0008 <4>[11340.226619] EIP is at __sco_sock_close+0xe8/0x1a0 <4>[11340.226629] EAX: f063a740 EBX: ECX: f58f4544 EDX: <4>[11340.226640] ESI: dec83e00 EDI: 5f9a081f EBP: e0fdff38 ESP: e0fdff1c <0>[11340.226674] Stack: <4>[11340.226682] c184db87 c1251028 dec83e00 e0fdff38 c1754aef dec83e00 e0fdff5c <4>[11340.226718] c184f587 e0fdff64 e0fdff68 5f9a081f e0fdff5c c1751852 d7813800 62262f10 <4>[11340.226752] e0fdff70 c1753c00 0001 000d e0fdffac c175425c 0041 <0>[11340.226793] Call Trace: <4>[11340.226813] [] ? sco_sock_clear_timer+0x27/0x60 <4>[11340.226831] [] ? local_bh_enable+0x68/0xd0 <4>[11340.226846] [] ? lock_sock_nested+0x4f/0x60 <4>[11340.226862] [] sco_sock_shutdown+0x67/0xb0 <4>[11340.226879] [] ? sockfd_lookup_light+0x22/0x80 <4>[11340.226897] [] sys_shutdown+0x30/0x60 <4>[11340.226912] [] sys_socketcall+0x1dc/0x2a0 <4>[11340.226929] [] ? trace_hardirqs_on_thunk+0xc/0x10 <4>[11340.226944] [] syscall_call+0x7/0xb <4>[11340.226960] [] ? restore_cur+0x5e/0xd7 <0>[11340.226969] Code: ff 4b 08 0f 94 c0 84 c0 74 20 80 7b 19 01 74 2f b8 0a 00 00 Disassemble the code: base address of __sco_sock_close is 0xc184f410 0xc184f4f8 <+232>: lock decl 0x8(%ebx) < == crash here, ebx is 0x0, the related source code is: (gdb) l *0xc184f4f8 0xc184f4f8 is in __sco_sock_close (arch/x86/include/asm/atomic.h:123) 119 static inline int atomic_dec_and_test(atomic_t *v) 123 asm volatile(LOCK_PREFIX "decl %0; sete %1" The whole call stack is: sys_shutdown() sco_sock_shutdown() __sco_sock_close() hci_conn_put() atomic_dec_and_test() Due to the conn->hcon is NULL, and the member hcon->refcnt is at offset 0x8, so "BUG: unable to handle kernel NULL pointer dereference at 0008" appears. Here fix it that adding the condition if conn->hcon is NULL, just like in sco_chan_del(). Signed-off-by: liu chuansheng --- net/bluetooth/sco.c |6 -- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 531a93d..190f70c 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -355,8 +355,10 @@ static void __sco_sock_close(struct sock *sk) if (sco_pi(sk)->conn) { sk->sk_state = BT_DISCONN; sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT); - hci_conn_put(sco_pi(sk)->conn->hcon); - sco_pi(sk)->conn->hcon = NULL; + if (sco_pi(sk)->conn->hcon) { + hci_conn_put(sco_pi(sk)->conn->hcon); + sco_pi(sk)->conn->hcon = NULL; + } } else sco_chan_del(sk, ECONNRESET); break; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] mfd, TWL4030: TWL4030 need select REGMAP_I2C
This patch fix the below build error: drivers/built-in.o: In function `twl_probe': drivers/mfd/twl-core.c:1256: undefined reference to `devm_regmap_init_i2c' make: *** [vmlinux] Error 1 Signed-off-by: liu chuansheng --- drivers/mfd/Kconfig |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1c0abd4..47ad4e2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -292,6 +292,7 @@ config TWL4030_CORE bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" depends on I2C=y && GENERIC_HARDIRQS select IRQ_DOMAIN + select REGMAP_I2C help Say yes here if you have TWL4030 / TWL6030 family chip on your board. This core driver provides register access and IRQ handling -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ASoC: core: giving WARN when device starting from non-off bias with idle_bias_off
Just found some cases that some codec drivers set the bias to _STANDBY and set idle_bias_off to 1 during probing. It will cause unpaired runtime_get_sync/put() issue. Also as Mark suggested, there is no reason to start from _STANDBY bias with idle_bias_off == 1. So here giving one warning when detected (dapm.idle_bias_off == 1) and (dapm.bias_level != SND_SOC_BIAS_OFF) just after driver->probe(). Signed-off-by: liu chuansheng --- sound/soc/soc-core.c |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9c768bc..d7ec007 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1107,6 +1107,10 @@ static int soc_probe_codec(struct snd_soc_card *card, "ASoC: failed to probe CODEC %d\n", ret); goto err_probe; } + WARN(codec->dapm.idle_bias_off && + codec->dapm.bias_level != SND_SOC_BIAS_OFF, + "codec %s can not start from non-off bias" + " with idle_bias_off==1\n", codec->name); } /* If the driver didn't set I/O up try regmap */ -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] mmc: sdio: Removing the unnecessary runtime_get/put in sdio_bus_remove()
The runtime_get_sync() is called during sdio_bus_probe(), then the device will be kept in active runtime state, so not neccessary to call runtime_get_sync/put_noidle() again in sdio_bus_remove(). Signed-off-by: liu chuansheng --- drivers/mmc/core/sdio_bus.c |8 1 files changed, 0 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 5e57048..b576b70 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -167,10 +167,6 @@ static int sdio_bus_remove(struct device *dev) struct sdio_func *func = dev_to_sdio_func(dev); int ret = 0; - /* Make sure card is powered before invoking ->remove() */ - if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) - pm_runtime_get_sync(dev); - drv->remove(func); if (func->irq_handler) { @@ -181,10 +177,6 @@ static int sdio_bus_remove(struct device *dev) sdio_release_host(func); } - /* First, undo the increment made directly above */ - if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) - pm_runtime_put_noidle(dev); - /* Then undo the runtime PM settings in sdio_bus_probe() */ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) pm_runtime_put_sync(dev); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ASoC: dapm: Fix the unpaired runtime_get/put cases
Commit f1aac484f7(Take a pm_runtime reference on DAPM devices that are enabled) introduced runtime_get/put calling when devices are in off/non-off bias. It is based on: 1/ device from off to non-off bias is called thru dapm_pre_sequence_async; 2/ device from non-off to off bias is called thru dapm_post_sequence_async; There are the above conditions which then make sure runtime_get/put() are pairs. But some devices has been set to STANDY bias directly during device probing, such as cs42l73_probe(): cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); Then it will cause runtime_get() not be called but laterly runtime_put() will be called. Also found some other uppaired cases. So here add new flag get_runtime, and the logic will be: 1/ when device is from off to non-off bias, runtime_get() will be called if not yet; 2/ When device is off bias, runtime_put() will be called if runtime_get() has been called; Signed-off-by: liu chuansheng --- include/sound/soc-dapm.h |1 + sound/soc/soc-dapm.c | 18 -- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index e1ef63d..e52fdcc 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -586,6 +586,7 @@ struct snd_soc_dapm_context { struct list_head list; int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); + bool get_runtime; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_dapm; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1e36bc8..e6d030a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1460,12 +1460,15 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) struct snd_soc_dapm_context *d = data; int ret; + if ((d->target_bias_level != SND_SOC_BIAS_OFF) && + (d->dev) && !(d->get_runtime)) { + pm_runtime_get_sync(d->dev); + d->get_runtime = true; + } + /* If we're off and we're not supposed to be go into STANDBY */ if (d->bias_level == SND_SOC_BIAS_OFF && d->target_bias_level != SND_SOC_BIAS_OFF) { - if (d->dev) - pm_runtime_get_sync(d->dev); - ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); if (ret != 0) dev_err(d->dev, @@ -1506,9 +1509,6 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) if (ret != 0) dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n", ret); - - if (d->dev) - pm_runtime_put(d->dev); } /* If we just powered up then move to active bias */ @@ -1519,6 +1519,12 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n", ret); } + + if ((d->bias_level == SND_SOC_BIAS_OFF) && + (d->dev) && (d->get_runtime)) { + pm_runtime_put(d->dev); + d->get_runtime = false; + } } static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer, -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] smpboot: calling smpboot_register_percpu_thread is unsafe during one CPU being down
When one CPU is going down, and smpboot_register_percpu_thread is called, there is the race issue below: T1(CPUA): T2(CPUB): _cpu_down()smpboot_register_percpu_thread() smpboot_park_threads() ... __stop_machine() __smpboot_create_thread(CPU_Dying) [Currently, the being down CPU is online yet] take_cpu_down() smpboot_unpark_thread(CPU_Dying) __cpu_disable() native_cpu_disable() Here the new kthread will get running based on the CPU_Dying set_cpu_online(cpu, false) cpu_notify(CPU_DYING) After notified the CPU_DYING, the new created kthead for dying CPU will be migrated to another CPU in migration_call(). Here we need use get_online_cpus()/put_online_cpus() when calling function smpboot_register_percpu_thread(). Signed-off-by: liu chuansheng --- kernel/smpboot.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/kernel/smpboot.c b/kernel/smpboot.c index d6c5fc0..3fe708a 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c @@ -266,6 +266,7 @@ int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) unsigned int cpu; int ret = 0; + get_online_cpus(); mutex_lock(&smpboot_threads_lock); for_each_online_cpu(cpu) { ret = __smpboot_create_thread(plug_thread, cpu); @@ -278,6 +279,7 @@ int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) list_add(&plug_thread->list, &hotplug_threads); out: mutex_unlock(&smpboot_threads_lock); + put_online_cpus(); return ret; } EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] watchdog: store the watchdog sample period as a variable
Currently getting the sample period is always thru complex calculation: get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5). But just like the watchdog_thresh, which is not changed often. So we can store the sample period as a variable, and set it as __read_mostly type. Signed-off-by: liu chuansheng --- kernel/watchdog.c | 13 - 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index dd4b80a..7a32b20 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -31,6 +31,7 @@ int watchdog_enabled = 1; int __read_mostly watchdog_thresh = 10; static int __read_mostly watchdog_disabled; +static u64 __read_mostly sample_period; static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts); static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog); @@ -116,7 +117,7 @@ static unsigned long get_timestamp(int this_cpu) return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */ } -static u64 get_sample_period(void) +static void set_sample_period(void) { /* * convert watchdog_thresh from seconds to ns @@ -125,7 +126,7 @@ static u64 get_sample_period(void) * and hard thresholds) to increment before the * hardlockup detector generates a warning */ - return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5); + sample_period = get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5); } /* Commands for resetting the watchdog */ @@ -275,7 +276,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) wake_up_process(__this_cpu_read(softlockup_watchdog)); /* .. and repeat */ - hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period())); + hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period)); if (touch_ts == 0) { if (unlikely(__this_cpu_read(softlockup_touch_sync))) { @@ -356,7 +357,7 @@ static void watchdog_enable(unsigned int cpu) hrtimer->function = watchdog_timer_fn; /* done here because hrtimer_start can only pin to smp_processor_id() */ - hrtimer_start(hrtimer, ns_to_ktime(get_sample_period()), + hrtimer_start(hrtimer, ns_to_ktime(sample_period), HRTIMER_MODE_REL_PINNED); /* initialize timestamp */ @@ -383,7 +384,7 @@ static int watchdog_should_run(unsigned int cpu) /* * The watchdog thread function - touches the timestamp. * - * It only runs once every get_sample_period() seconds (4 seconds by + * It only runs once every sample_period seconds (4 seconds by * default) to reset the softlockup timestamp. If this gets delayed * for more than 2*watchdog_thresh seconds then the debug-printout * triggers in watchdog_timer_fn(). @@ -516,6 +517,7 @@ int proc_dowatchdog(struct ctl_table *table, int write, if (ret || !write) return ret; + set_sample_period(); if (watchdog_enabled && watchdog_thresh) watchdog_enable_all_cpus(); else @@ -537,6 +539,7 @@ static struct smp_hotplug_thread watchdog_threads = { void __init lockup_detector_init(void) { + set_sample_period(); if (smpboot_register_percpu_thread(&watchdog_threads)) { pr_err("Failed to create watchdog threads, disabled\n"); watchdog_disabled = -ENODEV; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] watchdog: optimizing the hrtimer interval for power saving
By default, the watchdog threshold is 10, it means every 4s every CPU will receive one hrtimer interrupt, for low power device, it will cause 4-5mV power impact when device is deep sleep. So here want to optimize it as below: 4s + 4s + 4s + 4s + 4s == > 1s + 9s + 9s ... Or 1s + 1s..+ 9s + 9s For soft lockup detection, it will have more than 5 chances to hit, once one chance is successful, we will start 9s hrtimer instead of 1s; For hard lockup dection, it will have more than 2 chances to hit, As Don said, the min window is 10s just when CPU is always running as MAX frequency. In most case, the window is 60s, so we should have much more than 2 chances. With this patch, in most cases the hrtimer will be 9s instead of 4s averagely. It can save the device power indeed. Change log: Since V1: In V1, Don pointed out, "12 seconds will miss the window repeatedly." So here set the long period < min window 10s. Signed-off-by: liu chuansheng --- kernel/watchdog.c | 30 -- 1 files changed, 28 insertions(+), 2 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index dd4b80a..b37d682 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -125,7 +125,24 @@ static u64 get_sample_period(void) * and hard thresholds) to increment before the * hardlockup detector generates a warning */ - return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5); + return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 20); +} + +static u64 get_long_sample_period(void) +{ + /* +* convert watchdog_thresh from seconds to ns +* We want to give 5 chances to detect softlockup, +* for power saving, once one chance is succeeding, +* we can set long period to avoid power consumption. +* Currently, set the long sample period is: +* 9s = 10s - 1s, the reason is for covering the window +* of nmi interrupt 10s interval. +* So at least, for hard lockup, it has >=2 chances, +* for soft lockup, it has >= 5 chances. +* +*/ + return (watchdog_thresh * (u64)NSEC_PER_SEC) - get_sample_period(); } /* Commands for resetting the watchdog */ @@ -267,6 +284,10 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts); struct pt_regs *regs = get_irq_regs(); int duration; + bool is_touched; + + is_touched = (__this_cpu_read(hrtimer_interrupts) == + __this_cpu_read(soft_lockup_hrtimer_cnt)); /* kick the hardlockup detector */ watchdog_interrupt_count(); @@ -275,7 +296,12 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) wake_up_process(__this_cpu_read(softlockup_watchdog)); /* .. and repeat */ - hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period())); + if (is_touched) { + hrtimer_forward_now(hrtimer, + ns_to_ktime(get_long_sample_period())); + } else { + hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period())); + } if (touch_ts == 0) { if (unlikely(__this_cpu_read(softlockup_touch_sync))) { -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] watchdog: optimizing the hrtimer interval for power saving
By default, the watchdog threshold is 10, it means every 4s every CPU will receive one hrtimer interrupt, for low power device, it will cause 4-5mV power impact when device is deep sleep. So here want to optimize it as below: 4s + 4s + 4s + 4s + 4s == > 12s + 2s + 2s + 2s + 2s 3/5 1/10 1/10 1/10 1/10 In 5 chances, once one chance is hit, then we can start the hrtimer with a longer period sample(12s). Until the current chance is not hit, will start the hrtimer with a shorted period sample(2s). With this patch, in most case the hrtimer will be 12s instead of 4s averagely. It can save the device power indeed. Signed-off-by: liu chuansheng --- kernel/watchdog.c | 30 -- 1 files changed, 28 insertions(+), 2 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index dd4b80a..6457e62 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -125,7 +125,24 @@ static u64 get_sample_period(void) * and hard thresholds) to increment before the * hardlockup detector generates a warning */ - return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5); + return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 10); +} + +static u64 get_long_sample_period(void) +{ + /* +* convert watchdog_thresh from seconds to ns +* We want to give 5 chances to detect softlockup, +* for power saving, once one chance is succeeding, +* we can set long period to avoid power consumption. +* Currently, set the long sample period is: +* 20s * 3/5 = 12s, once this 12s chance is not hit, +* we will divide the left 8s into 4 pieces, give every +* chance every 2s, so it will be likely: +* 12s + 2s + 2s + 2s + 2s, +* Anyway, we just use 12s is enough in normal case. +*/ + return get_softlockup_thresh() * ((u64)NSEC_PER_SEC * 3 / 5); } /* Commands for resetting the watchdog */ @@ -267,6 +284,10 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts); struct pt_regs *regs = get_irq_regs(); int duration; + bool is_touched; + + is_touched = (__this_cpu_read(hrtimer_interrupts) == + __this_cpu_read(soft_lockup_hrtimer_cnt)); /* kick the hardlockup detector */ watchdog_interrupt_count(); @@ -275,7 +296,12 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) wake_up_process(__this_cpu_read(softlockup_watchdog)); /* .. and repeat */ - hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period())); + if (is_touched) { + hrtimer_forward_now(hrtimer, + ns_to_ktime(get_long_sample_period())); + } else { + hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period())); + } if (touch_ts == 0) { if (unlikely(__this_cpu_read(softlockup_touch_sync))) { -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] watchdog: using u64 in get_sample_period()
In get_sample_period(), unsigned long is not enough: watchdog_thresh * 2 * (NSEC_PER_SEC / 5) case1: watchdog_thresh is 10 by default, the sample value will be: 0xEE6B 2800 case2: set watchdog_thresh is 20, the sample value will be: 0x1 DCD6 5000 >From case2, we need use u64 to express the sample period. Otherwise, Changing the threshold thru proc often can not be successful. Signed-off-by: liu chuansheng --- kernel/watchdog.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 9d4c8d5..dd4b80a 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -116,7 +116,7 @@ static unsigned long get_timestamp(int this_cpu) return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */ } -static unsigned long get_sample_period(void) +static u64 get_sample_period(void) { /* * convert watchdog_thresh from seconds to ns @@ -125,7 +125,7 @@ static unsigned long get_sample_period(void) * and hard thresholds) to increment before the * hardlockup detector generates a warning */ - return get_softlockup_thresh() * (NSEC_PER_SEC / 5); + return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5); } /* Commands for resetting the watchdog */ -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] mmc,sdio: advancing the setting of dev name in mmc_sdio_init_card()
In below call trace: mmc_rescan -> mmc_rescan_try_freq() -> mmc_attach_sdio() -> mmc_sdio_init_card() ... pm_runtime_set_active() ... mmc_add_card() The dev name is set until in mmc_add_card(), but before that, it is possible the dev name is needed, for example in pm_runtime_set_active(), we can call trace event to trace which dev is changing the runtime status. So here advance it into mmc_sdio_init_card() to benefit others. Signed-off-by: liu chuansheng --- drivers/mmc/core/bus.c |5 +++-- drivers/mmc/core/sdio.c |5 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 9b68933..4884d6e 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -270,8 +270,9 @@ int mmc_add_card(struct mmc_card *card) [UHS_DDR50_BUS_SPEED] = "DDR50 ", }; - - dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca); + if (!dev_name(&card->dev)) + dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), + card->rca); switch (card->type) { case MMC_TYPE_MMC: diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2273ce6..a9f6f02 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -795,8 +795,11 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, goto remove; } finish: - if (!oldcard) + if (!oldcard) { host->card = card; + dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), + card->rca); + } return 0; remove: -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] mmc,sdio: Fix the panic due to devname NULL when calling pm_runtime_set_active()
Subject: [PATCH] mmc,sdio: Fix the panic due to devname NULL when calling pm_runtime_set_active() Meet one panic as the below: <1>[ 15.067350] BUG: unable to handle kernel NULL pointer dereference at (null) <1>[ 15.074455] IP: [] strlen+0x12/0x20 <4>[ 15.078803] *pde = <0>[ 15.081674] Oops: [#1] PREEMPT SMP <4>[ 15.101676] Pid: 5, comm: kworker/u:0 Tainted: G C 3.0.34-140729-g7f9d5c5 #1 Intel Corporation Medfield/BKB2 <4>[ 15.112282] EIP: 0060:[] EFLAGS: 00010046 CPU: 0 <4>[ 15.117760] EIP is at strlen+0x12/0x20 <4>[ 15.121496] EAX: EBX: f344cc04 ECX: EDX: f344cc04 <4>[ 15.127754] ESI: c12bcee0 EDI: EBP: f586fe74 ESP: f586fe70 <4>[ 15.134013] DS: 007b ES: 007b FS: 00d8 GS: SS: 0068 <0>[ 15.139406] Process kworker/u:0 (pid: 5, ti=f586e000 task=f585b440 task.ti=f586e000) <0>[ 15.147140] Stack: <4>[ 15.149141] f344cc04 f586feb0 c12bcf12 f586fe9c 0007 0082 <4>[ 15.156877] 0092 0002 c1b01ee4 f586feb8 c1635f31 f3b42330 c12bcee0 f344cc04 <4>[ 15.164616] f586fed0 c152f815 f3b42330 f3b42328 f344cc04 f589b804 <0>[ 15.172351] Call Trace: <4>[ 15.174810] [] ftrace_raw_event_runtime_pm_status+0x32/0x140 <4>[ 15.181411] [] ? sdio_enable_wide.part.8+0x61/0x80 <4>[ 15.187145] [] ? perf_trace_runtime_pm_usage+0x1a0/0x1a0 <4>[ 15.193407] [] __update_runtime_status+0x65/0x90 <4>[ 15.198968] [] __pm_runtime_set_status+0xe0/0x1b0 <4>[ 15.204621] [] mmc_attach_sdio+0x2f6/0x410 <4>[ 15.209666] [] mmc_rescan+0x240/0x2b0 <4>[ 15.214270] [] process_one_work+0xfe/0x3f0 <4>[ 15.219311] [] ? wake_up_process+0x14/0x20 <4>[ 15.224357] [] ? mmc_detect_card_removed+0x80/0x80 <4>[ 15.230091] [] worker_thread+0x121/0x2f0 <4>[ 15.234958] [] ? rescuer_thread+0x1e0/0x1e0 <4>[ 15.240091] [] kthread+0x6d/0x80 <4>[ 15.244264] [] ? __init_kthread_worker+0x30/0x30 <4>[ 15.245485] [] kernel_thread_helper+0x6/0x10 The reason is pm_runtime_set_active() is called before the device name is set, and the dev name setting is done at mmc_add_card() laterly. So when calling pm_runtime_set_active(), it will hit the strlen(devname==0) which trigger the panic. Here before calling pm_runtime_set_active(), set the dev name, although it is duplicated with mmc_add_card(), but it do not break the original design(commit 81968561b). Signed-off-by: liu chuansheng --- drivers/mmc/core/sdio.c |9 + 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2273ce6..73746af 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1104,6 +1104,15 @@ int mmc_attach_sdio(struct mmc_host *host) */ if (host->caps & MMC_CAP_POWER_OFF_CARD) { /* +* pm_runtime_set_active will use strlen(dev_name), +* we must set it in advance to avoid crash, +* although it is the duplication in mmc_add_card +* laterly. +*/ + dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), + card->rca); + + /* * Let runtime PM core know our card is active */ err = pm_runtime_set_active(&card->dev); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] x86/irq,io_apic: Fix wrong unmask_ioapic calling when the irq is masked
There is one typical case will cause this issue, that is: One io-apic interrupt with ONE_SHOT and threaded, when interrupt is coming: handle_fasteoi_irq() --> mask_irq(desc) ... desc->irq_data.chip->irq_eoi(&desc->irq_data)[ack_apic_level] --> ioapic_irqd_mask() ... ioapic_irqd_unmask() After that, the irq will be in unmasked state. It will break the ONE_SHOT and threaded irq, and brings some unwanted issues. Here adding the irqd_irq_masked() condition to know if unmasking action is needed. Signed-off-by: liu chuansheng --- arch/x86/kernel/apic/io_apic.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 1817fa9..d963e76 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2479,7 +2479,8 @@ static inline void ioapic_irqd_unmask(struct irq_data *data, */ if (!io_apic_level_ack_pending(cfg)) irq_move_masked_irq(data); - unmask_ioapic(cfg); + if (!irqd_irq_masked(data)) + unmask_ioapic(cfg); } } #else -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/