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