···138138The output buffer contains a single byte which signals success or failure (``0x00`` on failure)139139and 31 bytes of output data, the meaning if which depends on the subfeature being accessed.140140141141+.. note::142142+ The ACPI control method responsible for handling the WMI method calls is not thread-safe.143143+ This is a firmware bug that needs to be handled inside the driver itself.144144+141145WMI method Get_EC()142146-------------------143147
···644644 struct smu_metrics table;645645 int rc;646646647647- /* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */648648- if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) &&649649- table.s0i3_last_entry_status)650650- usleep_range(10000, 20000);647647+ /* Avoid triggering OVP */648648+ if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status)649649+ msleep(2500);651650652651 /* Dump the IdleMask before we add to the STB */653652 amd_pmc_idlemask_read(pdev, pdev->dev, NULL);
···176176 dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value);177177}178178179179+/**180180+ * fixp_q88_fromint: Convert integer to Q8.8181181+ * @val: input value182182+ *183183+ * Converts an integer into binary fixed point format where 8 bits184184+ * are used for integer and 8 bits are used for the decimal.185185+ *186186+ * Return: unsigned integer converted to Q8.8 format187187+ */188188+u32 fixp_q88_fromint(u32 val)189189+{190190+ return val << 8;191191+}192192+179193int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data)180194{181195 int rc;
···426426427427static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)428428{429429+ unsigned long long val = (unsigned long long)curr;430430+ acpi_status status;429431 int i, delta;430430- unsigned long long val;431431- for (i = 0; i < PEGA_ACC_RETRIES; i++) {432432- acpi_evaluate_integer(asus->handle, method, NULL, &val);433432433433+ for (i = 0; i < PEGA_ACC_RETRIES; i++) {434434+ status = acpi_evaluate_integer(asus->handle, method, NULL, &val);435435+ if (ACPI_FAILURE(status))436436+ continue;434437 /* The output is noisy. From reading the ASL435438 * dissassembly, timeout errors are returned with 1's436439 * in the high word, and the lack of locking around
+12-2
drivers/platform/x86/asus-wmi.c
···305305306306 u32 kbd_rgb_dev;307307 bool kbd_rgb_state_available;308308+ bool oobe_state_available;308309309310 u8 throttle_thermal_policy_mode;310311 u32 throttle_thermal_policy_dev;···18691868 goto error;18701869 }1871187018721872- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE)) {18711871+ if (asus->oobe_state_available) {18731872 /*18741873 * Disable OOBE state, so that e.g. the keyboard backlight18751874 * works.···47814780 asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);47824781 asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);47834782 asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);47834783+ asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE);4784478447854785 if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))47864786 asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;···48344832 goto fail_leds;4835483348364834 asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result);48374837- if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))48354835+ if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) ==48364836+ (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))48384837 asus->driver->wlan_ctrl_by_user = 1;4839483848404839 if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) {···50004997 }50014998 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))50024999 kbd_led_update(asus);50005000+ if (asus->oobe_state_available) {50015001+ /*50025002+ * Disable OOBE state, so that e.g. the keyboard backlight50035003+ * works.50045004+ */50055005+ asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL);50065006+ }5003500750045008 if (asus_wmi_has_fnlock_key(asus))50055009 asus_wmi_fnlock_update(asus);
···146146{147147 struct uncore_data *data;148148 int target;149149+ int ret;149150150151 /* Check if there is an online cpu in the package for uncore MSR */151152 target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu));152153 if (target < nr_cpu_ids)153154 return 0;154154-155155- /* Use this CPU on this die as a control CPU */156156- cpumask_set_cpu(cpu, &uncore_cpu_mask);157155158156 data = uncore_get_instance(cpu);159157 if (!data)···161163 data->die_id = topology_die_id(cpu);162164 data->domain_id = UNCORE_DOMAIN_ID_INVALID;163165164164- return uncore_freq_add_entry(data, cpu);166166+ ret = uncore_freq_add_entry(data, cpu);167167+ if (ret)168168+ return ret;169169+170170+ /* Use this CPU on this die as a control CPU */171171+ cpumask_set_cpu(cpu, &uncore_cpu_mask);172172+173173+ return 0;165174}166175167176static int uncore_event_cpu_offline(unsigned int cpu)
+63-36
drivers/platform/x86/msi-wmi-platform.c
···1010#include <linux/acpi.h>1111#include <linux/bits.h>1212#include <linux/bitfield.h>1313+#include <linux/cleanup.h>1314#include <linux/debugfs.h>1415#include <linux/device.h>1516#include <linux/device/driver.h>···1817#include <linux/hwmon.h>1918#include <linux/kernel.h>2019#include <linux/module.h>2020+#include <linux/mutex.h>2121#include <linux/printk.h>2222#include <linux/rwsem.h>2323#include <linux/types.h>···7876 MSI_PLATFORM_GET_WMI = 0x1d,7977};80788181-struct msi_wmi_platform_debugfs_data {7979+struct msi_wmi_platform_data {8280 struct wmi_device *wdev;8181+ struct mutex wmi_lock; /* Necessary when calling WMI methods */8282+};8383+8484+struct msi_wmi_platform_debugfs_data {8585+ struct msi_wmi_platform_data *data;8386 enum msi_wmi_platform_method method;8487 struct rw_semaphore buffer_lock; /* Protects debugfs buffer */8588 size_t length;···139132 return 0;140133}141134142142-static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform_method method,143143- u8 *input, size_t input_length, u8 *output, size_t output_length)135135+static int msi_wmi_platform_query(struct msi_wmi_platform_data *data,136136+ enum msi_wmi_platform_method method, u8 *input,137137+ size_t input_length, u8 *output, size_t output_length)144138{145139 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };146140 struct acpi_buffer in = {···155147 if (!input_length || !output_length)156148 return -EINVAL;157149158158- status = wmidev_evaluate_method(wdev, 0x0, method, &in, &out);159159- if (ACPI_FAILURE(status))160160- return -EIO;150150+ /*151151+ * The ACPI control method responsible for handling the WMI method calls152152+ * is not thread-safe. Because of this we have to do the locking ourself.153153+ */154154+ scoped_guard(mutex, &data->wmi_lock) {155155+ status = wmidev_evaluate_method(data->wdev, 0x0, method, &in, &out);156156+ if (ACPI_FAILURE(status))157157+ return -EIO;158158+ }161159162160 obj = out.pointer;163161 if (!obj)···184170static int msi_wmi_platform_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,185171 int channel, long *val)186172{187187- struct wmi_device *wdev = dev_get_drvdata(dev);173173+ struct msi_wmi_platform_data *data = dev_get_drvdata(dev);188174 u8 input[32] = { 0 };189175 u8 output[32];190190- u16 data;176176+ u16 value;191177 int ret;192178193193- ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_FAN, input, sizeof(input), output,179179+ ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_FAN, input, sizeof(input), output,194180 sizeof(output));195181 if (ret < 0)196182 return ret;197183198198- data = get_unaligned_be16(&output[channel * 2 + 1]);199199- if (!data)184184+ value = get_unaligned_be16(&output[channel * 2 + 1]);185185+ if (!value)200186 *val = 0;201187 else202202- *val = 480000 / data;188188+ *val = 480000 / value;203189204190 return 0;205191}···245231 return ret;246232247233 down_write(&data->buffer_lock);248248- ret = msi_wmi_platform_query(data->wdev, data->method, payload, data->length, data->buffer,234234+ ret = msi_wmi_platform_query(data->data, data->method, payload, data->length, data->buffer,249235 data->length);250236 up_write(&data->buffer_lock);251237···291277 debugfs_remove_recursive(dir);292278}293279294294-static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry *dir,280280+static void msi_wmi_platform_debugfs_add(struct msi_wmi_platform_data *drvdata, struct dentry *dir,295281 const char *name, enum msi_wmi_platform_method method)296282{297283 struct msi_wmi_platform_debugfs_data *data;298284 struct dentry *entry;299285300300- data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);286286+ data = devm_kzalloc(&drvdata->wdev->dev, sizeof(*data), GFP_KERNEL);301287 if (!data)302288 return;303289304304- data->wdev = wdev;290290+ data->data = drvdata;305291 data->method = method;306292 init_rwsem(&data->buffer_lock);307293···312298313299 entry = debugfs_create_file(name, 0600, dir, data, &msi_wmi_platform_debugfs_fops);314300 if (IS_ERR(entry))315315- devm_kfree(&wdev->dev, data);301301+ devm_kfree(&drvdata->wdev->dev, data);316302}317303318318-static void msi_wmi_platform_debugfs_init(struct wmi_device *wdev)304304+static void msi_wmi_platform_debugfs_init(struct msi_wmi_platform_data *data)319305{320306 struct dentry *dir;321307 char dir_name[64];322308 int ret, method;323309324324- scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev));310310+ scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&data->wdev->dev));325311326312 dir = debugfs_create_dir(dir_name, NULL);327313 if (IS_ERR(dir))328314 return;329315330330- ret = devm_add_action_or_reset(&wdev->dev, msi_wmi_platform_debugfs_remove, dir);316316+ ret = devm_add_action_or_reset(&data->wdev->dev, msi_wmi_platform_debugfs_remove, dir);331317 if (ret < 0)332318 return;333319334320 for (method = MSI_PLATFORM_GET_PACKAGE; method <= MSI_PLATFORM_GET_WMI; method++)335335- msi_wmi_platform_debugfs_add(wdev, dir, msi_wmi_platform_debugfs_names[method - 1],321321+ msi_wmi_platform_debugfs_add(data, dir, msi_wmi_platform_debugfs_names[method - 1],336322 method);337323}338324339339-static int msi_wmi_platform_hwmon_init(struct wmi_device *wdev)325325+static int msi_wmi_platform_hwmon_init(struct msi_wmi_platform_data *data)340326{341327 struct device *hdev;342328343343- hdev = devm_hwmon_device_register_with_info(&wdev->dev, "msi_wmi_platform", wdev,329329+ hdev = devm_hwmon_device_register_with_info(&data->wdev->dev, "msi_wmi_platform", data,344330 &msi_wmi_platform_chip_info, NULL);345331346332 return PTR_ERR_OR_ZERO(hdev);347333}348334349349-static int msi_wmi_platform_ec_init(struct wmi_device *wdev)335335+static int msi_wmi_platform_ec_init(struct msi_wmi_platform_data *data)350336{351337 u8 input[32] = { 0 };352338 u8 output[32];353339 u8 flags;354340 int ret;355341356356- ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_EC, input, sizeof(input), output,342342+ ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_EC, input, sizeof(input), output,357343 sizeof(output));358344 if (ret < 0)359345 return ret;360346361347 flags = output[MSI_PLATFORM_EC_FLAGS_OFFSET];362348363363- dev_dbg(&wdev->dev, "EC RAM version %lu.%lu\n",349349+ dev_dbg(&data->wdev->dev, "EC RAM version %lu.%lu\n",364350 FIELD_GET(MSI_PLATFORM_EC_MAJOR_MASK, flags),365351 FIELD_GET(MSI_PLATFORM_EC_MINOR_MASK, flags));366366- dev_dbg(&wdev->dev, "EC firmware version %.28s\n",352352+ dev_dbg(&data->wdev->dev, "EC firmware version %.28s\n",367353 &output[MSI_PLATFORM_EC_VERSION_OFFSET]);368354369355 if (!(flags & MSI_PLATFORM_EC_IS_TIGERLAKE)) {370356 if (!force)371357 return -ENODEV;372358373373- dev_warn(&wdev->dev, "Loading on a non-Tigerlake platform\n");359359+ dev_warn(&data->wdev->dev, "Loading on a non-Tigerlake platform\n");374360 }375361376362 return 0;377363}378364379379-static int msi_wmi_platform_init(struct wmi_device *wdev)365365+static int msi_wmi_platform_init(struct msi_wmi_platform_data *data)380366{381367 u8 input[32] = { 0 };382368 u8 output[32];383369 int ret;384370385385- ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_WMI, input, sizeof(input), output,371371+ ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_WMI, input, sizeof(input), output,386372 sizeof(output));387373 if (ret < 0)388374 return ret;389375390390- dev_dbg(&wdev->dev, "WMI interface version %u.%u\n",376376+ dev_dbg(&data->wdev->dev, "WMI interface version %u.%u\n",391377 output[MSI_PLATFORM_WMI_MAJOR_OFFSET],392378 output[MSI_PLATFORM_WMI_MINOR_OFFSET]);393379···395381 if (!force)396382 return -ENODEV;397383398398- dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u.%u)\n",384384+ dev_warn(&data->wdev->dev,385385+ "Loading despite unsupported WMI interface version (%u.%u)\n",399386 output[MSI_PLATFORM_WMI_MAJOR_OFFSET],400387 output[MSI_PLATFORM_WMI_MINOR_OFFSET]);401388 }···406391407392static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context)408393{394394+ struct msi_wmi_platform_data *data;409395 int ret;410396411411- ret = msi_wmi_platform_init(wdev);397397+ data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);398398+ if (!data)399399+ return -ENOMEM;400400+401401+ data->wdev = wdev;402402+ dev_set_drvdata(&wdev->dev, data);403403+404404+ ret = devm_mutex_init(&wdev->dev, &data->wmi_lock);412405 if (ret < 0)413406 return ret;414407415415- ret = msi_wmi_platform_ec_init(wdev);408408+ ret = msi_wmi_platform_init(data);416409 if (ret < 0)417410 return ret;418411419419- msi_wmi_platform_debugfs_init(wdev);412412+ ret = msi_wmi_platform_ec_init(data);413413+ if (ret < 0)414414+ return ret;420415421421- return msi_wmi_platform_hwmon_init(wdev);416416+ msi_wmi_platform_debugfs_init(data);417417+418418+ return msi_wmi_platform_hwmon_init(data);422419}423420424421static const struct wmi_device_id msi_wmi_platform_id_table[] = {
···180180 .driver_data = (void *)&peaq_c1010_info,181181 },182182 {183183+ /* Vexia Edu Atla 10 tablet 5V version */184184+ .matches = {185185+ /* Having all 3 of these not set is somewhat unique */186186+ DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),187187+ DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),188188+ DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."),189189+ /* Above strings are too generic, also match on BIOS date */190190+ DMI_MATCH(DMI_BIOS_DATE, "05/14/2015"),191191+ },192192+ .driver_data = (void *)&vexia_edu_atla10_5v_info,193193+ },194194+ {183195 /* Vexia Edu Atla 10 tablet 9V version */184196 .matches = {185197 DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),···199187 /* Above strings are too generic, also match on BIOS date */200188 DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),201189 },202202- .driver_data = (void *)&vexia_edu_atla10_info,190190+ .driver_data = (void *)&vexia_edu_atla10_9v_info,203191 },204192 {205193 /* Whitelabel (sold as various brands) TM800A550L */