3
0
Fork 0
forked from mirrors/linux

Merge branch 'fixes' into for-next

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.
This commit is contained in:
Ilpo Järvinen 2025-05-12 00:18:11 +03:00
commit 593ee93aa7
No known key found for this signature in database
GPG key ID: 59AC4F6153E5CE31
25 changed files with 384 additions and 131 deletions

View file

@ -138,6 +138,10 @@ input data, the meaning of which depends on the subfeature being accessed.
The output buffer contains a single byte which signals success or failure (``0x00`` on failure)
and 31 bytes of output data, the meaning if which depends on the subfeature being accessed.
.. note::
The ACPI control method responsible for handling the WMI method calls is not thread-safe.
This is a firmware bug that needs to be handled inside the driver itself.
WMI method Get_EC()
-------------------

View file

@ -333,9 +333,9 @@ static ssize_t secure_boot_fuse_state_show(struct device *dev,
else
status = valid ? "Invalid" : "Free";
}
buf_len += sysfs_emit(buf + buf_len, "%d:%s ", key, status);
buf_len += sysfs_emit_at(buf, buf_len, "%d:%s ", key, status);
}
buf_len += sysfs_emit(buf + buf_len, "\n");
buf_len += sysfs_emit_at(buf, buf_len, "\n");
return buf_len;
}

View file

@ -27,9 +27,8 @@
#include "hsmp.h"
#define DRIVER_NAME "amd_hsmp"
#define DRIVER_NAME "hsmp_acpi"
#define DRIVER_VERSION "2.3"
#define ACPI_HSMP_DEVICE_HID "AMDI0097"
/* These are the strings specified in ACPI table */
#define MSG_IDOFF_STR "MsgIdOffset"

View file

@ -23,6 +23,7 @@
#define HSMP_CDEV_NAME "hsmp_cdev"
#define HSMP_DEVNODE_NAME "hsmp"
#define ACPI_HSMP_DEVICE_HID "AMDI0097"
struct hsmp_mbaddr_info {
u32 base_addr;

View file

@ -11,6 +11,7 @@
#include <asm/amd_hsmp.h>
#include <linux/acpi.h>
#include <linux/build_bug.h>
#include <linux/device.h>
#include <linux/module.h>
@ -266,7 +267,7 @@ static bool legacy_hsmp_support(void)
}
case 0x1A:
switch (boot_cpu_data.x86_model) {
case 0x00 ... 0x1F:
case 0x00 ... 0x0F:
return true;
default:
return false;
@ -288,6 +289,9 @@ static int __init hsmp_plt_init(void)
return ret;
}
if (acpi_dev_present(ACPI_HSMP_DEVICE_HID, NULL, -1))
return -ENODEV;
hsmp_pdev = get_hsmp_pdev();
if (!hsmp_pdev)
return -ENOMEM;

View file

@ -217,6 +217,13 @@ static const struct dmi_system_id fwbug_list[] = {
DMI_MATCH(DMI_BIOS_VERSION, "03.05"),
}
},
{
.ident = "MECHREVO Wujie 14X (GX4HRXL)",
.driver_data = &quirk_spurious_8042,
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"),
}
},
{}
};

View file

@ -644,10 +644,9 @@ static void amd_pmc_s2idle_check(void)
struct smu_metrics table;
int rc;
/* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */
if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) &&
table.s0i3_last_entry_status)
usleep_range(10000, 20000);
/* Avoid triggering OVP */
if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status)
msleep(2500);
/* Dump the IdleMask before we add to the STB */
amd_pmc_idlemask_read(pdev, pdev->dev, NULL);

View file

