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>
This commit is contained in:
parent
be9d73e649
commit
4b4967cbd2
@ -82,12 +82,17 @@ enum hp_wmi_event_ids {
|
|||||||
HPWMI_BATTERY_CHARGE_PERIOD = 0x10,
|
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 {
|
struct bios_args {
|
||||||
u32 signature;
|
u32 signature;
|
||||||
u32 command;
|
u32 command;
|
||||||
u32 commandtype;
|
u32 commandtype;
|
||||||
u32 datasize;
|
u32 datasize;
|
||||||
u8 data[128];
|
u8 data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum hp_wmi_commandtype {
|
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,
|
static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
|
||||||
void *buffer, int insize, int outsize)
|
void *buffer, int insize, int outsize)
|
||||||
{
|
{
|
||||||
int mid;
|
struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
struct bios_return *bios_return;
|
struct bios_return *bios_return;
|
||||||
int actual_outsize;
|
union acpi_object *obj = NULL;
|
||||||
union acpi_object *obj;
|
struct bios_args *args = NULL;
|
||||||
struct bios_args args = {
|
int mid, actual_outsize, ret;
|
||||||
.signature = 0x55434553,
|
size_t bios_args_size;
|
||||||
.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;
|
|
||||||
|
|
||||||
mid = encode_outsize_for_pvsz(outsize);
|
mid = encode_outsize_for_pvsz(outsize);
|
||||||
if (WARN_ON(mid < 0))
|
if (WARN_ON(mid < 0))
|
||||||
return mid;
|
return mid;
|
||||||
|
|
||||||
if (WARN_ON(insize > sizeof(args.data)))
|
bios_args_size = struct_size(args, data, insize);
|
||||||
return -EINVAL;
|
args = kmalloc(bios_args_size, GFP_KERNEL);
|
||||||
memcpy(&args.data[0], buffer, insize);
|
if (!args)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
|
input.length = bios_args_size;
|
||||||
|
input.pointer = args;
|
||||||
|
|
||||||
|
args->signature = 0x55434553;
|
||||||
|
args->command = command;
|
||||||
|
args->commandtype = query;
|
||||||
|
args->datasize = insize;
|
||||||
|
memcpy(args->data, buffer, flex_array_size(args, data, insize));
|
||||||
|
|
||||||
|
ret = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
|
||||||
|
if (ret)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
obj = output.pointer;
|
obj = output.pointer;
|
||||||
|
if (!obj) {
|
||||||
if (!obj)
|
ret = -EINVAL;
|
||||||
return -EINVAL;
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||||
|
pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
@ -321,6 +332,7 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
|
|||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
kfree(obj);
|
kfree(obj);
|
||||||
|
kfree(args);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user