ACPI: processor: Export acpi_processor_evaluate_cst()
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 13 Dec 2019 08:55:42 +0000 (09:55 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 27 Dec 2019 10:02:07 +0000 (11:02 +0100)
The intel_idle driver will be modified to use ACPI _CST subsequently
and it will need to call acpi_processor_evaluate_cst(), so move that
function to acpi_processor.c so that it is always present (which is
required by intel_idle) and export it to modules to allow the ACPI
processor driver (which is modular) to call it.

No intentional functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpi_processor.c
drivers/acpi/processor_idle.c
include/linux/acpi.h

index 8a53f3c5b70e6471137dfa2fda74438bdf0506ba..5379bc3f275d76628742ce2b59e021b9d2535395 100644 (file)
@@ -729,4 +729,161 @@ bool acpi_processor_claim_cst_control(void)
        return true;
 }
 EXPORT_SYMBOL_GPL(acpi_processor_claim_cst_control);
+
+/**
+ * acpi_processor_evaluate_cst - Evaluate the processor _CST control method.
+ * @handle: ACPI handle of the processor object containing the _CST.
+ * @cpu: The numeric ID of the target CPU.
+ * @info: Object write the C-states information into.
+ *
+ * Extract the C-state information for the given CPU from the output of the _CST
+ * control method under the corresponding ACPI processor object (or processor
+ * device object) and populate @info with it.
+ *
+ * If any ACPI_ADR_SPACE_FIXED_HARDWARE C-states are found, invoke
+ * acpi_processor_ffh_cstate_probe() to verify them and update the
+ * cpu_cstate_entry data for @cpu.
+ */
+int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
+                               struct acpi_processor_power *info)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *cst;
+       acpi_status status;
+       u64 count;
+       int last_index = 0;
+       int i, ret = 0;
+
+       status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               acpi_handle_debug(handle, "No _CST\n");
+               return -ENODEV;
+       }
+
+       cst = buffer.pointer;
+
+       /* There must be at least 2 elements. */
+       if (!cst || cst->type != ACPI_TYPE_PACKAGE || cst->package.count < 2) {
+               acpi_handle_warn(handle, "Invalid _CST output\n");
+               ret = -EFAULT;
+               goto end;
+       }
+
+       count = cst->package.elements[0].integer.value;
+
+       /* Validate the number of C-states. */
+       if (count < 1 || count != cst->package.count - 1) {
+               acpi_handle_warn(handle, "Inconsistent _CST data\n");
+               ret = -EFAULT;
+               goto end;
+       }
+
+       for (i = 1; i <= count; i++) {
+               union acpi_object *element;
+               union acpi_object *obj;
+               struct acpi_power_register *reg;
+               struct acpi_processor_cx cx;
+
+               /*
+                * If there is not enough space for all C-states, skip the
+                * excess ones and log a warning.
+                */
+               if (last_index >= ACPI_PROCESSOR_MAX_POWER - 1) {
+                       acpi_handle_warn(handle,
+                                        "No room for more idle states (limit: %d)\n",
+                                        ACPI_PROCESSOR_MAX_POWER - 1);
+                       break;
+               }
+
+               memset(&cx, 0, sizeof(cx));
+
+               element = &cst->package.elements[i];
+               if (element->type != ACPI_TYPE_PACKAGE)
+                       continue;
+
+               if (element->package.count != 4)
+                       continue;
+
+               obj = &element->package.elements[0];
+
+               if (obj->type != ACPI_TYPE_BUFFER)
+                       continue;
+
+               reg = (struct acpi_power_register *)obj->buffer.pointer;
+
+               obj = &element->package.elements[1];
+               if (obj->type != ACPI_TYPE_INTEGER)
+                       continue;
+
+               cx.type = obj->integer.value;
+               /*
+                * There are known cases in which the _CST output does not
+                * contain C1, so if the type of the first state found is not
+                * C1, leave an empty slot for C1 to be filled in later.
+                */
+               if (i == 1 && cx.type != ACPI_STATE_C1)
+                       last_index = 1;
+
+               cx.address = reg->address;
+               cx.index = last_index + 1;
+
+               if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+                       if (!acpi_processor_ffh_cstate_probe(cpu, &cx, reg)) {
+                               /*
+                                * In the majority of cases _CST describes C1 as
+                                * a FIXED_HARDWARE C-state, but if the command
+                                * line forbids using MWAIT, use CSTATE_HALT for
+                                * C1 regardless.
+                                */
+                               if (cx.type == ACPI_STATE_C1 &&
+                                   boot_option_idle_override == IDLE_NOMWAIT) {
+                                       cx.entry_method = ACPI_CSTATE_HALT;
+                                       snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
+                               } else {
+                                       cx.entry_method = ACPI_CSTATE_FFH;
+                               }
+                       } else if (cx.type == ACPI_STATE_C1) {
+                               /*
+                                * In the special case of C1, FIXED_HARDWARE can
+                                * be handled by executing the HLT instruction.
+                                */
+                               cx.entry_method = ACPI_CSTATE_HALT;
+                               snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
+                       } else {
+                               continue;
+                       }
+               } else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+                       cx.entry_method = ACPI_CSTATE_SYSTEMIO;
+                       snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",
+                                cx.address);
+               } else {
+                       continue;
+               }
+
+               if (cx.type == ACPI_STATE_C1)
+                       cx.valid = 1;
+
+               obj = &element->package.elements[2];
+               if (obj->type != ACPI_TYPE_INTEGER)
+                       continue;
+
+               cx.latency = obj->integer.value;
+
+               obj = &element->package.elements[3];
+               if (obj->type != ACPI_TYPE_INTEGER)
+                       continue;
+
+               memcpy(&info->states[++last_index], &cx, sizeof(cx));
+       }
+
+       acpi_handle_info(handle, "Found %d idle states\n", last_index);
+
+       info->count = last_index;
+
+      end:
+       kfree(buffer.pointer);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_processor_evaluate_cst);
 #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