@ -120,9 +120,9 @@ static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx,
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL);
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
pwr_ctrl->stt_skin_temp[STT_TEMP_APU], NULL);
fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_APU]), NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
pwr_ctrl->stt_skin_temp[STT_TEMP_HS2], NULL);
fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_HS2]), NULL);
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
apmf_update_fan_idx(dev, config_store.mode_set[idx].fan_control.manual,

View file

@ -81,10 +81,10 @@ static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx,
amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL);
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL);
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU],
NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2],
NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_APU]), NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_HS2]), NULL);
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
apmf_update_fan_idx(dev,

View file

@ -176,6 +176,20 @@ static void __maybe_unused amd_pmf_dump_registers(struct amd_pmf_dev *dev)
dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value);
}
/**
* fixp_q88_fromint: Convert integer to Q8.8
* @val: input value
*
* Converts an integer into binary fixed point format where 8 bits
* are used for integer and 8 bits are used for the decimal.
*
* Return: unsigned integer converted to Q8.8 format
*/
u32 fixp_q88_fromint(u32 val)
{
return val << 8;
}
int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data)
{
int rc;

View file

@ -777,6 +777,7 @@ int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag);
int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer);
int amd_pmf_notify_sbios_heartbeat_event_v2(struct amd_pmf_dev *dev, u8 flag);
u32 fixp_q88_fromint(u32 val);
/* SPS Layer */
int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);

View file

@ -198,9 +198,11 @@ static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx)
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
apts_config_store.val[idx].stt_min_limit, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
apts_config_store.val[idx].stt_skin_temp_limit_apu, NULL);
fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_apu),
NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
apts_config_store.val[idx].stt_skin_temp_limit_hs2, NULL);
fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_hs2),
NULL);
}
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,
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
config_store.prop[src][idx].stt_min, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL);
fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU]),
NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL);
fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2]),
NULL);
} else if (op == SLIDER_OP_GET) {
amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl);
amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt);

View file

@ -123,7 +123,8 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_STT_SKINTEMP_APU:
if (dev->prev_data->stt_skintemp_apu != val) {
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, val, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
fixp_q88_fromint(val), NULL);
dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val);
dev->prev_data->stt_skintemp_apu = val;
}
@ -131,7 +132,8 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_STT_SKINTEMP_HS2:
if (dev->prev_data->stt_skintemp_hs2 != val) {
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, val, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
fixp_q88_fromint(val), NULL);
dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val);
dev->prev_data->stt_skintemp_hs2 = val;
}
@ -332,6 +334,11 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)
return 0;
}
static inline bool amd_pmf_pb_valid(struct amd_pmf_dev *dev)
{
return memchr_inv(dev->policy_buf, 0xff, dev->policy_sz);
}
#ifdef CONFIG_AMD_PMF_DEBUG
static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev)
{
@ -359,12 +366,22 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf,
dev->policy_buf = new_policy_buf;
dev->policy_sz = length;
if (!amd_pmf_pb_valid(dev)) {
ret = -EINVAL;
goto cleanup;
}
amd_pmf_hex_dump_pb(dev);
ret = amd_pmf_start_policy_engine(dev);
if (ret < 0)
return ret;
goto cleanup;
return length;
cleanup:
kfree(dev->policy_buf);
dev->policy_buf = NULL;
return ret;
}
static const struct file_operations pb_fops = {
@ -526,6 +543,12 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz);
if (!amd_pmf_pb_valid(dev)) {
dev_info(dev->dev, "No Smart PC policy present\n");
ret = -EINVAL;
goto err_free_policy;
}
amd_pmf_hex_dump_pb(dev);
dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL);

View file

@ -426,11 +426,14 @@ static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable)
static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)
{
unsigned long long val = (unsigned long long)curr;
acpi_status status;
int i, delta;
unsigned long long val;
for (i = 0; i < PEGA_ACC_RETRIES; i++) {
acpi_evaluate_integer(asus->handle, method, NULL, &val);
for (i = 0; i < PEGA_ACC_RETRIES; i++) {
status = acpi_evaluate_integer(asus->handle, method, NULL, &val);
if (ACPI_FAILURE(status))
continue;
/* The output is noisy. From reading the ASL
* dissassembly, timeout errors are returned with 1's
* in the high word, and the lack of locking around

View file

@ -305,6 +305,7 @@ struct asus_wmi {
u32 kbd_rgb_dev;
bool kbd_rgb_state_available;
bool oobe_state_available;
u8 throttle_thermal_policy_mode;
u32 throttle_thermal_policy_dev;
@ -1868,7 +1869,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
goto error;
}
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE)) {
if (asus->oobe_state_available) {
/*
* Disable OOBE state, so that e.g. the keyboard backlight
* works.
@ -4780,6 +4781,7 @@ static int asus_wmi_add(struct platform_device *pdev)
asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE);
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))
asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
@ -4832,7 +4834,8 @@ static int asus_wmi_add(struct platform_device *pdev)
goto fail_leds;
asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result);
if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))
if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) ==
(ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))
asus->driver->wlan_ctrl_by_user = 1;
if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) {
@ -4997,6 +5000,13 @@ static int asus_hotk_restore(struct device *device)
}
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
kbd_led_update(asus);
if (asus->oobe_state_available) {
/*
* Disable OOBE state, so that e.g. the keyboard backlight
* works.
*/
asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL);
}
if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus);

