Commit | Line | Data |
---|---|---|
de6cc651 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
74889e41 CK |
2 | /* |
3 | * pmi backend for the cbe_cpufreq driver | |
4 | * | |
5 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 | |
6 | * | |
7 | * Author: Christian Krafft <krafft@de.ibm.com> | |
74889e41 CK |
8 | */ |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/types.h> | |
12 | #include <linux/timer.h> | |
dbbe972c | 13 | #include <linux/init.h> |
d8caf74f | 14 | #include <linux/of_platform.h> |
afe96907 | 15 | #include <linux/pm_qos.h> |
95996a67 | 16 | #include <linux/slab.h> |
d8caf74f | 17 | |
74889e41 | 18 | #include <asm/processor.h> |
74889e41 | 19 | #include <asm/pmi.h> |
eef686a0 | 20 | #include <asm/cell-regs.h> |
74889e41 CK |
21 | |
22 | #ifdef DEBUG | |
23 | #include <asm/time.h> | |
24 | #endif | |
25 | ||
6eb1c377 | 26 | #include "ppc_cbe_cpufreq.h" |
74889e41 | 27 | |
74889e41 CK |
28 | bool cbe_cpufreq_has_pmi = false; |
29 | EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi); | |
30 | ||
31 | /* | |
32 | * hardware specific functions | |
33 | */ | |
34 | ||
35 | int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode) | |
36 | { | |
37 | int ret; | |
38 | pmi_message_t pmi_msg; | |
39 | #ifdef DEBUG | |
40 | long time; | |
41 | #endif | |
42 | pmi_msg.type = PMI_TYPE_FREQ_CHANGE; | |
43 | pmi_msg.data1 = cbe_cpu_to_node(cpu); | |
44 | pmi_msg.data2 = pmode; | |
45 | ||
46 | #ifdef DEBUG | |
47 | time = jiffies; | |
48 | #endif | |
49 | pmi_send_message(pmi_msg); | |
50 | ||
51 | #ifdef DEBUG | |
52 | time = jiffies - time; | |
53 | time = jiffies_to_msecs(time); | |
54 | pr_debug("had to wait %lu ms for a transition using " \ | |
55 | "PMI\n", time); | |
56 | #endif | |
57 | ret = pmi_msg.data2; | |
58 | pr_debug("PMI returned slow mode %d\n", ret); | |
59 | ||
60 | return ret; | |
61 | } | |
62 | EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi); | |
63 | ||
64 | ||
65 | static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg) | |
66 | { | |
afe96907 | 67 | struct cpufreq_policy *policy; |
3000ce3c | 68 | struct freq_qos_request *req; |
74889e41 | 69 | u8 node, slow_mode; |
afe96907 | 70 | int cpu, ret; |
74889e41 CK |
71 | |
72 | BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); | |
73 | ||
74 | node = pmi_msg.data1; | |
75 | slow_mode = pmi_msg.data2; | |
76 | ||
afe96907 | 77 | cpu = cbe_node_to_cpu(node); |
74889e41 CK |
78 | |
79 | pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode); | |
74889e41 | 80 | |
afe96907 VK |
81 | policy = cpufreq_cpu_get(cpu); |
82 | if (!policy) { | |
83 | pr_warn("cpufreq policy not found cpu%d\n", cpu); | |
84 | return; | |
85 | } | |
74889e41 | 86 | |
afe96907 | 87 | req = policy->driver_data; |
74889e41 | 88 | |
3000ce3c | 89 | ret = freq_qos_update_request(req, |
afe96907 VK |
90 | policy->freq_table[slow_mode].frequency); |
91 | if (ret < 0) | |
92 | pr_warn("Failed to update freq constraint: %d\n", ret); | |
93 | else | |
94 | pr_debug("limiting node %d to slow mode %d\n", node, slow_mode); | |
74889e41 | 95 | |
afe96907 | 96 | cpufreq_cpu_put(policy); |
74889e41 CK |
97 | } |
98 | ||
74889e41 CK |
99 | static struct pmi_handler cbe_pmi_handler = { |
100 | .type = PMI_TYPE_FREQ_CHANGE, | |
101 | .handle_pmi_message = cbe_cpufreq_handle_pmi, | |
102 | }; | |
103 | ||
afe96907 VK |
104 | void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy *policy) |
105 | { | |
3000ce3c | 106 | struct freq_qos_request *req; |
afe96907 VK |
107 | int ret; |
108 | ||
109 | if (!cbe_cpufreq_has_pmi) | |
110 | return; | |
111 | ||
112 | req = kzalloc(sizeof(*req), GFP_KERNEL); | |
113 | if (!req) | |
114 | return; | |
115 | ||
3000ce3c RW |
116 | ret = freq_qos_add_request(&policy->constraints, req, FREQ_QOS_MAX, |
117 | policy->freq_table[0].frequency); | |
afe96907 VK |
118 | if (ret < 0) { |
119 | pr_err("Failed to add freq constraint (%d)\n", ret); | |
120 | kfree(req); | |
121 | return; | |
122 | } | |
74889e41 | 123 | |
afe96907 VK |
124 | policy->driver_data = req; |
125 | } | |
126 | EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_init); | |
74889e41 | 127 | |
afe96907 | 128 | void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy *policy) |
74889e41 | 129 | { |
3000ce3c | 130 | struct freq_qos_request *req = policy->driver_data; |
74889e41 | 131 | |
afe96907 | 132 | if (cbe_cpufreq_has_pmi) { |
3000ce3c | 133 | freq_qos_remove_request(req); |
afe96907 VK |
134 | kfree(req); |
135 | } | |
136 | } | |
137 | EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_exit); | |
74889e41 | 138 | |
afe96907 VK |
139 | void cbe_cpufreq_pmi_init(void) |
140 | { | |
141 | if (!pmi_register_handler(&cbe_pmi_handler)) | |
142 | cbe_cpufreq_has_pmi = true; | |
143 | } | |
144 | EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_init); | |
74889e41 | 145 | |
afe96907 VK |
146 | void cbe_cpufreq_pmi_exit(void) |
147 | { | |
148 | pmi_unregister_handler(&cbe_pmi_handler); | |
149 | cbe_cpufreq_has_pmi = false; | |
74889e41 | 150 | } |
afe96907 | 151 | EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_exit); |