Skip to contentSkip to conversation

cpufreq: Add sfi based cpufreq driver support

PATCH Superseded Srinidhi Kasagar 2 participants 3 messages Oct 15, 2014 – Oct 17, 2014 CPU frequency scaling framework

v2 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 cpufreq: Add sfi based cpufreq driver support

This adds the sfi based cpu freq driver for some of the Intel's Silver Mont based atom architectures like Merrifield and Moorfield (intel-mid)

---
 drivers/cpufreq/Kconfig.x86   |   10 ++
 drivers/cpufreq/Makefile      |    1 +
 drivers/cpufreq/sfi-cpufreq.c |  332 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 343 insertions(+)
 create mode 100644 drivers/cpufreq/sfi-cpufreq.c
drivers/cpufreq/Kconfig.x86 +10 -0
index 89ae88f91895..2bca6a5dcffd 100644
@@ -57,6 +57,16 @@ config X86_ACPI_CPUFREQ_CPB
 	  By enabling this option the acpi_cpufreq driver provides the old
 	  entry in addition to the new boost ones, for compatibility reasons.
 
+config X86_SFI_CPUFREQ
+	tristate "SFI Processor P-States driver"
+	depends on X86_INTEL_MID && SFI
+	help
+	  This adds a CPUFreq driver for some Silver Mont based Intel
+	  Atom platforms (like INTEL_MID) which utilizes the SFI based
+	  processor performance states.
+
+	  If in doubt, say N.
+
 config ELAN_CPUFREQ
 	tristate "AMD Elan SC400 and SC410"
 	depends on MELAN
drivers/cpufreq/Makefile +1 -0
index db6d9a2fea4d..c3b51efd4a85 100644
@@ -41,6 +41,7 @@ obj-$(CONFIG_X86_P4_CLOCKMOD)		+= p4-clockmod.o
 obj-$(CONFIG_X86_CPUFREQ_NFORCE2)	+= cpufreq-nforce2.o
 obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
 obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY)	+= amd_freq_sensitivity.o
+obj-$(CONFIG_X86_SFI_CPUFREQ)		+= sfi-cpufreq.o
 
 ##################################################################################
 # ARM SoC drivers
drivers/cpufreq/sfi-cpufreq.c new file +332 -0

332 lines not on this page · raw message

Signature · 4 lines
1.7.9.5


-- 
maintainer
#1 lore raw
Quoted 7 lines · Srinidhi Kasagar

This adds the sfi based cpu freq driver for some of the Intel's Silver Mont based atom architectures like Merrifield and Moorfield (intel-mid)

---

Always good to let people know what changed from previous version.

drivers/cpufreq/sfi-cpufreq.c line 179

Quoted 9 lines
drivers/cpufreq/sfi-cpufreq.c +8 -0
+static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
+{
+       struct sfi_cpufreq_data *data = per_cpu(drv_data, cpu);
+       unsigned int cached_freq;
+
+       pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
+
+       cached_freq = data->freq_table[data->sfi_data->state].frequency;

Are you sure cached_freq is used at all ? And if not, then you don't need to pass 'data' in exact_freq(), just get it there..

Quoted 11 lines
drivers/cpufreq/sfi-cpufreq.c +11 -0
+       return extract_freq(get_cur_val(cpumask_of(cpu)), data);
+
+}
+
+static int sfi_cpufreq_target(struct cpufreq_policy *policy,
+                               unsigned int index)
+{
+       struct sfi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+       struct sfi_processor_performance *perf;
+       unsigned int next_perf_state = 0; /* Index into perf table */
+       u32 lo, hi;

drivers/cpufreq/sfi-cpufreq.c line 201

Quoted 10 lines
drivers/cpufreq/sfi-cpufreq.c +10 -0
+
+       perf = data->sfi_data;
+       next_perf_state = data->freq_table[index].driver_data;
+
+       rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi);
+       lo = (lo & ~INTEL_MSR_RANGE) |
+               ((u32) perf->states[next_perf_state].control & INTEL_MSR_RANGE);
+       wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi);
+
+       perf->state = next_perf_state;

This looks much better now :)

drivers/cpufreq/sfi-cpufreq.c line 213

Quoted 11 lines
drivers/cpufreq/sfi-cpufreq.c +11 -0
+       return 0;
+}
+
+static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       unsigned int i, result = 0, valid_states = 0;
+       unsigned int cpu = policy->cpu;
+       struct sfi_cpufreq_data *data;
+       struct sfi_processor_performance *perf;
+
+       pr_debug("%s: CPU:%d\n", __func__, policy->cpu);

Use cpu here instead of policy->cpu ?