View file

@ -89,12 +89,44 @@ static struct awcc_quirks generic_quirks = {
static struct awcc_quirks empty_quirks;
static const struct dmi_system_id awcc_dmi_table[] __initconst = {
{
.ident = "Alienware Area-51m R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware Area-51m R2"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware m15 R7",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m15 R7"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware m16 R1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Alienware m16 R1 AMD",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Alienware m16 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R2"),
},
.driver_data = &generic_quirks,
},
{
@ -121,6 +153,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware x15 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R2"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware x17 R2",
.matches = {
@ -153,6 +193,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G16 7630",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Dell G16 7630"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G3 3500",
.matches = {
@ -177,6 +225,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G5 5505",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "G5 5505"),
},
.driver_data = &g_series_quirks,
},
};
enum AWCC_GET_FAN_SENSORS_OPERATIONS {
@ -1241,14 +1297,14 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
for (unsigned int i = 0; i < priv->profile_count; i++) {
ret = awcc_op_get_resource_id(priv->wdev, i + offset, &id);
if (ret == -EIO)
return ret;
/*
* Some devices report an incorrect number of thermal profiles
* so the resource ID list may end prematurely
*/
if (ret == -EBADRQC)
break;
if (ret)
return ret;
if (!is_awcc_thermal_profile_id(id)) {
dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id);

View file

@ -1294,6 +1294,16 @@ static const struct key_entry ideapad_keymap[] = {
/* Specific to some newer models */
{ KE_KEY, 0x3e | IDEAPAD_WMI_KEY, { KEY_MICMUTE } },
{ KE_KEY, 0x3f | IDEAPAD_WMI_KEY, { KEY_RFKILL } },
/* Star- (User Assignable Key) */
{ KE_KEY, 0x44 | IDEAPAD_WMI_KEY, { KEY_PROG1 } },
/* Eye */
{ KE_KEY, 0x45 | IDEAPAD_WMI_KEY, { KEY_PROG3 } },
/* Performance toggle also Fn+Q, handled inside ideapad_wmi_notify() */
{ KE_KEY, 0x3d | IDEAPAD_WMI_KEY, { KEY_PROG4 } },
/* shift + prtsc */
{ KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_CUT } },
{ KE_KEY, 0x29 | IDEAPAD_WMI_KEY, { KEY_TOUCHPAD_TOGGLE } },
{ KE_KEY, 0x2a | IDEAPAD_WMI_KEY, { KEY_ROOT_MENU } },
{ KE_END },
};
@ -2080,6 +2090,12 @@ static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data)
dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n",
data->integer.value);
/* performance button triggered by 0x3d */
if (data->integer.value == 0x3d && priv->dytc) {
platform_profile_cycle();
break;
}
/* 0x02 FnLock, 0x03 Esc */
if (data->integer.value == 0x02 || data->integer.value == 0x03)
ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02);

View file

@ -44,16 +44,17 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex Hung");
static const struct acpi_device_id intel_hid_ids[] = {
{"INT33D5", 0},
{"INTC1051", 0},
{"INTC1054", 0},
{"INTC1070", 0},
{"INTC1076", 0},
{"INTC1077", 0},
{"INTC1078", 0},
{"INTC107B", 0},
{"INTC10CB", 0},
{"", 0},
{ "INT33D5" },
{ "INTC1051" },
{ "INTC1054" },
{ "INTC1070" },
{ "INTC1076" },
{ "INTC1077" },
{ "INTC1078" },
{ "INTC107B" },
{ "INTC10CB" },
{ "INTC10CC" },
{ }
};
MODULE_DEVICE_TABLE(acpi, intel_hid_ids);

