]>
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> | |
26 | #include <asm/of_platform.h> | |
27 | #include <asm/processor.h> | |
28 | #include <asm/prom.h> | |
29 | #include <asm/pmi.h> | |
eef686a0 | 30 | #include <asm/cell-regs.h> |
74889e41 CK |
31 | |
32 | #ifdef DEBUG | |
33 | #include <asm/time.h> | |
34 | #endif | |
35 | ||
74889e41 CK |
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>"); |