Path: blob/master/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
10818 views
/*1* pmi backend for the cbe_cpufreq driver2*3* (C) Copyright IBM Deutschland Entwicklung GmbH 2005-20074*5* Author: Christian Krafft <[email protected]>6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License as published by9* the Free Software Foundation; either version 2, or (at your option)10* any later version.11*12* This program is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15* GNU General Public License for more details.16*17* You should have received a copy of the GNU General Public License18* along with this program; if not, write to the Free Software19* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.20*/2122#include <linux/kernel.h>23#include <linux/types.h>24#include <linux/timer.h>25#include <linux/of_platform.h>2627#include <asm/processor.h>28#include <asm/prom.h>29#include <asm/pmi.h>30#include <asm/cell-regs.h>3132#ifdef DEBUG33#include <asm/time.h>34#endif3536#include "cbe_cpufreq.h"3738static u8 pmi_slow_mode_limit[MAX_CBE];3940bool cbe_cpufreq_has_pmi = false;41EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);4243/*44* hardware specific functions45*/4647int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)48{49int ret;50pmi_message_t pmi_msg;51#ifdef DEBUG52long time;53#endif54pmi_msg.type = PMI_TYPE_FREQ_CHANGE;55pmi_msg.data1 = cbe_cpu_to_node(cpu);56pmi_msg.data2 = pmode;5758#ifdef DEBUG59time = jiffies;60#endif61pmi_send_message(pmi_msg);6263#ifdef DEBUG64time = jiffies - time;65time = jiffies_to_msecs(time);66pr_debug("had to wait %lu ms for a transition using " \67"PMI\n", time);68#endif69ret = pmi_msg.data2;70pr_debug("PMI returned slow mode %d\n", ret);7172return ret;73}74EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);757677static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)78{79u8 node, slow_mode;8081BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);8283node = pmi_msg.data1;84slow_mode = pmi_msg.data2;8586pmi_slow_mode_limit[node] = slow_mode;8788pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);89}9091static int pmi_notifier(struct notifier_block *nb,92unsigned long event, void *data)93{94struct cpufreq_policy *policy = data;95struct cpufreq_frequency_table *cbe_freqs;96u8 node;9798/* Should this really be called for CPUFREQ_ADJUST, CPUFREQ_INCOMPATIBLE99* and CPUFREQ_NOTIFY policy events?)100*/101if (event == CPUFREQ_START)102return 0;103104cbe_freqs = cpufreq_frequency_get_table(policy->cpu);105node = cbe_cpu_to_node(policy->cpu);106107pr_debug("got notified, event=%lu, node=%u\n", event, node);108109if (pmi_slow_mode_limit[node] != 0) {110pr_debug("limiting node %d to slow mode %d\n",111node, pmi_slow_mode_limit[node]);112113cpufreq_verify_within_limits(policy, 0,114115cbe_freqs[pmi_slow_mode_limit[node]].frequency);116}117118return 0;119}120121static struct notifier_block pmi_notifier_block = {122.notifier_call = pmi_notifier,123};124125static struct pmi_handler cbe_pmi_handler = {126.type = PMI_TYPE_FREQ_CHANGE,127.handle_pmi_message = cbe_cpufreq_handle_pmi,128};129130131132static int __init cbe_cpufreq_pmi_init(void)133{134cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0;135136if (!cbe_cpufreq_has_pmi)137return -ENODEV;138139cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);140141return 0;142}143144static void __exit cbe_cpufreq_pmi_exit(void)145{146cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);147pmi_unregister_handler(&cbe_pmi_handler);148}149150module_init(cbe_cpufreq_pmi_init);151module_exit(cbe_cpufreq_pmi_exit);152153MODULE_LICENSE("GPL");154MODULE_AUTHOR("Christian Krafft <[email protected]>");155156157