Resolve conflicts in dell/alienware-wmi-wmax and asus-wmi, and enable applying a few amd/hsmp patches that depend on changes in the fixes branch.
Unified · Split
| @@ -138,6 +138,10 @@ input data, the meaning of which depends on the subfeature being accessed. · 137 unmodified lines | ||
| 138 | 138 | The output buffer contains a single byte which signals success or failure (``0x00`` on failure) |
| 139 | 139 | and 31 bytes of output data, the meaning if which depends on the subfeature being accessed. |
| 140 | 140 | |
| 141 | +.. note:: | |
| 142 | + The ACPI control method responsible for handling the WMI method calls is not thread-safe. | |
| 143 | + This is a firmware bug that needs to be handled inside the driver itself. | |
| 144 | + | |
| 141 | 145 | WMI method Get_EC() |
| 142 | 146 | ------------------- |
| 143 | 147 | |
| @@ -333,9 +333,9 @@ static ssize_t secure_boot_fuse_state_show(struct device *dev, · 332 unmodified lines | ||
| 333 | 333 | else |
| 334 | 334 | status = valid ? "Invalid" : "Free"; |
| 335 | 335 | } |
| 336 | − buf_len += sysfs_emit(buf + buf_len, "%d:%s ", key, status); | |
| 336 | + buf_len += sysfs_emit_at(buf, buf_len, "%d:%s ", key, status); | |
| 337 | 337 | } |
| 338 | − buf_len += sysfs_emit(buf + buf_len, "\n"); | |
| 338 | + buf_len += sysfs_emit_at(buf, buf_len, "\n"); | |
| 339 | 339 | |
| 340 | 340 | return buf_len; |
| 341 | 341 | } |
| @@ -27,9 +27,8 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | #include "hsmp.h" |
| 29 | 29 | |
| 30 | −#define DRIVER_NAME "amd_hsmp" | |
| 30 | +#define DRIVER_NAME "hsmp_acpi" | |
| 31 | 31 | #define DRIVER_VERSION "2.3" |
| 32 | −#define ACPI_HSMP_DEVICE_HID "AMDI0097" | |
| 33 | 32 | |
| 34 | 33 | /* These are the strings specified in ACPI table */ |
| 35 | 34 | #define MSG_IDOFF_STR "MsgIdOffset" |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | #define HSMP_CDEV_NAME "hsmp_cdev" |
| 25 | 25 | #define HSMP_DEVNODE_NAME "hsmp" |
| 26 | +#define ACPI_HSMP_DEVICE_HID "AMDI0097" | |
| 26 | 27 | |
| 27 | 28 | struct hsmp_mbaddr_info { |
| 28 | 29 | u32 base_addr; |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include <asm/amd_hsmp.h> |
| 13 | 13 | |
| 14 | +#include <linux/acpi.h> | |
| 14 | 15 | #include <linux/build_bug.h> |
| 15 | 16 | #include <linux/device.h> |
| 16 | 17 | #include <linux/module.h> |
| @@ -266,7 +267,7 @@ static bool legacy_hsmp_support(void) · 249 unmodified lines | ||
| 266 | 267 | } |
| 267 | 268 | case 0x1A: |
| 268 | 269 | switch (boot_cpu_data.x86_model) { |
| 269 | − case 0x00 ... 0x1F: | |
| 270 | + case 0x00 ... 0x0F: | |
| 270 | 271 | return true; |
| 271 | 272 | default: |
| 272 | 273 | return false; |
| @@ -288,6 +289,9 @@ static int __init hsmp_plt_init(void) · 15 unmodified lines | ||
| 288 | 289 | return ret; |
| 289 | 290 | } |
| 290 | 291 | |
| 292 | + if (acpi_dev_present(ACPI_HSMP_DEVICE_HID, NULL, -1)) | |
| 293 | + return -ENODEV; | |
| 294 | + | |
| 291 | 295 | hsmp_pdev = get_hsmp_pdev(); |
| 292 | 296 | if (!hsmp_pdev) |
| 293 | 297 | return -ENOMEM; |
| @@ -217,6 +217,13 @@ static const struct dmi_system_id fwbug_list[] = { · 216 unmodified lines | ||
| 217 | 217 | DMI_MATCH(DMI_BIOS_VERSION, "03.05"), |
| 218 | 218 | } |
| 219 | 219 | }, |
| 220 | + { | |
| 221 | + .ident = "MECHREVO Wujie 14X (GX4HRXL)", | |
| 222 | + .driver_data = &quirk_spurious_8042, | |
| 223 | + .matches = { | |
| 224 | + DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"), | |
| 225 | + } | |
| 226 | + }, | |
| 220 | 227 | {} |
| 221 | 228 | }; |
| 222 | 229 | |
| @@ -644,10 +644,9 @@ static void amd_pmc_s2idle_check(void) · 643 unmodified lines | ||
| 644 | 644 | struct smu_metrics table; |
| 645 | 645 | int rc; |
| 646 | 646 | |
| 647 | − /* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */ | |
| 648 | − if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) && | |
| 649 | − table.s0i3_last_entry_status) | |
| 650 | − usleep_range(10000, 20000); | |
| 647 | + /* Avoid triggering OVP */ | |
| 648 | + if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status) | |
| 649 | + msleep(2500); | |
| 651 | 650 | |
| 652 | 651 | /* Dump the IdleMask before we add to the STB */ |
| 653 | 652 | amd_pmc_idlemask_read(pdev, pdev->dev, NULL); |
| @@ -120,9 +120,9 @@ static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx, · 119 unmodified lines | ||
| 120 | 120 | amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL); |
| 121 | 121 | amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL); |
| 122 | 122 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, |
| 123 | − pwr_ctrl->stt_skin_temp[STT_TEMP_APU], NULL); | |
| 123 | + fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_APU]), NULL); | |
| 124 | 124 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, |
| 125 | − pwr_ctrl->stt_skin_temp[STT_TEMP_HS2], NULL); | |
| 125 | + fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_HS2]), NULL); | |
| 126 | 126 | |
| 127 | 127 | if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) |
| 128 | 128 | apmf_update_fan_idx(dev, config_store.mode_set[idx].fan_control.manual, |
| @@ -81,10 +81,10 @@ static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx, · 80 unmodified lines | ||
| 81 | 81 | amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL); |
| 82 | 82 | amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL); |
| 83 | 83 | amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL); |
| 84 | − amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU], | |
| 85 | − NULL); | |
| 86 | − amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2], | |
| 87 | − NULL); | |
| 84 | + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, | |
| 85 | + fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_APU]), NULL); | |
| 86 | + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, | |
| 87 | + fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_HS2]), NULL); | |
| 88 | 88 | |
| 89 | 89 | if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) |
| 90 | 90 | apmf_update_fan_idx(dev, |
| @@ -176,6 +176,20 @@ static void __maybe_unused amd_pmf_dump_registers(struct amd_pmf_dev *dev) · 175 unmodified lines | ||
| 176 | 176 | dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value); |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | +/** | |
| 180 | + * fixp_q88_fromint: Convert integer to Q8.8 | |
| 181 | + * @val: input value | |
| 182 | + * | |
| 183 | + * Converts an integer into binary fixed point format where 8 bits | |
| 184 | + * are used for integer and 8 bits are used for the decimal. | |
| 185 | + * | |
| 186 | + * Return: unsigned integer converted to Q8.8 format | |
| 187 | + */ | |
| 188 | +u32 fixp_q88_fromint(u32 val) | |
| 189 | +{ | |
| 190 | + return val << 8; | |
| 191 | +} | |
| 192 | + | |
| 179 | 193 | int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data) |
| 180 | 194 | { |
| 181 | 195 | int rc; |
| @@ -777,6 +777,7 @@ int apmf_install_handler(struct amd_pmf_dev *pmf_dev); · 776 unmodified lines | ||
| 777 | 777 | int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag); |
| 778 | 778 | int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer); |
| 779 | 779 | int amd_pmf_notify_sbios_heartbeat_event_v2(struct amd_pmf_dev *dev, u8 flag); |
| 780 | +u32 fixp_q88_fromint(u32 val); | |
| 780 | 781 | |
| 781 | 782 | /* SPS Layer */ |
| 782 | 783 | int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf); |
| @@ -198,9 +198,11 @@ static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx) · 197 unmodified lines | ||
| 198 | 198 | amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, |
| 199 | 199 | apts_config_store.val[idx].stt_min_limit, NULL); |
| 200 | 200 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, |
| 201 | − apts_config_store.val[idx].stt_skin_temp_limit_apu, NULL); | |
| 201 | + fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_apu), | |
| 202 | + NULL); | |
| 202 | 203 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, |
| 203 | − apts_config_store.val[idx].stt_skin_temp_limit_hs2, NULL); | |
| 204 | + fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_hs2), | |
| 205 | + NULL); | |
| 204 | 206 | } |
| 205 | 207 | |
| 206 | 208 | void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, |
| @@ -217,9 +219,11 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, · 10 unmodified lines | ||
| 217 | 219 | amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, |
| 218 | 220 | config_store.prop[src][idx].stt_min, NULL); |
| 219 | 221 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, |
| 220 | − config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); | |
| 222 | + fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU]), | |
| 223 | + NULL); | |
| 221 | 224 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, |
| 222 | − config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); | |
| 225 | + fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2]), | |
| 226 | + NULL); | |
| 223 | 227 | } else if (op == SLIDER_OP_GET) { |
| 224 | 228 | amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); |
| 225 | 229 | amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); |
| @@ -123,7 +123,8 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ · 122 unmodified lines | ||
| 123 | 123 | |
| 124 | 124 | case PMF_POLICY_STT_SKINTEMP_APU: |
| 125 | 125 | if (dev->prev_data->stt_skintemp_apu != val) { |
| 126 | − amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, val, NULL); | |
| 126 | + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, | |
| 127 | + fixp_q88_fromint(val), NULL); | |
| 127 | 128 | dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val); |
| 128 | 129 | dev->prev_data->stt_skintemp_apu = val; |
| 129 | 130 | } |
| @@ -131,7 +132,8 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_ · 1 unmodified line | ||
| 131 | 132 | |
| 132 | 133 | case PMF_POLICY_STT_SKINTEMP_HS2: |
| 133 | 134 | if (dev->prev_data->stt_skintemp_hs2 != val) { |
| 134 | − amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, val, NULL); | |
| 135 | + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, | |
| 136 | + fixp_q88_fromint(val), NULL); | |
| 135 | 137 | dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val); |
| 136 | 138 | dev->prev_data->stt_skintemp_hs2 = val; |
| 137 | 139 | } |
| @@ -332,6 +334,11 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) · 194 unmodified lines | ||
| 332 | 334 | return 0; |
| 333 | 335 | } |
| 334 | 336 | |
| 337 | +static inline bool amd_pmf_pb_valid(struct amd_pmf_dev *dev) | |
| 338 | +{ | |
| 339 | + return memchr_inv(dev->policy_buf, 0xff, dev->policy_sz); | |
| 340 | +} | |
| 341 | + | |
| 335 | 342 | #ifdef CONFIG_AMD_PMF_DEBUG |
| 336 | 343 | static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev) |
| 337 | 344 | { |
| @@ -359,12 +366,22 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf, · 21 unmodified lines | ||
| 359 | 366 | dev->policy_buf = new_policy_buf; |
| 360 | 367 | dev->policy_sz = length; |
| 361 | 368 | |
| 369 | + if (!amd_pmf_pb_valid(dev)) { | |
| 370 | + ret = -EINVAL; | |
| 371 | + goto cleanup; | |
| 372 | + } | |
| 373 | + | |
| 362 | 374 | amd_pmf_hex_dump_pb(dev); |
| 363 | 375 | ret = amd_pmf_start_policy_engine(dev); |
| 364 | 376 | if (ret < 0) |
| 365 | − return ret; | |
| 377 | + goto cleanup; | |
| 366 | 378 | |
| 367 | 379 | return length; |
| 380 | + | |
| 381 | +cleanup: | |
| 382 | + kfree(dev->policy_buf); | |
| 383 | + dev->policy_buf = NULL; | |
| 384 | + return ret; | |
| 368 | 385 | } |
| 369 | 386 | |
| 370 | 387 | static const struct file_operations pb_fops = { |
| @@ -526,6 +543,12 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) · 155 unmodified lines | ||
| 526 | 543 | |
| 527 | 544 | memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz); |
| 528 | 545 | |
| 546 | + if (!amd_pmf_pb_valid(dev)) { | |
| 547 | + dev_info(dev->dev, "No Smart PC policy present\n"); | |
| 548 | + ret = -EINVAL; | |
| 549 | + goto err_free_policy; | |
| 550 | + } | |
| 551 | + | |
| 529 | 552 | amd_pmf_hex_dump_pb(dev); |
| 530 | 553 | |
| 531 | 554 | dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL); |
| @@ -426,11 +426,14 @@ static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable) · 425 unmodified lines | ||
| 426 | 426 | |
| 427 | 427 | static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method) |
| 428 | 428 | { |
| 429 | + unsigned long long val = (unsigned long long)curr; | |
| 430 | + acpi_status status; | |
| 429 | 431 | int i, delta; |
| 430 | − unsigned long long val; | |
| 431 | − for (i = 0; i < PEGA_ACC_RETRIES; i++) { | |
| 432 | − acpi_evaluate_integer(asus->handle, method, NULL, &val); | |
| 433 | 432 | |
| 433 | + for (i = 0; i < PEGA_ACC_RETRIES; i++) { | |
| 434 | + status = acpi_evaluate_integer(asus->handle, method, NULL, &val); | |
| 435 | + if (ACPI_FAILURE(status)) | |
| 436 | + continue; | |
| 434 | 437 | /* The output is noisy. From reading the ASL |
| 435 | 438 | * dissassembly, timeout errors are returned with 1's |
| 436 | 439 | * in the high word, and the lack of locking around |
| @@ -305,6 +305,7 @@ struct asus_wmi { · 304 unmodified lines | ||
| 305 | 305 | |
| 306 | 306 | u32 kbd_rgb_dev; |
| 307 | 307 | bool kbd_rgb_state_available; |
| 308 | + bool oobe_state_available; | |
| 308 | 309 | |
| 309 | 310 | u8 throttle_thermal_policy_mode; |
| 310 | 311 | u32 throttle_thermal_policy_dev; |
| @@ -1868,7 +1869,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus) · 1557 unmodified lines | ||
| 1868 | 1869 | goto error; |
| 1869 | 1870 | } |
| 1870 | 1871 | |
| 1871 | − if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE)) { | |
| 1872 | + if (asus->oobe_state_available) { | |
| 1872 | 1873 | /* |
| 1873 | 1874 | * Disable OOBE state, so that e.g. the keyboard backlight |
| 1874 | 1875 | * works. |
| @@ -4780,6 +4781,7 @@ static int asus_wmi_add(struct platform_device *pdev) · 2905 unmodified lines | ||
| 4780 | 4781 | asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); |
| 4781 | 4782 | asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); |
| 4782 | 4783 | asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); |
| 4784 | + asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE); | |
| 4783 | 4785 | |
| 4784 | 4786 | if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) |
| 4785 | 4787 | asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; |
| @@ -4832,7 +4834,8 @@ static int asus_wmi_add(struct platform_device *pdev) · 46 unmodified lines | ||
| 4832 | 4834 | goto fail_leds; |
| 4833 | 4835 | |
| 4834 | 4836 | asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result); |
| 4835 | − if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) | |
| 4837 | + if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) == | |
| 4838 | + (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) | |
| 4836 | 4839 | asus->driver->wlan_ctrl_by_user = 1; |
| 4837 | 4840 | |
| 4838 | 4841 | if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) { |
| @@ -4997,6 +5000,13 @@ static int asus_hotk_restore(struct device *device) · 158 unmodified lines | ||
| 4997 | 5000 | } |
| 4998 | 5001 | if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) |
| 4999 | 5002 | kbd_led_update(asus); |
| 5003 | + if (asus->oobe_state_available) { | |
| 5004 | + /* | |
| 5005 | + * Disable OOBE state, so that e.g. the keyboard backlight | |
| 5006 | + * works. | |
| 5007 | + */ | |
| 5008 | + asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL); | |
| 5009 | + } | |
| 5000 | 5010 | |
| 5001 | 5011 | if (asus_wmi_has_fnlock_key(asus)) |
| 5002 | 5012 | asus_wmi_fnlock_update(asus); |
| @@ -89,12 +89,44 @@ static struct awcc_quirks generic_quirks = { · 88 unmodified lines | ||
| 89 | 89 | static struct awcc_quirks empty_quirks; |
| 90 | 90 | |
| 91 | 91 | static const struct dmi_system_id awcc_dmi_table[] __initconst = { |
| 92 | + { | |
| 93 | + .ident = "Alienware Area-51m R2", | |
| 94 | + .matches = { | |
| 95 | + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | |
| 96 | + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware Area-51m R2"), | |
| 97 | + }, | |
| 98 | + .driver_data = &generic_quirks, | |
| 99 | + }, | |
| 100 | + { | |
| 101 | + .ident = "Alienware m15 R7", | |
| 102 | + .matches = { | |
| 103 | + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | |
| 104 | + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m15 R7"), | |
| 105 | + }, | |
| 106 | + .driver_data = &generic_quirks, | |
| 107 | + }, | |
| 108 | + { | |
| 109 | + .ident = "Alienware m16 R1", | |
| 110 | + .matches = { | |
| 111 | + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | |
| 112 | + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1"), | |
| 113 | + }, | |
| 114 | + .driver_data = &g_series_quirks, | |
| 115 | + }, | |
| 92 | 116 | { |
| 93 | 117 | .ident = "Alienware m16 R1 AMD", |
| 94 | 118 | .matches = { |
| 95 | 119 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), |
| 96 | 120 | DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"), |
| 97 | 121 | }, |
| 122 | + .driver_data = &g_series_quirks, | |
| 123 | + }, | |
| 124 | + { | |
| 125 | + .ident = "Alienware m16 R2", | |
| 126 | + .matches = { | |
| 127 | + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | |
| 128 | + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R2"), | |
| 129 | + }, | |
| 98 | 130 | .driver_data = &generic_quirks, |
| 99 | 131 | }, |
| 100 | 132 | { |
| @@ -121,6 +153,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { · 20 unmodified lines | ||
| 121 | 153 | }, |
| 122 | 154 | .driver_data = &generic_quirks, |
| 123 | 155 | }, |
| 156 | + { | |
| 157 | + .ident = "Alienware x15 R2", | |
| 158 | + .matches = { | |
| 159 | + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | |
| 160 | + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R2"), | |
| 161 | + }, | |
| 162 | + .driver_data = &generic_quirks, | |
| 163 | + }, | |
| 124 | 164 | { |
| 125 | 165 | .ident = "Alienware x17 R2", |
| 126 | 166 | .matches = { |
| @@ -153,6 +193,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { · 26 unmodified lines | ||
| 153 | 193 | }, |
| 154 | 194 | .driver_data = &g_series_quirks, |
| 155 | 195 | }, |
| 196 | + { | |
| 197 | + .ident = "Dell Inc. G16 7630", | |
| 198 | + .matches = { | |
| 199 | + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | |
| 200 | + DMI_MATCH(DMI_PRODUCT_NAME, "Dell G16 7630"), | |
| 201 | + }, | |
| 202 | + .driver_data = &g_series_quirks, | |
| 203 | + }, | |
| 156 | 204 | { |
| 157 | 205 | .ident = "Dell Inc. G3 3500", |
| 158 | 206 | .matches = { |
| @@ -177,6 +225,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { · 18 unmodified lines | ||
| 177 | 225 | }, |
| 178 | 226 | .driver_data = &g_series_quirks, |
| 179 | 227 | }, |
| 228 | + { | |
| 229 | + .ident = "Dell Inc. G5 5505", | |
| 230 | + .matches = { | |
| 231 | + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | |
| 232 | + DMI_MATCH(DMI_PRODUCT_NAME, "G5 5505"), | |
| 233 | + }, | |
| 234 | + .driver_data = &g_series_quirks, | |
| 235 | + }, | |
| 180 | 236 | }; |
| 181 | 237 | |
| 182 | 238 | enum AWCC_GET_FAN_SENSORS_OPERATIONS { |
| @@ -1241,14 +1297,14 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices) · 1058 unmodified lines | ||
| 1241 | 1297 | |
| 1242 | 1298 | for (unsigned int i = 0; i < priv->profile_count; i++) { |
| 1243 | 1299 | ret = awcc_op_get_resource_id(priv->wdev, i + offset, &id); |
| 1244 | − if (ret == -EIO) | |
| 1245 | − return ret; | |
| 1246 | 1300 | /* |
| 1247 | 1301 | * Some devices report an incorrect number of thermal profiles |
| 1248 | 1302 | * so the resource ID list may end prematurely |
| 1249 | 1303 | */ |
| 1250 | 1304 | if (ret == -EBADRQC) |
| 1251 | 1305 | break; |
| 1306 | + if (ret) | |
| 1307 | + return ret; | |
| 1252 | 1308 | |
| 1253 | 1309 | if (!is_awcc_thermal_profile_id(id)) { |
| 1254 | 1310 | dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id); |
| @@ -1294,6 +1294,16 @@ static const struct key_entry ideapad_keymap[] = { · 1293 unmodified lines | ||
| 1294 | 1294 | /* Specific to some newer models */ |
| 1295 | 1295 | { KE_KEY, 0x3e | IDEAPAD_WMI_KEY, { KEY_MICMUTE } }, |
| 1296 | 1296 | { KE_KEY, 0x3f | IDEAPAD_WMI_KEY, { KEY_RFKILL } }, |
| 1297 | + /* Star- (User Assignable Key) */ | |
| 1298 | + { KE_KEY, 0x44 | IDEAPAD_WMI_KEY, { KEY_PROG1 } }, | |
| 1299 | + /* Eye */ | |
| 1300 | + { KE_KEY, 0x45 | IDEAPAD_WMI_KEY, { KEY_PROG3 } }, | |
| 1301 | + /* Performance toggle also Fn+Q, handled inside ideapad_wmi_notify() */ | |
| 1302 | + { KE_KEY, 0x3d | IDEAPAD_WMI_KEY, { KEY_PROG4 } }, | |
| 1303 | + /* shift + prtsc */ | |
| 1304 | + { KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_CUT } }, | |
| 1305 | + { KE_KEY, 0x29 | IDEAPAD_WMI_KEY, { KEY_TOUCHPAD_TOGGLE } }, | |
| 1306 | + { KE_KEY, 0x2a | IDEAPAD_WMI_KEY, { KEY_ROOT_MENU } }, | |
| 1297 | 1307 | |
| 1298 | 1308 | { KE_END }, |
| 1299 | 1309 | }; |
| @@ -2080,6 +2090,12 @@ static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data) · 780 unmodified lines | ||
| 2080 | 2090 | dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n", |
| 2081 | 2091 | data->integer.value); |
| 2082 | 2092 | |
| 2093 | + /* performance button triggered by 0x3d */ | |
| 2094 | + if (data->integer.value == 0x3d && priv->dytc) { | |
| 2095 | + platform_profile_cycle(); | |
| 2096 | + break; | |
| 2097 | + } | |
| 2098 | + | |
| 2083 | 2099 | /* 0x02 FnLock, 0x03 Esc */ |
| 2084 | 2100 | if (data->integer.value == 0x02 || data->integer.value == 0x03) |
| 2085 | 2101 | ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02); |
| @@ -44,16 +44,17 @@ MODULE_LICENSE("GPL"); · 43 unmodified lines | ||
| 44 | 44 | MODULE_AUTHOR("Alex Hung"); |
| 45 | 45 | |
| 46 | 46 | static const struct acpi_device_id intel_hid_ids[] = { |
| 47 | − {"INT33D5", 0}, | |
| 48 | − {"INTC1051", 0}, | |
| 49 | − {"INTC1054", 0}, | |
| 50 | − {"INTC1070", 0}, | |
| 51 | − {"INTC1076", 0}, | |
| 52 | − {"INTC1077", 0}, | |
| 53 | − {"INTC1078", 0}, | |
| 54 | − {"INTC107B", 0}, | |
| 55 | − {"INTC10CB", 0}, | |
| 56 | − {"", 0}, | |
| 47 | + { "INT33D5" }, | |
| 48 | + { "INTC1051" }, | |
| 49 | + { "INTC1054" }, | |
| 50 | + { "INTC1070" }, | |
| 51 | + { "INTC1076" }, | |
| 52 | + { "INTC1077" }, | |
| 53 | + { "INTC1078" }, | |
| 54 | + { "INTC107B" }, | |
| 55 | + { "INTC10CB" }, | |
| 56 | + { "INTC10CC" }, | |
| 57 | + { } | |
| 57 | 58 | }; |
| 58 | 59 | MODULE_DEVICE_TABLE(acpi, intel_hid_ids); |
| 59 | 60 | |
| @@ -146,15 +146,13 @@ static int uncore_event_cpu_online(unsigned int cpu) · 145 unmodified lines | ||
| 146 | 146 | { |
| 147 | 147 | struct uncore_data *data; |
| 148 | 148 | int target; |
| 149 | + int ret; | |
| 149 | 150 | |
| 150 | 151 | /* Check if there is an online cpu in the package for uncore MSR */ |
| 151 | 152 | target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu)); |
| 152 | 153 | if (target < nr_cpu_ids) |
| 153 | 154 | return 0; |
| 154 | 155 | |
| 155 | − /* Use this CPU on this die as a control CPU */ | |
| 156 | − cpumask_set_cpu(cpu, &uncore_cpu_mask); | |
| 157 | − | |
| 158 | 156 | data = uncore_get_instance(cpu); |
| 159 | 157 | if (!data) |
| 160 | 158 | return 0; |
| @@ -163,7 +161,14 @@ static int uncore_event_cpu_online(unsigned int cpu) · 2 unmodified lines | ||
| 163 | 161 | data->die_id = topology_die_id(cpu); |
| 164 | 162 | data->domain_id = UNCORE_DOMAIN_ID_INVALID; |
| 165 | 163 | |
| 166 | − return uncore_freq_add_entry(data, cpu); | |
| 164 | + ret = uncore_freq_add_entry(data, cpu); | |
| 165 | + if (ret) | |
| 166 | + return ret; | |
| 167 | + | |
| 168 | + /* Use this CPU on this die as a control CPU */ | |
| 169 | + cpumask_set_cpu(cpu, &uncore_cpu_mask); | |
| 170 | + | |
| 171 | + return 0; | |
| 167 | 172 | } |
| 168 | 173 | |
| 169 | 174 | static int uncore_event_cpu_offline(unsigned int cpu) |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/acpi.h> |
| 11 | 11 | #include <linux/bits.h> |
| 12 | 12 | #include <linux/bitfield.h> |
| 13 | +#include <linux/cleanup.h> | |
| 13 | 14 | #include <linux/debugfs.h> |
| 14 | 15 | #include <linux/device.h> |
| 15 | 16 | #include <linux/device/driver.h> |
| @@ -17,6 +18,7 @@ · 1 unmodified line | ||
| 17 | 18 | #include <linux/hwmon.h> |
| 18 | 19 | #include <linux/kernel.h> |
| 19 | 20 | #include <linux/module.h> |
| 21 | +#include <linux/mutex.h> | |
| 20 | 22 | #include <linux/printk.h> |
| 21 | 23 | #include <linux/rwsem.h> |
| 22 | 24 | #include <linux/types.h> |
| @@ -76,8 +78,13 @@ enum msi_wmi_platform_method { · 53 unmodified lines | ||
| 76 | 78 | MSI_PLATFORM_GET_WMI = 0x1d, |
| 77 | 79 | }; |
| 78 | 80 | |
| 79 | −struct msi_wmi_platform_debugfs_data { | |
| 81 | +struct msi_wmi_platform_data { | |
| 80 | 82 | struct wmi_device *wdev; |
| 83 | + struct mutex wmi_lock; /* Necessary when calling WMI methods */ | |
| 84 | +}; | |
| 85 | + | |
| 86 | +struct msi_wmi_platform_debugfs_data { | |
| 87 | + struct msi_wmi_platform_data *data; | |
| 81 | 88 | enum msi_wmi_platform_method method; |
| 82 | 89 | struct rw_semaphore buffer_lock; /* Protects debugfs buffer */ |
| 83 | 90 | size_t length; |
| @@ -132,8 +139,9 @@ static int msi_wmi_platform_parse_buffer(union acpi_object *obj, u8 *output, siz · 48 unmodified lines | ||
| 132 | 139 | return 0; |
| 133 | 140 | } |
| 134 | 141 | |
| 135 | −static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform_method method, | |
| 136 | − u8 *input, size_t input_length, u8 *output, size_t output_length) | |
| 142 | +static int msi_wmi_platform_query(struct msi_wmi_platform_data *data, | |
| 143 | + enum msi_wmi_platform_method method, u8 *input, | |
| 144 | + size_t input_length, u8 *output, size_t output_length) | |
| 137 | 145 | { |
| 138 | 146 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 139 | 147 | struct acpi_buffer in = { |
| @@ -147,9 +155,15 @@ static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform · 7 unmodified lines | ||
| 147 | 155 | if (!input_length || !output_length) |
| 148 | 156 | return -EINVAL; |
| 149 | 157 | |
| 150 | − status = wmidev_evaluate_method(wdev, 0x0, method, &in, &out); | |
| 151 | − if (ACPI_FAILURE(status)) | |
| 152 | − return -EIO; | |
| 158 | + /* | |
| 159 | + * The ACPI control method responsible for handling the WMI method calls | |
| 160 | + * is not thread-safe. Because of this we have to do the locking ourself. | |
| 161 | + */ | |
| 162 | + scoped_guard(mutex, &data->wmi_lock) { | |
| 163 | + status = wmidev_evaluate_method(data->wdev, 0x0, method, &in, &out); | |
| 164 | + if (ACPI_FAILURE(status)) | |
| 165 | + return -EIO; | |
| 166 | + } | |
| 153 | 167 | |
| 154 | 168 | obj = out.pointer; |
| 155 | 169 | if (!obj) |
| @@ -170,22 +184,22 @@ static umode_t msi_wmi_platform_is_visible(const void *drvdata, enum hwmon_senso · 14 unmodified lines | ||
| 170 | 184 | static int msi_wmi_platform_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, |
| 171 | 185 | int channel, long *val) |
| 172 | 186 | { |
| 173 | − struct wmi_device *wdev = dev_get_drvdata(dev); | |
| 187 | + struct msi_wmi_platform_data *data = dev_get_drvdata(dev); | |
| 174 | 188 | u8 input[32] = { 0 }; |
| 175 | 189 | u8 output[32]; |
| 176 | − u16 data; | |
| 190 | + u16 value; | |
| 177 | 191 | int ret; |
| 178 | 192 | |
| 179 | − ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_FAN, input, sizeof(input), output, | |
| 193 | + ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_FAN, input, sizeof(input), output, | |
| 180 | 194 | sizeof(output)); |
| 181 | 195 | if (ret < 0) |
| 182 | 196 | return ret; |
| 183 | 197 | |
| 184 | − data = get_unaligned_be16(&output[channel * 2 + 1]); | |
| 185 | − if (!data) | |
| 198 | + value = get_unaligned_be16(&output[channel * 2 + 1]); | |
| 199 | + if (!value) | |
| 186 | 200 | *val = 0; |
| 187 | 201 | else |
| 188 | − *val = 480000 / data; | |
| 202 | + *val = 480000 / value; | |
| 189 | 203 | |
| 190 | 204 | return 0; |
| 191 | 205 | } |
| @@ -231,7 +245,7 @@ static ssize_t msi_wmi_platform_write(struct file *fp, const char __user *input, · 39 unmodified lines | ||
| 231 | 245 | return ret; |
| 232 | 246 | |
| 233 | 247 | down_write(&data->buffer_lock); |
| 234 | − ret = msi_wmi_platform_query(data->wdev, data->method, payload, data->length, data->buffer, | |
| 248 | + ret = msi_wmi_platform_query(data->data, data->method, payload, data->length, data->buffer, | |
| 235 | 249 | data->length); |
| 236 | 250 | up_write(&data->buffer_lock); |
| 237 | 251 | |
| @@ -277,17 +291,17 @@ static void msi_wmi_platform_debugfs_remove(void *data) · 39 unmodified lines | ||
| 277 | 291 | debugfs_remove_recursive(dir); |
| 278 | 292 | } |
| 279 | 293 | |
| 280 | −static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry *dir, | |
| 294 | +static void msi_wmi_platform_debugfs_add(struct msi_wmi_platform_data *drvdata, struct dentry *dir, | |
| 281 | 295 | const char *name, enum msi_wmi_platform_method method) |
| 282 | 296 | { |
| 283 | 297 | struct msi_wmi_platform_debugfs_data *data; |
| 284 | 298 | struct dentry *entry; |
| 285 | 299 | |
| 286 | − data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); | |
| 300 | + data = devm_kzalloc(&drvdata->wdev->dev, sizeof(*data), GFP_KERNEL); | |
| 287 | 301 | if (!data) |
| 288 | 302 | return; |
| 289 | 303 | |
| 290 | − data->wdev = wdev; | |
| 304 | + data->data = drvdata; | |
| 291 | 305 | data->method = method; |
| 292 | 306 | init_rwsem(&data->buffer_lock); |
| 293 | 307 | |
| @@ -298,82 +312,82 @@ static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry · 4 unmodified lines | ||
| 298 | 312 | |
| 299 | 313 | entry = debugfs_create_file(name, 0600, dir, data, &msi_wmi_platform_debugfs_fops); |
| 300 | 314 | if (IS_ERR(entry)) |
| 301 | − devm_kfree(&wdev->dev, data); | |
| 315 | + devm_kfree(&drvdata->wdev->dev, data); | |
| 302 | 316 | } |
| 303 | 317 | |
| 304 | −static void msi_wmi_platform_debugfs_init(struct wmi_device *wdev) | |
| 318 | +static void msi_wmi_platform_debugfs_init(struct msi_wmi_platform_data *data) | |
| 305 | 319 | { |
| 306 | 320 | struct dentry *dir; |
| 307 | 321 | char dir_name[64]; |
| 308 | 322 | int ret, method; |
| 309 | 323 | |
| 310 | − scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev)); | |
| 324 | + scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&data->wdev->dev)); | |
| 311 | 325 | |
| 312 | 326 | dir = debugfs_create_dir(dir_name, NULL); |
| 313 | 327 | if (IS_ERR(dir)) |
| 314 | 328 | return; |
| 315 | 329 | |
| 316 | − ret = devm_add_action_or_reset(&wdev->dev, msi_wmi_platform_debugfs_remove, dir); | |
| 330 | + ret = devm_add_action_or_reset(&data->wdev->dev, msi_wmi_platform_debugfs_remove, dir); | |
| 317 | 331 | if (ret < 0) |
| 318 | 332 | return; |
| 319 | 333 | |
| 320 | 334 | for (method = MSI_PLATFORM_GET_PACKAGE; method <= MSI_PLATFORM_GET_WMI; method++) |
| 321 | − msi_wmi_platform_debugfs_add(wdev, dir, msi_wmi_platform_debugfs_names[method - 1], | |
| 335 | + msi_wmi_platform_debugfs_add(data, dir, msi_wmi_platform_debugfs_names[method - 1], | |
| 322 | 336 | method); |
| 323 | 337 | } |
| 324 | 338 | |
| 325 | −static int msi_wmi_platform_hwmon_init(struct wmi_device *wdev) | |
| 339 | +static int msi_wmi_platform_hwmon_init(struct msi_wmi_platform_data *data) | |
| 326 | 340 | { |
| 327 | 341 | struct device *hdev; |
| 328 | 342 | |
| 329 | − hdev = devm_hwmon_device_register_with_info(&wdev->dev, "msi_wmi_platform", wdev, | |
| 343 | + hdev = devm_hwmon_device_register_with_info(&data->wdev->dev, "msi_wmi_platform", data, | |
| 330 | 344 | &msi_wmi_platform_chip_info, NULL); |
| 331 | 345 | |
| 332 | 346 | return PTR_ERR_OR_ZERO(hdev); |
| 333 | 347 | } |
| 334 | 348 | |
| 335 | −static int msi_wmi_platform_ec_init(struct wmi_device *wdev) | |
| 349 | +static int msi_wmi_platform_ec_init(struct msi_wmi_platform_data *data) | |
| 336 | 350 | { |
| 337 | 351 | u8 input[32] = { 0 }; |
| 338 | 352 | u8 output[32]; |
| 339 | 353 | u8 flags; |
| 340 | 354 | int ret; |
| 341 | 355 | |
| 342 | − ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_EC, input, sizeof(input), output, | |
| 356 | + ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_EC, input, sizeof(input), output, | |
| 343 | 357 | sizeof(output)); |
| 344 | 358 | if (ret < 0) |
| 345 | 359 | return ret; |
| 346 | 360 | |
| 347 | 361 | flags = output[MSI_PLATFORM_EC_FLAGS_OFFSET]; |
| 348 | 362 | |
| 349 | − dev_dbg(&wdev->dev, "EC RAM version %lu.%lu\n", | |
| 363 | + dev_dbg(&data->wdev->dev, "EC RAM version %lu.%lu\n", | |
| 350 | 364 | FIELD_GET(MSI_PLATFORM_EC_MAJOR_MASK, flags), |
| 351 | 365 | FIELD_GET(MSI_PLATFORM_EC_MINOR_MASK, flags)); |
| 352 | − dev_dbg(&wdev->dev, "EC firmware version %.28s\n", | |
| 366 | + dev_dbg(&data->wdev->dev, "EC firmware version %.28s\n", | |
| 353 | 367 | &output[MSI_PLATFORM_EC_VERSION_OFFSET]); |
| 354 | 368 | |
| 355 | 369 | if (!(flags & MSI_PLATFORM_EC_IS_TIGERLAKE)) { |
| 356 | 370 | if (!force) |
| 357 | 371 | return -ENODEV; |
| 358 | 372 | |
| 359 | − dev_warn(&wdev->dev, "Loading on a non-Tigerlake platform\n"); | |
| 373 | + dev_warn(&data->wdev->dev, "Loading on a non-Tigerlake platform\n"); | |
| 360 | 374 | } |
| 361 | 375 | |
| 362 | 376 | return 0; |
| 363 | 377 | } |
| 364 | 378 | |
| 365 | −static int msi_wmi_platform_init(struct wmi_device *wdev) | |
| 379 | +static int msi_wmi_platform_init(struct msi_wmi_platform_data *data) | |
| 366 | 380 | { |
| 367 | 381 | u8 input[32] = { 0 }; |
| 368 | 382 | u8 output[32]; |
| 369 | 383 | int ret; |
| 370 | 384 | |
| 371 | − ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_WMI, input, sizeof(input), output, | |
| 385 | + ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_WMI, input, sizeof(input), output, | |
| 372 | 386 | sizeof(output)); |
| 373 | 387 | if (ret < 0) |
| 374 | 388 | return ret; |
| 375 | 389 | |
| 376 | − dev_dbg(&wdev->dev, "WMI interface version %u.%u\n", | |
| 390 | + dev_dbg(&data->wdev->dev, "WMI interface version %u.%u\n", | |
| 377 | 391 | output[MSI_PLATFORM_WMI_MAJOR_OFFSET], |
| 378 | 392 | output[MSI_PLATFORM_WMI_MINOR_OFFSET]); |
| 379 | 393 | |
| @@ -381,7 +395,8 @@ static int msi_wmi_platform_init(struct wmi_device *wdev) · 1 unmodified line | ||
| 381 | 395 | if (!force) |
| 382 | 396 | return -ENODEV; |
| 383 | 397 | |
| 384 | − dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u.%u)\n", | |
| 398 | + dev_warn(&data->wdev->dev, | |
| 399 | + "Loading despite unsupported WMI interface version (%u.%u)\n", | |
| 385 | 400 | output[MSI_PLATFORM_WMI_MAJOR_OFFSET], |
| 386 | 401 | output[MSI_PLATFORM_WMI_MINOR_OFFSET]); |
| 387 | 402 | } |
| @@ -391,19 +406,31 @@ static int msi_wmi_platform_init(struct wmi_device *wdev) · 3 unmodified lines | ||
| 391 | 406 | |
| 392 | 407 | static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) |
| 393 | 408 | { |
| 409 | + struct msi_wmi_platform_data *data; | |
| 394 | 410 | int ret; |
| 395 | 411 | |
| 396 | − ret = msi_wmi_platform_init(wdev); | |
| 412 | + data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); | |
| 413 | + if (!data) | |
| 414 | + return -ENOMEM; | |
| 415 | + | |
| 416 | + data->wdev = wdev; | |
| 417 | + dev_set_drvdata(&wdev->dev, data); | |
| 418 | + | |
| 419 | + ret = devm_mutex_init(&wdev->dev, &data->wmi_lock); | |
| 420 | + if (ret < 0) | |
| 421 | + return ret; | |
| 422 | + | |
| 423 | + ret = msi_wmi_platform_init(data); | |
| 397 | 424 | if (ret < 0) |
| 398 | 425 | return ret; |
| 399 | 426 | |
| 400 | − ret = msi_wmi_platform_ec_init(wdev); | |
| 427 | + ret = msi_wmi_platform_ec_init(data); | |
| 401 | 428 | if (ret < 0) |
| 402 | 429 | return ret; |
| 403 | 430 | |
| 404 | − msi_wmi_platform_debugfs_init(wdev); | |
| 431 | + msi_wmi_platform_debugfs_init(data); | |
| 405 | 432 | |
| 406 | − return msi_wmi_platform_hwmon_init(wdev); | |
| 433 | + return msi_wmi_platform_hwmon_init(data); | |
| 407 | 434 | } |
| 408 | 435 | |
| 409 | 436 | static const struct wmi_device_id msi_wmi_platform_id_table[] = { |
| @@ -11519,6 +11519,8 @@ static int __must_check __init get_thinkpad_model_data( · 11518 unmodified lines | ||
| 11519 | 11519 | tp->vendor = PCI_VENDOR_ID_IBM; |
| 11520 | 11520 | else if (dmi_name_in_vendors("LENOVO")) |
| 11521 | 11521 | tp->vendor = PCI_VENDOR_ID_LENOVO; |
| 11522 | + else if (dmi_name_in_vendors("NEC")) | |
| 11523 | + tp->vendor = PCI_VENDOR_ID_LENOVO; | |
| 11522 | 11524 | else |
| 11523 | 11525 | return 0; |
| 11524 | 11526 | |
| @@ -179,6 +179,18 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = { · 178 unmodified lines | ||
| 179 | 179 | }, |
| 180 | 180 | .driver_data = (void *)&peaq_c1010_info, |
| 181 | 181 | }, |
| 182 | + { | |
| 183 | + /* Vexia Edu Atla 10 tablet 5V version */ | |
| 184 | + .matches = { | |
| 185 | + /* Having all 3 of these not set is somewhat unique */ | |
| 186 | + DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), | |
| 187 | + DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."), | |
| 188 | + DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."), | |
| 189 | + /* Above strings are too generic, also match on BIOS date */ | |
| 190 | + DMI_MATCH(DMI_BIOS_DATE, "05/14/2015"), | |
| 191 | + }, | |
| 192 | + .driver_data = (void *)&vexia_edu_atla10_5v_info, | |
| 193 | + }, | |
| 182 | 194 | { |
| 183 | 195 | /* Vexia Edu Atla 10 tablet 9V version */ |
| 184 | 196 | .matches = { |
| @@ -187,7 +199,7 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = { · 2 unmodified lines | ||
| 187 | 199 | /* Above strings are too generic, also match on BIOS date */ |
| 188 | 200 | DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), |
| 189 | 201 | }, |
| 190 | − .driver_data = (void *)&vexia_edu_atla10_info, | |
| 202 | + .driver_data = (void *)&vexia_edu_atla10_9v_info, | |
| 191 | 203 | }, |
| 192 | 204 | { |
| 193 | 205 | /* Whitelabel (sold as various brands) TM800A550L */ |
| @@ -599,62 +599,122 @@ const struct x86_dev_info whitelabel_tm800a550l_info __initconst = { · 598 unmodified lines | ||
| 599 | 599 | }; |
| 600 | 600 | |
| 601 | 601 | /* |
| 602 | − * Vexia EDU ATLA 10 tablet, Android 4.2 / 4.4 + Guadalinex Ubuntu tablet | |
| 602 | + * Vexia EDU ATLA 10 tablet 5V, Android 4.4 + Guadalinex Ubuntu tablet | |
| 603 | + * distributed to schools in the Spanish Andalucía region. | |
| 604 | + */ | |
| 605 | +static const struct property_entry vexia_edu_atla10_5v_touchscreen_props[] = { | |
| 606 | + PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000), | |
| 607 | + PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120), | |
| 608 | + { } | |
| 609 | +}; | |
| 610 | + | |
| 611 | +static const struct software_node vexia_edu_atla10_5v_touchscreen_node = { | |
| 612 | + .properties = vexia_edu_atla10_5v_touchscreen_props, | |
| 613 | +}; | |
| 614 | + | |
| 615 | +static const struct x86_i2c_client_info vexia_edu_atla10_5v_i2c_clients[] __initconst = { | |
| 616 | + { | |
| 617 | + /* kxcjk1013 accelerometer */ | |
| 618 | + .board_info = { | |
| 619 | + .type = "kxcjk1013", | |
| 620 | + .addr = 0x0f, | |
| 621 | + .dev_name = "kxcjk1013", | |
| 622 | + }, | |
| 623 | + .adapter_path = "\\_SB_.I2C3", | |
| 624 | + }, { | |
| 625 | + /* touchscreen controller */ | |
| 626 | + .board_info = { | |
| 627 | + .type = "hid-over-i2c", | |
| 628 | + .addr = 0x38, | |
| 629 | + .dev_name = "FTSC1000", | |
| 630 | + .swnode = &vexia_edu_atla10_5v_touchscreen_node, | |
| 631 | + }, | |
| 632 | + .adapter_path = "\\_SB_.I2C4", | |
| 633 | + .irq_data = { | |
| 634 | + .type = X86_ACPI_IRQ_TYPE_APIC, | |
| 635 | + .index = 0x44, | |
| 636 | + .trigger = ACPI_LEVEL_SENSITIVE, | |
| 637 | + .polarity = ACPI_ACTIVE_HIGH, | |
| 638 | + }, | |
| 639 | + } | |
| 640 | +}; | |
| 641 | + | |
| 642 | +static struct gpiod_lookup_table vexia_edu_atla10_5v_ft5416_gpios = { | |
| 643 | + .dev_id = "i2c-FTSC1000", | |
| 644 | + .table = { | |
| 645 | + GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW), | |
| 646 | + { } | |
| 647 | + }, | |
| 648 | +}; | |
| 649 | + | |
| 650 | +static struct gpiod_lookup_table * const vexia_edu_atla10_5v_gpios[] = { | |
| 651 | + &vexia_edu_atla10_5v_ft5416_gpios, | |
| 652 | + NULL | |
| 653 | +}; | |
| 654 | + | |
| 655 | +const struct x86_dev_info vexia_edu_atla10_5v_info __initconst = { | |
| 656 | + .i2c_client_info = vexia_edu_atla10_5v_i2c_clients, | |
| 657 | + .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_5v_i2c_clients), | |
| 658 | + .gpiod_lookup_tables = vexia_edu_atla10_5v_gpios, | |
| 659 | +}; | |
| 660 | + | |
| 661 | +/* | |
| 662 | + * Vexia EDU ATLA 10 tablet 9V, Android 4.2 + Guadalinex Ubuntu tablet | |
| 603 | 663 | * distributed to schools in the Spanish Andalucía region. |
| 604 | 664 | */ |
| 605 | 665 | static const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" }; |
| 606 | 666 | |
| 607 | −static const struct property_entry vexia_edu_atla10_ulpmc_props[] = { | |
| 667 | +static const struct property_entry vexia_edu_atla10_9v_ulpmc_props[] = { | |
| 608 | 668 | PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy), |
| 609 | 669 | { } |
| 610 | 670 | }; |
| 611 | 671 | |
| 612 | −static const struct software_node vexia_edu_atla10_ulpmc_node = { | |
| 613 | − .properties = vexia_edu_atla10_ulpmc_props, | |
| 672 | +static const struct software_node vexia_edu_atla10_9v_ulpmc_node = { | |
| 673 | + .properties = vexia_edu_atla10_9v_ulpmc_props, | |
| 614 | 674 | }; |
| 615 | 675 | |
| 616 | −static const char * const vexia_edu_atla10_accel_mount_matrix[] = { | |
| 676 | +static const char * const vexia_edu_atla10_9v_accel_mount_matrix[] = { | |
| 617 | 677 | "0", "-1", "0", |
| 618 | 678 | "1", "0", "0", |
| 619 | 679 | "0", "0", "1" |
| 620 | 680 | }; |
| 621 | 681 | |
| 622 | −static const struct property_entry vexia_edu_atla10_accel_props[] = { | |
| 623 | − PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_accel_mount_matrix), | |
| 682 | +static const struct property_entry vexia_edu_atla10_9v_accel_props[] = { | |
| 683 | + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_9v_accel_mount_matrix), | |
| 624 | 684 | { } |
| 625 | 685 | }; |
| 626 | 686 | |
| 627 | −static const struct software_node vexia_edu_atla10_accel_node = { | |
| 628 | − .properties = vexia_edu_atla10_accel_props, | |
| 687 | +static const struct software_node vexia_edu_atla10_9v_accel_node = { | |
| 688 | + .properties = vexia_edu_atla10_9v_accel_props, | |
| 629 | 689 | }; |
| 630 | 690 | |
| 631 | −static const struct property_entry vexia_edu_atla10_touchscreen_props[] = { | |
| 691 | +static const struct property_entry vexia_edu_atla10_9v_touchscreen_props[] = { | |
| 632 | 692 | PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000), |
| 633 | 693 | PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120), |
| 634 | 694 | { } |
| 635 | 695 | }; |
| 636 | 696 | |
| 637 | −static const struct software_node vexia_edu_atla10_touchscreen_node = { | |
| 638 | − .properties = vexia_edu_atla10_touchscreen_props, | |
| 697 | +static const struct software_node vexia_edu_atla10_9v_touchscreen_node = { | |
| 698 | + .properties = vexia_edu_atla10_9v_touchscreen_props, | |
| 639 | 699 | }; |
| 640 | 700 | |
| 641 | −static const struct property_entry vexia_edu_atla10_pmic_props[] = { | |
| 701 | +static const struct property_entry vexia_edu_atla10_9v_pmic_props[] = { | |
| 642 | 702 | PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"), |
| 643 | 703 | { } |
| 644 | 704 | }; |
| 645 | 705 | |
| 646 | −static const struct software_node vexia_edu_atla10_pmic_node = { | |
| 647 | − .properties = vexia_edu_atla10_pmic_props, | |
| 706 | +static const struct software_node vexia_edu_atla10_9v_pmic_node = { | |
| 707 | + .properties = vexia_edu_atla10_9v_pmic_props, | |
| 648 | 708 | }; |
| 649 | 709 | |
| 650 | −static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initconst = { | |
| 710 | +static const struct x86_i2c_client_info vexia_edu_atla10_9v_i2c_clients[] __initconst = { | |
| 651 | 711 | { |
| 652 | 712 | /* I2C attached embedded controller, used to access fuel-gauge */ |
| 653 | 713 | .board_info = { |
| 654 | 714 | .type = "vexia_atla10_ec", |
| 655 | 715 | .addr = 0x76, |
| 656 | 716 | .dev_name = "ulpmc", |
| 657 | − .swnode = &vexia_edu_atla10_ulpmc_node, | |
| 717 | + .swnode = &vexia_edu_atla10_9v_ulpmc_node, | |
| 658 | 718 | }, |
| 659 | 719 | .adapter_path = "0000:00:18.1", |
| 660 | 720 | }, { |
| @@ -679,7 +739,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon · 18 unmodified lines | ||
| 679 | 739 | .type = "kxtj21009", |
| 680 | 740 | .addr = 0x0f, |
| 681 | 741 | .dev_name = "kxtj21009", |
| 682 | − .swnode = &vexia_edu_atla10_accel_node, | |
| 742 | + .swnode = &vexia_edu_atla10_9v_accel_node, | |
| 683 | 743 | }, |
| 684 | 744 | .adapter_path = "0000:00:18.5", |
| 685 | 745 | }, { |
| @@ -688,7 +748,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon · 2 unmodified lines | ||
| 688 | 748 | .type = "hid-over-i2c", |
| 689 | 749 | .addr = 0x38, |
| 690 | 750 | .dev_name = "FTSC1000", |
| 691 | − .swnode = &vexia_edu_atla10_touchscreen_node, | |
| 751 | + .swnode = &vexia_edu_atla10_9v_touchscreen_node, | |
| 692 | 752 | }, |
| 693 | 753 | .adapter_path = "0000:00:18.6", |
| 694 | 754 | .irq_data = { |
| @@ -703,7 +763,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon · 8 unmodified lines | ||
| 703 | 763 | .type = "intel_soc_pmic_crc", |
| 704 | 764 | .addr = 0x6e, |
| 705 | 765 | .dev_name = "intel_soc_pmic_crc", |
| 706 | − .swnode = &vexia_edu_atla10_pmic_node, | |
| 766 | + .swnode = &vexia_edu_atla10_9v_pmic_node, | |
| 707 | 767 | }, |
| 708 | 768 | .adapter_path = "0000:00:18.7", |
| 709 | 769 | .irq_data = { |
| @@ -715,7 +775,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon · 5 unmodified lines | ||
| 715 | 775 | } |
| 716 | 776 | }; |
| 717 | 777 | |
| 718 | −static const struct x86_serdev_info vexia_edu_atla10_serdevs[] __initconst = { | |
| 778 | +static const struct x86_serdev_info vexia_edu_atla10_9v_serdevs[] __initconst = { | |
| 719 | 779 | { |
| 720 | 780 | .ctrl.pci.devfn = PCI_DEVFN(0x1e, 3), |
| 721 | 781 | .ctrl_devname = "serial0", |
| @@ -723,7 +783,7 @@ static const struct x86_serdev_info vexia_edu_atla10_serdevs[] __initconst = { · 1 unmodified line | ||
| 723 | 783 | }, |
| 724 | 784 | }; |
| 725 | 785 | |
| 726 | −static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = { | |
| 786 | +static struct gpiod_lookup_table vexia_edu_atla10_9v_ft5416_gpios = { | |
| 727 | 787 | .dev_id = "i2c-FTSC1000", |
| 728 | 788 | .table = { |
| 729 | 789 | GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW), |
| @@ -731,12 +791,12 @@ static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = { · 1 unmodified line | ||
| 731 | 791 | }, |
| 732 | 792 | }; |
| 733 | 793 | |
| 734 | −static struct gpiod_lookup_table * const vexia_edu_atla10_gpios[] = { | |
| 735 | − &vexia_edu_atla10_ft5416_gpios, | |
| 794 | +static struct gpiod_lookup_table * const vexia_edu_atla10_9v_gpios[] = { | |
| 795 | + &vexia_edu_atla10_9v_ft5416_gpios, | |
| 736 | 796 | NULL |
| 737 | 797 | }; |
| 738 | 798 | |
| 739 | −static int __init vexia_edu_atla10_init(struct device *dev) | |
| 799 | +static int __init vexia_edu_atla10_9v_init(struct device *dev) | |
| 740 | 800 | { |
| 741 | 801 | struct pci_dev *pdev; |
| 742 | 802 | int ret; |
| @@ -760,13 +820,13 @@ static int __init vexia_edu_atla10_init(struct device *dev) · 17 unmodified lines | ||
| 760 | 820 | return 0; |
| 761 | 821 | } |
| 762 | 822 | |
| 763 | −const struct x86_dev_info vexia_edu_atla10_info __initconst = { | |
| 764 | − .i2c_client_info = vexia_edu_atla10_i2c_clients, | |
| 765 | − .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_i2c_clients), | |
| 766 | − .serdev_info = vexia_edu_atla10_serdevs, | |
| 767 | − .serdev_count = ARRAY_SIZE(vexia_edu_atla10_serdevs), | |
| 768 | − .gpiod_lookup_tables = vexia_edu_atla10_gpios, | |
| 769 | − .init = vexia_edu_atla10_init, | |
| 823 | +const struct x86_dev_info vexia_edu_atla10_9v_info __initconst = { | |
| 824 | + .i2c_client_info = vexia_edu_atla10_9v_i2c_clients, | |
| 825 | + .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_9v_i2c_clients), | |
| 826 | + .serdev_info = vexia_edu_atla10_9v_serdevs, | |
| 827 | + .serdev_count = ARRAY_SIZE(vexia_edu_atla10_9v_serdevs), | |
| 828 | + .gpiod_lookup_tables = vexia_edu_atla10_9v_gpios, | |
| 829 | + .init = vexia_edu_atla10_9v_init, | |
| 770 | 830 | .use_pci = true, |
| 771 | 831 | }; |
| 772 | 832 | |
| @@ -127,7 +127,8 @@ extern const struct x86_dev_info nextbook_ares8_info; · 126 unmodified lines | ||
| 127 | 127 | extern const struct x86_dev_info nextbook_ares8a_info; |
| 128 | 128 | extern const struct x86_dev_info peaq_c1010_info; |
| 129 | 129 | extern const struct x86_dev_info whitelabel_tm800a550l_info; |
| 130 | −extern const struct x86_dev_info vexia_edu_atla10_info; | |
| 130 | +extern const struct x86_dev_info vexia_edu_atla10_5v_info; | |
| 131 | +extern const struct x86_dev_info vexia_edu_atla10_9v_info; | |
| 131 | 132 | extern const struct x86_dev_info xiaomi_mipad2_info; |
| 132 | 133 | extern const struct dmi_system_id x86_android_tablet_ids[]; |
| 133 | 134 | |
| @@ -36,6 +36,7 @@ struct pmc_ipc_rbuf { · 35 unmodified lines | ||
| 36 | 36 | */ |
| 37 | 37 | static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf *rbuf) |
| 38 | 38 | { |
| 39 | +#ifdef CONFIG_ACPI | |
| 39 | 40 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 40 | 41 | union acpi_object params[PMC_IPCS_PARAM_COUNT] = { |
| 41 | 42 | {.type = ACPI_TYPE_INTEGER,}, |
| @@ -89,6 +90,9 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf · 47 unmodified lines | ||
| 89 | 90 | } |
| 90 | 91 | |
| 91 | 92 | return 0; |
| 93 | +#else | |
| 94 | + return -ENODEV; | |
| 95 | +#endif /* CONFIG_ACPI */ | |
| 92 | 96 | } |
| 93 | 97 | |
| 94 | 98 | #endif /* INTEL_PMC_IPC_H */ |