Quoted 40 lines
drivers/cpufreq/sfi-cpufreq.c +40 -0
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->sfi_data = per_cpu_ptr(sfi_perf_data, cpu);
+       per_cpu(drv_data, cpu) = data;
+
+       result = sfi_processor_register_performance(data->sfi_data);
+       if (result)
+               goto err_free;
+
+       perf = data->sfi_data;
+       policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
+
+       /* capability check */
+       if (perf->state_count <= 1) {
+               pr_debug("No P-States\n");
+               result = -ENODEV;
+               goto err_unreg;
+       }
+
+       data->freq_table = kzalloc(sizeof(*data->freq_table) *
+                               (perf->state_count+1), GFP_KERNEL);
+       if (!data->freq_table) {
+               result = -ENOMEM;
+               goto err_unreg;
+       }
+
+       /* detect transition latency */
+       policy->cpuinfo.transition_latency = 0;
+       for (i = 0; i < perf->state_count; i++) {
+               if ((perf->states[i].transition_latency * 1000) >
+                   policy->cpuinfo.transition_latency)
+                       policy->cpuinfo.transition_latency =
+                           perf->states[i].transition_latency * 1000;
+
+               pr_debug("     %cP%d: %d MHz, %d uS\n",
+                       (i == perf->state ? '*' : ' '), i,
+                       (u32) perf->states[i].core_frequency,

drivers/cpufreq/sfi-cpufreq.c line 263

Quoted 10 lines
drivers/cpufreq/sfi-cpufreq.c +10 -0
+                       (u32) perf->states[i].transition_latency);
+       }
+
+       /* initialize the freq table */
+       for (i = 0; i < perf->state_count; i++) {
+               data->freq_table[valid_states].driver_data = i;
+               data->freq_table[valid_states].frequency =
+                   perf->states[i].core_frequency * 1000;
+               valid_states++;
+       }

Why not merge both 'for' loops?

Quoted 59 lines
drivers/cpufreq/sfi-cpufreq.c +59 -0
+       data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
+       perf->state = 0;
+
+       result = cpufreq_table_validate_and_show(policy, data->freq_table);
+       if (result)
+               goto err_freqfree;
+
+       pr_debug("CPU%u - SFI performance management activated.\n", cpu);
+
+       return result;
+
+err_freqfree:
+       kfree(data->freq_table);
+err_unreg:
+       sfi_processor_unregister_performance(perf);
+err_free:
+       kfree(data);
+       per_cpu(drv_data, cpu) = NULL;
+
+       return result;
+}
+
+static int sfi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+       struct sfi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
+
+       pr_debug("sfi_cpufreq_cpu_exit\n");
+
+       per_cpu(drv_data, policy->cpu) = NULL;
+       sfi_processor_unregister_performance(data->sfi_data);
+       kfree(data->freq_table);
+       kfree(data);
+
+       return 0;
+}
+
+static struct cpufreq_driver sfi_cpufreq_driver = {
+       .flags          = CPUFREQ_CONST_LOOPS,
+       .get            = get_cur_freq_on_cpu,
+       .verify         = cpufreq_generic_frequency_table_verify,
+       .target_index   = sfi_cpufreq_target,
+       .init           = sfi_cpufreq_cpu_init,
+       .exit           = sfi_cpufreq_cpu_exit,
+       .name           = "sfi-cpufreq",
+       .attr           = cpufreq_generic_attr,
+};
+
+static int __init sfi_cpufreq_init(void)
+{
+       sfi_perf_data = alloc_percpu(struct sfi_processor_performance);
+       if (!sfi_perf_data) {
+               pr_err("Memory allocation error for sfi_perf_data.\n");
+               return -ENOMEM;
+       }
+
+       return cpufreq_register_driver(&sfi_cpufreq_driver);
+}
+late_initcall(sfi_cpufreq_init);
+

drivers/cpufreq/sfi-cpufreq.c line 332

Quoted 10 lines
drivers/cpufreq/sfi-cpufreq.c +10 -0
+static void __exit sfi_cpufreq_exit(void)
+{
+       cpufreq_unregister_driver(&sfi_cpufreq_driver);
+       free_percpu(sfi_perf_data);
+}
+module_exit(sfi_cpufreq_exit);
+
+MODULE_AUTHOR("Vishwesh M Rudramuni <[email protected]>");
+MODULE_DESCRIPTION("SFI P-States Driver");
+MODULE_LICENSE("GPL");

Looks fine otherwise.

#2 lore raw
Quoted 10 lines · Viresh Kumar
Quoted 7 lines · Srinidhi Kasagar

This adds the sfi based cpu freq driver for some of the Intel's Silver Mont based atom architectures like Merrifield and Moorfield (intel-mid)

---

Always good to let people know what changed from previous version.

Thanks much Viresh. I will respin the patch with the rest of your comments.

Srinidhi