index 7c2fe3b2ec31c27a0e7579010e30c749606ec238..dcc289e30166cf78d2c33932dcbe304ee08bc5ff 100644 (file)
@@ -297,148 +297,6 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
        return 0;
 }
 
-static int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
-                                      struct acpi_processor_power *info)
-{
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *cst;
-       acpi_status status;
-       u64 count;
-       int last_index = 0;
-       int i, ret = 0;
-
-       status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
-       if (ACPI_FAILURE(status)) {
-               acpi_handle_debug(handle, "No _CST\n");
-               return -ENODEV;
-       }
-
-       cst = buffer.pointer;
-
-       /* There must be at least 2 elements. */
-       if (!cst || cst->type != ACPI_TYPE_PACKAGE || cst->package.count < 2) {
-               acpi_handle_warn(handle, "Invalid _CST output\n");
-               ret = -EFAULT;
-               goto end;
-       }
-
-       count = cst->package.elements[0].integer.value;
-
-       /* Validate the number of C-states. */
-       if (count < 1 || count != cst->package.count - 1) {
-               acpi_handle_warn(handle, "Inconsistent _CST data\n");
-               ret = -EFAULT;
-               goto end;
-       }
-
-       for (i = 1; i <= count; i++) {
-               union acpi_object *element;
-               union acpi_object *obj;
-               struct acpi_power_register *reg;
-               struct acpi_processor_cx cx;
-
-               /*
-                * If there is not enough space for all C-states, skip the
-                * excess ones and log a warning.
-                */
-               if (last_index >= ACPI_PROCESSOR_MAX_POWER - 1) {
-                       acpi_handle_warn(handle,
-                                        "No room for more idle states (limit: %d)\n",
-                                        ACPI_PROCESSOR_MAX_POWER - 1);
-                       break;
-               }
-
-               memset(&cx, 0, sizeof(cx));
-
-               element = &cst->package.elements[i];
-               if (element->type != ACPI_TYPE_PACKAGE)
-                       continue;
-
-               if (element->package.count != 4)
-                       continue;
-
-               obj = &element->package.elements[0];
-
-               if (obj->type != ACPI_TYPE_BUFFER)
-                       continue;
-
-               reg = (struct acpi_power_register *)obj->buffer.pointer;
-
-               obj = &element->package.elements[1];
-               if (obj->type != ACPI_TYPE_INTEGER)
-                       continue;
-
-               cx.type = obj->integer.value;
-               /*
-                * There are known cases in which the _CST output does not
-                * contain C1, so if the type of the first state found is not
-                * C1, leave an empty slot for C1 to be filled in later.
-                */
-               if (i == 1 && cx.type != ACPI_STATE_C1)
-                       last_index = 1;
-
-               cx.address = reg->address;
-               cx.index = last_index + 1;
-
-               if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
-                       if (!acpi_processor_ffh_cstate_probe(cpu, &cx, reg)) {
-                               /*
-                                * In the majority of cases _CST describes C1 as
-                                * a FIXED_HARDWARE C-state, but if the command
-                                * line forbids using MWAIT, use CSTATE_HALT for
-                                * C1 regardless.
-                                */
-                               if (cx.type == ACPI_STATE_C1 &&
-                                   boot_option_idle_override == IDLE_NOMWAIT) {
-                                       cx.entry_method = ACPI_CSTATE_HALT;
-                                       snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
-                               } else {
-                                       cx.entry_method = ACPI_CSTATE_FFH;
-                               }
-                       } else if (cx.type == ACPI_STATE_C1) {
-                               /*
-                                * In the special case of C1, FIXED_HARDWARE can
-                                * be handled by executing the HLT instruction.
-                                */
-                               cx.entry_method = ACPI_CSTATE_HALT;
-                               snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
-                       } else {
-                               continue;
-                       }
-               } else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
-                       cx.entry_method = ACPI_CSTATE_SYSTEMIO;
-                       snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",
-                                cx.address);
-               } else {
-                       continue;
-               }
-
-               if (cx.type == ACPI_STATE_C1)
-                       cx.valid = 1;
-
-               obj = &element->package.elements[2];
-               if (obj->type != ACPI_TYPE_INTEGER)
-                       continue;
-
-               cx.latency = obj->integer.value;
-
-               obj = &element->package.elements[3];
-               if (obj->type != ACPI_TYPE_INTEGER)
-                       continue;
-
-               memcpy(&info->states[++last_index], &cx, sizeof(cx));
-       }
-
-       acpi_handle_info(handle, "Found %d idle states\n", last_index);
-
-       info->count = last_index;
-
-      end:
-       kfree(buffer.pointer);
-
-       return ret;
-}
-
 static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
 {
        int ret;
index ee39b05e7f76c24b962ba44d279a674d421d872e..0f24d701fbdc9f09a9a1e706ad168ae37ed50e49 100644 (file)
@@ -280,10 +280,19 @@ static inline bool invalid_phys_cpuid(phys_cpuid_t phys_id)
 /* Validate the processor object's proc_id */
 bool acpi_duplicate_processor_id(int proc_id);
 /* Processor _CTS control */
+struct acpi_processor_power;
+
 #ifdef CONFIG_ACPI_PROCESSOR_CSTATE
 bool acpi_processor_claim_cst_control(void);
+int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
+                               struct acpi_processor_power *info);
 #else
 static inline bool acpi_processor_claim_cst_control(void) { return false; }
+static inline int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
+                                             struct acpi_processor_power *info)
+{
+       return -ENODEV;
+}
 #endif
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU