0001
0002
0003
0004
0005
0006
0007
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
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);