aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/platform
diff options
context:
space:
mode:
authorJorge Lopez <jorge.lopez2@hp.com>2022-03-10 15:08:53 -0600
committerHans de Goede <hdegoede@redhat.com>2022-03-15 10:49:37 +0100
commit4b4967cbd2685f313411e6facf915fb2ae01d796 (patch)
tree298862ed4cc67f04aaaef39b432f3ff525b03288 /drivers/platform
parentplatform/x86: hp-wmi: Fix 0x05 error code reported by several WMI calls (diff)
downloadwireguard-linux-4b4967cbd2685f313411e6facf915fb2ae01d796.tar.xz
wireguard-linux-4b4967cbd2685f313411e6facf915fb2ae01d796.zip
platform/x86: hp-wmi: Changing bios_args.data to be dynamically allocated
The purpose of this patch is to remove 128 bytes buffer limitation imposed in bios_args structure. A limiting factor discovered during this investigation was the struct bios_args.data size restriction. The data member size limits all possible WMI commands to those requiring buffer size of 128 bytes or less. Several WMI commands and queries require a buffer size larger than 128 bytes hence limiting current and feature supported by the driver. It is for this reason, struct bios_args.data changed and is dynamically allocated. hp_wmi_perform_query function changed to handle the memory allocation and release of any required buffer size. All changes were validated on a HP ZBook Workstation notebook, HP EliteBook x360, and HP EliteBook 850 G8. Additional validation was included in the test process to ensure no other commands were incorrectly handled. Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com> Link: https://lore.kernel.org/r/20220310210853.28367-5-jorge.lopez2@hp.com Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/hp-wmi.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 29ae35d15a41..1f9d6e1de5af 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -82,12 +82,17 @@ enum hp_wmi_event_ids {
HPWMI_BATTERY_CHARGE_PERIOD = 0x10,
};
+/*
+ * struct bios_args buffer is dynamically allocated. New WMI command types
+ * were introduced that exceeds 128-byte data size. Changes to handle
+ * the data size allocation scheme were kept in hp_wmi_perform_qurey function.
+ */
struct bios_args {
u32 signature;
u32 command;
u32 commandtype;
u32 datasize;
- u8 data[128];
+ u8 data[];
};
enum hp_wmi_commandtype {
@@ -266,37 +271,43 @@ static inline int encode_outsize_for_pvsz(int outsize)
static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
void *buffer, int insize, int outsize)
{
- int mid;
+ struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL };
struct bios_return *bios_return;
- int actual_outsize;
- union acpi_object *obj;
- struct bios_args args = {
- .signature = 0x55434553,
- .command = command,
- .commandtype = query,
- .datasize = insize,
- .data = { 0 },
- };
- struct acpi_buffer input = { sizeof(struct bios_args), &args };
- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
- int ret = 0;
+ union acpi_object *obj = NULL;
+ struct bios_args *args = NULL;
+ int mid, actual_outsize, ret;
+ size_t bios_args_size;
mid = encode_outsize_for_pvsz(outsize);
if (WARN_ON(mid < 0))
return mid;
- if (WARN_ON(insize > sizeof(args.data)))
- return -EINVAL;
- memcpy(&args.data[0], buffer, insize);
+ bios_args_size = struct_size(args, data, insize);
+ args = kmalloc(bios_args_size, GFP_KERNEL);
+ if (!args)
+ return -ENOMEM;
- wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
+ input.length = bios_args_size;
+ input.pointer = args;
- obj = output.pointer;
+ args->signature = 0x55434553;
+ args->command = command;
+ args->commandtype = query;
+ args->datasize = insize;
+ memcpy(args->data, buffer, flex_array_size(args, data, insize));
- if (!obj)
- return -EINVAL;
+ ret = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
+ if (ret)
+ goto out_free;
+
+ obj = output.pointer;
+ if (!obj) {
+ ret = -EINVAL;
+ goto out_free;
+ }
if (obj->type != ACPI_TYPE_BUFFER) {
+ pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret);
ret = -EINVAL;
goto out_free;
}
@@ -321,6 +332,7 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
out_free:
kfree(obj);
+ kfree(args);
return ret;
}