Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * pmi backend for the cbe_cpufreq driver
0004  *
0005  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
0006  *
0007  * Author: Christian Krafft <krafft@de.ibm.com>
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/types.h>
0012 #include <linux/timer.h>
0013 #include <linux/init.h>
0014 #include <linux/of_platform.h>
0015 #include <linux/pm_qos.h>
0016 #include <linux/slab.h>
0017 
0018 #include <asm/processor.h>
0019 #include <asm/pmi.h>
0020 #include <asm/cell-regs.h>
0021 
0022 #ifdef DEBUG
0023 #include <asm/time.h>
0024 #endif
0025 
0026 #include "ppc_cbe_cpufreq.h"
0027 
0028 bool cbe_cpufreq_has_pmi = false;
0029 EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);
0030 
0031 /*
0032  * hardware specific functions
0033  */
0034 
0035 int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)
0036 {
0037     int ret;
0038     pmi_message_t pmi_msg;
0039 #ifdef DEBUG
0040     long time;
0041 #endif
0042     pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
0043     pmi_msg.data1 = cbe_cpu_to_node(cpu);
0044     pmi_msg.data2 = pmode;
0045 
0046 #ifdef DEBUG
0047     time = jiffies;
0048 #endif
0049     pmi_send_message(pmi_msg);
0050 
0051 #ifdef DEBUG
0052     time = jiffies  - time;
0053     time = jiffies_to_msecs(time);
0054     pr_debug("had to wait %lu ms for a transition using " \
0055          "PMI\n", time);
0056 #endif
0057     ret = pmi_msg.data2;
0058     pr_debug("PMI returned slow mode %d\n", ret);
0059 
0060     return ret;
0061 }
0062 EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);
0063 
0064 
0065 static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)
0066 {
0067     struct cpufreq_policy *policy;
0068     struct freq_qos_request *req;
0069     u8 node, slow_mode;
0070     int cpu, ret;
0071 
0072     BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
0073 
0074     node = pmi_msg.data1;
0075     slow_mode = pmi_msg.data2;
0076 
0077     cpu = cbe_node_to_cpu(node);
0078 
0079     pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);
0080 
0081     policy = cpufreq_cpu_get(cpu);
0082     if (!policy) {
0083         pr_warn("cpufreq policy not found cpu%d\n", cpu);
0084         return;
0085     }
0086 
0087     req = policy->driver_data;
0088 
0089     ret = freq_qos_update_request(req,
0090             policy->freq_table[slow_mode].frequency);
0091     if (ret < 0)
0092         pr_warn("Failed to update freq constraint: %d\n", ret);
0093     else
0094         pr_debug("limiting node %d to slow mode %d\n", node, slow_mode);
0095 
0096     cpufreq_cpu_put(policy);
0097 }
0098 
0099 static struct pmi_handler cbe_pmi_handler = {
0100     .type           = PMI_TYPE_FREQ_CHANGE,
0101     .handle_pmi_message = cbe_cpufreq_handle_pmi,
0102 };
0103 
0104 void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy *policy)
0105 {
0106     struct freq_qos_request *req;
0107     int ret;
0108 
0109     if (!cbe_cpufreq_has_pmi)
0110         return;
0111 
0112     req = kzalloc(sizeof(*req), GFP_KERNEL);
0113     if (!req)
0114         return;
0115 
0116     ret = freq_qos_add_request(&policy->constraints, req, FREQ_QOS_MAX,
0117                    policy->freq_table[0].frequency);
0118     if (ret < 0) {
0119         pr_err("Failed to add freq constraint (%d)\n", ret);
0120         kfree(req);
0121         return;
0122     }
0123 
0124     policy->driver_data = req;
0125 }
0126 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_init);
0127 
0128 void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy *policy)
0129 {
0130     struct freq_qos_request *req = policy->driver_data;
0131 
0132     if (cbe_cpufreq_has_pmi) {
0133         freq_qos_remove_request(req);
0134         kfree(req);
0135     }
0136 }
0137 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_exit);
0138 
0139 void cbe_cpufreq_pmi_init(void)
0140 {
0141     if (!pmi_register_handler(&cbe_pmi_handler))
0142         cbe_cpufreq_has_pmi = true;
0143 }
0144 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_init);
0145 
0146 void cbe_cpufreq_pmi_exit(void)
0147 {
0148     pmi_unregister_handler(&cbe_pmi_handler);
0149     cbe_cpufreq_has_pmi = false;
0150 }
0151 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_exit);