Subject: [CPUFREQ]: Add the suspend/resume flag to avoid smp_call in cpufreq_suspend/resume From: Zhao Yakui <yakui.zhao@xxxxxxxxx> Only CPU0 is available in course of cpufreq_suspend/resume. So it is unnecessary to do the smp_call for getting the current cpufreq. Add a flag of suspend/resume to avoid the smp_call in course of cpufreq_suspend/resume. http://bugzilla.kernel.org/show_bug.cgi?id=13781 http://bugzilla.kernel.org/show_bug.cgi?id=13269 Signed-off-by: Zhao Yakui <yakui.zhao@xxxxxxxxx> Tested-by: Christian Casteyde<casteyde.christian@xxxxxxx> --- arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 24 +++++++++++++++++++++--- arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 13 ++++++++++++- arch/x86/kernel/cpu/cpufreq/speedstep-ich.c | 12 ++++++++++-- drivers/cpufreq/cpufreq.c | 7 +++++++ include/linux/cpufreq.h | 2 ++ 5 files changed, 52 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/cpufreq/cpufreq.c =================================================================== --- linux-2.6.orig/drivers/cpufreq/cpufreq.c 2009-07-23 09:23:36.000000000 +0800 +++ linux-2.6/drivers/cpufreq/cpufreq.c 2009-07-24 09:08:27.000000000 +0800 @@ -1266,6 +1266,9 @@ /* only handle each CPU group once */ if (unlikely(cpu_policy->cpu != cpu)) goto out; + /* Set the flag of suspend/resume */ + if (!cpufreq_driver->suspend_resume) + cpufreq_driver->suspend_resume = 1; if (cpufreq_driver->suspend) { ret = cpufreq_driver->suspend(cpu_policy, pmsg); @@ -1391,6 +1394,10 @@ schedule_work(&cpu_policy->update); fail: cpufreq_cpu_put(cpu_policy); + /* clear the flag of suspend/resume */ + if (cpufreq_driver->suspend_resume) + cpufreq_driver->suspend_resume = 0; + return ret; } Index: linux-2.6/include/linux/cpufreq.h =================================================================== --- linux-2.6.orig/include/linux/cpufreq.h 2009-07-09 13:03:11.000000000 +0800 +++ linux-2.6/include/linux/cpufreq.h 2009-07-24 09:08:27.000000000 +0800 @@ -234,6 +234,8 @@ int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg); int (*resume) (struct cpufreq_policy *policy); struct freq_attr **attr; + int suspend_resume; /* indicates whether it is + * suspend/resume */ }; /* flags */ Index: linux-2.6/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2009-07-09 13:07:06.000000000 +0800 +++ linux-2.6/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2009-07-24 09:08:27.000000000 +0800 @@ -197,19 +197,37 @@ static void drv_read(struct drv_cmd *cmd) { - cmd->val = 0; + struct cpufreq_driver *freq_driver; - smp_call_function_single(cpumask_any(cmd->mask), do_drv_read, cmd, 1); + freq_driver = &acpi_cpufreq_driver; + cmd->val = 0; + /* + * In fact only CPU0 is availabe in course of sysdev_suspend/resume. + * So do it on the current cpu directly + */ + if (!freq_driver->suspend_resume) + smp_call_function_single(cpumask_any(cmd->mask), + do_drv_read, cmd, 1); + else + do_drv_read(cmd); } static void drv_write(struct drv_cmd *cmd) { + struct cpufreq_driver *freq_driver; int this_cpu; this_cpu = get_cpu(); + freq_driver = &acpi_cpufreq_driver; if (cpumask_test_cpu(this_cpu, cmd->mask)) do_drv_write(cmd); - smp_call_function_many(cmd->mask, do_drv_write, cmd, 1); + + /* + * Only CPU0 is available in course of sysdev_suspend/resume. + * Don't use the smp call again when it is in suspend/resume. + */ + if (!freq_driver->suspend_resume) + smp_call_function_many(cmd->mask, do_drv_write, cmd, 1); put_cpu(); } Index: linux-2.6/arch/x86/kernel/cpu/cpufreq/powernow-k8.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/cpu/cpufreq/powernow-k8.c 2009-07-23 09:23:36.000000000 +0800 +++ linux-2.6/arch/x86/kernel/cpu/cpufreq/powernow-k8.c 2009-07-24 09:08:27.000000000 +0800 @@ -53,6 +53,7 @@ static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data); static int cpu_family = CPU_OPTERON; +static struct cpufreq_driver cpufreq_amd64_driver; #ifndef CONFIG_SMP static inline const struct cpumask *cpu_core_mask(int cpu) @@ -1388,11 +1389,21 @@ struct powernow_k8_data *data = per_cpu(powernow_data, cpu); unsigned int khz = 0; int err; + struct cpufreq_driver *freq_driver = &cpufreq_amd64_driver; if (!data) return -EINVAL; - smp_call_function_single(cpu, query_values_on_cpu, &err, true); + /* + * Only CPU0 is available in course of sysdev_suspend/resume. + * So do it on the current cpu directly in course of + * sysdev_suspend/resume. + */ + if (!freq_driver->suspend_resume) + smp_call_function_single(cpu, query_values_on_cpu, &err, true); + else + query_values_on_cpu(&err); + if (err) goto out; Index: linux-2.6/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c 2009-07-09 13:07:08.000000000 +0800 +++ linux-2.6/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c 2009-07-24 09:08:27.000000000 +0800 @@ -41,6 +41,8 @@ */ static unsigned int speedstep_processor; +static struct cpufreq_driver speedstep_driver; + static u32 pmbase; /* @@ -246,11 +248,17 @@ static unsigned int speedstep_get(unsigned int cpu) { + struct cpufreq_driver *freq_driver = &speedstep_driver; struct get_freq_data data = { .processor = cpu }; + /* In fact only CPU0 is available in course of sysdev_suspend/resume. + * So do it on the current cpu directly + */ + if (freq_driver->suspend_resume) + get_freq_data(&data); /* You're supposed to ensure CPU is online. */ - if (smp_call_function_single(cpu, get_freq_data, &data, 1) != 0) - BUG(); + else + smp_call_function_single(cpu, get_freq_data, &data, 1); dprintk("detected %u kHz as current frequency\n", data.speed); return data.speed; -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html