Re: [PATCH] ACPI: PM: s2idle: Add AMD support to handle _DSM during S2Idle

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Oct 23, 2020 at 10:04 AM Shyam Sundar S K
<Shyam-sundar.S-k@xxxxxxx> wrote:
>
> Initial support for S2Idle based on the Intel implementation[1] does not
> work for AMD as the BIOS implementation for ACPI methods like the _DSM
> are not standardized.
>
> So, the way in which the UUID's were parsed and the ACPI packages were
> retrieved out of the ACPI objects are not the same between Intel and AMD.
>
> This patch adds AMD support for S2Idle to parse the UUID, evaluate the
> _DSM methods, preparing the Idle constaint list etc.

constraint

> Link: https://uefi.org/sites/default/files/resources/Intel_ACPI_Low_Power_S0_Idle.pdf # [1]
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@xxxxxxx>
> ---
>  drivers/acpi/sleep.c | 166 ++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 158 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
> index aff13bf4d947..a36b4ddcd1e9 100644
> --- a/drivers/acpi/sleep.c
> +++ b/drivers/acpi/sleep.c
> @@ -710,6 +710,11 @@ static const struct acpi_device_id lps0_device_ids[] = {
>  #define ACPI_LPS0_ENTRY                5
>  #define ACPI_LPS0_EXIT         6
>
> +/* AMD */
> +#define ACPI_LPS0_DSM_UUID_AMD      "e3f32452-febc-43ce-9039-932122d37721"
> +#define ACPI_LPS0_SCREEN_OFF_AMD    4
> +#define ACPI_LPS0_SCREEN_ON_AMD     5
> +
>  static acpi_handle lps0_device_handle;
>  static guid_t lps0_dsm_guid;
>  static char lps0_dsm_func_mask;
> @@ -733,8 +738,128 @@ struct lpi_constraints {
>         int min_dstate;
>  };
>
> +/* AMD */
> +/* Device constraint entry structure */
> +struct lpi_device_info_amd {
> +       int revision;
> +       int count;
> +       union acpi_object *package;
> +};
> +
> +/* Constraint package structure */
> +struct lpi_device_constraint_amd {
> +       char *name;
> +       int enabled;
> +       int function_states;
> +       int min_dstate;
> +};
> +
>  static struct lpi_constraints *lpi_constraints_table;
>  static int lpi_constraints_table_size;
> +static int rev_id;
> +
> +static void lpi_device_get_constraints_amd(void)
> +{
> +       union acpi_object *out_obj;
> +       int i, j, k;
> +
> +       out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
> +                                         1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
> +                                         NULL, ACPI_TYPE_PACKAGE);
> +
> +       if (!out_obj)
> +               return;
> +
> +       acpi_handle_info(lps0_device_handle, "_DSM function 1 eval %s\n",
> +                        out_obj ? "successful" : "failed");

The existing lpi_device_get_constraints() uses acpi_handle_debug().

Why is it necessary to use acpi_handle_info() here?

> +
> +       for (i = 0; i < out_obj->package.count; i++) {
> +               union acpi_object *package = &out_obj->package.elements[i];
> +               struct lpi_device_info_amd info = { };
> +
> +               if (package->type == ACPI_TYPE_INTEGER) {
> +                       switch (i) {
> +                       case 0:
> +                               info.revision = package->integer.value;
> +                               break;
> +                       case 1:
> +                               info.count = package->integer.value;
> +                               break;
> +                       default:
> +                               break;

Not needed AFAICS.

> +                       }
> +               } else if (package->type == ACPI_TYPE_PACKAGE) {
> +                       lpi_constraints_table = kcalloc(package->package.count,
> +                                                       sizeof(*lpi_constraints_table),
> +                                                       GFP_KERNEL);
> +
> +                       if (!lpi_constraints_table)
> +                               goto free_acpi_buffer;
> +
> +                       acpi_handle_info(lps0_device_handle,
> +                                        "LPI: constraints list begin:\n");
> +
> +                       for (j = 0; j < package->package.count; ++j) {
> +                               union acpi_object *info_obj = &package->package.elements[j];
> +                               struct lpi_device_constraint_amd dev_info = {};
> +                               struct lpi_constraints *list;
> +                               acpi_status status;
> +
> +                               for (k = 0; k < info_obj->package.count; ++k) {
> +                                       union acpi_object *obj = &info_obj->package.elements[k];
> +                                       union acpi_object *obj_new;
> +
> +                                       list = &lpi_constraints_table[lpi_constraints_table_size];
> +                                       list->min_dstate = -1;
> +
> +                                       obj_new = &obj[k];
> +                                       switch (k) {
> +                                       case 0:
> +                                               dev_info.enabled = obj->integer.value;
> +                                               break;
> +                                       case 1:
> +                                               dev_info.name = obj->string.pointer;
> +                                               break;
> +                                       case 2:
> +                                               dev_info.function_states = obj->integer.value;
> +                                               break;
> +                                       case 3:
> +                                               dev_info.min_dstate = obj->integer.value;
> +                                               break;
> +                                       default:
> +                                               break;

Likewise.

> +                                       }
> +
> +                                       if (!dev_info.enabled || !dev_info.name ||
> +                                           !dev_info.min_dstate)
> +                                               continue;
> +
> +                                       status = acpi_get_handle(NULL, dev_info.name,
> +                                                                &list->handle);
> +                                       if (ACPI_FAILURE(status))
> +                                               continue;
> +
> +                                       acpi_handle_info(lps0_device_handle,
> +                                                        "index:%d Name:%s\n", k, dev_info.name);
> +
> +                                       list->min_dstate = dev_info.min_dstate;
> +
> +                                       if (list->min_dstate < 0) {
> +                                               acpi_handle_info(lps0_device_handle,
> +                                                                "Incomplete constraint defined\n");
> +                                               continue;
> +                                       }
> +                               }
> +                               lpi_constraints_table_size++;
> +                       }
> +               }
> +       }
> +
> +       acpi_handle_info(lps0_device_handle, "LPI: constraints list end\n");
> +
> +free_acpi_buffer:
> +       ACPI_FREE(out_obj);
> +}
>
>  static void lpi_device_get_constraints(void)
>  {
> @@ -883,7 +1008,7 @@ static void acpi_sleep_run_lps0_dsm(unsigned int func)
>         if (!(lps0_dsm_func_mask & (1 << func)))
>                 return;
>
> -       out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, 1, func, NULL);
> +       out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, rev_id, func, NULL);
>         ACPI_FREE(out_obj);
>
>         acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n",
> @@ -894,6 +1019,7 @@ static int lps0_device_attach(struct acpi_device *adev,
>                               const struct acpi_device_id *not_used)
>  {
>         union acpi_object *out_obj;
> +       struct cpuinfo_x86 *c = &boot_cpu_data;

Why do you need this pointer on the stack?

What would be wrong with accessing boot_cpu_data directly below?

Besides, this file doesn't depend on X86 and it may not build on the
other architectures after your changes.



[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux