]>
Commit | Line | Data |
---|---|---|
74889e41 CK |
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> | |
d8caf74f JL |
26 | #include <linux/of_platform.h> |
27 | ||
74889e41 CK |
28 | #include <asm/processor.h> |
29 | #include <asm/prom.h> | |
30 | #include <asm/pmi.h> | |
eef686a0 | 31 | #include <asm/cell-regs.h> |
74889e41 CK |
32 | |
33 | #ifdef DEBUG | |
34 | #include <asm/time.h> | |
35 | #endif | |
36 | ||
74889e41 CK |
37 | #include "cbe_cpufreq.h" |
38 | ||
39 | static u8 pmi_slow_mode_limit[MAX_CBE]; | |
40 | ||
41 | bool cbe_cpufreq_has_pmi = false; | |
42 | EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi); | |
43 | ||
44 | /* | |
45 | * hardware specific functions | |
46 | */ | |
47 | ||
48 | int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode) | |
49 | { | |
50 | int ret; | |
51 | pmi_message_t pmi_msg; | |
52 | #ifdef DEBUG | |
53 | long time; | |
54 | #endif | |
55 | pmi_msg.type = PMI_TYPE_FREQ_CHANGE; | |
56 | pmi_msg.data1 = cbe_cpu_to_node(cpu); | |
57 | pmi_msg.data2 = pmode; | |
58 | ||
59 | #ifdef DEBUG | |
60 | time = jiffies; | |
61 | #endif | |
62 | pmi_send_message(pmi_msg); | |
63 | ||
64 | #ifdef DEBUG | |
65 | time = jiffies - time; | |
66 | time = jiffies_to_msecs(time); | |
67 | pr_debug("had to wait %lu ms for a transition using " \ | |
68 | "PMI\n", time); | |
69 | #endif | |
70 | ret = pmi_msg.data2; | |
71 | pr_debug("PMI returned slow mode %d\n", ret); | |
72 | ||
73 | return ret; | |
74 | } | |
75 | EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi); | |
76 | ||
77 | ||
78 | static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg) | |
79 | { | |
80 | u8 node, slow_mode; | |
81 | ||
82 | BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); | |
83 | ||
84 | node = pmi_msg.data1; | |
85 | slow_mode = pmi_msg.data2; | |
86 | ||
87 | pmi_slow_mode_limit[node] = slow_mode; | |
88 | ||
89 | pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode); | |
90 | } | |
91 | ||
92 | static int pmi_notifier(struct notifier_block *nb, | |
93 | unsigned long event, void *data) | |
94 | { | |
95 | struct cpufreq_policy *policy = data; | |
96 | struct cpufreq_frequency_table *cbe_freqs; | |
97 | u8 node; | |
98 | ||
99 | cbe_freqs = cpufreq_frequency_get_table(policy->cpu); | |
100 | node = cbe_cpu_to_node(policy->cpu); | |
101 | ||
102 | pr_debug("got notified, event=%lu, node=%u\n", event, node); | |
103 | ||
104 | if (pmi_slow_mode_limit[node] != 0) { | |
105 | pr_debug("limiting node %d to slow mode %d\n", | |
106 | node, pmi_slow_mode_limit[node]); | |
107 | ||
108 | cpufreq_verify_within_limits(policy, 0, | |
109 | ||
110 | cbe_freqs[pmi_slow_mode_limit[node]].frequency); | |
111 | } | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | static struct notifier_block pmi_notifier_block = { | |
117 | .notifier_call = pmi_notifier, | |
118 | }; | |
119 | ||
120 | static struct pmi_handler cbe_pmi_handler = { | |
121 | .type = PMI_TYPE_FREQ_CHANGE, | |
122 | .handle_pmi_message = cbe_cpufreq_handle_pmi, | |
123 | }; | |
124 | ||
125 | ||
126 | ||
127 | static int __init cbe_cpufreq_pmi_init(void) | |
128 | { | |
129 | cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0; | |
130 | ||
131 | if (!cbe_cpufreq_has_pmi) | |
132 | return -ENODEV; | |
133 | ||
134 | cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | static void __exit cbe_cpufreq_pmi_exit(void) | |
140 | { | |
141 | cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); | |
142 | pmi_unregister_handler(&cbe_pmi_handler); | |
143 | } | |
144 | ||
145 | module_init(cbe_cpufreq_pmi_init); | |
146 | module_exit(cbe_cpufreq_pmi_exit); | |
147 | ||
148 | MODULE_LICENSE("GPL"); | |
149 | MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); |