On Wed, Mar 6, 2013 at 10:25 AM, Guru Prasad <gurupras@xxxxxxxxxxx> wrote: > Hi Viresh, > > I think I found the problem in my code. > I made it a point to explicitly add CPUFREQ_TABLE_END as an entry in > my cpufreq_freq_table, but while calculating the steps between > min_freq and max_freq, I failed to allocate an extra step for the > CPUFREQ_TABLE_END entry. > This probably caused some segfault in the driver and it failed to init. > > Please find my code attached. > Since I'm not well versed in writing kernel code, I would appreciate > it if you could take a quick glace and pointed out the flaws > > I have followed used mach-integrator as a base to write this code. > > Thank you for your help. > > Regards > Guru > > > On Tue, Mar 5, 2013 at 7:31 PM, Viresh Kumar <viresh.kumar@xxxxxxxxxx> wrote: >> On 6 March 2013 01:28, Guru Prasad <gurupras@xxxxxxxxxxx> wrote: >>> What I mean is, every time i start the simulation with a new clock >>> frequency, I have my cpufreq_init function do the following >>> int steps; >>> policy->cpuinfo.max_freq = my_cpufreq_get(policy->cpu); //In KHz >>> policy->cpuinfo.min_freq = 100 * 1000; //In KHz >> >> You don't have to set these, but you just need to pass the right table >> to cpufreq core and call cpufreq_frequency_table_cpuinfo(). These would >> be set accordingly by this routine. >> >>> policy->cpuinfo.transition_latency = 10 * 1000; //In us >>> policy->cur = my_cpufreq_get(policy->cpu); //(I'm assuming that >>> the CPU frequency is always at the maximum before the driver takes >>> control.) >>> >>> >>> // Get the number of cpufreq steps - Each step is 200MHz >>> steps = get_cpufreq_steps(policy->cpuinfo.max_freq, >>> policy->cpuinfo.min_freq); >>> // Malloc the required space based on number of steps >>> dyn_cpufreq_table = kmalloc(sizeof(struct >>> cpufreq_frequency_table) * steps, GFP_KERNEL); >>> // Create entries in the table >>> create_freq_table(dyn_cpufreq_table, policy); >> >> That's okay, but i didn't get how will you get different set of >> freqs in your table when you boot up. >> >>> However, when I use this code, although my debug statements suggest >>> that the table is created successfully, sysfs shows no cpufreq under >>> /sys/devices/system/cpu/cpu0/ >> >> Something is wrong. And for finding out what, you need to post your code >> here, even if it is non-mainline-able. >> >> >>> Am I doing something wrong? Is GFP_KERNEL the wrong flag to use for >>> this purpose? >> >> That's not the culprit for sure.
/* * linux/arch/arm/mach-realview/cpufreq.c * * Copyright (C) 2012-2013 University at Buffalo. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * CPUfreq driver for the RealView platform */ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/cpufreq.h> #include <linux/sched.h> #include <linux/smp.h> #include <linux/init.h> #include <linux/io.h> #include <linux/slab.h> #include <mach/hardware.h> #include <mach/platform.h> #include <asm/mach-types.h> #include <asm/hardware/realview.h> static struct cpufreq_driver realview_driver; #define REALVIEW_ID IO_ADDRESS(REALVIEW_SYS_ID) #define REALVIEW_CPU IO_ADDRESS(REALVIEW_SYS_OSC3) #define REALVIEW_LOCK IO_ADDRESS(REALVIEW_SYS_LOCK) static struct cpufreq_frequency_table *realview_freq_table; /* static struct cpufreq_frequency_table realview_freq_table[] = { { 0, 100 * 1000 }, { 1, 200 * 1000 }, { 2, 400 * 1000 }, { 3, 800 * 1000 }, { 4, 1000 * 1000 }, { 5, 1200 * 1000 }, { 6, 1400 * 1000 }, { 7, 1800 * 1000 }, { 8, 2000 * 1000 }, { 9, CPUFREQ_TABLE_END }, }; */ /* * Gets number of steps between min_freq and max_freq * Each step is 200MHz * This is used for realview_init */ static int get_cpufreq_steps(struct cpufreq_policy * policy) { int min_freq = policy->cpuinfo.min_freq; int max_freq = policy->cpuinfo.max_freq; int freq = min_freq, steps = 0; while(freq <= max_freq) { freq += 200 * 1000; steps++; } /* * Explicit steps + 1 for * CPUFREQ_TABLE_END */ steps += 1; printk("Number of steps :%d\n", steps); return steps; } /* * Creates frequency table with steps of 200MHz */ static void create_freq_table(struct cpufreq_policy *policy) { int i = 0; int freq = policy->cpuinfo.min_freq; while(freq <= policy->cpuinfo.max_freq) { realview_freq_table[i].index = i; realview_freq_table[i].frequency = freq; freq += 200 * 1000; i++; } realview_freq_table[i].index = i; realview_freq_table[i].frequency = CPUFREQ_TABLE_END; i = 0; while(realview_freq_table[i].frequency != CPUFREQ_TABLE_END) { printk("realview_freq_table[%d] =%d\n", i, realview_freq_table[i].frequency); i++; } } static int realview_cpufreq_verify_speed(struct cpufreq_policy *policy) { if (policy->cpu != 0) return -EINVAL; return cpufreq_frequency_table_verify(policy, realview_freq_table); } /* * Validate the speed policy. */ static int realview_verify_policy(struct cpufreq_policy *policy) { printk("RealView CPUFreq policy verification\n"); cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); policy->max = (4000 * 1000) / 1000; //Pre-defined value of 4 GHz..Let's face it..nothing's going faster than that right now policy->min = (100 * 1000) / 1000; //Pre-defined value of 100MHz cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); return 0; } static int realview_set_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { cpumask_t cpus_allowed; int cpu = policy->cpu; struct cpufreq_freqs freqs; u_int current_freq; int i; int ret = cpufreq_frequency_table_target(policy, realview_freq_table, target_freq, relation, &i); if(ret != 0) return ret; // printk("realview_set_target :%u\n", realview_freq_table[i].frequency); /* * Save this threads cpus_allowed mask. */ cpus_allowed = current->cpus_allowed; /* * Bind to the specified CPU. When this call returns, * we should be running on the right CPU. */ set_cpus_allowed(current, cpumask_of_cpu(cpu)); BUG_ON(cpu != smp_processor_id()); /* get current setting */ current_freq = __raw_readl(REALVIEW_CPU); freqs.old = current_freq; freqs.new = realview_freq_table[i].frequency; freqs.cpu = policy->cpu; if (freqs.old == freqs.new) { set_cpus_allowed(current, cpus_allowed); return 0; } cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); current_freq = __raw_readl(REALVIEW_CPU); __raw_writel(0xA05F, REALVIEW_LOCK); __raw_writel(realview_freq_table[i].frequency, REALVIEW_CPU); __raw_writel(0, REALVIEW_LOCK); /* * Restore the CPUs allowed mask. */ set_cpus_allowed(current, cpus_allowed); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); return 0; } static unsigned int realview_get(unsigned int cpu) { cpumask_t cpus_allowed; unsigned int current_freq; cpus_allowed = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(cpu)); BUG_ON(cpu != smp_processor_id()); /* detect memory etc. */ current_freq = __raw_readl(REALVIEW_CPU); set_cpus_allowed(current, cpus_allowed); return current_freq; } static int realview_cpufreq_init(struct cpufreq_policy *policy) { int steps; /* set default policy and cpuinfo */ policy->cpuinfo.max_freq = realview_get(policy->cpu); //In KHz policy->cpuinfo.min_freq = 200 * 1000; //In KHz policy->cpuinfo.transition_latency = 100 * 1000; //In us policy->cur = policy->min = policy->max = realview_get(policy->cpu); steps = get_cpufreq_steps(policy); realview_freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * steps, GFP_KERNEL); create_freq_table(policy); cpufreq_frequency_table_cpuinfo(policy, realview_freq_table); return 0; } static struct cpufreq_driver realview_driver = { .owner = THIS_MODULE, .flags = 0, .verify = realview_cpufreq_verify_speed, .target = realview_set_target, .get = realview_get, .init = realview_cpufreq_init, .name = "realview", }; static int __init realview_cpu_init(void) { return cpufreq_register_driver(&realview_driver); } static void __exit realview_cpu_exit(void) { cpufreq_unregister_driver(&realview_driver); } MODULE_AUTHOR ("Guru Prasad"); MODULE_DESCRIPTION ("cpufreq driver for ARM RealView CPUs"); MODULE_LICENSE ("GPL"); module_init(realview_cpu_init); module_exit(realview_cpu_exit);