1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * pmi backend for the cbe_cpufreq driver
5 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
7 * Author: Christian Krafft <krafft@de.ibm.com>
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>
17 #include <asm/processor.h>
19 #include <asm/cell-regs.h>
25 #include "ppc_cbe_cpufreq.h"
27 bool cbe_cpufreq_has_pmi
= false;
28 EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi
);
31 * hardware specific functions
34 int cbe_cpufreq_set_pmode_pmi(int cpu
, unsigned int pmode
)
37 pmi_message_t pmi_msg
;
41 pmi_msg
.type
= PMI_TYPE_FREQ_CHANGE
;
42 pmi_msg
.data1
= cbe_cpu_to_node(cpu
);
43 pmi_msg
.data2
= pmode
;
48 pmi_send_message(pmi_msg
);
51 time
= jiffies
- time
;
52 time
= jiffies_to_msecs(time
);
53 pr_debug("had to wait %lu ms for a transition using " \
57 pr_debug("PMI returned slow mode %d\n", ret
);
61 EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi
);
64 static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg
)
66 struct cpufreq_policy
*policy
;
67 struct freq_qos_request
*req
;
71 BUG_ON(pmi_msg
.type
!= PMI_TYPE_FREQ_CHANGE
);
74 slow_mode
= pmi_msg
.data2
;
76 cpu
= cbe_node_to_cpu(node
);
78 pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node
, slow_mode
);
80 policy
= cpufreq_cpu_get(cpu
);
82 pr_warn("cpufreq policy not found cpu%d\n", cpu
);
86 req
= policy
->driver_data
;
88 ret
= freq_qos_update_request(req
,
89 policy
->freq_table
[slow_mode
].frequency
);
91 pr_warn("Failed to update freq constraint: %d\n", ret
);
93 pr_debug("limiting node %d to slow mode %d\n", node
, slow_mode
);
95 cpufreq_cpu_put(policy
);
98 static struct pmi_handler cbe_pmi_handler
= {
99 .type
= PMI_TYPE_FREQ_CHANGE
,
100 .handle_pmi_message
= cbe_cpufreq_handle_pmi
,
103 void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy
*policy
)
105 struct freq_qos_request
*req
;
108 if (!cbe_cpufreq_has_pmi
)
111 req
= kzalloc(sizeof(*req
), GFP_KERNEL
);
115 ret
= freq_qos_add_request(&policy
->constraints
, req
, FREQ_QOS_MAX
,
116 policy
->freq_table
[0].frequency
);
118 pr_err("Failed to add freq constraint (%d)\n", ret
);
123 policy
->driver_data
= req
;
125 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_init
);
127 void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy
*policy
)
129 struct freq_qos_request
*req
= policy
->driver_data
;
131 if (cbe_cpufreq_has_pmi
) {
132 freq_qos_remove_request(req
);
136 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_exit
);
138 void cbe_cpufreq_pmi_init(void)
140 if (!pmi_register_handler(&cbe_pmi_handler
))
141 cbe_cpufreq_has_pmi
= true;
143 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_init
);
145 void cbe_cpufreq_pmi_exit(void)
147 pmi_unregister_handler(&cbe_pmi_handler
);
148 cbe_cpufreq_has_pmi
= false;
150 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_exit
);