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