mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
Merge branch 'intel-idle-lpi'
Merge an ACPI processor driver update related to ACPI _LPI support and the introduction of ACPI _LPI suppor to intel_idle based on that update for 7.3-rc1. * intel-idle-lpi: intel_idle: Update documentation after adding ACPI _LPI support intel_idle: Add ACPI _LPI support intel_idle: Prepare for adding ACPI _LPI support ACPI: processor: idle: Add switch for strict _LPI processing ACPI: processor: idle: Relocate acpi_processor_extract_lpi_info() ACPI: processor: idle: Introduce acpi_processor_extract_lpi_info() ACPI: processor: idle: Introduce too_many_states() for _LPI ACPI: processor: idle: Rework flatten_lpi_states() ACPI: processor: idle: Rearrange loop in acpi_processor_get_lpi_info() ACPI: processor: idle: Drop redundant _LPI presence checks ACPI: processor: idle: Rework first-level _LPI states processing ACPI: processor: idle: Rearrange acpi_processor_get_lpi_info() ACPI: processor: idle: Introduce lpi_state_debug() ACPI: processor: idle: Split acpi_processor_evaluate_lpi() ACPI: processor: idle: Rearrange acpi_processor_evaluate_lpi() ACPI: processor: idle: Unify debug in acpi_processor_evaluate_lpi() ACPI: processor: idle: Ignore _LPI states with SYSTEMIO entry method ACPI: processor: idle: Expand _LPI package sanity checks
This commit is contained in:
@@ -87,17 +87,22 @@ tables with any processor model recognized by it; see
|
||||
`below <intel-idle-parameters_>`_.]
|
||||
|
||||
If the ACPI tables are going to be used for building the list of available idle
|
||||
states, ``intel_idle`` first looks for a ``_CST`` object under one of the ACPI
|
||||
objects corresponding to the CPUs in the system (refer to the ACPI specification
|
||||
[2]_ for the description of ``_CST`` and its output package). Because the
|
||||
``CPUIdle`` subsystem expects that the list of idle states supplied by the
|
||||
driver will be suitable for all of the CPUs handled by it and ``intel_idle`` is
|
||||
registered as the ``CPUIdle`` driver for all of the CPUs in the system, the
|
||||
driver looks for the first ``_CST`` object returning at least one valid idle
|
||||
state description and such that all of the idle states included in its return
|
||||
package are of the FFH (Functional Fixed Hardware) type, which means that the
|
||||
``MWAIT`` instruction is expected to be used to tell the processor that it can
|
||||
enter one of them. The return package of that ``_CST`` is then assumed to be
|
||||
states, ``intel_idle`` will be looking for ``_LPI`` or ``_CST`` objects in them
|
||||
(refer to the ACPI specification [2]_ for the definitions of the ``_LPI`` and
|
||||
``_CST`` objects). If ``_LPI`` is present under at least one of the ACPI
|
||||
objects representing the CPUs in the system and ``_LPI`` processing produces a
|
||||
non-empty list of valid idle states, it will be used. Otherwise, ``_CST`` will
|
||||
be used so long as it is present under at least one of the ACPI objects
|
||||
representing the CPUs in the system and it returns a non-empty list of valid
|
||||
idle states. In either case, since the ``CPUIdle`` subsystem expects that the
|
||||
list of idle states supplied by the driver will be suitable for all of the CPUs
|
||||
handled by it and ``intel_idle`` is registered as the ``CPUIdle`` driver for all
|
||||
of the CPUs in the system, ``intel_idle`` looks for the first CPU where the
|
||||
ACPI-supplied list of idle states (coming from either ``_LPI`` or ``_CST``)
|
||||
is not empty. Moreover, all of the states in that list need to be of the FFH
|
||||
(Functional Fixed Hardware) type, which means that the ``MWAIT`` instruction is
|
||||
expected to be used to tell the processor that the given idle state may be
|
||||
entered. If that expectation is met, the list of idle states is assumed to be
|
||||
applicable to all of the other CPUs in the system and the idle state
|
||||
descriptions extracted from it are stored in a preliminary list of idle states
|
||||
coming from the ACPI tables. [This step is skipped if ``intel_idle`` is
|
||||
@@ -129,18 +134,21 @@ If the given processor model is not recognized by ``intel_idle``, but it
|
||||
supports ``MWAIT``, the preliminary list of idle states coming from the ACPI
|
||||
tables is used for building the final list that will be supplied to the
|
||||
``CPUIdle`` core during driver registration. For each idle state in that list,
|
||||
the description, ``MWAIT`` hint and exit latency are copied to the corresponding
|
||||
entry in the final list of idle states. The name of the idle state represented
|
||||
by it (to be returned by the ``name`` idle state attribute in ``sysfs``) is
|
||||
"CX_ACPI", where X is the index of that idle state in the final list (note that
|
||||
the minimum value of X is 1, because 0 is reserved for the "polling" state), and
|
||||
its target residency is based on the exit latency value. Specifically, for
|
||||
C1-type idle states the exit latency value is also used as the target residency
|
||||
(for compatibility with the majority of the "internal" tables of idle states for
|
||||
various processor models recognized by ``intel_idle``) and for the other idle
|
||||
state types (C2 and C3) the target residency value is 3 times the exit latency
|
||||
(again, that is because it reflects the target residency to exit latency ratio
|
||||
in the majority of cases for the processor models recognized by ``intel_idle``).
|
||||
the description, ``MWAIT`` hint and exit (wake) latency are copied to the
|
||||
corresponding entry in the final list of idle states. If the preliminary list
|
||||
of idle states has been obtained through ``_LPI`` processing, the minimum
|
||||
residency parameter of the given idle state is taken as its target residency.
|
||||
Otherwise, for C1-type idle states, the exit latency value is also used as the
|
||||
target residency (for compatibility with the majority of the "internal" tables
|
||||
of idle states for various processor models recognized by ``intel_idle``), and
|
||||
for the other idle state types (C2 and C3) the target residency value is 3 times
|
||||
the exit latency (again, that is because it reflects the target residency to
|
||||
exit latency ratio in the majority of cases for the processor models recognized
|
||||
by ``intel_idle``). The name of the idle state (to be returned by the ``name``
|
||||
idle state attribute in ``sysfs``) is either "Cx_LPI" (if it comes from ``_LPI``
|
||||
processing) or "Cx_ACPI", where x is the index of that idle state in the final
|
||||
list (note that the minimum value of x is 1, because 0 is reserved for the
|
||||
"polling" state), and its target residency is based on the exit latency value.
|
||||
All of the idle states in the final list are enabled by default in this case.
|
||||
|
||||
|
||||
|
||||
@@ -994,3 +994,357 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acpi_processor_evaluate_cst, "ACPI_PROCESSOR_IDLE");
|
||||
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCESSOR_IDLE
|
||||
struct acpi_lpi_states_array {
|
||||
unsigned int size;
|
||||
unsigned int composite_states_size;
|
||||
struct acpi_lpi_state *entries;
|
||||
struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER];
|
||||
};
|
||||
|
||||
static int obj_get_integer(union acpi_object *obj, u32 *value)
|
||||
{
|
||||
if (obj->type != ACPI_TYPE_INTEGER)
|
||||
return -EINVAL;
|
||||
|
||||
*value = obj->integer.value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define lpi_state_debug(handle, message, state_idx) \
|
||||
acpi_handle_debug(handle, message " for _LPI state %u\n", state_idx)
|
||||
|
||||
static void process_lpi_state_package(union acpi_object *lpi_pkg,
|
||||
struct acpi_lpi_state *lpi_state,
|
||||
acpi_handle handle,
|
||||
unsigned int state_idx, bool strict)
|
||||
{
|
||||
union acpi_object *lpi_pkg_elem, *obj;
|
||||
|
||||
if (lpi_pkg->type != ACPI_TYPE_PACKAGE || lpi_pkg->package.count < 7)
|
||||
return;
|
||||
|
||||
lpi_pkg_elem = lpi_pkg->package.elements;
|
||||
|
||||
/* Get the entry method first and skip the state if that fails. */
|
||||
obj = &lpi_pkg_elem[6];
|
||||
if (obj->type == ACPI_TYPE_BUFFER) {
|
||||
struct acpi_power_register *reg;
|
||||
|
||||
if (obj->buffer.length < sizeof(*reg)) {
|
||||
lpi_state_debug(handle, "Invalid register data", state_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
reg = (struct acpi_power_register *)obj->buffer.pointer;
|
||||
if (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
|
||||
lpi_state_debug(handle, "Unsupported entry method", state_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
lpi_state->entry_method = ACPI_CSTATE_FFH;
|
||||
lpi_state->address = reg->address;
|
||||
} else if (obj->type == ACPI_TYPE_INTEGER) {
|
||||
lpi_state->entry_method = ACPI_CSTATE_INTEGER;
|
||||
lpi_state->address = obj->integer.value;
|
||||
} else {
|
||||
lpi_state_debug(handle, "Invalid entry method", state_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj_get_integer(&lpi_pkg_elem[0], &lpi_state->min_residency)) {
|
||||
if (strict) {
|
||||
lpi_state_debug(handle, "No min. residency", state_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
lpi_state_debug(handle, "Assuming 10 us min. residency", state_idx);
|
||||
lpi_state->min_residency = 10;
|
||||
}
|
||||
|
||||
if (obj_get_integer(&lpi_pkg_elem[1], &lpi_state->wake_latency)) {
|
||||
if (strict) {
|
||||
lpi_state_debug(handle, "No wake latency", state_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
lpi_state_debug(handle, "Assuming 10 us wake latency", state_idx);
|
||||
lpi_state->wake_latency = 10;
|
||||
}
|
||||
|
||||
if (obj_get_integer(&lpi_pkg_elem[2], &lpi_state->flags))
|
||||
lpi_state->flags = 0;
|
||||
|
||||
if (obj_get_integer(&lpi_pkg_elem[3], &lpi_state->arch_flags))
|
||||
lpi_state->arch_flags = 0;
|
||||
|
||||
if (obj_get_integer(&lpi_pkg_elem[4], &lpi_state->res_cnt_freq))
|
||||
lpi_state->res_cnt_freq = 1;
|
||||
|
||||
if (obj_get_integer(&lpi_pkg_elem[5], &lpi_state->enable_parent_state))
|
||||
lpi_state->enable_parent_state = 0;
|
||||
|
||||
/* Skip elements [7-8] i.e. Residency/Usage counters. */
|
||||
|
||||
/*
|
||||
* Avoid out-of-bounds access if the size of the package is less than
|
||||
* expected.
|
||||
*/
|
||||
if (lpi_pkg->package.count < 10)
|
||||
return;
|
||||
|
||||
obj = &lpi_pkg_elem[9];
|
||||
if (obj->type == ACPI_TYPE_STRING)
|
||||
strscpy(lpi_state->desc, obj->string.pointer, ACPI_CX_DESC_LEN);
|
||||
}
|
||||
|
||||
static int acpi_processor_evaluate_lpi(acpi_handle handle,
|
||||
struct acpi_lpi_states_array *info,
|
||||
bool strict)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *lpi_data, *lpi_pkg;
|
||||
unsigned int lpi_pkg_count, state_idx;
|
||||
struct acpi_lpi_state *lpi_state;
|
||||
acpi_status status;
|
||||
int ret = 0;
|
||||
|
||||
status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_debug(handle, "No _LPI, giving up\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
lpi_data = buffer.pointer;
|
||||
|
||||
/* There must be at least 4 elements = 3 elements + 1 package */
|
||||
if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
|
||||
lpi_data->package.count < 4) {
|
||||
acpi_handle_debug(handle, "Not enough elements in _LPI\n");
|
||||
ret = -ENODATA;
|
||||
goto end;
|
||||
}
|
||||
|
||||
lpi_pkg_count = lpi_data->package.elements[2].integer.value;
|
||||
|
||||
/* Validate number of power states. */
|
||||
if (!lpi_pkg_count || lpi_pkg_count != lpi_data->package.count - 3) {
|
||||
acpi_handle_debug(handle, "Invalid _LPI state count\n");
|
||||
ret = -ENODATA;
|
||||
goto end;
|
||||
}
|
||||
|
||||
lpi_state = kzalloc_objs(*lpi_state, lpi_pkg_count);
|
||||
if (!lpi_state) {
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
info->size = lpi_pkg_count;
|
||||
info->entries = lpi_state;
|
||||
|
||||
/* _LPI State packages start at index 3. */
|
||||
lpi_pkg = &lpi_data->package.elements[3];
|
||||
|
||||
for (state_idx = 1; state_idx <= lpi_pkg_count; state_idx++) {
|
||||
lpi_state->index = state_idx;
|
||||
process_lpi_state_package(lpi_pkg++, lpi_state++, handle,
|
||||
state_idx, strict);
|
||||
}
|
||||
|
||||
acpi_handle_debug(handle, "Found %u power states\n", lpi_pkg_count);
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* combine_lpi_states - combine local and parent LPI states to form a composite LPI state
|
||||
*
|
||||
* @local: local LPI state
|
||||
* @parent: parent LPI state
|
||||
* @result: composite LPI state
|
||||
*/
|
||||
static bool combine_lpi_states(struct acpi_lpi_state *local,
|
||||
struct acpi_lpi_state *parent,
|
||||
struct acpi_lpi_state *result)
|
||||
{
|
||||
if (parent->entry_method == ACPI_CSTATE_INTEGER) {
|
||||
if (!parent->address) /* 0 means autopromotable */
|
||||
return false;
|
||||
result->address = local->address + parent->address;
|
||||
} else {
|
||||
result->address = parent->address;
|
||||
}
|
||||
|
||||
result->min_residency = max(local->min_residency, parent->min_residency);
|
||||
result->wake_latency = local->wake_latency + parent->wake_latency;
|
||||
result->enable_parent_state = parent->enable_parent_state;
|
||||
result->entry_method = local->entry_method;
|
||||
|
||||
result->flags = parent->flags;
|
||||
result->arch_flags = parent->arch_flags;
|
||||
result->index = parent->index;
|
||||
|
||||
scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0)
|
||||
|
||||
static void stash_composite_state(struct acpi_lpi_states_array *curr_level,
|
||||
struct acpi_lpi_state *t)
|
||||
{
|
||||
curr_level->composite_states[curr_level->composite_states_size++] = t;
|
||||
}
|
||||
|
||||
static bool too_many_states(acpi_handle handle, unsigned int state_count)
|
||||
{
|
||||
if (state_count < ACPI_PROCESSOR_MAX_POWER)
|
||||
return false;
|
||||
|
||||
acpi_handle_info(handle, "No space for more _LPI states than %d\n",
|
||||
ACPI_PROCESSOR_MAX_POWER);
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int flatten_lpi_states(acpi_handle handle,
|
||||
struct acpi_lpi_state *lpi_states,
|
||||
unsigned int state_count,
|
||||
struct acpi_lpi_states_array *curr,
|
||||
struct acpi_lpi_states_array *prev)
|
||||
{
|
||||
struct acpi_lpi_state *parent_lpi = curr->entries;
|
||||
unsigned int j;
|
||||
|
||||
/*
|
||||
* Combine each of the "raw" _LPI states from the current (processor
|
||||
* container) level with all of the composite _LPI states from the
|
||||
* previous (processor or processor container) level.
|
||||
*/
|
||||
for (j = 0; j < curr->size; j++, parent_lpi++) {
|
||||
struct acpi_lpi_state *flpi;
|
||||
int i;
|
||||
|
||||
if (!(parent_lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED))
|
||||
continue;
|
||||
|
||||
if (too_many_states(handle, state_count))
|
||||
break;
|
||||
|
||||
flpi = &lpi_states[state_count];
|
||||
|
||||
for (i = 0; i < prev->composite_states_size; i++) {
|
||||
struct acpi_lpi_state *local_lpi = prev->composite_states[i];
|
||||
|
||||
if (parent_lpi->index > local_lpi->enable_parent_state)
|
||||
continue;
|
||||
|
||||
if (!combine_lpi_states(local_lpi, parent_lpi, flpi))
|
||||
continue;
|
||||
|
||||
stash_composite_state(curr, flpi);
|
||||
state_count++;
|
||||
flpi++;
|
||||
|
||||
if (state_count >= ACPI_PROCESSOR_MAX_POWER)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state_count;
|
||||
}
|
||||
|
||||
int acpi_processor_extract_lpi_info(acpi_handle pr_handle,
|
||||
struct acpi_processor_power *pr_power,
|
||||
bool strict)
|
||||
{
|
||||
struct acpi_lpi_states_array info[2], *prev, *curr;
|
||||
acpi_handle handle = pr_handle;
|
||||
unsigned int state_count = 0;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!osc_pc_lpi_support_confirmed)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
curr = &info[0];
|
||||
curr->composite_states_size = 0;
|
||||
|
||||
ret = acpi_processor_evaluate_lpi(handle, curr, strict);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Copy all of the usable first-level states to power.lpi_states[]. */
|
||||
for (i = 0; i < curr->size; i++) {
|
||||
struct acpi_lpi_state *lpi = &curr->entries[i];
|
||||
struct acpi_lpi_state *flpi;
|
||||
|
||||
/*
|
||||
* Skip states that are not enabled or have an inadequate entry
|
||||
* method for this level.
|
||||
*/
|
||||
if (!(lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED) ||
|
||||
lpi->entry_method == ACPI_CSTATE_INTEGER)
|
||||
continue;
|
||||
|
||||
if (too_many_states(pr_handle, state_count))
|
||||
break;
|
||||
|
||||
flpi = &pr_power->lpi_states[state_count++];
|
||||
memcpy(flpi, lpi, sizeof(*lpi));
|
||||
stash_composite_state(curr, flpi);
|
||||
}
|
||||
|
||||
kfree(curr->entries);
|
||||
|
||||
/*
|
||||
* If there are no _LPI states at the first level, there are no _LPI
|
||||
* states at all.
|
||||
*/
|
||||
if (!state_count)
|
||||
return -ENODATA;
|
||||
|
||||
prev = curr;
|
||||
curr = &info[1];
|
||||
|
||||
for (;;) {
|
||||
struct acpi_lpi_states_array *tmp;
|
||||
struct acpi_device *d;
|
||||
|
||||
if (ACPI_FAILURE(acpi_get_parent(handle, &handle)))
|
||||
break;
|
||||
|
||||
d = acpi_fetch_acpi_dev(handle);
|
||||
if (!d)
|
||||
break;
|
||||
|
||||
if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
|
||||
break;
|
||||
|
||||
curr->composite_states_size = 0;
|
||||
|
||||
ret = acpi_processor_evaluate_lpi(handle, curr, strict);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
/* flatten all the LPI states in this level of hierarchy */
|
||||
state_count = flatten_lpi_states(pr_handle, pr_power->lpi_states,
|
||||
state_count, curr, prev);
|
||||
|
||||
kfree(curr->entries);
|
||||
|
||||
tmp = prev, prev = curr, curr = tmp;
|
||||
}
|
||||
|
||||
/* reset the index after flattening */
|
||||
for (i = 0; i < state_count; i++)
|
||||
pr_power->lpi_states[i].index = i;
|
||||
|
||||
pr_power->count = state_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acpi_processor_extract_lpi_info, "ACPI_PROCESSOR_IDLE");
|
||||
#endif /* CONFIG_ACPI_PROCESSOR_IDLE */
|
||||
|
||||
@@ -853,223 +853,6 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr)
|
||||
|
||||
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
|
||||
|
||||
struct acpi_lpi_states_array {
|
||||
unsigned int size;
|
||||
unsigned int composite_states_size;
|
||||
struct acpi_lpi_state *entries;
|
||||
struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER];
|
||||
};
|
||||
|
||||
static int obj_get_integer(union acpi_object *obj, u32 *value)
|
||||
{
|
||||
if (obj->type != ACPI_TYPE_INTEGER)
|
||||
return -EINVAL;
|
||||
|
||||
*value = obj->integer.value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_evaluate_lpi(acpi_handle handle,
|
||||
struct acpi_lpi_states_array *info)
|
||||
{
|
||||
acpi_status status;
|
||||
int ret = 0;
|
||||
int pkg_count, state_idx = 1, loop;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *lpi_data;
|
||||
struct acpi_lpi_state *lpi_state;
|
||||
|
||||
status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_debug(handle, "No _LPI, giving up\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
lpi_data = buffer.pointer;
|
||||
|
||||
/* There must be at least 4 elements = 3 elements + 1 package */
|
||||
if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
|
||||
lpi_data->package.count < 4) {
|
||||
pr_debug("not enough elements in _LPI\n");
|
||||
ret = -ENODATA;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pkg_count = lpi_data->package.elements[2].integer.value;
|
||||
|
||||
/* Validate number of power states. */
|
||||
if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) {
|
||||
pr_debug("count given by _LPI is not valid\n");
|
||||
ret = -ENODATA;
|
||||
goto end;
|
||||
}
|
||||
|
||||
lpi_state = kzalloc_objs(*lpi_state, pkg_count);
|
||||
if (!lpi_state) {
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
info->size = pkg_count;
|
||||
info->entries = lpi_state;
|
||||
|
||||
/* LPI States start at index 3 */
|
||||
for (loop = 3; state_idx <= pkg_count; loop++, state_idx++, lpi_state++) {
|
||||
union acpi_object *element, *pkg_elem, *obj;
|
||||
|
||||
element = &lpi_data->package.elements[loop];
|
||||
if (element->type != ACPI_TYPE_PACKAGE || element->package.count < 7)
|
||||
continue;
|
||||
|
||||
pkg_elem = element->package.elements;
|
||||
|
||||
obj = pkg_elem + 6;
|
||||
if (obj->type == ACPI_TYPE_BUFFER) {
|
||||
struct acpi_power_register *reg;
|
||||
|
||||
reg = (struct acpi_power_register *)obj->buffer.pointer;
|
||||
if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&
|
||||
reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)
|
||||
continue;
|
||||
|
||||
lpi_state->address = reg->address;
|
||||
lpi_state->entry_method =
|
||||
reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE ?
|
||||
ACPI_CSTATE_FFH : ACPI_CSTATE_SYSTEMIO;
|
||||
} else if (obj->type == ACPI_TYPE_INTEGER) {
|
||||
lpi_state->entry_method = ACPI_CSTATE_INTEGER;
|
||||
lpi_state->address = obj->integer.value;
|
||||
} else {
|
||||
pr_debug("Entry method of state-%d is invalid, disable it.\n",
|
||||
state_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* elements[7,8] skipped for now i.e. Residency/Usage counter*/
|
||||
|
||||
obj = pkg_elem + 9;
|
||||
if (obj->type == ACPI_TYPE_STRING)
|
||||
strscpy(lpi_state->desc, obj->string.pointer,
|
||||
ACPI_CX_DESC_LEN);
|
||||
|
||||
lpi_state->index = state_idx;
|
||||
if (obj_get_integer(pkg_elem + 0, &lpi_state->min_residency)) {
|
||||
pr_debug("No min. residency found, assuming 10 us\n");
|
||||
lpi_state->min_residency = 10;
|
||||
}
|
||||
|
||||
if (obj_get_integer(pkg_elem + 1, &lpi_state->wake_latency)) {
|
||||
pr_debug("No wakeup residency found, assuming 10 us\n");
|
||||
lpi_state->wake_latency = 10;
|
||||
}
|
||||
|
||||
if (obj_get_integer(pkg_elem + 2, &lpi_state->flags))
|
||||
lpi_state->flags = 0;
|
||||
|
||||
if (obj_get_integer(pkg_elem + 3, &lpi_state->arch_flags))
|
||||
lpi_state->arch_flags = 0;
|
||||
|
||||
if (obj_get_integer(pkg_elem + 4, &lpi_state->res_cnt_freq))
|
||||
lpi_state->res_cnt_freq = 1;
|
||||
|
||||
if (obj_get_integer(pkg_elem + 5, &lpi_state->enable_parent_state))
|
||||
lpi_state->enable_parent_state = 0;
|
||||
}
|
||||
|
||||
acpi_handle_debug(handle, "Found %d power states\n", state_idx);
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* combine_lpi_states - combine local and parent LPI states to form a composite LPI state
|
||||
*
|
||||
* @local: local LPI state
|
||||
* @parent: parent LPI state
|
||||
* @result: composite LPI state
|
||||
*/
|
||||
static bool combine_lpi_states(struct acpi_lpi_state *local,
|
||||
struct acpi_lpi_state *parent,
|
||||
struct acpi_lpi_state *result)
|
||||
{
|
||||
if (parent->entry_method == ACPI_CSTATE_INTEGER) {
|
||||
if (!parent->address) /* 0 means autopromotable */
|
||||
return false;
|
||||
result->address = local->address + parent->address;
|
||||
} else {
|
||||
result->address = parent->address;
|
||||
}
|
||||
|
||||
result->min_residency = max(local->min_residency, parent->min_residency);
|
||||
result->wake_latency = local->wake_latency + parent->wake_latency;
|
||||
result->enable_parent_state = parent->enable_parent_state;
|
||||
result->entry_method = local->entry_method;
|
||||
|
||||
result->flags = parent->flags;
|
||||
result->arch_flags = parent->arch_flags;
|
||||
result->index = parent->index;
|
||||
|
||||
scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0)
|
||||
|
||||
static void stash_composite_state(struct acpi_lpi_states_array *curr_level,
|
||||
struct acpi_lpi_state *t)
|
||||
{
|
||||
curr_level->composite_states[curr_level->composite_states_size++] = t;
|
||||
}
|
||||
|
||||
static unsigned int flatten_lpi_states(struct acpi_processor *pr,
|
||||
unsigned int flat_state_cnt,
|
||||
struct acpi_lpi_states_array *curr_level,
|
||||
struct acpi_lpi_states_array *prev_level)
|
||||
{
|
||||
int i, j, state_count = curr_level->size;
|
||||
struct acpi_lpi_state *p, *t = curr_level->entries;
|
||||
|
||||
curr_level->composite_states_size = 0;
|
||||
for (j = 0; j < state_count; j++, t++) {
|
||||
struct acpi_lpi_state *flpi;
|
||||
|
||||
if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED))
|
||||
continue;
|
||||
|
||||
if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) {
|
||||
pr_warn("Limiting number of LPI states to max (%d)\n",
|
||||
ACPI_PROCESSOR_MAX_POWER);
|
||||
pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
flpi = &pr->power.lpi_states[flat_state_cnt];
|
||||
|
||||
if (!prev_level) { /* leaf/processor node */
|
||||
memcpy(flpi, t, sizeof(*t));
|
||||
stash_composite_state(curr_level, flpi);
|
||||
flat_state_cnt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < prev_level->composite_states_size; i++) {
|
||||
p = prev_level->composite_states[i];
|
||||
if (t->index <= p->enable_parent_state &&
|
||||
combine_lpi_states(p, t, flpi)) {
|
||||
stash_composite_state(curr_level, flpi);
|
||||
flat_state_cnt++;
|
||||
flpi++;
|
||||
if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kfree(curr_level->entries);
|
||||
return flat_state_cnt;
|
||||
}
|
||||
|
||||
int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
@@ -1077,64 +860,16 @@ int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
|
||||
|
||||
static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
|
||||
{
|
||||
int ret, i;
|
||||
acpi_status status;
|
||||
acpi_handle handle = pr->handle, pr_ahandle;
|
||||
struct acpi_device *d = NULL;
|
||||
struct acpi_lpi_states_array info[2], *tmp, *prev, *curr;
|
||||
unsigned int state_count;
|
||||
int ret;
|
||||
|
||||
/* make sure our architecture has support */
|
||||
ret = acpi_processor_ffh_lpi_probe(pr->id);
|
||||
if (ret == -EOPNOTSUPP)
|
||||
return ret;
|
||||
|
||||
if (!osc_pc_lpi_support_confirmed)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!acpi_has_method(handle, "_LPI"))
|
||||
return -EINVAL;
|
||||
|
||||
prev = &info[0];
|
||||
curr = &info[1];
|
||||
handle = pr->handle;
|
||||
ret = acpi_processor_evaluate_lpi(handle, prev);
|
||||
ret = acpi_processor_extract_lpi_info(pr->handle, &pr->power, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
state_count = flatten_lpi_states(pr, 0, prev, NULL);
|
||||
|
||||
status = acpi_get_parent(handle, &pr_ahandle);
|
||||
while (ACPI_SUCCESS(status)) {
|
||||
d = acpi_fetch_acpi_dev(pr_ahandle);
|
||||
if (!d)
|
||||
break;
|
||||
|
||||
handle = pr_ahandle;
|
||||
|
||||
if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
|
||||
break;
|
||||
|
||||
/* can be optional ? */
|
||||
if (!acpi_has_method(handle, "_LPI"))
|
||||
break;
|
||||
|
||||
ret = acpi_processor_evaluate_lpi(handle, curr);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
/* flatten all the LPI states in this level of hierarchy */
|
||||
state_count = flatten_lpi_states(pr, state_count, curr, prev);
|
||||
|
||||
tmp = prev, prev = curr, curr = tmp;
|
||||
|
||||
status = acpi_get_parent(handle, &pr_ahandle);
|
||||
}
|
||||
|
||||
/* reset the index after flattening */
|
||||
for (i = 0; i < state_count; i++)
|
||||
pr->power.lpi_states[i].index = i;
|
||||
|
||||
pr->power.count = state_count;
|
||||
|
||||
/* Tell driver that _LPI is supported. */
|
||||
pr->flags.has_lpi = 1;
|
||||
|
||||
@@ -1780,6 +1780,7 @@ module_param_named(no_native, no_native, bool, 0444);
|
||||
MODULE_PARM_DESC(no_native, "Ignore cpu specific (native) idle states in lieu of ACPI idle states");
|
||||
|
||||
static struct acpi_processor_power acpi_state_table __initdata;
|
||||
static bool acpi_lpi_available __initdata;
|
||||
|
||||
/**
|
||||
* intel_idle_cst_usable - Check if the _CST information can be used.
|
||||
@@ -1804,18 +1805,37 @@ static bool __init intel_idle_cst_usable(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __init intel_idle_acpi_cst_extract(void)
|
||||
static bool __init intel_idle_acpi_extract_lpi_cstates(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
if (no_acpi) {
|
||||
pr_debug("Not allowed to use ACPI _CST\n");
|
||||
return false;
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct acpi_processor *pr;
|
||||
|
||||
pr = per_cpu(processors, cpu);
|
||||
if (!pr)
|
||||
continue;
|
||||
|
||||
if (acpi_processor_extract_lpi_info(pr->handle,
|
||||
&acpi_state_table, true))
|
||||
continue;
|
||||
|
||||
acpi_lpi_available = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct acpi_processor *pr = per_cpu(processors, cpu);
|
||||
pr_debug("No ACPI _LPI idle states\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool __init intel_idle_acpi_extract_cst_cstates(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct acpi_processor *pr;
|
||||
|
||||
pr = per_cpu(processors, cpu);
|
||||
if (!pr)
|
||||
continue;
|
||||
|
||||
@@ -1827,18 +1847,96 @@ static bool __init intel_idle_acpi_cst_extract(void)
|
||||
if (!intel_idle_cst_usable())
|
||||
continue;
|
||||
|
||||
if (!acpi_processor_claim_cst_control())
|
||||
break;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
acpi_state_table.count = 0;
|
||||
pr_debug("ACPI _CST not found or not usable\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv)
|
||||
static bool __init intel_idle_acpi_extract_cstates(void)
|
||||
{
|
||||
if (intel_idle_acpi_extract_lpi_cstates())
|
||||
return true;
|
||||
|
||||
if (intel_idle_acpi_extract_cst_cstates())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool __init intel_idle_acpi_probe(void)
|
||||
{
|
||||
if (no_acpi) {
|
||||
pr_debug("Not allowed to use ACPI for C-states extraction\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intel_idle_acpi_extract_cstates() &&
|
||||
acpi_processor_claim_cst_control())
|
||||
return true;
|
||||
|
||||
acpi_state_table.count = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __init intel_idle_complete_state_init(struct cpuidle_state *state)
|
||||
{
|
||||
if (intel_idle_state_needs_timer_stop(state))
|
||||
state->flags |= CPUIDLE_FLAG_TIMER_STOP;
|
||||
|
||||
state->enter = intel_idle;
|
||||
state->enter_dead = intel_idle_enter_dead;
|
||||
state->enter_s2idle = intel_idle_s2idle;
|
||||
}
|
||||
|
||||
static void __init intel_idle_init_cstates_acpi_lpi(struct cpuidle_driver *drv)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < acpi_state_table.count; index++) {
|
||||
struct acpi_lpi_state *lpi_state;
|
||||
struct cpuidle_state *state;
|
||||
|
||||
if (intel_idle_max_cstate_reached(index))
|
||||
break;
|
||||
|
||||
lpi_state = &acpi_state_table.lpi_states[index];
|
||||
|
||||
state = &drv->states[drv->state_count++];
|
||||
|
||||
scnprintf(state->name, CPUIDLE_NAME_LEN, "C%d_LPI", index + 1);
|
||||
strscpy(state->desc, lpi_state->desc, CPUIDLE_DESC_LEN);
|
||||
state->exit_latency = lpi_state->wake_latency;
|
||||
state->target_residency = lpi_state->min_residency;
|
||||
state->flags = MWAIT2flg(lpi_state->address);
|
||||
/*
|
||||
* Assume that entering any of the idle states extracted from
|
||||
* _LPI except for the first two will cause the TLB to be
|
||||
* flushed and let the core call leave_mm() for them upfront
|
||||
* to avoid unnecessary wakeups due to TLB shootdowns.
|
||||
*/
|
||||
if (index > 1)
|
||||
state->flags |= CPUIDLE_FLAG_TLB_FLUSHED;
|
||||
|
||||
if (disabled_states_mask & BIT(index + 1))
|
||||
state->flags |= CPUIDLE_FLAG_OFF;
|
||||
|
||||
intel_idle_complete_state_init(state);
|
||||
|
||||
pr_info("%s: MWAIT hint 0x%x\n", state->name, flg2MWAIT(state->flags));
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume the first idle state in the table to be C1 and if any deeper
|
||||
* idle states are exposed while X86_FEATURE_NONSTOP_TSC is unset, mark
|
||||
* the TSC as unstable.
|
||||
*/
|
||||
if (index > 1 && !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
|
||||
mark_tsc_unstable("TSC halts in idle");
|
||||
}
|
||||
|
||||
static void __init intel_idle_init_cstates_acpi_cst(struct cpuidle_driver *drv)
|
||||
{
|
||||
int cstate, limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count);
|
||||
|
||||
@@ -1880,49 +1978,76 @@ static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv)
|
||||
if (disabled_states_mask & BIT(cstate))
|
||||
state->flags |= CPUIDLE_FLAG_OFF;
|
||||
|
||||
if (intel_idle_state_needs_timer_stop(state))
|
||||
state->flags |= CPUIDLE_FLAG_TIMER_STOP;
|
||||
|
||||
if (cx->type > ACPI_STATE_C1 && !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
|
||||
mark_tsc_unstable("TSC halts in idle");
|
||||
|
||||
state->enter = intel_idle;
|
||||
state->enter_dead = intel_idle_enter_dead;
|
||||
state->enter_s2idle = intel_idle_s2idle;
|
||||
intel_idle_complete_state_init(state);
|
||||
}
|
||||
}
|
||||
|
||||
static bool __init intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
|
||||
static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv)
|
||||
{
|
||||
int cstate, limit;
|
||||
if (acpi_lpi_available)
|
||||
intel_idle_init_cstates_acpi_lpi(drv);
|
||||
else
|
||||
intel_idle_init_cstates_acpi_cst(drv);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no _CST C-states, do not disable any C-states by
|
||||
* default.
|
||||
*/
|
||||
if (!acpi_state_table.count)
|
||||
return false;
|
||||
static bool __init intel_idle_acpi_hint_match(unsigned int flags, u32 acpi_hint,
|
||||
u32 table_hint)
|
||||
{
|
||||
if (flags & CPUIDLE_FLAG_PARTIAL_HINT_MATCH) {
|
||||
acpi_hint &= ~MWAIT_SUBSTATE_MASK;
|
||||
table_hint &= ~MWAIT_SUBSTATE_MASK;
|
||||
}
|
||||
return acpi_hint == table_hint;
|
||||
}
|
||||
|
||||
static bool __init intel_idle_off_by_default_lpi(unsigned int flags, u32 mwait_hint)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < acpi_state_table.count; index++) {
|
||||
u32 acpi_hint = acpi_state_table.lpi_states[index].address;
|
||||
|
||||
if (intel_idle_acpi_hint_match(flags, acpi_hint, mwait_hint))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __init intel_idle_off_by_default_cst(unsigned int flags, u32 mwait_hint)
|
||||
{
|
||||
int cstate, limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count);
|
||||
|
||||
limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count);
|
||||
/*
|
||||
* If limit > 0, intel_idle_cst_usable() has returned 'true', so all of
|
||||
* the interesting states are ACPI_CSTATE_FFH.
|
||||
*/
|
||||
for (cstate = 1; cstate < limit; cstate++) {
|
||||
u32 acpi_hint = acpi_state_table.states[cstate].address;
|
||||
u32 table_hint = mwait_hint;
|
||||
|
||||
if (flags & CPUIDLE_FLAG_PARTIAL_HINT_MATCH) {
|
||||
acpi_hint &= ~MWAIT_SUBSTATE_MASK;
|
||||
table_hint &= ~MWAIT_SUBSTATE_MASK;
|
||||
}
|
||||
|
||||
if (acpi_hint == table_hint)
|
||||
if (intel_idle_acpi_hint_match(flags, acpi_hint, mwait_hint))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __init intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
|
||||
{
|
||||
/*
|
||||
* If there is no C-states information in the ACPI tables, do not
|
||||
* disable any C-states by default.
|
||||
*/
|
||||
if (!acpi_state_table.count)
|
||||
return false;
|
||||
|
||||
if (acpi_lpi_available)
|
||||
return intel_idle_off_by_default_lpi(flags, mwait_hint);
|
||||
|
||||
return intel_idle_off_by_default_cst(flags, mwait_hint);
|
||||
}
|
||||
|
||||
static inline bool ignore_native(void)
|
||||
{
|
||||
return no_native && !no_acpi;
|
||||
@@ -1930,7 +2055,7 @@ static inline bool ignore_native(void)
|
||||
#else /* !CONFIG_ACPI_PROCESSOR_CSTATE */
|
||||
#define force_use_acpi (false)
|
||||
|
||||
static inline bool intel_idle_acpi_cst_extract(void) { return false; }
|
||||
static inline bool intel_idle_acpi_probe(void) { return false; }
|
||||
static inline void intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) { }
|
||||
static inline bool intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
|
||||
{
|
||||
@@ -2745,7 +2870,7 @@ static int __init intel_idle_init(void)
|
||||
if (icpu) {
|
||||
if (icpu->state_table)
|
||||
cpuidle_state_table = icpu->state_table;
|
||||
else if (!intel_idle_acpi_cst_extract())
|
||||
else if (!intel_idle_acpi_probe())
|
||||
return -ENODEV;
|
||||
|
||||
auto_demotion_disable_flags = icpu->auto_demotion_disable_flags;
|
||||
@@ -2754,8 +2879,8 @@ static int __init intel_idle_init(void)
|
||||
if (icpu->c1_demotion_supported)
|
||||
c1_demotion_supported = true;
|
||||
if (icpu->use_acpi || force_use_acpi)
|
||||
intel_idle_acpi_cst_extract();
|
||||
} else if (!intel_idle_acpi_cst_extract()) {
|
||||
intel_idle_acpi_probe();
|
||||
} else if (!intel_idle_acpi_probe()) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
@@ -315,6 +315,19 @@ static inline int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCESSOR_IDLE
|
||||
int acpi_processor_extract_lpi_info(acpi_handle pr_handle,
|
||||
struct acpi_processor_power *pr_power,
|
||||
bool strict);
|
||||
#else
|
||||
static inline int acpi_processor_extract_lpi_info(acpi_handle pr_handle,
|
||||
struct acpi_processor_power *pr_power,
|
||||
bool strict)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
/* Arch dependent functions for cpu hotplug support */
|
||||
int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id,
|
||||
|
||||
Reference in New Issue
Block a user