[PATCH] PCI: Add disabling pm async quirk for JMicron chips

2014-12-04 Thread Chuansheng Liu
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

2014-11-04 Thread Chuansheng Liu
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

2014-11-04 Thread Chuansheng Liu
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

2014-09-24 Thread Chuansheng Liu
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

2014-09-22 Thread Chuansheng Liu
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

2014-09-19 Thread tip-bot for Chuansheng Liu
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

2014-09-19 Thread tip-bot for Chuansheng Liu
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

2014-09-19 Thread tip-bot for Chuansheng Liu
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

2014-09-04 Thread Chuansheng Liu
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

2014-09-04 Thread Chuansheng Liu
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()

2014-09-04 Thread Chuansheng Liu
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

2014-08-31 Thread Chuansheng Liu
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

2014-08-18 Thread Chuansheng Liu
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()

2014-08-18 Thread Chuansheng Liu
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

2014-08-18 Thread Chuansheng Liu
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

2014-08-15 Thread Chuansheng Liu
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()

2014-08-15 Thread Chuansheng Liu
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

2014-08-15 Thread Chuansheng Liu
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

2014-08-13 Thread Chuansheng Liu
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()

2014-03-03 Thread Chuansheng Liu
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

2014-02-27 Thread tip-bot for Chuansheng Liu
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()

2014-02-26 Thread Chuansheng Liu
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

2014-02-23 Thread Chuansheng Liu
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

2014-02-19 Thread tip-bot for Chuansheng Liu
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

2014-02-17 Thread Chuansheng Liu
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

2014-02-17 Thread Chuansheng Liu
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

2014-02-17 Thread Chuansheng Liu
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

2014-02-17 Thread Chuansheng Liu
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

2014-02-17 Thread Chuansheng Liu
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

2014-02-17 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-16 Thread Chuansheng Liu
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

2014-02-10 Thread Chuansheng Liu
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

2014-02-10 Thread Chuansheng Liu
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

2014-01-15 Thread Chuansheng Liu

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

2014-01-13 Thread Chuansheng Liu

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()

2014-01-07 Thread Chuansheng Liu

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()

2014-01-07 Thread Chuansheng Liu

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()

2014-01-07 Thread Chuansheng Liu

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

2013-12-18 Thread tip-bot for Chuansheng Liu
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()

2013-12-17 Thread Chuansheng Liu

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()

2013-12-17 Thread Chuansheng Liu

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

2013-12-03 Thread Chuansheng Liu

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

2013-11-05 Thread Chuansheng Liu

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

2013-11-04 Thread Chuansheng Liu

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

2013-10-24 Thread Chuansheng Liu

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

2013-10-21 Thread Chuansheng Liu

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

2013-10-15 Thread Chuansheng Liu

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

2013-09-17 Thread Chuansheng Liu

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

2013-09-17 Thread Chuansheng Liu

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()

2013-09-11 Thread Chuansheng Liu

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

2013-09-10 Thread tip-bot for Chuansheng Liu
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()

2013-09-09 Thread Chuansheng Liu

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

2013-09-08 Thread Chuansheng Liu

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()

2013-08-25 Thread Chuansheng Liu

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

2013-04-09 Thread Chuansheng Liu

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()

2013-03-11 Thread Chuansheng Liu

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

2013-03-11 Thread Chuansheng Liu

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

2013-03-11 Thread Chuansheng Liu

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

2013-03-11 Thread Chuansheng Liu

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

2013-03-11 Thread Chuansheng Liu

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

2013-03-10 Thread Chuansheng Liu

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

2013-03-07 Thread Chuansheng Liu

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

2013-03-07 Thread Chuansheng Liu

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()

2013-03-07 Thread Chuansheng Liu

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

2013-03-07 Thread Chuansheng Liu
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

2013-03-06 Thread Chuansheng Liu

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

2013-02-15 Thread Chuansheng Liu
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

2013-02-15 Thread Chuansheng Liu

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()

2013-02-06 Thread tip-bot for Chuansheng Liu
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

2013-02-05 Thread Chuansheng Liu

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()

2013-01-31 Thread Chuansheng Liu

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()

2013-01-14 Thread Chuansheng Liu

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()

2013-01-14 Thread Chuansheng Liu

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

2013-01-09 Thread Chuansheng Liu

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()

2012-12-24 Thread Chuansheng Liu

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

2012-12-24 Thread Chuansheng Liu

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

2012-12-24 Thread Chuansheng Liu

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

2012-12-23 Thread Chuansheng Liu


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

2012-12-20 Thread Chuansheng Liu

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()

2012-12-18 Thread Chuansheng Liu

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

2012-12-18 Thread Chuansheng Liu

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

2012-12-10 Thread Chuansheng Liu

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

2012-12-03 Thread Chuansheng Liu

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

2012-11-27 Thread Chuansheng Liu

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

2012-11-22 Thread Chuansheng Liu

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()

2012-11-20 Thread Chuansheng Liu

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()

2012-11-19 Thread Chuansheng Liu

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()

2012-11-15 Thread Chuansheng Liu
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

2012-11-13 Thread Chuansheng Liu

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/


  1   2   >