View file

@ -146,15 +146,13 @@ static int uncore_event_cpu_online(unsigned int cpu)
{
struct uncore_data *data;
int target;
int ret;
/* Check if there is an online cpu in the package for uncore MSR */
target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu));
if (target < nr_cpu_ids)
return 0;
/* Use this CPU on this die as a control CPU */
cpumask_set_cpu(cpu, &uncore_cpu_mask);
data = uncore_get_instance(cpu);
if (!data)
return 0;
@ -163,7 +161,14 @@ static int uncore_event_cpu_online(unsigned int cpu)
data->die_id = topology_die_id(cpu);
data->domain_id = UNCORE_DOMAIN_ID_INVALID;
return uncore_freq_add_entry(data, cpu);
ret = uncore_freq_add_entry(data, cpu);
if (ret)
return ret;
/* Use this CPU on this die as a control CPU */
cpumask_set_cpu(cpu, &uncore_cpu_mask);
return 0;
}
static int uncore_event_cpu_offline(unsigned int cpu)

View file

@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/device/driver.h>
@ -17,6 +18,7 @@
#include <linux/hwmon.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/printk.h>
#include <linux/rwsem.h>
#include <linux/types.h>
@ -76,8 +78,13 @@ enum msi_wmi_platform_method {
MSI_PLATFORM_GET_WMI = 0x1d,
};
struct msi_wmi_platform_debugfs_data {
struct msi_wmi_platform_data {
struct wmi_device *wdev;
struct mutex wmi_lock; /* Necessary when calling WMI methods */
};
struct msi_wmi_platform_debugfs_data {
struct msi_wmi_platform_data *data;
enum msi_wmi_platform_method method;
struct rw_semaphore buffer_lock; /* Protects debugfs buffer */
size_t length;
@ -132,8 +139,9 @@ static int msi_wmi_platform_parse_buffer(union acpi_object *obj, u8 *output, siz
return 0;
}
static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform_method method,
u8 *input, size_t input_length, u8 *output, size_t output_length)
static int msi_wmi_platform_query(struct msi_wmi_platform_data *data,
enum msi_wmi_platform_method method, u8 *input,
size_t input_length, u8 *output, size_t output_length)
{
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer in = {
@ -147,9 +155,15 @@ static int msi_wmi_platform_query(struct wmi_device *wdev, enum msi_wmi_platform
if (!input_length || !output_length)
return -EINVAL;
status = wmidev_evaluate_method(wdev, 0x0, method, &in, &out);
if (ACPI_FAILURE(status))
return -EIO;
/*
* The ACPI control method responsible for handling the WMI method calls
* is not thread-safe. Because of this we have to do the locking ourself.
*/
scoped_guard(mutex, &data->wmi_lock) {
status = wmidev_evaluate_method(data->wdev, 0x0, method, &in, &out);
if (ACPI_FAILURE(status))
return -EIO;
}
obj = out.pointer;
if (!obj)
@ -170,22 +184,22 @@ static umode_t msi_wmi_platform_is_visible(const void *drvdata, enum hwmon_senso
static int msi_wmi_platform_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct wmi_device *wdev = dev_get_drvdata(dev);
struct msi_wmi_platform_data *data = dev_get_drvdata(dev);
u8 input[32] = { 0 };
u8 output[32];
u16 data;
u16 value;
int ret;
ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_FAN, input, sizeof(input), output,
ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_FAN, input, sizeof(input), output,
sizeof(output));
if (ret < 0)
return ret;
data = get_unaligned_be16(&output[channel * 2 + 1]);
if (!data)
value = get_unaligned_be16(&output[channel * 2 + 1]);
if (!value)
*val = 0;
else
*val = 480000 / data;
*val = 480000 / value;
return 0;
}
@ -231,7 +245,7 @@ static ssize_t msi_wmi_platform_write(struct file *fp, const char __user *input,
return ret;
down_write(&data->buffer_lock);
ret = msi_wmi_platform_query(data->wdev, data->method, payload, data->length, data->buffer,
ret = msi_wmi_platform_query(data->data, data->method, payload, data->length, data->buffer,
data->length);
up_write(&data->buffer_lock);
@ -277,17 +291,17 @@ static void msi_wmi_platform_debugfs_remove(void *data)
debugfs_remove_recursive(dir);
}
static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry *dir,
static void msi_wmi_platform_debugfs_add(struct msi_wmi_platform_data *drvdata, struct dentry *dir,
const char *name, enum msi_wmi_platform_method method)
{
struct msi_wmi_platform_debugfs_data *data;
struct dentry *entry;
data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
data = devm_kzalloc(&drvdata->wdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return;
data->wdev = wdev;
data->data = drvdata;
data->method = method;
init_rwsem(&data->buffer_lock);
@ -298,82 +312,82 @@ static void msi_wmi_platform_debugfs_add(struct wmi_device *wdev, struct dentry
entry = debugfs_create_file(name, 0600, dir, data, &msi_wmi_platform_debugfs_fops);
if (IS_ERR(entry))
devm_kfree(&wdev->dev, data);
devm_kfree(&drvdata->wdev->dev, data);
}
static void msi_wmi_platform_debugfs_init(struct wmi_device *wdev)
static void msi_wmi_platform_debugfs_init(struct msi_wmi_platform_data *data)
{
struct dentry *dir;
char dir_name[64];
int ret, method;
scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev));
scnprintf(dir_name, ARRAY_SIZE(dir_name), "%s-%s", DRIVER_NAME, dev_name(&data->wdev->dev));
dir = debugfs_create_dir(dir_name, NULL);
if (IS_ERR(dir))
return;
ret = devm_add_action_or_reset(&wdev->dev, msi_wmi_platform_debugfs_remove, dir);
ret = devm_add_action_or_reset(&data->wdev->dev, msi_wmi_platform_debugfs_remove, dir);
if (ret < 0)
return;
for (method = MSI_PLATFORM_GET_PACKAGE; method <= MSI_PLATFORM_GET_WMI; method++)
msi_wmi_platform_debugfs_add(wdev, dir, msi_wmi_platform_debugfs_names[method - 1],
msi_wmi_platform_debugfs_add(data, dir, msi_wmi_platform_debugfs_names[method - 1],
method);
}
static int msi_wmi_platform_hwmon_init(struct wmi_device *wdev)
static int msi_wmi_platform_hwmon_init(struct msi_wmi_platform_data *data)
{
struct device *hdev;
hdev = devm_hwmon_device_register_with_info(&wdev->dev, "msi_wmi_platform", wdev,
hdev = devm_hwmon_device_register_with_info(&data->wdev->dev, "msi_wmi_platform", data,
&msi_wmi_platform_chip_info, NULL);
return PTR_ERR_OR_ZERO(hdev);
}
static int msi_wmi_platform_ec_init(struct wmi_device *wdev)
static int msi_wmi_platform_ec_init(struct msi_wmi_platform_data *data)
{
u8 input[32] = { 0 };
u8 output[32];
u8 flags;
int ret;
ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_EC, input, sizeof(input), output,
ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_EC, input, sizeof(input), output,
sizeof(output));
if (ret < 0)
return ret;
flags = output[MSI_PLATFORM_EC_FLAGS_OFFSET];
dev_dbg(&wdev->dev, "EC RAM version %lu.%lu\n",
dev_dbg(&data->wdev->dev, "EC RAM version %lu.%lu\n",
FIELD_GET(MSI_PLATFORM_EC_MAJOR_MASK, flags),
FIELD_GET(MSI_PLATFORM_EC_MINOR_MASK, flags));
dev_dbg(&wdev->dev, "EC firmware version %.28s\n",
dev_dbg(&data->wdev->dev, "EC firmware version %.28s\n",
&output[MSI_PLATFORM_EC_VERSION_OFFSET]);
if (!(flags & MSI_PLATFORM_EC_IS_TIGERLAKE)) {
if (!force)
return -ENODEV;
dev_warn(&wdev->dev, "Loading on a non-Tigerlake platform\n");
dev_warn(&data->wdev->dev, "Loading on a non-Tigerlake platform\n");
}
return 0;
}
static int msi_wmi_platform_init(struct wmi_device *wdev)
static int msi_wmi_platform_init(struct msi_wmi_platform_data *data)
{
u8 input[32] = { 0 };
u8 output[32];
int ret;
ret = msi_wmi_platform_query(wdev, MSI_PLATFORM_GET_WMI, input, sizeof(input), output,
ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_WMI, input, sizeof(input), output,
sizeof(output));
if (ret < 0)
return ret;
dev_dbg(&wdev->dev, "WMI interface version %u.%u\n",
dev_dbg(&data->wdev->dev, "WMI interface version %u.%u\n",
output[MSI_PLATFORM_WMI_MAJOR_OFFSET],
output[MSI_PLATFORM_WMI_MINOR_OFFSET]);
@ -381,7 +395,8 @@ static int msi_wmi_platform_init(struct wmi_device *wdev)
if (!force)
return -ENODEV;
dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u.%u)\n",
dev_warn(&data->wdev->dev,
"Loading despite unsupported WMI interface version (%u.%u)\n",
output[MSI_PLATFORM_WMI_MAJOR_OFFSET],
output[MSI_PLATFORM_WMI_MINOR_OFFSET]);
}
@ -391,19 +406,31 @@ static int msi_wmi_platform_init(struct wmi_device *wdev)
static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context)
{
struct msi_wmi_platform_data *data;
int ret;
ret = msi_wmi_platform_init(wdev);
data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->wdev = wdev;
dev_set_drvdata(&wdev->dev, data);
ret = devm_mutex_init(&wdev->dev, &data->wmi_lock);
if (ret < 0)
return ret;
ret = msi_wmi_platform_ec_init(wdev);
ret = msi_wmi_platform_init(data);
if (ret < 0)
return ret;
msi_wmi_platform_debugfs_init(wdev);
ret = msi_wmi_platform_ec_init(data);
if (ret < 0)
return ret;
return msi_wmi_platform_hwmon_init(wdev);
msi_wmi_platform_debugfs_init(data);
return msi_wmi_platform_hwmon_init(data);
}
static const struct wmi_device_id msi_wmi_platform_id_table[] = {

View file

@ -11519,6 +11519,8 @@ static int __must_check __init get_thinkpad_model_data(
tp->vendor = PCI_VENDOR_ID_IBM;
else if (dmi_name_in_vendors("LENOVO"))
tp->vendor = PCI_VENDOR_ID_LENOVO;
else if (dmi_name_in_vendors("NEC"))
tp->vendor = PCI_VENDOR_ID_LENOVO;
else
return 0;

View file

@ -179,6 +179,18 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
},
.driver_data = (void *)&peaq_c1010_info,
},
{
/* Vexia Edu Atla 10 tablet 5V version */
.matches = {
/* Having all 3 of these not set is somewhat unique */
DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),
DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."),
/* Above strings are too generic, also match on BIOS date */
DMI_MATCH(DMI_BIOS_DATE, "05/14/2015"),
},
.driver_data = (void *)&vexia_edu_atla10_5v_info,
},
{
/* Vexia Edu Atla 10 tablet 9V version */
.matches = {
@ -187,7 +199,7 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
/* Above strings are too generic, also match on BIOS date */
DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
},
.driver_data = (void *)&vexia_edu_atla10_info,
.driver_data = (void *)&vexia_edu_atla10_9v_info,
},
{
/* Whitelabel (sold as various brands) TM800A550L */

View file

@ -599,62 +599,122 @@ const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
};
/*
* Vexia EDU ATLA 10 tablet, Android 4.2 / 4.4 + Guadalinex Ubuntu tablet
* Vexia EDU ATLA 10 tablet 5V, Android 4.4 + Guadalinex Ubuntu tablet
* distributed to schools in the Spanish Andalucía region.
*/
static const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" };
static const struct property_entry vexia_edu_atla10_ulpmc_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
{ }
};
static const struct software_node vexia_edu_atla10_ulpmc_node = {
.properties = vexia_edu_atla10_ulpmc_props,
};
static const char * const vexia_edu_atla10_accel_mount_matrix[] = {
"0", "-1", "0",
"1", "0", "0",
"0", "0", "1"
};
static const struct property_entry vexia_edu_atla10_accel_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_accel_mount_matrix),
{ }
};
static const struct software_node vexia_edu_atla10_accel_node = {
.properties = vexia_edu_atla10_accel_props,
};
static const struct property_entry vexia_edu_atla10_touchscreen_props[] = {
static const struct property_entry vexia_edu_atla10_5v_touchscreen_props[] = {
PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
{ }
};
static const struct software_node vexia_edu_atla10_touchscreen_node = {
.properties = vexia_edu_atla10_touchscreen_props,
static const struct software_node vexia_edu_atla10_5v_touchscreen_node = {
.properties = vexia_edu_atla10_5v_touchscreen_props,
};
static const struct property_entry vexia_edu_atla10_pmic_props[] = {
static const struct x86_i2c_client_info vexia_edu_atla10_5v_i2c_clients[] __initconst = {
{
/* kxcjk1013 accelerometer */
.board_info = {
.type = "kxcjk1013",
.addr = 0x0f,
.dev_name = "kxcjk1013",
},
.adapter_path = "\\_SB_.I2C3",
}, {
/* touchscreen controller */
.board_info = {
.type = "hid-over-i2c",
.addr = 0x38,
.dev_name = "FTSC1000",
.swnode = &vexia_edu_atla10_5v_touchscreen_node,
},
.adapter_path = "\\_SB_.I2C4",
.irq_data = {
.type = X86_ACPI_IRQ_TYPE_APIC,
.index = 0x44,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
},
}
};
static struct gpiod_lookup_table vexia_edu_atla10_5v_ft5416_gpios = {
.dev_id = "i2c-FTSC1000",
.table = {
GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
{ }
},
};
static struct gpiod_lookup_table * const vexia_edu_atla10_5v_gpios[] = {
&vexia_edu_atla10_5v_ft5416_gpios,
NULL
};
const struct x86_dev_info vexia_edu_atla10_5v_info __initconst = {
.i2c_client_info = vexia_edu_atla10_5v_i2c_clients,
.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_5v_i2c_clients),
.gpiod_lookup_tables = vexia_edu_atla10_5v_gpios,
};
/*
* Vexia EDU ATLA 10 tablet 9V, Android 4.2 + Guadalinex Ubuntu tablet
* distributed to schools in the Spanish Andalucía region.
*/
static const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" };
static const struct property_entry vexia_edu_atla10_9v_ulpmc_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
{ }
};
static const struct software_node vexia_edu_atla10_9v_ulpmc_node = {
.properties = vexia_edu_atla10_9v_ulpmc_props,
};
static const char * const vexia_edu_atla10_9v_accel_mount_matrix[] = {
"0", "-1", "0",
"1", "0", "0",
"0", "0", "1"
};
static const struct property_entry vexia_edu_atla10_9v_accel_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_9v_accel_mount_matrix),
{ }
};
static const struct software_node vexia_edu_atla10_9v_accel_node = {
.properties = vexia_edu_atla10_9v_accel_props,
};
static const struct property_entry vexia_edu_atla10_9v_touchscreen_props[] = {
PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
{ }
};
static const struct software_node vexia_edu_atla10_9v_touchscreen_node = {
.properties = vexia_edu_atla10_9v_touchscreen_props,
};
static const struct property_entry vexia_edu_atla10_9v_pmic_props[] = {
PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"),
{ }
};
static const struct software_node vexia_edu_atla10_pmic_node = {
.properties = vexia_edu_atla10_pmic_props,
static const struct software_node vexia_edu_atla10_9v_pmic_node = {
.properties = vexia_edu_atla10_9v_pmic_props,
};
static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initconst = {
static const struct x86_i2c_client_info vexia_edu_atla10_9v_i2c_clients[] __initconst = {
{
/* I2C attached embedded controller, used to access fuel-gauge */
.board_info = {
.type = "vexia_atla10_ec",
.addr = 0x76,
.dev_name = "ulpmc",
.swnode = &vexia_edu_atla10_ulpmc_node,
.swnode = &vexia_edu_atla10_9v_ulpmc_node,
},
.adapter_path = "0000:00:18.1",
}, {
@ -679,7 +739,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
.type = "kxtj21009",
.addr = 0x0f,
.dev_name = "kxtj21009",
.swnode = &vexia_edu_atla10_accel_node,
.swnode = &vexia_edu_atla10_9v_accel_node,
},
.adapter_path = "0000:00:18.5",
}, {
@ -688,7 +748,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
.type = "hid-over-i2c",
.addr = 0x38,
.dev_name = "FTSC1000",
.swnode = &vexia_edu_atla10_touchscreen_node,
.swnode = &vexia_edu_atla10_9v_touchscreen_node,
},
.adapter_path = "0000:00:18.6",
.irq_data = {
@ -703,7 +763,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
.type = "intel_soc_pmic_crc",
.addr = 0x6e,
.dev_name = "intel_soc_pmic_crc",
.swnode = &vexia_edu_atla10_pmic_node,
.swnode = &vexia_edu_atla10_9v_pmic_node,
},
.adapter_path = "0000:00:18.7",
.irq_data = {
@ -715,7 +775,7 @@ static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initcon
}
};
static const struct x86_serdev_info vexia_edu_atla10_serdevs[] __initconst = {
static const struct x86_serdev_info vexia_edu_atla10_9v_serdevs[] __initconst = {
{
.ctrl.pci.devfn = PCI_DEVFN(0x1e, 3),
.ctrl_devname = "serial0",
@ -723,7 +783,7 @@ static const struct x86_serdev_info vexia_edu_atla10_serdevs[] __initconst = {
},
};
static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = {
static struct gpiod_lookup_table vexia_edu_atla10_9v_ft5416_gpios = {
.dev_id = "i2c-FTSC1000",
.table = {
GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW),
@ -731,12 +791,12 @@ static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = {
},
};
static struct gpiod_lookup_table * const vexia_edu_atla10_gpios[] = {
&vexia_edu_atla10_ft5416_gpios,
static struct gpiod_lookup_table * const vexia_edu_atla10_9v_gpios[] = {
&vexia_edu_atla10_9v_ft5416_gpios,
NULL
};
static int __init vexia_edu_atla10_init(struct device *dev)
static int __init vexia_edu_atla10_9v_init(struct device *dev)
{
struct pci_dev *pdev;
int ret;
@ -760,13 +820,13 @@ static int __init vexia_edu_atla10_init(struct device *dev)
return 0;
}
const struct x86_dev_info vexia_edu_atla10_info __initconst = {
.i2c_client_info = vexia_edu_atla10_i2c_clients,
.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_i2c_clients),
.serdev_info = vexia_edu_atla10_serdevs,
.serdev_count = ARRAY_SIZE(vexia_edu_atla10_serdevs),
.gpiod_lookup_tables = vexia_edu_atla10_gpios,
.init = vexia_edu_atla10_init,
const struct x86_dev_info vexia_edu_atla10_9v_info __initconst = {
.i2c_client_info = vexia_edu_atla10_9v_i2c_clients,
.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_9v_i2c_clients),
.serdev_info = vexia_edu_atla10_9v_serdevs,
.serdev_count = ARRAY_SIZE(vexia_edu_atla10_9v_serdevs),
.gpiod_lookup_tables = vexia_edu_atla10_9v_gpios,
.init = vexia_edu_atla10_9v_init,
.use_pci = true,
};

View file

@ -127,7 +127,8 @@ extern const struct x86_dev_info nextbook_ares8_info;
extern const struct x86_dev_info nextbook_ares8a_info;
extern const struct x86_dev_info peaq_c1010_info;
extern const struct x86_dev_info whitelabel_tm800a550l_info;
extern const struct x86_dev_info vexia_edu_atla10_info;
extern const struct x86_dev_info vexia_edu_atla10_5v_info;
extern const struct x86_dev_info vexia_edu_atla10_9v_info;
extern const struct x86_dev_info xiaomi_mipad2_info;
extern const struct dmi_system_id x86_android_tablet_ids[];

View file

@ -36,6 +36,7 @@ struct pmc_ipc_rbuf {
*/
static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf *rbuf)
{
#ifdef CONFIG_ACPI
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object params[PMC_IPCS_PARAM_COUNT] = {
{.type = ACPI_TYPE_INTEGER,},
@ -89,6 +90,9 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
}
return 0;
#else
return -ENODEV;
#endif /* CONFIG_ACPI */
}
#endif /* INTEL_PMC_IPC_H */