// SPDX-License-Identifier: GPL-2.0-or-later/* * processor_throttling.c - Throttling submodule of the ACPI processor driver * * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> * - Added processor hotplug support */ #define pr_fmt(fmt) "ACPI: " fmt #include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/cpufreq.h>#include <linux/acpi.h>#include <linux/uaccess.h>#include <acpi/processor.h>#include <asm/io.h>#ifdef CONFIG_X86#include <asm/msr.h>#endif /* ignore_tpc: * 0 -> acpi processor driver doesn't ignore _TPC values * 1 -> acpi processor driver ignores _TPC values */static int ignore_tpc;module_param(ignore_tpc, int, 0644);MODULE_PARM_DESC(ignore_tpc, "Disable broken BIOS _TPC throttling support"); struct throttling_tstate { unsigned int cpu; /* cpu nr */ int target_state; /* target T-state */}; struct acpi_processor_throttling_arg { struct acpi_processor *pr; int target_state; bool force;}; #define THROTTLING_PRECHANGE (1)#define THROTTLING_POSTCHANGE (2) static int acpi_processor_get_throttling(struct acpi_processor *pr);static int __acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force, bool direct); static int acpi_processor_update_tsd_coord(void){ int count_target; int retval = 0; unsigned int i, j; cpumask_var_t covered_cpus; struct acpi_processor *pr, *match_pr; struct acpi_tsd_package *pdomain, *match_pdomain; struct acpi_processor_throttling *pthrottling, *match_pthrottling; if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL)) return -ENOMEM; /* * Now that we have _TSD data from all CPUs, lets setup T-state * coordination between all CPUs. */ for_each_possible_cpu(i) { pr = per_cpu(processors, i); if (!pr) continue; /* Basic validity check for domain info */ pthrottling = &(pr->throttling); /* * If tsd package for one cpu is invalid, the coordination * among all CPUs is thought as invalid. * Maybe it is ugly. */ if (!pthrottling->tsd_valid_flag) { retval = -EINVAL; break; } } if (retval) goto err_ret; for_each_possible_cpu(i) { pr = per_cpu(processors, i); if (!pr) continue; if (cpumask_test_cpu(i, covered_cpus)) continue; pthrottling = &pr->throttling; pdomain = &(pthrottling->domain_info); cpumask_set_cpu(i, pthrottling->shared_cpu_map); cpumask_set_cpu(i, covered_cpus); /* * If the number of processor in the TSD domain is 1, it is * unnecessary to parse the coordination for this CPU. */ if (pdomain->num_processors <= 1) continue; /* Validate the Domain info */ count_target = pdomain->num_processors; for_each_possible_cpu(j) { if (i == j) continue; match_pr = per_cpu(processors, j); if (!match_pr) continue; match_pthrottling = &(match_pr->throttling); match_pdomain = &(match_pthrottling->domain_info); if (match_pdomain->domain != pdomain->domain) continue; /* Here i and j are in the same domain. * If two TSD packages have the same domain, they * should have the same num_porcessors and * coordination type. Otherwise it will be regarded * as illegal. */ if (match_pdomain->num_processors != count_target) { retval = -EINVAL; goto err_ret; } if (pdomain->coord_type != match_pdomain->coord_type) { retval = -EINVAL; goto err_ret; } cpumask_set_cpu(j, covered_cpus); cpumask_set_cpu(j, pthrottling->shared_cpu_map); } for_each_possible_cpu(j) { if (i == j) continue; match_pr = per_cpu(processors, j); if (!match_pr) continue; match_pthrottling = &(match_pr->throttling); match_pdomain = &(match_pthrottling->domain_info); if (match_pdomain->domain != pdomain->domain) continue; /* * If some CPUS have the same domain, they * will have the same shared_cpu_map. */ cpumask_copy(match_pthrottling->shared_cpu_map, pthrottling->shared_cpu_map); } } err_ret: free_cpumask_var(covered_cpus); for_each_possible_cpu(i) { pr = per_cpu(processors, i); if (!pr) continue; /* * Assume no coordination on any error parsing domain info. * The coordination type will be forced as SW_ALL. */ if (retval) { pthrottling = &(pr->throttling); cpumask_clear(pthrottling->shared_cpu_map); cpumask_set_cpu(i, pthrottling->shared_cpu_map); pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL; } } return retval;} /* * Update the T-state coordination after the _TSD * data for all cpus is obtained. */void acpi_processor_throttling_init(void){ if (acpi_processor_update_tsd_coord()) pr_debug("Assume no T-state coordination\n");} static int acpi_processor_throttling_notifier(unsigned long event, void *data){ struct throttling_tstate *p_tstate = data; struct acpi_processor *pr; unsigned int cpu; int target_state; struct acpi_processor_limit *p_limit; struct acpi_processor_throttling *p_throttling; cpu = p_tstate->cpu; pr = per_cpu(processors, cpu); if (!pr) { pr_debug("Invalid pr pointer\n"); return 0; } if (!pr->flags.throttling) { acpi_handle_debug(pr->handle, "Throttling control unsupported on CPU %d\n", cpu); return 0; } target_state = p_tstate->target_state; p_throttling = &(pr->throttling); switch (event) { case THROTTLING_PRECHANGE: /* * Prechange event is used to choose one proper t-state, * which meets the limits of thermal, user and _TPC. */ p_limit = &pr->limit; if (p_limit->thermal.tx > target_state) target_state = p_limit->thermal.tx; if (p_limit->user.tx > target_state) target_state = p_limit->user.tx; if (pr->throttling_platform_limit > target_state) target_state = pr->throttling_platform_limit; if (target_state >= p_throttling->state_count) { pr_warn("Exceed the limit of T-state\n"); target_state = p_throttling->state_count - 1; } p_tstate->target_state = target_state; acpi_handle_debug(pr->handle, "PreChange Event: target T-state of CPU %d is T%d\n", cpu, target_state); break; case THROTTLING_POSTCHANGE: /* * Postchange event is only used to update the * T-state flag of acpi_processor_throttling. */ p_throttling->state = target_state; acpi_handle_debug(pr->handle, "PostChange Event: CPU %d is switched to T%d\n", cpu, target_state); break; default: pr_warn("Unsupported Throttling notifier event\n"); break; } return 0;} /* * _TPC - Throttling Present Capabilities */static int acpi_processor_get_platform_limit(struct acpi_processor *pr){ acpi_status status = 0; unsigned long long tpc = 0; if (!pr) return -EINVAL; if (ignore_tpc) goto end; status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) acpi_evaluation_failure_warn(pr->handle, "_TPC", status); return -ENODEV; } end: pr->throttling_platform_limit = (int)tpc; return 0;} int acpi_processor_tstate_has_changed(struct acpi_processor *pr){ int result = 0; int throttling_limit; int current_state; struct acpi_processor_limit *limit; int target_state; if (ignore_tpc) return 0; result = acpi_processor_get_platform_limit(pr); if (result) { /* Throttling Limit is unsupported */ return result; } throttling_limit = pr->throttling_platform_limit; if (throttling_limit >= pr->throttling.state_count) { /* Uncorrect Throttling Limit */ return -EINVAL; } current_state = pr->throttling.state; if (current_state > throttling_limit) { /* * The current state can meet the requirement of * _TPC limit. But it is reasonable that OSPM changes * t-states from high to low for better performance. * Of course the limit condition of thermal * and user should be considered. */ limit = &pr->limit; target_state = throttling_limit; if (limit->thermal.tx > target_state) target_state = limit->thermal.tx; if (limit->user.tx > target_state) target_state = limit->user.tx; } else if (current_state == throttling_limit) { /* * Unnecessary to change the throttling state */ return 0; } else { /* * If the current state is lower than the limit of _TPC, it * will be forced to switch to the throttling state defined * by throttling_platfor_limit. * Because the previous state meets with the limit condition * of thermal and user, it is unnecessary to check it again. */ target_state = throttling_limit; } return acpi_processor_set_throttling(pr, target_state, false);} /* * This function is used to reevaluate whether the T-state is valid * after one CPU is onlined/offlined. * It is noted that it won't reevaluate the following properties for * the T-state. * 1. Control method. * 2. the number of supported T-state * 3. TSD domain */void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, bool is_dead){ int result = 0; if (is_dead) { /* When one CPU is offline, the T-state throttling * will be invalidated. */ pr->flags.throttling = 0; return; } /* the following is to recheck whether the T-state is valid for * the online CPU */ if (!pr->throttling.state_count) { /* If the number of T-state is invalid, it is * invalidated. */ pr->flags.throttling = 0; return; } pr->flags.throttling = 1; /* Disable throttling (if enabled). We'll let subsequent * policy (e.g.thermal) decide to lower performance if it * so chooses, but for now we'll crank up the speed. */ result = acpi_processor_get_throttling(pr); if (result) goto end; if (pr->throttling.state) { result = acpi_processor_set_throttling(pr, 0, false); if (result) goto end; } end: if (result) pr->flags.throttling = 0;}/* * _PTC - Processor Throttling Control (and status) register location */static int acpi_processor_get_throttling_control(struct acpi_processor *pr){ int result = 0; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *ptc = NULL; union acpi_object obj; struct acpi_processor_throttling *throttling; status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) acpi_evaluation_failure_warn(pr->handle, "_PTC", status); return -ENODEV; } ptc = (union acpi_object *)buffer.pointer; if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE) || (ptc->package.count != 2)) { pr_err("Invalid _PTC data\n"); result = -EFAULT; goto end; } /* * control_register */ obj = ptc->package.elements[0]; if ((obj.type != ACPI_TYPE_BUFFER) || (obj.buffer.length < sizeof(struct acpi_ptc_register)) || (obj.buffer.pointer == NULL)) { pr_err("Invalid _PTC data (control_register)\n"); result = -EFAULT; goto end; } memcpy(&pr->throttling.control_register, obj.buffer.pointer, sizeof(struct acpi_ptc_register)); /* * status_register */ obj = ptc->package.elements[1]; if ((obj.type != ACPI_TYPE_BUFFER) || (obj.buffer.length < sizeof(struct acpi_ptc_register)) || (obj.buffer.pointer == NULL)) { pr_err("Invalid _PTC data (status_register)\n"); result = -EFAULT; goto end; } memcpy(&pr->throttling.status_register, obj.buffer.pointer, sizeof(struct acpi_ptc_register)); throttling = &pr->throttling; if ((throttling->control_register.bit_width + throttling->control_register.bit_offset) > 32) { pr_err("Invalid _PTC control register\n"); result = -EFAULT; goto end; } if ((throttling->status_register.bit_width + throttling->status_register.bit_offset) > 32) { pr_err("Invalid _PTC status register\n"); result = -EFAULT; goto end; } end: kfree(buffer.pointer); return result;} /* * _TSS - Throttling Supported States */static int acpi_processor_get_throttling_states(struct acpi_processor *pr){ int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; struct acpi_buffer state = { 0, NULL }; union acpi_object *tss = NULL; int i; status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) acpi_evaluation_failure_warn(pr->handle, "_TSS", status); return -ENODEV;Lines 1–500 of 1233. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * processor_throttling.c - Throttling submodule of the ACPI processor driver * * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> * - Added processor hotplug support */ #define pr_fmt(fmt) "ACPI: " fmt #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/cpufreq.h> #include <linux/acpi.h> #include <linux/uaccess.h> #include <acpi/processor.h> #include <asm/io.h> #ifdef CONFIG_X86 #include <asm/msr.h> #endif /* ignore_tpc: * 0 -> acpi processor driver doesn't ignore _TPC values * 1 -> acpi processor driver ignores _TPC values */ static int ignore_tpc; module_param(ignore_tpc, int, 0644); MODULE_PARM_DESC(ignore_tpc, "Disable broken BIOS _TPC throttling support"); struct throttling_tstate { unsigned int cpu; /* cpu nr */ int target_state; /* target T-state */ }; struct acpi_processor_throttling_arg { struct acpi_processor *pr; int target_state; bool force; }; #define THROTTLING_PRECHANGE (1) #define THROTTLING_POSTCHANGE (2) static int acpi_processor_get_throttling(struct acpi_processor *pr); static int __acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force, bool direct); static int acpi_processor_update_tsd_coord(void) { int count_target; int retval = 0; unsigned int i, j; cpumask_var_t covered_cpus; struct acpi_processor *pr, *match_pr; struct acpi_tsd_package *pdomain, *match_pdomain; struct acpi_processor_throttling *pthrottling, *match_pthrottling; if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL)) return -ENOMEM; /* * Now that we have _TSD data from all CPUs, lets setup T-state * coordination between all CPUs. */ for_each_possible_cpu(i) { pr = per_cpu(processors, i); if (!pr) continue; /* Basic validity check for domain info */ pthrottling = &(pr->throttling); /* * If tsd package for one cpu is invalid, the coordination * among all CPUs is thought as invalid. * Maybe it is ugly. */ if (!pthrottling->tsd_valid_flag) { retval = -EINVAL; break; } } if (retval) goto err_ret; for_each_possible_cpu(i) { pr = per_cpu(processors, i); if (!pr) continue; if (cpumask_test_cpu(i, covered_cpus)) continue; pthrottling = &pr->throttling; pdomain = &(pthrottling->domain_info); cpumask_set_cpu(i, pthrottling->shared_cpu_map); cpumask_set_cpu(i, covered_cpus); /* * If the number of processor in the TSD domain is 1, it is * unnecessary to parse the coordination for this CPU. */ if (pdomain->num_processors <= 1) continue; /* Validate the Domain info */ count_target = pdomain->num_processors; for_each_possible_cpu(j) { if (i == j) continue; match_pr = per_cpu(processors, j); if (!match_pr) continue; match_pthrottling = &(match_pr->throttling); match_pdomain = &(match_pthrottling->domain_info); if (match_pdomain->domain != pdomain->domain) continue; /* Here i and j are in the same domain. * If two TSD packages have the same domain, they * should have the same num_porcessors and * coordination type. Otherwise it will be regarded * as illegal. */ if (match_pdomain->num_processors != count_target) { retval = -EINVAL; goto err_ret; } if (pdomain->coord_type != match_pdomain->coord_type) { retval = -EINVAL; goto err_ret; } cpumask_set_cpu(j, covered_cpus); cpumask_set_cpu(j, pthrottling->shared_cpu_map); } for_each_possible_cpu(j) { if (i == j) continue; match_pr = per_cpu(processors, j); if (!match_pr) continue; match_pthrottling = &(match_pr->throttling); match_pdomain = &(match_pthrottling->domain_info); if (match_pdomain->domain != pdomain->domain) continue; /* * If some CPUS have the same domain, they * will have the same shared_cpu_map. */ cpumask_copy(match_pthrottling->shared_cpu_map, pthrottling->shared_cpu_map); } } err_ret: free_cpumask_var(covered_cpus); for_each_possible_cpu(i) { pr = per_cpu(processors, i); if (!pr) continue; /* * Assume no coordination on any error parsing domain info. * The coordination type will be forced as SW_ALL. */ if (retval) { pthrottling = &(pr->throttling); cpumask_clear(pthrottling->shared_cpu_map); cpumask_set_cpu(i, pthrottling->shared_cpu_map); pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL; } } return retval; } /* * Update the T-state coordination after the _TSD * data for all cpus is obtained. */ void acpi_processor_throttling_init(void) { if (acpi_processor_update_tsd_coord()) pr_debug("Assume no T-state coordination\n"); } static int acpi_processor_throttling_notifier(unsigned long event, void *data) { struct throttling_tstate *p_tstate = data; struct acpi_processor *pr; unsigned int cpu; int target_state; struct acpi_processor_limit *p_limit; struct acpi_processor_throttling *p_throttling; cpu = p_tstate->cpu; pr = per_cpu(processors, cpu); if (!pr) { pr_debug("Invalid pr pointer\n"); return 0; } if (!pr->flags.throttling) { acpi_handle_debug(pr->handle, "Throttling control unsupported on CPU %d\n", cpu); return 0; } target_state = p_tstate->target_state; p_throttling = &(pr->throttling); switch (event) { case THROTTLING_PRECHANGE: /* * Prechange event is used to choose one proper t-state, * which meets the limits of thermal, user and _TPC. */ p_limit = &pr->limit; if (p_limit->thermal.tx > target_state) target_state = p_limit->thermal.tx; if (p_limit->user.tx > target_state) target_state = p_limit->user.tx; if (pr->throttling_platform_limit > target_state) target_state = pr->throttling_platform_limit; if (target_state >= p_throttling->state_count) { pr_warn("Exceed the limit of T-state\n"); target_state = p_throttling->state_count - 1; } p_tstate->target_state = target_state; acpi_handle_debug(pr->handle, "PreChange Event: target T-state of CPU %d is T%d\n", cpu, target_state); break; case THROTTLING_POSTCHANGE: /* * Postchange event is only used to update the * T-state flag of acpi_processor_throttling. */ p_throttling->state = target_state; acpi_handle_debug(pr->handle, "PostChange Event: CPU %d is switched to T%d\n", cpu, target_state); break; default: pr_warn("Unsupported Throttling notifier event\n"); break; } return 0; } /* * _TPC - Throttling Present Capabilities */ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) { acpi_status status = 0; unsigned long long tpc = 0; if (!pr) return -EINVAL; if (ignore_tpc) goto end; status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) acpi_evaluation_failure_warn(pr->handle, "_TPC", status); return -ENODEV; } end: pr->throttling_platform_limit = (int)tpc; return 0; } int acpi_processor_tstate_has_changed(struct acpi_processor *pr) { int result = 0; int throttling_limit; int current_state; struct acpi_processor_limit *limit; int target_state; if (ignore_tpc) return 0; result = acpi_processor_get_platform_limit(pr); if (result) { /* Throttling Limit is unsupported */ return result; } throttling_limit = pr->throttling_platform_limit; if (throttling_limit >= pr->throttling.state_count) { /* Uncorrect Throttling Limit */ return -EINVAL; } current_state = pr->throttling.state; if (current_state > throttling_limit) { /* * The current state can meet the requirement of * _TPC limit. But it is reasonable that OSPM changes * t-states from high to low for better performance. * Of course the limit condition of thermal * and user should be considered. */ limit = &pr->limit; target_state = throttling_limit; if (limit->thermal.tx > target_state) target_state = limit->thermal.tx; if (limit->user.tx > target_state) target_state = limit->user.tx; } else if (current_state == throttling_limit) { /* * Unnecessary to change the throttling state */ return 0; } else { /* * If the current state is lower than the limit of _TPC, it * will be forced to switch to the throttling state defined * by throttling_platfor_limit. * Because the previous state meets with the limit condition * of thermal and user, it is unnecessary to check it again. */ target_state = throttling_limit; } return acpi_processor_set_throttling(pr, target_state, false); } /* * This function is used to reevaluate whether the T-state is valid * after one CPU is onlined/offlined. * It is noted that it won't reevaluate the following properties for * the T-state. * 1. Control method. * 2. the number of supported T-state * 3. TSD domain */ void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, bool is_dead) { int result = 0; if (is_dead) { /* When one CPU is offline, the T-state throttling * will be invalidated. */ pr->flags.throttling = 0; return; } /* the following is to recheck whether the T-state is valid for * the online CPU */ if (!pr->throttling.state_count) { /* If the number of T-state is invalid, it is * invalidated. */ pr->flags.throttling = 0; return; } pr->flags.throttling = 1; /* Disable throttling (if enabled). We'll let subsequent * policy (e.g.thermal) decide to lower performance if it * so chooses, but for now we'll crank up the speed. */ result = acpi_processor_get_throttling(pr); if (result) goto end; if (pr->throttling.state) { result = acpi_processor_set_throttling(pr, 0, false); if (result) goto end; } end: if (result) pr->flags.throttling = 0; } /* * _PTC - Processor Throttling Control (and status) register location */ static int acpi_processor_get_throttling_control(struct acpi_processor *pr) { int result = 0; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *ptc = NULL; union acpi_object obj; struct acpi_processor_throttling *throttling; status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) acpi_evaluation_failure_warn(pr->handle, "_PTC", status); return -ENODEV; } ptc = (union acpi_object *)buffer.pointer; if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE) || (ptc->package.count != 2)) { pr_err("Invalid _PTC data\n"); result = -EFAULT; goto end; } /* * control_register */ obj = ptc->package.elements[0]; if ((obj.type != ACPI_TYPE_BUFFER) || (obj.buffer.length < sizeof(struct acpi_ptc_register)) || (obj.buffer.pointer == NULL)) { pr_err("Invalid _PTC data (control_register)\n"); result = -EFAULT; goto end; } memcpy(&pr->throttling.control_register, obj.buffer.pointer, sizeof(struct acpi_ptc_register)); /* * status_register */ obj = ptc->package.elements[1]; if ((obj.type != ACPI_TYPE_BUFFER) || (obj.buffer.length < sizeof(struct acpi_ptc_register)) || (obj.buffer.pointer == NULL)) { pr_err("Invalid _PTC data (status_register)\n"); result = -EFAULT; goto end; } memcpy(&pr->throttling.status_register, obj.buffer.pointer, sizeof(struct acpi_ptc_register)); throttling = &pr->throttling; if ((throttling->control_register.bit_width + throttling->control_register.bit_offset) > 32) { pr_err("Invalid _PTC control register\n"); result = -EFAULT; goto end; } if ((throttling->status_register.bit_width + throttling->status_register.bit_offset) > 32) { pr_err("Invalid _PTC status register\n"); result = -EFAULT; goto end; } end: kfree(buffer.pointer); return result; } /* * _TSS - Throttling Supported States */ static int acpi_processor_get_throttling_states(struct acpi_processor *pr) { int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; struct acpi_buffer state = { 0, NULL }; union acpi_object *tss = NULL; int i; status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) acpi_evaluation_failure_warn(pr->handle, "_TSS", status); return -ENODEV;