From 19c8b5241425948daeb0f91fe7a07cf1a4b76239 Mon Sep 17 00:00:00 2001 From: Muhammad Usama Anjum Date: Tue, 4 Oct 2022 13:10:19 +0500 Subject: platform/x86/amd/pmf: pass the struct by reference The out structure should be passed by reference instead of passing by value. This saves the extra copy of the structure. Signed-off-by: Muhammad Usama Anjum Link: https://lore.kernel.org/r/20221004081019.619193-1-usama.anjum@collabora.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/cnqf.c | 92 ++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c index 668c7c0fea83..3f9731a2ac28 100644 --- a/drivers/platform/x86/amd/pmf/cnqf.c +++ b/drivers/platform/x86/amd/pmf/cnqf.c @@ -158,100 +158,100 @@ int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_l return 0; } -static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output out) +static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out) { struct cnqf_tran_params *tp; tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET]; - tp->time_constant = out.t_balanced_to_quiet; + tp->time_constant = out->t_balanced_to_quiet; tp->target_mode = CNQF_MODE_QUIET; tp->shifting_up = false; tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; - tp->time_constant = out.t_balanced_to_perf; + tp->time_constant = out->t_balanced_to_perf; tp->target_mode = CNQF_MODE_PERFORMANCE; tp->shifting_up = true; tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; - tp->time_constant = out.t_quiet_to_balanced; + tp->time_constant = out->t_quiet_to_balanced; tp->target_mode = CNQF_MODE_BALANCE; tp->shifting_up = true; tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; - tp->time_constant = out.t_perf_to_balanced; + tp->time_constant = out->t_perf_to_balanced; tp->target_mode = CNQF_MODE_BALANCE; tp->shifting_up = false; tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; - tp->time_constant = out.t_turbo_to_perf; + tp->time_constant = out->t_turbo_to_perf; tp->target_mode = CNQF_MODE_PERFORMANCE; tp->shifting_up = false; tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO]; - tp->time_constant = out.t_perf_to_turbo; + tp->time_constant = out->t_perf_to_turbo; tp->target_mode = CNQF_MODE_TURBO; tp->shifting_up = true; } -static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output out) +static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out) { struct cnqf_mode_settings *ms; /* Quiet Mode */ ms = &config_store.mode_set[idx][CNQF_MODE_QUIET]; - ms->power_floor = out.ps[APMF_CNQF_QUIET].pfloor; - ms->power_control.fppt = out.ps[APMF_CNQF_QUIET].fppt; - ms->power_control.sppt = out.ps[APMF_CNQF_QUIET].sppt; - ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_QUIET].sppt_apu_only; - ms->power_control.spl = out.ps[APMF_CNQF_QUIET].spl; - ms->power_control.stt_min = out.ps[APMF_CNQF_QUIET].stt_min_limit; + ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor; + ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt; + ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt; + ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only; + ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl; + ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit; ms->power_control.stt_skin_temp[STT_TEMP_APU] = - out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU]; + out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU]; ms->power_control.stt_skin_temp[STT_TEMP_HS2] = - out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2]; - ms->fan_control.fan_id = out.ps[APMF_CNQF_QUIET].fan_id; + out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id; /* Balance Mode */ ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE]; - ms->power_floor = out.ps[APMF_CNQF_BALANCE].pfloor; - ms->power_control.fppt = out.ps[APMF_CNQF_BALANCE].fppt; - ms->power_control.sppt = out.ps[APMF_CNQF_BALANCE].sppt; - ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_BALANCE].sppt_apu_only; - ms->power_control.spl = out.ps[APMF_CNQF_BALANCE].spl; - ms->power_control.stt_min = out.ps[APMF_CNQF_BALANCE].stt_min_limit; + ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor; + ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt; + ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt; + ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only; + ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl; + ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit; ms->power_control.stt_skin_temp[STT_TEMP_APU] = - out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU]; + out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU]; ms->power_control.stt_skin_temp[STT_TEMP_HS2] = - out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2]; - ms->fan_control.fan_id = out.ps[APMF_CNQF_BALANCE].fan_id; + out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id; /* Performance Mode */ ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE]; - ms->power_floor = out.ps[APMF_CNQF_PERFORMANCE].pfloor; - ms->power_control.fppt = out.ps[APMF_CNQF_PERFORMANCE].fppt; - ms->power_control.sppt = out.ps[APMF_CNQF_PERFORMANCE].sppt; - ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_PERFORMANCE].sppt_apu_only; - ms->power_control.spl = out.ps[APMF_CNQF_PERFORMANCE].spl; - ms->power_control.stt_min = out.ps[APMF_CNQF_PERFORMANCE].stt_min_limit; + ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor; + ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt; + ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt; + ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only; + ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl; + ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit; ms->power_control.stt_skin_temp[STT_TEMP_APU] = - out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU]; + out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU]; ms->power_control.stt_skin_temp[STT_TEMP_HS2] = - out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2]; - ms->fan_control.fan_id = out.ps[APMF_CNQF_PERFORMANCE].fan_id; + out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id; /* Turbo Mode */ ms = &config_store.mode_set[idx][CNQF_MODE_TURBO]; - ms->power_floor = out.ps[APMF_CNQF_TURBO].pfloor; - ms->power_control.fppt = out.ps[APMF_CNQF_TURBO].fppt; - ms->power_control.sppt = out.ps[APMF_CNQF_TURBO].sppt; - ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_TURBO].sppt_apu_only; - ms->power_control.spl = out.ps[APMF_CNQF_TURBO].spl; - ms->power_control.stt_min = out.ps[APMF_CNQF_TURBO].stt_min_limit; + ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor; + ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt; + ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt; + ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only; + ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl; + ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit; ms->power_control.stt_skin_temp[STT_TEMP_APU] = - out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU]; + out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU]; ms->power_control.stt_skin_temp[STT_TEMP_HS2] = - out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2]; - ms->fan_control.fan_id = out.ps[APMF_CNQF_TURBO].fan_id; + out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id; } static int amd_pmf_check_flags(struct amd_pmf_dev *dev) @@ -284,8 +284,8 @@ static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev) return ret; } - amd_pmf_update_mode_set(i, out); - amd_pmf_update_trans_data(i, out); + amd_pmf_update_mode_set(i, &out); + amd_pmf_update_trans_data(i, &out); amd_pmf_update_power_threshold(i); for (j = 0; j < CNQF_MODE_MAX; j++) { -- cgit v1.2.3 From 878a82c23469d6626b27b44ade4d8f9438de51ab Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 27 Sep 2022 22:45:20 +0200 Subject: ACPI: battery: Pass battery hook pointer to hook callbacks Right now, is impossible for battery hook callbacks to access instance-specific data, forcing most drivers to provide some sort of global state. This however is difficult for drivers which can be instantiated multiple times and/or are hotplug-capable. Pass a pointer to the battery hook to those callbacks for usage with container_of(). Signed-off-by: Armin Wolf Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20220927204521.601887-2-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/acpi/battery.c | 8 ++++---- drivers/platform/x86/asus-wmi.c | 4 ++-- drivers/platform/x86/huawei-wmi.c | 4 ++-- drivers/platform/x86/lg-laptop.c | 4 ++-- drivers/platform/x86/system76_acpi.c | 4 ++-- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- drivers/platform/x86/toshiba_acpi.c | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 306513fec1e1..9482b0b6eadc 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -696,7 +696,7 @@ static void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock) if (lock) mutex_lock(&hook_mutex); list_for_each_entry(battery, &acpi_battery_list, list) { - hook->remove_battery(battery->bat); + hook->remove_battery(battery->bat, hook); } list_del(&hook->list); if (lock) @@ -724,7 +724,7 @@ void battery_hook_register(struct acpi_battery_hook *hook) * its attributes. */ list_for_each_entry(battery, &acpi_battery_list, list) { - if (hook->add_battery(battery->bat)) { + if (hook->add_battery(battery->bat, hook)) { /* * If a add-battery returns non-zero, * the registration of the extension has failed, @@ -762,7 +762,7 @@ static void battery_hook_add_battery(struct acpi_battery *battery) * during the battery module initialization. */ list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) { - if (hook_node->add_battery(battery->bat)) { + if (hook_node->add_battery(battery->bat, hook_node)) { /* * The notification of the extensions has failed, to * prevent further errors we will unload the extension. @@ -785,7 +785,7 @@ static void battery_hook_remove_battery(struct acpi_battery *battery) * custom attributes from the battery. */ list_for_each_entry(hook, &battery_hook_list, list) { - hook->remove_battery(battery->bat); + hook->remove_battery(battery->bat, hook); } /* Then, just remove the battery from the list */ list_del(&battery->list); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 872efc1d5b36..6f81b2844dcb 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -883,7 +883,7 @@ static ssize_t charge_control_end_threshold_show(struct device *device, static DEVICE_ATTR_RW(charge_control_end_threshold); -static int asus_wmi_battery_add(struct power_supply *battery) +static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { /* The WMI method does not provide a way to specific a battery, so we * just assume it is the first battery. @@ -910,7 +910,7 @@ static int asus_wmi_battery_add(struct power_supply *battery) return 0; } -static int asus_wmi_battery_remove(struct power_supply *battery) +static int asus_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold); diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index 5873c2663a65..415ccb3a95de 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -468,7 +468,7 @@ static DEVICE_ATTR_RW(charge_control_start_threshold); static DEVICE_ATTR_RW(charge_control_end_threshold); static DEVICE_ATTR_RW(charge_control_thresholds); -static int huawei_wmi_battery_add(struct power_supply *battery) +static int huawei_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { int err = 0; @@ -483,7 +483,7 @@ static int huawei_wmi_battery_add(struct power_supply *battery) return err; } -static int huawei_wmi_battery_remove(struct power_supply *battery) +static int huawei_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold); device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold); diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index 332868b140ed..d662b64b0ba9 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -546,7 +546,7 @@ static DEVICE_ATTR_RW(fn_lock); static DEVICE_ATTR_RW(charge_control_end_threshold); static DEVICE_ATTR_RW(battery_care_limit); -static int lg_battery_add(struct power_supply *battery) +static int lg_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { if (device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold)) @@ -555,7 +555,7 @@ static int lg_battery_add(struct power_supply *battery) return 0; } -static int lg_battery_remove(struct power_supply *battery) +static int lg_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold); diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index 958df41ad509..9031bd53253f 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -254,7 +254,7 @@ static struct attribute *system76_battery_attrs[] = { ATTRIBUTE_GROUPS(system76_battery); -static int system76_battery_add(struct power_supply *battery) +static int system76_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { // System76 EC only supports 1 battery if (strcmp(battery->desc->name, "BAT0") != 0) @@ -266,7 +266,7 @@ static int system76_battery_add(struct power_supply *battery) return 0; } -static int system76_battery_remove(struct power_supply *battery) +static int system76_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_groups(&battery->dev, system76_battery_groups); return 0; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 8476dfef4e62..4b12808bddab 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9907,7 +9907,7 @@ ATTRIBUTE_GROUPS(tpacpi_battery); /* ACPI battery hooking */ -static int tpacpi_battery_add(struct power_supply *battery) +static int tpacpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { int batteryid = tpacpi_battery_get_id(battery->desc->name); @@ -9918,7 +9918,7 @@ static int tpacpi_battery_add(struct power_supply *battery) return 0; } -static int tpacpi_battery_remove(struct power_supply *battery) +static int tpacpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_groups(&battery->dev, tpacpi_battery_groups); return 0; diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 160abd3b3af8..13628d41799a 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -3113,7 +3113,7 @@ static struct attribute *toshiba_acpi_battery_attrs[] = { ATTRIBUTE_GROUPS(toshiba_acpi_battery); -static int toshiba_acpi_battery_add(struct power_supply *battery) +static int toshiba_acpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { if (toshiba_acpi == NULL) { pr_err("Init order issue\n"); @@ -3126,7 +3126,7 @@ static int toshiba_acpi_battery_add(struct power_supply *battery) return 0; } -static int toshiba_acpi_battery_remove(struct power_supply *battery) +static int toshiba_acpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_groups(&battery->dev, toshiba_acpi_battery_groups); return 0; -- cgit v1.2.3 From a77272c16041862c5c8d450c8701139887e1bb05 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 27 Sep 2022 22:45:21 +0200 Subject: platform/x86: dell: Add new dell-wmi-ddv driver The dell-wmi-ddv driver adds support for reading the current temperature and ePPID of ACPI batteries on supported Dell machines. Since the WMI interface used by this driver does not do any input validation and thus cannot be used for probing, the driver depends on the ACPI battery extension machanism to discover batteries. The driver also supports a debugfs interface for retrieving buffers containing fan and thermal sensor information. Since the meaing of the content of those buffers is currently unknown, the interface is meant for reverse-engineering and will likely be replaced with an hwmon interface once the meaning has been understood. The driver was tested on a Dell Inspiron 3505. Signed-off-by: Armin Wolf Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220927204521.601887-3-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/Kconfig | 13 ++ drivers/platform/x86/dell/Makefile | 1 + drivers/platform/x86/dell/dell-wmi-ddv.c | 364 +++++++++++++++++++++++++++++++ drivers/platform/x86/wmi.c | 1 + 4 files changed, 379 insertions(+) create mode 100644 drivers/platform/x86/dell/dell-wmi-ddv.c (limited to 'drivers') diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index 25421e061c47..d319de8f2132 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -189,6 +189,19 @@ config DELL_WMI_DESCRIPTOR default n depends on ACPI_WMI +config DELL_WMI_DDV + tristate "Dell WMI sensors Support" + default m + depends on ACPI_BATTERY + depends on ACPI_WMI + help + This option adds support for WMI-based sensors like + battery temperature sensors found on some Dell notebooks. + It also supports reading of the battery ePPID. + + To compile this drivers as a module, choose M here: the module will + be called dell-wmi-ddv. + config DELL_WMI_LED tristate "External LED on Dell Business Netbooks" default m diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile index ddba1df71e80..1b8942426622 100644 --- a/drivers/platform/x86/dell/Makefile +++ b/drivers/platform/x86/dell/Makefile @@ -19,5 +19,6 @@ dell-wmi-objs := dell-wmi-base.o dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o +obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/ diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c new file mode 100644 index 000000000000..699feae3c435 --- /dev/null +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Linux driver for WMI sensor information on Dell notebooks. + * + * Copyright (C) 2022 Armin Wolf + */ + +#define pr_format(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "dell-wmi-ddv" + +#define DELL_DDV_SUPPORTED_INTERFACE 2 +#define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608" + +enum dell_ddv_method { + DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01, + DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02, + DELL_DDV_BATTERY_MANUFACTURE_NAME = 0x03, + DELL_DDV_BATTERY_MANUFACTURE_DATE = 0x04, + DELL_DDV_BATTERY_SERIAL_NUMBER = 0x05, + DELL_DDV_BATTERY_CHEMISTRY_VALUE = 0x06, + DELL_DDV_BATTERY_TEMPERATURE = 0x07, + DELL_DDV_BATTERY_CURRENT = 0x08, + DELL_DDV_BATTERY_VOLTAGE = 0x09, + DELL_DDV_BATTERY_MANUFACTURER_ACCESS = 0x0A, + DELL_DDV_BATTERY_RELATIVE_CHARGE_STATE = 0x0B, + DELL_DDV_BATTERY_CYCLE_COUNT = 0x0C, + DELL_DDV_BATTERY_EPPID = 0x0D, + DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E, + DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F, + DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10, + + DELL_DDV_INTERFACE_VERSION = 0x12, + + DELL_DDV_FAN_SENSOR_INFORMATION = 0x20, + DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22, +}; + +struct dell_wmi_ddv_data { + struct acpi_battery_hook hook; + struct device_attribute temp_attr; + struct device_attribute eppid_attr; + struct wmi_device *wdev; +}; + +static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg, + union acpi_object **result, acpi_object_type type) +{ + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + const struct acpi_buffer in = { + .length = sizeof(arg), + .pointer = &arg, + }; + union acpi_object *obj; + acpi_status ret; + + ret = wmidev_evaluate_method(wdev, 0x0, method, &in, &out); + if (ACPI_FAILURE(ret)) + return -EIO; + + obj = out.pointer; + if (!obj) + return -ENODATA; + + if (obj->type != type) { + kfree(obj); + return -EIO; + } + + *result = obj; + + return 0; +} + +static int dell_wmi_ddv_query_integer(struct wmi_device *wdev, enum dell_ddv_method method, + u32 arg, u32 *res) +{ + union acpi_object *obj; + int ret; + + ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_INTEGER); + if (ret < 0) + return ret; + + if (obj->integer.value <= U32_MAX) + *res = (u32)obj->integer.value; + else + ret = -ERANGE; + + kfree(obj); + + return ret; +} + +static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_method method, + u32 arg, union acpi_object **result) +{ + union acpi_object *obj; + u64 buffer_size; + int ret; + + ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_PACKAGE); + if (ret < 0) + return ret; + + if (obj->package.count != 2) + goto err_free; + + if (obj->package.elements[0].type != ACPI_TYPE_INTEGER) + goto err_free; + + buffer_size = obj->package.elements[0].integer.value; + + if (obj->package.elements[1].type != ACPI_TYPE_BUFFER) + goto err_free; + + if (buffer_size != obj->package.elements[1].buffer.length) { + dev_warn(&wdev->dev, + FW_WARN "ACPI buffer size (%llu) does not match WMI buffer size (%d)\n", + buffer_size, obj->package.elements[1].buffer.length); + + goto err_free; + } + + *result = obj; + + return 0; + +err_free: + kfree(obj); + + return -EIO; +} + +static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method, + u32 arg, union acpi_object **result) +{ + return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING); +} + +static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index) +{ + const char *uid_str; + + uid_str = acpi_device_uid(acpi_dev); + if (!uid_str) + return -ENODEV; + + return kstrtou32(uid_str, 10, index); +} + +static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr); + u32 index, value; + int ret; + + ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index); + if (ret < 0) + return ret; + + ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", DIV_ROUND_CLOSEST(value, 10)); +} + +static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr); + union acpi_object *obj; + u32 index; + int ret; + + ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index); + if (ret < 0) + return ret; + + ret = dell_wmi_ddv_query_string(data->wdev, DELL_DDV_BATTERY_EPPID, index, &obj); + if (ret < 0) + return ret; + + ret = sysfs_emit(buf, "%s\n", obj->string.pointer); + + kfree(obj); + + return ret; +} + +static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); + u32 index; + int ret; + + /* Return 0 instead of error to avoid being unloaded */ + ret = dell_wmi_ddv_battery_index(to_acpi_device(battery->dev.parent), &index); + if (ret < 0) + return 0; + + ret = device_create_file(&battery->dev, &data->temp_attr); + if (ret < 0) + return ret; + + ret = device_create_file(&battery->dev, &data->eppid_attr); + if (ret < 0) { + device_remove_file(&battery->dev, &data->temp_attr); + + return ret; + } + + return 0; +} + +static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); + + device_remove_file(&battery->dev, &data->temp_attr); + device_remove_file(&battery->dev, &data->eppid_attr); + + return 0; +} + +static void dell_wmi_ddv_battery_remove(void *data) +{ + struct acpi_battery_hook *hook = data; + + battery_hook_unregister(hook); +} + +static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) +{ + data->hook.name = "Dell DDV Battery Extension"; + data->hook.add_battery = dell_wmi_ddv_add_battery; + data->hook.remove_battery = dell_wmi_ddv_remove_battery; + + sysfs_attr_init(&data->temp_attr.attr); + data->temp_attr.attr.name = "temp"; + data->temp_attr.attr.mode = 0444; + data->temp_attr.show = temp_show; + + sysfs_attr_init(&data->eppid_attr.attr); + data->eppid_attr.attr.name = "eppid"; + data->eppid_attr.attr.mode = 0444; + data->eppid_attr.show = eppid_show; + + battery_hook_register(&data->hook); + + return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook); +} + +static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method) +{ + struct device *dev = seq->private; + struct dell_wmi_ddv_data *data = dev_get_drvdata(dev); + union acpi_object *obj; + union acpi_object buf; + int ret; + + ret = dell_wmi_ddv_query_buffer(data->wdev, method, 0, &obj); + if (ret < 0) + return ret; + + buf = obj->package.elements[1]; + ret = seq_write(seq, buf.buffer.pointer, buf.buffer.length); + kfree(obj); + + return ret; +} + +static int dell_wmi_ddv_fan_read(struct seq_file *seq, void *offset) +{ + return dell_wmi_ddv_buffer_read(seq, DELL_DDV_FAN_SENSOR_INFORMATION); +} + +static int dell_wmi_ddv_temp_read(struct seq_file *seq, void *offset) +{ + return dell_wmi_ddv_buffer_read(seq, DELL_DDV_THERMAL_SENSOR_INFORMATION); +} + +static void dell_wmi_ddv_debugfs_remove(void *data) +{ + struct dentry *entry = data; + + debugfs_remove(entry); +} + +static void dell_wmi_ddv_debugfs_init(struct wmi_device *wdev) +{ + struct dentry *entry; + char name[64]; + + scnprintf(name, ARRAY_SIZE(name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev)); + entry = debugfs_create_dir(name, NULL); + + debugfs_create_devm_seqfile(&wdev->dev, "fan_sensor_information", entry, + dell_wmi_ddv_fan_read); + debugfs_create_devm_seqfile(&wdev->dev, "thermal_sensor_information", entry, + dell_wmi_ddv_temp_read); + + devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_debugfs_remove, entry); +} + +static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context) +{ + struct dell_wmi_ddv_data *data; + u32 version; + int ret; + + ret = dell_wmi_ddv_query_integer(wdev, DELL_DDV_INTERFACE_VERSION, 0, &version); + if (ret < 0) + return ret; + + dev_dbg(&wdev->dev, "WMI interface version: %d\n", version); + if (version != DELL_DDV_SUPPORTED_INTERFACE) + return -ENODEV; + + data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + dev_set_drvdata(&wdev->dev, data); + data->wdev = wdev; + + dell_wmi_ddv_debugfs_init(wdev); + + return dell_wmi_ddv_battery_add(data); +} + +static const struct wmi_device_id dell_wmi_ddv_id_table[] = { + { DELL_DDV_GUID, NULL }, + { } +}; +MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table); + +static struct wmi_driver dell_wmi_ddv_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .id_table = dell_wmi_ddv_id_table, + .probe = dell_wmi_ddv_probe, +}; +module_wmi_driver(dell_wmi_ddv_driver); + +MODULE_AUTHOR("Armin Wolf "); +MODULE_DESCRIPTION("Dell WMI sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 223550a10d4d..5ffc00480aef 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(acpi, wmi_device_ids); /* allow duplicate GUIDs as these device drivers use struct wmi_driver */ static const char * const allow_duplicates[] = { "05901221-D566-11D1-B2F0-00A0C9062910", /* wmi-bmof */ + "8A42EA14-4F2A-FD45-6422-0087F7A7E608", /* dell-wmi-ddv */ NULL }; -- cgit v1.2.3 From d6fef93258f3b902f5166297b05d72746e16e1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Wed, 5 Oct 2022 15:00:39 +0000 Subject: platform/x86: huawei-wmi: do not hard-code sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use `sizeof()` and `ARRAY_SIZE()` instead of hard-coding buffer sizes and indices. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20221005150032.173198-1-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/huawei-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index 415ccb3a95de..2b48e86448b3 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -323,12 +323,12 @@ static int huawei_wmi_battery_get(int *start, int *end) u8 ret[0x100]; int err, i; - err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, 0x100); + err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, sizeof(ret)); if (err) return err; /* Find the last two non-zero values. Return status is ignored. */ - i = 0xff; + i = ARRAY_SIZE(ret) - 1; do { if (start) *start = ret[i-1]; -- cgit v1.2.3 From 0b9a1dcdb6a2c841899389bf2dd7a3e0e2aa0e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Wed, 5 Oct 2022 15:00:45 +0000 Subject: platform/x86: huawei-wmi: fix return value calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, `huawei_wmi_input_setup()` returned the result of logical or-ing the return values of two functions that return negative errno-style error codes and one that returns `acpi_status`. If this returned value was non-zero, then it was propagated from the platform driver's probe function. That function should return a negative errno-style error code, so the result of the logical or that `huawei_wmi_input_setup()` returned was not appropriate. Fix that by checking each function separately and returning the error code unmodified. Fixes: 1ac9abeb2e5b ("platform/x86: huawei-wmi: Move to platform driver") Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20221005150032.173198-2-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/huawei-wmi.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index 2b48e86448b3..981420f7f5d7 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -760,6 +760,9 @@ static int huawei_wmi_input_setup(struct device *dev, const char *guid, struct input_dev **idev) { + acpi_status status; + int err; + *idev = devm_input_allocate_device(dev); if (!*idev) return -ENOMEM; @@ -769,10 +772,19 @@ static int huawei_wmi_input_setup(struct device *dev, (*idev)->id.bustype = BUS_HOST; (*idev)->dev.parent = dev; - return sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL) || - input_register_device(*idev) || - wmi_install_notify_handler(guid, huawei_wmi_input_notify, - *idev); + err = sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL); + if (err) + return err; + + err = input_register_device(*idev); + if (err) + return err; + + status = wmi_install_notify_handler(guid, huawei_wmi_input_notify, *idev); + if (ACPI_FAILURE(status)) + return -EIO; + + return 0; } static void huawei_wmi_input_exit(struct device *dev, const char *guid) -- cgit v1.2.3 From e57d58ee1868b1ad3e8040335a2941506feb52e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Wed, 5 Oct 2022 15:00:51 +0000 Subject: platform/x86: huawei-wmi: remove unnecessary member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `huawei_wmi::idev` array is not actually used by the driver, so remove it. The piece of code that - I believe - was supposed to fill the array is flawed, it did not actually set any of the values inside the array. This was most likely masked by the fact that the input devices are devm managed and that the only function that needs a reference to the input devices is `huawei_wmi_input_notify()`, however, that does not access the appropriate input device via the `huawei_wmi` object. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20221005150032.173198-3-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/huawei-wmi.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index 981420f7f5d7..2df1b2d5e3ea 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -63,7 +63,6 @@ struct huawei_wmi { bool fn_lock_available; struct huawei_wmi_debug debug; - struct input_dev *idev[2]; struct led_classdev cdev; struct device *dev; @@ -756,31 +755,30 @@ static void huawei_wmi_input_notify(u32 value, void *context) kfree(response.pointer); } -static int huawei_wmi_input_setup(struct device *dev, - const char *guid, - struct input_dev **idev) +static int huawei_wmi_input_setup(struct device *dev, const char *guid) { + struct input_dev *idev; acpi_status status; int err; - *idev = devm_input_allocate_device(dev); - if (!*idev) + idev = devm_input_allocate_device(dev); + if (!idev) return -ENOMEM; - (*idev)->name = "Huawei WMI hotkeys"; - (*idev)->phys = "wmi/input0"; - (*idev)->id.bustype = BUS_HOST; - (*idev)->dev.parent = dev; + idev->name = "Huawei WMI hotkeys"; + idev->phys = "wmi/input0"; + idev->id.bustype = BUS_HOST; + idev->dev.parent = dev; - err = sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL); + err = sparse_keymap_setup(idev, huawei_wmi_keymap, NULL); if (err) return err; - err = input_register_device(*idev); + err = input_register_device(idev); if (err) return err; - status = wmi_install_notify_handler(guid, huawei_wmi_input_notify, *idev); + status = wmi_install_notify_handler(guid, huawei_wmi_input_notify, idev); if (ACPI_FAILURE(status)) return -EIO; @@ -809,17 +807,14 @@ static int huawei_wmi_probe(struct platform_device *pdev) huawei_wmi->dev = &pdev->dev; while (*guid->guid_string) { - struct input_dev *idev = *huawei_wmi->idev; - if (wmi_has_guid(guid->guid_string)) { - err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string, &idev); + err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string); if (err) { dev_err(&pdev->dev, "Failed to setup input on %s\n", guid->guid_string); return err; } } - idev++; guid++; } -- cgit v1.2.3 From db5e2a4ca0a7a5fe54f410590292ea2e91de6798 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Nov 2022 13:43:22 +0100 Subject: platform/x86: thinkpad_acpi: Fix max_brightness of thinklight MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thinklight has only two values, on/off so it's reasonable for max_brightness to be 0 and 1 as if you write anything between 0 and 255 it will be 255 anyway so there's no point for it to be 255. This may look like it is a userspace API change, but writes with a value larget then the new max_brightness will still be accepted, these will be silently clamped to the new max_brightness by led_set_brightness_nosleep(). So no userspace API problems are expected. Reported-by: Michał Szczepaniak Link: https://lore.kernel.org/platform-driver-x86/55400326-e64f-5444-94e5-22b8214d00b6@gmail.com/ Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 4b12808bddab..cfeed1c45b54 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5572,6 +5572,7 @@ static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) static struct tpacpi_led_classdev tpacpi_led_thinklight = { .led_classdev = { .name = "tpacpi::thinklight", + .max_brightness = 1, .brightness_set_blocking = &light_sysfs_set, .brightness_get = &light_sysfs_get, } -- cgit v1.2.3 From bc05ea63b39420fd561dcffba00753da90338ea8 Mon Sep 17 00:00:00 2001 From: Liming Sun Date: Tue, 18 Oct 2022 09:33:03 -0400 Subject: platform/mellanox: Add BlueField-3 support in the tmfifo driver BlueField-3 uses the same control registers in tmfifo access but at different addresses. This commit replaces the offset reference with pointers, and set up these pointers in the probe functions accordingly. Signed-off-by: Liming Sun Reviewed-by: David Thompson Reviewed-by: Vadim Pasternak Link: https://lore.kernel.org/r/20221018133303.243920-1-limings@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxbf-tmfifo-regs.h | 10 ++++ drivers/platform/mellanox/mlxbf-tmfifo.c | 86 ++++++++++++++++++++------- 2 files changed, 74 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/mellanox/mlxbf-tmfifo-regs.h b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h index e4f0d2eda714..44fb8c5b1484 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo-regs.h +++ b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h @@ -60,4 +60,14 @@ #define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0) #define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32) +/* BF3 register offsets within resource 0. */ +#define MLXBF_TMFIFO_RX_DATA_BF3 0x0000 +#define MLXBF_TMFIFO_TX_DATA_BF3 0x1000 + +/* BF3 register offsets within resource 1. */ +#define MLXBF_TMFIFO_RX_STS_BF3 0x0000 +#define MLXBF_TMFIFO_RX_CTL_BF3 0x0008 +#define MLXBF_TMFIFO_TX_STS_BF3 0x0100 +#define MLXBF_TMFIFO_TX_CTL_BF3 0x0108 + #endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */ diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index 1ae3c56b66b0..91a077c35b8b 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -47,6 +47,9 @@ /* Message with data needs at least two words (for header & data). */ #define MLXBF_TMFIFO_DATA_MIN_WORDS 2 +/* ACPI UID for BlueField-3. */ +#define TMFIFO_BF3_UID 1 + struct mlxbf_tmfifo; /** @@ -136,12 +139,26 @@ struct mlxbf_tmfifo_irq_info { int index; }; +/** + * mlxbf_tmfifo_io - Structure of the TmFifo IO resource (for both rx & tx) + * @ctl: control register offset (TMFIFO_RX_CTL / TMFIFO_TX_CTL) + * @sts: status register offset (TMFIFO_RX_STS / TMFIFO_TX_STS) + * @data: data register offset (TMFIFO_RX_DATA / TMFIFO_TX_DATA) + */ +struct mlxbf_tmfifo_io { + void __iomem *ctl; + void __iomem *sts; + void __iomem *data; +}; + /** * mlxbf_tmfifo - Structure of the TmFifo * @vdev: array of the virtual devices running over the TmFifo * @lock: lock to protect the TmFifo access - * @rx_base: mapped register base address for the Rx FIFO - * @tx_base: mapped register base address for the Tx FIFO + * @res0: mapped resource block 0 + * @res1: mapped resource block 1 + * @rx: rx io resource + * @tx: tx io resource * @rx_fifo_size: number of entries of the Rx FIFO * @tx_fifo_size: number of entries of the Tx FIFO * @pend_events: pending bits for deferred events @@ -155,8 +172,10 @@ struct mlxbf_tmfifo_irq_info { struct mlxbf_tmfifo { struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX]; struct mutex lock; /* TmFifo lock */ - void __iomem *rx_base; - void __iomem *tx_base; + void __iomem *res0; + void __iomem *res1; + struct mlxbf_tmfifo_io rx; + struct mlxbf_tmfifo_io tx; int rx_fifo_size; int tx_fifo_size; unsigned long pend_events; @@ -472,7 +491,7 @@ static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo) { u64 sts; - sts = readq(fifo->rx_base + MLXBF_TMFIFO_RX_STS); + sts = readq(fifo->rx.sts); return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts); } @@ -489,7 +508,7 @@ static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id) else tx_reserve = 1; - sts = readq(fifo->tx_base + MLXBF_TMFIFO_TX_STS); + sts = readq(fifo->tx.sts); count = FIELD_GET(MLXBF_TMFIFO_TX_STS__COUNT_MASK, sts); return fifo->tx_fifo_size - tx_reserve - count; } @@ -525,7 +544,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail) /* Write header. */ hdr.type = VIRTIO_ID_CONSOLE; hdr.len = htons(size); - writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); + writeq(*(u64 *)&hdr, fifo->tx.data); /* Use spin-lock to protect the 'cons->tx_buf'. */ spin_lock_irqsave(&fifo->spin_lock[0], flags); @@ -542,7 +561,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail) memcpy((u8 *)&data + seg, cons->tx_buf.buf, sizeof(u64) - seg); } - writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); + writeq(data, fifo->tx.data); if (size >= sizeof(u64)) { cons->tx_buf.tail = (cons->tx_buf.tail + sizeof(u64)) % @@ -573,7 +592,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring, /* Read a word from FIFO for Rx. */ if (is_rx) - data = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA); + data = readq(fifo->rx.data); if (vring->cur_len + sizeof(u64) <= len) { /* The whole word. */ @@ -595,7 +614,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring, /* Write the word into FIFO for Tx. */ if (!is_rx) - writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); + writeq(data, fifo->tx.data); } /* @@ -617,7 +636,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, /* Read/Write packet header. */ if (is_rx) { /* Drain one word from the FIFO. */ - *(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA); + *(u64 *)&hdr = readq(fifo->rx.data); /* Skip the length 0 packets (keepalive). */ if (hdr.len == 0) @@ -661,7 +680,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ? VIRTIO_ID_NET : VIRTIO_ID_CONSOLE; hdr.len = htons(vring->pkt_len - hdr_len); - writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); + writeq(*(u64 *)&hdr, fifo->tx.data); } vring->cur_len = hdr_len; @@ -1157,7 +1176,7 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo) u64 ctl; /* Get Tx FIFO size and set the low/high watermark. */ - ctl = readq(fifo->tx_base + MLXBF_TMFIFO_TX_CTL); + ctl = readq(fifo->tx.ctl); fifo->tx_fifo_size = FIELD_GET(MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK, ctl); ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__LWM_MASK) | @@ -1166,17 +1185,17 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo) ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__HWM_MASK) | FIELD_PREP(MLXBF_TMFIFO_TX_CTL__HWM_MASK, fifo->tx_fifo_size - 1); - writeq(ctl, fifo->tx_base + MLXBF_TMFIFO_TX_CTL); + writeq(ctl, fifo->tx.ctl); /* Get Rx FIFO size and set the low/high watermark. */ - ctl = readq(fifo->rx_base + MLXBF_TMFIFO_RX_CTL); + ctl = readq(fifo->rx.ctl); fifo->rx_fifo_size = FIELD_GET(MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK, ctl); ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__LWM_MASK) | FIELD_PREP(MLXBF_TMFIFO_RX_CTL__LWM_MASK, 0); ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__HWM_MASK) | FIELD_PREP(MLXBF_TMFIFO_RX_CTL__HWM_MASK, 1); - writeq(ctl, fifo->rx_base + MLXBF_TMFIFO_RX_CTL); + writeq(ctl, fifo->rx.ctl); } static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo) @@ -1197,8 +1216,15 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev) struct virtio_net_config net_config; struct device *dev = &pdev->dev; struct mlxbf_tmfifo *fifo; + u64 dev_id; int i, rc; + rc = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &dev_id); + if (rc) { + dev_err(dev, "Cannot retrieve UID\n"); + return rc; + } + fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL); if (!fifo) return -ENOMEM; @@ -1209,14 +1235,30 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev) mutex_init(&fifo->lock); /* Get the resource of the Rx FIFO. */ - fifo->rx_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(fifo->rx_base)) - return PTR_ERR(fifo->rx_base); + fifo->res0 = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(fifo->res0)) + return PTR_ERR(fifo->res0); /* Get the resource of the Tx FIFO. */ - fifo->tx_base = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(fifo->tx_base)) - return PTR_ERR(fifo->tx_base); + fifo->res1 = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(fifo->res1)) + return PTR_ERR(fifo->res1); + + if (dev_id == TMFIFO_BF3_UID) { + fifo->rx.ctl = fifo->res1 + MLXBF_TMFIFO_RX_CTL_BF3; + fifo->rx.sts = fifo->res1 + MLXBF_TMFIFO_RX_STS_BF3; + fifo->rx.data = fifo->res0 + MLXBF_TMFIFO_RX_DATA_BF3; + fifo->tx.ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL_BF3; + fifo->tx.sts = fifo->res1 + MLXBF_TMFIFO_TX_STS_BF3; + fifo->tx.data = fifo->res0 + MLXBF_TMFIFO_TX_DATA_BF3; + } else { + fifo->rx.ctl = fifo->res0 + MLXBF_TMFIFO_RX_CTL; + fifo->rx.sts = fifo->res0 + MLXBF_TMFIFO_RX_STS; + fifo->rx.data = fifo->res0 + MLXBF_TMFIFO_RX_DATA; + fifo->tx.ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL; + fifo->tx.sts = fifo->res1 + MLXBF_TMFIFO_TX_STS; + fifo->tx.data = fifo->res1 + MLXBF_TMFIFO_TX_DATA; + } platform_set_drvdata(pdev, fifo); -- cgit v1.2.3 From 26174aaee3832d681dcc0744b005021c7480a8f6 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Wed, 19 Oct 2022 20:53:55 +0800 Subject: platform/x86/intel: pmc: Fix repeated word in comment Delete the redundant word 'to'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20221019125355.50674-1-yuanjilin@cdjrlc.com Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/pmc/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h index 7a059e02c265..4c7e77f1ccac 100644 --- a/drivers/platform/x86/intel/pmc/core.h +++ b/drivers/platform/x86/intel/pmc/core.h @@ -264,7 +264,7 @@ struct pmc_bit_map { * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit * @regmap_length: Length of memory to map from PWRMBASE address to access - * @ppfear0_offset: PWRMBASE offset to to read PPFEAR* + * @ppfear0_offset: PWRMBASE offset to read PPFEAR* * @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from * PPFEAR * @pm_cfg_offset: PWRMBASE offset to PM_CFG register -- cgit v1.2.3 From 6e9b8992b122cb12688bd259fc99e67d1be234eb Mon Sep 17 00:00:00 2001 From: Jorge Lopez Date: Thu, 20 Oct 2022 15:10:28 -0500 Subject: platform/x86: Move existing HP drivers to a new hp subdir The purpose of this patch is to provide a central location where all HP related drivers are found. HP drivers will recide under drivers/platform/x86/hp directory. Introduce changes to Kconfig file to list all HP driver under "HP X86 Platform Specific Device Drivers" menu option. Additional changes include update MAINTAINERS file to indicate hp related drivers new path. Signed-off-by: Jorge Lopez Link: https://lore.kernel.org/r/20221020201033.12790-2-jorge.lopez2@hp.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 43 +- drivers/platform/x86/Makefile | 4 +- drivers/platform/x86/hp-wmi.c | 1566 ---------------------------------- drivers/platform/x86/hp/Kconfig | 63 ++ drivers/platform/x86/hp/Makefile | 10 + drivers/platform/x86/hp/hp-wmi.c | 1566 ++++++++++++++++++++++++++++++++++ drivers/platform/x86/hp/hp_accel.c | 387 +++++++++ drivers/platform/x86/hp/tc1100-wmi.c | 265 ++++++ drivers/platform/x86/hp_accel.c | 387 --------- drivers/platform/x86/tc1100-wmi.c | 265 ------ 10 files changed, 2293 insertions(+), 2263 deletions(-) delete mode 100644 drivers/platform/x86/hp-wmi.c create mode 100644 drivers/platform/x86/hp/Kconfig create mode 100644 drivers/platform/x86/hp/Makefile create mode 100644 drivers/platform/x86/hp/hp-wmi.c create mode 100644 drivers/platform/x86/hp/hp_accel.c create mode 100644 drivers/platform/x86/hp/tc1100-wmi.c delete mode 100644 drivers/platform/x86/hp_accel.c delete mode 100644 drivers/platform/x86/tc1100-wmi.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f5312f51de19..5692385e2d26 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -424,24 +424,7 @@ config GPD_POCKET_FAN of the CPU temperature. Say Y or M if the kernel may be used on a GPD pocket. -config HP_ACCEL - tristate "HP laptop accelerometer" - depends on INPUT && ACPI - depends on SERIO_I8042 - select SENSORS_LIS3LV02D - select NEW_LEDS - select LEDS_CLASS - help - This driver provides support for the "Mobile Data Protection System 3D" - or "3D DriveGuard" feature of HP laptops. On such systems the driver - should load automatically (via ACPI alias). - - Support for a led indicating disk protection will be provided as - hp::hddprotect. For more information on the feature, refer to - Documentation/misc-devices/lis3lv02d.rst. - - To compile this driver as a module, choose M here: the module will - be called hp_accel. +source "drivers/platform/x86/hp/Kconfig" config WIRELESS_HOTKEY tristate "Wireless hotkey button" @@ -455,30 +438,6 @@ config WIRELESS_HOTKEY To compile this driver as a module, choose M here: the module will be called wireless-hotkey. -config HP_WMI - tristate "HP WMI extras" - depends on ACPI_WMI - depends on INPUT - depends on RFKILL || RFKILL = n - select INPUT_SPARSEKMAP - select ACPI_PLATFORM_PROFILE - select HWMON - help - Say Y here if you want to support WMI-based hotkeys on HP laptops and - to read data from WMI such as docking or ambient light sensor state. - - To compile this driver as a module, choose M here: the module will - be called hp-wmi. - -config TC1100_WMI - tristate "HP Compaq TC1100 Tablet WMI Extras" - depends on !X86_64 - depends on ACPI - depends on ACPI_WMI - help - This is a driver for the WMI extensions (wireless and bluetooth power - control) of the HP Compaq TC1100 tablet. - config IBM_RTL tristate "Device driver to enable PRTL support" depends on PCI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 5a428caa654a..1d3d1b02541b 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -55,9 +55,7 @@ obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o # Hewlett Packard -obj-$(CONFIG_HP_ACCEL) += hp_accel.o -obj-$(CONFIG_HP_WMI) += hp-wmi.o -obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o +obj-$(CONFIG_X86_PLATFORM_DRIVERS_HP) += hp/ # Hewlett Packard Enterprise obj-$(CONFIG_UV_SYSFS) += uv_sysfs.o diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c deleted file mode 100644 index 0a99058be813..000000000000 --- a/drivers/platform/x86/hp-wmi.c +++ /dev/null @@ -1,1566 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * HP WMI hotkeys - * - * Copyright (C) 2008 Red Hat - * Copyright (C) 2010, 2011 Anssi Hannula - * - * Portions based on wistron_btns.c: - * Copyright (C) 2005 Miloslav Trmac - * Copyright (C) 2005 Bernhard Rosenkraenzer - * Copyright (C) 2005 Dmitry Torokhov - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Matthew Garrett "); -MODULE_DESCRIPTION("HP laptop WMI hotkeys driver"); -MODULE_LICENSE("GPL"); - -MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C"); -MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); - -#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" -#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4" -#define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95 -#define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required - -/* DMI board names of devices that should use the omen specific path for - * thermal profiles. - * This was obtained by taking a look in the windows omen command center - * app and parsing a json file that they use to figure out what capabilities - * the device should have. - * A device is considered an omen if the DisplayName in that list contains - * "OMEN", and it can use the thermal profile stuff if the "Feature" array - * contains "PerformanceControl". - */ -static const char * const omen_thermal_profile_boards[] = { - "84DA", "84DB", "84DC", "8574", "8575", "860A", "87B5", "8572", "8573", - "8600", "8601", "8602", "8605", "8606", "8607", "8746", "8747", "8749", - "874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C", - "88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD", - "88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912", - "8917", "8918", "8949", "894A", "89EB" -}; - -/* DMI Board names of Omen laptops that are specifically set to be thermal - * profile version 0 by the Omen Command Center app, regardless of what - * the get system design information WMI call returns - */ -static const char *const omen_thermal_profile_force_v0_boards[] = { - "8607", "8746", "8747", "8749", "874A", "8748" -}; - -enum hp_wmi_radio { - HPWMI_WIFI = 0x0, - HPWMI_BLUETOOTH = 0x1, - HPWMI_WWAN = 0x2, - HPWMI_GPS = 0x3, -}; - -enum hp_wmi_event_ids { - HPWMI_DOCK_EVENT = 0x01, - HPWMI_PARK_HDD = 0x02, - HPWMI_SMART_ADAPTER = 0x03, - HPWMI_BEZEL_BUTTON = 0x04, - HPWMI_WIRELESS = 0x05, - HPWMI_CPU_BATTERY_THROTTLE = 0x06, - HPWMI_LOCK_SWITCH = 0x07, - HPWMI_LID_SWITCH = 0x08, - HPWMI_SCREEN_ROTATION = 0x09, - HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A, - HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B, - HPWMI_PROXIMITY_SENSOR = 0x0C, - HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D, - HPWMI_PEAKSHIFT_PERIOD = 0x0F, - HPWMI_BATTERY_CHARGE_PERIOD = 0x10, - HPWMI_SANITIZATION_MODE = 0x17, - HPWMI_SMART_EXPERIENCE_APP = 0x21, -}; - -/* - * 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[]; -}; - -enum hp_wmi_commandtype { - HPWMI_DISPLAY_QUERY = 0x01, - HPWMI_HDDTEMP_QUERY = 0x02, - HPWMI_ALS_QUERY = 0x03, - HPWMI_HARDWARE_QUERY = 0x04, - HPWMI_WIRELESS_QUERY = 0x05, - HPWMI_BATTERY_QUERY = 0x07, - HPWMI_BIOS_QUERY = 0x09, - HPWMI_FEATURE_QUERY = 0x0b, - HPWMI_HOTKEY_QUERY = 0x0c, - HPWMI_FEATURE2_QUERY = 0x0d, - HPWMI_WIRELESS2_QUERY = 0x1b, - HPWMI_POSTCODEERROR_QUERY = 0x2a, - HPWMI_SYSTEM_DEVICE_MODE = 0x40, - HPWMI_THERMAL_PROFILE_QUERY = 0x4c, -}; - -enum hp_wmi_gm_commandtype { - HPWMI_FAN_SPEED_GET_QUERY = 0x11, - HPWMI_SET_PERFORMANCE_MODE = 0x1A, - HPWMI_FAN_SPEED_MAX_GET_QUERY = 0x26, - HPWMI_FAN_SPEED_MAX_SET_QUERY = 0x27, - HPWMI_GET_SYSTEM_DESIGN_DATA = 0x28, -}; - -enum hp_wmi_command { - HPWMI_READ = 0x01, - HPWMI_WRITE = 0x02, - HPWMI_ODM = 0x03, - HPWMI_GM = 0x20008, -}; - -enum hp_wmi_hardware_mask { - HPWMI_DOCK_MASK = 0x01, - HPWMI_TABLET_MASK = 0x04, -}; - -struct bios_return { - u32 sigpass; - u32 return_code; -}; - -enum hp_return_value { - HPWMI_RET_WRONG_SIGNATURE = 0x02, - HPWMI_RET_UNKNOWN_COMMAND = 0x03, - HPWMI_RET_UNKNOWN_CMDTYPE = 0x04, - HPWMI_RET_INVALID_PARAMETERS = 0x05, -}; - -enum hp_wireless2_bits { - HPWMI_POWER_STATE = 0x01, - HPWMI_POWER_SOFT = 0x02, - HPWMI_POWER_BIOS = 0x04, - HPWMI_POWER_HARD = 0x08, - HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, -}; - -enum hp_thermal_profile_omen_v0 { - HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00, - HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01, - HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02, -}; - -enum hp_thermal_profile_omen_v1 { - HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30, - HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31, - HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50, -}; - -enum hp_thermal_profile { - HP_THERMAL_PROFILE_PERFORMANCE = 0x00, - HP_THERMAL_PROFILE_DEFAULT = 0x01, - HP_THERMAL_PROFILE_COOL = 0x02, - HP_THERMAL_PROFILE_QUIET = 0x03, -}; - -#define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW) -#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) - -struct bios_rfkill2_device_state { - u8 radio_type; - u8 bus_type; - u16 vendor_id; - u16 product_id; - u16 subsys_vendor_id; - u16 subsys_product_id; - u8 rfkill_id; - u8 power; - u8 unknown[4]; -}; - -/* 7 devices fit into the 128 byte buffer */ -#define HPWMI_MAX_RFKILL2_DEVICES 7 - -struct bios_rfkill2_state { - u8 unknown[7]; - u8 count; - u8 pad[8]; - struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES]; -}; - -static const struct key_entry hp_wmi_keymap[] = { - { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, - { KE_KEY, 0x20e6, { KEY_PROG1 } }, - { KE_KEY, 0x20e8, { KEY_MEDIA } }, - { KE_KEY, 0x2142, { KEY_MEDIA } }, - { KE_KEY, 0x213b, { KEY_INFO } }, - { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } }, - { KE_KEY, 0x216a, { KEY_SETUP } }, - { KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } }, - { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } }, - { KE_KEY, 0x231b, { KEY_HELP } }, - { KE_END, 0 } -}; - -static struct input_dev *hp_wmi_input_dev; -static struct platform_device *hp_wmi_platform_dev; -static struct platform_profile_handler platform_profile_handler; -static bool platform_profile_support; -static bool zero_insize_support; - -static struct rfkill *wifi_rfkill; -static struct rfkill *bluetooth_rfkill; -static struct rfkill *wwan_rfkill; - -struct rfkill2_device { - u8 id; - int num; - struct rfkill *rfkill; -}; - -static int rfkill2_count; -static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; - -/* - * Chassis Types values were obtained from SMBIOS reference - * specification version 3.00. A complete list of system enclosures - * and chassis types is available on Table 17. - */ -static const char * const tablet_chassis_types[] = { - "30", /* Tablet*/ - "31", /* Convertible */ - "32" /* Detachable */ -}; - -#define DEVICE_MODE_TABLET 0x06 - -/* map output size to the corresponding WMI method id */ -static inline int encode_outsize_for_pvsz(int outsize) -{ - if (outsize > 4096) - return -EINVAL; - if (outsize > 1024) - return 5; - if (outsize > 128) - return 4; - if (outsize > 4) - return 3; - if (outsize > 0) - return 2; - return 1; -} - -/* - * hp_wmi_perform_query - * - * query: The commandtype (enum hp_wmi_commandtype) - * write: The command (enum hp_wmi_command) - * buffer: Buffer used as input and/or output - * insize: Size of input buffer - * outsize: Size of output buffer - * - * returns zero on success - * an HP WMI query specific error code (which is positive) - * -EINVAL if the query was not successful at all - * -EINVAL if the output buffer size exceeds buffersize - * - * Note: The buffersize must at least be the maximum of the input and output - * size. E.g. Battery info query is defined to have 1 byte input - * and 128 byte output. The caller would do: - * buffer = kzalloc(128, GFP_KERNEL); - * ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128) - */ -static int hp_wmi_perform_query(int query, enum hp_wmi_command command, - void *buffer, int insize, int outsize) -{ - struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct bios_return *bios_return; - union acpi_object *obj = NULL; - struct bios_args *args = NULL; - int mid, actual_insize, actual_outsize; - size_t bios_args_size; - int ret; - - mid = encode_outsize_for_pvsz(outsize); - if (WARN_ON(mid < 0)) - return mid; - - actual_insize = max(insize, 128); - bios_args_size = struct_size(args, data, actual_insize); - args = kmalloc(bios_args_size, GFP_KERNEL); - if (!args) - return -ENOMEM; - - 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; - 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; - } - - bios_return = (struct bios_return *)obj->buffer.pointer; - ret = bios_return->return_code; - - if (ret) { - if (ret != HPWMI_RET_UNKNOWN_COMMAND && - ret != HPWMI_RET_UNKNOWN_CMDTYPE) - pr_warn("query 0x%x returned error 0x%x\n", query, ret); - goto out_free; - } - - /* Ignore output data of zero size */ - if (!outsize) - goto out_free; - - actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); - memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); - memset(buffer + actual_outsize, 0, outsize - actual_outsize); - -out_free: - kfree(obj); - kfree(args); - return ret; -} - -static int hp_wmi_get_fan_speed(int fan) -{ - u8 fsh, fsl; - char fan_data[4] = { fan, 0, 0, 0 }; - - int ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_GET_QUERY, HPWMI_GM, - &fan_data, sizeof(char), - sizeof(fan_data)); - - if (ret != 0) - return -EINVAL; - - fsh = fan_data[2]; - fsl = fan_data[3]; - - return (fsh << 8) | fsl; -} - -static int hp_wmi_read_int(int query) -{ - int val = 0, ret; - - ret = hp_wmi_perform_query(query, HPWMI_READ, &val, - zero_if_sup(