1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * processor_throttling.c - Throttling submodule of the ACPI processor driver
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
61da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
71da177e4SLinus Torvalds * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
81da177e4SLinus Torvalds * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
91da177e4SLinus Torvalds * - Added processor hotplug support
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
124140054aSHanjun Guo #define pr_fmt(fmt) "ACPI: " fmt
134140054aSHanjun Guo
141da177e4SLinus Torvalds #include <linux/kernel.h>
151da177e4SLinus Torvalds #include <linux/module.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
171da177e4SLinus Torvalds #include <linux/init.h>
18357dc4c3SZhao Yakui #include <linux/sched.h>
191da177e4SLinus Torvalds #include <linux/cpufreq.h>
208b48463fSLv Zheng #include <linux/acpi.h>
218b48463fSLv Zheng #include <acpi/processor.h>
221da177e4SLinus Torvalds #include <asm/io.h>
237c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
241da177e4SLinus Torvalds
2556c213faSZhang Rui /* ignore_tpc:
2656c213faSZhang Rui * 0 -> acpi processor driver doesn't ignore _TPC values
2756c213faSZhang Rui * 1 -> acpi processor driver ignores _TPC values
2856c213faSZhang Rui */
2956c213faSZhang Rui static int ignore_tpc;
3056c213faSZhang Rui module_param(ignore_tpc, int, 0644);
3156c213faSZhang Rui MODULE_PARM_DESC(ignore_tpc, "Disable broken BIOS _TPC throttling support");
3256c213faSZhang Rui
33e4aa5cb2SZhao Yakui struct throttling_tstate {
34e4aa5cb2SZhao Yakui unsigned int cpu; /* cpu nr */
35e4aa5cb2SZhao Yakui int target_state; /* target T-state */
36e4aa5cb2SZhao Yakui };
37e4aa5cb2SZhao Yakui
38f3ca4164SLan Tianyu struct acpi_processor_throttling_arg {
39f3ca4164SLan Tianyu struct acpi_processor *pr;
40f3ca4164SLan Tianyu int target_state;
41f3ca4164SLan Tianyu bool force;
42f3ca4164SLan Tianyu };
43f3ca4164SLan Tianyu
44e4aa5cb2SZhao Yakui #define THROTTLING_PRECHANGE (1)
45e4aa5cb2SZhao Yakui #define THROTTLING_POSTCHANGE (2)
46e4aa5cb2SZhao Yakui
4701854e69SLuming Yu static int acpi_processor_get_throttling(struct acpi_processor *pr);
488153f9acSThomas Gleixner static int __acpi_processor_set_throttling(struct acpi_processor *pr,
498153f9acSThomas Gleixner int state, bool force, bool direct);
5001854e69SLuming Yu
acpi_processor_update_tsd_coord(void)511180509fSZhao Yakui static int acpi_processor_update_tsd_coord(void)
521180509fSZhao Yakui {
53*04068da8SColin Ian King int count_target;
541180509fSZhao Yakui int retval = 0;
551180509fSZhao Yakui unsigned int i, j;
562fdf66b4SRusty Russell cpumask_var_t covered_cpus;
571180509fSZhao Yakui struct acpi_processor *pr, *match_pr;
581180509fSZhao Yakui struct acpi_tsd_package *pdomain, *match_pdomain;
591180509fSZhao Yakui struct acpi_processor_throttling *pthrottling, *match_pthrottling;
601180509fSZhao Yakui
6179f55997SLi Zefan if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
622fdf66b4SRusty Russell return -ENOMEM;
632fdf66b4SRusty Russell
641180509fSZhao Yakui /*
651180509fSZhao Yakui * Now that we have _TSD data from all CPUs, lets setup T-state
6633a2a529SZhao Yakui * coordination between all CPUs.
671180509fSZhao Yakui */
681180509fSZhao Yakui for_each_possible_cpu(i) {
69706546d0SMike Travis pr = per_cpu(processors, i);
701180509fSZhao Yakui if (!pr)
711180509fSZhao Yakui continue;
721180509fSZhao Yakui
731180509fSZhao Yakui /* Basic validity check for domain info */
741180509fSZhao Yakui pthrottling = &(pr->throttling);
751180509fSZhao Yakui
761180509fSZhao Yakui /*
771180509fSZhao Yakui * If tsd package for one cpu is invalid, the coordination
781180509fSZhao Yakui * among all CPUs is thought as invalid.
791180509fSZhao Yakui * Maybe it is ugly.
801180509fSZhao Yakui */
811180509fSZhao Yakui if (!pthrottling->tsd_valid_flag) {
821180509fSZhao Yakui retval = -EINVAL;
831180509fSZhao Yakui break;
841180509fSZhao Yakui }
851180509fSZhao Yakui }
861180509fSZhao Yakui if (retval)
871180509fSZhao Yakui goto err_ret;
881180509fSZhao Yakui
891180509fSZhao Yakui for_each_possible_cpu(i) {
90706546d0SMike Travis pr = per_cpu(processors, i);
911180509fSZhao Yakui if (!pr)
921180509fSZhao Yakui continue;
931180509fSZhao Yakui
942fdf66b4SRusty Russell if (cpumask_test_cpu(i, covered_cpus))
951180509fSZhao Yakui continue;
961180509fSZhao Yakui pthrottling = &pr->throttling;
971180509fSZhao Yakui
981180509fSZhao Yakui pdomain = &(pthrottling->domain_info);
992fdf66b4SRusty Russell cpumask_set_cpu(i, pthrottling->shared_cpu_map);
1002fdf66b4SRusty Russell cpumask_set_cpu(i, covered_cpus);
1011180509fSZhao Yakui /*
1021180509fSZhao Yakui * If the number of processor in the TSD domain is 1, it is
1031180509fSZhao Yakui * unnecessary to parse the coordination for this CPU.
1041180509fSZhao Yakui */
1051180509fSZhao Yakui if (pdomain->num_processors <= 1)
1061180509fSZhao Yakui continue;
1071180509fSZhao Yakui
1081180509fSZhao Yakui /* Validate the Domain info */
1091180509fSZhao Yakui count_target = pdomain->num_processors;
1101180509fSZhao Yakui
1111180509fSZhao Yakui for_each_possible_cpu(j) {
1121180509fSZhao Yakui if (i == j)
1131180509fSZhao Yakui continue;
1141180509fSZhao Yakui
115706546d0SMike Travis match_pr = per_cpu(processors, j);
1161180509fSZhao Yakui if (!match_pr)
1171180509fSZhao Yakui continue;
1181180509fSZhao Yakui
1191180509fSZhao Yakui match_pthrottling = &(match_pr->throttling);
1201180509fSZhao Yakui match_pdomain = &(match_pthrottling->domain_info);
1211180509fSZhao Yakui if (match_pdomain->domain != pdomain->domain)
1221180509fSZhao Yakui continue;
1231180509fSZhao Yakui
1241180509fSZhao Yakui /* Here i and j are in the same domain.
1251180509fSZhao Yakui * If two TSD packages have the same domain, they
1261180509fSZhao Yakui * should have the same num_porcessors and
1271180509fSZhao Yakui * coordination type. Otherwise it will be regarded
1281180509fSZhao Yakui * as illegal.
1291180509fSZhao Yakui */
1301180509fSZhao Yakui if (match_pdomain->num_processors != count_target) {
1311180509fSZhao Yakui retval = -EINVAL;
1321180509fSZhao Yakui goto err_ret;
1331180509fSZhao Yakui }
1341180509fSZhao Yakui
1351180509fSZhao Yakui if (pdomain->coord_type != match_pdomain->coord_type) {
1361180509fSZhao Yakui retval = -EINVAL;
1371180509fSZhao Yakui goto err_ret;
1381180509fSZhao Yakui }
1391180509fSZhao Yakui
1402fdf66b4SRusty Russell cpumask_set_cpu(j, covered_cpus);
1412fdf66b4SRusty Russell cpumask_set_cpu(j, pthrottling->shared_cpu_map);
1421180509fSZhao Yakui }
1431180509fSZhao Yakui for_each_possible_cpu(j) {
1441180509fSZhao Yakui if (i == j)
1451180509fSZhao Yakui continue;
1461180509fSZhao Yakui
147706546d0SMike Travis match_pr = per_cpu(processors, j);
1481180509fSZhao Yakui if (!match_pr)
1491180509fSZhao Yakui continue;
1501180509fSZhao Yakui
1511180509fSZhao Yakui match_pthrottling = &(match_pr->throttling);
1521180509fSZhao Yakui match_pdomain = &(match_pthrottling->domain_info);
1531180509fSZhao Yakui if (match_pdomain->domain != pdomain->domain)
1541180509fSZhao Yakui continue;
1551180509fSZhao Yakui
1561180509fSZhao Yakui /*
1571180509fSZhao Yakui * If some CPUS have the same domain, they
1581180509fSZhao Yakui * will have the same shared_cpu_map.
1591180509fSZhao Yakui */
1602fdf66b4SRusty Russell cpumask_copy(match_pthrottling->shared_cpu_map,
1612fdf66b4SRusty Russell pthrottling->shared_cpu_map);
1621180509fSZhao Yakui }
1631180509fSZhao Yakui }
1641180509fSZhao Yakui
1651180509fSZhao Yakui err_ret:
1662fdf66b4SRusty Russell free_cpumask_var(covered_cpus);
1672fdf66b4SRusty Russell
1681180509fSZhao Yakui for_each_possible_cpu(i) {
169706546d0SMike Travis pr = per_cpu(processors, i);
1701180509fSZhao Yakui if (!pr)
1711180509fSZhao Yakui continue;
1721180509fSZhao Yakui
1731180509fSZhao Yakui /*
1741180509fSZhao Yakui * Assume no coordination on any error parsing domain info.
1751180509fSZhao Yakui * The coordination type will be forced as SW_ALL.
1761180509fSZhao Yakui */
1771180509fSZhao Yakui if (retval) {
1781180509fSZhao Yakui pthrottling = &(pr->throttling);
1792fdf66b4SRusty Russell cpumask_clear(pthrottling->shared_cpu_map);
1802fdf66b4SRusty Russell cpumask_set_cpu(i, pthrottling->shared_cpu_map);
1811180509fSZhao Yakui pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
1821180509fSZhao Yakui }
1831180509fSZhao Yakui }
1841180509fSZhao Yakui
1851180509fSZhao Yakui return retval;
1861180509fSZhao Yakui }
1871180509fSZhao Yakui
1881180509fSZhao Yakui /*
1891180509fSZhao Yakui * Update the T-state coordination after the _TSD
1901180509fSZhao Yakui * data for all cpus is obtained.
1911180509fSZhao Yakui */
acpi_processor_throttling_init(void)1921180509fSZhao Yakui void acpi_processor_throttling_init(void)
1931180509fSZhao Yakui {
19452af99c3SRafael J. Wysocki if (acpi_processor_update_tsd_coord())
19552af99c3SRafael J. Wysocki pr_debug("Assume no T-state coordination\n");
1961180509fSZhao Yakui }
1971180509fSZhao Yakui
acpi_processor_throttling_notifier(unsigned long event,void * data)198e4aa5cb2SZhao Yakui static int acpi_processor_throttling_notifier(unsigned long event, void *data)
199e4aa5cb2SZhao Yakui {
200e4aa5cb2SZhao Yakui struct throttling_tstate *p_tstate = data;
201e4aa5cb2SZhao Yakui struct acpi_processor *pr;
202e4aa5cb2SZhao Yakui unsigned int cpu;
203e4aa5cb2SZhao Yakui int target_state;
204e4aa5cb2SZhao Yakui struct acpi_processor_limit *p_limit;
205e4aa5cb2SZhao Yakui struct acpi_processor_throttling *p_throttling;
206e4aa5cb2SZhao Yakui
207e4aa5cb2SZhao Yakui cpu = p_tstate->cpu;
208706546d0SMike Travis pr = per_cpu(processors, cpu);
209e4aa5cb2SZhao Yakui if (!pr) {
21052af99c3SRafael J. Wysocki pr_debug("Invalid pr pointer\n");
211e4aa5cb2SZhao Yakui return 0;
212e4aa5cb2SZhao Yakui }
213e4aa5cb2SZhao Yakui if (!pr->flags.throttling) {
21452af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
21552af99c3SRafael J. Wysocki "Throttling control unsupported on CPU %d\n",
21652af99c3SRafael J. Wysocki cpu);
217e4aa5cb2SZhao Yakui return 0;
218e4aa5cb2SZhao Yakui }
219e4aa5cb2SZhao Yakui target_state = p_tstate->target_state;
220e4aa5cb2SZhao Yakui p_throttling = &(pr->throttling);
221e4aa5cb2SZhao Yakui switch (event) {
222e4aa5cb2SZhao Yakui case THROTTLING_PRECHANGE:
223e4aa5cb2SZhao Yakui /*
224e4aa5cb2SZhao Yakui * Prechange event is used to choose one proper t-state,
225e4aa5cb2SZhao Yakui * which meets the limits of thermal, user and _TPC.
226e4aa5cb2SZhao Yakui */
227e4aa5cb2SZhao Yakui p_limit = &pr->limit;
228e4aa5cb2SZhao Yakui if (p_limit->thermal.tx > target_state)
229e4aa5cb2SZhao Yakui target_state = p_limit->thermal.tx;
230e4aa5cb2SZhao Yakui if (p_limit->user.tx > target_state)
231e4aa5cb2SZhao Yakui target_state = p_limit->user.tx;
232e4aa5cb2SZhao Yakui if (pr->throttling_platform_limit > target_state)
233e4aa5cb2SZhao Yakui target_state = pr->throttling_platform_limit;
234e4aa5cb2SZhao Yakui if (target_state >= p_throttling->state_count) {
2354140054aSHanjun Guo pr_warn("Exceed the limit of T-state \n");
236e4aa5cb2SZhao Yakui target_state = p_throttling->state_count - 1;
237e4aa5cb2SZhao Yakui }
238e4aa5cb2SZhao Yakui p_tstate->target_state = target_state;
23952af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
24052af99c3SRafael J. Wysocki "PreChange Event: target T-state of CPU %d is T%d\n",
24152af99c3SRafael J. Wysocki cpu, target_state);
242e4aa5cb2SZhao Yakui break;
243e4aa5cb2SZhao Yakui case THROTTLING_POSTCHANGE:
244e4aa5cb2SZhao Yakui /*
245e4aa5cb2SZhao Yakui * Postchange event is only used to update the
246e4aa5cb2SZhao Yakui * T-state flag of acpi_processor_throttling.
247e4aa5cb2SZhao Yakui */
248e4aa5cb2SZhao Yakui p_throttling->state = target_state;
24952af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
25052af99c3SRafael J. Wysocki "PostChange Event: CPU %d is switched to T%d\n",
25152af99c3SRafael J. Wysocki cpu, target_state);
252e4aa5cb2SZhao Yakui break;
253e4aa5cb2SZhao Yakui default:
2544140054aSHanjun Guo pr_warn("Unsupported Throttling notifier event\n");
255e4aa5cb2SZhao Yakui break;
256e4aa5cb2SZhao Yakui }
257e4aa5cb2SZhao Yakui
258e4aa5cb2SZhao Yakui return 0;
259e4aa5cb2SZhao Yakui }
260e4aa5cb2SZhao Yakui
261c30c620eSLen Brown /*
262c30c620eSLen Brown * _TPC - Throttling Present Capabilities
263c30c620eSLen Brown */
acpi_processor_get_platform_limit(struct acpi_processor * pr)26401854e69SLuming Yu static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
26501854e69SLuming Yu {
26601854e69SLuming Yu acpi_status status = 0;
26727663c58SMatthew Wilcox unsigned long long tpc = 0;
26801854e69SLuming Yu
26901854e69SLuming Yu if (!pr)
27001854e69SLuming Yu return -EINVAL;
27156c213faSZhang Rui
27256c213faSZhang Rui if (ignore_tpc)
27356c213faSZhang Rui goto end;
27456c213faSZhang Rui
27501854e69SLuming Yu status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
276c30c620eSLen Brown if (ACPI_FAILURE(status)) {
27752af99c3SRafael J. Wysocki if (status != AE_NOT_FOUND)
2784c324548SRafael J. Wysocki acpi_evaluation_failure_warn(pr->handle, "_TPC", status);
27952af99c3SRafael J. Wysocki
28001854e69SLuming Yu return -ENODEV;
28101854e69SLuming Yu }
28256c213faSZhang Rui
28356c213faSZhang Rui end:
28401854e69SLuming Yu pr->throttling_platform_limit = (int)tpc;
28501854e69SLuming Yu return 0;
28601854e69SLuming Yu }
28701854e69SLuming Yu
acpi_processor_tstate_has_changed(struct acpi_processor * pr)28801854e69SLuming Yu int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
28901854e69SLuming Yu {
290ef54d5adSZhao Yakui int result = 0;
291ef54d5adSZhao Yakui int throttling_limit;
292ef54d5adSZhao Yakui int current_state;
293ef54d5adSZhao Yakui struct acpi_processor_limit *limit;
294ef54d5adSZhao Yakui int target_state;
295ef54d5adSZhao Yakui
29656c213faSZhang Rui if (ignore_tpc)
29756c213faSZhang Rui return 0;
29856c213faSZhang Rui
299ef54d5adSZhao Yakui result = acpi_processor_get_platform_limit(pr);
300ef54d5adSZhao Yakui if (result) {
301ef54d5adSZhao Yakui /* Throttling Limit is unsupported */
302ef54d5adSZhao Yakui return result;
303ef54d5adSZhao Yakui }
304ef54d5adSZhao Yakui
305ef54d5adSZhao Yakui throttling_limit = pr->throttling_platform_limit;
306ef54d5adSZhao Yakui if (throttling_limit >= pr->throttling.state_count) {
307ef54d5adSZhao Yakui /* Uncorrect Throttling Limit */
308ef54d5adSZhao Yakui return -EINVAL;
309ef54d5adSZhao Yakui }
310ef54d5adSZhao Yakui
311ef54d5adSZhao Yakui current_state = pr->throttling.state;
312ef54d5adSZhao Yakui if (current_state > throttling_limit) {
313ef54d5adSZhao Yakui /*
314ef54d5adSZhao Yakui * The current state can meet the requirement of
315ef54d5adSZhao Yakui * _TPC limit. But it is reasonable that OSPM changes
316ef54d5adSZhao Yakui * t-states from high to low for better performance.
317ef54d5adSZhao Yakui * Of course the limit condition of thermal
318ef54d5adSZhao Yakui * and user should be considered.
319ef54d5adSZhao Yakui */
320ef54d5adSZhao Yakui limit = &pr->limit;
321ef54d5adSZhao Yakui target_state = throttling_limit;
322ef54d5adSZhao Yakui if (limit->thermal.tx > target_state)
323ef54d5adSZhao Yakui target_state = limit->thermal.tx;
324ef54d5adSZhao Yakui if (limit->user.tx > target_state)
325ef54d5adSZhao Yakui target_state = limit->user.tx;
326ef54d5adSZhao Yakui } else if (current_state == throttling_limit) {
327ef54d5adSZhao Yakui /*
328ef54d5adSZhao Yakui * Unnecessary to change the throttling state
329ef54d5adSZhao Yakui */
330ef54d5adSZhao Yakui return 0;
331ef54d5adSZhao Yakui } else {
332ef54d5adSZhao Yakui /*
333ef54d5adSZhao Yakui * If the current state is lower than the limit of _TPC, it
334ef54d5adSZhao Yakui * will be forced to switch to the throttling state defined
335ef54d5adSZhao Yakui * by throttling_platfor_limit.
336ef54d5adSZhao Yakui * Because the previous state meets with the limit condition
337ef54d5adSZhao Yakui * of thermal and user, it is unnecessary to check it again.
338ef54d5adSZhao Yakui */
339ef54d5adSZhao Yakui target_state = throttling_limit;
340ef54d5adSZhao Yakui }
3412a908002SFrans Pop return acpi_processor_set_throttling(pr, target_state, false);
34201854e69SLuming Yu }
34301854e69SLuming Yu
344c30c620eSLen Brown /*
3455a344a50SZhao Yakui * This function is used to reevaluate whether the T-state is valid
3465a344a50SZhao Yakui * after one CPU is onlined/offlined.
3475a344a50SZhao Yakui * It is noted that it won't reevaluate the following properties for
3485a344a50SZhao Yakui * the T-state.
3495a344a50SZhao Yakui * 1. Control method.
3505a344a50SZhao Yakui * 2. the number of supported T-state
3515a344a50SZhao Yakui * 3. TSD domain
3525a344a50SZhao Yakui */
acpi_processor_reevaluate_tstate(struct acpi_processor * pr,bool is_dead)3535a344a50SZhao Yakui void acpi_processor_reevaluate_tstate(struct acpi_processor *pr,
35464f3bf2fSSebastian Andrzej Siewior bool is_dead)
3555a344a50SZhao Yakui {
3565a344a50SZhao Yakui int result = 0;
3575a344a50SZhao Yakui
35864f3bf2fSSebastian Andrzej Siewior if (is_dead) {
3595a344a50SZhao Yakui /* When one CPU is offline, the T-state throttling
3605a344a50SZhao Yakui * will be invalidated.
3615a344a50SZhao Yakui */
3625a344a50SZhao Yakui pr->flags.throttling = 0;
3635a344a50SZhao Yakui return;
3645a344a50SZhao Yakui }
3655a344a50SZhao Yakui /* the following is to recheck whether the T-state is valid for
3665a344a50SZhao Yakui * the online CPU
3675a344a50SZhao Yakui */
3685a344a50SZhao Yakui if (!pr->throttling.state_count) {
3695a344a50SZhao Yakui /* If the number of T-state is invalid, it is
3705a344a50SZhao Yakui * invalidated.
3715a344a50SZhao Yakui */
3725a344a50SZhao Yakui pr->flags.throttling = 0;
3735a344a50SZhao Yakui return;
3745a344a50SZhao Yakui }
3755a344a50SZhao Yakui pr->flags.throttling = 1;
3765a344a50SZhao Yakui
3775a344a50SZhao Yakui /* Disable throttling (if enabled). We'll let subsequent
3785a344a50SZhao Yakui * policy (e.g.thermal) decide to lower performance if it
3795a344a50SZhao Yakui * so chooses, but for now we'll crank up the speed.
3805a344a50SZhao Yakui */
3815a344a50SZhao Yakui
3825a344a50SZhao Yakui result = acpi_processor_get_throttling(pr);
3835a344a50SZhao Yakui if (result)
3845a344a50SZhao Yakui goto end;
3855a344a50SZhao Yakui
3865a344a50SZhao Yakui if (pr->throttling.state) {
3875a344a50SZhao Yakui result = acpi_processor_set_throttling(pr, 0, false);
3885a344a50SZhao Yakui if (result)
3895a344a50SZhao Yakui goto end;
3905a344a50SZhao Yakui }
3915a344a50SZhao Yakui
3925a344a50SZhao Yakui end:
3935a344a50SZhao Yakui if (result)
3945a344a50SZhao Yakui pr->flags.throttling = 0;
3955a344a50SZhao Yakui }
3965a344a50SZhao Yakui /*
397c30c620eSLen Brown * _PTC - Processor Throttling Control (and status) register location
398c30c620eSLen Brown */
acpi_processor_get_throttling_control(struct acpi_processor * pr)39901854e69SLuming Yu static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
40001854e69SLuming Yu {
40101854e69SLuming Yu int result = 0;
40201854e69SLuming Yu acpi_status status = 0;
40301854e69SLuming Yu struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
40401854e69SLuming Yu union acpi_object *ptc = NULL;
40569530b43SYang Li union acpi_object obj;
4069bcb2721SZhao Yakui struct acpi_processor_throttling *throttling;
40701854e69SLuming Yu
40801854e69SLuming Yu status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
40901854e69SLuming Yu if (ACPI_FAILURE(status)) {
41052af99c3SRafael J. Wysocki if (status != AE_NOT_FOUND)
4114c324548SRafael J. Wysocki acpi_evaluation_failure_warn(pr->handle, "_PTC", status);
41252af99c3SRafael J. Wysocki
41301854e69SLuming Yu return -ENODEV;
41401854e69SLuming Yu }
41501854e69SLuming Yu
41601854e69SLuming Yu ptc = (union acpi_object *)buffer.pointer;
41701854e69SLuming Yu if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
41801854e69SLuming Yu || (ptc->package.count != 2)) {
4194140054aSHanjun Guo pr_err("Invalid _PTC data\n");
42001854e69SLuming Yu result = -EFAULT;
42101854e69SLuming Yu goto end;
42201854e69SLuming Yu }
42301854e69SLuming Yu
42401854e69SLuming Yu /*
42501854e69SLuming Yu * control_register
42601854e69SLuming Yu */
42701854e69SLuming Yu
42801854e69SLuming Yu obj = ptc->package.elements[0];
42901854e69SLuming Yu
43001854e69SLuming Yu if ((obj.type != ACPI_TYPE_BUFFER)
43101854e69SLuming Yu || (obj.buffer.length < sizeof(struct acpi_ptc_register))
43201854e69SLuming Yu || (obj.buffer.pointer == NULL)) {
4334140054aSHanjun Guo pr_err("Invalid _PTC data (control_register)\n");
43401854e69SLuming Yu result = -EFAULT;
43501854e69SLuming Yu goto end;
43601854e69SLuming Yu }
43701854e69SLuming Yu memcpy(&pr->throttling.control_register, obj.buffer.pointer,
43801854e69SLuming Yu sizeof(struct acpi_ptc_register));
43901854e69SLuming Yu
44001854e69SLuming Yu /*
44101854e69SLuming Yu * status_register
44201854e69SLuming Yu */
44301854e69SLuming Yu
44401854e69SLuming Yu obj = ptc->package.elements[1];
44501854e69SLuming Yu
44601854e69SLuming Yu if ((obj.type != ACPI_TYPE_BUFFER)
44701854e69SLuming Yu || (obj.buffer.length < sizeof(struct acpi_ptc_register))
44801854e69SLuming Yu || (obj.buffer.pointer == NULL)) {
4494140054aSHanjun Guo pr_err("Invalid _PTC data (status_register)\n");
45001854e69SLuming Yu result = -EFAULT;
45101854e69SLuming Yu goto end;
45201854e69SLuming Yu }
45301854e69SLuming Yu
45401854e69SLuming Yu memcpy(&pr->throttling.status_register, obj.buffer.pointer,
45501854e69SLuming Yu sizeof(struct acpi_ptc_register));
45601854e69SLuming Yu
4579bcb2721SZhao Yakui throttling = &pr->throttling;
4589bcb2721SZhao Yakui
4599bcb2721SZhao Yakui if ((throttling->control_register.bit_width +
4609bcb2721SZhao Yakui throttling->control_register.bit_offset) > 32) {
4614140054aSHanjun Guo pr_err("Invalid _PTC control register\n");
4629bcb2721SZhao Yakui result = -EFAULT;
4639bcb2721SZhao Yakui goto end;
4649bcb2721SZhao Yakui }
4659bcb2721SZhao Yakui
4669bcb2721SZhao Yakui if ((throttling->status_register.bit_width +
4679bcb2721SZhao Yakui throttling->status_register.bit_offset) > 32) {
4684140054aSHanjun Guo pr_err("Invalid _PTC status register\n");
4699bcb2721SZhao Yakui result = -EFAULT;
4709bcb2721SZhao Yakui goto end;
4719bcb2721SZhao Yakui }
4729bcb2721SZhao Yakui
47301854e69SLuming Yu end:
47401854e69SLuming Yu kfree(buffer.pointer);
47501854e69SLuming Yu
47601854e69SLuming Yu return result;
47701854e69SLuming Yu }
478c30c620eSLen Brown
479c30c620eSLen Brown /*
480c30c620eSLen Brown * _TSS - Throttling Supported States
481c30c620eSLen Brown */
acpi_processor_get_throttling_states(struct acpi_processor * pr)48201854e69SLuming Yu static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
48301854e69SLuming Yu {
48401854e69SLuming Yu int result = 0;
48501854e69SLuming Yu acpi_status status = AE_OK;
48601854e69SLuming Yu struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
48701854e69SLuming Yu struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
48801854e69SLuming Yu struct acpi_buffer state = { 0, NULL };
48901854e69SLuming Yu union acpi_object *tss = NULL;
49001854e69SLuming Yu int i;
49101854e69SLuming Yu
49201854e69SLuming Yu status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
49301854e69SLuming Yu if (ACPI_FAILURE(status)) {
49452af99c3SRafael J. Wysocki if (status != AE_NOT_FOUND)
4954c324548SRafael J. Wysocki acpi_evaluation_failure_warn(pr->handle, "_TSS", status);
49652af99c3SRafael J. Wysocki
49701854e69SLuming Yu return -ENODEV;
49801854e69SLuming Yu }
49901854e69SLuming Yu
50001854e69SLuming Yu tss = buffer.pointer;
50101854e69SLuming Yu if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
5024140054aSHanjun Guo pr_err("Invalid _TSS data\n");
50301854e69SLuming Yu result = -EFAULT;
50401854e69SLuming Yu goto end;
50501854e69SLuming Yu }
50601854e69SLuming Yu
50752af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle, "Found %d throttling states\n",
50852af99c3SRafael J. Wysocki tss->package.count);
50901854e69SLuming Yu
51001854e69SLuming Yu pr->throttling.state_count = tss->package.count;
51101854e69SLuming Yu pr->throttling.states_tss =
5126da2ec56SKees Cook kmalloc_array(tss->package.count,
5136da2ec56SKees Cook sizeof(struct acpi_processor_tx_tss),
51401854e69SLuming Yu GFP_KERNEL);
51501854e69SLuming Yu if (!pr->throttling.states_tss) {
51601854e69SLuming Yu result = -ENOMEM;
51701854e69SLuming Yu goto end;
51801854e69SLuming Yu }
51901854e69SLuming Yu
52001854e69SLuming Yu for (i = 0; i < pr->throttling.state_count; i++) {
52101854e69SLuming Yu
522ff55a9ceSLen Brown struct acpi_processor_tx_tss *tx =
523ff55a9ceSLen Brown (struct acpi_processor_tx_tss *)&(pr->throttling.
524ff55a9ceSLen Brown states_tss[i]);
52501854e69SLuming Yu
52601854e69SLuming Yu state.length = sizeof(struct acpi_processor_tx_tss);
52701854e69SLuming Yu state.pointer = tx;
52801854e69SLuming Yu
52952af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle, "Extracting state %d\n", i);
53001854e69SLuming Yu
53101854e69SLuming Yu status = acpi_extract_package(&(tss->package.elements[i]),
53201854e69SLuming Yu &format, &state);
53301854e69SLuming Yu if (ACPI_FAILURE(status)) {
53452af99c3SRafael J. Wysocki acpi_handle_warn(pr->handle, "Invalid _TSS data: %s\n",
53552af99c3SRafael J. Wysocki acpi_format_exception(status));
53601854e69SLuming Yu result = -EFAULT;
53701854e69SLuming Yu kfree(pr->throttling.states_tss);
53801854e69SLuming Yu goto end;
53901854e69SLuming Yu }
54001854e69SLuming Yu
54101854e69SLuming Yu if (!tx->freqpercentage) {
5424140054aSHanjun Guo pr_err("Invalid _TSS data: freq is zero\n");
54301854e69SLuming Yu result = -EFAULT;
54401854e69SLuming Yu kfree(pr->throttling.states_tss);
54501854e69SLuming Yu goto end;
54601854e69SLuming Yu }
54701854e69SLuming Yu }
54801854e69SLuming Yu
54901854e69SLuming Yu end:
55001854e69SLuming Yu kfree(buffer.pointer);
55101854e69SLuming Yu
55201854e69SLuming Yu return result;
55301854e69SLuming Yu }
554c30c620eSLen Brown
555c30c620eSLen Brown /*
556c30c620eSLen Brown * _TSD - T-State Dependencies
557c30c620eSLen Brown */
acpi_processor_get_tsd(struct acpi_processor * pr)55801854e69SLuming Yu static int acpi_processor_get_tsd(struct acpi_processor *pr)
55901854e69SLuming Yu {
56001854e69SLuming Yu int result = 0;
56101854e69SLuming Yu acpi_status status = AE_OK;
56201854e69SLuming Yu struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
56301854e69SLuming Yu struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
56401854e69SLuming Yu struct acpi_buffer state = { 0, NULL };
56501854e69SLuming Yu union acpi_object *tsd = NULL;
56601854e69SLuming Yu struct acpi_tsd_package *pdomain;
5671180509fSZhao Yakui struct acpi_processor_throttling *pthrottling;
5681180509fSZhao Yakui
5691180509fSZhao Yakui pthrottling = &pr->throttling;
5701180509fSZhao Yakui pthrottling->tsd_valid_flag = 0;
57101854e69SLuming Yu
57201854e69SLuming Yu status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
57301854e69SLuming Yu if (ACPI_FAILURE(status)) {
57452af99c3SRafael J. Wysocki if (status != AE_NOT_FOUND)
5754c324548SRafael J. Wysocki acpi_evaluation_failure_warn(pr->handle, "_TSD", status);
57652af99c3SRafael J. Wysocki
57701854e69SLuming Yu return -ENODEV;
57801854e69SLuming Yu }
57901854e69SLuming Yu
58001854e69SLuming Yu tsd = buffer.pointer;
58101854e69SLuming Yu if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
5824140054aSHanjun Guo pr_err("Invalid _TSD data\n");
58301854e69SLuming Yu result = -EFAULT;
58401854e69SLuming Yu goto end;
58501854e69SLuming Yu }
58601854e69SLuming Yu
58701854e69SLuming Yu if (tsd->package.count != 1) {
5884140054aSHanjun Guo pr_err("Invalid _TSD data\n");
58901854e69SLuming Yu result = -EFAULT;
59001854e69SLuming Yu goto end;
59101854e69SLuming Yu }
59201854e69SLuming Yu
59301854e69SLuming Yu pdomain = &(pr->throttling.domain_info);
59401854e69SLuming Yu
59501854e69SLuming Yu state.length = sizeof(struct acpi_tsd_package);
59601854e69SLuming Yu state.pointer = pdomain;
59701854e69SLuming Yu
59801854e69SLuming Yu status = acpi_extract_package(&(tsd->package.elements[0]),
59901854e69SLuming Yu &format, &state);
60001854e69SLuming Yu if (ACPI_FAILURE(status)) {
6014140054aSHanjun Guo pr_err("Invalid _TSD data\n");
60201854e69SLuming Yu result = -EFAULT;
60301854e69SLuming Yu goto end;
60401854e69SLuming Yu }
60501854e69SLuming Yu
60601854e69SLuming Yu if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
6074140054aSHanjun Guo pr_err("Unknown _TSD:num_entries\n");
60801854e69SLuming Yu result = -EFAULT;
60901854e69SLuming Yu goto end;
61001854e69SLuming Yu }
61101854e69SLuming Yu
61201854e69SLuming Yu if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
6134140054aSHanjun Guo pr_err("Unknown _TSD:revision\n");
61401854e69SLuming Yu result = -EFAULT;
61501854e69SLuming Yu goto end;
61601854e69SLuming Yu }
61701854e69SLuming Yu
6181180509fSZhao Yakui pthrottling = &pr->throttling;
6191180509fSZhao Yakui pthrottling->tsd_valid_flag = 1;
6201180509fSZhao Yakui pthrottling->shared_type = pdomain->coord_type;
6212fdf66b4SRusty Russell cpumask_set_cpu(pr->id, pthrottling->shared_cpu_map);
6221180509fSZhao Yakui /*
6231180509fSZhao Yakui * If the coordination type is not defined in ACPI spec,
6241180509fSZhao Yakui * the tsd_valid_flag will be clear and coordination type
6251180509fSZhao Yakui * will be forecd as DOMAIN_COORD_TYPE_SW_ALL.
6261180509fSZhao Yakui */
6271180509fSZhao Yakui if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
6281180509fSZhao Yakui pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
6291180509fSZhao Yakui pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
6301180509fSZhao Yakui pthrottling->tsd_valid_flag = 0;
6311180509fSZhao Yakui pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
6321180509fSZhao Yakui }
6331180509fSZhao Yakui
63401854e69SLuming Yu end:
63501854e69SLuming Yu kfree(buffer.pointer);
63601854e69SLuming Yu return result;
63701854e69SLuming Yu }
63801854e69SLuming Yu
6391da177e4SLinus Torvalds /* --------------------------------------------------------------------------
6401da177e4SLinus Torvalds Throttling Control
6411da177e4SLinus Torvalds -------------------------------------------------------------------------- */
acpi_processor_get_throttling_fadt(struct acpi_processor * pr)64201854e69SLuming Yu static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
6431da177e4SLinus Torvalds {
6441da177e4SLinus Torvalds int state = 0;
6451da177e4SLinus Torvalds u32 value = 0;
6461da177e4SLinus Torvalds u32 duty_mask = 0;
6471da177e4SLinus Torvalds u32 duty_value = 0;
6481da177e4SLinus Torvalds
6491da177e4SLinus Torvalds if (!pr)
650d550d98dSPatrick Mochel return -EINVAL;
6511da177e4SLinus Torvalds
6521da177e4SLinus Torvalds if (!pr->flags.throttling)
653d550d98dSPatrick Mochel return -ENODEV;
6541da177e4SLinus Torvalds
65586314751SRafael J. Wysocki /*
65686314751SRafael J. Wysocki * We don't care about error returns - we just try to mark
65786314751SRafael J. Wysocki * these reserved so that nobody else is confused into thinking
65886314751SRafael J. Wysocki * that this region might be unused..
65986314751SRafael J. Wysocki *
66086314751SRafael J. Wysocki * (In particular, allocating the IO range for Cardbus)
66186314751SRafael J. Wysocki */
66286314751SRafael J. Wysocki request_region(pr->throttling.address, 6, "ACPI CPU throttle");
66386314751SRafael J. Wysocki
6641da177e4SLinus Torvalds pr->throttling.state = 0;
6651da177e4SLinus Torvalds
6661da177e4SLinus Torvalds duty_mask = pr->throttling.state_count - 1;
6671da177e4SLinus Torvalds
6681da177e4SLinus Torvalds duty_mask <<= pr->throttling.duty_offset;
6691da177e4SLinus Torvalds
6701da177e4SLinus Torvalds local_irq_disable();
6711da177e4SLinus Torvalds
6721da177e4SLinus Torvalds value = inl(pr->throttling.address);
6731da177e4SLinus Torvalds
6741da177e4SLinus Torvalds /*
6751da177e4SLinus Torvalds * Compute the current throttling state when throttling is enabled
6761da177e4SLinus Torvalds * (bit 4 is on).
6771da177e4SLinus Torvalds */
6781da177e4SLinus Torvalds if (value & 0x10) {
6791da177e4SLinus Torvalds duty_value = value & duty_mask;
6801da177e4SLinus Torvalds duty_value >>= pr->throttling.duty_offset;
6811da177e4SLinus Torvalds
6821da177e4SLinus Torvalds if (duty_value)
6831da177e4SLinus Torvalds state = pr->throttling.state_count - duty_value;
6841da177e4SLinus Torvalds }
6851da177e4SLinus Torvalds
6861da177e4SLinus Torvalds pr->throttling.state = state;
6871da177e4SLinus Torvalds
6881da177e4SLinus Torvalds local_irq_enable();
6891da177e4SLinus Torvalds
69052af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
6911da177e4SLinus Torvalds "Throttling state is T%d (%d%% throttling applied)\n",
69252af99c3SRafael J. Wysocki state, pr->throttling.states[state].performance);
6931da177e4SLinus Torvalds
694d550d98dSPatrick Mochel return 0;
6951da177e4SLinus Torvalds }
6961da177e4SLinus Torvalds
697f79f06abSZhao Yakui #ifdef CONFIG_X86
acpi_throttling_rdmsr(u64 * value)6989d42a53eSChristoph Lameter static int acpi_throttling_rdmsr(u64 *value)
699f79f06abSZhao Yakui {
700f79f06abSZhao Yakui u64 msr_high, msr_low;
701f79f06abSZhao Yakui u64 msr = 0;
702f79f06abSZhao Yakui int ret = -1;
703f79f06abSZhao Yakui
7049d42a53eSChristoph Lameter if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
7059d42a53eSChristoph Lameter !this_cpu_has(X86_FEATURE_ACPI)) {
7064140054aSHanjun Guo pr_err("HARDWARE addr space,NOT supported yet\n");
707f79f06abSZhao Yakui } else {
708f79f06abSZhao Yakui msr_low = 0;
709f79f06abSZhao Yakui msr_high = 0;
710357dc4c3SZhao Yakui rdmsr_safe(MSR_IA32_THERM_CONTROL,
711f79f06abSZhao Yakui (u32 *)&msr_low, (u32 *) &msr_high);
712f79f06abSZhao Yakui msr = (msr_high << 32) | msr_low;
713439913ffSLin Ming *value = (u64) msr;
714f79f06abSZhao Yakui ret = 0;
715f79f06abSZhao Yakui }
716f79f06abSZhao Yakui return ret;
717f79f06abSZhao Yakui }
718f79f06abSZhao Yakui
acpi_throttling_wrmsr(u64 value)7199d42a53eSChristoph Lameter static int acpi_throttling_wrmsr(u64 value)
720f79f06abSZhao Yakui {
721f79f06abSZhao Yakui int ret = -1;
722f79f06abSZhao Yakui u64 msr;
723f79f06abSZhao Yakui
7249d42a53eSChristoph Lameter if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
7259d42a53eSChristoph Lameter !this_cpu_has(X86_FEATURE_ACPI)) {
7264140054aSHanjun Guo pr_err("HARDWARE addr space,NOT supported yet\n");
727f79f06abSZhao Yakui } else {
728f79f06abSZhao Yakui msr = value;
729357dc4c3SZhao Yakui wrmsr_safe(MSR_IA32_THERM_CONTROL,
730f79f06abSZhao Yakui msr & 0xffffffff, msr >> 32);
731f79f06abSZhao Yakui ret = 0;
732f79f06abSZhao Yakui }
733f79f06abSZhao Yakui return ret;
734f79f06abSZhao Yakui }
735f79f06abSZhao Yakui #else
acpi_throttling_rdmsr(u64 * value)7369d42a53eSChristoph Lameter static int acpi_throttling_rdmsr(u64 *value)
737f79f06abSZhao Yakui {
7384140054aSHanjun Guo pr_err("HARDWARE addr space,NOT supported yet\n");
739f79f06abSZhao Yakui return -1;
740f79f06abSZhao Yakui }
741f79f06abSZhao Yakui
acpi_throttling_wrmsr(u64 value)7429d42a53eSChristoph Lameter static int acpi_throttling_wrmsr(u64 value)
743f79f06abSZhao Yakui {
7444140054aSHanjun Guo pr_err("HARDWARE addr space,NOT supported yet\n");
745f79f06abSZhao Yakui return -1;
746f79f06abSZhao Yakui }
747f79f06abSZhao Yakui #endif
748f79f06abSZhao Yakui
acpi_read_throttling_status(struct acpi_processor * pr,u64 * value)7490753f6e0SZhao Yakui static int acpi_read_throttling_status(struct acpi_processor *pr,
750439913ffSLin Ming u64 *value)
75101854e69SLuming Yu {
7529bcb2721SZhao Yakui u32 bit_width, bit_offset;
753344e222eSDan Carpenter u32 ptc_value;
7549bcb2721SZhao Yakui u64 ptc_mask;
7550753f6e0SZhao Yakui struct acpi_processor_throttling *throttling;
7560753f6e0SZhao Yakui int ret = -1;
7570753f6e0SZhao Yakui
7580753f6e0SZhao Yakui throttling = &pr->throttling;
75901854e69SLuming Yu switch (throttling->status_register.space_id) {
76001854e69SLuming Yu case ACPI_ADR_SPACE_SYSTEM_IO:
7619bcb2721SZhao Yakui bit_width = throttling->status_register.bit_width;
7629bcb2721SZhao Yakui bit_offset = throttling->status_register.bit_offset;
7639bcb2721SZhao Yakui
764ff55a9ceSLen Brown acpi_os_read_port((acpi_io_address) throttling->status_register.
765344e222eSDan Carpenter address, &ptc_value,
7669bcb2721SZhao Yakui (u32) (bit_width + bit_offset));
7679bcb2721SZhao Yakui ptc_mask = (1 << bit_width) - 1;
768439913ffSLin Ming *value = (u64) ((ptc_value >> bit_offset) & ptc_mask);
7690753f6e0SZhao Yakui ret = 0;
77001854e69SLuming Yu break;
77101854e69SLuming Yu case ACPI_ADR_SPACE_FIXED_HARDWARE:
7729d42a53eSChristoph Lameter ret = acpi_throttling_rdmsr(value);
77301854e69SLuming Yu break;
77401854e69SLuming Yu default:
7754140054aSHanjun Guo pr_err("Unknown addr space %d\n",
77601854e69SLuming Yu (u32) (throttling->status_register.space_id));
77701854e69SLuming Yu }
7780753f6e0SZhao Yakui return ret;
77901854e69SLuming Yu }
78001854e69SLuming Yu
acpi_write_throttling_state(struct acpi_processor * pr,u64 value)7810753f6e0SZhao Yakui static int acpi_write_throttling_state(struct acpi_processor *pr,
782439913ffSLin Ming u64 value)
78301854e69SLuming Yu {
7849bcb2721SZhao Yakui u32 bit_width, bit_offset;
7850753f6e0SZhao Yakui u64 ptc_value;
7869bcb2721SZhao Yakui u64 ptc_mask;
7870753f6e0SZhao Yakui struct acpi_processor_throttling *throttling;
78801854e69SLuming Yu int ret = -1;
78901854e69SLuming Yu
7900753f6e0SZhao Yakui throttling = &pr->throttling;
79101854e69SLuming Yu switch (throttling->control_register.space_id) {
79201854e69SLuming Yu case ACPI_ADR_SPACE_SYSTEM_IO:
7939bcb2721SZhao Yakui bit_width = throttling->control_register.bit_width;
7949bcb2721SZhao Yakui bit_offset = throttling->control_register.bit_offset;
7959bcb2721SZhao Yakui ptc_mask = (1 << bit_width) - 1;
7969bcb2721SZhao Yakui ptc_value = value & ptc_mask;
7979bcb2721SZhao Yakui
798ff55a9ceSLen Brown acpi_os_write_port((acpi_io_address) throttling->
7999bcb2721SZhao Yakui control_register.address,
8009bcb2721SZhao Yakui (u32) (ptc_value << bit_offset),
8019bcb2721SZhao Yakui (u32) (bit_width + bit_offset));
80201854e69SLuming Yu ret = 0;
80301854e69SLuming Yu break;
80401854e69SLuming Yu case ACPI_ADR_SPACE_FIXED_HARDWARE:
8059d42a53eSChristoph Lameter ret = acpi_throttling_wrmsr(value);
80601854e69SLuming Yu break;
80701854e69SLuming Yu default:
8084140054aSHanjun Guo pr_err("Unknown addr space %d\n",
80901854e69SLuming Yu (u32) (throttling->control_register.space_id));
81001854e69SLuming Yu }
81101854e69SLuming Yu return ret;
81201854e69SLuming Yu }
81301854e69SLuming Yu
acpi_get_throttling_state(struct acpi_processor * pr,u64 value)8140753f6e0SZhao Yakui static int acpi_get_throttling_state(struct acpi_processor *pr,
815439913ffSLin Ming u64 value)
81601854e69SLuming Yu {
81701854e69SLuming Yu int i;
81801854e69SLuming Yu
81901854e69SLuming Yu for (i = 0; i < pr->throttling.state_count; i++) {
820ff55a9ceSLen Brown struct acpi_processor_tx_tss *tx =
821ff55a9ceSLen Brown (struct acpi_processor_tx_tss *)&(pr->throttling.
822ff55a9ceSLen Brown states_tss[i]);
82301854e69SLuming Yu if (tx->control == value)
82401854e69SLuming Yu return i;
82501854e69SLuming Yu }
82653af9cfbSLen Brown return -1;
82753af9cfbSLen Brown }
82801854e69SLuming Yu
acpi_get_throttling_value(struct acpi_processor * pr,int state,u64 * value)8290753f6e0SZhao Yakui static int acpi_get_throttling_value(struct acpi_processor *pr,
830439913ffSLin Ming int state, u64 *value)
83101854e69SLuming Yu {
8320753f6e0SZhao Yakui int ret = -1;
8330753f6e0SZhao Yakui
83401854e69SLuming Yu if (state >= 0 && state <= pr->throttling.state_count) {
835ff55a9ceSLen Brown struct acpi_processor_tx_tss *tx =
836ff55a9ceSLen Brown (struct acpi_processor_tx_tss *)&(pr->throttling.
837ff55a9ceSLen Brown states_tss[state]);
8380753f6e0SZhao Yakui *value = tx->control;
8390753f6e0SZhao Yakui ret = 0;
84001854e69SLuming Yu }
8410753f6e0SZhao Yakui return ret;
84201854e69SLuming Yu }
84301854e69SLuming Yu
acpi_processor_get_throttling_ptc(struct acpi_processor * pr)84401854e69SLuming Yu static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
84501854e69SLuming Yu {
84601854e69SLuming Yu int state = 0;
8470753f6e0SZhao Yakui int ret;
848439913ffSLin Ming u64 value;
84901854e69SLuming Yu
85001854e69SLuming Yu if (!pr)
85101854e69SLuming Yu return -EINVAL;
85201854e69SLuming Yu
85301854e69SLuming Yu if (!pr->flags.throttling)
85401854e69SLuming Yu return -ENODEV;
85501854e69SLuming Yu
85601854e69SLuming Yu pr->throttling.state = 0;
857357dc4c3SZhao Yakui
8580753f6e0SZhao Yakui value = 0;
8590753f6e0SZhao Yakui ret = acpi_read_throttling_status(pr, &value);
8600753f6e0SZhao Yakui if (ret >= 0) {
86101854e69SLuming Yu state = acpi_get_throttling_state(pr, value);
8624973b22aSZhang Rui if (state == -1) {
86352af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
86452af99c3SRafael J. Wysocki "Invalid throttling state, reset\n");
8654973b22aSZhang Rui state = 0;
8668153f9acSThomas Gleixner ret = __acpi_processor_set_throttling(pr, state, true,
8678153f9acSThomas Gleixner true);
8684973b22aSZhang Rui if (ret)
8694973b22aSZhang Rui return ret;
8704973b22aSZhang Rui }
87101854e69SLuming Yu pr->throttling.state = state;
87201854e69SLuming Yu }
87301854e69SLuming Yu
87401854e69SLuming Yu return 0;
87501854e69SLuming Yu }
87601854e69SLuming Yu
__acpi_processor_get_throttling(void * data)8778153f9acSThomas Gleixner static long __acpi_processor_get_throttling(void *data)
8788153f9acSThomas Gleixner {
8798153f9acSThomas Gleixner struct acpi_processor *pr = data;
8808153f9acSThomas Gleixner
8818153f9acSThomas Gleixner return pr->throttling.acpi_processor_get_throttling(pr);
8828153f9acSThomas Gleixner }
8838153f9acSThomas Gleixner
acpi_processor_get_throttling(struct acpi_processor * pr)88401854e69SLuming Yu static int acpi_processor_get_throttling(struct acpi_processor *pr)
88501854e69SLuming Yu {
88687654273SZhao Yakui if (!pr)
88787654273SZhao Yakui return -EINVAL;
88887654273SZhao Yakui
88987654273SZhao Yakui if (!pr->flags.throttling)
89087654273SZhao Yakui return -ENODEV;
8912fdf66b4SRusty Russell
892357dc4c3SZhao Yakui /*
8938153f9acSThomas Gleixner * This is either called from the CPU hotplug callback of
8948153f9acSThomas Gleixner * processor_driver or via the ACPI probe function. In the latter
8958153f9acSThomas Gleixner * case the CPU is not guaranteed to be online. Both call sites are
8968153f9acSThomas Gleixner * protected against CPU hotplug.
897357dc4c3SZhao Yakui */
8988153f9acSThomas Gleixner if (!cpu_online(pr->id))
899daef1f35SZhao Yakui return -ENODEV;
900357dc4c3SZhao Yakui
9010266d81eSThomas Gleixner return call_on_cpu(pr->id, __acpi_processor_get_throttling, pr, false);
90201854e69SLuming Yu }
90301854e69SLuming Yu
acpi_processor_get_fadt_info(struct acpi_processor * pr)90422cc5019SZhao Yakui static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
90522cc5019SZhao Yakui {
90622cc5019SZhao Yakui int i, step;
90722cc5019SZhao Yakui
90822cc5019SZhao Yakui if (!pr->throttling.address) {
90952af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle, "No throttling register\n");
91022cc5019SZhao Yakui return -EINVAL;
91122cc5019SZhao Yakui } else if (!pr->throttling.duty_width) {
91252af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle, "No throttling states\n");
91322cc5019SZhao Yakui return -EINVAL;
91422cc5019SZhao Yakui }
91522cc5019SZhao Yakui /* TBD: Support duty_cycle values that span bit 4. */
91622cc5019SZhao Yakui else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
9174140054aSHanjun Guo pr_warn("duty_cycle spans bit 4\n");
91822cc5019SZhao Yakui return -EINVAL;
91922cc5019SZhao Yakui }
92022cc5019SZhao Yakui
92122cc5019SZhao Yakui pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
92222cc5019SZhao Yakui
92322cc5019SZhao Yakui /*
92422cc5019SZhao Yakui * Compute state values. Note that throttling displays a linear power
92522cc5019SZhao Yakui * performance relationship (at 50% performance the CPU will consume
92622cc5019SZhao Yakui * 50% power). Values are in 1/10th of a percent to preserve accuracy.
92722cc5019SZhao Yakui */
92822cc5019SZhao Yakui
92922cc5019SZhao Yakui step = (1000 / pr->throttling.state_count);
93022cc5019SZhao Yakui
93122cc5019SZhao Yakui for (i = 0; i < pr->throttling.state_count; i++) {
93222cc5019SZhao Yakui pr->throttling.states[i].performance = 1000 - step * i;
93322cc5019SZhao Yakui pr->throttling.states[i].power = 1000 - step * i;
93422cc5019SZhao Yakui }
93522cc5019SZhao Yakui return 0;
93622cc5019SZhao Yakui }
93722cc5019SZhao Yakui
acpi_processor_set_throttling_fadt(struct acpi_processor * pr,int state,bool force)9386c5cf8aaSAdrian Bunk static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
9392a908002SFrans Pop int state, bool force)
9401da177e4SLinus Torvalds {
9411da177e4SLinus Torvalds u32 value = 0;
9421da177e4SLinus Torvalds u32 duty_mask = 0;
9431da177e4SLinus Torvalds u32 duty_value = 0;
9441da177e4SLinus Torvalds
9451da177e4SLinus Torvalds if (!pr)
946d550d98dSPatrick Mochel return -EINVAL;
9471da177e4SLinus Torvalds
9481da177e4SLinus Torvalds if ((state < 0) || (state > (pr->throttling.state_count - 1)))
949d550d98dSPatrick Mochel return -EINVAL;
9501da177e4SLinus Torvalds
9511da177e4SLinus Torvalds if (!pr->flags.throttling)
952d550d98dSPatrick Mochel return -ENODEV;
9531da177e4SLinus Torvalds
9542a908002SFrans Pop if (!force && (state == pr->throttling.state))
955d550d98dSPatrick Mochel return 0;
9561da177e4SLinus Torvalds
95701854e69SLuming Yu if (state < pr->throttling_platform_limit)
95801854e69SLuming Yu return -EPERM;
9591da177e4SLinus Torvalds /*
9601da177e4SLinus Torvalds * Calculate the duty_value and duty_mask.
9611da177e4SLinus Torvalds */
9621da177e4SLinus Torvalds if (state) {
9631da177e4SLinus Torvalds duty_value = pr->throttling.state_count - state;
9641da177e4SLinus Torvalds
9651da177e4SLinus Torvalds duty_value <<= pr->throttling.duty_offset;
9661da177e4SLinus Torvalds
9671da177e4SLinus Torvalds /* Used to clear all duty_value bits */
9681da177e4SLinus Torvalds duty_mask = pr->throttling.state_count - 1;
9691da177e4SLinus Torvalds
970cee324b1SAlexey Starikovskiy duty_mask <<= acpi_gbl_FADT.duty_offset;
9711da177e4SLinus Torvalds duty_mask = ~duty_mask;
9721da177e4SLinus Torvalds }
9731da177e4SLinus Torvalds
9741da177e4SLinus Torvalds local_irq_disable();
9751da177e4SLinus Torvalds
9761da177e4SLinus Torvalds /*
9771da177e4SLinus Torvalds * Disable throttling by writing a 0 to bit 4. Note that we must
9781da177e4SLinus Torvalds * turn it off before you can change the duty_value.
9791da177e4SLinus Torvalds */
9801da177e4SLinus Torvalds value = inl(pr->throttling.address);
9811da177e4SLinus Torvalds if (value & 0x10) {
9821da177e4SLinus Torvalds value &= 0xFFFFFFEF;
9831da177e4SLinus Torvalds outl(value, pr->throttling.address);
9841da177e4SLinus Torvalds }
9851da177e4SLinus Torvalds
9861da177e4SLinus Torvalds /*
9871da177e4SLinus Torvalds * Write the new duty_value and then enable throttling. Note
9881da177e4SLinus Torvalds * that a state value of 0 leaves throttling disabled.
9891da177e4SLinus Torvalds */
9901da177e4SLinus Torvalds if (state) {
9911da177e4SLinus Torvalds value &= duty_mask;
9921da177e4SLinus Torvalds value |= duty_value;
9931da177e4SLinus Torvalds outl(value, pr->throttling.address);
9941da177e4SLinus Torvalds
9951da177e4SLinus Torvalds value |= 0x00000010;
9961da177e4SLinus Torvalds outl(value, pr->throttling.address);
9971da177e4SLinus Torvalds }
9981da177e4SLinus Torvalds
9991da177e4SLinus Torvalds pr->throttling.state = state;
10001da177e4SLinus Torvalds
10011da177e4SLinus Torvalds local_irq_enable();
10021da177e4SLinus Torvalds
100352af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
10041da177e4SLinus Torvalds "Throttling state set to T%d (%d%%)\n", state,
10054be44fcdSLen Brown (pr->throttling.states[state].performance ? pr->
100652af99c3SRafael J. Wysocki throttling.states[state].performance / 10 : 0));
10071da177e4SLinus Torvalds
1008d550d98dSPatrick Mochel return 0;
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds
acpi_processor_set_throttling_ptc(struct acpi_processor * pr,int state,bool force)10116c5cf8aaSAdrian Bunk static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
10122a908002SFrans Pop int state, bool force)
101301854e69SLuming Yu {
10140753f6e0SZhao Yakui int ret;
1015439913ffSLin Ming u64 value;
101601854e69SLuming Yu
101701854e69SLuming Yu if (!pr)
101801854e69SLuming Yu return -EINVAL;
101901854e69SLuming Yu
102001854e69SLuming Yu if ((state < 0) || (state > (pr->throttling.state_count - 1)))
102101854e69SLuming Yu return -EINVAL;
102201854e69SLuming Yu
102301854e69SLuming Yu if (!pr->flags.throttling)
102401854e69SLuming Yu return -ENODEV;
102501854e69SLuming Yu
10262a908002SFrans Pop if (!force && (state == pr->throttling.state))
102701854e69SLuming Yu return 0;
102801854e69SLuming Yu
102901854e69SLuming Yu if (state < pr->throttling_platform_limit)
103001854e69SLuming Yu return -EPERM;
103101854e69SLuming Yu
10320753f6e0SZhao Yakui value = 0;
10330753f6e0SZhao Yakui ret = acpi_get_throttling_value(pr, state, &value);
10340753f6e0SZhao Yakui if (ret >= 0) {
10350753f6e0SZhao Yakui acpi_write_throttling_state(pr, value);
103601854e69SLuming Yu pr->throttling.state = state;
103701854e69SLuming Yu }
103801854e69SLuming Yu
103901854e69SLuming Yu return 0;
104001854e69SLuming Yu }
104101854e69SLuming Yu
acpi_processor_throttling_fn(void * data)1042f3ca4164SLan Tianyu static long acpi_processor_throttling_fn(void *data)
1043f3ca4164SLan Tianyu {
1044f3ca4164SLan Tianyu struct acpi_processor_throttling_arg *arg = data;
1045f3ca4164SLan Tianyu struct acpi_processor *pr = arg->pr;
1046f3ca4164SLan Tianyu
1047f3ca4164SLan Tianyu return pr->throttling.acpi_processor_set_throttling(pr,
1048f3ca4164SLan Tianyu arg->target_state, arg->force);
1049f3ca4164SLan Tianyu }
1050f3ca4164SLan Tianyu
__acpi_processor_set_throttling(struct acpi_processor * pr,int state,bool force,bool direct)10518153f9acSThomas Gleixner static int __acpi_processor_set_throttling(struct acpi_processor *pr,
10528153f9acSThomas Gleixner int state, bool force, bool direct)
105301854e69SLuming Yu {
10543391a76fSLen Brown int ret = 0;
105533a2a529SZhao Yakui unsigned int i;
105633a2a529SZhao Yakui struct acpi_processor *match_pr;
105733a2a529SZhao Yakui struct acpi_processor_throttling *p_throttling;
1058f3ca4164SLan Tianyu struct acpi_processor_throttling_arg arg;
105933a2a529SZhao Yakui struct throttling_tstate t_state;
106087654273SZhao Yakui
106187654273SZhao Yakui if (!pr)
106287654273SZhao Yakui return -EINVAL;
106387654273SZhao Yakui
106487654273SZhao Yakui if (!pr->flags.throttling)
106587654273SZhao Yakui return -ENODEV;
106687654273SZhao Yakui
106787654273SZhao Yakui if ((state < 0) || (state > (pr->throttling.state_count - 1)))
106887654273SZhao Yakui return -EINVAL;
106987654273SZhao Yakui
1070daef1f35SZhao Yakui if (cpu_is_offline(pr->id)) {
1071daef1f35SZhao Yakui /*
1072daef1f35SZhao Yakui * the cpu pointed by pr->id is offline. Unnecessary to change
1073daef1f35SZhao Yakui * the throttling state any more.
1074daef1f35SZhao Yakui */
1075daef1f35SZhao Yakui return -ENODEV;
1076daef1f35SZhao Yakui }
1077daef1f35SZhao Yakui
107833a2a529SZhao Yakui t_state.target_state = state;
107933a2a529SZhao Yakui p_throttling = &(pr->throttling);
1080f3ca4164SLan Tianyu
108133a2a529SZhao Yakui /*
108233a2a529SZhao Yakui * The throttling notifier will be called for every
108333a2a529SZhao Yakui * affected cpu in order to get one proper T-state.
108433a2a529SZhao Yakui * The notifier event is THROTTLING_PRECHANGE.
108533a2a529SZhao Yakui */
1086f3ca4164SLan Tianyu for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
108733a2a529SZhao Yakui t_state.cpu = i;
108833a2a529SZhao Yakui acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
108933a2a529SZhao Yakui &t_state);
109033a2a529SZhao Yakui }
109133a2a529SZhao Yakui /*
109233a2a529SZhao Yakui * The function of acpi_processor_set_throttling will be called
109333a2a529SZhao Yakui * to switch T-state. If the coordination type is SW_ALL or HW_ALL,
109433a2a529SZhao Yakui * it is necessary to call it for every affected cpu. Otherwise
109533a2a529SZhao Yakui * it can be called only for the cpu pointed by pr.
109633a2a529SZhao Yakui */
109733a2a529SZhao Yakui if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
1098f3ca4164SLan Tianyu arg.pr = pr;
1099f3ca4164SLan Tianyu arg.target_state = state;
1100f3ca4164SLan Tianyu arg.force = force;
11018153f9acSThomas Gleixner ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg,
11028153f9acSThomas Gleixner direct);
110333a2a529SZhao Yakui } else {
110433a2a529SZhao Yakui /*
110533a2a529SZhao Yakui * When the T-state coordination is SW_ALL or HW_ALL,
110633a2a529SZhao Yakui * it is necessary to set T-state for every affected
110733a2a529SZhao Yakui * cpus.
110833a2a529SZhao Yakui */
1109f3ca4164SLan Tianyu for_each_cpu_and(i, cpu_online_mask,
1110f3ca4164SLan Tianyu p_throttling->shared_cpu_map) {
1111706546d0SMike Travis match_pr = per_cpu(processors, i);
111233a2a529SZhao Yakui /*
111333a2a529SZhao Yakui * If the pointer is invalid, we will report the
111433a2a529SZhao Yakui * error message and continue.
111533a2a529SZhao Yakui */
111633a2a529SZhao Yakui if (!match_pr) {
111752af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
111852af99c3SRafael J. Wysocki "Invalid Pointer for CPU %d\n", i);
111933a2a529SZhao Yakui continue;
112033a2a529SZhao Yakui }
112133a2a529SZhao Yakui /*
112233a2a529SZhao Yakui * If the throttling control is unsupported on CPU i,
112333a2a529SZhao Yakui * we will report the error message and continue.
112433a2a529SZhao Yakui */
112533a2a529SZhao Yakui if (!match_pr->flags.throttling) {
112652af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
112752af99c3SRafael J. Wysocki "Throttling Control unsupported on CPU %d\n", i);
112833a2a529SZhao Yakui continue;
112933a2a529SZhao Yakui }
1130f3ca4164SLan Tianyu
1131f3ca4164SLan Tianyu arg.pr = match_pr;
1132f3ca4164SLan Tianyu arg.target_state = state;
1133f3ca4164SLan Tianyu arg.force = force;
11348153f9acSThomas Gleixner ret = call_on_cpu(pr->id, acpi_processor_throttling_fn,
11358153f9acSThomas Gleixner &arg, direct);
113633a2a529SZhao Yakui }
113733a2a529SZhao Yakui }
113833a2a529SZhao Yakui /*
113933a2a529SZhao Yakui * After the set_throttling is called, the
114033a2a529SZhao Yakui * throttling notifier is called for every
114133a2a529SZhao Yakui * affected cpu to update the T-states.
114233a2a529SZhao Yakui * The notifier event is THROTTLING_POSTCHANGE
114333a2a529SZhao Yakui */
1144f3ca4164SLan Tianyu for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
114533a2a529SZhao Yakui t_state.cpu = i;
114633a2a529SZhao Yakui acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
114733a2a529SZhao Yakui &t_state);
114833a2a529SZhao Yakui }
1149f3ca4164SLan Tianyu
1150357dc4c3SZhao Yakui return ret;
115101854e69SLuming Yu }
115201854e69SLuming Yu
acpi_processor_set_throttling(struct acpi_processor * pr,int state,bool force)11538153f9acSThomas Gleixner int acpi_processor_set_throttling(struct acpi_processor *pr, int state,
11548153f9acSThomas Gleixner bool force)
11558153f9acSThomas Gleixner {
11568153f9acSThomas Gleixner return __acpi_processor_set_throttling(pr, state, force, false);
11578153f9acSThomas Gleixner }
11588153f9acSThomas Gleixner
acpi_processor_get_throttling_info(struct acpi_processor * pr)11594be44fcdSLen Brown int acpi_processor_get_throttling_info(struct acpi_processor *pr)
11601da177e4SLinus Torvalds {
11611da177e4SLinus Torvalds int result = 0;
11621180509fSZhao Yakui struct acpi_processor_throttling *pthrottling;
11631da177e4SLinus Torvalds
116452af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
11651da177e4SLinus Torvalds "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
11661da177e4SLinus Torvalds pr->throttling.address,
11671da177e4SLinus Torvalds pr->throttling.duty_offset,
116852af99c3SRafael J. Wysocki pr->throttling.duty_width);
11691da177e4SLinus Torvalds
1170c30c620eSLen Brown /*
1171c30c620eSLen Brown * Evaluate _PTC, _TSS and _TPC
1172c30c620eSLen Brown * They must all be present or none of them can be used.
1173c30c620eSLen Brown */
1174c30c620eSLen Brown if (acpi_processor_get_throttling_control(pr) ||
1175c30c620eSLen Brown acpi_processor_get_throttling_states(pr) ||
11762ef53bf7SClayton Casciato acpi_processor_get_platform_limit(pr)) {
1177ff55a9ceSLen Brown pr->throttling.acpi_processor_get_throttling =
1178ff55a9ceSLen Brown &acpi_processor_get_throttling_fadt;
1179ff55a9ceSLen Brown pr->throttling.acpi_processor_set_throttling =
1180ff55a9ceSLen Brown &acpi_processor_set_throttling_fadt;
1181d1154be3SAlexey Starikovskiy if (acpi_processor_get_fadt_info(pr))
1182d1154be3SAlexey Starikovskiy return 0;
118301854e69SLuming Yu } else {
1184ff55a9ceSLen Brown pr->throttling.acpi_processor_get_throttling =
1185ff55a9ceSLen Brown &acpi_processor_get_throttling_ptc;
1186ff55a9ceSLen Brown pr->throttling.acpi_processor_set_throttling =
1187ff55a9ceSLen Brown &acpi_processor_set_throttling_ptc;
118801854e69SLuming Yu }
11891da177e4SLinus Torvalds
11901180509fSZhao Yakui /*
11911180509fSZhao Yakui * If TSD package for one CPU can't be parsed successfully, it means
11921180509fSZhao Yakui * that this CPU will have no coordination with other CPUs.
11931180509fSZhao Yakui */
11941180509fSZhao Yakui if (acpi_processor_get_tsd(pr)) {
11951180509fSZhao Yakui pthrottling = &pr->throttling;
11961180509fSZhao Yakui pthrottling->tsd_valid_flag = 0;
11972fdf66b4SRusty Russell cpumask_set_cpu(pr->id, pthrottling->shared_cpu_map);
11981180509fSZhao Yakui pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
11991180509fSZhao Yakui }
1200c30c620eSLen Brown
12011da177e4SLinus Torvalds /*
12021da177e4SLinus Torvalds * PIIX4 Errata: We don't support throttling on the original PIIX4.
12031da177e4SLinus Torvalds * This shouldn't be an issue as few (if any) mobile systems ever
12041da177e4SLinus Torvalds * used this part.
12051da177e4SLinus Torvalds */
12061da177e4SLinus Torvalds if (errata.piix4.throttle) {
120752af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
120852af99c3SRafael J. Wysocki "Throttling not supported on PIIX4 A- or B-step\n");
1209d550d98dSPatrick Mochel return 0;
12101da177e4SLinus Torvalds }
12111da177e4SLinus Torvalds
121252af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle, "Found %d throttling states\n",
121352af99c3SRafael J. Wysocki pr->throttling.state_count);
12141da177e4SLinus Torvalds
12151da177e4SLinus Torvalds pr->flags.throttling = 1;
12161da177e4SLinus Torvalds
12171da177e4SLinus Torvalds /*
12181da177e4SLinus Torvalds * Disable throttling (if enabled). We'll let subsequent policy (e.g.
12191da177e4SLinus Torvalds * thermal) decide to lower performance if it so chooses, but for now
12201da177e4SLinus Torvalds * we'll crank up the speed.
12211da177e4SLinus Torvalds */
12221da177e4SLinus Torvalds
12231da177e4SLinus Torvalds result = acpi_processor_get_throttling(pr);
12241da177e4SLinus Torvalds if (result)
12251da177e4SLinus Torvalds goto end;
12261da177e4SLinus Torvalds
12271da177e4SLinus Torvalds if (pr->throttling.state) {
122852af99c3SRafael J. Wysocki acpi_handle_debug(pr->handle,
12294be44fcdSLen Brown "Disabling throttling (was T%d)\n",
123052af99c3SRafael J. Wysocki pr->throttling.state);
12312a908002SFrans Pop result = acpi_processor_set_throttling(pr, 0, false);
12321da177e4SLinus Torvalds if (result)
12331da177e4SLinus Torvalds goto end;
12341da177e4SLinus Torvalds }
12351da177e4SLinus Torvalds
12361da177e4SLinus Torvalds end:
12371da177e4SLinus Torvalds if (result)
12381da177e4SLinus Torvalds pr->flags.throttling = 0;
12391da177e4SLinus Torvalds
1240d550d98dSPatrick Mochel return result;
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds
1243