Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[CELL] cbe_cpufreq: reorganize code

This patch reorganizes the code of the driver into three files.
Two cbe_cpufreq_pmi.c and cbe_cpufreq_pervasive.c care about hardware.
cbe_cpufreq.c contains the logic.
There is no changed behaviour, except that the PMI related function
is now located in a seperate module cbe_cpufreq_pmi. This module
will be required by cbe_cpufreq, if CONFIG_CBE_CPUFREQ_PMI has been set.

Signed-off-by: Christian Krafft <krafft@de.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

authored by

Christian Krafft and committed by
Arnd Bergmann
74889e41 1e21fd5a

+311 -190
+10
arch/powerpc/platforms/cell/Kconfig
··· 73 73 For details, take a look at <file:Documentation/cpu-freq/>. 74 74 If you don't have such processor, say N 75 75 76 + config CBE_CPUFREQ_PMI 77 + tristate "CBE frequency scaling using PMI interface" 78 + depends on CBE_CPUFREQ && PPC_PMI && EXPERIMENTAL 79 + default n 80 + help 81 + Select this, if you want to use the PMI interface 82 + to switch frequencies. Using PMI, the 83 + processor will not only be able to run at lower speed, 84 + but also at lower core voltage. 85 + 76 86 endmenu
+3 -1
arch/powerpc/platforms/cell/Makefile
··· 4 4 obj-$(CONFIG_CBE_RAS) += ras.o 5 5 6 6 obj-$(CONFIG_CBE_THERM) += cbe_thermal.o 7 - obj-$(CONFIG_CBE_CPUFREQ) += cbe_cpufreq.o 7 + obj-$(CONFIG_CBE_CPUFREQ_PMI) += cbe_cpufreq_pmi.o 8 + obj-$(CONFIG_CBE_CPUFREQ) += cbe-cpufreq.o 9 + cbe-cpufreq-y += cbe_cpufreq_pervasive.o cbe_cpufreq.o 8 10 9 11 ifeq ($(CONFIG_SMP),y) 10 12 obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
+11 -189
arch/powerpc/platforms/cell/cbe_cpufreq.c
··· 1 1 /* 2 2 * cpufreq driver for the cell processor 3 3 * 4 - * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 4 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 5 5 * 6 6 * Author: Christian Krafft <krafft@de.ibm.com> 7 7 * ··· 21 21 */ 22 22 23 23 #include <linux/cpufreq.h> 24 - #include <linux/timer.h> 25 - 26 - #include <asm/hw_irq.h> 27 - #include <asm/io.h> 28 24 #include <asm/machdep.h> 29 - #include <asm/processor.h> 30 - #include <asm/prom.h> 31 - #include <asm/time.h> 32 - #include <asm/pmi.h> 33 25 #include <asm/of_platform.h> 34 - 35 - #include "cbe_regs.h" 26 + #include <asm/prom.h> 27 + #include "cbe_cpufreq.h" 36 28 37 29 static DEFINE_MUTEX(cbe_switch_mutex); 38 30 ··· 42 50 {0, CPUFREQ_TABLE_END}, 43 51 }; 44 52 45 - /* to write to MIC register */ 46 - static u64 MIC_Slow_Fast_Timer_table[] = { 47 - [0 ... 7] = 0x007fc00000000000ull, 48 - }; 49 - 50 - /* more values for the MIC */ 51 - static u64 MIC_Slow_Next_Timer_table[] = { 52 - 0x0000240000000000ull, 53 - 0x0000268000000000ull, 54 - 0x000029C000000000ull, 55 - 0x00002D0000000000ull, 56 - 0x0000300000000000ull, 57 - 0x0000334000000000ull, 58 - 0x000039C000000000ull, 59 - 0x00003FC000000000ull, 60 - }; 61 - 62 - static u8 pmi_slow_mode_limit[MAX_BE]; 63 - 64 53 /* 65 54 * hardware specific functions 66 55 */ 67 56 68 - static bool cbe_cpufreq_has_pmi; 69 - 70 - #ifdef CONFIG_PPC_PMI 71 - static int set_pmode_pmi(int cpu, unsigned int pmode) 72 - { 73 - int ret; 74 - pmi_message_t pmi_msg; 75 - #ifdef DEBUG 76 - long time; 77 - #endif 78 - 79 - pmi_msg.type = PMI_TYPE_FREQ_CHANGE; 80 - pmi_msg.data1 = cbe_cpu_to_node(cpu); 81 - pmi_msg.data2 = pmode; 82 - 83 - #ifdef DEBUG 84 - time = jiffies; 85 - #endif 86 - 87 - pmi_send_message(pmi_msg); 88 - ret = pmi_msg.data2; 89 - 90 - pr_debug("PMI returned slow mode %d\n", ret); 91 - 92 - #ifdef DEBUG 93 - time = jiffies - time; /* actual cycles (not cpu cycles!) */ 94 - time = jiffies_to_msecs(time); 95 - pr_debug("had to wait %lu ms for a transition using PMI.\n", time); 96 - #endif 97 - return ret; 98 - } 99 - #endif 100 - 101 - static int get_pmode(int cpu) 102 - { 103 - int ret; 104 - struct cbe_pmd_regs __iomem *pmd_regs; 105 - 106 - pmd_regs = cbe_get_cpu_pmd_regs(cpu); 107 - ret = in_be64(&pmd_regs->pmsr) & 0x07; 108 - 109 - return ret; 110 - } 111 - 112 - static int set_pmode_reg(int cpu, unsigned int pmode) 113 - { 114 - struct cbe_pmd_regs __iomem *pmd_regs; 115 - struct cbe_mic_tm_regs __iomem *mic_tm_regs; 116 - u64 flags; 117 - u64 value; 118 - #ifdef DEBUG 119 - long time; 120 - #endif 121 - 122 - local_irq_save(flags); 123 - 124 - mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu); 125 - pmd_regs = cbe_get_cpu_pmd_regs(cpu); 126 - 127 - #ifdef DEBUG 128 - time = jiffies; 129 - #endif 130 - out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]); 131 - out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]); 132 - 133 - out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]); 134 - out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]); 135 - 136 - value = in_be64(&pmd_regs->pmcr); 137 - /* set bits to zero */ 138 - value &= 0xFFFFFFFFFFFFFFF8ull; 139 - /* set bits to next pmode */ 140 - value |= pmode; 141 - 142 - out_be64(&pmd_regs->pmcr, value); 143 - 144 - #ifdef DEBUG 145 - /* wait until new pmode appears in status register */ 146 - value = in_be64(&pmd_regs->pmsr) & 0x07; 147 - while(value != pmode) { 148 - cpu_relax(); 149 - value = in_be64(&pmd_regs->pmsr) & 0x07; 150 - } 151 - 152 - time = jiffies - time; 153 - time = jiffies_to_msecs(time); 154 - pr_debug("had to wait %lu ms for a transition using " \ 155 - "the pervasive unit.\n", time); 156 - #endif 157 - local_irq_restore(flags); 158 - 159 - return 0; 160 - } 161 - 162 - static int set_pmode(int cpu, unsigned int slow_mode) 57 + static int set_pmode(unsigned int cpu, unsigned int slow_mode) 163 58 { 164 59 int rc; 165 - #ifdef CONFIG_PPC_PMI 166 - if (cbe_cpufreq_has_pmi) 167 - rc = set_pmode_pmi(cpu, slow_mode); 168 - else 169 - #endif 170 - rc = set_pmode_reg(cpu, slow_mode); 171 60 172 - pr_debug("register contains slow mode %d\n", get_pmode(cpu)); 61 + if (cbe_cpufreq_has_pmi) 62 + rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode); 63 + else 64 + rc = cbe_cpufreq_set_pmode(cpu, slow_mode); 65 + 66 + pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu)); 173 67 174 68 return rc; 175 69 } 176 - 177 - static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg) 178 - { 179 - u8 node; slow_mode; 180 - 181 - BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); 182 - 183 - node = pmi_msg.data1; 184 - slow_mode = pmi_msg.data2; 185 - 186 - pmi_slow_mode_limit[node] = slow_mode; 187 - 188 - pr_debug("cbe_handle_pmi: node: %d, max slow_mode=%d\n", slow_mode); 189 - } 190 - 191 - static int pmi_notifier(struct notifier_block *nb, 192 - unsigned long event, void *data) 193 - { 194 - struct cpufreq_policy *policy = data; 195 - u8 node; 196 - 197 - node = cbe_cpu_to_node(policy->cpu); 198 - 199 - pr_debug("got notified, event=%lu, node=%u\n", event, node); 200 - 201 - if (pmi_slow_mode_limit[node] != 0) { 202 - pr_debug("limiting node %d to slow mode %d\n", 203 - node, pmi_slow_mode_limit[node]); 204 - 205 - cpufreq_verify_within_limits(policy, 0, 206 - cbe_freqs[pmi_slow_mode_limit[node]].frequency); 207 - } 208 - 209 - return 0; 210 - } 211 - 212 - static struct notifier_block pmi_notifier_block = { 213 - .notifier_call = pmi_notifier, 214 - }; 215 - 216 - static struct pmi_handler cbe_pmi_handler = { 217 - .type = PMI_TYPE_FREQ_CHANGE, 218 - .handle_pmi_message = cbe_cpufreq_handle_pmi, 219 - }; 220 - 221 70 222 71 /* 223 72 * cpufreq functions ··· 103 270 * of a transition */ 104 271 policy->cpuinfo.transition_latency = 25000; 105 272 106 - cur_pmode = get_pmode(policy->cpu); 273 + cur_pmode = cbe_cpufreq_get_pmode(policy->cpu); 107 274 pr_debug("current pmode is at %d\n",cur_pmode); 108 275 109 276 policy->cur = cbe_freqs[cur_pmode].frequency; ··· 129 296 { 130 297 return cpufreq_frequency_table_verify(policy, cbe_freqs); 131 298 } 132 - 133 299 134 300 static int cbe_cpufreq_target(struct cpufreq_policy *policy, 135 301 unsigned int target_freq, ··· 184 352 if (!machine_is(cell)) 185 353 return -ENODEV; 186 354 187 - cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0; 188 - 189 - if (cbe_cpufreq_has_pmi) 190 - cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 191 - 192 355 return cpufreq_register_driver(&cbe_cpufreq_driver); 193 356 } 194 357 195 358 static void __exit cbe_cpufreq_exit(void) 196 359 { 197 360 cpufreq_unregister_driver(&cbe_cpufreq_driver); 198 - 199 - if (cbe_cpufreq_has_pmi) { 200 - cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 201 - pmi_unregister_handler(&cbe_pmi_handler); 202 - } 203 361 } 204 362 205 363 module_init(cbe_cpufreq_init);
+24
arch/powerpc/platforms/cell/cbe_cpufreq.h
··· 1 + /* 2 + * cbe_cpufreq.h 3 + * 4 + * This file contains the definitions used by the cbe_cpufreq driver. 5 + * 6 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 7 + * 8 + * Author: Christian Krafft <krafft@de.ibm.com> 9 + * 10 + */ 11 + 12 + #include <linux/cpufreq.h> 13 + #include <linux/types.h> 14 + 15 + int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode); 16 + int cbe_cpufreq_get_pmode(int cpu); 17 + 18 + int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode); 19 + 20 + #if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE) 21 + extern bool cbe_cpufreq_has_pmi; 22 + #else 23 + #define cbe_cpufreq_has_pmi (0) 24 + #endif
+115
arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
··· 1 + /* 2 + * pervasive backend for the cbe_cpufreq driver 3 + * 4 + * This driver makes use of the pervasive unit to 5 + * engage the desired frequency. 6 + * 7 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 8 + * 9 + * Author: Christian Krafft <krafft@de.ibm.com> 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2, or (at your option) 14 + * any later version. 15 + * 16 + * This program is distributed in the hope that it will be useful, 17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + * GNU General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 + */ 25 + 26 + #include <linux/io.h> 27 + #include <linux/kernel.h> 28 + #include <linux/time.h> 29 + #include <asm/machdep.h> 30 + #include <asm/hw_irq.h> 31 + 32 + #include "cbe_regs.h" 33 + #include "cbe_cpufreq.h" 34 + 35 + /* to write to MIC register */ 36 + static u64 MIC_Slow_Fast_Timer_table[] = { 37 + [0 ... 7] = 0x007fc00000000000ull, 38 + }; 39 + 40 + /* more values for the MIC */ 41 + static u64 MIC_Slow_Next_Timer_table[] = { 42 + 0x0000240000000000ull, 43 + 0x0000268000000000ull, 44 + 0x000029C000000000ull, 45 + 0x00002D0000000000ull, 46 + 0x0000300000000000ull, 47 + 0x0000334000000000ull, 48 + 0x000039C000000000ull, 49 + 0x00003FC000000000ull, 50 + }; 51 + 52 + 53 + int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode) 54 + { 55 + struct cbe_pmd_regs __iomem *pmd_regs; 56 + struct cbe_mic_tm_regs __iomem *mic_tm_regs; 57 + u64 flags; 58 + u64 value; 59 + #ifdef DEBUG 60 + long time; 61 + #endif 62 + 63 + local_irq_save(flags); 64 + 65 + mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu); 66 + pmd_regs = cbe_get_cpu_pmd_regs(cpu); 67 + 68 + #ifdef DEBUG 69 + time = jiffies; 70 + #endif 71 + 72 + out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]); 73 + out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]); 74 + 75 + out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]); 76 + out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]); 77 + 78 + value = in_be64(&pmd_regs->pmcr); 79 + /* set bits to zero */ 80 + value &= 0xFFFFFFFFFFFFFFF8ull; 81 + /* set bits to next pmode */ 82 + value |= pmode; 83 + 84 + out_be64(&pmd_regs->pmcr, value); 85 + 86 + #ifdef DEBUG 87 + /* wait until new pmode appears in status register */ 88 + value = in_be64(&pmd_regs->pmsr) & 0x07; 89 + while (value != pmode) { 90 + cpu_relax(); 91 + value = in_be64(&pmd_regs->pmsr) & 0x07; 92 + } 93 + 94 + time = jiffies - time; 95 + time = jiffies_to_msecs(time); 96 + pr_debug("had to wait %lu ms for a transition using " \ 97 + "pervasive unit\n", time); 98 + #endif 99 + local_irq_restore(flags); 100 + 101 + return 0; 102 + } 103 + 104 + 105 + int cbe_cpufreq_get_pmode(int cpu) 106 + { 107 + int ret; 108 + struct cbe_pmd_regs __iomem *pmd_regs; 109 + 110 + pmd_regs = cbe_get_cpu_pmd_regs(cpu); 111 + ret = in_be64(&pmd_regs->pmsr) & 0x07; 112 + 113 + return ret; 114 + } 115 +
+148
arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
··· 1 + /* 2 + * pmi backend for the cbe_cpufreq driver 3 + * 4 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 5 + * 6 + * Author: Christian Krafft <krafft@de.ibm.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2, or (at your option) 11 + * any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 + */ 22 + 23 + #include <linux/kernel.h> 24 + #include <linux/types.h> 25 + #include <linux/timer.h> 26 + #include <asm/of_platform.h> 27 + #include <asm/processor.h> 28 + #include <asm/prom.h> 29 + #include <asm/pmi.h> 30 + 31 + #ifdef DEBUG 32 + #include <asm/time.h> 33 + #endif 34 + 35 + #include "cbe_regs.h" 36 + #include "cbe_cpufreq.h" 37 + 38 + static u8 pmi_slow_mode_limit[MAX_CBE]; 39 + 40 + bool cbe_cpufreq_has_pmi = false; 41 + EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi); 42 + 43 + /* 44 + * hardware specific functions 45 + */ 46 + 47 + int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode) 48 + { 49 + int ret; 50 + pmi_message_t pmi_msg; 51 + #ifdef DEBUG 52 + long time; 53 + #endif 54 + pmi_msg.type = PMI_TYPE_FREQ_CHANGE; 55 + pmi_msg.data1 = cbe_cpu_to_node(cpu); 56 + pmi_msg.data2 = pmode; 57 + 58 + #ifdef DEBUG 59 + time = jiffies; 60 + #endif 61 + pmi_send_message(pmi_msg); 62 + 63 + #ifdef DEBUG 64 + time = jiffies - time; 65 + time = jiffies_to_msecs(time); 66 + pr_debug("had to wait %lu ms for a transition using " \ 67 + "PMI\n", time); 68 + #endif 69 + ret = pmi_msg.data2; 70 + pr_debug("PMI returned slow mode %d\n", ret); 71 + 72 + return ret; 73 + } 74 + EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi); 75 + 76 + 77 + static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg) 78 + { 79 + u8 node, slow_mode; 80 + 81 + BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); 82 + 83 + node = pmi_msg.data1; 84 + slow_mode = pmi_msg.data2; 85 + 86 + pmi_slow_mode_limit[node] = slow_mode; 87 + 88 + pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode); 89 + } 90 + 91 + static int pmi_notifier(struct notifier_block *nb, 92 + unsigned long event, void *data) 93 + { 94 + struct cpufreq_policy *policy = data; 95 + struct cpufreq_frequency_table *cbe_freqs; 96 + u8 node; 97 + 98 + cbe_freqs = cpufreq_frequency_get_table(policy->cpu); 99 + node = cbe_cpu_to_node(policy->cpu); 100 + 101 + pr_debug("got notified, event=%lu, node=%u\n", event, node); 102 + 103 + if (pmi_slow_mode_limit[node] != 0) { 104 + pr_debug("limiting node %d to slow mode %d\n", 105 + node, pmi_slow_mode_limit[node]); 106 + 107 + cpufreq_verify_within_limits(policy, 0, 108 + 109 + cbe_freqs[pmi_slow_mode_limit[node]].frequency); 110 + } 111 + 112 + return 0; 113 + } 114 + 115 + static struct notifier_block pmi_notifier_block = { 116 + .notifier_call = pmi_notifier, 117 + }; 118 + 119 + static struct pmi_handler cbe_pmi_handler = { 120 + .type = PMI_TYPE_FREQ_CHANGE, 121 + .handle_pmi_message = cbe_cpufreq_handle_pmi, 122 + }; 123 + 124 + 125 + 126 + static int __init cbe_cpufreq_pmi_init(void) 127 + { 128 + cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0; 129 + 130 + if (!cbe_cpufreq_has_pmi) 131 + return -ENODEV; 132 + 133 + cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 134 + 135 + return 0; 136 + } 137 + 138 + static void __exit cbe_cpufreq_pmi_exit(void) 139 + { 140 + cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 141 + pmi_unregister_handler(&cbe_pmi_handler); 142 + } 143 + 144 + module_init(cbe_cpufreq_pmi_init); 145 + module_exit(cbe_cpufreq_pmi_exit); 146 + 147 + MODULE_LICENSE("GPL"); 148 + MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");