staticint acpi_processor_update_tsd_coord(void)
{ int count_target; int retval = 0; unsignedint 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;
/* 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 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");
}
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;
}
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;
}
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;
} elseif (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
*/ staticint 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);
status = acpi_extract_package(&(tsd->package.elements[0]),
&format, &state); if (ACPI_FAILURE(status)) {
pr_err("Invalid _TSD data\n");
result = -EFAULT; goto end;
}
if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
pr_err("Unknown _TSD:num_entries\n");
result = -EFAULT; goto end;
}
if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
pr_err("Unknown _TSD:revision\n");
result = -EFAULT; goto end;
}
pthrottling = &pr->throttling;
pthrottling->tsd_valid_flag = 1;
pthrottling->shared_type = pdomain->coord_type;
cpumask_set_cpu(pr->id, pthrottling->shared_cpu_map); /* * If the coordination type is not defined in ACPI spec, * the tsd_valid_flag will be clear and coordination type * will be forecd as DOMAIN_COORD_TYPE_SW_ALL.
*/ if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
pthrottling->tsd_valid_flag = 0;
pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
}
end:
kfree(buffer.pointer); return result;
}
/* -------------------------------------------------------------------------- Throttling Control
-------------------------------------------------------------------------- */ staticint acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
{ int state = 0;
u32 value = 0;
u32 duty_mask = 0;
u32 duty_value = 0;
if (!pr) return -EINVAL;
if (!pr->flags.throttling) return -ENODEV;
/* * We don't care about error returns - we just try to mark * these reserved so that nobody else is confused into thinking * that this region might be unused.. * * (In particular, allocating the IO range for Cardbus)
*/
request_region(pr->throttling.address, 6, "ACPI CPU throttle");
pr->throttling.state = 0;
duty_mask = pr->throttling.state_count - 1;
duty_mask <<= pr->throttling.duty_offset;
local_irq_disable();
value = inl(pr->throttling.address);
/* * Compute the current throttling state when throttling is enabled * (bit 4 is on).
*/ if (value & 0x10) {
duty_value = value & duty_mask;
duty_value >>= pr->throttling.duty_offset;
if (duty_value)
state = pr->throttling.state_count - duty_value;
}
pr->throttling.state = state;
local_irq_enable();
acpi_handle_debug(pr->handle, "Throttling state is T%d (%d%% throttling applied)\n",
state, pr->throttling.states[state].performance);
return 0;
}
#ifdef CONFIG_X86 staticint acpi_throttling_rdmsr(u64 *value)
{
u64 msr_high, msr_low;
u64 msr = 0; int ret = -1;
staticint acpi_processor_get_throttling(struct acpi_processor *pr)
{ if (!pr) return -EINVAL;
if (!pr->flags.throttling) return -ENODEV;
/* * This is either called from the CPU hotplug callback of * processor_driver or via the ACPI probe function. In the latter * case the CPU is not guaranteed to be online. Both call sites are * protected against CPU hotplug.
*/ if (!cpu_online(pr->id)) return -ENODEV;
/* * Compute state values. Note that throttling displays a linear power * performance relationship (at 50% performance the CPU will consume * 50% power). Values are in 1/10th of a percent to preserve accuracy.
*/
step = (1000 / pr->throttling.state_count);
for (i = 0; i < pr->throttling.state_count; i++) {
pr->throttling.states[i].performance = 1000 - step * i;
pr->throttling.states[i].power = 1000 - step * i;
} return 0;
}
/* * Disable throttling by writing a 0 to bit 4. Note that we must * turn it off before you can change the duty_value.
*/
value = inl(pr->throttling.address); if (value & 0x10) {
value &= 0xFFFFFFEF;
outl(value, pr->throttling.address);
}
/* * Write the new duty_value and then enable throttling. Note * that a state value of 0 leaves throttling disabled.
*/ if (state) {
value &= duty_mask;
value |= duty_value;
outl(value, pr->throttling.address);
value |= 0x00000010;
outl(value, pr->throttling.address);
}
pr->throttling.state = state;
local_irq_enable();
acpi_handle_debug(pr->handle, "Throttling state set to T%d (%d%%)\n", state,
(pr->throttling.states[state].performance ? pr->
throttling.states[state].performance / 10 : 0));
return 0;
}
staticint acpi_processor_set_throttling_ptc(struct acpi_processor *pr, int state, bool force)
{ int ret;
u64 value;
/* * The throttling notifier will be called for every * affected cpu in order to get one proper T-state. * The notifier event is THROTTLING_PRECHANGE.
*/
for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
&t_state);
} /* * The function of acpi_processor_set_throttling will be called * to switch T-state. If the coordination type is SW_ALL or HW_ALL, * it is necessary to call it for every affected cpu. Otherwise * it can be called only for the cpu pointed by pr.
*/ if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
arg.pr = pr;
arg.target_state = state;
arg.force = force;
ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg,
direct);
} else { /* * When the T-state coordination is SW_ALL or HW_ALL, * it is necessary to set T-state for every affected * cpus.
*/
for_each_cpu_and(i, cpu_online_mask,
p_throttling->shared_cpu_map) {
match_pr = per_cpu(processors, i); /* * If the pointer is invalid, we will report the * error message and continue.
*/ if (!match_pr) {
acpi_handle_debug(pr->handle, "Invalid Pointer for CPU %d\n", i); continue;
} /* * If the throttling control is unsupported on CPU i, * we will report the error message and continue.
*/ if (!match_pr->flags.throttling) {
acpi_handle_debug(pr->handle, "Throttling Control unsupported on CPU %d\n", i); continue;
}
arg.pr = match_pr;
arg.target_state = state;
arg.force = force;
ret = call_on_cpu(pr->id, acpi_processor_throttling_fn,
&arg, direct);
}
} /* * After the set_throttling is called, the * throttling notifier is called for every * affected cpu to update the T-states. * The notifier event is THROTTLING_POSTCHANGE
*/
for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
&t_state);
}
return ret;
}
int acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force)
{ return __acpi_processor_set_throttling(pr, state, force, false);
}
int acpi_processor_get_throttling_info(struct acpi_processor *pr)
{ int result = 0; struct acpi_processor_throttling *pthrottling;
/* * Evaluate _PTC, _TSS and _TPC * They must all be present or none of them can be used.
*/ if (acpi_processor_get_throttling_control(pr) ||
acpi_processor_get_throttling_states(pr) ||
acpi_processor_get_platform_limit(pr)) {
pr->throttling.acpi_processor_get_throttling =
&acpi_processor_get_throttling_fadt;
pr->throttling.acpi_processor_set_throttling =
&acpi_processor_set_throttling_fadt; if (acpi_processor_get_fadt_info(pr)) return 0;
} else {
pr->throttling.acpi_processor_get_throttling =
&acpi_processor_get_throttling_ptc;
pr->throttling.acpi_processor_set_throttling =
&acpi_processor_set_throttling_ptc;
}
/* * If TSD package for one CPU can't be parsed successfully, it means * that this CPU will have no coordination with other CPUs.
*/ if (acpi_processor_get_tsd(pr)) {
pthrottling = &pr->throttling;
pthrottling->tsd_valid_flag = 0;
cpumask_set_cpu(pr->id, pthrottling->shared_cpu_map);
pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
}
/* * PIIX4 Errata: We don't support throttling on the original PIIX4. * This shouldn't be an issue as few (if any) mobile systems ever * used this part.
*/ if (errata.piix4.throttle) {
acpi_handle_debug(pr->handle, "Throttling not supported on PIIX4 A- or B-step\n"); return 0;
}
/* * 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) {
acpi_handle_debug(pr->handle, "Disabling throttling (was T%d)\n",
pr->throttling.state);
result = acpi_processor_set_throttling(pr, 0, false); if (result) goto end;
}
end: if (result)
pr->flags.throttling = 0;
return result;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.