From da5ce22df5fe5cbaf0e86d0357728b224c0b1b0e Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:39 +0530 Subject: platform/x86/amd/pmf: Add support for PMF core layer PMF core layer is meant to abstract the common functionalities across PMF features. This layer also does the plumbing work like setting up the mailbox channel for the communication between the PMF driver and the PMFW (Power Management Firmware) running on the SMU. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-2-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/Kconfig | 2 + drivers/platform/x86/amd/Makefile | 1 + drivers/platform/x86/amd/pmf/Kconfig | 15 +++ drivers/platform/x86/amd/pmf/Makefile | 8 ++ drivers/platform/x86/amd/pmf/core.c | 235 ++++++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/pmf.h | 46 +++++++ 6 files changed, 307 insertions(+) create mode 100644 drivers/platform/x86/amd/pmf/Kconfig create mode 100644 drivers/platform/x86/amd/pmf/Makefile create mode 100644 drivers/platform/x86/amd/pmf/core.c create mode 100644 drivers/platform/x86/amd/pmf/pmf.h (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/Kconfig b/drivers/platform/x86/amd/Kconfig index c0d0a3c5170c..a825af8126c8 100644 --- a/drivers/platform/x86/amd/Kconfig +++ b/drivers/platform/x86/amd/Kconfig @@ -3,6 +3,8 @@ # AMD x86 Platform Specific Drivers # +source "drivers/platform/x86/amd/pmf/Kconfig" + config AMD_PMC tristate "AMD SoC PMC driver" depends on ACPI && PCI && RTC_CLASS diff --git a/drivers/platform/x86/amd/Makefile b/drivers/platform/x86/amd/Makefile index a03fbb08e808..2c229198e24c 100644 --- a/drivers/platform/x86/amd/Makefile +++ b/drivers/platform/x86/amd/Makefile @@ -8,3 +8,4 @@ amd-pmc-y := pmc.o obj-$(CONFIG_AMD_PMC) += amd-pmc.o amd_hsmp-y := hsmp.o obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o +obj-$(CONFIG_AMD_PMF) += pmf/ diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig new file mode 100644 index 000000000000..e65ffa52229b --- /dev/null +++ b/drivers/platform/x86/amd/pmf/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# AMD PMF Driver +# + +config AMD_PMF + tristate "AMD Platform Management Framework" + depends on ACPI && PCI + help + This driver provides support for the AMD Platform Management Framework. + The goal is to enhance end user experience by making AMD PCs smarter, + quiter, power efficient by adapting to user behavior and environment. + + To compile this driver as a module, choose M here: the module will + be called amd_pmf. diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile new file mode 100644 index 000000000000..459005f659e5 --- /dev/null +++ b/drivers/platform/x86/amd/pmf/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for linux/drivers/platform/x86/amd/pmf +# AMD Platform Management Framework +# + +obj-$(CONFIG_AMD_PMF) += amd-pmf.o +amd-pmf-objs := core.o diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c new file mode 100644 index 000000000000..aef97965c181 --- /dev/null +++ b/drivers/platform/x86/amd/pmf/core.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Platform Management Framework Driver + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Shyam Sundar S K + */ + +#include +#include +#include +#include +#include "pmf.h" + +/* PMF-SMU communication registers */ +#define AMD_PMF_REGISTER_MESSAGE 0xA18 +#define AMD_PMF_REGISTER_RESPONSE 0xA78 +#define AMD_PMF_REGISTER_ARGUMENT 0xA58 + +/* Base address of SMU for mapping physical address to virtual address */ +#define AMD_PMF_SMU_INDEX_ADDRESS 0xB8 +#define AMD_PMF_SMU_INDEX_DATA 0xBC +#define AMD_PMF_MAPPING_SIZE 0x01000 +#define AMD_PMF_BASE_ADDR_OFFSET 0x10000 +#define AMD_PMF_BASE_ADDR_LO 0x13B102E8 +#define AMD_PMF_BASE_ADDR_HI 0x13B102EC +#define AMD_PMF_BASE_ADDR_LO_MASK GENMASK(15, 0) +#define AMD_PMF_BASE_ADDR_HI_MASK GENMASK(31, 20) + +/* SMU Response Codes */ +#define AMD_PMF_RESULT_OK 0x01 +#define AMD_PMF_RESULT_CMD_REJECT_BUSY 0xFC +#define AMD_PMF_RESULT_CMD_REJECT_PREREQ 0xFD +#define AMD_PMF_RESULT_CMD_UNKNOWN 0xFE +#define AMD_PMF_RESULT_FAILED 0xFF + +/* List of supported CPU ids */ +#define AMD_CPU_ID_PS 0x14e8 + +#define PMF_MSG_DELAY_MIN_US 50 +#define RESPONSE_REGISTER_LOOP_MAX 20000 + +#define DELAY_MIN_US 2000 +#define DELAY_MAX_US 3000 + +static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset) +{ + return ioread32(dev->regbase + reg_offset); +} + +static inline void amd_pmf_reg_write(struct amd_pmf_dev *dev, int reg_offset, u32 val) +{ + iowrite32(val, dev->regbase + reg_offset); +} + +static void __maybe_unused amd_pmf_dump_registers(struct amd_pmf_dev *dev) +{ + u32 value; + + value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_RESPONSE); + dev_dbg(dev->dev, "AMD_PMF_REGISTER_RESPONSE:%x\n", value); + + value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT); + dev_dbg(dev->dev, "AMD_PMF_REGISTER_ARGUMENT:%d\n", value); + + value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_MESSAGE); + dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value); +} + +int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data) +{ + int rc; + u32 val; + + mutex_lock(&dev->lock); + + /* Wait until we get a valid response */ + rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE, + val, val != 0, PMF_MSG_DELAY_MIN_US, + PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); + if (rc) { + dev_err(dev->dev, "failed to talk to SMU\n"); + goto out_unlock; + } + + /* Write zero to response register */ + amd_pmf_reg_write(dev, AMD_PMF_REGISTER_RESPONSE, 0); + + /* Write argument into argument register */ + amd_pmf_reg_write(dev, AMD_PMF_REGISTER_ARGUMENT, arg); + + /* Write message ID to message ID register */ + amd_pmf_reg_write(dev, AMD_PMF_REGISTER_MESSAGE, message); + + /* Wait until we get a valid response */ + rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE, + val, val != 0, PMF_MSG_DELAY_MIN_US, + PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); + if (rc) { + dev_err(dev->dev, "SMU response timed out\n"); + goto out_unlock; + } + + switch (val) { + case AMD_PMF_RESULT_OK: + if (get) { + /* PMFW may take longer time to return back the data */ + usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US); + *data = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT); + } + break; + case AMD_PMF_RESULT_CMD_REJECT_BUSY: + dev_err(dev->dev, "SMU not ready. err: 0x%x\n", val); + rc = -EBUSY; + goto out_unlock; + case AMD_PMF_RESULT_CMD_UNKNOWN: + dev_err(dev->dev, "SMU cmd unknown. err: 0x%x\n", val); + rc = -EINVAL; + goto out_unlock; + case AMD_PMF_RESULT_CMD_REJECT_PREREQ: + case AMD_PMF_RESULT_FAILED: + default: + dev_err(dev->dev, "SMU cmd failed. err: 0x%x\n", val); + rc = -EIO; + goto out_unlock; + } + +out_unlock: + mutex_unlock(&dev->lock); + amd_pmf_dump_registers(dev); + return rc; +} + +static const struct pci_device_id pmf_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) }, + { } +}; + +static const struct acpi_device_id amd_pmf_acpi_ids[] = { + {"AMDI0102", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids); + +static int amd_pmf_probe(struct platform_device *pdev) +{ + struct amd_pmf_dev *dev; + struct pci_dev *rdev; + u32 base_addr_lo; + u32 base_addr_hi; + u64 base_addr; + u32 val; + int err; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->dev = &pdev->dev; + + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); + if (!rdev || !pci_match_id(pmf_pci_ids, rdev)) { + pci_dev_put(rdev); + return -ENODEV; + } + + dev->cpu_id = rdev->device; + err = pci_write_config_dword(rdev, AMD_PMF_SMU_INDEX_ADDRESS, AMD_PMF_BASE_ADDR_LO); + if (err) { + dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMF_SMU_INDEX_ADDRESS); + pci_dev_put(rdev); + return pcibios_err_to_errno(err); + } + + err = pci_read_config_dword(rdev, AMD_PMF_SMU_INDEX_DATA, &val); + if (err) { + pci_dev_put(rdev); + return pcibios_err_to_errno(err); + } + + base_addr_lo = val & AMD_PMF_BASE_ADDR_HI_MASK; + + err = pci_write_config_dword(rdev, AMD_PMF_SMU_INDEX_ADDRESS, AMD_PMF_BASE_ADDR_HI); + if (err) { + dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMF_SMU_INDEX_ADDRESS); + pci_dev_put(rdev); + return pcibios_err_to_errno(err); + } + + err = pci_read_config_dword(rdev, AMD_PMF_SMU_INDEX_DATA, &val); + if (err) { + pci_dev_put(rdev); + return pcibios_err_to_errno(err); + } + + base_addr_hi = val & AMD_PMF_BASE_ADDR_LO_MASK; + pci_dev_put(rdev); + base_addr = ((u64)base_addr_hi << 32 | base_addr_lo); + + dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMF_BASE_ADDR_OFFSET, + AMD_PMF_MAPPING_SIZE); + if (!dev->regbase) + return -ENOMEM; + + platform_set_drvdata(pdev, dev); + + mutex_init(&dev->lock); + dev_info(dev->dev, "registered PMF device successfully\n"); + + return 0; +} + +static int amd_pmf_remove(struct platform_device *pdev) +{ + struct amd_pmf_dev *dev = platform_get_drvdata(pdev); + + mutex_destroy(&dev->lock); + kfree(dev->buf); + return 0; +} + +static struct platform_driver amd_pmf_driver = { + .driver = { + .name = "amd-pmf", + .acpi_match_table = amd_pmf_acpi_ids, + }, + .probe = amd_pmf_probe, + .remove = amd_pmf_remove, +}; +module_platform_driver(amd_pmf_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Platform Management Framework Driver"); diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h new file mode 100644 index 000000000000..1c2e942e5096 --- /dev/null +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AMD Platform Management Framework Driver + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Shyam Sundar S K + */ + +#ifndef PMF_H +#define PMF_H + +/* Message Definitions */ +#define SET_SPL 0x03 /* SPL: Sustained Power Limit */ +#define SET_SPPT 0x05 /* SPPT: Slow Package Power Tracking */ +#define SET_FPPT 0x07 /* FPPT: Fast Package Power Tracking */ +#define GET_SPL 0x0B +#define GET_SPPT 0x0D +#define GET_FPPT 0x0F +#define SET_DRAM_ADDR_HIGH 0x14 +#define SET_DRAM_ADDR_LOW 0x15 +#define SET_TRANSFER_TABLE 0x16 +#define SET_STT_MIN_LIMIT 0x18 /* STT: Skin Temperature Tracking */ +#define SET_STT_LIMIT_APU 0x19 +#define SET_STT_LIMIT_HS2 0x1A +#define SET_SPPT_APU_ONLY 0x1D +#define GET_SPPT_APU_ONLY 0x1E +#define GET_STT_MIN_LIMIT 0x1F +#define GET_STT_LIMIT_APU 0x20 +#define GET_STT_LIMIT_HS2 0x21 + +struct amd_pmf_dev { + void __iomem *regbase; + void __iomem *smu_virt_addr; + void *buf; + u32 base_addr; + u32 cpu_id; + struct device *dev; + struct mutex lock; /* protects the PMF interface */ +}; + +/* Core Layer */ +int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data); + +#endif /* PMF_H */ -- cgit v1.2.3 From 5eb315ebf47b605cb9364da40a9363ad4065014b Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:40 +0530 Subject: platform/x86/amd/pmf: Add support for PMF APCI layer PMF driver implements the ACPI methods as defined by AMD for PMF Support. The ACPI layer acts as a glue that helps in providing the infrastructure for OEMs customization. OEMs can refer to PMF support documentation to decide on the list of functions to be supported on their specific platform model. AMD mandates that PMF ACPI fn0 and fn1 to be implemented which provides the set of functions, params and the notifications that would be sent to PMF driver so that PMF driver can adapt and react. Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-3-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/Makefile | 2 +- drivers/platform/x86/amd/pmf/acpi.c | 151 ++++++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/core.c | 1 + drivers/platform/x86/amd/pmf/pmf.h | 23 ++++++ 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/x86/amd/pmf/acpi.c (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile index 459005f659e5..2617eba773ce 100644 --- a/drivers/platform/x86/amd/pmf/Makefile +++ b/drivers/platform/x86/amd/pmf/Makefile @@ -5,4 +5,4 @@ # obj-$(CONFIG_AMD_PMF) += amd-pmf.o -amd-pmf-objs := core.o +amd-pmf-objs := core.o acpi.o diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c new file mode 100644 index 000000000000..b378f9e31194 --- /dev/null +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Platform Management Framework Driver + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Shyam Sundar S K + */ + +#include +#include "pmf.h" + +static union acpi_object *apmf_if_call(struct amd_pmf_dev *pdev, int fn, struct acpi_buffer *param) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_handle ahandle = ACPI_HANDLE(pdev->dev); + struct acpi_object_list apmf_if_arg_list; + union acpi_object apmf_if_args[2]; + acpi_status status; + + apmf_if_arg_list.count = 2; + apmf_if_arg_list.pointer = &apmf_if_args[0]; + + apmf_if_args[0].type = ACPI_TYPE_INTEGER; + apmf_if_args[0].integer.value = fn; + + if (param) { + apmf_if_args[1].type = ACPI_TYPE_BUFFER; + apmf_if_args[1].buffer.length = param->length; + apmf_if_args[1].buffer.pointer = param->pointer; + } else { + apmf_if_args[1].type = ACPI_TYPE_INTEGER; + apmf_if_args[1].integer.value = 0; + } + + status = acpi_evaluate_object(ahandle, "APMF", &apmf_if_arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(pdev->dev, "APMF method:%d call failed\n", fn); + kfree(buffer.pointer); + return NULL; + } + + return buffer.pointer; +} + +static int apmf_if_call_store_buffer(struct amd_pmf_dev *pdev, int fn, void *dest, size_t out_sz) +{ + union acpi_object *info; + size_t size; + int err = 0; + + info = apmf_if_call(pdev, fn, NULL); + if (!info) + return -EIO; + + if (info->type != ACPI_TYPE_BUFFER) { + dev_err(pdev->dev, "object is not a buffer\n"); + err = -EINVAL; + goto out; + } + + if (info->buffer.length < 2) { + dev_err(pdev->dev, "buffer too small\n"); + err = -EINVAL; + goto out; + } + + size = *(u16 *)info->buffer.pointer; + if (info->buffer.length < size) { + dev_err(pdev->dev, "buffer smaller then headersize %u < %zu\n", + info->buffer.length, size); + err = -EINVAL; + goto out; + } + + if (size < out_sz) { + dev_err(pdev->dev, "buffer too small %zu\n", size); + err = -EINVAL; + goto out; + } + + memcpy(dest, info->buffer.pointer, out_sz); + +out: + kfree(info); + return err; +} + +int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index) +{ + /* If bit-n is set, that indicates function n+1 is supported */ + return !!(pdev->supported_func & BIT(index - 1)); +} + +static int apmf_if_verify_interface(struct amd_pmf_dev *pdev) +{ + struct apmf_verify_interface output; + int err; + + err = apmf_if_call_store_buffer(pdev, APMF_FUNC_VERIFY_INTERFACE, &output, sizeof(output)); + if (err) + return err; + + pdev->supported_func = output.supported_functions; + dev_dbg(pdev->dev, "supported functions:0x%x notifications:0x%x\n", + output.supported_functions, output.notification_mask); + + return 0; +} + +static int apmf_get_system_params(struct amd_pmf_dev *dev) +{ + struct apmf_system_params params; + int err; + + if (!is_apmf_func_supported(dev, APMF_FUNC_GET_SYS_PARAMS)) + return -EINVAL; + + err = apmf_if_call_store_buffer(dev, APMF_FUNC_GET_SYS_PARAMS, ¶ms, sizeof(params)); + if (err) + return err; + + dev_dbg(dev->dev, "system params mask:0x%x flags:0x%x cmd_code:0x%x\n", + params.valid_mask, + params.flags, + params.command_code); + params.flags = params.flags & params.valid_mask; + + return 0; +} + +int apmf_acpi_init(struct amd_pmf_dev *pmf_dev) +{ + int ret; + + ret = apmf_if_verify_interface(pmf_dev); + if (ret) { + dev_err(pmf_dev->dev, "APMF verify interface failed :%d\n", ret); + goto out; + } + + ret = apmf_get_system_params(pmf_dev); + if (ret) { + dev_err(pmf_dev->dev, "APMF apmf_get_system_params failed :%d\n", ret); + goto out; + } + +out: + return ret; +} diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index aef97965c181..c5002b7bb904 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -204,6 +204,7 @@ static int amd_pmf_probe(struct platform_device *pdev) if (!dev->regbase) return -ENOMEM; + apmf_acpi_init(dev); platform_set_drvdata(pdev, dev); mutex_init(&dev->lock); diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 1c2e942e5096..bdadbff168ee 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -11,6 +11,12 @@ #ifndef PMF_H #define PMF_H +#include + +/* APMF Functions */ +#define APMF_FUNC_VERIFY_INTERFACE 0 +#define APMF_FUNC_GET_SYS_PARAMS 1 + /* Message Definitions */ #define SET_SPL 0x03 /* SPL: Sustained Power Limit */ #define SET_SPPT 0x05 /* SPPT: Slow Package Power Tracking */ @@ -30,6 +36,21 @@ #define GET_STT_LIMIT_APU 0x20 #define GET_STT_LIMIT_HS2 0x21 +/* AMD PMF BIOS interfaces */ +struct apmf_verify_interface { + u16 size; + u16 version; + u32 notification_mask; + u32 supported_functions; +} __packed; + +struct apmf_system_params { + u16 size; + u32 valid_mask; + u32 flags; + u8 command_code; +} __packed; + struct amd_pmf_dev { void __iomem *regbase; void __iomem *smu_virt_addr; @@ -38,9 +59,11 @@ struct amd_pmf_dev { u32 cpu_id; struct device *dev; struct mutex lock; /* protects the PMF interface */ + u32 supported_func; }; /* Core Layer */ +int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data); #endif /* PMF_H */ -- cgit v1.2.3 From 4c71ae4144746eb467f6aaab0ff83e306f11d6af Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:41 +0530 Subject: platform/x86/amd/pmf: Add support SPS PMF feature SPS (a.k.a. Static Power Slider) gives a feel of Windows performance power slider for the Linux users, where the user selects a certain mode (like "balanced", "low-power" or "performance") and the thermals associated with each selected mode gets applied from the silicon side via the mailboxes defined through PMFW. PMF driver hooks to platform_profile by reading the PMF ACPI fn9 to see if the support is being advertised by ACPI interface. If supported, the PMF driver reacts to platform_profile selection choices made by the user and adjust the system thermal behavior. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-4-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/Makefile | 2 +- drivers/platform/x86/amd/pmf/acpi.c | 10 +++ drivers/platform/x86/amd/pmf/core.c | 26 +++++++ drivers/platform/x86/amd/pmf/pmf.h | 63 +++++++++++++++ drivers/platform/x86/amd/pmf/sps.c | 143 ++++++++++++++++++++++++++++++++++ 5 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/x86/amd/pmf/sps.c (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile index 2617eba773ce..557521a80427 100644 --- a/drivers/platform/x86/amd/pmf/Makefile +++ b/drivers/platform/x86/amd/pmf/Makefile @@ -5,4 +5,4 @@ # obj-$(CONFIG_AMD_PMF) += amd-pmf.o -amd-pmf-objs := core.o acpi.o +amd-pmf-objs := core.o acpi.o sps.o diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index b378f9e31194..5997ab724f3a 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -93,6 +93,16 @@ int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index) return !!(pdev->supported_func & BIT(index - 1)); } +int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev, + struct apmf_static_slider_granular_output *data) +{ + if (!is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) + return -EINVAL; + + return apmf_if_call_store_buffer(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR, + data, sizeof(*data)); +} + static int apmf_if_verify_interface(struct amd_pmf_dev *pdev) { struct apmf_verify_interface output; diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index c5002b7bb904..a70ab6c9608a 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "pmf.h" /* PMF-SMU communication registers */ @@ -45,6 +46,14 @@ #define DELAY_MIN_US 2000 #define DELAY_MAX_US 3000 +int amd_pmf_get_power_source(void) +{ + if (power_supply_is_system_supplied() > 0) + return POWER_SOURCE_AC; + else + return POWER_SOURCE_DC; +} + static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset) { return ioread32(dev->regbase + reg_offset); @@ -138,6 +147,21 @@ static const struct pci_device_id pmf_pci_ids[] = { { } }; +static void amd_pmf_init_features(struct amd_pmf_dev *dev) +{ + /* Enable Static Slider */ + if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { + amd_pmf_init_sps(dev); + dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n"); + } +} + +static void amd_pmf_deinit_features(struct amd_pmf_dev *dev) +{ + if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) + amd_pmf_deinit_sps(dev); +} + static const struct acpi_device_id amd_pmf_acpi_ids[] = { {"AMDI0102", 0}, { } @@ -206,6 +230,7 @@ static int amd_pmf_probe(struct platform_device *pdev) apmf_acpi_init(dev); platform_set_drvdata(pdev, dev); + amd_pmf_init_features(dev); mutex_init(&dev->lock); dev_info(dev->dev, "registered PMF device successfully\n"); @@ -218,6 +243,7 @@ static int amd_pmf_remove(struct platform_device *pdev) struct amd_pmf_dev *dev = platform_get_drvdata(pdev); mutex_destroy(&dev->lock); + amd_pmf_deinit_features(dev); kfree(dev->buf); return 0; } diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index bdadbff168ee..fa3ea103b54a 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -12,10 +12,12 @@ #define PMF_H #include +#include /* APMF Functions */ #define APMF_FUNC_VERIFY_INTERFACE 0 #define APMF_FUNC_GET_SYS_PARAMS 1 +#define APMF_FUNC_STATIC_SLIDER_GRANULAR 9 /* Message Definitions */ #define SET_SPL 0x03 /* SPL: Sustained Power Limit */ @@ -36,6 +38,8 @@ #define GET_STT_LIMIT_APU 0x20 #define GET_STT_LIMIT_HS2 0x21 +#define ARG_NONE 0 + /* AMD PMF BIOS interfaces */ struct apmf_verify_interface { u16 size; @@ -51,6 +55,30 @@ struct apmf_system_params { u8 command_code; } __packed; +enum amd_stt_skin_temp { + STT_TEMP_APU, + STT_TEMP_HS2, + STT_TEMP_COUNT, +}; + +enum amd_slider_op { + SLIDER_OP_GET, + SLIDER_OP_SET, +}; + +enum power_source { + POWER_SOURCE_AC, + POWER_SOURCE_DC, + POWER_SOURCE_MAX, +}; + +enum power_modes { + POWER_MODE_PERFORMANCE, + POWER_MODE_BALANCED_POWER, + POWER_MODE_POWER_SAVER, + POWER_MODE_MAX, +}; + struct amd_pmf_dev { void __iomem *regbase; void __iomem *smu_virt_addr; @@ -60,10 +88,45 @@ struct amd_pmf_dev { struct device *dev; struct mutex lock; /* protects the PMF interface */ u32 supported_func; + enum platform_profile_option current_profile; + struct platform_profile_handler pprof; +}; + +struct apmf_sps_prop_granular { + u32 fppt; + u32 sppt; + u32 sppt_apu_only; + u32 spl; + u32 stt_min; + u8 stt_skin_temp[STT_TEMP_COUNT]; + u32 fan_id; +} __packed; + +/* Static Slider */ +struct apmf_static_slider_granular_output { + u16 size; + struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX * POWER_MODE_MAX]; +} __packed; + +struct amd_pmf_static_slider_granular { + u16 size; + struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX][POWER_MODE_MAX]; }; /* Core Layer */ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); +int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index); int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data); +int amd_pmf_get_power_source(void); + +/* SPS Layer */ +u8 amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf); +void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, + struct amd_pmf_static_slider_granular *table); +int amd_pmf_init_sps(struct amd_pmf_dev *dev); +void amd_pmf_deinit_sps(struct amd_pmf_dev *dev); +int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev, + struct apmf_static_slider_granular_output *output); + #endif /* PMF_H */ diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c new file mode 100644 index 000000000000..8923e29cc6ca --- /dev/null +++ b/drivers/platform/x86/amd/pmf/sps.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Platform Management Framework (PMF) Driver + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Shyam Sundar S K + */ + +#include "pmf.h" + +static struct amd_pmf_static_slider_granular config_store; + +static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev) +{ + struct apmf_static_slider_granular_output output; + int i, j, idx = 0; + + memset(&config_store, 0, sizeof(config_store)); + apmf_get_static_slider_granular(dev, &output); + + for (i = 0; i < POWER_SOURCE_MAX; i++) { + for (j = 0; j < POWER_MODE_MAX; j++) { + config_store.prop[i][j].spl = output.prop[idx].spl; + config_store.prop[i][j].sppt = output.prop[idx].sppt; + config_store.prop[i][j].sppt_apu_only = + output.prop[idx].sppt_apu_only; + config_store.prop[i][j].fppt = output.prop[idx].fppt; + config_store.prop[i][j].stt_min = output.prop[idx].stt_min; + config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] = + output.prop[idx].stt_skin_temp[STT_TEMP_APU]; + config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] = + output.prop[idx].stt_skin_temp[STT_TEMP_HS2]; + config_store.prop[i][j].fan_id = output.prop[idx].fan_id; + idx++; + } + } +} + +void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, + struct amd_pmf_static_slider_granular *table) +{ + int src = amd_pmf_get_power_source(); + + if (op == SLIDER_OP_SET) { + amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); + amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, + config_store.prop[src][idx].sppt_apu_only, NULL); + 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); + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, + 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); + amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); + amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, + &table->prop[src][idx].sppt_apu_only); + amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, + &table->prop[src][idx].stt_min); + amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, + (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); + amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, + (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); + } +} + +static int amd_pmf_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) +{ + struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); + + *profile = pmf->current_profile; + return 0; +} + +u8 amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) +{ + u8 mode; + + switch (pmf->current_profile) { + case PLATFORM_PROFILE_PERFORMANCE: + mode = POWER_MODE_PERFORMANCE; + break; + case PLATFORM_PROFILE_BALANCED: + mode = POWER_MODE_BALANCED_POWER; + break; + case PLATFORM_PROFILE_LOW_POWER: + mode = POWER_MODE_POWER_SAVER; + break; + default: + dev_err(pmf->dev, "Unknown Platform Profile.\n"); + break; + } + + return mode; +} + +static int amd_pmf_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) +{ + struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); + u8 mode; + + pmf->current_profile = profile; + mode = amd_pmf_get_pprof_modes(pmf); + amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); + return 0; +} + +int amd_pmf_init_sps(struct amd_pmf_dev *dev) +{ + int err; + + dev->current_profile = PLATFORM_PROFILE_BALANCED; + amd_pmf_load_defaults_sps(dev); + + dev->pprof.profile_get = amd_pmf_profile_get; + dev->pprof.profile_set = amd_pmf_profile_set; + + /* Setup supported modes */ + set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices); + set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices); + set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices); + + /* Create platform_profile structure and register */ + err = platform_profile_register(&dev->pprof); + if (err) + dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n", + err); + + return err; +} + +void amd_pmf_deinit_sps(struct amd_pmf_dev *dev) +{ + platform_profile_remove(); +} -- cgit v1.2.3 From 4dc491c898fb47406423547da4d1e1ef8ff36b3e Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:42 +0530 Subject: platform/x86/amd/pmf: Add debugfs information Add debugfs support to the PMF driver so that using this interface the live counters from the PMFW can be queried to see if the power parameters are getting set properly when a certain power mode change happens. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-5-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/core.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/pmf.h | 1 + 2 files changed, 37 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index a70ab6c9608a..032d9dc5e09f 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -8,6 +8,7 @@ * Author: Shyam Sundar S K */ +#include #include #include #include @@ -46,6 +47,39 @@ #define DELAY_MIN_US 2000 #define DELAY_MAX_US 3000 +static int current_power_limits_show(struct seq_file *seq, void *unused) +{ + struct amd_pmf_dev *dev = seq->private; + struct amd_pmf_static_slider_granular table; + int mode, src = 0; + + mode = amd_pmf_get_pprof_modes(dev); + src = amd_pmf_get_power_source(); + amd_pmf_update_slider(dev, SLIDER_OP_GET, mode, &table); + seq_printf(seq, "spl:%u fppt:%u sppt:%u sppt_apu_only:%u stt_min:%u stt[APU]:%u stt[HS2]: %u\n", + table.prop[src][mode].spl, + table.prop[src][mode].fppt, + table.prop[src][mode].sppt, + table.prop[src][mode].sppt_apu_only, + table.prop[src][mode].stt_min, + table.prop[src][mode].stt_skin_temp[STT_TEMP_APU], + table.prop[src][mode].stt_skin_temp[STT_TEMP_HS2]); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(current_power_limits); + +static void amd_pmf_dbgfs_unregister(struct amd_pmf_dev *dev) +{ + debugfs_remove_recursive(dev->dbgfs_dir); +} + +static void amd_pmf_dbgfs_register(struct amd_pmf_dev *dev) +{ + dev->dbgfs_dir = debugfs_create_dir("amd_pmf", NULL); + debugfs_create_file("current_power_limits", 0644, dev->dbgfs_dir, dev, + ¤t_power_limits_fops); +} + int amd_pmf_get_power_source(void) { if (power_supply_is_system_supplied() > 0) @@ -231,6 +265,7 @@ static int amd_pmf_probe(struct platform_device *pdev) apmf_acpi_init(dev); platform_set_drvdata(pdev, dev); amd_pmf_init_features(dev); + amd_pmf_dbgfs_register(dev); mutex_init(&dev->lock); dev_info(dev->dev, "registered PMF device successfully\n"); @@ -244,6 +279,7 @@ static int amd_pmf_remove(struct platform_device *pdev) mutex_destroy(&dev->lock); amd_pmf_deinit_features(dev); + amd_pmf_dbgfs_unregister(dev); kfree(dev->buf); return 0; } diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index fa3ea103b54a..8b25fd19e473 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -90,6 +90,7 @@ struct amd_pmf_dev { u32 supported_func; enum platform_profile_option current_profile; struct platform_profile_handler pprof; + struct dentry *dbgfs_dir; }; struct apmf_sps_prop_granular { -- cgit v1.2.3 From b9ab888b4eccfd9b90835d6d95459aec7382564d Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:43 +0530 Subject: platform/x86/amd/pmf: Add heartbeat signal support PMF driver can send periodic heartbeat signals to OEM BIOS. When BIOS does not receive the signal after a period of time, it can infer that AMDPMF has hung or failed to load. In this situation, BIOS can fallback to legacy operations. OEM can modify the time interval of the signal or completely disable signals through ACPI Method. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-6-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/acpi.c | 34 ++++++++++++++++++++++++++++++++-- drivers/platform/x86/amd/pmf/core.c | 1 + drivers/platform/x86/amd/pmf/pmf.h | 5 +++++ 3 files changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index 5997ab724f3a..6af0e23257ea 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -103,6 +103,22 @@ int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev, data, sizeof(*data)); } +static void apmf_sbios_heartbeat_notify(struct work_struct *work) +{ + struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, heart_beat.work); + union acpi_object *info; + + dev_dbg(dev->dev, "Sending heartbeat to SBIOS\n"); + info = apmf_if_call(dev, APMF_FUNC_SBIOS_HEARTBEAT, NULL); + if (!info) + goto out; + + schedule_delayed_work(&dev->heart_beat, msecs_to_jiffies(dev->hb_interval * 1000)); + +out: + kfree(info); +} + static int apmf_if_verify_interface(struct amd_pmf_dev *pdev) { struct apmf_verify_interface output; @@ -131,15 +147,23 @@ static int apmf_get_system_params(struct amd_pmf_dev *dev) if (err) return err; - dev_dbg(dev->dev, "system params mask:0x%x flags:0x%x cmd_code:0x%x\n", + dev_dbg(dev->dev, "system params mask:0x%x flags:0x%x cmd_code:0x%x heartbeat:%d\n", params.valid_mask, params.flags, - params.command_code); + params.command_code, + params.heartbeat_int); params.flags = params.flags & params.valid_mask; + dev->hb_interval = params.heartbeat_int; return 0; } +void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev) +{ + if (pmf_dev->hb_interval) + cancel_delayed_work_sync(&pmf_dev->heart_beat); +} + int apmf_acpi_init(struct amd_pmf_dev *pmf_dev) { int ret; @@ -156,6 +180,12 @@ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev) goto out; } + if (pmf_dev->hb_interval) { + /* send heartbeats only if the interval is not zero */ + INIT_DELAYED_WORK(&pmf_dev->heart_beat, apmf_sbios_heartbeat_notify); + schedule_delayed_work(&pmf_dev->heart_beat, 0); + } + out: return ret; } diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index 032d9dc5e09f..87a1f9b27d2c 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -279,6 +279,7 @@ static int amd_pmf_remove(struct platform_device *pdev) mutex_destroy(&dev->lock); amd_pmf_deinit_features(dev); + apmf_acpi_deinit(dev); amd_pmf_dbgfs_unregister(dev); kfree(dev->buf); return 0; diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 8b25fd19e473..e3a21e4e1c9b 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -17,6 +17,7 @@ /* APMF Functions */ #define APMF_FUNC_VERIFY_INTERFACE 0 #define APMF_FUNC_GET_SYS_PARAMS 1 +#define APMF_FUNC_SBIOS_HEARTBEAT 4 #define APMF_FUNC_STATIC_SLIDER_GRANULAR 9 /* Message Definitions */ @@ -53,6 +54,7 @@ struct apmf_system_params { u32 valid_mask; u32 flags; u8 command_code; + u32 heartbeat_int; } __packed; enum amd_stt_skin_temp { @@ -91,6 +93,8 @@ struct amd_pmf_dev { enum platform_profile_option current_profile; struct platform_profile_handler pprof; struct dentry *dbgfs_dir; + int hb_interval; /* SBIOS heartbeat interval */ + struct delayed_work heart_beat; }; struct apmf_sps_prop_granular { @@ -116,6 +120,7 @@ struct amd_pmf_static_slider_granular { /* Core Layer */ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); +void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev); int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index); int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data); int amd_pmf_get_power_source(void); -- cgit v1.2.3 From a3281ec556071bda86964b6cf3ed42ec9f924cd8 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:44 +0530 Subject: platform/x86/amd/pmf: Add fan control support PMF has a generic interface defined via PMF ACPI fn9 for influencing fan policy during mode switch. PMF ACPI fn9 will normally be invoked when AMDPMF needs to change the fan table index for the EC. When AMDPMF is loaded this function will be invoked to change fan speed. OEM can also choose to report the actual fan table index and fan RPM to PMF through OEM structure. This information will be communicated by PMF driver to customer BIOS. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-7-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/acpi.c | 25 +++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/pmf.h | 16 ++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index 6af0e23257ea..1fc4d1400364 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -119,6 +119,31 @@ out: kfree(info); } +int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx) +{ + union acpi_object *info; + struct apmf_fan_idx args; + struct acpi_buffer params; + int err = 0; + + args.size = sizeof(args); + args.fan_ctl_mode = manual; + args.fan_ctl_idx = idx; + + params.length = sizeof(args); + params.pointer = (void *)&args; + + info = apmf_if_call(pdev, APMF_FUNC_SET_FAN_IDX, ¶ms); + if (!info) { + err = -EIO; + goto out; + } + +out: + kfree(info); + return err; +} + static int apmf_if_verify_interface(struct amd_pmf_dev *pdev) { struct apmf_verify_interface output; diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index e3a21e4e1c9b..3c64903d67d3 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -18,6 +18,7 @@ #define APMF_FUNC_VERIFY_INTERFACE 0 #define APMF_FUNC_GET_SYS_PARAMS 1 #define APMF_FUNC_SBIOS_HEARTBEAT 4 +#define APMF_FUNC_SET_FAN_IDX 7 #define APMF_FUNC_STATIC_SLIDER_GRANULAR 9 /* Message Definitions */ @@ -39,6 +40,9 @@ #define GET_STT_LIMIT_APU 0x20 #define GET_STT_LIMIT_HS2 0x21 +/* Fan Index for Auto Mode */ +#define FAN_INDEX_AUTO 0xFFFFFFFF + #define ARG_NONE 0 /* AMD PMF BIOS interfaces */ @@ -57,6 +61,12 @@ struct apmf_system_params { u32 heartbeat_int; } __packed; +struct apmf_fan_idx { + u16 size; + u8 fan_ctl_mode; + u32 fan_ctl_idx; +} __packed; + enum amd_stt_skin_temp { STT_TEMP_APU, STT_TEMP_HS2, @@ -118,6 +128,11 @@ struct amd_pmf_static_slider_granular { struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX][POWER_MODE_MAX]; }; +struct fan_table_control { + bool manual; + unsigned long fan_id; +}; + /* Core Layer */ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev); @@ -135,4 +150,5 @@ int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev, struct apmf_static_slider_granular_output *output); +int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx); #endif /* PMF_H */ -- cgit v1.2.3 From 1a409b35c9956617f9e201120225f230f1695d6e Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:45 +0530 Subject: platform/x86/amd/pmf: Get performance metrics from PMFW PMF driver polls for metrics information from PMFW to understand the system behavior, power consumption etc. This metrics table information will be used the PMF features to tweak the thermal heuristics. The poll duration can also be changed by the user by changing the poll duration time. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-8-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/core.c | 52 +++++++++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/pmf.h | 39 ++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index 87a1f9b27d2c..5f09458abb9c 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -47,6 +47,11 @@ #define DELAY_MIN_US 2000 #define DELAY_MAX_US 3000 +/* override Metrics Table sample size time (in ms) */ +static int metrics_table_loop_ms = 1000; +module_param(metrics_table_loop_ms, int, 0644); +MODULE_PARM_DESC(metrics_table_loop_ms, "Metrics Table sample size time (default = 1000ms)"); + static int current_power_limits_show(struct seq_file *seq, void *unused) { struct amd_pmf_dev *dev = seq->private; @@ -88,6 +93,25 @@ int amd_pmf_get_power_source(void) return POWER_SOURCE_DC; } +static void amd_pmf_get_metrics(struct work_struct *work) +{ + struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, work_buffer.work); + ktime_t time_elapsed_ms; + int socket_power; + + /* Transfer table contents */ + memset(dev->buf, 0, sizeof(dev->m_table)); + amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL); + memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table)); + + time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time; + /* Calculate the avg SoC power consumption */ + socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power; + + dev->start_time = ktime_to_ms(ktime_get()); + schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms)); +} + static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset) { return ioread32(dev->regbase + reg_offset); @@ -181,6 +205,34 @@ static const struct pci_device_id pmf_pci_ids[] = { { } }; +int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) +{ + u64 phys_addr; + u32 hi, low; + + INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics); + + /* Get Metrics Table Address */ + dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL); + if (!dev->buf) + return -ENOMEM; + + phys_addr = virt_to_phys(dev->buf); + hi = phys_addr >> 32; + low = phys_addr & GENMASK(31, 0); + + amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL); + amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL); + + /* + * Start collecting the metrics data after a small delay + * or else, we might end up getting stale values from PMFW. + */ + schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms * 3)); + + return 0; +} + static void amd_pmf_init_features(struct amd_pmf_dev *dev) { /* Enable Static Slider */ diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 3c64903d67d3..09353f3f948d 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -67,6 +67,41 @@ struct apmf_fan_idx { u32 fan_ctl_idx; } __packed; +struct smu_pmf_metrics { + u16 gfxclk_freq; /* in MHz */ + u16 socclk_freq; /* in MHz */ + u16 vclk_freq; /* in MHz */ + u16 dclk_freq; /* in MHz */ + u16 memclk_freq; /* in MHz */ + u16 spare; + u16 gfx_activity; /* in Centi */ + u16 uvd_activity; /* in Centi */ + u16 voltage[2]; /* in mV */ + u16 currents[2]; /* in mA */ + u16 power[2];/* in mW */ + u16 core_freq[8]; /* in MHz */ + u16 core_power[8]; /* in mW */ + u16 core_temp[8]; /* in centi-Celsius */ + u16 l3_freq; /* in MHz */ + u16 l3_temp; /* in centi-Celsius */ + u16 gfx_temp; /* in centi-Celsius */ + u16 soc_temp; /* in centi-Celsius */ + u16 throttler_status; + u16 current_socketpower; /* in mW */ + u16 stapm_orig_limit; /* in W */ + u16 stapm_cur_limit; /* in W */ + u32 apu_power; /* in mW */ + u32 dgpu_power; /* in mW */ + u16 vdd_tdc_val; /* in mA */ + u16 soc_tdc_val; /* in mA */ + u16 vdd_edc_val; /* in mA */ + u16 soc_edcv_al; /* in mA */ + u16 infra_cpu_maxfreq; /* in MHz */ + u16 infra_gfx_maxfreq; /* in MHz */ + u16 skin_temp; /* in centi-Celsius */ + u16 device_state; +} __packed; + enum amd_stt_skin_temp { STT_TEMP_APU, STT_TEMP_HS2, @@ -105,6 +140,9 @@ struct amd_pmf_dev { struct dentry *dbgfs_dir; int hb_interval; /* SBIOS heartbeat interval */ struct delayed_work heart_beat; + struct smu_pmf_metrics m_table; + struct delayed_work work_buffer; + ktime_t start_time; }; struct apmf_sps_prop_granular { @@ -138,6 +176,7 @@ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev); int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index); int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data); +int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev); int amd_pmf_get_power_source(void); /* SPS Layer */ -- cgit v1.2.3 From 3f5571d9952473c183762b801c61c42b9dbe1903 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:46 +0530 Subject: platform/x86/amd/pmf: Add support for Auto mode feature This feature has 3 modes quiet, balanced, performance The objective of this feature is to track the moving average of system power over the time period specified and switch to the subsequent mode. In order to do this, PMF driver will get the moving average of APU power from PMFW and power threshold, time constants, system config parameters from OEM inputs. System power as read by PMF driver from PMFW is the filtered value over the sampling window. Every sampling window, moving average of system power is computed. At the end of the monitoring window, the moving average is compared against the threshold for mode switch for decision making. With AMD managing the system config limits, any mode switch within auto-mode will result in limits of fPPT/sPPT/STAPM or STT being scaled down. When "auto mode" is enabled, the static slider control remains out of the PMF driver, so the platform_profile registration would not happen in PMF driver. The transition to auto-mode only happens when the APMF fn5 is enabled in BIOS, platform_profile set to "balanced" and a AMT (Auto Mode transition) is received. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-9-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/Makefile | 3 +- drivers/platform/x86/amd/pmf/acpi.c | 5 + drivers/platform/x86/amd/pmf/auto-mode.c | 263 +++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/core.c | 9 ++ drivers/platform/x86/amd/pmf/pmf.h | 112 +++++++++++++ 5 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/x86/amd/pmf/auto-mode.c (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile index 557521a80427..ef2b08c9174d 100644 --- a/drivers/platform/x86/amd/pmf/Makefile +++ b/drivers/platform/x86/amd/pmf/Makefile @@ -5,4 +5,5 @@ # obj-$(CONFIG_AMD_PMF) += amd-pmf.o -amd-pmf-objs := core.o acpi.o sps.o +amd-pmf-objs := core.o acpi.o sps.o \ + auto-mode.o diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index 1fc4d1400364..401fee381e90 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -144,6 +144,11 @@ out: return err; } +int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data) +{ + return apmf_if_call_store_buffer(pdev, APMF_FUNC_AUTO_MODE, data, sizeof(*data)); +} + static int apmf_if_verify_interface(struct amd_pmf_dev *pdev) { struct apmf_verify_interface output; diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c new file mode 100644 index 000000000000..ab0628b76f2f --- /dev/null +++ b/drivers/platform/x86/amd/pmf/auto-mode.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Platform Management Framework Driver + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Shyam Sundar S K + */ + +#include +#include +#include "pmf.h" + +static struct auto_mode_mode_config config_store; +static const char *state_as_str(unsigned int state); + +static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx, + struct auto_mode_mode_config *table) +{ + struct power_table_control *pwr_ctrl = &config_store.mode_set[idx].power_control; + + amd_pmf_send_cmd(dev, SET_SPL, false, pwr_ctrl->spl, NULL); + amd_pmf_send_cmd(dev, SET_FPPT, false, pwr_ctrl->fppt, NULL); + amd_pmf_send_cmd(dev, SET_SPPT, false, pwr_ctrl->sppt, NULL); + 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); + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, + 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, + config_store.mode_set[idx].fan_control.fan_id); +} + +static int amd_pmf_get_moving_avg(struct amd_pmf_dev *pdev, int socket_power) +{ + int i, total = 0; + + if (pdev->socket_power_history_idx == -1) { + for (i = 0; i < AVG_SAMPLE_SIZE; i++) + pdev->socket_power_history[i] = socket_power; + } + + pdev->socket_power_history_idx = (pdev->socket_power_history_idx + 1) % AVG_SAMPLE_SIZE; + pdev->socket_power_history[pdev->socket_power_history_idx] = socket_power; + + for (i = 0; i < AVG_SAMPLE_SIZE; i++) + total += pdev->socket_power_history[i]; + + return total / AVG_SAMPLE_SIZE; +} + +void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms) +{ + int avg_power = 0; + bool update = false; + int i, j; + + /* Get the average moving average computed by auto mode algorithm */ + avg_power = amd_pmf_get_moving_avg(dev, socket_power); + + for (i = 0; i < AUTO_TRANSITION_MAX; i++) { + if ((config_store.transition[i].shifting_up && avg_power >= + config_store.transition[i].power_threshold) || + (!config_store.transition[i].shifting_up && avg_power <= + config_store.transition[i].power_threshold)) { + if (config_store.transition[i].timer < + config_store.transition[i].time_constant) + config_store.transition[i].timer += time_elapsed_ms; + } else { + config_store.transition[i].timer = 0; + } + + if (config_store.transition[i].timer >= + config_store.transition[i].time_constant && + !config_store.transition[i].applied) { + config_store.transition[i].applied = true; + update = true; + } else if (config_store.transition[i].timer <= + config_store.transition[i].time_constant && + config_store.transition[i].applied) { + config_store.transition[i].applied = false; + update = true; + } + } + + dev_dbg(dev->dev, "[AUTO_MODE] avg power: %u mW mode: %s\n", avg_power, + state_as_str(config_store.current_mode)); + + if (update) { + for (j = 0; j < AUTO_TRANSITION_MAX; j++) { + /* Apply the mode with highest priority indentified */ + if (config_store.transition[j].applied) { + if (config_store.current_mode != + config_store.transition[j].target_mode) { + config_store.current_mode = + config_store.transition[j].target_mode; + dev_dbg(dev->dev, "[AUTO_MODE] moving to mode:%s\n", + state_as_str(config_store.current_mode)); + amd_pmf_set_automode(dev, config_store.current_mode, NULL); + } + break; + } + } + } +} + +static void amd_pmf_get_power_threshold(void) +{ + config_store.transition[AUTO_TRANSITION_TO_QUIET].power_threshold = + config_store.mode_set[AUTO_BALANCE].power_floor - + config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta; + + config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_threshold = + config_store.mode_set[AUTO_BALANCE].power_floor - + config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta; + + config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_threshold = + config_store.mode_set[AUTO_QUIET].power_floor - + config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta; + + config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_threshold = + config_store.mode_set[AUTO_PERFORMANCE].power_floor - + config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta; +} + +static const char *state_as_str(unsigned int state) +{ + switch (state) { + case AUTO_QUIET: + return "QUIET"; + case AUTO_BALANCE: + return "BALANCED"; + case AUTO_PERFORMANCE_ON_LAP: + return "ON_LAP"; + case AUTO_PERFORMANCE: + return "PERFORMANCE"; + default: + return "Unknown Auto Mode State"; + } +} + +static void amd_pmf_load_defaults_auto_mode(struct amd_pmf_dev *dev) +{ + struct apmf_auto_mode output; + struct power_table_control *pwr_ctrl; + int i; + + apmf_get_auto_mode_def(dev, &output); + /* time constant */ + config_store.transition[AUTO_TRANSITION_TO_QUIET].time_constant = + output.balanced_to_quiet; + config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].time_constant = + output.balanced_to_perf; + config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].time_constant = + output.quiet_to_balanced; + config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].time_constant = + output.perf_to_balanced; + + /* power floor */ + config_store.mode_set[AUTO_QUIET].power_floor = output.pfloor_quiet; + config_store.mode_set[AUTO_BALANCE].power_floor = output.pfloor_balanced; + config_store.mode_set[AUTO_PERFORMANCE].power_floor = output.pfloor_perf; + config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_floor = output.pfloor_perf; + + /* Power delta for mode change */ + config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta = + output.pd_balanced_to_quiet; + config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta = + output.pd_balanced_to_perf; + config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta = + output.pd_quiet_to_balanced; + config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta = + output.pd_perf_to_balanced; + + /* Power threshold */ + amd_pmf_get_power_threshold(); + + /* skin temperature limits */ + pwr_ctrl = &config_store.mode_set[AUTO_QUIET].power_control; + pwr_ctrl->spl = output.spl_quiet; + pwr_ctrl->sppt = output.sppt_quiet; + pwr_ctrl->fppt = output.fppt_quiet; + pwr_ctrl->sppt_apu_only = output.sppt_apu_only_quiet; + pwr_ctrl->stt_min = output.stt_min_limit_quiet; + pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_quiet; + pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_quiet; + + pwr_ctrl = &config_store.mode_set[AUTO_BALANCE].power_control; + pwr_ctrl->spl = output.spl_balanced; + pwr_ctrl->sppt = output.sppt_balanced; + pwr_ctrl->fppt = output.fppt_balanced; + pwr_ctrl->sppt_apu_only = output.sppt_apu_only_balanced; + pwr_ctrl->stt_min = output.stt_min_limit_balanced; + pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_balanced; + pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_balanced; + + pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE].power_control; + pwr_ctrl->spl = output.spl_perf; + pwr_ctrl->sppt = output.sppt_perf; + pwr_ctrl->fppt = output.fppt_perf; + pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf; + pwr_ctrl->stt_min = output.stt_min_limit_perf; + pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf; + pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf; + + pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_control; + pwr_ctrl->spl = output.spl_perf_on_lap; + pwr_ctrl->sppt = output.sppt_perf_on_lap; + pwr_ctrl->fppt = output.fppt_perf_on_lap; + pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf_on_lap; + pwr_ctrl->stt_min = output.stt_min_limit_perf_on_lap; + pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf_on_lap; + pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf_on_lap; + + /* Fan ID */ + config_store.mode_set[AUTO_QUIET].fan_control.fan_id = output.fan_id_quiet; + config_store.mode_set[AUTO_BALANCE].fan_control.fan_id = output.fan_id_balanced; + config_store.mode_set[AUTO_PERFORMANCE].fan_control.fan_id = output.fan_id_perf; + config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].fan_control.fan_id = + output.fan_id_perf; + + config_store.transition[AUTO_TRANSITION_TO_QUIET].target_mode = AUTO_QUIET; + config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode = + AUTO_PERFORMANCE; + config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].target_mode = + AUTO_BALANCE; + config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].target_mode = + AUTO_BALANCE; + + config_store.transition[AUTO_TRANSITION_TO_QUIET].shifting_up = false; + config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].shifting_up = true; + config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].shifting_up = true; + config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].shifting_up = + false; + + for (i = 0 ; i < AUTO_MODE_MAX ; i++) { + if (config_store.mode_set[i].fan_control.fan_id == FAN_INDEX_AUTO) + config_store.mode_set[i].fan_control.manual = false; + else + config_store.mode_set[i].fan_control.manual = true; + } + + /* set to initial default values */ + config_store.current_mode = AUTO_BALANCE; + dev->socket_power_history_idx = -1; +} + +void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev) +{ + cancel_delayed_work_sync(&dev->work_buffer); +} + +void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev) +{ + amd_pmf_load_defaults_auto_mode(dev); + /* update the thermal limits for Automode */ + amd_pmf_set_automode(dev, config_store.current_mode, NULL); + amd_pmf_init_metrics_table(dev); +} diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index 5f09458abb9c..d27560f1ebb7 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -240,12 +240,21 @@ static void amd_pmf_init_features(struct amd_pmf_dev *dev) amd_pmf_init_sps(dev); dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n"); } + + /* Enable Auto Mode */ + if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) { + amd_pmf_init_auto_mode(dev); + dev_dbg(dev->dev, "Auto Mode Init done\n"); + } } static void amd_pmf_deinit_features(struct amd_pmf_dev *dev) { if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) amd_pmf_deinit_sps(dev); + + if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) + amd_pmf_deinit_auto_mode(dev); } static const struct acpi_device_id amd_pmf_acpi_ids[] = { diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 09353f3f948d..5b12784e11b8 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -18,6 +18,7 @@ #define APMF_FUNC_VERIFY_INTERFACE 0 #define APMF_FUNC_GET_SYS_PARAMS 1 #define APMF_FUNC_SBIOS_HEARTBEAT 4 +#define APMF_FUNC_AUTO_MODE 5 #define APMF_FUNC_SET_FAN_IDX 7 #define APMF_FUNC_STATIC_SLIDER_GRANULAR 9 @@ -44,6 +45,7 @@ #define FAN_INDEX_AUTO 0xFFFFFFFF #define ARG_NONE 0 +#define AVG_SAMPLE_SIZE 3 /* AMD PMF BIOS interfaces */ struct apmf_verify_interface { @@ -143,6 +145,8 @@ struct amd_pmf_dev { struct smu_pmf_metrics m_table; struct delayed_work work_buffer; ktime_t start_time; + int socket_power_history[AVG_SAMPLE_SIZE]; + int socket_power_history_idx; }; struct apmf_sps_prop_granular { @@ -171,6 +175,107 @@ struct fan_table_control { unsigned long fan_id; }; +struct power_table_control { + u32 spl; + u32 sppt; + u32 fppt; + u32 sppt_apu_only; + u32 stt_min; + u32 stt_skin_temp[STT_TEMP_COUNT]; + u32 reserved[16]; +}; + +/* Auto Mode Layer */ +enum auto_mode_transition_priority { + AUTO_TRANSITION_TO_PERFORMANCE, /* Any other mode to Performance Mode */ + AUTO_TRANSITION_FROM_QUIET_TO_BALANCE, /* Quiet Mode to Balance Mode */ + AUTO_TRANSITION_TO_QUIET, /* Any other mode to Quiet Mode */ + AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE, /* Performance Mode to Balance Mode */ + AUTO_TRANSITION_MAX, +}; + +enum auto_mode_mode { + AUTO_QUIET, + AUTO_BALANCE, + AUTO_PERFORMANCE_ON_LAP, + AUTO_PERFORMANCE, + AUTO_MODE_MAX, +}; + +struct auto_mode_trans_params { + u32 time_constant; /* minimum time required to switch to next mode */ + u32 power_delta; /* delta power to shift mode */ + u32 power_threshold; + u32 timer; /* elapsed time. if timer > TimeThreshold, it will move to next mode */ + u32 applied; + enum auto_mode_mode target_mode; + u32 shifting_up; +}; + +struct auto_mode_mode_settings { + struct power_table_control power_control; + struct fan_table_control fan_control; + u32 power_floor; +}; + +struct auto_mode_mode_config { + struct auto_mode_trans_params transition[AUTO_TRANSITION_MAX]; + struct auto_mode_mode_settings mode_set[AUTO_MODE_MAX]; + enum auto_mode_mode current_mode; +}; + +struct apmf_auto_mode { + u16 size; + /* time constant */ + u32 balanced_to_perf; + u32 perf_to_balanced; + u32 quiet_to_balanced; + u32 balanced_to_quiet; + /* power floor */ + u32 pfloor_perf; + u32 pfloor_balanced; + u32 pfloor_quiet; + /* Power delta for mode change */ + u32 pd_balanced_to_perf; + u32 pd_perf_to_balanced; + u32 pd_quiet_to_balanced; + u32 pd_balanced_to_quiet; + /* skin temperature limits */ + u8 stt_apu_perf_on_lap; /* CQL ON */ + u8 stt_hs2_perf_on_lap; /* CQL ON */ + u8 stt_apu_perf; + u8 stt_hs2_perf; + u8 stt_apu_balanced; + u8 stt_hs2_balanced; + u8 stt_apu_quiet; + u8 stt_hs2_quiet; + u32 stt_min_limit_perf_on_lap; /* CQL ON */ + u32 stt_min_limit_perf; + u32 stt_min_limit_balanced; + u32 stt_min_limit_quiet; + /* SPL based */ + u32 fppt_perf_on_lap; /* CQL ON */ + u32 sppt_perf_on_lap; /* CQL ON */ + u32 spl_perf_on_lap; /* CQL ON */ + u32 sppt_apu_only_perf_on_lap; /* CQL ON */ + u32 fppt_perf; + u32 sppt_perf; + u32 spl_perf; + u32 sppt_apu_only_perf; + u32 fppt_balanced; + u32 sppt_balanced; + u32 spl_balanced; + u32 sppt_apu_only_balanced; + u32 fppt_quiet; + u32 sppt_quiet; + u32 spl_quiet; + u32 sppt_apu_only_quiet; + /* Fan ID */ + u32 fan_id_perf; + u32 fan_id_balanced; + u32 fan_id_quiet; +} __packed; + /* Core Layer */ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev); @@ -190,4 +295,11 @@ int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev, int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx); + +/* Auto Mode Layer */ +int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data); +void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev); +void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev); +void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms); + #endif /* PMF_H */ -- cgit v1.2.3 From 7d77dcc83adaffacbb9000924a212566170c1257 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:47 +0530 Subject: platform/x86/amd/pmf: Handle AMT and CQL events for Auto mode The transition to auto-mode happens when the PMF driver receives AMT (Auto Mode transition) event. transition logic will reside in the PMF driver but the events would come from other supported drivers[1]. The thermal parameters would vary between when a performance "on-lap" mode is detected and versus when not. The CQL event would get triggered from other drivers, so that PMF driver would adjust the system thermal config based on the ACPI inputs. OEMs can control whether or not to enable AMT or CQL via other supported drivers[1] but the actual transition logic resides in the AMD PMF driver. When an AMT event is received the automatic mode transition RAPL algorithm will run. When a CQL event is received an performance "on-lap" mode will be enabled and thermal parameters will be adjusted accordingly. [1] Link: https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/commit/?h=review-hans&id=755b249250df1b612d982f3b702c831b26ecdf73 Cc: Mario Limonciello Cc: Mark Pearson Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-10-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/acpi.c | 67 ++++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/auto-mode.c | 38 ++++++++++++++++++ drivers/platform/x86/amd/pmf/core.c | 9 +++++ drivers/platform/x86/amd/pmf/pmf.h | 22 +++++++++++ 4 files changed, 136 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index 401fee381e90..cb46a7252414 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -11,6 +11,9 @@ #include #include "pmf.h" +#define APMF_CQL_NOTIFICATION 2 +#define APMF_AMT_NOTIFICATION 3 + static union acpi_object *apmf_if_call(struct amd_pmf_dev *pdev, int fn, struct acpi_buffer *param) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -149,6 +152,48 @@ int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data return apmf_if_call_store_buffer(pdev, APMF_FUNC_AUTO_MODE, data, sizeof(*data)); } +int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req) +{ + return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS, + req, sizeof(*req)); +} + +static void apmf_event_handler(acpi_handle handle, u32 event, void *data) +{ + struct amd_pmf_dev *pmf_dev = data; + struct apmf_sbios_req req; + int ret; + + mutex_lock(&pmf_dev->update_mutex); + ret = apmf_get_sbios_requests(pmf_dev, &req); + if (ret) { + dev_err(pmf_dev->dev, "Failed to get SBIOS requests:%d\n", ret); + goto out; + } + + if (req.pending_req & BIT(APMF_AMT_NOTIFICATION)) { + dev_dbg(pmf_dev->dev, "AMT is supported and notifications %s\n", + req.amt_event ? "Enabled" : "Disabled"); + pmf_dev->amt_enabled = !!req.amt_event; + + if (pmf_dev->amt_enabled) + amd_pmf_handle_amt(pmf_dev); + else + amd_pmf_reset_amt(pmf_dev); + } + + if (req.pending_req & BIT(APMF_CQL_NOTIFICATION)) { + dev_dbg(pmf_dev->dev, "CQL is supported and notifications %s\n", + req.cql_event ? "Enabled" : "Disabled"); + + /* update the target mode information */ + if (pmf_dev->amt_enabled) + amd_pmf_update_2_cql(pmf_dev, req.cql_event); + } +out: + mutex_unlock(&pmf_dev->update_mutex); +} + static int apmf_if_verify_interface(struct amd_pmf_dev *pdev) { struct apmf_verify_interface output; @@ -190,12 +235,20 @@ static int apmf_get_system_params(struct amd_pmf_dev *dev) void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev) { + acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); + if (pmf_dev->hb_interval) cancel_delayed_work_sync(&pmf_dev->heart_beat); + + if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) && + is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS)) + acpi_remove_notify_handler(ahandle, ACPI_ALL_NOTIFY, apmf_event_handler); } int apmf_acpi_init(struct amd_pmf_dev *pmf_dev) { + acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); + acpi_status status; int ret; ret = apmf_if_verify_interface(pmf_dev); @@ -216,6 +269,20 @@ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev) schedule_delayed_work(&pmf_dev->heart_beat, 0); } + /* Install the APMF Notify handler */ + if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) && + is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS)) { + status = acpi_install_notify_handler(ahandle, + ACPI_ALL_NOTIFY, + apmf_event_handler, pmf_dev); + if (ACPI_FAILURE(status)) { + dev_err(pmf_dev->dev, "failed to install notify handler\n"); + return -ENODEV; + } + /* Call the handler once manually to catch up with possibly missed notifies. */ + apmf_event_handler(ahandle, 0, pmf_dev); + } + out: return ret; } diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c index ab0628b76f2f..368964d885a2 100644 --- a/drivers/platform/x86/amd/pmf/auto-mode.c +++ b/drivers/platform/x86/amd/pmf/auto-mode.c @@ -108,6 +108,21 @@ void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t t } } +void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event) +{ + int mode = config_store.current_mode; + + config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode = + is_cql_event ? AUTO_PERFORMANCE_ON_LAP : AUTO_PERFORMANCE; + + if ((mode == AUTO_PERFORMANCE || mode == AUTO_PERFORMANCE_ON_LAP) && + mode != config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode) { + mode = config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode; + amd_pmf_set_automode(dev, mode, NULL); + } + dev_dbg(dev->dev, "updated CQL thermals\n"); +} + static void amd_pmf_get_power_threshold(void) { config_store.transition[AUTO_TRANSITION_TO_QUIET].power_threshold = @@ -249,6 +264,29 @@ static void amd_pmf_load_defaults_auto_mode(struct amd_pmf_dev *dev) dev->socket_power_history_idx = -1; } +void amd_pmf_reset_amt(struct amd_pmf_dev *dev) +{ + /* + * OEM BIOS implementation guide says that if the auto mode is enabled + * the platform_profile registration shall be done by the OEM driver. + * There could be cases where both static slider and auto mode BIOS + * functions are enabled, in that case enable static slider updates + * only if it advertised as supported. + */ + + if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { + u8 mode = amd_pmf_get_pprof_modes(dev); + + dev_dbg(dev->dev, "resetting AMT thermals\n"); + amd_pmf_update_slider(dev, SLIDER_OP_SET, mode, NULL); + } +} + +void amd_pmf_handle_amt(struct amd_pmf_dev *dev) +{ + amd_pmf_set_automode(dev, config_store.current_mode, NULL); +} + void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev) { cancel_delayed_work_sync(&dev->work_buffer); diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index d27560f1ebb7..228fe243a13c 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -99,6 +99,7 @@ static void amd_pmf_get_metrics(struct work_struct *work) ktime_t time_elapsed_ms; int socket_power; + mutex_lock(&dev->update_mutex); /* Transfer table contents */ memset(dev->buf, 0, sizeof(dev->m_table)); amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL); @@ -108,8 +109,14 @@ static void amd_pmf_get_metrics(struct work_struct *work) /* Calculate the avg SoC power consumption */ socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power; + if (dev->amt_enabled) { + /* Apply the Auto Mode transition */ + amd_pmf_trans_automode(dev, socket_power, time_elapsed_ms); + } + dev->start_time = ktime_to_ms(ktime_get()); schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms)); + mutex_unlock(&dev->update_mutex); } static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset) @@ -329,6 +336,7 @@ static int amd_pmf_probe(struct platform_device *pdev) amd_pmf_dbgfs_register(dev); mutex_init(&dev->lock); + mutex_init(&dev->update_mutex); dev_info(dev->dev, "registered PMF device successfully\n"); return 0; @@ -339,6 +347,7 @@ static int amd_pmf_remove(struct platform_device *pdev) struct amd_pmf_dev *dev = platform_get_drvdata(pdev); mutex_destroy(&dev->lock); + mutex_destroy(&dev->update_mutex); amd_pmf_deinit_features(dev); apmf_acpi_deinit(dev); amd_pmf_dbgfs_unregister(dev); diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 5b12784e11b8..7613ed2ef6e3 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -17,6 +17,7 @@ /* APMF Functions */ #define APMF_FUNC_VERIFY_INTERFACE 0 #define APMF_FUNC_GET_SYS_PARAMS 1 +#define APMF_FUNC_SBIOS_REQUESTS 2 #define APMF_FUNC_SBIOS_HEARTBEAT 4 #define APMF_FUNC_AUTO_MODE 5 #define APMF_FUNC_SET_FAN_IDX 7 @@ -63,6 +64,21 @@ struct apmf_system_params { u32 heartbeat_int; } __packed; +struct apmf_sbios_req { + u16 size; + u32 pending_req; + u8 rsd; + u8 cql_event; + u8 amt_event; + u32 fppt; + u32 sppt; + u32 fppt_apu_only; + u32 spl; + u32 stt_min_limit; + u8 skin_temp_apu; + u8 skin_temp_hs2; +} __packed; + struct apmf_fan_idx { u16 size; u8 fan_ctl_mode; @@ -147,6 +163,8 @@ struct amd_pmf_dev { ktime_t start_time; int socket_power_history[AVG_SAMPLE_SIZE]; int socket_power_history_idx; + bool amt_enabled; + struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */ }; struct apmf_sps_prop_granular { @@ -301,5 +319,9 @@ int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev); void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev); void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms); +int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req); +void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event); +void amd_pmf_reset_amt(struct amd_pmf_dev *dev); +void amd_pmf_handle_amt(struct amd_pmf_dev *dev); #endif /* PMF_H */ -- cgit v1.2.3 From 9448ec9b0f90ce0479264d37106b9f5df232ea41 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 2 Aug 2022 20:41:48 +0530 Subject: platform/x86/amd/pmf: Force load driver on older supported platforms Some of the older platforms with _HID "AMDI0100" PMF driver can be force loaded by interested users but only for experimental purposes. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220802151149.2123699-11-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index 228fe243a13c..e46d63aa51b8 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -39,6 +39,7 @@ #define AMD_PMF_RESULT_FAILED 0xFF /* List of supported CPU ids */ +#define AMD_CPU_ID_RMB 0x14b5 #define AMD_CPU_ID_PS 0x14e8 #define PMF_MSG_DELAY_MIN_US 50 @@ -52,6 +53,11 @@ static int metrics_table_loop_ms = 1000; module_param(metrics_table_loop_ms, int, 0644); MODULE_PARM_DESC(metrics_table_loop_ms, "Metrics Table sample size time (default = 1000ms)"); +/* Force load on supported older platforms */ +static bool force_load; +module_param(force_load, bool, 0444); +MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)"); + static int current_power_limits_show(struct seq_file *seq, void *unused) { struct amd_pmf_dev *dev = seq->private; @@ -208,6 +214,7 @@ out_unlock: } static const struct pci_device_id pmf_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RMB) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) }, { } }; @@ -265,6 +272,7 @@ static void amd_pmf_deinit_features(struct amd_pmf_dev *dev) } static const struct acpi_device_id amd_pmf_acpi_ids[] = { + {"AMDI0100", 0x100}, {"AMDI0102", 0}, { } }; @@ -272,6 +280,7 @@ MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids); static int amd_pmf_probe(struct platform_device *pdev) { + const struct acpi_device_id *id; struct amd_pmf_dev *dev; struct pci_dev *rdev; u32 base_addr_lo; @@ -280,6 +289,13 @@ static int amd_pmf_probe(struct platform_device *pdev) u32 val; int err; + id = acpi_match_device(amd_pmf_acpi_ids, &pdev->dev); + if (!id) + return -ENODEV; + + if (id->driver_data == 0x100 && !force_load) + return -ENODEV; + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; -- cgit v1.2.3 From c2f7edf81a82db20d91974ba2cf50a4c90c2dbe3 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Fri, 19 Aug 2022 14:08:58 +0530 Subject: platform/x86/amd/pmf: Fix undefined reference to platform_profile Its reported that amd-pmf driver when built with config which does not have ACPI_PLATFORM_PROFILE set/enabled throws a undefined references to symbols used. ld: vmlinux.o: in function `amd_pmf_init_sps': drivers/platform/x86/amd/pmf/sps.c:132: undefined reference to `platform_profile_register' ld: vmlinux.o: in function `amd_pmf_deinit_sps': drivers/platform/x86/amd/pmf/sps.c:142: undefined reference to `platform_profile_remove' Fix it by adding a "select" to the Kconfig. Fixes: da5ce22df5fe ("platform/x86/amd/pmf: Add support for PMF core layer") Reported-by: Randy Dunlap Signed-off-by: Shyam Sundar S K Acked-by: Randy Dunlap # build-tested Link: https://lore.kernel.org/r/20220819083858.3987590-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig index e65ffa52229b..c375498c4071 100644 --- a/drivers/platform/x86/amd/pmf/Kconfig +++ b/drivers/platform/x86/amd/pmf/Kconfig @@ -6,6 +6,7 @@ config AMD_PMF tristate "AMD Platform Management Framework" depends on ACPI && PCI + select ACPI_PLATFORM_PROFILE help This driver provides support for the AMD Platform Management Framework. The goal is to enhance end user experience by making AMD PCs smarter, -- cgit v1.2.3 From ea522b806162ca947427f8305310d3c8a3d42d7a Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Mon, 22 Aug 2022 11:59:17 +0530 Subject: platform/x86/amd/pmf: Fix clang unused variable warning variable 'mode' is used uninitialized whenever switch default is taken in sps.c which leads to the following clang warning. drivers/platform/x86/amd/pmf/sps.c:96:2: error: variable 'mode' is used uninitialized whenever switch default is taken [-Werror,-Wsometimes-uninitialized] default: ^~~~~~~ drivers/platform/x86/amd/pmf/sps.c:101:9: note: uninitialized use occurs here return mode; ^~~~ drivers/platform/x86/amd/pmf/sps.c:84:9: note: initialize the variable 'mode' to silence this warning u8 mode; ^ = '\0' 1 error generated. Fix it by returning -EOPNOTSUPP in default case and also change the return type of the function amd_pmf_get_pprof_modes() to keep it similar like other drivers which implement platform_profile. Fixes: 4c71ae414474 ("platform/x86/amd/pmf: Add support SPS PMF feature") Reported-by: Nathan Chancellor Reviewed-by: Nathan Chancellor Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220822062917.4061503-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/auto-mode.c | 8 ++++++-- drivers/platform/x86/amd/pmf/core.c | 3 +++ drivers/platform/x86/amd/pmf/pmf.h | 4 ++-- drivers/platform/x86/amd/pmf/sps.c | 11 +++++++---- 4 files changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c index 368964d885a2..644af42e07cf 100644 --- a/drivers/platform/x86/amd/pmf/auto-mode.c +++ b/drivers/platform/x86/amd/pmf/auto-mode.c @@ -264,7 +264,7 @@ static void amd_pmf_load_defaults_auto_mode(struct amd_pmf_dev *dev) dev->socket_power_history_idx = -1; } -void amd_pmf_reset_amt(struct amd_pmf_dev *dev) +int amd_pmf_reset_amt(struct amd_pmf_dev *dev) { /* * OEM BIOS implementation guide says that if the auto mode is enabled @@ -275,11 +275,15 @@ void amd_pmf_reset_amt(struct amd_pmf_dev *dev) */ if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { - u8 mode = amd_pmf_get_pprof_modes(dev); + int mode = amd_pmf_get_pprof_modes(dev); + + if (mode < 0) + return mode; dev_dbg(dev->dev, "resetting AMT thermals\n"); amd_pmf_update_slider(dev, SLIDER_OP_SET, mode, NULL); } + return 0; } void amd_pmf_handle_amt(struct amd_pmf_dev *dev) diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index e46d63aa51b8..a675ca969331 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -65,6 +65,9 @@ static int current_power_limits_show(struct seq_file *seq, void *unused) int mode, src = 0; mode = amd_pmf_get_pprof_modes(dev); + if (mode < 0) + return mode; + src = amd_pmf_get_power_source(); amd_pmf_update_slider(dev, SLIDER_OP_GET, mode, &table); seq_printf(seq, "spl:%u fppt:%u sppt:%u sppt_apu_only:%u stt_min:%u stt[APU]:%u stt[HS2]: %u\n", diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 7613ed2ef6e3..0a72a395c2ef 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -303,7 +303,7 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev); int amd_pmf_get_power_source(void); /* SPS Layer */ -u8 amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf); +int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf); void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, struct amd_pmf_static_slider_granular *table); int amd_pmf_init_sps(struct amd_pmf_dev *dev); @@ -322,6 +322,6 @@ void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t t int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req); void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event); -void amd_pmf_reset_amt(struct amd_pmf_dev *dev); +int amd_pmf_reset_amt(struct amd_pmf_dev *dev); void amd_pmf_handle_amt(struct amd_pmf_dev *dev); #endif /* PMF_H */ diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c index 8923e29cc6ca..dba7e36962dc 100644 --- a/drivers/platform/x86/amd/pmf/sps.c +++ b/drivers/platform/x86/amd/pmf/sps.c @@ -79,9 +79,9 @@ static int amd_pmf_profile_get(struct platform_profile_handler *pprof, return 0; } -u8 amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) +int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) { - u8 mode; + int mode; switch (pmf->current_profile) { case PLATFORM_PROFILE_PERFORMANCE: @@ -95,7 +95,7 @@ u8 amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) break; default: dev_err(pmf->dev, "Unknown Platform Profile.\n"); - break; + return -EOPNOTSUPP; } return mode; @@ -105,10 +105,13 @@ static int amd_pmf_profile_set(struct platform_profile_handler *pprof, enum platform_profile_option profile) { struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); - u8 mode; + int mode; pmf->current_profile = profile; mode = amd_pmf_get_pprof_modes(pmf); + if (mode < 0) + return mode; + amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); return 0; } -- cgit v1.2.3 From 4b0133533e82af25d6aaf9d0c7b2a5af388feb74 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 29 Jul 2022 13:53:02 +0200 Subject: platform/x86: dell-privacy: convert to use dev_groups The driver core supports the ability to handle the creation and removal of device-specific sysfs files in a race-free manner. Take advantage of that by converting this driver to use this by moving the sysfs attributes into a group and assigning the dev_groups pointer to it. Cc: Perry Yuan Cc: Hans de Goede Cc: Mark Gross Cc: Dell.Client.Kernel@dell.com Cc: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20220729115302.2258296-1-gregkh@linuxfoundation.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-privacy.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell/dell-wmi-privacy.c b/drivers/platform/x86/dell/dell-wmi-privacy.c index 074b7e68c227..c82b3d6867c5 100644 --- a/drivers/platform/x86/dell/dell-wmi-privacy.c +++ b/drivers/platform/x86/dell/dell-wmi-privacy.c @@ -174,15 +174,12 @@ static ssize_t dell_privacy_current_state_show(struct device *dev, static DEVICE_ATTR_RO(dell_privacy_supported_type); static DEVICE_ATTR_RO(dell_privacy_current_state); -static struct attribute *privacy_attributes[] = { +static struct attribute *privacy_attrs[] = { &dev_attr_dell_privacy_supported_type.attr, &dev_attr_dell_privacy_current_state.attr, NULL, }; - -static const struct attribute_group privacy_attribute_group = { - .attrs = privacy_attributes -}; +ATTRIBUTE_GROUPS(privacy); /* * Describes the Device State class exposed by BIOS which can be consumed by @@ -342,10 +339,6 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context) if (ret) return ret; - ret = devm_device_add_group(&wdev->dev, &privacy_attribute_group); - if (ret) - return ret; - if (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO)) { ret = dell_privacy_leds_setup(&priv->wdev->dev); if (ret) @@ -374,6 +367,7 @@ static const struct wmi_device_id dell_wmi_privacy_wmi_id_table[] = { static struct wmi_driver dell_privacy_wmi_driver = { .driver = { .name = "dell-privacy", + .dev_groups = privacy_groups, }, .probe = dell_privacy_wmi_probe, .remove = dell_privacy_wmi_remove, -- cgit v1.2.3 From d8c04e27d93eb0afd750d5ea60119a92b146a755 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 1 Aug 2022 14:37:31 +0300 Subject: platform/x86: pmc_atom: Fix SLP_TYPx bitfield mask On Intel hardware the SLP_TYPx bitfield occupies bits 10-12 as per ACPI specification (see Table 4.13 "PM1 Control Registers Fixed Hardware Feature Control Bits" for the details). Fix the mask and other related definitions accordingly. Fixes: 93e5eadd1f6e ("x86/platform: New Intel Atom SOC power management controller driver") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220801113734.36131-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/pmc_atom.c | 2 +- include/linux/platform_data/x86/pmc_atom.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index 154317e9910d..5c757c7f64de 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -232,7 +232,7 @@ static void pmc_power_off(void) pm1_cnt_port = acpi_base_addr + PM1_CNT; pm1_cnt_value = inl(pm1_cnt_port); - pm1_cnt_value &= SLEEP_TYPE_MASK; + pm1_cnt_value &= ~SLEEP_TYPE_MASK; pm1_cnt_value |= SLEEP_TYPE_S5; pm1_cnt_value |= SLEEP_ENABLE; diff --git a/include/linux/platform_data/x86/pmc_atom.h b/include/linux/platform_data/x86/pmc_atom.h index 3edfb6d4e67a..dd81f510e4cf 100644 --- a/include/linux/platform_data/x86/pmc_atom.h +++ b/include/linux/platform_data/x86/pmc_atom.h @@ -7,6 +7,8 @@ #ifndef PMC_ATOM_H #define PMC_ATOM_H +#include + /* ValleyView Power Control Unit PCI Device ID */ #define PCI_DEVICE_ID_VLV_PMC 0x0F1C /* CherryTrail Power Control Unit PCI Device ID */ @@ -139,9 +141,9 @@ #define ACPI_MMIO_REG_LEN 0x100 #define PM1_CNT 0x4 -#define SLEEP_TYPE_MASK 0xFFFFECFF +#define SLEEP_TYPE_MASK GENMASK(12, 10) #define SLEEP_TYPE_S5 0x1C00 -#define SLEEP_ENABLE 0x2000 +#define SLEEP_ENABLE BIT(13) extern int pmc_atom_read(int offset, u32 *value); -- cgit v1.2.3 From 32c9b75640aeb1b144f9e2963c1640f4cef7c6f2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 1 Aug 2022 14:37:32 +0300 Subject: platform/x86: pmc_atom: Improve quirk message to be less cryptic Not everyone can get what "critclks" means in the message, improve it to make less cryptic. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220801113734.36131-2-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/pmc_atom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index 5c757c7f64de..f4046572a9fe 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -354,7 +354,7 @@ static bool pmc_clk_is_critical = true; static int dmi_callback(const struct dmi_system_id *d) { - pr_info("%s critclks quirk enabled\n", d->ident); + pr_info("%s: PMC critical clocks quirk enabled\n", d->ident); return 1; } -- cgit v1.2.3 From 27526525f3f6028298590cb0986557c98e9c1bd8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 1 Aug 2022 14:37:33 +0300 Subject: platform/x86: pmc_atom: Make terminator entry uniform Make terminator entry uniform by dropping: - trailing commas - anything inside curly braces Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220801113734.36131-3-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/pmc_atom.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index f4046572a9fe..cf707a46019f 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -60,7 +60,7 @@ static const struct pmc_clk byt_clks[] = { .freq = 19200000, .parent_name = "xtal", }, - {}, + {} }; static const struct pmc_clk cht_clks[] = { @@ -69,7 +69,7 @@ static const struct pmc_clk cht_clks[] = { .freq = 19200000, .parent_name = NULL, }, - {}, + {} }; static const struct pmc_bit_map d3_sts_0_map[] = { @@ -105,7 +105,7 @@ static const struct pmc_bit_map d3_sts_0_map[] = { {"LPSS2_F5_I2C5", BIT_LPSS2_F5_I2C5}, {"LPSS2_F6_I2C6", BIT_LPSS2_F6_I2C6}, {"LPSS2_F7_I2C7", BIT_LPSS2_F7_I2C7}, - {}, + {} }; static struct pmc_bit_map byt_d3_sts_1_map[] = { @@ -113,21 +113,21 @@ static struct pmc_bit_map byt_d3_sts_1_map[] = { {"OTG_SS_PHY", BIT_OTG_SS_PHY}, {"USH_SS_PHY", BIT_USH_SS_PHY}, {"DFX", BIT_DFX}, - {}, + {} }; static struct pmc_bit_map cht_d3_sts_1_map[] = { {"SMB", BIT_SMB}, {"GMM", BIT_STS_GMM}, {"ISH", BIT_STS_ISH}, - {}, + {} }; static struct pmc_bit_map cht_func_dis_2_map[] = { {"SMB", BIT_SMB}, {"GMM", BIT_FD_GMM}, {"ISH", BIT_FD_ISH}, - {}, + {} }; static const struct pmc_bit_map byt_pss_map[] = { @@ -149,7 +149,7 @@ static const struct pmc_bit_map byt_pss_map[] = { {"OTG_VCCA", PMC_PSS_BIT_OTG_VCCA}, {"USB", PMC_PSS_BIT_USB}, {"USB_SUS", PMC_PSS_BIT_USB_SUS}, - {}, + {} }; static const struct pmc_bit_map cht_pss_map[] = { @@ -172,7 +172,7 @@ static const struct pmc_bit_map cht_pss_map[] = { {"DFX_CLUSTER3", PMC_PSS_BIT_CHT_DFX_CLUSTER3}, {"DFX_CLUSTER4", PMC_PSS_BIT_CHT_DFX_CLUSTER4}, {"DFX_CLUSTER5", PMC_PSS_BIT_CHT_DFX_CLUSTER5}, - {}, + {} }; static const struct pmc_reg_map byt_reg_map = { @@ -417,8 +417,7 @@ static const struct dmi_system_id critclk_systems[] = { DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), }, }, - - { /*sentinel*/ } + {} }; static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap, @@ -498,7 +497,7 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) static const struct pci_device_id pmc_pci_ids[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data }, - { 0, }, + {} }; static int __init pmc_atom_init(void) -- cgit v1.2.3 From 5a88ace44d0f99e2bac55d827f4cd6e8bc07e00b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 1 Aug 2022 14:37:34 +0300 Subject: platform/x86: pmc_atom: Amend comment style and grammar The style of the comments is not uniform, make it so and fix a few grammar issues. While at it, update Copyright years. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220801113734.36131-4-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/pmc_atom.c | 19 ++++++++----------- include/linux/platform_data/x86/pmc_atom.h | 4 ++-- 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index cf707a46019f..93a6414c6611 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Intel Atom SOC Power Management Controller Driver - * Copyright (c) 2014, Intel Corporation. + * Intel Atom SoC Power Management Controller Driver + * Copyright (c) 2014-2015,2017,2022 Intel Corporation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -489,11 +489,7 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; } -/* - * Data for PCI driver interface - * - * used by pci_match_id() call below. - */ +/* Data for PCI driver interface used by pci_match_id() call below */ static const struct pci_device_id pmc_pci_ids[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data }, @@ -505,8 +501,9 @@ static int __init pmc_atom_init(void) struct pci_dev *pdev = NULL; const struct pci_device_id *ent; - /* We look for our device - PCU PMC - * we assume that there is max. one device. + /* + * We look for our device - PCU PMC. + * We assume that there is maximum one device. * * We can't use plain pci_driver mechanism, * as the device is really a multiple function device, @@ -518,7 +515,7 @@ static int __init pmc_atom_init(void) if (ent) return pmc_setup_dev(pdev, ent); } - /* Device not found. */ + /* Device not found */ return -ENODEV; } @@ -526,6 +523,6 @@ device_initcall(pmc_atom_init); /* MODULE_AUTHOR("Aubrey Li "); -MODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface"); +MODULE_DESCRIPTION("Intel Atom SoC Power Management Controller Interface"); MODULE_LICENSE("GPL v2"); */ diff --git a/include/linux/platform_data/x86/pmc_atom.h b/include/linux/platform_data/x86/pmc_atom.h index dd81f510e4cf..b8a701c77fd0 100644 --- a/include/linux/platform_data/x86/pmc_atom.h +++ b/include/linux/platform_data/x86/pmc_atom.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Intel Atom SOC Power Management Controller Header File - * Copyright (c) 2014, Intel Corporation. + * Intel Atom SoC Power Management Controller Header File + * Copyright (c) 2014-2015,2022 Intel Corporation. */ #ifndef PMC_ATOM_H -- cgit v1.2.3 From 5cc7ce779b60ca9a6cb84a22debf278327550ff7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 10 Aug 2022 16:19:34 +0200 Subject: platform/x86: x86-android-tablets: Fix broken touchscreen on Chuwi Hi8 with Windows BIOS The x86-android-tablets handling for the Chuwi Hi8 is only necessary with the Android BIOS and it is causing problems with the Windows BIOS version. Specifically when trying to register the already present touchscreen x86_acpi_irq_helper_get() calls acpi_unregister_gsi(), this breaks the working of the touchscreen and also leads to an oops: [ 14.248946] ------------[ cut here ]------------ [ 14.248954] remove_proc_entry: removing non-empty directory 'irq/75', leaking at least 'MSSL0001:00' [ 14.248983] WARNING: CPU: 3 PID: 440 at fs/proc/generic.c:718 remove_proc_entry ... [ 14.249293] unregister_irq_proc+0xe0/0x100 [ 14.249305] free_desc+0x29/0x70 [ 14.249312] irq_free_descs+0x4b/0x80 [ 14.249320] mp_unmap_irq+0x5c/0x60 [ 14.249329] acpi_unregister_gsi_ioapic+0x2a/0x40 [ 14.249338] x86_acpi_irq_helper_get+0x4b/0x190 [x86_android_tablets] [ 14.249355] x86_android_tablet_init+0x178/0xe34 [x86_android_tablets] Add an init callback for the Chuwi Hi8, which detects when the Windows BIOS is in use and exits with -ENODEV in that case, fixing this. Fixes: 84c2dcdd475f ("platform/x86: x86-android-tablets: Add an init() callback to struct x86_dev_info") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220810141934.140771-1-hdegoede@redhat.com --- drivers/platform/x86/x86-android-tablets.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c index 480375977435..4acd6fa8d43b 100644 --- a/drivers/platform/x86/x86-android-tablets.c +++ b/drivers/platform/x86/x86-android-tablets.c @@ -663,9 +663,23 @@ static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = { }, }; +static int __init chuwi_hi8_init(void) +{ + /* + * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get() + * breaking the touchscreen + logging various errors when the Windows + * BIOS is used. + */ + if (acpi_dev_present("MSSL0001", NULL, 1)) + return -ENODEV; + + return 0; +} + static const struct x86_dev_info chuwi_hi8_info __initconst = { .i2c_client_info = chuwi_hi8_i2c_clients, .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients), + .init = chuwi_hi8_init, }; #define CZC_EC_EXTRA_PORT 0x68 -- cgit v1.2.3 From 6f5e02cfb123c608bdb0c9ab32cb8705c2bb9bba Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 10 Aug 2022 16:01:33 +0200 Subject: platform/surface: aggregator_registry: Add support for Surface Laptop Go 2 The Surface Laptop Go 2 seems to have the same SAM client devices as the Surface Laptop Go 1, so re-use its node group. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220810140133.99087-1-luzmaximilian@gmail.com Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index d5655f6a4a41..93ab62eb393d 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -325,6 +325,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { /* Surface Laptop Go 1 */ { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + /* Surface Laptop Go 2 */ + { "MSHW0290", (unsigned long)ssam_node_group_slg1 }, + /* Surface Laptop Studio */ { "MSHW0123", (unsigned long)ssam_node_group_sls }, -- cgit v1.2.3 From 637b8210c788b7f17866a9140c118df9231ee2a3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 10 Aug 2022 16:41:15 +0200 Subject: platform/surface: aggregator_registry: Rename HID device nodes based on their function Rename HID device nodes based on their function. In particular, these are nodes for firmware updates via the CFU mechanism (component firmware update), HID based sensors, and a USB-C UCSI client. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220810144117.493710-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 93ab62eb393d..7d82398f55b1 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -104,14 +104,14 @@ static const struct software_node ssam_node_hid_tid1_touchpad = { .parent = &ssam_node_root, }; -/* HID device instance 6 (TID1, unknown HID device). */ -static const struct software_node ssam_node_hid_tid1_iid6 = { +/* HID device instance 6 (TID1, HID sensor collection). */ +static const struct software_node ssam_node_hid_tid1_sensors = { .name = "ssam:01:15:01:06:00", .parent = &ssam_node_root, }; -/* HID device instance 7 (TID1, unknown HID device). */ -static const struct software_node ssam_node_hid_tid1_iid7 = { +/* HID device instance 7 (TID1, UCM UCSI HID client). */ +static const struct software_node ssam_node_hid_tid1_ucm_ucsi = { .name = "ssam:01:15:01:07:00", .parent = &ssam_node_root, }; @@ -182,8 +182,8 @@ static const struct software_node ssam_node_hid_kip_touchpad = { .parent = &ssam_node_hub_kip, }; -/* HID device instance 5 (KIP hub, unknown HID device). */ -static const struct software_node ssam_node_hid_kip_iid5 = { +/* HID device instance 5 (KIP hub, type-cover firmware update). */ +static const struct software_node ssam_node_hid_kip_fwupd = { .name = "ssam:01:15:02:05:00", .parent = &ssam_node_hub_kip, }; @@ -244,8 +244,8 @@ static const struct software_node *ssam_node_group_sls[] = { &ssam_node_hid_tid1_keyboard, &ssam_node_hid_tid1_penstash, &ssam_node_hid_tid1_touchpad, - &ssam_node_hid_tid1_iid6, - &ssam_node_hid_tid1_iid7, + &ssam_node_hid_tid1_sensors, + &ssam_node_hid_tid1_ucm_ucsi, &ssam_node_hid_tid1_sysctrl, NULL, }; @@ -278,7 +278,7 @@ static const struct software_node *ssam_node_group_sp8[] = { &ssam_node_hid_kip_keyboard, &ssam_node_hid_kip_penstash, &ssam_node_hid_kip_touchpad, - &ssam_node_hid_kip_iid5, + &ssam_node_hid_kip_fwupd, NULL, }; -- cgit v1.2.3 From 95a82322505f9e941f8fd85b751b929b055a8f17 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 10 Aug 2022 16:41:16 +0200 Subject: platform/surface: aggregator_registry: Rename HID device nodes based on new findings On Windows, the HID devices with target ID 1 are grouped as "Surface Hot Plug - SAM". Rename their device nodes in the registry to reflect that and update the comments accordingly. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220810144117.493710-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../platform/surface/surface_aggregator_registry.c | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 7d82398f55b1..9970f89b1411 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -86,38 +86,38 @@ static const struct software_node ssam_node_bas_dtx = { .parent = &ssam_node_root, }; -/* HID keyboard (TID1). */ -static const struct software_node ssam_node_hid_tid1_keyboard = { +/* HID keyboard (SAM, TID=1). */ +static const struct software_node ssam_node_hid_sam_keyboard = { .name = "ssam:01:15:01:01:00", .parent = &ssam_node_root, }; -/* HID pen stash (TID1; pen taken / stashed away evens). */ -static const struct software_node ssam_node_hid_tid1_penstash = { +/* HID pen stash (SAM, TID=1; pen taken / stashed away evens). */ +static const struct software_node ssam_node_hid_sam_penstash = { .name = "ssam:01:15:01:02:00", .parent = &ssam_node_root, }; -/* HID touchpad (TID1). */ -static const struct software_node ssam_node_hid_tid1_touchpad = { +/* HID touchpad (SAM, TID=1). */ +static const struct software_node ssam_node_hid_sam_touchpad = { .name = "ssam:01:15:01:03:00", .parent = &ssam_node_root, }; -/* HID device instance 6 (TID1, HID sensor collection). */ -static const struct software_node ssam_node_hid_tid1_sensors = { +/* HID device instance 6 (SAM, TID=1, HID sensor collection). */ +static const struct software_node ssam_node_hid_sam_sensors = { .name = "ssam:01:15:01:06:00", .parent = &ssam_node_root, }; -/* HID device instance 7 (TID1, UCM UCSI HID client). */ -static const struct software_node ssam_node_hid_tid1_ucm_ucsi = { +/* HID device instance 7 (SAM, TID=1, UCM UCSI HID client). */ +static const struct software_node ssam_node_hid_sam_ucm_ucsi = { .name = "ssam:01:15:01:07:00", .parent = &ssam_node_root, }; -/* HID system controls (TID1). */ -static const struct software_node ssam_node_hid_tid1_sysctrl = { +/* HID system controls (SAM, TID=1). */ +static const struct software_node ssam_node_hid_sam_sysctrl = { .name = "ssam:01:15:01:08:00", .parent = &ssam_node_root, }; @@ -241,12 +241,12 @@ static const struct software_node *ssam_node_group_sls[] = { &ssam_node_bat_main, &ssam_node_tmp_pprof, &ssam_node_pos_tablet_switch, - &ssam_node_hid_tid1_keyboard, - &ssam_node_hid_tid1_penstash, - &ssam_node_hid_tid1_touchpad, - &ssam_node_hid_tid1_sensors, - &ssam_node_hid_tid1_ucm_ucsi, - &ssam_node_hid_tid1_sysctrl, + &ssam_node_hid_sam_keyboard, + &ssam_node_hid_sam_penstash, + &ssam_node_hid_sam_touchpad, + &ssam_node_hid_sam_sensors, + &ssam_node_hid_sam_ucm_ucsi, + &ssam_node_hid_sam_sysctrl, NULL, }; -- cgit v1.2.3 From c6607bcbbe5395c9eb7d556356941b3e65f11e9f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 10 Aug 2022 16:41:17 +0200 Subject: platform/surface: aggregator_registry: Add HID devices for sensors and UCSI client to SP8 Add software nodes for the HID sensor collection and the UCM UCSI HID client to the Surface Pro 8. In contrast to the type-cover devices, these devices are directly attached to the SAM controller, without any hub. This enables support for HID-based sensors, including the ones used for automatic screen rotation, on the Surface Pro 8. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220810144117.493710-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 9970f89b1411..585911020cea 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -279,6 +279,8 @@ static const struct software_node *ssam_node_group_sp8[] = { &ssam_node_hid_kip_penstash, &ssam_node_hid_kip_touchpad, &ssam_node_hid_kip_fwupd, + &ssam_node_hid_sam_sensors, + &ssam_node_hid_sam_ucm_ucsi, NULL, }; -- cgit v1.2.3 From 170f0da25dac630dacb920d043fb20e12c287520 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Tue, 9 Aug 2022 14:50:53 +1200 Subject: platform/x86: asus-wmi: Convert all attr-show to use sysfs_emit This changes all *_show attributes in asus-wmi.c to use sysfs_emit() instead of the older method of writing to the output buffer manually. Signed-off-by: Luke D. Jones Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220809025054.1626339-6-luke@ljones.dev Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 89b604e04d7f..b5c977d37bc1 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -771,7 +771,7 @@ static ssize_t charge_control_end_threshold_show(struct device *device, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", charge_end_threshold); + return sysfs_emit(buf, "%d\n", charge_end_threshold); } static DEVICE_ATTR_RW(charge_control_end_threshold); @@ -1819,7 +1819,7 @@ static ssize_t pwm1_show(struct device *dev, value = -1; } - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static ssize_t pwm1_store(struct device *dev, @@ -1879,7 +1879,7 @@ static ssize_t fan1_input_show(struct device *dev, return -ENXIO; } - return sprintf(buf, "%d\n", value < 0 ? -1 : value*100); + return sysfs_emit(buf, "%d\n", value < 0 ? -1 : value * 100); } static ssize_t pwm1_enable_show(struct device *dev, @@ -1897,7 +1897,7 @@ static ssize_t pwm1_enable_show(struct device *dev, * in practice on X532FL at least (the bit is always 0) and there's * also nothing in the DSDT to indicate that this behaviour exists. */ - return sprintf(buf, "%d\n", asus->fan_pwm_mode); + return sysfs_emit(buf, "%d\n", asus->fan_pwm_mode); } static ssize_t pwm1_enable_store(struct device *dev, @@ -1965,7 +1965,7 @@ static ssize_t fan1_label_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", ASUS_FAN_DESC); + return sysfs_emit(buf, "%s\n", ASUS_FAN_DESC); } static ssize_t asus_hwmon_temp1(struct device *dev, @@ -2158,7 +2158,7 @@ static ssize_t fan_boost_mode_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_boost_mode); + return sysfs_emit(buf, "%d\n", asus->fan_boost_mode); } static ssize_t fan_boost_mode_store(struct device *dev, @@ -2711,7 +2711,7 @@ static ssize_t throttle_thermal_policy_show(struct device *dev, struct asus_wmi *asus = dev_get_drvdata(dev); u8 mode = asus->throttle_thermal_policy_mode; - return scnprintf(buf, PAGE_SIZE, "%d\n", mode); + return sysfs_emit(buf, "%d\n", mode); } static ssize_t throttle_thermal_policy_store(struct device *dev, -- cgit v1.2.3 From a8f9c36c4bb705af4b6054244ff9669cdd8dcf71 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Thu, 11 Aug 2022 01:32:03 +0000 Subject: platform/x86: asus-wmi: Use kobj_to_dev() Use kobj_to_dev() instead of open-coding it. Reported-by: Zeal Robot Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220811013203.16010-1-ye.xingchen@zte.com.cn Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index b5c977d37bc1..e461299d938a 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -2006,7 +2006,7 @@ static struct attribute *hwmon_attributes[] = { static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct asus_wmi *asus = dev_get_drvdata(dev->parent); u32 value = ASUS_WMI_UNSUPPORTED_METHOD; @@ -3294,7 +3294,7 @@ static struct attribute *platform_attributes[] = { static umode_t asus_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct asus_wmi *asus = dev_get_drvdata(dev); bool ok = true; int devid = -1; -- cgit v1.2.3 From cdf36fc865f0aff8de5a9afc3654f114c4d04cba Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 13 Aug 2022 10:25:07 +1200 Subject: platform/x86: asus-wmi: Refactor disable_gpu attribute The settings for these attributes can be read from the device, this is now done instead of reading a stored value from module. The stored value is also removed. This means the simpler asus_wmi_dev_is_present() can be used in *_check_present() - it is not an error for these methods to be missing. The _write() functions have their bodies shifted in to *_store() which simplifies things further. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220812222509.292692-5-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 73 ++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 49 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index e461299d938a..f58cbda862d2 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -233,7 +233,6 @@ struct asus_wmi { bool egpu_enable; bool dgpu_disable_available; - bool dgpu_disable; bool throttle_thermal_policy_available; u8 throttle_thermal_policy_mode; @@ -563,47 +562,10 @@ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus) /* dGPU ********************************************************************/ static int dgpu_disable_check_present(struct asus_wmi *asus) { - u32 result; - int err; - asus->dgpu_disable_available = false; - err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_DGPU, &result); - if (err) { - if (err == -ENODEV) - return 0; - return err; - } - - if (result & ASUS_WMI_DSTS_PRESENCE_BIT) { + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU)) asus->dgpu_disable_available = true; - asus->dgpu_disable = result & ASUS_WMI_DSTS_STATUS_BIT; - } - - return 0; -} - -static int dgpu_disable_write(struct asus_wmi *asus) -{ - u32 retval; - u8 value; - int err; - - /* Don't rely on type conversion */ - value = asus->dgpu_disable ? 1 : 0; - - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, value, &retval); - if (err) { - pr_warn("Failed to set dgpu disable: %d\n", err); - return err; - } - - if (retval > 1) { - pr_warn("Failed to set dgpu disable (retval): 0x%x\n", retval); - return -EIO; - } - - sysfs_notify(&asus->platform_device->dev.kobj, NULL, "dgpu_disable"); return 0; } @@ -612,9 +574,13 @@ static ssize_t dgpu_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct asus_wmi *asus = dev_get_drvdata(dev); - u8 mode = asus->dgpu_disable; + int result; - return sysfs_emit(buf, "%d\n", mode); + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU); + if (result < 0) + return result; + + return sysfs_emit(buf, "%d\n", result); } /* @@ -627,24 +593,33 @@ static ssize_t dgpu_disable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - bool disable; - int result; + int result, err; + u32 disable; struct asus_wmi *asus = dev_get_drvdata(dev); - result = kstrtobool(buf, &disable); + result = kstrtou32(buf, 10, &disable); if (result) return result; - asus->dgpu_disable = disable; + if (disable > 1) + return -EINVAL; - result = dgpu_disable_write(asus); - if (result) - return result; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result); + if (err) { + pr_warn("Failed to set dgpu disable: %d\n", err); + return err; + } + + if (result > 1) { + pr_warn("Failed to set dgpu disable (result): 0x%x\n", result); + return -EIO; + } + + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "dgpu_disable"); return count; } - static DEVICE_ATTR_RW(dgpu_disable); /* eGPU ********************************************************************/ -- cgit v1.2.3 From 36450e7db0fe55c338f32059382a2d8342cbc9a1 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 13 Aug 2022 10:25:08 +1200 Subject: platform/x86: asus-wmi: Refactor egpu_enable attribute The settings for these attributes can be read from the device, this is now done instead of reading a stored value from module. The stored value is also removed. This means the simpler asus_wmi_dev_is_present() can be used in *_check_present() - it is not an error for these methods to be missing. The _write() functions have their bodies shifted in to *_store() which simplifies things further. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220812222509.292692-6-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 84 +++++++++++++---------------------------- 1 file changed, 26 insertions(+), 58 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index f58cbda862d2..c82e7b128444 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -229,9 +229,7 @@ struct asus_wmi { u8 fan_boost_mode_mask; u8 fan_boost_mode; - bool egpu_enable_available; // 0 = enable - bool egpu_enable; - + bool egpu_enable_available; bool dgpu_disable_available; bool throttle_thermal_policy_available; @@ -625,48 +623,10 @@ static DEVICE_ATTR_RW(dgpu_disable); /* eGPU ********************************************************************/ static int egpu_enable_check_present(struct asus_wmi *asus) { - u32 result; - int err; - asus->egpu_enable_available = false; - err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_EGPU, &result); - if (err) { - if (err == -ENODEV) - return 0; - return err; - } - - if (result & ASUS_WMI_DSTS_PRESENCE_BIT) { + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU)) asus->egpu_enable_available = true; - asus->egpu_enable = result & ASUS_WMI_DSTS_STATUS_BIT; - } - - return 0; -} - -static int egpu_enable_write(struct asus_wmi *asus) -{ - u32 retval; - u8 value; - int err; - - /* Don't rely on type conversion */ - value = asus->egpu_enable ? 1 : 0; - - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, value, &retval); - - if (err) { - pr_warn("Failed to set egpu disable: %d\n", err); - return err; - } - - if (retval > 1) { - pr_warn("Failed to set egpu disable (retval): 0x%x\n", retval); - return -EIO; - } - - sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable"); return 0; } @@ -675,9 +635,13 @@ static ssize_t egpu_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct asus_wmi *asus = dev_get_drvdata(dev); - bool mode = asus->egpu_enable; + int result; - return sysfs_emit(buf, "%d\n", mode); + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU); + if (result < 0) + return result; + + return sysfs_emit(buf, "%d\n", result); } /* The ACPI call to enable the eGPU also disables the internal dGPU */ @@ -685,29 +649,33 @@ static ssize_t egpu_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - bool enable; - int result; + int result, err; + u32 enable; struct asus_wmi *asus = dev_get_drvdata(dev); - result = kstrtobool(buf, &enable); - if (result) - return result; + err = kstrtou32(buf, 10, &enable); + if (err) + return err; - asus->egpu_enable = enable; + if (enable > 1) + return -EINVAL; - result = egpu_enable_write(asus); - if (result) - return result; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); + if (err) { + pr_warn("Failed to set egpu disable: %d\n", err); + return err; + } - /* Ensure that the kernel status of dgpu is updated */ - result = dgpu_disable_check_present(asus); - if (result) - return result; + if (result > 1) { + pr_warn("Failed to set egpu disable (retval): 0x%x\n", result); + return -EIO; + } + + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable"); return count; } - static DEVICE_ATTR_RW(egpu_enable); /* Battery ********************************************************************/ -- cgit v1.2.3 From ebc443ad379fad80b8fc350f35cc0652b8447995 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 13 Aug 2022 10:25:09 +1200 Subject: platform/x86: asus-wmi: Refactor panel_od attribute The settings for these attributes can be read from the device, this is now done instead of reading a stored value from module. The stored value is also removed. This means the simpler asus_wmi_dev_is_present() can be used in *_check_present() - it is not an error for these methods to be missing. The _write() functions have their bodies shifted in to *_store() which simplifies things further. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220812222509.292692-7-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 74 ++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 49 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index c82e7b128444..2d9d709aa59f 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -246,7 +246,6 @@ struct asus_wmi { bool battery_rsoc_available; bool panel_overdrive_available; - bool panel_overdrive; struct hotplug_slot hotplug_slot; struct mutex hotplug_lock; @@ -1500,48 +1499,10 @@ exit: /* Panel Overdrive ************************************************************/ static int panel_od_check_present(struct asus_wmi *asus) { - u32 result; - int err; - asus->panel_overdrive_available = false; - err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_PANEL_OD, &result); - if (err) { - if (err == -ENODEV) - return 0; - return err; - } - - if (result & ASUS_WMI_DSTS_PRESENCE_BIT) { + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD)) asus->panel_overdrive_available = true; - asus->panel_overdrive = result & ASUS_WMI_DSTS_STATUS_BIT; - } - - return 0; -} - -static int panel_od_write(struct asus_wmi *asus) -{ - u32 retval; - u8 value; - int err; - - /* Don't rely on type conversion */ - value = asus->panel_overdrive ? 1 : 0; - - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, value, &retval); - - if (err) { - pr_warn("Failed to set panel overdrive: %d\n", err); - return err; - } - - if (retval > 1) { - pr_warn("Failed to set panel overdrive (retval): 0x%x\n", retval); - return -EIO; - } - - sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od"); return 0; } @@ -1550,32 +1511,47 @@ static ssize_t panel_od_show(struct device *dev, struct device_attribute *attr, char *buf) { struct asus_wmi *asus = dev_get_drvdata(dev); + int result; - return sysfs_emit(buf, "%d\n", asus->panel_overdrive); + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_PANEL_OD); + if (result < 0) + return result; + + return sysfs_emit(buf, "%d\n", result); } static ssize_t panel_od_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - bool overdrive; - int result; + int result, err; + u32 overdrive; struct asus_wmi *asus = dev_get_drvdata(dev); - result = kstrtobool(buf, &overdrive); + result = kstrtou32(buf, 10, &overdrive); if (result) return result; - asus->panel_overdrive = overdrive; - result = panel_od_write(asus); + if (overdrive > 1) + return -EINVAL; - if (result) - return result; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, overdrive, &result); + + if (err) { + pr_warn("Failed to set panel overdrive: %d\n", err); + return err; + } + + if (result > 1) { + pr_warn("Failed to set panel overdrive (result): 0x%x\n", result); + return -EIO; + } + + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od"); return count; } - static DEVICE_ATTR_RW(panel_od); /* Quirks *********************************************************************/ -- cgit v1.2.3 From 3c3b55564afa8b7d952ce2ba90e7f522832ed0f7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Aug 2022 17:05:38 +0200 Subject: platform/x86: asus-wmi: Simplify some of the *_check_present() helpers After the recent cleanup patches, some of the *_check_present() helpers just propagate the result of asus_wmi_dev_is_present(). Replace these with direct asus_wmi_dev_is_present() calls as a further cleanup. Cc: Luke D. Jones Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220815150538.474306-1-hdegoede@redhat.com --- drivers/platform/x86/asus-wmi.c | 47 +++-------------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 2d9d709aa59f..d72491fb218b 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -557,16 +557,6 @@ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus) } /* dGPU ********************************************************************/ -static int dgpu_disable_check_present(struct asus_wmi *asus) -{ - asus->dgpu_disable_available = false; - - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU)) - asus->dgpu_disable_available = true; - - return 0; -} - static ssize_t dgpu_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -620,16 +610,6 @@ static ssize_t dgpu_disable_store(struct device *dev, static DEVICE_ATTR_RW(dgpu_disable); /* eGPU ********************************************************************/ -static int egpu_enable_check_present(struct asus_wmi *asus) -{ - asus->egpu_enable_available = false; - - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU)) - asus->egpu_enable_available = true; - - return 0; -} - static ssize_t egpu_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1497,16 +1477,6 @@ exit: } /* Panel Overdrive ************************************************************/ -static int panel_od_check_present(struct asus_wmi *asus) -{ - asus->panel_overdrive_available = false; - - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD)) - asus->panel_overdrive_available = true; - - return 0; -} - static ssize_t panel_od_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3493,13 +3463,9 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_platform; - err = egpu_enable_check_present(asus); - if (err) - goto fail_egpu_enable; - - err = dgpu_disable_check_present(asus); - if (err) - goto fail_dgpu_disable; + 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->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); err = fan_boost_mode_check_present(asus); if (err) @@ -3515,10 +3481,6 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_platform_profile_setup; - err = panel_od_check_present(asus); - if (err) - goto fail_panel_od; - err = asus_wmi_sysfs_init(asus->platform_device); if (err) goto fail_sysfs; @@ -3613,10 +3575,7 @@ fail_platform_profile_setup: if (asus->platform_profile_support) platform_profile_remove(); fail_fan_boost_mode: -fail_egpu_enable: -fail_dgpu_disable: fail_platform: -fail_panel_od: kfree(asus); return err; } -- cgit v1.2.3 From 01ef026ab36357a818c7d8324a36dbb8beff6ff5 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 13 Aug 2022 21:26:24 +1200 Subject: platform/x86: asus-wmi: Support the hardware GPU MUX on some laptops Support the hardware GPU MUX switch available on some models. This switch can toggle the MUX between: - 0, Dedicated mode - 1, Optimus mode Optimus mode is the regular iGPU + dGPU available, while dedicated mode switches the system to have only the dGPU available. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220813092624.6228-1-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- Documentation/ABI/testing/sysfs-platform-asus-wmi | 12 ++++++ drivers/platform/x86/asus-wmi.c | 51 +++++++++++++++++++++++ include/linux/platform_data/x86/asus-wmi.h | 3 ++ 3 files changed, 66 insertions(+) (limited to 'drivers/platform') diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi index 4d63824713ac..a77a004a1baa 100644 --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi @@ -58,6 +58,18 @@ Description: * 1 - overboost, * 2 - silent +What: /sys/devices/platform//gpu_mux_mode +Date: Aug 2022 +KernelVersion: 6.1 +Contact: "Luke Jones" +Description: + Switch the GPU hardware MUX mode. Laptops with this feature can + can be toggled to boot with only the dGPU (discrete mode) or in + standard Optimus/Hybrid mode. On switch a reboot is required: + + * 0 - Discrete GPU, + * 1 - Optimus/Hybrid, + What: /sys/devices/platform//dgpu_disable Date: Aug 2022 KernelVersion: 5.17 diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d72491fb218b..46d0dd96a351 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -231,6 +231,7 @@ struct asus_wmi { bool egpu_enable_available; bool dgpu_disable_available; + bool gpu_mux_mode_available; bool throttle_thermal_policy_available; u8 throttle_thermal_policy_mode; @@ -657,6 +658,52 @@ static ssize_t egpu_enable_store(struct device *dev, } static DEVICE_ATTR_RW(egpu_enable); +/* gpu mux switch *************************************************************/ +static ssize_t gpu_mux_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + int result; + + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX); + if (result < 0) + return result; + + return sysfs_emit(buf, "%d\n", result); +} + +static ssize_t gpu_mux_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + int result, err; + u32 optimus; + + err = kstrtou32(buf, 10, &optimus); + if (err) + return err; + + if (optimus > 1) + return -EINVAL; + + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result); + if (err) { + dev_err(dev, "Failed to set GPU MUX mode: %d\n", err); + return err; + } + /* !1 is considered a fail by ASUS */ + if (result != 1) { + dev_warn(dev, "Failed to set GPU MUX mode (result): 0x%x\n", result); + return -EIO; + } + + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "gpu_mux_mode"); + + return count; +} +static DEVICE_ATTR_RW(gpu_mux_mode); + /* Battery ********************************************************************/ /* The battery maximum charging percentage */ @@ -3172,6 +3219,7 @@ static struct attribute *platform_attributes[] = { &dev_attr_touchpad.attr, &dev_attr_egpu_enable.attr, &dev_attr_dgpu_disable.attr, + &dev_attr_gpu_mux_mode.attr, &dev_attr_lid_resume.attr, &dev_attr_als_enable.attr, &dev_attr_fan_boost_mode.attr, @@ -3202,6 +3250,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, ok = asus->egpu_enable_available; else if (attr == &dev_attr_dgpu_disable.attr) ok = asus->dgpu_disable_available; + else if (attr == &dev_attr_gpu_mux_mode.attr) + ok = asus->gpu_mux_mode_available; else if (attr == &dev_attr_fan_boost_mode.attr) ok = asus->fan_boost_mode_available; else if (attr == &dev_attr_throttle_thermal_policy.attr) @@ -3465,6 +3515,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->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX); asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); err = fan_boost_mode_check_present(asus); diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 98f2b2f20f3e..70d2347bf6ca 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -99,6 +99,9 @@ /* dgpu on/off */ #define ASUS_WMI_DEVID_DGPU 0x00090020 +/* gpu mux switch, 0 = dGPU, 1 = Optimus */ +#define ASUS_WMI_DEVID_GPU_MUX 0x00090016 + /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 -- cgit v1.2.3 From 00aa846955fbfb04f7bc0c26c49febfe5395eca1 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 13 Aug 2022 21:27:52 +1200 Subject: platform/x86: asus-wmi: Adjust tablet/lidflip handling to use enum Due to multiple types of tablet/lidflip, the existing code for handling these events is refactored to use an enum for each type. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220813092753.6635-1-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-nb-wmi.c | 13 ++++------ drivers/platform/x86/asus-wmi.c | 49 +++++++++++++++++++++++++++----------- drivers/platform/x86/asus-wmi.h | 9 +++++-- 3 files changed, 47 insertions(+), 24 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 478dd300b9c9..4672a2b8322e 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -115,12 +115,12 @@ static struct quirk_entry quirk_asus_forceals = { }; static struct quirk_entry quirk_asus_use_kbd_dock_devid = { - .use_kbd_dock_devid = true, + .tablet_switch_mode = asus_wmi_kbd_dock_devid, }; static struct quirk_entry quirk_asus_use_lid_flip_devid = { .wmi_backlight_set_devstate = true, - .use_lid_flip_devid = true, + .tablet_switch_mode = asus_wmi_lid_flip_devid, }; static int dmi_matched(const struct dmi_system_id *dmi) @@ -492,16 +492,13 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) switch (tablet_mode_sw) { case 0: - quirks->use_kbd_dock_devid = false; - quirks->use_lid_flip_devid = false; + quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; break; case 1: - quirks->use_kbd_dock_devid = true; - quirks->use_lid_flip_devid = false; + quirks->tablet_switch_mode = asus_wmi_kbd_dock_devid; break; case 2: - quirks->use_kbd_dock_devid = false; - quirks->use_lid_flip_devid = true; + quirks->tablet_switch_mode = asus_wmi_lid_flip_devid; break; } diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 46d0dd96a351..fe2d072e1acc 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -486,8 +486,11 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id) static int asus_wmi_input_init(struct asus_wmi *asus) { + struct device *dev; int err, result; + dev = &asus->platform_device->dev; + asus->inputdev = input_allocate_device(); if (!asus->inputdev) return -ENOMEM; @@ -495,35 +498,38 @@ static int asus_wmi_input_init(struct asus_wmi *asus) asus->inputdev->name = asus->driver->input_name; asus->inputdev->phys = asus->driver->input_phys; asus->inputdev->id.bustype = BUS_HOST; - asus->inputdev->dev.parent = &asus->platform_device->dev; + asus->inputdev->dev.parent = dev; set_bit(EV_REP, asus->inputdev->evbit); err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); if (err) goto err_free_dev; - if (asus->driver->quirks->use_kbd_dock_devid) { + switch (asus->driver->quirks->tablet_switch_mode) { + case asus_wmi_no_tablet_switch: + break; + case asus_wmi_kbd_dock_devid: result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK); if (result >= 0) { input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); input_report_switch(asus->inputdev, SW_TABLET_MODE, !result); } else if (result != -ENODEV) { - pr_err("Error checking for keyboard-dock: %d\n", result); + dev_err(dev, "Error checking for keyboard-dock: %d\n", result); } - } - - if (asus->driver->quirks->use_lid_flip_devid) { + break; + case asus_wmi_lid_flip_devid: result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP); if (result < 0) - asus->driver->quirks->use_lid_flip_devid = 0; + asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; if (result >= 0) { input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); input_report_switch(asus->inputdev, SW_TABLET_MODE, result); } else if (result == -ENODEV) { - pr_err("This device has lid_flip quirk but got ENODEV checking it. This is a bug."); + dev_err(dev, "This device has lid_flip quirk but got ENODEV checking it. This is a bug."); } else { - pr_err("Error checking for lid-flip: %d\n", result); + dev_err(dev, "Error checking for lid-flip: %d\n", result); } + break; } err = input_register_device(asus->inputdev); @@ -549,8 +555,9 @@ static void asus_wmi_input_exit(struct asus_wmi *asus) static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus) { - int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP); + int result; + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP); if (result >= 0) { input_report_switch(asus->inputdev, SW_TABLET_MODE, result); input_sync(asus->inputdev); @@ -3044,7 +3051,8 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) return; } - if (asus->driver->quirks->use_kbd_dock_devid && code == NOTIFY_KBD_DOCK_CHANGE) { + if (asus->driver->quirks->tablet_switch_mode == asus_wmi_kbd_dock_devid && + code == NOTIFY_KBD_DOCK_CHANGE) { result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK); if (result >= 0) { @@ -3055,7 +3063,8 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) return; } - if (asus->driver->quirks->use_lid_flip_devid && code == NOTIFY_LID_FLIP) { + if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_devid && + code == NOTIFY_LID_FLIP) { lid_flip_tablet_mode_get_state(asus); return; } @@ -3685,8 +3694,14 @@ static int asus_hotk_resume(struct device *device) if (asus_wmi_has_fnlock_key(asus)) asus_wmi_fnlock_update(asus); - if (asus->driver->quirks->use_lid_flip_devid) + switch (asus->driver->quirks->tablet_switch_mode) { + case asus_wmi_no_tablet_switch: + case asus_wmi_kbd_dock_devid: + break; + case asus_wmi_lid_flip_devid: lid_flip_tablet_mode_get_state(asus); + break; + } return 0; } @@ -3727,8 +3742,14 @@ static int asus_hotk_restore(struct device *device) if (asus_wmi_has_fnlock_key(asus)) asus_wmi_fnlock_update(asus); - if (asus->driver->quirks->use_lid_flip_devid) + switch (asus->driver->quirks->tablet_switch_mode) { + case asus_wmi_no_tablet_switch: + case asus_wmi_kbd_dock_devid: + break; + case asus_wmi_lid_flip_devid: lid_flip_tablet_mode_get_state(asus); + break; + } return 0; } diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index b302415bf1d9..413920bad0c6 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -25,6 +25,12 @@ struct module; struct key_entry; struct asus_wmi; +enum asus_wmi_tablet_switch_mode { + asus_wmi_no_tablet_switch, + asus_wmi_kbd_dock_devid, + asus_wmi_lid_flip_devid, +}; + struct quirk_entry { bool hotplug_wireless; bool scalar_panel_brightness; @@ -33,8 +39,7 @@ struct quirk_entry { bool wmi_backlight_native; bool wmi_backlight_set_devstate; bool wmi_force_als_set; - bool use_kbd_dock_devid; - bool use_lid_flip_devid; + enum asus_wmi_tablet_switch_mode tablet_switch_mode; int wapf; /* * For machines with AMD graphic chips, it will send out WMI event -- cgit v1.2.3 From e397c3c460bf3849384f2f55516d1887617cfca9 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 13 Aug 2022 21:27:53 +1200 Subject: platform/x86: asus-wmi: Add support for ROG X13 tablet mode Add quirk for ASUS ROG X13 Flow 2-in-1 to enable tablet mode with lid flip (all screen rotations). Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220813092753.6635-2-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-nb-wmi.c | 15 ++++++++++++ drivers/platform/x86/asus-wmi.c | 37 ++++++++++++++++++++++++++++++ drivers/platform/x86/asus-wmi.h | 1 + include/linux/platform_data/x86/asus-wmi.h | 1 + 4 files changed, 54 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 4672a2b8322e..d9e7cf6e4a0e 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -123,6 +123,11 @@ static struct quirk_entry quirk_asus_use_lid_flip_devid = { .tablet_switch_mode = asus_wmi_lid_flip_devid, }; +static struct quirk_entry quirk_asus_tablet_mode = { + .wmi_backlight_set_devstate = true, + .tablet_switch_mode = asus_wmi_lid_flip_rog_devid, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { pr_info("Identified laptop model '%s'\n", dmi->ident); @@ -471,6 +476,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_use_lid_flip_devid, }, + { + .callback = dmi_matched, + .ident = "ASUS ROG FLOW X13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GV301Q"), + }, + .driver_data = &quirk_asus_tablet_mode, + }, {}, }; @@ -578,6 +592,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ + { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */ { KE_END, 0}, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index fe2d072e1acc..5352055848d0 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -68,6 +68,7 @@ module_param(fnlock_default, bool, 0444); #define NOTIFY_KBD_FBM 0x99 #define NOTIFY_KBD_TTP 0xae #define NOTIFY_LID_FLIP 0xfa +#define NOTIFY_LID_FLIP_ROG 0xbd #define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0) @@ -530,6 +531,19 @@ static int asus_wmi_input_init(struct asus_wmi *asus) dev_err(dev, "Error checking for lid-flip: %d\n", result); } break; + case asus_wmi_lid_flip_rog_devid: + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG); + if (result < 0) + asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; + if (result >= 0) { + input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); + input_report_switch(asus->inputdev, SW_TABLET_MODE, result); + } else if (result == -ENODEV) { + dev_err(dev, "This device has lid-flip-rog quirk but got ENODEV checking it. This is a bug."); + } else { + dev_err(dev, "Error checking for lid-flip: %d\n", result); + } + break; } err = input_register_device(asus->inputdev); @@ -564,6 +578,17 @@ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus) } } +static void lid_flip_rog_tablet_mode_get_state(struct asus_wmi *asus) +{ + int result; + + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG); + if (result >= 0) { + input_report_switch(asus->inputdev, SW_TABLET_MODE, result); + input_sync(asus->inputdev); + } +} + /* dGPU ********************************************************************/ static ssize_t dgpu_disable_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -3069,6 +3094,12 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) return; } + if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_rog_devid && + code == NOTIFY_LID_FLIP_ROG) { + lid_flip_rog_tablet_mode_get_state(asus); + return; + } + if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) { fan_boost_mode_switch_next(asus); return; @@ -3701,6 +3732,9 @@ static int asus_hotk_resume(struct device *device) case asus_wmi_lid_flip_devid: lid_flip_tablet_mode_get_state(asus); break; + case asus_wmi_lid_flip_rog_devid: + lid_flip_rog_tablet_mode_get_state(asus); + break; } return 0; @@ -3749,6 +3783,9 @@ static int asus_hotk_restore(struct device *device) case asus_wmi_lid_flip_devid: lid_flip_tablet_mode_get_state(asus); break; + case asus_wmi_lid_flip_rog_devid: + lid_flip_rog_tablet_mode_get_state(asus); + break; } return 0; diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 413920bad0c6..0187f13d2414 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -29,6 +29,7 @@ enum asus_wmi_tablet_switch_mode { asus_wmi_no_tablet_switch, asus_wmi_kbd_dock_devid, asus_wmi_lid_flip_devid, + asus_wmi_lid_flip_rog_devid, }; struct quirk_entry { diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 70d2347bf6ca..6e8a95c10d17 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -65,6 +65,7 @@ #define ASUS_WMI_DEVID_PANEL_OD 0x00050019 #define ASUS_WMI_DEVID_CAMERA 0x00060013 #define ASUS_WMI_DEVID_LID_FLIP 0x00060062 +#define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077 /* Storage */ #define ASUS_WMI_DEVID_CARDREADER 0x00080013 -- cgit v1.2.3 From c98dc61ee08f833e68337700546e120e2edac7c9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Aug 2022 17:11:44 +0200 Subject: platform/x86: asus-wmi: Simplify tablet-mode-switch probing The 3 different tablet-mode-switch initialization paths repeat a lot of the same code. Add a helper function for this. This also makes the error-handling for the kbd_dock_devid case consistent with the other 2 cases. Cc: Luke D. Jones Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220824151145.1448010-1-hdegoede@redhat.com --- drivers/platform/x86/asus-wmi.c | 55 +++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 33 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 5352055848d0..d71daa024752 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -484,13 +484,28 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id) } /* Input **********************************************************************/ +static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code) +{ + struct device *dev = &asus->platform_device->dev; + int result; + + result = asus_wmi_get_devstate_simple(asus, dev_id); + if (result < 0) + asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; + if (result >= 0) { + input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); + input_report_switch(asus->inputdev, SW_TABLET_MODE, result); + } else if (result == -ENODEV) { + dev_err(dev, "This device has tablet-mode-switch quirk but got ENODEV checking it. This is a bug."); + } else { + dev_err(dev, "Error checking for tablet-mode-switch: %d\n", result); + } +} static int asus_wmi_input_init(struct asus_wmi *asus) { - struct device *dev; - int err, result; - - dev = &asus->platform_device->dev; + struct device *dev = &asus->platform_device->dev; + int err; asus->inputdev = input_allocate_device(); if (!asus->inputdev) @@ -510,39 +525,13 @@ static int asus_wmi_input_init(struct asus_wmi *asus) case asus_wmi_no_tablet_switch: break; case asus_wmi_kbd_dock_devid: - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK); - if (result >= 0) { - input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); - input_report_switch(asus->inputdev, SW_TABLET_MODE, !result); - } else if (result != -ENODEV) { - dev_err(dev, "Error checking for keyboard-dock: %d\n", result); - } + asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE); break; case asus_wmi_lid_flip_devid: - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP); - if (result < 0) - asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; - if (result >= 0) { - input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); - input_report_switch(asus->inputdev, SW_TABLET_MODE, result); - } else if (result == -ENODEV) { - dev_err(dev, "This device has lid_flip quirk but got ENODEV checking it. This is a bug."); - } else { - dev_err(dev, "Error checking for lid-flip: %d\n", result); - } + asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP, NOTIFY_LID_FLIP); break; case asus_wmi_lid_flip_rog_devid: - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG); - if (result < 0) - asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; - if (result >= 0) { - input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); - input_report_switch(asus->inputdev, SW_TABLET_MODE, result); - } else if (result == -ENODEV) { - dev_err(dev, "This device has lid-flip-rog quirk but got ENODEV checking it. This is a bug."); - } else { - dev_err(dev, "Error checking for lid-flip: %d\n", result); - } + asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP_ROG, NOTIFY_LID_FLIP_ROG); break; } -- cgit v1.2.3 From 1ea0d3b46798afc35c3185f6058b8bc08525d56c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Aug 2022 17:11:45 +0200 Subject: platform/x86: asus-wmi: Simplify tablet-mode-switch handling Simplify tablet-mode-switch handling: 1. The code is the same for all variants, the only difference is the dev_id and notify event code. Store the dev_id + code in struct asus_wmi and unify the handling 2. Make the new unified asus_wmi_tablet_mode_get_state() check dev_id has been set and make it a no-op when not set. This allows calling it unconditionally at resume/restore time 3. Simplify the tablet_mode_sw module-param handling, this also allows selecting the new lid-flip-rog type through the module-param. Cc: Luke D. Jones Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220824151145.1448010-2-hdegoede@redhat.com --- drivers/platform/x86/asus-nb-wmi.c | 13 +------ drivers/platform/x86/asus-wmi.c | 76 +++++++------------------------------- 2 files changed, 16 insertions(+), 73 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index d9e7cf6e4a0e..cb8af61d684c 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -504,17 +504,8 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) else wapf = quirks->wapf; - switch (tablet_mode_sw) { - case 0: - quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; - break; - case 1: - quirks->tablet_switch_mode = asus_wmi_kbd_dock_devid; - break; - case 2: - quirks->tablet_switch_mode = asus_wmi_lid_flip_devid; - break; - } + if (tablet_mode_sw != -1) + quirks->tablet_switch_mode = tablet_mode_sw; if (quirks->i8042_filter) { ret = i8042_install_filter(quirks->i8042_filter); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d71daa024752..0f9f79f249c7 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -222,6 +222,9 @@ struct asus_wmi { struct asus_rfkill gps; struct asus_rfkill uwb; + int tablet_switch_event_code; + u32 tablet_switch_dev_id; + enum fan_type fan_type; int fan_pwm_mode; int agfn_pwm; @@ -490,11 +493,11 @@ static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event int result; result = asus_wmi_get_devstate_simple(asus, dev_id); - if (result < 0) - asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch; if (result >= 0) { input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); input_report_switch(asus->inputdev, SW_TABLET_MODE, result); + asus->tablet_switch_dev_id = dev_id; + asus->tablet_switch_event_code = event_code; } else if (result == -ENODEV) { dev_err(dev, "This device has tablet-mode-switch quirk but got ENODEV checking it. This is a bug."); } else { @@ -556,22 +559,14 @@ static void asus_wmi_input_exit(struct asus_wmi *asus) /* Tablet mode ****************************************************************/ -static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus) +static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) { int result; - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP); - if (result >= 0) { - input_report_switch(asus->inputdev, SW_TABLET_MODE, result); - input_sync(asus->inputdev); - } -} - -static void lid_flip_rog_tablet_mode_get_state(struct asus_wmi *asus) -{ - int result; + if (!asus->tablet_switch_dev_id) + return; - result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG); + result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id); if (result >= 0) { input_report_switch(asus->inputdev, SW_TABLET_MODE, result); input_sync(asus->inputdev); @@ -3020,9 +3015,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) { unsigned int key_value = 1; bool autorelease = 1; - int result, orig_code; - - orig_code = code; + int orig_code = code; if (asus->driver->key_filter) { asus->driver->key_filter(asus->driver, &code, &key_value, @@ -3065,27 +3058,8 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) return; } - if (asus->driver->quirks->tablet_switch_mode == asus_wmi_kbd_dock_devid && - code == NOTIFY_KBD_DOCK_CHANGE) { - result = asus_wmi_get_devstate_simple(asus, - ASUS_WMI_DEVID_KBD_DOCK); - if (result >= 0) { - input_report_switch(asus->inputdev, SW_TABLET_MODE, - !result); - input_sync(asus->inputdev); - } - return; - } - - if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_devid && - code == NOTIFY_LID_FLIP) { - lid_flip_tablet_mode_get_state(asus); - return; - } - - if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_rog_devid && - code == NOTIFY_LID_FLIP_ROG) { - lid_flip_rog_tablet_mode_get_state(asus); + if (code == asus->tablet_switch_event_code) { + asus_wmi_tablet_mode_get_state(asus); return; } @@ -3714,18 +3688,7 @@ static int asus_hotk_resume(struct device *device) if (asus_wmi_has_fnlock_key(asus)) asus_wmi_fnlock_update(asus); - switch (asus->driver->quirks->tablet_switch_mode) { - case asus_wmi_no_tablet_switch: - case asus_wmi_kbd_dock_devid: - break; - case asus_wmi_lid_flip_devid: - lid_flip_tablet_mode_get_state(asus); - break; - case asus_wmi_lid_flip_rog_devid: - lid_flip_rog_tablet_mode_get_state(asus); - break; - } - + asus_wmi_tablet_mode_get_state(asus); return 0; } @@ -3765,18 +3728,7 @@ static int asus_hotk_restore(struct device *device) if (asus_wmi_has_fnlock_key(asus)) asus_wmi_fnlock_update(asus); - switch (asus->driver->quirks->tablet_switch_mode) { - case asus_wmi_no_tablet_switch: - case asus_wmi_kbd_dock_devid: - break; - case asus_wmi_lid_flip_devid: - lid_flip_tablet_mode_get_state(asus); - break; - case asus_wmi_lid_flip_rog_devid: - lid_flip_rog_tablet_mode_get_state(asus); - break; - } - + asus_wmi_tablet_mode_get_state(asus); return 0; } -- cgit v1.2.3 From 98a2aea68873db440770153b4e87d0e1e6dd7a90 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 Aug 2022 11:29:21 +0200 Subject: platform/x86: asus-wmi: Update tablet_mode_sw module-param help text Document how to select asus_wmi_lid_flip_rog_devid as tablet_switch_mode by adding "3:lid-flip-rog" to the tablet_mode_sw module-param help text. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220826092921.8907-1-hdegoede@redhat.com --- drivers/platform/x86/asus-nb-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index cb8af61d684c..aad5cc0e0092 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(wapf, "WAPF value"); static int tablet_mode_sw = -1; module_param(tablet_mode_sw, uint, 0444); -MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip"); +MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip 3:lid-flip-rog"); static struct quirk_entry *quirks; -- cgit v1.2.3 From 601eb4c8e1500285d1c40eacb1e2da19bf220e12 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 26 Aug 2022 12:42:09 +1200 Subject: platform/x86: asus-wmi: Modify behaviour of Fn+F5 fan key Some more recent TUF laptops have both fan_boost and thermal_throttle. The key code for Fn+F5 is also different and unmapped. This patch adjusts the asus_wmi_handle_event_code() match to match for both 0x99 and 0xAE, and run both mode switch functions for fan_boost and/or thermal_throttle if either are available. It is required that both are tried, as in some instances the ACPI set-method for one may not have any code body within it even though it was returned as supported by the get method. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220826004210.356534-2-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-nb-wmi.c | 1 + drivers/platform/x86/asus-wmi.c | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index aad5cc0e0092..432167690075 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -577,6 +577,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */ { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */ { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */ + { KE_KEY, 0xAE, { KEY_FN_F5 } }, /* Fn+F5 fan mode on 2020+ */ { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */ { KE_KEY, 0xB5, { KEY_CALC } }, { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 0f9f79f249c7..94e0be80baba 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -3063,14 +3063,13 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) return; } - if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) { - fan_boost_mode_switch_next(asus); + if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) { + if (asus->fan_boost_mode_available) + fan_boost_mode_switch_next(asus); + if (asus->throttle_thermal_policy_available) + throttle_thermal_policy_switch_next(asus); return; - } - if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) { - throttle_thermal_policy_switch_next(asus); - return; } if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle) -- cgit v1.2.3 From 12ff4c803d23218f9afea9f82019a5c9619f6744 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 26 Aug 2022 12:42:10 +1200 Subject: platform/x86: asus-wmi: Support the GPU fan on TUF laptops Add support for TUF laptops which have the ability to control the GPU fan. This will show as a second fan in hwmon, and has the ability to run as boost (fullspeed), or auto. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220826004210.356534-3-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 71 ++++++++++++++++++++++++++++++ include/linux/platform_data/x86/asus-wmi.h | 1 + 2 files changed, 72 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 94e0be80baba..eebc20c70bf7 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -226,7 +226,9 @@ struct asus_wmi { u32 tablet_switch_dev_id; enum fan_type fan_type; + enum fan_type gpu_fan_type; int fan_pwm_mode; + int gpu_fan_pwm_mode; int agfn_pwm; bool fan_boost_mode_available; @@ -1734,6 +1736,18 @@ static int asus_fan_set_auto(struct asus_wmi *asus) return -ENXIO; } + /* + * Modern models like the G713 also have GPU fan control (this is not AGFN) + */ + if (asus->gpu_fan_type == FAN_TYPE_SPEC83) { + status = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL, + 0, &retval); + if (status) + return status; + + if (retval != 1) + return -EIO; + } return 0; } @@ -1936,9 +1950,57 @@ static ssize_t asus_hwmon_temp1(struct device *dev, deci_kelvin_to_millicelsius(value & 0xFFFF)); } +/* GPU fan on modern ROG laptops */ +static ssize_t pwm2_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", asus->gpu_fan_pwm_mode); +} + +static ssize_t pwm2_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + int state; + int value; + int ret; + u32 retval; + + ret = kstrtouint(buf, 10, &state); + if (ret) + return ret; + + switch (state) { /* standard documented hwmon values */ + case ASUS_FAN_CTRL_FULLSPEED: + value = 1; + break; + case ASUS_FAN_CTRL_AUTO: + value = 0; + break; + default: + return -EINVAL; + } + + ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL, + value, &retval); + if (ret) + return ret; + + if (retval != 1) + return -EIO; + + asus->gpu_fan_pwm_mode = state; + return count; +} + /* Fan1 */ static DEVICE_ATTR_RW(pwm1); static DEVICE_ATTR_RW(pwm1_enable); +static DEVICE_ATTR_RW(pwm2_enable); static DEVICE_ATTR_RO(fan1_input); static DEVICE_ATTR_RO(fan1_label); @@ -1948,6 +2010,7 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL); static struct attribute *hwmon_attributes[] = { &dev_attr_pwm1.attr, &dev_attr_pwm1_enable.attr, + &dev_attr_pwm2_enable.attr, &dev_attr_fan1_input.attr, &dev_attr_fan1_label.attr, @@ -1970,6 +2033,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, || attr == &dev_attr_pwm1_enable.attr) { if (asus->fan_type == FAN_TYPE_NONE) return 0; + } else if (attr == &dev_attr_pwm2_enable.attr) { + if (asus->gpu_fan_type == FAN_TYPE_NONE) + return 0; } else if (attr == &dev_attr_temp1_input.attr) { int err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, @@ -2012,6 +2078,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus) static int asus_wmi_fan_init(struct asus_wmi *asus) { + asus->gpu_fan_type = FAN_TYPE_NONE; asus->fan_type = FAN_TYPE_NONE; asus->agfn_pwm = -1; @@ -2020,6 +2087,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus) else if (asus_wmi_has_agfn_fan(asus)) asus->fan_type = FAN_TYPE_AGFN; + /* Modern models like G713 also have GPU fan control */ + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL)) + asus->gpu_fan_type = FAN_TYPE_SPEC83; + if (asus->fan_type == FAN_TYPE_NONE) return -ENODEV; diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 6e8a95c10d17..31d810e6569d 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -79,6 +79,7 @@ #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */ #define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013 +#define ASUS_WMI_DEVID_GPU_FAN_CTRL 0x00110014 #define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024 #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025 -- cgit v1.2.3 From e305a71cea37a64c7558b8b979f6f08f657d0c3d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 26 Aug 2022 11:22:50 +1200 Subject: platform/x86: asus-wmi: Implement TUF laptop keyboard LED modes Adds support for changing the laptop keyboard LED mode and colour. The modes are visible effects such as static, rainbow, pulsing, colour cycles. These sysfs attributes are added to asus::kbd_backlight: - kbd_rgb_mode - kbd_rgb_mode_index Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220825232251.345893-2-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 74 +++++++++++++++++++++++++++++- include/linux/platform_data/x86/asus-wmi.h | 3 ++ 2 files changed, 76 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index eebc20c70bf7..46cd91efd693 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -239,6 +239,8 @@ struct asus_wmi { bool dgpu_disable_available; bool gpu_mux_mode_available; + bool kbd_rgb_mode_available; + bool throttle_thermal_policy_available; u8 throttle_thermal_policy_mode; @@ -722,6 +724,69 @@ static ssize_t gpu_mux_mode_store(struct device *dev, } static DEVICE_ATTR_RW(gpu_mux_mode); +/* TUF Laptop Keyboard RGB Modes **********************************************/ +static ssize_t kbd_rgb_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 cmd, mode, r, g, b, speed; + int err; + + if (sscanf(buf, "%d %d %d %d %d %d", &cmd, &mode, &r, &g, &b, &speed) != 6) + return -EINVAL; + + cmd = !!cmd; + + /* These are the known usable modes across all TUF/ROG */ + if (mode >= 12 || mode == 9) + mode = 10; + + switch (speed) { + case 0: + speed = 0xe1; + break; + case 1: + speed = 0xeb; + break; + case 2: + speed = 0xf5; + break; + default: + speed = 0xeb; + } + + err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, ASUS_WMI_DEVID_TUF_RGB_MODE, + cmd | (mode << 8) | (r << 16) | (g << 24), b | (speed << 8), NULL); + if (err) + return err; + + return count; +} +static DEVICE_ATTR_WO(kbd_rgb_mode); + +static ssize_t kbd_rgb_mode_index_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", "cmd mode red green blue speed"); +} +static DEVICE_ATTR_RO(kbd_rgb_mode_index); + +static struct attribute *kbd_rgb_mode_attrs[] = { + &dev_attr_kbd_rgb_mode.attr, + &dev_attr_kbd_rgb_mode_index.attr, + NULL, +}; + +static const struct attribute_group kbd_rgb_mode_group = { + .attrs = kbd_rgb_mode_attrs, +}; + +const struct attribute_group *kbd_rgb_mode_groups[] = { + NULL, + NULL, +}; + /* Battery ********************************************************************/ /* The battery maximum charging percentage */ @@ -1040,7 +1105,10 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) static int asus_wmi_led_init(struct asus_wmi *asus) { - int rv = 0, led_val; + int rv = 0, num_rgb_groups = 0, led_val; + + if (asus->kbd_rgb_mode_available) + kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group; asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!asus->led_workqueue) @@ -1068,6 +1136,9 @@ static int asus_wmi_led_init(struct asus_wmi *asus) asus->kbd_led.brightness_get = kbd_led_get; asus->kbd_led.max_brightness = 3; + if (num_rgb_groups != 0) + asus->kbd_led.groups = kbd_rgb_mode_groups; + rv = led_classdev_register(&asus->platform_device->dev, &asus->kbd_led); if (rv) @@ -3589,6 +3660,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->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX); + asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE); asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); err = fan_boost_mode_check_present(asus); diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 31d810e6569d..09e5477f1aea 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -104,6 +104,9 @@ /* gpu mux switch, 0 = dGPU, 1 = Optimus */ #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 +/* TUF laptop RGB modes/colours */ +#define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056 + /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 -- cgit v1.2.3 From 61f64515299e5f4885093656087ec1c0df8109c5 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 26 Aug 2022 11:22:51 +1200 Subject: platform/x86: asus-wmi: Implement TUF laptop keyboard power states Adds support for setting various power states of TUF keyboards. These states are combinations of: - boot, set if a boot animation is shown on keyboard - awake, set if the keyboard LEDs are visible while laptop is on - sleep, set if an animation is displayed while the laptop is suspended - keyboard (unknown effect) Adds two sysfs attributes to asus::kbd_backlight: - kbd_rgb_state - kbd_rgb_state_index Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220825232251.345893-3-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 57 ++++++++++++++++++++++++++++++ include/linux/platform_data/x86/asus-wmi.h | 3 ++ 2 files changed, 60 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 46cd91efd693..bb430260653e 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -240,6 +240,7 @@ struct asus_wmi { bool gpu_mux_mode_available; bool kbd_rgb_mode_available; + bool kbd_rgb_state_available; bool throttle_thermal_policy_available; u8 throttle_thermal_policy_mode; @@ -782,9 +783,62 @@ static const struct attribute_group kbd_rgb_mode_group = { .attrs = kbd_rgb_mode_attrs, }; +/* TUF Laptop Keyboard RGB State **********************************************/ +static ssize_t kbd_rgb_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 flags, cmd, boot, awake, sleep, keyboard; + int err; + + if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &keyboard) != 5) + return -EINVAL; + + if (cmd) + cmd = BIT(2); + + flags = 0; + if (boot) + flags |= BIT(1); + if (awake) + flags |= BIT(3); + if (sleep) + flags |= BIT(5); + if (keyboard) + flags |= BIT(7); + + /* 0xbd is the required default arg0 for the method. Nothing happens otherwise */ + err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, + ASUS_WMI_DEVID_TUF_RGB_STATE, 0xbd | cmd << 8 | (flags << 16), 0, NULL); + if (err) + return err; + + return count; +} +static DEVICE_ATTR_WO(kbd_rgb_state); + +static ssize_t kbd_rgb_state_index_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", "cmd boot awake sleep keyboard"); +} +static DEVICE_ATTR_RO(kbd_rgb_state_index); + +static struct attribute *kbd_rgb_state_attrs[] = { + &dev_attr_kbd_rgb_state.attr, + &dev_attr_kbd_rgb_state_index.attr, + NULL, +}; + +static const struct attribute_group kbd_rgb_state_group = { + .attrs = kbd_rgb_state_attrs, +}; + const struct attribute_group *kbd_rgb_mode_groups[] = { NULL, NULL, + NULL, }; /* Battery ********************************************************************/ @@ -1109,6 +1163,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus) if (asus->kbd_rgb_mode_available) kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group; + if (asus->kbd_rgb_state_available) + kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_state_group; asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!asus->led_workqueue) @@ -3661,6 +3717,7 @@ static int asus_wmi_add(struct platform_device *pdev) asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX); asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE); + asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); err = fan_boost_mode_check_present(asus); diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 09e5477f1aea..28234dc9fa6a 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -107,6 +107,9 @@ /* TUF laptop RGB modes/colours */ #define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056 +/* TUF laptop RGB power/state */ +#define ASUS_WMI_DEVID_TUF_RGB_STATE 0x00100057 + /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 -- cgit v1.2.3 From 8028d5d481ebed904388e7248deea1f3620511eb Mon Sep 17 00:00:00 2001 From: PaddyKP_Yao Date: Thu, 25 Aug 2022 08:43:05 +0800 Subject: platform/x86: asus-wmi: Fix the name of the mic-mute LED classdev According to well-known-leds.txt, we should use "platform::micmute" instead of "asus::micmute" for the name of the mic-mute LED classdev. Signed-off-by: PaddyKP_Yao Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220825004305.709539-1-PaddyKP_Yao@asus.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index bb430260653e..3d9fd58573f9 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1232,7 +1232,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus) } if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MICMUTE_LED)) { - asus->micmute_led.name = "asus::micmute"; + asus->micmute_led.name = "platform::micmute"; asus->micmute_led.max_brightness = 1; asus->micmute_led.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); asus->micmute_led.brightness_set_blocking = micmute_led_set; -- cgit v1.2.3 From 9c9ac2e659e1b009d16a1f43d8ca26abcf17e0bb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Aug 2022 23:00:57 +0200 Subject: platform/x86: move from strlcpy with unused retval to strscpy Follow the advice of the below link and prefer 'strscpy' in this subsystem. Conversion is 1:1 because the return value is not used. Generated by a coccinelle script. Link: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/ Signed-off-by: Wolfram Sang Reviewed-by: Andy Shevchenko Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20220818210058.7229-1-wsa+renesas@sang-engineering.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface3_power.c | 2 +- drivers/platform/x86/dell/dell-wmi-sysman/sysman.c | 2 +- drivers/platform/x86/intel/chtwc_int33fe.c | 6 +++--- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/surface/surface3_power.c b/drivers/platform/surface/surface3_power.c index 444ec81ba02d..4c53d116d59b 100644 --- a/drivers/platform/surface/surface3_power.c +++ b/drivers/platform/surface/surface3_power.c @@ -519,7 +519,7 @@ static int mshw0011_probe(struct i2c_client *client) i2c_set_clientdata(client, data); memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE); + strscpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE); bat0 = i2c_acpi_new_device(dev, 1, &board_info); if (IS_ERR(bat0)) diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c index 636bdfa83284..0a6411a8a104 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c @@ -270,7 +270,7 @@ void strlcpy_attr(char *dest, char *src) size_t len = strlen(src) + 1; if (len > 1 && len <= MAX_BUFF) - strlcpy(dest, src, len); + strscpy(dest, src, len); /*len can be zero because any property not-applicable to attribute can * be empty so check only for too long buffers and log error diff --git a/drivers/platform/x86/intel/chtwc_int33fe.c b/drivers/platform/x86/intel/chtwc_int33fe.c index c52ac23e2331..1ea989df513c 100644 --- a/drivers/platform/x86/intel/chtwc_int33fe.c +++ b/drivers/platform/x86/intel/chtwc_int33fe.c @@ -270,7 +270,7 @@ cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data) } memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); + strscpy(board_info.type, "max17047", I2C_NAME_SIZE); board_info.dev_name = "max17047"; board_info.fwnode = fwnode; data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); @@ -361,7 +361,7 @@ static int cht_int33fe_typec_probe(struct platform_device *pdev) } memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); + strscpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); board_info.dev_name = "fusb302"; board_info.fwnode = fwnode; board_info.irq = fusb302_irq; @@ -381,7 +381,7 @@ static int cht_int33fe_typec_probe(struct platform_device *pdev) memset(&board_info, 0, sizeof(board_info)); board_info.dev_name = "pi3usb30532"; board_info.fwnode = fwnode; - strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); + strscpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); if (IS_ERR(data->pi3usb30532)) { diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 22d4e8633e30..8dad0428a83c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -7623,9 +7623,9 @@ static int __init volume_create_alsa_mixer(void) data = card->private_data; data->card = card; - strlcpy(card->driver, TPACPI_ALSA_DRVNAME, + strscpy(card->driver, TPACPI_ALSA_DRVNAME, sizeof(card->driver)); - strlcpy(card->shortname, TPACPI_ALSA_SHRTNAME, + strscpy(card->shortname, TPACPI_ALSA_SHRTNAME, sizeof(card->shortname)); snprintf(card->mixername, sizeof(card->mixername), "ThinkPad EC %s", (thinkpad_id.ec_version_str) ? -- cgit v1.2.3 From 23657a437ea2fbccc715fce2dac74e3c923540cf Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 19 Aug 2022 13:01:00 -0500 Subject: platform/x86: thinkpad_acpi: Explicitly set to balanced mode on startup It was observed that on a Thinkpad T14 Gen1 (AMD) that the platform profile is starting up in 'low-power' mode after refreshing what the firmware had. This is most likely a firmware bug, but as a harmless workaround set the default profile to 'balanced' at thinkpad_acpi startup. Reported-by: madcatx@atlas.cz Link: https://bugzilla.kernel.org/show_bug.cgi?id=216347 Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220819180101.6383-1-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 8dad0428a83c..8fbe21ebcc52 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10592,10 +10592,9 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) /* Ensure initial values are correct */ dytc_profile_refresh(); - /* Set AMT correctly now we know current profile */ - if ((dytc_capabilities & BIT(DYTC_FC_PSC)) && - (dytc_capabilities & BIT(DYTC_FC_AMT))) - dytc_control_amt(dytc_current_profile == PLATFORM_PROFILE_BALANCED); + /* Workaround for https://bugzilla.kernel.org/show_bug.cgi?id=216347 */ + if (dytc_capabilities & BIT(DYTC_FC_PSC)) + dytc_profile_set(NULL, PLATFORM_PROFILE_BALANCED); return 0; } -- cgit v1.2.3 From 4058ea22d7ce26d3d71698768e636274d08e9ccd Mon Sep 17 00:00:00 2001 From: Arvid Norlander Date: Sun, 21 Aug 2022 22:08:21 +0200 Subject: platform/x86: toshiba_acpi: Fix ECO LED control on Toshiba Z830 The toshiba_acpi driver checks for TOS_INPUT_DATA_ERROR and tries a different format. On the Z830 the error returned is TOS_NOT_SUPPORTED though the different format still works. Allow either error. Signed-off-by: Arvid Norlander Link: https://lore.kernel.org/r/20220821200821.1837460-2-lkml@vorpal.se Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/toshiba_acpi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 0fc9e8b8827b..6cc617b2940e 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -675,12 +675,15 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) return; } - if (out[0] == TOS_INPUT_DATA_ERROR) { + if (out[0] == TOS_INPUT_DATA_ERROR || out[0] == TOS_NOT_SUPPORTED) { /* * If we receive 0x8300 (Input Data Error), it means that the * LED device is present, but that we just screwed the input * parameters. * + * On some laptops 0x8000 (Not supported) is also returned in + * this case, so we need to allow for that as well. + * * Let's query the status of the LED to see if we really have a * success response, indicating the actual presense of the LED, * bail out otherwise. -- cgit v1.2.3 From ae030bbf7bdb253e4c9d3c53175aa018c3e9bee9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 22 Aug 2022 17:08:17 +0200 Subject: platform/x86: msi-laptop: Use MODULE_DEVICE_TABLE() Use MODULE_DEVICE_TABLE() instead of manually adding a bunch of MODULE_ALIAS() statements. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220822150818.45765-1-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 24ffc8e2d2d1..843f72200cfc 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -705,6 +705,7 @@ static const struct dmi_system_id msi_dmi_table[] __initconst = { }, { } }; +MODULE_DEVICE_TABLE(dmi, msi_dmi_table); static int rfkill_bluetooth_set(void *data, bool blocked) { @@ -1166,14 +1167,3 @@ MODULE_AUTHOR("Lennart Poettering"); MODULE_DESCRIPTION("MSI Laptop Support"); MODULE_VERSION(MSI_DRIVER_VERSION); MODULE_LICENSE("GPL"); - -MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); -MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*"); -MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); -MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); -MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*"); -MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*"); -MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*"); -MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*"); -MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*"); -MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnU90/U100:*"); -- cgit v1.2.3 From 6485f72b515690bdbebc711755af096d1dc08ce2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 22 Aug 2022 17:08:18 +0200 Subject: platform/x86: msi-laptop: Drop MSI_DRIVER_VERSION Modules carrying there own version is a practice which the kernel has stopped doing for a long time now, drop it. While dropping the version pr_info from msi_init() lets remove the somewhat useless pr_info() from msi_cleanup() as well. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220822150818.45765-2-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 843f72200cfc..93ef8851b93e 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -53,8 +53,6 @@ #include #include -#define MSI_DRIVER_VERSION "0.5" - #define MSI_LCD_LEVEL_MAX 9 #define MSI_EC_COMMAND_WIRELESS 0x10 @@ -1109,8 +1107,6 @@ static int __init msi_init(void) set_auto_brightness(auto_brightness); } - pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n"); - return 0; fail_create_attr: @@ -1156,8 +1152,6 @@ static void __exit msi_cleanup(void) if (auto_brightness != 2) set_auto_brightness(1); } - - pr_info("driver unloaded\n"); } module_init(msi_init); @@ -1165,5 +1159,4 @@ module_exit(msi_cleanup); MODULE_AUTHOR("Lennart Poettering"); MODULE_DESCRIPTION("MSI Laptop Support"); -MODULE_VERSION(MSI_DRIVER_VERSION); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 83ac7a1c2ed5f17caa07cbbc84bad3c05dc3bf22 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Aug 2022 16:13:34 +0200 Subject: platform/x86: msi-laptop: Fix old-ec check for backlight registering Commit 2cc6c717799f ("msi-laptop: Port to new backlight interface selection API") replaced this check: if (!quirks->old_ec_model || acpi_video_backlight_support()) pr_info("Brightness ignored, ..."); else do_register(); With: if (quirks->old_ec_model || acpi_video_get_backlight_type() == acpi_backlight_vendor) do_register(); But since the do_register() part was part of the else branch, the entire condition should be inverted. So not only the 2 statements on either side of the || should be inverted, but the || itself should be replaced with a &&. In practice this has likely not been an issue because the new-ec models (old_ec_model==false) likely all support ACPI video backlight control, making acpi_video_get_backlight_type() return acpi_backlight_video turning the second part of the || also false when old_ec_model == false. Fixes: 2cc6c717799f ("msi-laptop: Port to new backlight interface selection API") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220825141336.208597-1-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 93ef8851b93e..54170172a666 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -1047,8 +1047,7 @@ static int __init msi_init(void) return -EINVAL; /* Register backlight stuff */ - - if (quirks->old_ec_model || + if (quirks->old_ec_model && acpi_video_get_backlight_type() == acpi_backlight_vendor) { struct backlight_properties props; memset(&props, 0, sizeof(struct backlight_properties)); -- cgit v1.2.3 From 042184ea42e002e79ea844ffb658846c272f31bd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Aug 2022 16:13:35 +0200 Subject: platform/x86: msi-laptop: Simplify ec_delay handling There is no reason to have both non-delayed and delayed work structs for the rfkill and touchpad work. Instead simply call schedule_delayed_work() with a delay of 0 for the quirks->ec_delay == false case. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220825141336.208597-2-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 54170172a666..65db18c6e3e8 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -590,6 +590,14 @@ static int dmi_check_cb(const struct dmi_system_id *dmi) return 1; } +static unsigned long msi_work_delay(int msecs) +{ + if (quirks->ec_delay) + return msecs_to_jiffies(msecs); + + return 0; +} + static const struct dmi_system_id msi_dmi_table[] __initconst = { { .ident = "MSI S270", @@ -784,7 +792,6 @@ static void msi_update_rfkill(struct work_struct *ignored) msi_rfkill_set_state(rfk_threeg, !threeg_s); } static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill); -static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill); static void msi_send_touchpad_key(struct work_struct *ignored) { @@ -800,7 +807,6 @@ static void msi_send_touchpad_key(struct work_struct *ignored) KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); } static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key); -static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key); static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, struct serio *port) @@ -818,20 +824,12 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, extended = false; switch (data) { case 0xE4: - if (quirks->ec_delay) { - schedule_delayed_work(&msi_touchpad_dwork, - round_jiffies_relative(0.5 * HZ)); - } else - schedule_work(&msi_touchpad_work); + schedule_delayed_work(&msi_touchpad_dwork, msi_work_delay(500)); break; case 0x54: case 0x62: case 0x76: - if (quirks->ec_delay) { - schedule_delayed_work(&msi_rfkill_dwork, - round_jiffies_relative(0.5 * HZ)); - } else - schedule_work(&msi_rfkill_work); + schedule_delayed_work(&msi_rfkill_dwork, msi_work_delay(500)); break; } } @@ -898,12 +896,7 @@ static int rfkill_init(struct platform_device *sdev) } /* schedule to run rfkill state initial */ - if (quirks->ec_delay) { - schedule_delayed_work(&msi_rfkill_init, - round_jiffies_relative(1 * HZ)); - } else - schedule_work(&msi_rfkill_work); - + schedule_delayed_work(&msi_rfkill_init, msi_work_delay(1000)); return 0; err_threeg: @@ -1114,7 +1107,6 @@ fail_create_group: if (quirks->load_scm_model) { i8042_remove_filter(msi_laptop_i8042_filter); cancel_delayed_work_sync(&msi_rfkill_dwork); - cancel_work_sync(&msi_rfkill_work); rfkill_cleanup(); } fail_scm_model_init: @@ -1135,7 +1127,6 @@ static void __exit msi_cleanup(void) i8042_remove_filter(msi_laptop_i8042_filter); input_unregister_device(msi_laptop_input_dev); cancel_delayed_work_sync(&msi_rfkill_dwork); - cancel_work_sync(&msi_rfkill_work); rfkill_cleanup(); } -- cgit v1.2.3 From 5523632aa10f906dfe2eb714ee748590dc7fc6b1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Aug 2022 16:13:36 +0200 Subject: platform/x86: msi-laptop: Fix resource cleanup Fix the input-device not getting free-ed on probe-errors and fix the msi_touchpad_dwork not getting cancelled on neither probe-errors nor on remove. Fixes: 143a4c0284dc ("msi-laptop: send out touchpad on/off key") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220825141336.208597-3-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 65db18c6e3e8..5d4b10b8d771 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -1106,6 +1106,8 @@ fail_create_attr: fail_create_group: if (quirks->load_scm_model) { i8042_remove_filter(msi_laptop_i8042_filter); + cancel_delayed_work_sync(&msi_touchpad_dwork); + input_unregister_device(msi_laptop_input_dev); cancel_delayed_work_sync(&msi_rfkill_dwork); rfkill_cleanup(); } @@ -1125,6 +1127,7 @@ static void __exit msi_cleanup(void) { if (quirks->load_scm_model) { i8042_remove_filter(msi_laptop_i8042_filter); + cancel_delayed_work_sync(&msi_touchpad_dwork); input_unregister_device(msi_laptop_input_dev); cancel_delayed_work_sync(&msi_rfkill_dwork); rfkill_cleanup(); -- cgit v1.2.3 From 57209ddd5be6c128cc18dad73c19d1b7f7cae6c1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 Aug 2022 13:14:52 +0200 Subject: platform/x86: msi-laptop: Add msi_scm_model_exit() helper The probe-error-exit and remove paths both duplicate the exact same code to undo load_scm_model_init(). Add a helper for this. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220826111453.178962-1-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 5d4b10b8d771..74829f766b88 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -1014,9 +1014,19 @@ fail_input: rfkill_cleanup(); fail_rfkill: - return result; +} + +static void msi_scm_model_exit(void) +{ + if (!quirks->load_scm_model) + return; + i8042_remove_filter(msi_laptop_i8042_filter); + cancel_delayed_work_sync(&msi_touchpad_dwork); + input_unregister_device(msi_laptop_input_dev); + cancel_delayed_work_sync(&msi_rfkill_dwork); + rfkill_cleanup(); } static int __init msi_init(void) @@ -1104,13 +1114,7 @@ static int __init msi_init(void) fail_create_attr: sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); fail_create_group: - if (quirks->load_scm_model) { - i8042_remove_filter(msi_laptop_i8042_filter); - cancel_delayed_work_sync(&msi_touchpad_dwork); - input_unregister_device(msi_laptop_input_dev); - cancel_delayed_work_sync(&msi_rfkill_dwork); - rfkill_cleanup(); - } + msi_scm_model_exit(); fail_scm_model_init: platform_device_del(msipf_device); fail_device_add: @@ -1125,14 +1129,7 @@ fail_backlight: static void __exit msi_cleanup(void) { - if (quirks->load_scm_model) { - i8042_remove_filter(msi_laptop_i8042_filter); - cancel_delayed_work_sync(&msi_touchpad_dwork); - input_unregister_device(msi_laptop_input_dev); - cancel_delayed_work_sync(&msi_rfkill_dwork); - rfkill_cleanup(); - } - + msi_scm_model_exit(); sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); if (!quirks->old_ec_model && threeg_exists) device_remove_file(&msipf_device->dev, &dev_attr_threeg); -- cgit v1.2.3 From c35c7b9805971c6b09180a5570088940fd90ec56 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 Aug 2022 13:14:53 +0200 Subject: platform/x86: msi-laptop: Add msi_scm_disable_hw_fn_handling() helper Add a msi_scm_disable_hw_fn_handling() to remove the duplicate code for this in the resume and init paths. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220826111453.178962-2-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 74829f766b88..1c29678e5727 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -913,8 +913,7 @@ err_bluetooth: return retval; } -#ifdef CONFIG_PM_SLEEP -static int msi_laptop_resume(struct device *device) +static int msi_scm_disable_hw_fn_handling(void) { u8 data; int result; @@ -934,6 +933,12 @@ static int msi_laptop_resume(struct device *device) return 0; } + +#ifdef CONFIG_PM_SLEEP +static int msi_laptop_resume(struct device *device) +{ + return msi_scm_disable_hw_fn_handling(); +} #endif static int __init msi_laptop_input_setup(void) @@ -966,7 +971,6 @@ err_free_dev: static int __init load_scm_model_init(struct platform_device *sdev) { - u8 data; int result; if (!quirks->ec_read_only) { @@ -980,12 +984,7 @@ static int __init load_scm_model_init(struct platform_device *sdev) } /* disable hardware control by fn key */ - result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data); - if (result < 0) - return result; - - result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, - data | MSI_STANDARD_EC_SCM_LOAD_MASK); + result = msi_scm_disable_hw_fn_handling(); if (result < 0) return result; -- cgit v1.2.3 From af024a39ebda58694935f420bf396b11afb0df6b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 29 Aug 2022 18:35:44 +0200 Subject: platform/x86: acer-wmi: Acer Aspire One AOD270/Packard Bell Dot keymap fixes 2 keymap fixes for the Acer Aspire One AOD270 and the same hardware rebranded as Packard Bell Dot SC: 1. The F2 key is marked with a big '?' symbol on the Packard Bell Dot SC, this sends WMID_HOTKEY_EVENTs with a scancode of 0x27 add a mapping for this. 2. Scancode 0x61 is KEY_SWITCHVIDEOMODE. Usually this is a duplicate input event with the "Video Bus" input device events. But on these devices the "Video Bus" does not send events for this key. Map 0x61 to KEY_UNKNOWN instead of using KE_IGNORE so that udev/hwdb can override it on these devs. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220829163544.5288-1-hdegoede@redhat.com --- drivers/platform/x86/acer-wmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index e0230ea0cb7e..f1259d81d86d 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -99,6 +99,7 @@ static const struct key_entry acer_wmi_keymap[] __initconst = { {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */ {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ + {KE_KEY, 0x27, {KEY_HELP} }, {KE_KEY, 0x29, {KEY_PROG3} }, /* P_Key for TM8372 */ {KE_IGNORE, 0x41, {KEY_MUTE} }, {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} }, @@ -112,7 +113,13 @@ static const struct key_entry acer_wmi_keymap[] __initconst = { {KE_IGNORE, 0x48, {KEY_VOLUMEUP} }, {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} }, {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} }, - {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} }, + /* + * 0x61 is KEY_SWITCHVIDEOMODE. Usually this is a duplicate input event + * with the "Video Bus" input device events. But sometimes it is not + * a dup. Map it to KEY_UNKNOWN instead of using KE_IGNORE so that + * udev/hwdb can override it on systems where it is not a dup. + */ + {KE_KEY, 0x61, {KEY_UNKNOWN} }, {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} }, {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} }, {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ -- cgit v1.2.3 From 16b36a953bc7fc4843568abcdb7b32f92cc65457 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 23 Aug 2022 23:19:34 +0300 Subject: platform/mellanox: mlxreg-lc: Fix coverity warning Fix smatch warning: drivers/platform/mellanox/mlxreg-lc.c:866 mlxreg_lc_probe() warn: passing zero to 'PTR_ERR' by removing 'err = PTR_ERR(regmap)'. Fixes: b4b830a34d80 ("platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity") Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220823201937.46855-2-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-lc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index 55834ccb4ac7..9a1bfcd24317 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -863,7 +863,6 @@ static int mlxreg_lc_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n", data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); - err = PTR_ERR(regmap); goto regcache_sync_fail; } -- cgit v1.2.3 From 52e01c0b1d80b0a7e8d9970456e10b788398e633 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 23 Aug 2022 23:19:35 +0300 Subject: platform/mellanox: mlxreg-lc: Fix locking issue Fix locking issues: - mlxreg_lc_state_update() takes a lock when set or clear "MLXREG_LC_POWERED". - All the devices can be deleted before MLXREG_LC_POWERED flag is cleared. To fix it: - Add lock() / unlock() at the beginning / end of mlxreg_lc_event_handler() and remove locking from mlxreg_lc_power_on_off() and mlxreg_lc_enable_disable() - Add locked version of mlxreg_lc_state_update() - mlxreg_lc_state_update_locked() for using outside mlxreg_lc_event_handler(). (2) Remove redundant NULL check for of if 'data->notifier'. Fixes: 62f9529b8d5c87b ("platform/mellanox: mlxreg-lc: Add initial support for Nvidia line card devices") Reported-by: Dan Carpenter Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220823201937.46855-3-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-lc.c | 37 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index 9a1bfcd24317..e578c7bc060b 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -460,8 +460,6 @@ static int mlxreg_lc_power_on_off(struct mlxreg_lc *mlxreg_lc, u8 action) u32 regval; int err; - mutex_lock(&mlxreg_lc->lock); - err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, ®val); if (err) goto regmap_read_fail; @@ -474,7 +472,6 @@ static int mlxreg_lc_power_on_off(struct mlxreg_lc *mlxreg_lc, u8 action) err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval); regmap_read_fail: - mutex_unlock(&mlxreg_lc->lock); return err; } @@ -491,8 +488,6 @@ static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action) * line card which is already has been enabled. Disabling does not affect the disabled line * card. */ - mutex_lock(&mlxreg_lc->lock); - err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, ®val); if (err) goto regmap_read_fail; @@ -505,7 +500,6 @@ static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action) err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, regval); regmap_read_fail: - mutex_unlock(&mlxreg_lc->lock); return err; } @@ -537,6 +531,15 @@ mlxreg_lc_sn4800_c16_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, static void mlxreg_lc_state_update(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action) +{ + if (action) + mlxreg_lc->state |= state; + else + mlxreg_lc->state &= ~state; +} + +static void +mlxreg_lc_state_update_locked(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action) { mutex_lock(&mlxreg_lc->lock); @@ -560,8 +563,11 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, dev_info(mlxreg_lc->dev, "linecard#%d state %d event kind %d action %d\n", mlxreg_lc->data->slot, mlxreg_lc->state, kind, action); - if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED)) + mutex_lock(&mlxreg_lc->lock); + if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED)) { + mutex_unlock(&mlxreg_lc->lock); return 0; + } switch (kind) { case MLXREG_HOTPLUG_LC_SYNCED: @@ -574,7 +580,7 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, if (!(mlxreg_lc->state & MLXREG_LC_POWERED) && action) { err = mlxreg_lc_power_on_off(mlxreg_lc, 1); if (err) - return err; + goto mlxreg_lc_power_on_off_fail; } /* In case line card is configured - enable it. */ if (mlxreg_lc->state & MLXREG_LC_CONFIGURED && action) @@ -588,12 +594,13 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, /* In case line card is configured - enable it. */ if (mlxreg_lc->state & MLXREG_LC_CONFIGURED) err = mlxreg_lc_enable_disable(mlxreg_lc, 1); + mutex_unlock(&mlxreg_lc->lock); return err; } err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs, mlxreg_lc->main_devs_num); if (err) - return err; + goto mlxreg_lc_create_static_devices_fail; /* In case line card is already in ready state - enable it. */ if (mlxreg_lc->state & MLXREG_LC_CONFIGURED) @@ -620,6 +627,10 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, break; } +mlxreg_lc_power_on_off_fail: +mlxreg_lc_create_static_devices_fail: + mutex_unlock(&mlxreg_lc->lock); + return err; } @@ -665,7 +676,7 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent, if (err) goto mlxreg_lc_create_static_devices_failed; - mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED, 1); + mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_POWERED, 1); } /* Verify if line card is synchronized. */ @@ -676,7 +687,7 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent, /* Power on line card if necessary. */ if (regval & mlxreg_lc->data->mask) { mlxreg_lc->state |= MLXREG_LC_SYNCED; - mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED, 1); + mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_SYNCED, 1); if (mlxreg_lc->state & ~MLXREG_LC_POWERED) { err = mlxreg_lc_power_on_off(mlxreg_lc, 1); if (err) @@ -684,7 +695,7 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent, } } - mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_INITIALIZED, 1); + mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_INITIALIZED, 1); return 0; @@ -904,6 +915,8 @@ static int mlxreg_lc_remove(struct platform_device *pdev) struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev); struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev); + mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_INITIALIZED, 0); + /* * Probing and removing are invoked by hotplug events raised upon line card insertion and * removing. If probing procedure fails all data is cleared. However, hotplug event still -- cgit v1.2.3 From 1c8ee06b637f0b0146bbcda776d131e4822432c3 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 23 Aug 2022 23:19:36 +0300 Subject: platform/mellanox: Remove unnecessary code Remove redundant 'NULL' check for of if 'data->notifier'. Replace 'return err' by 'return 0' in mlxreg_lc_probe(). Fixes: 62f9529b8d5c87b ("platform/mellanox: mlxreg-lc: Add initial support for Nvidia line card devices") Reported-by: Dan Carpenter Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220823201937.46855-4-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-lc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index e578c7bc060b..1e0c3ddc46cd 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -825,10 +825,9 @@ static int mlxreg_lc_probe(struct platform_device *pdev) mutex_init(&mlxreg_lc->lock); /* Set event notification callback. */ - if (data->notifier) { - data->notifier->user_handler = mlxreg_lc_event_handler; - data->notifier->handle = mlxreg_lc; - } + data->notifier->user_handler = mlxreg_lc_event_handler; + data->notifier->handle = mlxreg_lc; + data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); if (!data->hpdev.adapter) { dev_err(&pdev->dev, "Failed to get adapter for bus %d\n", @@ -888,7 +887,7 @@ static int mlxreg_lc_probe(struct platform_device *pdev) if (err) goto mlxreg_lc_config_init_fail; - return err; + return 0; mlxreg_lc_config_init_fail: regcache_sync_fail: -- cgit v1.2.3 From 059209fd902f5ad4bec8124931c258e62fddf74f Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 23 Aug 2022 23:19:37 +0300 Subject: platform/mellanox: Remove redundant 'NULL' check Remove 'NULL' check for 'data->hpdev.client' in error flow of mlxreg_lc_probe(). It cannot be 'NULL' at this point. Fixes: b4b830a34d80 ("platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity") Reported-by: Dan Carpenter Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220823201937.46855-5-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-lc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index 1e0c3ddc46cd..1e071df4c9f5 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -893,10 +893,8 @@ mlxreg_lc_config_init_fail: regcache_sync_fail: regmap_write_fail: devm_regmap_init_i2c_fail: - if (data->hpdev.client) { - i2c_unregister_device(data->hpdev.client); - data->hpdev.client = NULL; - } + i2c_unregister_device(data->hpdev.client); + data->hpdev.client = NULL; i2c_new_device_fail: i2c_put_adapter(data->hpdev.adapter); data->hpdev.adapter = NULL; -- cgit v1.2.3 From f81fead027ecbb525c29d681eb95a222e76306a3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 24 Aug 2022 18:21:15 +0300 Subject: platform/x86: intel_cht_int33fe: Fix comment according to the code flow We don't use software_node_register_nodes() in the code, fix the comment. Fixes: 140355e5db8b ("platform/x86: intel_cht_int33fe: Convert software node array to group") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220824152115.88012-1-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/chtwc_int33fe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/intel/chtwc_int33fe.c b/drivers/platform/x86/intel/chtwc_int33fe.c index 1ea989df513c..2c9a7d52be07 100644 --- a/drivers/platform/x86/intel/chtwc_int33fe.c +++ b/drivers/platform/x86/intel/chtwc_int33fe.c @@ -219,7 +219,7 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) /* * Update node used in "usb-role-switch" property. Note that we - * rely on software_node_register_nodes() to use the original + * rely on software_node_register_node_group() to use the original * instance of properties instead of copying them. */ fusb302_mux_refs[0].node = mux_ref_node; -- cgit v1.2.3 From a97126265dfe10d3321c0fde4708a6cea49b19ed Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 25 Aug 2022 12:44:20 +0200 Subject: leds: simatic-ipc-leds-gpio: add new model 227G This adds support of the Siemens Simatic IPC227G. Its LEDs are connected to GPIO pins provided by the gpio-f7188x module. We make sure that gets loaded, if not enabled in the kernel config no LED support will be available. Reviewed-by: Andy Shevchenko Reviewed-by: Hans de Goede Signed-off-by: Henning Schild Link: https://lore.kernel.org/r/20220825104422.14156-6-henning.schild@siemens.com Signed-off-by: Hans de Goede --- drivers/leds/simple/simatic-ipc-leds-gpio.c | 42 +++++++++++++++++++--- drivers/platform/x86/simatic-ipc.c | 4 ++- include/linux/platform_data/x86/simatic-ipc-base.h | 1 + include/linux/platform_data/x86/simatic-ipc.h | 1 + 4 files changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio.c b/drivers/leds/simple/simatic-ipc-leds-gpio.c index 4c9e663a90ba..0d73dcbeec2d 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio.c @@ -13,28 +13,45 @@ #include #include #include +#include -static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { +struct gpiod_lookup_table *simatic_ipc_led_gpio_table; + +static struct gpiod_lookup_table simatic_ipc_led_gpio_table_127e = { .dev_id = "leds-gpio", .table = { - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 0, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 52, NULL, 1, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 53, NULL, 2, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 57, NULL, 3, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 58, NULL, 4, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 60, NULL, 5, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 0, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 56, NULL, 6, GPIO_ACTIVE_LOW), GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 59, NULL, 7, GPIO_ACTIVE_HIGH), }, }; +static struct gpiod_lookup_table simatic_ipc_led_gpio_table_227g = { + .dev_id = "leds-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-2", 1, NULL, 1, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-2", 2, NULL, 2, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-2", 3, NULL, 3, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-2", 4, NULL, 4, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-2", 5, NULL, 5, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-3", 6, NULL, 6, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio-f7188x-3", 7, NULL, 7, GPIO_ACTIVE_HIGH), + } +}; + static const struct gpio_led simatic_ipc_gpio_leds[] = { - { .name = "green:" LED_FUNCTION_STATUS "-3" }, { .name = "red:" LED_FUNCTION_STATUS "-1" }, { .name = "green:" LED_FUNCTION_STATUS "-1" }, { .name = "red:" LED_FUNCTION_STATUS "-2" }, { .name = "green:" LED_FUNCTION_STATUS "-2" }, { .name = "red:" LED_FUNCTION_STATUS "-3" }, + { .name = "green:" LED_FUNCTION_STATUS "-3" }, }; static const struct gpio_led_platform_data simatic_ipc_gpio_leds_pdata = { @@ -46,7 +63,7 @@ static struct platform_device *simatic_leds_pdev; static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev) { - gpiod_remove_lookup_table(&simatic_ipc_led_gpio_table); + gpiod_remove_lookup_table(simatic_ipc_led_gpio_table); platform_device_unregister(simatic_leds_pdev); return 0; @@ -54,10 +71,25 @@ static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev) static int simatic_ipc_leds_gpio_probe(struct platform_device *pdev) { + const struct simatic_ipc_platform *plat = pdev->dev.platform_data; struct gpio_desc *gpiod; int err; - gpiod_add_lookup_table(&simatic_ipc_led_gpio_table); + switch (plat->devmode) { + case SIMATIC_IPC_DEVICE_127E: + simatic_ipc_led_gpio_table = &simatic_ipc_led_gpio_table_127e; + break; + case SIMATIC_IPC_DEVICE_227G: + if (!IS_ENABLED(CONFIG_GPIO_F7188X)) + return -ENODEV; + request_module("gpio-f7188x"); + simatic_ipc_led_gpio_table = &simatic_ipc_led_gpio_table_227g; + break; + default: + return -ENODEV; + } + + gpiod_add_lookup_table(simatic_ipc_led_gpio_table); simatic_leds_pdev = platform_device_register_resndata(NULL, "leds-gpio", PLATFORM_DEVID_NONE, NULL, 0, &simatic_ipc_gpio_leds_pdata, diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c index ca3647b751d5..1825ef21a86d 100644 --- a/drivers/platform/x86/simatic-ipc.c +++ b/drivers/platform/x86/simatic-ipc.c @@ -41,6 +41,7 @@ static struct { {SIMATIC_IPC_IPC127E, SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC227D, SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC227E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E}, + {SIMATIC_IPC_IPC227G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E}, {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E}, @@ -65,7 +66,8 @@ static int register_platform_devices(u32 station_id) } if (ledmode != SIMATIC_IPC_DEVICE_NONE) { - if (ledmode == SIMATIC_IPC_DEVICE_127E) + if (ledmode == SIMATIC_IPC_DEVICE_127E || + ledmode == SIMATIC_IPC_DEVICE_227G) pdevname = KBUILD_MODNAME "_leds_gpio"; platform_data.devmode = ledmode; ipc_led_platform_device = diff --git a/include/linux/platform_data/x86/simatic-ipc-base.h b/include/linux/platform_data/x86/simatic-ipc-base.h index 39fefd48cf4d..57d6a10dfc9e 100644 --- a/include/linux/platform_data/x86/simatic-ipc-base.h +++ b/include/linux/platform_data/x86/simatic-ipc-base.h @@ -19,6 +19,7 @@ #define SIMATIC_IPC_DEVICE_427E 2 #define SIMATIC_IPC_DEVICE_127E 3 #define SIMATIC_IPC_DEVICE_227E 4 +#define SIMATIC_IPC_DEVICE_227G 5 struct simatic_ipc_platform { u8 devmode; diff --git a/include/linux/platform_data/x86/simatic-ipc.h b/include/linux/platform_data/x86/simatic-ipc.h index f3b76b39776b..7a2e79f3be0b 100644 --- a/include/linux/platform_data/x86/simatic-ipc.h +++ b/include/linux/platform_data/x86/simatic-ipc.h @@ -31,6 +31,7 @@ enum simatic_ipc_station_ids { SIMATIC_IPC_IPC427E = 0x00000A01, SIMATIC_IPC_IPC477E = 0x00000A02, SIMATIC_IPC_IPC127E = 0x00000D01, + SIMATIC_IPC_IPC227G = 0x00000F01, }; static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len) -- cgit v1.2.3 From d948b93ccff2c4d78c6dce4c7e6dc8b90976cdb0 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 25 Aug 2022 12:44:21 +0200 Subject: platform/x86: simatic-ipc: enable watchdog for 227G Just load the watchdog module, after having identified that machine. That watchdog module does not have any autoloading support. Reviewed-by: Andy Shevchenko Signed-off-by: Henning Schild Link: https://lore.kernel.org/r/20220825104422.14156-7-henning.schild@siemens.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/simatic-ipc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c index 1825ef21a86d..8dd686d1c9f1 100644 --- a/drivers/platform/x86/simatic-ipc.c +++ b/drivers/platform/x86/simatic-ipc.c @@ -96,6 +96,9 @@ static int register_platform_devices(u32 station_id) ipc_wdt_platform_device->name); } + if (station_id == SIMATIC_IPC_IPC227G) + request_module("w83627hf_wdt"); + if (ledmode == SIMATIC_IPC_DEVICE_NONE && wdtmode == SIMATIC_IPC_DEVICE_NONE) { pr_warn("unsupported IPC detected, station id=%08x\n", -- cgit v1.2.3 From 8f5c9858c5db129359b5de2f60f5f034bf5d56c0 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 25 Aug 2022 12:44:22 +0200 Subject: platform/x86: simatic-ipc: add new model 427G This adds support for the Siemens Simatic IPC427G. A board which basically works like the 227G added in a previous patch. So all there is to do is to add the station_id and make it take all the 227G branches. Reviewed-by: Andy Shevchenko Signed-off-by: Henning Schild Link: https://lore.kernel.org/r/20220825104422.14156-8-henning.schild@siemens.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/simatic-ipc.c | 11 +++++++---- include/linux/platform_data/x86/simatic-ipc.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c index 8dd686d1c9f1..ca76076fc706 100644 --- a/drivers/platform/x86/simatic-ipc.c +++ b/drivers/platform/x86/simatic-ipc.c @@ -41,11 +41,12 @@ static struct { {SIMATIC_IPC_IPC127E, SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC227D, SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC227E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E}, - {SIMATIC_IPC_IPC227G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE}, + {SIMATIC_IPC_IPC227G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, {SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E}, {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E}, {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E}, + {SIMATIC_IPC_IPC427G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, }; static int register_platform_devices(u32 station_id) @@ -82,6 +83,11 @@ static int register_platform_devices(u32 station_id) ipc_led_platform_device->name); } + if (wdtmode == SIMATIC_IPC_DEVICE_227G) { + request_module("w83627hf_wdt"); + return 0; + } + if (wdtmode != SIMATIC_IPC_DEVICE_NONE) { platform_data.devmode = wdtmode; ipc_wdt_platform_device = @@ -96,9 +102,6 @@ static int register_platform_devices(u32 station_id) ipc_wdt_platform_device->name); } - if (station_id == SIMATIC_IPC_IPC227G) - request_module("w83627hf_wdt"); - if (ledmode == SIMATIC_IPC_DEVICE_NONE && wdtmode == SIMATIC_IPC_DEVICE_NONE) { pr_warn("unsupported IPC detected, station id=%08x\n", diff --git a/include/linux/platform_data/x86/simatic-ipc.h b/include/linux/platform_data/x86/simatic-ipc.h index 7a2e79f3be0b..632320ec8f08 100644 --- a/include/linux/platform_data/x86/simatic-ipc.h +++ b/include/linux/platform_data/x86/simatic-ipc.h @@ -32,6 +32,7 @@ enum simatic_ipc_station_ids { SIMATIC_IPC_IPC477E = 0x00000A02, SIMATIC_IPC_IPC127E = 0x00000D01, SIMATIC_IPC_IPC227G = 0x00000F01, + SIMATIC_IPC_IPC427G = 0x00001001, }; static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len) -- cgit v1.2.3 From 6dd9eb95cb6d895be2827b40fd965d9ec2a0747b Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sat, 27 Aug 2022 15:30:40 +0200 Subject: platform/x86: dell-wmi: Add WMI event 0x0012 0x0003 to the list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks like that on Dell Latitude E6440 is WMI event 0x0012 0x0003 sent when display changes brightness. When it happens kernel prints "dell_wmi: Unknown WMI event type 0x12" message into dmesg. So ignore it for now to not spam dmesg. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20220827133040.15932-1-pali@kernel.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-base.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c index e07d3ba85a3f..0a259a27459f 100644 --- a/drivers/platform/x86/dell/dell-wmi-base.c +++ b/drivers/platform/x86/dell/dell-wmi-base.c @@ -344,6 +344,9 @@ static const struct key_entry dell_wmi_keymap_type_0011[] = { * They are events with extended data */ static const struct key_entry dell_wmi_keymap_type_0012[] = { + /* Backlight brightness change event */ + { KE_IGNORE, 0x0003, { KEY_RESERVED } }, + /* Ultra-performance mode switch request */ { KE_IGNORE, 0x000d, { KEY_RESERVED } }, -- cgit v1.2.3 From a2bdf10ce96efbccabdad7216db5587c1213996c Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 28 Aug 2022 19:46:38 +1200 Subject: platform/x86: asus-wmi: Increase FAN_CURVE_BUF_LEN to 32 Fix for TUF laptops returning with an -ENOSPC on calling asus_wmi_evaluate_method_buf() when fetching default curves. The TUF method requires at least 32 bytes space. This also moves and changes the pr_debug() in fan_curve_check_present() to pr_warn() in fan_curve_get_factory_default() so that there is at least some indication in logs of why it fails. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220828074638.5473-1-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 3d9fd58573f9..11203213e00d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -108,7 +108,7 @@ module_param(fnlock_default, bool, 0444); #define WMI_EVENT_MASK 0xFFFF #define FAN_CURVE_POINTS 8 -#define FAN_CURVE_BUF_LEN (FAN_CURVE_POINTS * 2) +#define FAN_CURVE_BUF_LEN 32 #define FAN_CURVE_DEV_CPU 0x00 #define FAN_CURVE_DEV_GPU 0x01 /* Mask to determine if setting temperature or percentage */ @@ -2383,8 +2383,10 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) curves = &asus->custom_fan_curves[fan_idx]; err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf, FAN_CURVE_BUF_LEN); - if (err) + if (err) { + pr_warn("%s (0x%08x) failed: %d\n", __func__, fan_dev, err); return err; + } fan_curve_copy_from_buf(curves, buf); curves->device_id = fan_dev; @@ -2402,9 +2404,6 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available, err = fan_curve_get_factory_default(asus, fan_dev); if (err) { - pr_debug("fan_curve_get_factory_default(0x%08x) failed: %d\n", - fan_dev, err); - /* Don't cause probe to fail on devices without fan-curves */ return 0; } -- cgit v1.2.3 From 3db2aeb121b9c54f52c399b8905c2bbbf201b7b5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 17 Aug 2022 14:03:32 +0200 Subject: platform/x86: nvidia-wmi-ec-backlight: Move fw interface definitions to a header (v2) Move the WMI interface definitions to a header, so that the definitions can be shared with drivers/acpi/video_detect.c . Changes in v2: - Add missing Nvidia copyright header - Move WMI_BRIGHTNESS_GUID to nvidia-wmi-ec-backlight.h as well Suggested-by: Daniel Dadap Reviewed-by: Daniel Dadap Signed-off-by: Hans de Goede --- MAINTAINERS | 1 + drivers/platform/x86/nvidia-wmi-ec-backlight.c | 68 +------------------ .../platform_data/x86/nvidia-wmi-ec-backlight.h | 76 ++++++++++++++++++++++ 3 files changed, 78 insertions(+), 67 deletions(-) create mode 100644 include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h (limited to 'drivers/platform') diff --git a/MAINTAINERS b/MAINTAINERS index 8a5012ba6ff9..8d59c6e9b4db 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14526,6 +14526,7 @@ M: Daniel Dadap L: platform-driver-x86@vger.kernel.org S: Supported F: drivers/platform/x86/nvidia-wmi-ec-backlight.c +F: include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h NVM EXPRESS DRIVER M: Keith Busch diff --git a/drivers/platform/x86/nvidia-wmi-ec-backlight.c b/drivers/platform/x86/nvidia-wmi-ec-backlight.c index 61e37194df70..be803e47eac0 100644 --- a/drivers/platform/x86/nvidia-wmi-ec-backlight.c +++ b/drivers/platform/x86/nvidia-wmi-ec-backlight.c @@ -7,74 +7,10 @@ #include #include #include +#include #include #include -/** - * enum wmi_brightness_method - WMI method IDs - * @WMI_BRIGHTNESS_METHOD_LEVEL: Get/Set EC brightness level status - * @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source - */ -enum wmi_brightness_method { - WMI_BRIGHTNESS_METHOD_LEVEL = 1, - WMI_BRIGHTNESS_METHOD_SOURCE = 2, - WMI_BRIGHTNESS_METHOD_MAX -}; - -/** - * enum wmi_brightness_mode - Operation mode for WMI-wrapped method - * @WMI_BRIGHTNESS_MODE_GET: Get the current brightness level/source. - * @WMI_BRIGHTNESS_MODE_SET: Set the brightness level. - * @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This - * is only valid when the WMI method is - * %WMI_BRIGHTNESS_METHOD_LEVEL. - */ -enum wmi_brightness_mode { - WMI_BRIGHTNESS_MODE_GET = 0, - WMI_BRIGHTNESS_MODE_SET = 1, - WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2, - WMI_BRIGHTNESS_MODE_MAX -}; - -/** - * enum wmi_brightness_source - Backlight brightness control source selection - * @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU. - * @WMI_BRIGHTNESS_SOURCE_EC: Backlight brightness is controlled by the - * system's Embedded Controller (EC). - * @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the - * DisplayPort AUX channel. - */ -enum wmi_brightness_source { - WMI_BRIGHTNESS_SOURCE_GPU = 1, - WMI_BRIGHTNESS_SOURCE_EC = 2, - WMI_BRIGHTNESS_SOURCE_AUX = 3, - WMI_BRIGHTNESS_SOURCE_MAX -}; - -/** - * struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method - * @mode: Pass in an &enum wmi_brightness_mode value to select between - * getting or setting a value. - * @val: In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET - * mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or - * %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode. - * @ret: Out parameter returning retrieved value when operating in - * %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL - * mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode. - * @ignored: Padding; not used. The ACPI method expects a 24 byte params struct. - * - * This is the parameters structure for the WmiBrightnessNotify ACPI method as - * wrapped by WMI. The value passed in to @val or returned by @ret will be a - * brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or - * an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE. - */ -struct wmi_brightness_args { - u32 mode; - u32 val; - u32 ret; - u32 ignored[3]; -}; - /** * wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method * @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID @@ -191,8 +127,6 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct return PTR_ERR_OR_ZERO(bdev); } -#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7" - static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table[] = { { .guid_string = WMI_BRIGHTNESS_GUID }, { } diff --git a/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h b/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h new file mode 100644 index 000000000000..23d60130272c --- /dev/null +++ b/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + */ + +#ifndef __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H +#define __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H + +#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7" + +/** + * enum wmi_brightness_method - WMI method IDs + * @WMI_BRIGHTNESS_METHOD_LEVEL: Get/Set EC brightness level status + * @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source + */ +enum wmi_brightness_method { + WMI_BRIGHTNESS_METHOD_LEVEL = 1, + WMI_BRIGHTNESS_METHOD_SOURCE = 2, + WMI_BRIGHTNESS_METHOD_MAX +}; + +/** + * enum wmi_brightness_mode - Operation mode for WMI-wrapped method + * @WMI_BRIGHTNESS_MODE_GET: Get the current brightness level/source. + * @WMI_BRIGHTNESS_MODE_SET: Set the brightness level. + * @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This + * is only valid when the WMI method is + * %WMI_BRIGHTNESS_METHOD_LEVEL. + */ +enum wmi_brightness_mode { + WMI_BRIGHTNESS_MODE_GET = 0, + WMI_BRIGHTNESS_MODE_SET = 1, + WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2, + WMI_BRIGHTNESS_MODE_MAX +}; + +/** + * enum wmi_brightness_source - Backlight brightness control source selection + * @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU. + * @WMI_BRIGHTNESS_SOURCE_EC: Backlight brightness is controlled by the + * system's Embedded Controller (EC). + * @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the + * DisplayPort AUX channel. + */ +enum wmi_brightness_source { + WMI_BRIGHTNESS_SOURCE_GPU = 1, + WMI_BRIGHTNESS_SOURCE_EC = 2, + WMI_BRIGHTNESS_SOURCE_AUX = 3, + WMI_BRIGHTNESS_SOURCE_MAX +}; + +/** + * struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method + * @mode: Pass in an &enum wmi_brightness_mode value to select between + * getting or setting a value. + * @val: In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET + * mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or + * %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode. + * @ret: Out parameter returning retrieved value when operating in + * %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL + * mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode. + * @ignored: Padding; not used. The ACPI method expects a 24 byte params struct. + * + * This is the parameters structure for the WmiBrightnessNotify ACPI method as + * wrapped by WMI. The value passed in to @val or returned by @ret will be a + * brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or + * an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE. + */ +struct wmi_brightness_args { + u32 mode; + u32 val; + u32 ret; + u32 ignored[3]; +}; + +#endif -- cgit v1.2.3 From 8d0ca287fd8cdc8110f5e441ec14874158f32a0f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 17 Aug 2022 14:37:21 +0200 Subject: platform/x86: nvidia-wmi-ec-backlight: Use acpi_video_get_backlight_type() Add an acpi_video_get_backlight_type() == acpi_backlight_nvidia_wmi_ec check. This will make nvidia-wmi-ec-backlight properly honor the user selecting a different backlight driver through the acpi_backlight=... kernel commandline option. Since the auto-detect code check for nvidia-wmi-ec-backlight in drivers/acpi/video_detect.c already checks that the WMI advertised brightness-source is the embedded controller, this new check makes it unnecessary for nvidia_wmi_ec_backlight_probe() to check this itself. Suggested-by: Daniel Dadap Reviewed-by: Daniel Dadap Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/nvidia-wmi-ec-backlight.c | 14 +++----------- 2 files changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f2f98e942cf2..0cc5ac35fc57 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -93,6 +93,7 @@ config PEAQ_WMI config NVIDIA_WMI_EC_BACKLIGHT tristate "EC Backlight Driver for Hybrid Graphics Notebook Systems" + depends on ACPI_VIDEO depends on ACPI_WMI depends on BACKLIGHT_CLASS_DEVICE help diff --git a/drivers/platform/x86/nvidia-wmi-ec-backlight.c b/drivers/platform/x86/nvidia-wmi-ec-backlight.c index be803e47eac0..baccdf658538 100644 --- a/drivers/platform/x86/nvidia-wmi-ec-backlight.c +++ b/drivers/platform/x86/nvidia-wmi-ec-backlight.c @@ -10,6 +10,7 @@ #include #include #include +#include /** * wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method @@ -87,19 +88,10 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct { struct backlight_properties props = {}; struct backlight_device *bdev; - u32 source; int ret; - ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_SOURCE, - WMI_BRIGHTNESS_MODE_GET, &source); - if (ret) - return ret; - - /* - * This driver is only to be used when brightness control is handled - * by the EC; otherwise, the GPU driver(s) should control brightness. - */ - if (source != WMI_BRIGHTNESS_SOURCE_EC) + /* drivers/acpi/video_detect.c also checks that SOURCE == EC */ + if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec) return -ENODEV; /* -- cgit v1.2.3 From 4f04c7dc83fd4339b00421174edc8556b6bac2b1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 4 Jun 2022 15:25:39 +0200 Subject: platform/x86: apple-gmux: Stop calling acpi/video.h functions Now that acpi_video_get_backlight_type() has apple-gmux detection (using apple_gmux_present()), it is no longer necessary for the apple-gmux code to manually remove possibly conflicting drivers. So remove the handling for this from the apple-gmux driver. Signed-off-by: Hans de Goede --- drivers/platform/x86/apple-gmux.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index ffe98a18440b..ca33df7ea550 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -21,7 +21,6 @@ #include #include #include -#include #include /** @@ -694,7 +693,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) * backlight control and supports more levels than other options. * Disable the other backlight choices. */ - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); apple_bl_unregister(); gmux_data->power_state = VGA_SWITCHEROO_ON; @@ -804,7 +802,6 @@ static void gmux_remove(struct pnp_dev *pnp) apple_gmux_data = NULL; kfree(gmux_data); - acpi_video_register(); apple_bl_register(); } -- cgit v1.2.3 From a2ed70d0ecb11b7eb3ff14ed897cd0995c86651d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 4 Jun 2022 16:18:05 +0200 Subject: platform/x86: toshiba_acpi: Stop using acpi_video_set_dmi_backlight_type() acpi_video_set_dmi_backlight_type() is troublesome because it may end up getting called after other backlight drivers have already called acpi_video_get_backlight_type() resulting in the other drivers already being registered even though they should not. In case of the acpi_video backlight, acpi_video_set_dmi_backlight_type() actually calls acpi_video_unregister_backlight() since that is often probed earlier, leading to userspace seeing the acpi_video0 class device being briefly available, leading to races in userspace where udev probe-rules try to access the device and it is already gone. In case of toshiba_acpi there are no DMI quirks to move to acpi/video_detect.c, but it also (ab)uses it for transflective displays. Adding transflective display support to video_detect.c would be quite involved. But luckily there are only 2 known models with a transflective display, so we can just add DMI quirks for those. Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede --- drivers/acpi/video_detect.c | 19 +++++++++++++++++++ drivers/platform/x86/toshiba_acpi.c | 16 ---------------- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index be2fc43418af..74e2087c8ff0 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -190,6 +190,25 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, }, + /* + * Toshiba models with Transflective display, these need to use + * the toshiba_acpi vendor driver for proper Transflective handling. + */ + { + .callback = video_detect_force_vendor, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R500"), + }, + }, + { + .callback = video_detect_force_vendor, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R600"), + }, + }, + /* * These models have a working acpi_video backlight control, and using * native backlight causes a regression where backlight does not work diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 0fc9e8b8827b..030dc37d50b8 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -271,14 +271,6 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = { { KE_END, 0 }, }; -/* - * List of models which have a broken acpi-video backlight interface and thus - * need to use the toshiba (vendor) interface instead. - */ -static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { - {} -}; - /* * Utility */ @@ -2881,14 +2873,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) return 0; } - /* - * Tell acpi-video-detect code to prefer vendor backlight on all - * systems with transflective backlight and on dmi matched systems. - */ - if (dev->tr_backlight_supported || - dmi_check_system(toshiba_vendor_backlight_dmi)) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (acpi_video_get_backlight_type() != acpi_backlight_vendor) return 0; -- cgit v1.2.3 From 0172df18dc4309a7052cbb37a6939f7a8b0735d5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 4 Jun 2022 18:28:52 +0200 Subject: platform/x86: acer-wmi: Move backlight DMI quirks to acpi/video_detect.c Move the backlight DMI quirks to acpi/video_detect.c, so that the driver no longer needs to call acpi_video_set_dmi_backlight_type(). acpi_video_set_dmi_backlight_type() is troublesome because it may end up getting called after other backlight drivers have already called acpi_video_get_backlight_type() resulting in the other drivers already being registered even though they should not. Note that even though the DMI quirk table name was video_vendor_dmi_table, 5/6 quirks were actually quirks to use the GPU native backlight. These 5 quirks also had a callback in their dmi_system_id entry which disabled the acer-wmi vendor driver; and any DMI match resulted in: acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); which disabled the acpi_video driver, so only the native driver was left. The new entries for these 5/6 devices correctly marks these as needing the native backlight driver. Also note that other changes in this series change the native backlight drivers to no longer unconditionally register their backlight. Instead these drivers now do this check: if (acpi_video_get_backlight_type(false) != acpi_backlight_native) return 0; /* bail */ which without this patch would have broken these 5/6 "special" quirks. Since I had to look at all the commits adding the quirks anyways, to make sure that I understood the code correctly, I've also added links to the various original bugzillas for these quirks to the new entries. Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede --- drivers/acpi/video_detect.c | 53 +++++++++++++++++++++++++++++++++ drivers/platform/x86/acer-wmi.c | 66 ----------------------------------------- 2 files changed, 53 insertions(+), 66 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 74e2087c8ff0..6a2523bc02ba 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -149,6 +149,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "X360"), }, }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1128309 */ + .callback = video_detect_force_vendor, + /* Acer KAV80 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"), + }, + }, { .callback = video_detect_force_vendor, /* Asus UL30VT */ @@ -437,6 +446,41 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "JV50"), }, }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1012674 */ + .callback = video_detect_force_native, + /* Acer Aspire 5741 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"), + }, + }, + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=42993 */ + .callback = video_detect_force_native, + /* Acer Aspire 5750 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), + }, + }, + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=42833 */ + .callback = video_detect_force_native, + /* Acer Extensa 5235 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), + }, + }, + { + .callback = video_detect_force_native, + /* Acer TravelMate 4750 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), + }, + }, { /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */ .callback = video_detect_force_native, @@ -447,6 +491,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"), }, }, + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=36322 */ + .callback = video_detect_force_native, + /* Acer TravelMate 5760 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), + }, + }, { .callback = video_detect_force_native, /* ASUSTeK COMPUTER INC. GA401 */ diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index e0230ea0cb7e..b933a5165edb 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -643,69 +643,6 @@ static const struct dmi_system_id non_acer_quirks[] __initconst = { {} }; -static int __init -video_set_backlight_video_vendor(const struct dmi_system_id *d) -{ - interface->capability &= ~ACER_CAP_BRIGHTNESS; - pr_info("Brightness must be controlled by generic video driver\n"); - return 0; -} - -static const struct dmi_system_id video_vendor_dmi_table[] __initconst = { - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer TravelMate 4750", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Extensa 5235", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer TravelMate 5760", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Aspire 5750", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Aspire 5741", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"), - }, - }, - { - /* - * Note no video_set_backlight_video_vendor, we must use the - * acer interface, as there is no native backlight interface. - */ - .ident = "Acer KAV80", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"), - }, - }, - {} -}; - /* Find which quirks are needed for a particular vendor/ model pair */ static void __init find_quirks(void) { @@ -2477,9 +2414,6 @@ static int __init acer_wmi_init(void) set_quirks(); - if (dmi_check_system(video_vendor_dmi_table)) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (acpi_video_get_backlight_type() != acpi_backlight_vendor) interface->capability &= ~ACER_CAP_BRIGHTNESS; -- cgit v1.2.3 From 2603c681e0f63581b2c7821728d5be2cdee8cb9f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 5 Jun 2022 17:26:54 +0200 Subject: platform/x86: asus-wmi: Drop DMI chassis-type check from backlight handling Remove this check from the asus-wmi backlight handling: /* Some Asus desktop boards export an acpi-video backlight interface, stop this from showing up */ chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); if (chassis_type && !strcmp(chassis_type, "3")) acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); This acpi_video_set_dmi_backlight_type(acpi_backlight_vendor) call must be removed because other changes in this series change the native backlight drivers to no longer unconditionally register their backlight. Instead these drivers now do this check: if (acpi_video_get_backlight_type(false) != acpi_backlight_native) return 0; /* bail */ So leaving this in place can break things on laptops with a broken DMI chassis-type, which would have GPU native brightness control before the addition of the acpi_video_get_backlight_type() != native check. Removing this should be ok now, since the ACPI video code has improved heuristics for this itself now (which includes a chassis-type check). Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 89b604e04d7f..301166a5697d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -3553,7 +3553,6 @@ static int asus_wmi_add(struct platform_device *pdev) struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); struct asus_wmi *asus; - const char *chassis_type; acpi_status status; int err; u32 result; @@ -3635,12 +3634,6 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_force_als_set) asus_wmi_set_als(); - /* Some Asus desktop boards export an acpi-video backlight interface, - stop this from showing up */ - chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); - if (chassis_type && !strcmp(chassis_type, "3")) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (asus->driver->quirks->wmi_backlight_power) acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); -- cgit v1.2.3 From 52796b304a517b002300bbb67074b38a6003fd7a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 18 Jun 2022 17:15:24 +0200 Subject: platform/x86: asus-wmi: Move acpi_backlight=vendor quirks to ACPI video_detect.c Remove the asus-wmi quirk_entry.wmi_backlight_power quirk-flag, which called acpi_video_set_dmi_backlight_type(acpi_backlight_vendor) and replace it with acpi/video_detect.c video_detect_dmi_table[] entries using the video_detect_force_vendor callback. acpi_video_set_dmi_backlight_type() is troublesome because it may end up getting called after other backlight drivers have already called acpi_video_get_backlight_type() resulting in the other drivers already being registered even though they should not. Note no entries are dropped from the dmi_system_id table in asus-nb-wmi.c. This is because the entries using the removed wmi_backlight_power flag also use other model specific quirks from the asus-wmi quirk_entry struct. So the quirk_asus_x55u struct and the entries pointing to it cannot be dropped. Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede --- drivers/acpi/video_detect.c | 40 ++++++++++++++++++++++++++++++++++++++ drivers/platform/x86/asus-nb-wmi.c | 7 ------- drivers/platform/x86/asus-wmi.c | 3 --- drivers/platform/x86/asus-wmi.h | 1 - drivers/platform/x86/eeepc-wmi.c | 25 +----------------------- 5 files changed, 41 insertions(+), 35 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 6a2523bc02ba..d893313fe1a0 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -174,6 +174,46 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), }, }, + { + .callback = video_detect_force_vendor, + /* Asus X55U */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus X101CH */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus X401U */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus X501U */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Asus 1015CX */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"), + }, + }, { .callback = video_detect_force_vendor, /* GIGABYTE GB-BXBT-2807 */ diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 478dd300b9c9..810a94557a85 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -79,12 +79,10 @@ static struct quirk_entry quirk_asus_q500a = { /* * For those machines that need software to control bt/wifi status - * and can't adjust brightness through ACPI interface * and have duplicate events(ACPI and WMI) for display toggle */ static struct quirk_entry quirk_asus_x55u = { .wapf = 4, - .wmi_backlight_power = true, .wmi_backlight_set_devstate = true, .no_display_toggle = true, }; @@ -147,11 +145,6 @@ static const struct dmi_system_id asus_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "U32U"), }, - /* - * Note this machine has a Brazos APU, and most Brazos Asus - * machines need quirk_asus_x55u / wmi_backlight_power but - * here acpi-video seems to work fine for backlight control. - */ .driver_data = &quirk_asus_wapf4, }, { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 301166a5697d..5cf9d9aff164 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -3634,9 +3634,6 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_force_als_set) asus_wmi_set_als(); - if (asus->driver->quirks->wmi_backlight_power) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (asus->driver->quirks->wmi_backlight_native) acpi_video_set_dmi_backlight_type(acpi_backlight_native); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index b302415bf1d9..30770e411301 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -29,7 +29,6 @@ struct quirk_entry { bool hotplug_wireless; bool scalar_panel_brightness; bool store_backlight_power; - bool wmi_backlight_power; bool wmi_backlight_native; bool wmi_backlight_set_devstate; bool wmi_force_als_set; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index ce86d84ee796..32d9f0ba6be3 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -96,11 +96,6 @@ static struct quirk_entry quirk_asus_et2012_type3 = { .store_backlight_power = true, }; -static struct quirk_entry quirk_asus_x101ch = { - /* We need this when ACPI function doesn't do this well */ - .wmi_backlight_power = true, -}; - static struct quirk_entry *quirks; static void et2012_quirks(void) @@ -151,25 +146,7 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_unknown, }, - { - .callback = dmi_matched, - .ident = "ASUSTeK Computer INC. X101CH", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"), - }, - .driver_data = &quirk_asus_x101ch, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK Computer INC. 1015CX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"), - }, - .driver_data = &quirk_asus_x101ch, - }, - {}, + {} }; static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, -- cgit v1.2.3 From 1e3344d6f2b329ca064b3016bc33d7f33ed7ba0e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 18 Jun 2022 17:44:58 +0200 Subject: platform/x86: asus-wmi: Move acpi_backlight=native quirks to ACPI video_detect.c Remove the asus-wmi quirk_entry.wmi_backlight_native quirk-flag, which called acpi_video_set_dmi_backlight_type(acpi_backlight_native) and replace it with acpi/video_detect.c video_detect_dmi_table[] entries using the video_detect_force_native callback. acpi_video_set_dmi_backlight_type() is troublesome because it may end up getting called after other backlight drivers have already called acpi_video_get_backlight_type() resulting in the other drivers already being registered even though they should not. Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede --- drivers/acpi/video_detect.c | 8 ++++++++ drivers/platform/x86/asus-nb-wmi.c | 14 -------------- drivers/platform/x86/asus-wmi.c | 3 --- drivers/platform/x86/asus-wmi.h | 1 - 4 files changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d893313fe1a0..a09089e7fada 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -564,6 +564,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "GA503"), }, }, + { + .callback = video_detect_force_native, + /* Asus UX303UB */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), + }, + }, /* * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a * working native and video interface. However the default detection diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 810a94557a85..bbfed85051ee 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -97,11 +97,6 @@ static struct quirk_entry quirk_asus_x200ca = { .wmi_backlight_set_devstate = true, }; -static struct quirk_entry quirk_asus_ux303ub = { - .wmi_backlight_native = true, - .wmi_backlight_set_devstate = true, -}; - static struct quirk_entry quirk_asus_x550lb = { .wmi_backlight_set_devstate = true, .xusb2pr = 0x01D9, @@ -372,15 +367,6 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_x200ca, }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. UX303UB", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), - }, - .driver_data = &quirk_asus_ux303ub, - }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. UX330UAK", diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 5cf9d9aff164..434249ac47a5 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -3634,9 +3634,6 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_force_als_set) asus_wmi_set_als(); - if (asus->driver->quirks->wmi_backlight_native) - acpi_video_set_dmi_backlight_type(acpi_backlight_native); - if (asus->driver->quirks->xusb2pr) asus_wmi_set_xusb2pr(asus); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 30770e411301..f30252efe1db 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -29,7 +29,6 @@ struct quirk_entry { bool hotplug_wireless; bool scalar_panel_brightness; bool store_backlight_power; - bool wmi_backlight_native; bool wmi_backlight_set_devstate; bool wmi_force_als_set; bool use_kbd_dock_devid; -- cgit v1.2.3 From 8991d7d9add0d9a711db692458d950050b38307b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 18 Jun 2022 19:01:05 +0200 Subject: platform/x86: samsung-laptop: Move acpi_backlight=[vendor|native] quirks to ACPI video_detect.c acpi_video_set_dmi_backlight_type() is troublesome because it may end up getting called after other backlight drivers have already called acpi_video_get_backlight_type() resulting in the other drivers already being registered even though they should not. Move all the acpi_backlight=[vendor|native] quirks from samsung-laptop to drivers/acpi/video_detect.c . Note the X360 -> acpi_backlight=native quirk is not moved because that already was present in drivers/acpi/video_detect.c . Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede --- drivers/acpi/video_detect.c | 54 ++++++++++++++++++++++ drivers/platform/x86/samsung-laptop.c | 87 ----------------------------------- 2 files changed, 54 insertions(+), 87 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index a09089e7fada..3861d4121172 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -222,6 +222,33 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"), }, }, + { + .callback = video_detect_force_vendor, + /* Samsung N150/N210/N220 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Samsung NF110/NF210/NF310 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), + DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Samsung NC210 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"), + DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"), + }, + }, { .callback = video_detect_force_vendor, /* Sony VPCEH3U1E */ @@ -572,6 +599,33 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), }, }, + { + .callback = video_detect_force_native, + /* Samsung N150P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N150P"), + DMI_MATCH(DMI_BOARD_NAME, "N150P"), + }, + }, + { + .callback = video_detect_force_native, + /* Samsung N145P/N250P/N260P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), + DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), + }, + }, + { + .callback = video_detect_force_native, + /* Samsung N250P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), + DMI_MATCH(DMI_BOARD_NAME, "N250P"), + }, + }, /* * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a * working native and video interface. However the default detection diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index c187dcdf82f0..cc30cf08f32d 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -356,23 +356,13 @@ struct samsung_laptop { }; struct samsung_quirks { - bool broken_acpi_video; bool four_kbd_backlight_levels; bool enable_kbd_backlight; - bool use_native_backlight; bool lid_handling; }; static struct samsung_quirks samsung_unknown = {}; -static struct samsung_quirks samsung_broken_acpi_video = { - .broken_acpi_video = true, -}; - -static struct samsung_quirks samsung_use_native_backlight = { - .use_native_backlight = true, -}; - static struct samsung_quirks samsung_np740u3e = { .four_kbd_backlight_levels = true, .enable_kbd_backlight = true, @@ -1540,76 +1530,6 @@ static const struct dmi_system_id samsung_dmi_table[] __initconst = { }, }, /* Specific DMI ids for laptop with quirks */ - { - .callback = samsung_dmi_matched, - .ident = "N150P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150P"), - DMI_MATCH(DMI_BOARD_NAME, "N150P"), - }, - .driver_data = &samsung_use_native_backlight, - }, - { - .callback = samsung_dmi_matched, - .ident = "N145P/N250P/N260P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), - DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), - }, - .driver_data = &samsung_use_native_backlight, - }, - { - .callback = samsung_dmi_matched, - .ident = "N150/N210/N220", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), - }, - .driver_data = &samsung_broken_acpi_video, - }, - { - .callback = samsung_dmi_matched, - .ident = "NF110/NF210/NF310", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), - DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), - }, - .driver_data = &samsung_broken_acpi_video, - }, - { - .callback = samsung_dmi_matched, - .ident = "X360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X360"), - DMI_MATCH(DMI_BOARD_NAME, "X360"), - }, - .driver_data = &samsung_broken_acpi_video, - }, - { - .callback = samsung_dmi_matched, - .ident = "N250P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), - DMI_MATCH(DMI_BOARD_NAME, "N250P"), - }, - .driver_data = &samsung_use_native_backlight, - }, - { - .callback = samsung_dmi_matched, - .ident = "NC210", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"), - DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"), - }, - .driver_data = &samsung_broken_acpi_video, - }, { .callback = samsung_dmi_matched, .ident = "730U3E/740U3E", @@ -1654,15 +1574,8 @@ static int __init samsung_init(void) samsung->handle_backlight = true; samsung->quirks = quirks; -#ifdef CONFIG_ACPI - if (samsung->quirks->broken_acpi_video) - acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); - if (samsung->quirks->use_native_backlight) - acpi_video_set_dmi_backlight_type(acpi_backlight_native); - if (acpi_video_get_backlight_type() != acpi_backlight_vendor) samsung->handle_backlight = false; -#endif ret = samsung_platform_init(samsung); if (ret) -- cgit v1.2.3 From 134038b075cb1dae21623499d765973d286ac94a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 29 Aug 2022 15:14:59 -0500 Subject: platform/x86: wmi: Allow duplicate GUIDs for drivers that use struct wmi_driver The WMI subsystem in the kernel currently tracks WMI devices by a GUID string not by ACPI device. The GUID used by the `wmi-bmof` module however is available from many devices on nearly every machine. This originally was thought to be a bug, but as it happens on most machines it is a design mistake. It has been fixed by tying an ACPI device to the driver with struct wmi_driver. So drivers that have moved over to struct wmi_driver can actually support multiple instantiations of a GUID without any problem. Add an allow list into wmi.c for GUIDs that the drivers that are known to use struct wmi_driver. The list is populated with `wmi-bmof` right now. The additional instances of that in sysfs with be suffixed with -%d Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220829201500.6341-1-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 49 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index aed293b5af81..aff23309b5d3 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -105,6 +105,12 @@ static const struct acpi_device_id wmi_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, wmi_device_ids); +/* allow duplicate GUIDs as these device drivers use struct wmi_driver */ +static const char * const allow_duplicates[] = { + "05901221-D566-11D1-B2F0-00A0C9062910", /* wmi-bmof */ + NULL +}; + static struct platform_driver acpi_wmi_driver = { .driver = { .name = "acpi-wmi", @@ -1073,6 +1079,23 @@ static const struct device_type wmi_type_data = { .release = wmi_dev_release, }; +/* + * _WDG is a static list that is only parsed at startup, + * so it's safe to count entries without extra protection. + */ +static int guid_count(const guid_t *guid) +{ + struct wmi_block *wblock; + int count = 0; + + list_for_each_entry(wblock, &wmi_block_list, list) { + if (guid_equal(&wblock->gblock.guid, guid)) + count++; + } + + return count; +} + static int wmi_create_device(struct device *wmi_bus_dev, struct wmi_block *wblock, struct acpi_device *device) @@ -1080,6 +1103,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, struct acpi_device_info *info; char method[WMI_ACPI_METHOD_NAME_SIZE]; int result; + uint count; if (wblock->gblock.flags & ACPI_WMI_EVENT) { wblock->dev.dev.type = &wmi_type_event; @@ -1134,7 +1158,11 @@ static int wmi_create_device(struct device *wmi_bus_dev, wblock->dev.dev.bus = &wmi_bus_type; wblock->dev.dev.parent = wmi_bus_dev; - dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid); + count = guid_count(&wblock->gblock.guid); + if (count) + dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, count); + else + dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid); device_initialize(&wblock->dev.dev); @@ -1154,11 +1182,20 @@ static void wmi_free_devices(struct acpi_device *device) } } -static bool guid_already_parsed(struct acpi_device *device, const guid_t *guid) +static bool guid_already_parsed_for_legacy(struct acpi_device *device, const guid_t *guid) { struct wmi_block *wblock; list_for_each_entry(wblock, &wmi_block_list, list) { + /* skip warning and register if we know the driver will use struct wmi_driver */ + for (int i = 0; allow_duplicates[i] != NULL; i++) { + guid_t tmp; + + if (guid_parse(allow_duplicates[i], &tmp)) + continue; + if (guid_equal(&tmp, guid)) + return false; + } if (guid_equal(&wblock->gblock.guid, guid)) { /* * Because we historically didn't track the relationship @@ -1208,13 +1245,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) if (debug_dump_wdg) wmi_dump_wdg(&gblock[i]); - /* - * Some WMI devices, like those for nVidia hooks, have a - * duplicate GUID. It's not clear what we should do in this - * case yet, so for now, we'll just ignore the duplicate - * for device creation. - */ - if (guid_already_parsed(device, &gblock[i].guid)) + if (guid_already_parsed_for_legacy(device, &gblock[i].guid)) continue; wblock = kzalloc(sizeof(*wblock), GFP_KERNEL); -- cgit v1.2.3 From f98d67ac427d416d46da5b82be92a2bed0c60be2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Sep 2022 14:34:06 +0300 Subject: platform/x86: p2sb: Fix UAF when caller uses resource name We have to copy only selected fields from the original resource. Because a PCI device will be removed immediately after getting its resources, we may not use any allocated data, hence we may not copy any pointers. Consider the following scenario: 1/ a caller of p2sb_bar() gets the resource; 2/ the resource has been copied by platform_device_add_data() in order to create a platform device; 3/ the platform device creation will call for the device driver's ->probe() as soon as a match found; 4/ the ->probe() takes given resources (see 2/) and tries to access one of its field, i.e. 'name', in the __devm_ioremap_resource() to create a pretty looking output; 5/ but the 'name' is a dangling pointer because p2sb_bar() removed a PCI device, which 'name' had been copied to the caller's memory. 6/ UAF (Use-After-Free) as a result. Kudos to Mika for the initial analisys of the issue. Fixes: 9745fb07474f ("platform/x86/intel: Add Primary to Sideband (P2SB) bridge support") Reported-by: kernel test robot Suggested-by: Mika Westerberg Link: https://lore.kernel.org/linux-i2c/YvPCbnKqDiL2XEKp@xsang-OptiPlex-9020/ Link: https://lore.kernel.org/linux-i2c/YtjAswDKfiuDfWYs@xsang-OptiPlex-9020/ Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220901113406.65876-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/p2sb.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/p2sb.c b/drivers/platform/x86/p2sb.c index fb2e141f3eb8..384d0962ae93 100644 --- a/drivers/platform/x86/p2sb.c +++ b/drivers/platform/x86/p2sb.c @@ -42,10 +42,24 @@ static int p2sb_get_devfn(unsigned int *devfn) return 0; } +/* Copy resource from the first BAR of the device in question */ static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) { - /* Copy resource from the first BAR of the device in question */ - *mem = pdev->resource[0]; + struct resource *bar0 = &pdev->resource[0]; + + /* Make sure we have no dangling pointers in the output */ + memset(mem, 0, sizeof(*mem)); + + /* + * We copy only selected fields from the original resource. + * Because a PCI device will be removed soon, we may not use + * any allocated data, hence we may not copy any pointers. + */ + mem->start = bar0->start; + mem->end = bar0->end; + mem->flags = bar0->flags; + mem->desc = bar0->desc; + return 0; } -- cgit v1.2.3 From e24faabf5f368c031ad50f0d915a01e1b591f536 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 29 Aug 2022 11:29:50 -0500 Subject: platform/x86/amd: pmc: Add defines for STB events Currently `amd-pmc` has two events, but just adds one to the first to distinguish the second. Add a clear definition what these events mean. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220829162953.5947-3-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 700eb19e8450..39e6ab88861d 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -39,7 +39,8 @@ #define AMD_PMC_STB_INDEX_ADDRESS 0xF8 #define AMD_PMC_STB_INDEX_DATA 0xFC #define AMD_PMC_STB_PMI_0 0x03E30600 -#define AMD_PMC_STB_PREDEF 0xC6000001 +#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 +#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 /* STB S2D(Spill to DRAM) has different message port offset */ #define STB_SPILL_TO_DRAM 0xBE @@ -701,7 +702,7 @@ static void amd_pmc_s2idle_prepare(void) } if (enable_stb) { - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF); + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_PREPARE); if (rc) dev_err(pdev->dev, "error writing to STB: %d\n", rc); } @@ -724,9 +725,8 @@ static void amd_pmc_s2idle_restore(void) /* Dump the IdleMask to see the blockers */ amd_pmc_idlemask_read(pdev, pdev->dev, NULL); - /* Write data incremented by 1 to distinguish in stb_read */ if (enable_stb) { - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF + 1); + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_RESTORE); if (rc) dev_err(pdev->dev, "error writing to STB: %d\n", rc); } -- cgit v1.2.3 From 90bec2855c566b6d07cc3e2bb47befb6266cf1ec Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 29 Aug 2022 11:29:51 -0500 Subject: platform/x86/amd: pmc: Always write to the STB The kernel parameter `enable_stb` currently gates the access to the STB from debugfs and also controls whether the kernel writes events to the STB. Even if not accessing STB data from the kernel it's useful to have this data stored to review the STB. So in suspend/resume always write it. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220829162953.5947-4-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 39e6ab88861d..fba42036682d 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -701,11 +701,9 @@ static void amd_pmc_s2idle_prepare(void) return; } - if (enable_stb) { - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_PREPARE); - if (rc) - dev_err(pdev->dev, "error writing to STB: %d\n", rc); - } + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_PREPARE); + if (rc) + dev_err(pdev->dev, "error writing to STB: %d\n", rc); } static void amd_pmc_s2idle_restore(void) @@ -725,11 +723,9 @@ static void amd_pmc_s2idle_restore(void) /* Dump the IdleMask to see the blockers */ amd_pmc_idlemask_read(pdev, pdev->dev, NULL); - if (enable_stb) { - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_RESTORE); - if (rc) - dev_err(pdev->dev, "error writing to STB: %d\n", rc); - } + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_RESTORE); + if (rc) + dev_err(pdev->dev, "error writing to STB: %d\n", rc); /* Notify on failed entry */ amd_pmc_validate_deepest(pdev); -- cgit v1.2.3 From db55fb8a06f241e168a4f275970f2701d52040c6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 29 Aug 2022 11:29:52 -0500 Subject: platform/x86/amd: pmc: Add an extra STB message for checking s2idle entry The `check` callback is run right before the cores are put into HLT. This will allow checking synchronization problems with other software that writes into the STB. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220829162953.5947-5-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index fba42036682d..32887687f888 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -41,6 +41,7 @@ #define AMD_PMC_STB_PMI_0 0x03E30600 #define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 #define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 +#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 /* STB S2D(Spill to DRAM) has different message port offset */ #define STB_SPILL_TO_DRAM 0xBE @@ -706,6 +707,16 @@ static void amd_pmc_s2idle_prepare(void) dev_err(pdev->dev, "error writing to STB: %d\n", rc); } +static void amd_pmc_s2idle_check(void) +{ + struct amd_pmc_dev *pdev = &pmc; + int rc; + + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_CHECK); + if (rc) + dev_err(pdev->dev, "error writing to STB: %d\n", rc); +} + static void amd_pmc_s2idle_restore(void) { struct amd_pmc_dev *pdev = &pmc; @@ -733,6 +744,7 @@ static void amd_pmc_s2idle_restore(void) static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = { .prepare = amd_pmc_s2idle_prepare, + .check = amd_pmc_s2idle_check, .restore = amd_pmc_s2idle_restore, }; #endif -- cgit v1.2.3 From dd193dcdc9c02ee28ca0490d737d7a0636332569 Mon Sep 17 00:00:00 2001 From: Arvid Norlander Date: Fri, 2 Sep 2022 19:40:17 +0200 Subject: platform/x86: toshiba_acpi: Add fan RPM reading (internals) This add the internal feature detection and reading function for fan RPM. The approach is based on tracing ACPI calls using AMLI (a tracer/debugger built into ACPI.sys) while using the Windows cooling self-test software. The call used is {HCI_GET, 0x45, 0, 1, 0, 0} which returns: {0x0, 0x45, fan_rpm, probably_max_rpm, 0x0, 0x0} What is probably the max RPM is not currently used. Signed-off-by: Arvid Norlander Link: https://lore.kernel.org/r/20220902174018.1720029-2-lkml@vorpal.se Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/toshiba_acpi.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 900ee68a4c0b..478b94c96dd4 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -106,6 +106,7 @@ MODULE_LICENSE("GPL"); #define HCI_VIDEO_OUT 0x001c #define HCI_HOTKEY_EVENT 0x001e #define HCI_LCD_BRIGHTNESS 0x002a +#define HCI_FAN_RPM 0x0045 #define HCI_WIRELESS 0x0056 #define HCI_ACCELEROMETER 0x006d #define HCI_COOLING_METHOD 0x007f @@ -185,6 +186,7 @@ struct toshiba_acpi_dev { unsigned int illumination_supported:1; unsigned int video_supported:1; unsigned int fan_supported:1; + unsigned int fan_rpm_supported:1; unsigned int system_event_supported:1; unsigned int ntfy_supported:1; unsigned int info_supported:1; @@ -1611,6 +1613,29 @@ static const struct proc_ops fan_proc_ops = { .proc_write = fan_proc_write, }; +/* Fan RPM */ +static int get_fan_rpm(struct toshiba_acpi_dev *dev, u32 *rpm) +{ + u32 in[TCI_WORDS] = { HCI_GET, HCI_FAN_RPM, 0, 1, 0, 0 }; + u32 out[TCI_WORDS]; + acpi_status status = tci_raw(dev, in, out); + + if (ACPI_FAILURE(status)) { + pr_err("ACPI call to get Fan speed failed\n"); + return -EIO; + } + + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] == TOS_SUCCESS) { + *rpm = out[2]; + return 0; + } + + return -EIO; +} + static int keys_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; @@ -2915,6 +2940,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev) pr_cont(" video-out"); if (dev->fan_supported) pr_cont(" fan"); + if (dev->fan_rpm_supported) + pr_cont(" fan-rpm"); if (dev->tr_backlight_supported) pr_cont(" transflective-backlight"); if (dev->illumination_supported) @@ -3144,6 +3171,9 @@ iio_error: ret = get_fan_status(dev, &dummy); dev->fan_supported = !ret; + ret = get_fan_rpm(dev, &dummy); + dev->fan_rpm_supported = !ret; + toshiba_wwan_available(dev); if (dev->wwan_supported) toshiba_acpi_setup_wwan_rfkill(dev); -- cgit v1.2.3 From c727ba4cd95a12d8e43b02963d3ba4daddbd100c Mon Sep 17 00:00:00 2001 From: Arvid Norlander Date: Fri, 2 Sep 2022 19:40:18 +0200 Subject: platform/x86: toshiba_acpi: Add fan RPM reading (hwmon interface) This expands on the previous commit, exporting the fan RPM via hwmon. This will look something like the following when using the "sensors" command from lm_sensors: toshiba_acpi_sensors-acpi-0 Adapter: ACPI interface fan1: 0 RPM Signed-off-by: Arvid Norlander Acked-by: Guenter Roeck Link: https://lore.kernel.org/r/20220902174018.1720029-3-lkml@vorpal.se Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/toshiba_acpi.c | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0cc5ac35fc57..daefe57c7b86 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -798,6 +798,7 @@ config ACPI_TOSHIBA depends on INPUT depends on SERIO_I8042 || SERIO_I8042 = n depends on ACPI_VIDEO || ACPI_VIDEO = n + depends on HWMON || HWMON = n depends on RFKILL || RFKILL = n depends on IIO select INPUT_SPARSEKMAP diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 478b94c96dd4..7fd9d97c9b3b 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -171,6 +172,9 @@ struct toshiba_acpi_dev { struct miscdevice miscdev; struct rfkill *wwan_rfk; struct iio_dev *indio_dev; +#if IS_ENABLED(CONFIG_HWMON) + struct device *hwmon_device; +#endif int force_fan; int last_key_event; @@ -2928,6 +2932,54 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) return 0; } +/* HWMON support for fan */ +#if IS_ENABLED(CONFIG_HWMON) +static umode_t toshiba_acpi_hwmon_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return 0444; +} + +static int toshiba_acpi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + /* + * There is only a single channel and single attribute (for the + * fan) at this point. + * This can be replaced with more advanced logic in the future, + * should the need arise. + */ + if (type == hwmon_fan && channel == 0 && attr == hwmon_fan_input) { + u32 value; + int ret; + + ret = get_fan_rpm(toshiba_acpi, &value); + if (ret) + return ret; + + *val = value; + return 0; + } + return -EOPNOTSUPP; +} + +static const struct hwmon_channel_info *toshiba_acpi_hwmon_info[] = { + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), + NULL +}; + +static const struct hwmon_ops toshiba_acpi_hwmon_ops = { + .is_visible = toshiba_acpi_hwmon_is_visible, + .read = toshiba_acpi_hwmon_read, +}; + +static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = { + .ops = &toshiba_acpi_hwmon_ops, + .info = toshiba_acpi_hwmon_info, +}; +#endif + static void print_supported_features(struct toshiba_acpi_dev *dev) { pr_info("Supported laptop features:"); @@ -2982,6 +3034,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) remove_toshiba_proc_entries(dev); +#if IS_ENABLED(CONFIG_HWMON) + if (dev->hwmon_device) + hwmon_device_unregister(dev->hwmon_device); +#endif + if (dev->accelerometer_supported && dev->indio_dev) { iio_device_unregister(dev->indio_dev); iio_device_free(dev->indio_dev); @@ -3174,6 +3231,18 @@ iio_error: ret = get_fan_rpm(dev, &dummy); dev->fan_rpm_supported = !ret; +#if IS_ENABLED(CONFIG_HWMON) + if (dev->fan_rpm_supported) { + dev->hwmon_device = hwmon_device_register_with_info( + &dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL, + &toshiba_acpi_hwmon_chip_info, NULL); + if (IS_ERR(dev->hwmon_device)) { + dev->hwmon_device = NULL; + pr_warn("unable to register hwmon device, skipping\n"); + } + } +#endif + toshiba_wwan_available(dev); if (dev->wwan_supported) toshiba_acpi_setup_wwan_rfkill(dev); -- cgit v1.2.3 From 89655fbb396aff20bd5247fa6b13a689e2f10f9c Mon Sep 17 00:00:00 2001 From: Arvid Norlander Date: Fri, 2 Sep 2022 20:00:35 +0200 Subject: platform/x86: Battery charge mode in toshiba_acpi (internals) This commit adds the internal functions to control the Toshiba laptop. Unlike for example ThinkPads where this control is granular here it is just off/on. When off it charges to 100%. When on it charges to about 80%. Controlling this setting is done via HCI register 0x00ba. Setting to value 1 will result in limiting the charing to 80% of the battery capacity, while setting it to 0 will allow charging to 100%. Reading the current state is a bit weird, and needs a 1 set in the last position of the query for whatever reason. In addition, the read may return 0x8d20 (Data not available) rarely, so a retry mechanism is needed. According to the Windows program used to control the feature the setting will not take effect until the battery has been discharged to around 50%. However, in my testing it takes effect as soon as the charge drops below 80%. On Windows Toshiba branded this feature as "Eco charging". Signed-off-by: Arvid Norlander Link: https://lore.kernel.org/r/20220902180037.1728546-2-lkml@vorpal.se Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/toshiba_acpi.c | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 7fd9d97c9b3b..b55e6e17f723 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -114,6 +114,7 @@ MODULE_LICENSE("GPL"); #define HCI_KBD_ILLUMINATION 0x0095 #define HCI_ECO_MODE 0x0097 #define HCI_ACCELEROMETER2 0x00a6 +#define HCI_BATTERY_CHARGE_MODE 0x00ba #define HCI_SYSTEM_INFO 0xc000 #define SCI_PANEL_POWER_ON 0x010d #define SCI_ILLUMINATION 0x014e @@ -207,6 +208,7 @@ struct toshiba_acpi_dev { unsigned int usb_three_supported:1; unsigned int wwan_supported:1; unsigned int cooling_method_supported:1; + unsigned int battery_charge_mode_supported:1; unsigned int sysfs_created:1; unsigned int special_functions; @@ -1283,6 +1285,69 @@ static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } +/* Battery charge control */ +static void toshiba_battery_charge_mode_available(struct toshiba_acpi_dev *dev) +{ + u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0 }; + u32 out[TCI_WORDS]; + acpi_status status; + + dev->battery_charge_mode_supported = 0; + + status = tci_raw(dev, in, out); + if (ACPI_FAILURE(status)) { + pr_err("ACPI call to get Battery Charge Mode failed\n"); + return; + } + + if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) + return; + + dev->battery_charge_mode_supported = 1; +} + +static int toshiba_battery_charge_mode_get(struct toshiba_acpi_dev *dev, u32 *state) +{ + u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0x1 }; + u32 out[TCI_WORDS]; + int retries = 3; + + do { + acpi_status status = tci_raw(dev, in, out); + + if (ACPI_FAILURE(status)) + pr_err("ACPI call to get Battery Charge Mode failed\n"); + switch (out[0]) { + case TOS_SUCCESS: + case TOS_SUCCESS2: + *state = out[2]; + return 0; + case TOS_NOT_SUPPORTED: + return -ENODEV; + case TOS_DATA_NOT_AVAILABLE: + retries--; + break; + default: + return -EIO; + } + } while (retries); + + return -EIO; +} + +static int toshiba_battery_charge_mode_set(struct toshiba_acpi_dev *dev, u32 state) +{ + u32 result = hci_write(dev, HCI_BATTERY_CHARGE_MODE, state); + + if (result == TOS_FAILURE) + pr_err("ACPI call to set Battery Charge Mode failed\n"); + + if (result == TOS_NOT_SUPPORTED) + return -ENODEV; + + return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; +} + /* Transflective Backlight */ static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) { @@ -3022,6 +3087,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev) pr_cont(" wwan"); if (dev->cooling_method_supported) pr_cont(" cooling-method"); + if (dev->battery_charge_mode_supported) + pr_cont(" battery-charge-mode"); pr_cont("\n"); } @@ -3249,6 +3316,8 @@ iio_error: toshiba_cooling_method_available(dev); + toshiba_battery_charge_mode_available(dev); + print_supported_features(dev); ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, -- cgit v1.2.3 From 8ef5db9eb084f6212345a7b09355c78ce05f71e2 Mon Sep 17 00:00:00 2001 From: Arvid Norlander Date: Fri, 2 Sep 2022 20:00:36 +0200 Subject: platform/x86: Battery charge mode in toshiba_acpi (sysfs) This commit adds the ACPI battery hook which in turns adds the sysfs entries. Because the Toshiba laptops only support two modes (eco or normal), which in testing correspond to 80% and 100% we simply round to the nearest possible level when set. It is possible that Toshiba laptops other than the Z830 has different set points for the charging. If so, a quirk table could be introduced in the future for this. For now, assume that all laptops that support this feature work the same way. Tested on a Toshiba Satellite Z830. Signed-off-by: Arvid Norlander Link: https://lore.kernel.org/r/20220902180037.1728546-3-lkml@vorpal.se Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/toshiba_acpi.c | 96 +++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index daefe57c7b86..f5312f51de19 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -791,6 +791,7 @@ config SAMSUNG_Q10 config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI + depends on ACPI_BATTERY depends on ACPI_WMI select LEDS_CLASS select NEW_LEDS diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index b55e6e17f723..1b3357a4207a 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -45,6 +45,7 @@ #include #include #include +#include #include MODULE_AUTHOR("John Belmonte"); @@ -3045,6 +3046,91 @@ static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = { }; #endif +/* ACPI battery hooking */ +static ssize_t charge_control_end_threshold_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + u32 state; + int status; + + if (toshiba_acpi == NULL) { + pr_err("Toshiba ACPI object invalid\n"); + return -ENODEV; + } + + status = toshiba_battery_charge_mode_get(toshiba_acpi, &state); + + if (status != 0) + return status; + + if (state == 1) + return sprintf(buf, "80\n"); + else + return sprintf(buf, "100\n"); +} + +static ssize_t charge_control_end_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + u32 value; + int rval; + + if (toshiba_acpi == NULL) { + pr_err("Toshiba ACPI object invalid\n"); + return -ENODEV; + } + + rval = kstrtou32(buf, 10, &value); + if (rval) + return rval; + + if (value < 1 || value > 100) + return -EINVAL; + rval = toshiba_battery_charge_mode_set(toshiba_acpi, + (value < 90) ? 1 : 0); + if (rval < 0) + return rval; + else + return count; +} + +static DEVICE_ATTR_RW(charge_control_end_threshold); + +static struct attribute *toshiba_acpi_battery_attrs[] = { + &dev_attr_charge_control_end_threshold.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(toshiba_acpi_battery); + +static int toshiba_acpi_battery_add(struct power_supply *battery) +{ + if (toshiba_acpi == NULL) { + pr_err("Init order issue\n"); + return -ENODEV; + } + if (!toshiba_acpi->battery_charge_mode_supported) + return -ENODEV; + if (device_add_groups(&battery->dev, toshiba_acpi_battery_groups)) + return -ENODEV; + return 0; +} + +static int toshiba_acpi_battery_remove(struct power_supply *battery) +{ + device_remove_groups(&battery->dev, toshiba_acpi_battery_groups); + return 0; +} + +static struct acpi_battery_hook battery_hook = { + .add_battery = toshiba_acpi_battery_add, + .remove_battery = toshiba_acpi_battery_remove, + .name = "Toshiba Battery Extension", +}; + static void print_supported_features(struct toshiba_acpi_dev *dev) { pr_info("Supported laptop features:"); @@ -3134,6 +3220,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) rfkill_destroy(dev->wwan_rfk); } + if (dev->battery_charge_mode_supported) + battery_hook_unregister(&battery_hook); + if (toshiba_acpi) toshiba_acpi = NULL; @@ -3332,6 +3421,13 @@ iio_error: toshiba_acpi = dev; + /* + * As the battery hook relies on the static variable toshiba_acpi being + * set, this must be done after toshiba_acpi is assigned. + */ + if (dev->battery_charge_mode_supported) + battery_hook_register(&battery_hook); + return 0; error: -- cgit v1.2.3 From 3cb1f40dfdc3b9f5449076c96b4e2523139f5cd0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 29 Aug 2022 15:17:03 +0200 Subject: drivers/platform: toshiba_acpi: Call HCI_PANEL_POWER_ON on resume on some models Some Toshibas have a broken acpi-video interface for brightness control, so far these have been using a special workaround in drivers/acpi/acpi_video.c which gets activated by the disable_backlight_sysfs_if module-param/quirks. The recent x86/acpi backlight refactoring has broken this workaround: 1. This workaround relies on acpi_video_get_backlight_type() returning acpi_video so that the acpi_video code actually runs; and 2. this relies on the actual native GPU driver to offer the sysfs backlight interface to userspace. After the refactor this breaks since the native driver will no longer register its backlight-device if acpi_video_get_backlight_type() does not return native and making it return native breaks 1. Keeping the acpi_video backlight handling on resume active, while not using it to set the brightness, is necessary because it does a _BCM call on resume which is necessary to turn the panel back on on resume. Looking at the DSDT shows that this _BCM call results in a Toshiba HCI_SET HCI_LCD_BRIGHTNESS call, which turns the panel back on. This commit makes toshiba_acpi do a HCI_SET HCI_PANEL_POWER_ON call on resume on the affected models, so that the (now broken) acpi_video disable_backlight_sysfs_if workaround will no longer be necessary. Note this uses HCI_PANEL_POWER_ON instead of HCI_LCD_BRIGHTNESS to avoid changing the configured brightness level. Tested-by: Arvid Norlander Signed-off-by: Hans de Goede --- drivers/platform/x86/toshiba_acpi.c | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 1b3357a4207a..43cc25351aea 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -23,6 +23,7 @@ #define PROC_INTERFACE_VERSION 1 #include +#include #include #include #include @@ -52,6 +53,11 @@ MODULE_AUTHOR("John Belmonte"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_LICENSE("GPL"); +int turn_on_panel_on_resume = -1; +module_param(turn_on_panel_on_resume, int, 0644); +MODULE_PARM_DESC(turn_on_panel_on_resume, + "Call HCI_PANEL_POWER_ON on resume (-1 = auto, 0 = no, 1 = yes"); + #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" /* Scan code for Fn key on TOS1900 models */ @@ -102,6 +108,7 @@ MODULE_LICENSE("GPL"); #define TOS_NOT_INSTALLED 0x8e00 /* Registers */ +#define HCI_PANEL_POWER_ON 0x0002 #define HCI_FAN 0x0004 #define HCI_TR_BACKLIGHT 0x0005 #define HCI_SYSTEM_EVENT 0x0016 @@ -3242,6 +3249,43 @@ static const char *find_hci_method(acpi_handle handle) return NULL; } +/* + * Some Toshibas have a broken acpi-video interface for brightness control, + * these are quirked in drivers/acpi/video_detect.c to use the GPU native + * (/sys/class/backlight/intel_backlight) instead. + * But these need a HCI_SET call to actually turn the panel back on at resume, + * without this call the screen stays black at resume. + * Either HCI_LCD_BRIGHTNESS (used by acpi_video's _BCM) or HCI_PANEL_POWER_ON + * works. toshiba_acpi_resume() uses HCI_PANEL_POWER_ON to avoid changing + * the configured brightness level. + */ +static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = { + { + /* Toshiba Portégé R700 */ + /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"), + }, + }, + { + /* Toshiba Satellite/Portégé R830 */ + /* Portégé: https://bugs.freedesktop.org/show_bug.cgi?id=82634 */ + /* Satellite: https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "R830"), + }, + }, + { + /* Toshiba Satellite/Portégé Z830 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Z830"), + }, + }, +}; + static int toshiba_acpi_add(struct acpi_device *acpi_dev) { struct toshiba_acpi_dev *dev; @@ -3399,6 +3443,9 @@ iio_error: } #endif + if (turn_on_panel_on_resume == -1) + turn_on_panel_on_resume = dmi_check_system(turn_on_panel_on_resume_dmi_ids); + toshiba_wwan_available(dev); if (dev->wwan_supported) toshiba_acpi_setup_wwan_rfkill(dev); @@ -3524,6 +3571,9 @@ static int toshiba_acpi_resume(struct device *device) rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); } + if (turn_on_panel_on_resume) + hci_write(dev, HCI_PANEL_POWER_ON, 1); + return 0; } #endif -- cgit v1.2.3 From 072aba58c9a4fa5edbfa1db92f78951cbb65d9b9 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 4 Sep 2022 17:11:13 +0300 Subject: platform/mellanox: mlxreg-lc: Make error handling flow consistent Use 'goto' statement in error flow of mlxreg_lc_event_handler() at all places for consistency. This follow-up patch implementing comments from https://www.spinics.net/lists/platform-driver-x86/msg34587.html Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220904141113.49048-1-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-lc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index 1e071df4c9f5..8d833836a6d3 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -564,10 +564,8 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, mlxreg_lc->data->slot, mlxreg_lc->state, kind, action); mutex_lock(&mlxreg_lc->lock); - if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED)) { - mutex_unlock(&mlxreg_lc->lock); - return 0; - } + if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED)) + goto mlxreg_lc_non_initialzed_exit; switch (kind) { case MLXREG_HOTPLUG_LC_SYNCED: @@ -594,8 +592,8 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, /* In case line card is configured - enable it. */ if (mlxreg_lc->state & MLXREG_LC_CONFIGURED) err = mlxreg_lc_enable_disable(mlxreg_lc, 1); - mutex_unlock(&mlxreg_lc->lock); - return err; + + goto mlxreg_lc_enable_disable_exit; } err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs, mlxreg_lc->main_devs_num); @@ -627,8 +625,10 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, break; } +mlxreg_lc_enable_disable_exit: mlxreg_lc_power_on_off_fail: mlxreg_lc_create_static_devices_fail: +mlxreg_lc_non_initialzed_exit: mutex_unlock(&mlxreg_lc->lock); return err; -- cgit v1.2.3 From 7318b613204942ccfd0973cd7f6e534baa86ff5e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 9 Sep 2022 23:09:50 +0200 Subject: platform/x86: asus-wmi: Make kbd_rgb_mode_groups static kbd_rgb_mode_groups is only used inside asus-wmi.c, make it static. Reported-by: kernel test robot Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220909210950.385398-1-hdegoede@redhat.com --- drivers/platform/x86/asus-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d95170b7dba0..ae46af731de9 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -835,7 +835,7 @@ static const struct attribute_group kbd_rgb_state_group = { .attrs = kbd_rgb_state_attrs, }; -const struct attribute_group *kbd_rgb_mode_groups[] = { +static const struct attribute_group *kbd_rgb_mode_groups[] = { NULL, NULL, NULL, -- cgit v1.2.3 From 4b93c6ea4e56c923e86bddffbc862c1bf3597cea Mon Sep 17 00:00:00 2001 From: Arvid Norlander Date: Sun, 11 Sep 2022 21:31:06 +0200 Subject: platform/x86: toshiba_acpi: Set correct parent for input device. This solves the input device showing up as a virtual device. Signed-off-by: Arvid Norlander Link: https://lore.kernel.org/r/20220911193106.555938-1-lkml@vorpal.se Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/toshiba_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 43cc25351aea..64a0088551fa 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -2883,6 +2883,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) dev->hotkey_dev->name = "Toshiba input device"; dev->hotkey_dev->phys = "toshiba_acpi/input0"; dev->hotkey_dev->id.bustype = BUS_HOST; + dev->hotkey_dev->dev.parent = &dev->acpi_dev->dev; if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 || !dev->kbd_function_keys_supported) -- cgit v1.2.3 From 00b1829294b7c88ecba92c661fbe6fe347b364d2 Mon Sep 17 00:00:00 2001 From: Jorge Lopez Date: Mon, 12 Sep 2022 14:26:03 -0500 Subject: platform/x86: hp-wmi: Setting thermal profile fails with 0x06 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Error 0x06 (invalid command parameter) is reported by hp-wmi module when reading the current thermal profile and then proceed to set it back. The failing condition occurs in Linux NixOS after user configures the thermal profile to ‘quiet mode’ in Windows. Quiet Fan Mode is supported in Windows but was not supported in hp-wmi module. This fix adds support for PLATFORM_PROFILE_QUIET in hp-wmi module for HP notebooks other than HP Omen series. Quiet thermal profile is not supported in HP Omen series notebooks. Signed-off-by: Jorge Lopez Link: https://lore.kernel.org/r/20220912192603.4001-1-jorge.lopez2@hp.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/hp-wmi.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index bc7020e9df9e..fc8dbbd6fc7c 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -177,7 +177,8 @@ enum hp_thermal_profile_omen_v1 { enum hp_thermal_profile { HP_THERMAL_PROFILE_PERFORMANCE = 0x00, HP_THERMAL_PROFILE_DEFAULT = 0x01, - HP_THERMAL_PROFILE_COOL = 0x02 + HP_THERMAL_PROFILE_COOL = 0x02, + HP_THERMAL_PROFILE_QUIET = 0x03, }; #define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW) @@ -1194,6 +1195,9 @@ static int hp_wmi_platform_profile_get(struct platform_profile_handler *pprof, case HP_THERMAL_PROFILE_COOL: *profile = PLATFORM_PROFILE_COOL; break; + case HP_THERMAL_PROFILE_QUIET: + *profile = PLATFORM_PROFILE_QUIET; + break; default: return -EINVAL; } @@ -1216,6 +1220,9 @@ static int hp_wmi_platform_profile_set(struct platform_profile_handler *pprof, case PLATFORM_PROFILE_COOL: tp = HP_THERMAL_PROFILE_COOL; break; + case PLATFORM_PROFILE_QUIET: + tp = HP_THERMAL_PROFILE_QUIET; + break; default: return -EOPNOTSUPP; } @@ -1263,6 +1270,8 @@ static int thermal_profile_setup(void) platform_profile_handler.profile_get = hp_wmi_platform_profile_get; platform_profile_handler.profile_set = hp_wmi_platform_profile_set; + + set_bit(PLATFORM_PROFILE_QUIET, platform_profile_handler.choices); } set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices); -- cgit v1.2.3 From 7f1ea75d499a5e3a6f593da0a87096f584752750 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 14 Sep 2022 09:18:50 -0500 Subject: platform/x86/amd: pmc: Add sysfs files for SMU The CPU/APU SMU FW version and program is currently discoverable by turning on dynamic debugging or examining debugfs for the amdgpu driver. To make this more discoverable, create a dedicated sysfs file for it that userspace can parse without debugging enabled. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220914141850.259-1-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- Documentation/ABI/testing/sysfs-amd-pmc | 13 +++++++++++ drivers/platform/x86/amd/pmc.c | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-amd-pmc (limited to 'drivers/platform') diff --git a/Documentation/ABI/testing/sysfs-amd-pmc b/Documentation/ABI/testing/sysfs-amd-pmc new file mode 100644 index 000000000000..c421b72844f1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-amd-pmc @@ -0,0 +1,13 @@ +What: /sys/bus/platform/drivers/amd_pmc/*/smu_fw_version +Date: October 2022 +Contact: Mario Limonciello +Description: Reading this file reports the version of the firmware loaded to + System Management Unit (SMU) contained in AMD CPUs and + APUs. + +What: /sys/bus/platform/drivers/amd_pmc/*/smu_program +Date: October 2022 +Contact: Mario Limonciello +Description: Reading this file reports the program corresponding to the SMU + firmware version. The program field is used to disambiguate two + APU/CPU models that can share the same firmware binary. diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 32887687f888..0616ef8ce64c 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -457,6 +457,44 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) return 0; } +static ssize_t smu_fw_version_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct amd_pmc_dev *dev = dev_get_drvdata(d); + + if (!dev->major) { + int rc = amd_pmc_get_smu_version(dev); + + if (rc) + return rc; + } + return sysfs_emit(buf, "%u.%u.%u\n", dev->major, dev->minor, dev->rev); +} + +static ssize_t smu_program_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct amd_pmc_dev *dev = dev_get_drvdata(d); + + if (!dev->major) { + int rc = amd_pmc_get_smu_version(dev); + + if (rc) + return rc; + } + return sysfs_emit(buf, "%u\n", dev->smu_program); +} + +static DEVICE_ATTR_RO(smu_fw_version); +static DEVICE_ATTR_RO(smu_program); + +static struct attribute *pmc_attrs[] = { + &dev_attr_smu_fw_version.attr, + &dev_attr_smu_program.attr, + NULL, +}; +ATTRIBUTE_GROUPS(pmc); + static int amd_pmc_idlemask_show(struct seq_file *s, void *unused) { struct amd_pmc_dev *dev = s->private; @@ -943,6 +981,7 @@ static struct platform_driver amd_pmc_driver = { .driver = { .name = "amd_pmc", .acpi_match_table = amd_pmc_acpi_ids, + .dev_groups = pmc_groups, }, .probe = amd_pmc_probe, .remove = amd_pmc_remove, -- cgit v1.2.3 From 91809918730f9596acc1ea4ce2e8419543653b87 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 16 Sep 2022 12:46:23 +1200 Subject: platform/x86: asus-wmi: Expand support of GPU fan to read RPM and label The previously added patch to add support for pwm change for TUF laptops also is usuable for more than TUF. The same method `0x00110014` is used to read the fan RPM. Add two extra attributes for reading fan2 plus fan2 label. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20220916004623.10992-1-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ae46af731de9..6e8e093f96b3 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -72,6 +72,7 @@ module_param(fnlock_default, bool, 0444); #define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0) +#define ASUS_GPU_FAN_DESC "gpu_fan" #define ASUS_FAN_DESC "cpu_fan" #define ASUS_FAN_MFUN 0x13 #define ASUS_FAN_SFUN_READ 0x06 @@ -2078,6 +2079,30 @@ static ssize_t asus_hwmon_temp1(struct device *dev, } /* GPU fan on modern ROG laptops */ +static ssize_t fan2_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + int value; + int ret; + + ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL, &value); + if (ret < 0) + return ret; + + value &= 0xffff; + + return sysfs_emit(buf, "%d\n", value * 100); +} + +static ssize_t fan2_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", ASUS_GPU_FAN_DESC); +} + static ssize_t pwm2_enable_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2127,9 +2152,12 @@ static ssize_t pwm2_enable_store(struct device *dev, /* Fan1 */ static DEVICE_ATTR_RW(pwm1); static DEVICE_ATTR_RW(pwm1_enable); -static DEVICE_ATTR_RW(pwm2_enable); static DEVICE_ATTR_RO(fan1_input); static DEVICE_ATTR_RO(fan1_label); +/* Fan2 - GPU fan */ +static DEVICE_ATTR_RW(pwm2_enable); +static DEVICE_ATTR_RO(fan2_input); +static DEVICE_ATTR_RO(fan2_label); /* Temperature */ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL); @@ -2140,6 +2168,8 @@ static struct attribute *hwmon_attributes[] = { &dev_attr_pwm2_enable.attr, &dev_attr_fan1_input.attr, &dev_attr_fan1_label.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_label.attr, &dev_attr_temp1_input.attr, NULL @@ -2160,7 +2190,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, || attr == &dev_attr_pwm1_enable.attr) { if (asus->fan_type == FAN_TYPE_NONE) return 0; - } else if (attr == &dev_attr_pwm2_enable.attr) { + } else if (attr == &dev_attr_fan2_input.attr + || attr == &dev_attr_fan2_label.attr + || attr == &dev_attr_pwm2_enable.attr) { if (asus->gpu_fan_type == FAN_TYPE_NONE) return 0; } else if (attr == &dev_attr_temp1_input.attr) { -- cgit v1.2.3 From 2a2565272a3628e45d61625e36ef17af7af4e3de Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 17 Sep 2022 23:04:07 +0200 Subject: platform/x86: msi-laptop: Change DMI match / alias strings to fix module autoloading On a MSI S270 with Fedora 37 x86_64 / systemd-251.4 the module does not properly autoload. This is likely caused by issues with how systemd-udevd handles the single quote char (') which is part of the sys_vendor / chassis_vendor strings on this laptop. As a workaround remove the single quote char + everything behind it from the sys_vendor + chassis_vendor matches. This fixes the module not autoloading. Link: https://github.com/systemd/systemd/issues/24715 Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220917210407.647432-1-hdegoede@redhat.com --- drivers/platform/x86/msi-laptop.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 1c29678e5727..2f850396e9a7 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -602,11 +602,10 @@ static const struct dmi_system_id msi_dmi_table[] __initconst = { { .ident = "MSI S270", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"), DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"), DMI_MATCH(DMI_PRODUCT_VERSION, "0131"), - DMI_MATCH(DMI_CHASSIS_VENDOR, - "MICRO-STAR INT'L CO.,LTD") + DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT") }, .driver_data = &quirk_old_ec_model, .callback = dmi_check_cb @@ -639,8 +638,7 @@ static const struct dmi_system_id msi_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"), DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"), DMI_MATCH(DMI_PRODUCT_VERSION, "0131"), - DMI_MATCH(DMI_CHASSIS_VENDOR, - "MICRO-STAR INT'L CO.,LTD") + DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT") }, .driver_data = &quirk_old_ec_model, .callback = dmi_check_cb -- cgit v1.2.3 From 8755e675a88680e15cfcc447b8d2de41e7fe8071 Mon Sep 17 00:00:00 2001 From: Yihao Han Date: Mon, 19 Sep 2022 04:15:18 -0700 Subject: platform/x86: toshiba_acpi: Remove duplicate include Remove duplicate include in toshiba_acpi.c. Signed-off-by: Yihao Han Link: https://lore.kernel.org/r/20220919111519.19491-1-hanyihao@vivo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/toshiba_acpi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 64a0088551fa..4ab0bd34d397 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From c710765a4742337e40199403acde2fdd3189183d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 19 Sep 2022 14:22:13 +0200 Subject: platform/x86: wmi: Drop forward declaration of static functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usually it's not necessary to declare static functions if the symbols are in the right order. Moving the definition of acpi_wmi_driver down in the compilation unit allows to drop two such declarations. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220919122213.852322-1-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index aff23309b5d3..223550a10d4d 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -95,9 +95,6 @@ module_param(debug_dump_wdg, bool, 0444); MODULE_PARM_DESC(debug_dump_wdg, "Dump available WMI interfaces [0/1]"); -static int acpi_wmi_remove(struct platform_device *device); -static int acpi_wmi_probe(struct platform_device *device); - static const struct acpi_device_id wmi_device_ids[] = { {"PNP0C14", 0}, {"pnp0c14", 0}, @@ -111,15 +108,6 @@ static const char * const allow_duplicates[] = { NULL }; -static struct platform_driver acpi_wmi_driver = { - .driver = { - .name = "acpi-wmi", - .acpi_match_table = wmi_device_ids, - }, - .probe = acpi_wmi_probe, - .remove = acpi_wmi_remove, -}; - /* * GUID parsing functions */ @@ -1480,6 +1468,15 @@ void wmi_driver_unregister(struct wmi_driver *driver) } EXPORT_SYMBOL(wmi_driver_unregister); +static struct platform_driver acpi_wmi_driver = { + .driver = { + .name = "acpi-wmi", + .acpi_match_table = wmi_device_ids, + }, + .probe = acpi_wmi_probe, + .remove = acpi_wmi_remove, +}; + static int __init acpi_wmi_init(void) { int error; -- cgit v1.2.3 From 5890032523780ddbf508d4b86ddd738bff43a70c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 20 Sep 2022 16:44:34 +0800 Subject: platform/x86: toshiba_acpi: change turn_on_panel_on_resume to static turn_on_panel_on_resume is only used in toshiba_acpi.c now, change it to static. Fixes: 3cb1f40dfdc3 ("drivers/platform: toshiba_acpi: Call HCI_PANEL_POWER_ON on resume on some models") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220920084434.3739493-1-yangyingliang@huawei.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/toshiba_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 4ab0bd34d397..160abd3b3af8 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -52,7 +52,7 @@ MODULE_AUTHOR("John Belmonte"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_LICENSE("GPL"); -int turn_on_panel_on_resume = -1; +static int turn_on_panel_on_resume = -1; module_param(turn_on_panel_on_resume, int, 0644); MODULE_PARM_DESC(turn_on_panel_on_resume, "Call HCI_PANEL_POWER_ON on resume (-1 = auto, 0 = no, 1 = yes"); -- cgit v1.2.3 From bb95d5c540a4101024fc36512d65b2cf2663bbdb Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 20 Sep 2022 09:01:01 +0200 Subject: platform/x86: int3472/discrete: Drop a forward declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By swapping the definition of skl_int3472_discrete_remove() and skl_int3472_discrete_probe() the forward declaration of the former can be dropped. This is a good thing as it removes code duplication. Signed-off-by: Uwe Kleine-König Reviewed-by: Daniel Scally Link: https://lore.kernel.org/r/20220920070101.907596-1-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/int3472/discrete.c | 34 +++++++++++++-------------- 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index ed4c9d760757..974a132db651 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -331,7 +331,22 @@ static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472) return 0; } -static int skl_int3472_discrete_remove(struct platform_device *pdev); +static int skl_int3472_discrete_remove(struct platform_device *pdev) +{ + struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev); + + gpiod_remove_lookup_table(&int3472->gpios); + + if (int3472->clock.cl) + skl_int3472_unregister_clock(int3472); + + gpiod_put(int3472->clock.ena_gpio); + gpiod_put(int3472->clock.led_gpio); + + skl_int3472_unregister_regulator(int3472); + + return 0; +} static int skl_int3472_discrete_probe(struct platform_device *pdev) { @@ -383,23 +398,6 @@ static int skl_int3472_discrete_probe(struct platform_device *pdev) return 0; } -static int skl_int3472_discrete_remove(struct platform_device *pdev) -{ - struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev); - - gpiod_remove_lookup_table(&int3472->gpios); - - if (int3472->clock.cl) - skl_int3472_unregister_clock(int3472); - - gpiod_put(int3472->clock.ena_gpio); - gpiod_put(int3472->clock.led_gpio); - - skl_int3472_unregister_regulator(int3472); - - return 0; -} - static const struct acpi_device_id int3472_device_id[] = { { "INT3472", 0 }, { } -- cgit v1.2.3 From 401199ffa9b69baf3fd1f9ad082aa65c10910585 Mon Sep 17 00:00:00 2001 From: Daniel Houldsworth Date: Thu, 22 Sep 2022 12:54:59 +0100 Subject: platform/x86: hp-wmi: Support touchpad on/off Add scancodes reported by the touchpad on/off button. The actual disabling and enabling is done in hardware, and this just reports that change to userspace. Signed-off-by: Daniel Houldsworth Link: https://lore.kernel.org/r/20220922115459.6511-1-dhould3@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/hp-wmi.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index fc8dbbd6fc7c..da0d25c67e57 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -207,15 +207,17 @@ struct bios_rfkill2_state { }; static const struct key_entry hp_wmi_keymap[] = { - { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, - { KE_KEY, 0x20e6, { KEY_PROG1 } }, - { KE_KEY, 0x20e8, { KEY_MEDIA } }, - { KE_KEY, 0x2142, { KEY_MEDIA } }, - { KE_KEY, 0x213b, { KEY_INFO } }, - { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } }, - { KE_KEY, 0x216a, { KEY_SETUP } }, - { KE_KEY, 0x231b, { KEY_HELP } }, + { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 0x20e6, { KEY_PROG1 } }, + { KE_KEY, 0x20e8, { KEY_MEDIA } }, + { KE_KEY, 0x2142, { KEY_MEDIA } }, + { KE_KEY, 0x213b, { KEY_INFO } }, + { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } }, + { KE_KEY, 0x216a, { KEY_SETUP } }, + { KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } }, + { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } }, + { KE_KEY, 0x231b, { KEY_HELP } }, { KE_END, 0 } }; -- cgit v1.2.3 From 9af48b262675561eefd6edc11b4b02854e6a18ae Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 22 Sep 2022 08:31:00 -0700 Subject: platform/x86/amd: pmc: Fix build without debugfs Without CONFIG_DEBUG_FS, the following build error occurs: drivers/platform/x86/amd/pmc.c:984:17: error: use of undeclared identifier 'pmc_groups'; did you mean 'set_groups'? .dev_groups = pmc_groups, ^~~~~~~~~~ set_groups ./include/linux/cred.h:65:13: note: 'set_groups' declared here extern void set_groups(struct cred *, struct group_info *); ^ drivers/platform/x86/amd/pmc.c:984:17: error: incompatible pointer types initializing 'const struct attribute_group **' with an expression of type 'void (struct cred *, struct group_info *)' [-Werror,-Wincompatible-pointer-types] .dev_groups = pmc_groups, ^~~~~~~~~~ 2 errors generated. pmc_groups was only defined inside a CONFIG_DEBUG_FS block but commit 7f1ea75d499a ("platform/x86/amd: pmc: Add sysfs files for SMU") intended for these sysfs files to be available outside of debugfs. Shuffle the necessary functions out of the CONFIG_DEBUG_FS block so that the file always builds. Fixes: 7f1ea75d499a ("platform/x86/amd: pmc: Add sysfs files for SMU") Signed-off-by: Nathan Chancellor Reviewed-by: Mario Limonciello Link: https://lore.kernel.org/r/20220922153100.324922-1-nathan@kernel.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 116 ++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 58 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 0616ef8ce64c..e47e54b095af 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -371,6 +371,64 @@ static void amd_pmc_validate_deepest(struct amd_pmc_dev *pdev) } #endif +static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) +{ + int rc; + u32 val; + + rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1); + if (rc) + return rc; + + dev->smu_program = (val >> 24) & GENMASK(7, 0); + dev->major = (val >> 16) & GENMASK(7, 0); + dev->minor = (val >> 8) & GENMASK(7, 0); + dev->rev = (val >> 0) & GENMASK(7, 0); + + dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n", + dev->smu_program, dev->major, dev->minor, dev->rev); + + return 0; +} + +static ssize_t smu_fw_version_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct amd_pmc_dev *dev = dev_get_drvdata(d); + + if (!dev->major) { + int rc = amd_pmc_get_smu_version(dev); + + if (rc) + return rc; + } + return sysfs_emit(buf, "%u.%u.%u\n", dev->major, dev->minor, dev->rev); +} + +static ssize_t smu_program_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct amd_pmc_dev *dev = dev_get_drvdata(d); + + if (!dev->major) { + int rc = amd_pmc_get_smu_version(dev); + + if (rc) + return rc; + } + return sysfs_emit(buf, "%u\n", dev->smu_program); +} + +static DEVICE_ATTR_RO(smu_fw_version); +static DEVICE_ATTR_RO(smu_program); + +static struct attribute *pmc_attrs[] = { + &dev_attr_smu_fw_version.attr, + &dev_attr_smu_program.attr, + NULL, +}; +ATTRIBUTE_GROUPS(pmc); + #ifdef CONFIG_DEBUG_FS static int smu_fw_info_show(struct seq_file *s, void *unused) { @@ -437,64 +495,6 @@ static int s0ix_stats_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(s0ix_stats); -static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) -{ - int rc; - u32 val; - - rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1); - if (rc) - return rc; - - dev->smu_program = (val >> 24) & GENMASK(7, 0); - dev->major = (val >> 16) & GENMASK(7, 0); - dev->minor = (val >> 8) & GENMASK(7, 0); - dev->rev = (val >> 0) & GENMASK(7, 0); - - dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n", - dev->smu_program, dev->major, dev->minor, dev->rev); - - return 0; -} - -static ssize_t smu_fw_version_show(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct amd_pmc_dev *dev = dev_get_drvdata(d); - - if (!dev->major) { - int rc = amd_pmc_get_smu_version(dev); - - if (rc) - return rc; - } - return sysfs_emit(buf, "%u.%u.%u\n", dev->major, dev->minor, dev->rev); -} - -static ssize_t smu_program_show(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct amd_pmc_dev *dev = dev_get_drvdata(d); - - if (!dev->major) { - int rc = amd_pmc_get_smu_version(dev); - - if (rc) - return rc; - } - return sysfs_emit(buf, "%u\n", dev->smu_program); -} - -static DEVICE_ATTR_RO(smu_fw_version); -static DEVICE_ATTR_RO(smu_program); - -static struct attribute *pmc_attrs[] = { - &dev_attr_smu_fw_version.attr, - &dev_attr_smu_program.attr, - NULL, -}; -ATTRIBUTE_GROUPS(pmc); - static int amd_pmc_idlemask_show(struct seq_file *s, void *unused) { struct amd_pmc_dev *dev = s->private; -- cgit v1.2.3 From 1738061c9ec854db2db76be8bb968f550d9bdddc Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 22 Sep 2022 18:42:00 +0530 Subject: platform/x86/amd/pmf: Add support for CnQF CnQF (a.k.a Cool and Quiet Framework) extends the static slider concept. PMF dynamically manages system power limits and fan policy based on system power trends which is representative of workload trend. Static slider and CnQF controls are mutually exclusive for system power budget adjustments. CnQF supports configurable number of modes which can be unique for AC and DC. Every mode is representative of a system state characterized by unique steady state and boost behavior. OEMs can configure the different modes/system states and how the transition to a mode happens. Whether to have CnQF manage system power budget dynamically in AC or DC or both is also configurable. Mode changes due to CnQF don't result in slider position change. The default OEM values are obtained after evaluating the PMF ACPI function idx 11 & 12 for AC and DC respectively. Whether to turn ON/OFF by default is guided by a "flag" passed by the OEM BIOS. Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220922131202.56529-2-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/Makefile | 2 +- drivers/platform/x86/amd/pmf/acpi.c | 10 + drivers/platform/x86/amd/pmf/cnqf.c | 335 ++++++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/core.c | 19 +- drivers/platform/x86/amd/pmf/pmf.h | 99 ++++++++++ 5 files changed, 463 insertions(+), 2 deletions(-) create mode 100644 drivers/platform/x86/amd/pmf/cnqf.c (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile index ef2b08c9174d..fdededf54392 100644 --- a/drivers/platform/x86/amd/pmf/Makefile +++ b/drivers/platform/x86/amd/pmf/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_AMD_PMF) += amd-pmf.o amd-pmf-objs := core.o acpi.o sps.o \ - auto-mode.o + auto-mode.o cnqf.o diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index cb46a7252414..05a2b8a056fc 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -233,6 +233,16 @@ static int apmf_get_system_params(struct amd_pmf_dev *dev) return 0; } +int apmf_get_dyn_slider_def_ac(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data) +{ + return apmf_if_call_store_buffer(pdev, APMF_FUNC_DYN_SLIDER_AC, data, sizeof(*data)); +} + +int apmf_get_dyn_slider_def_dc(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data) +{ + return apmf_if_call_store_buffer(pdev, APMF_FUNC_DYN_SLIDER_DC, data, sizeof(*data)); +} + void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev) { acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c new file mode 100644 index 000000000000..27fc3f909960 --- /dev/null +++ b/drivers/platform/x86/amd/pmf/cnqf.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Platform Management Framework Driver + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Shyam Sundar S K + */ + +#include +#include "pmf.h" + +static struct cnqf_config config_store; + +static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx, + struct cnqf_config *table) +{ + struct power_table_control *pc; + + pc = &config_store.mode_set[src][idx].power_control; + + amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL); + amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL); + 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); + + if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) + apmf_update_fan_idx(dev, + config_store.mode_set[src][idx].fan_control.manual, + config_store.mode_set[src][idx].fan_control.fan_id); + + return 0; +} + +static void amd_pmf_update_power_threshold(int src) +{ + struct cnqf_mode_settings *ts; + struct cnqf_tran_params *tp; + + tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET]; + ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; + tp->power_threshold = ts->power_floor - tp->power_delta; + + tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO]; + ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; + tp->power_threshold = ts->power_floor - tp->power_delta; + + tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; + ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; + tp->power_threshold = ts->power_floor - tp->power_delta; + + tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; + ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; + tp->power_threshold = ts->power_floor - tp->power_delta; + + tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; + ts = &config_store.mode_set[src][CNQF_MODE_QUIET]; + tp->power_threshold = ts->power_floor - tp->power_delta; + + tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; + ts = &config_store.mode_set[src][CNQF_MODE_TURBO]; + tp->power_threshold = ts->power_floor - tp->power_delta; +} + +static const char *state_as_str(unsigned int state) +{ + switch (state) { + case CNQF_MODE_QUIET: + return "QUIET"; + case CNQF_MODE_BALANCE: + return "BALANCED"; + case CNQF_MODE_TURBO: + return "TURBO"; + case CNQF_MODE_PERFORMANCE: + return "PERFORMANCE"; + default: + return "Unknown CnQF mode"; + } +} + +static int amd_pmf_cnqf_get_power_source(struct amd_pmf_dev *dev) +{ + if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) && + is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) + return amd_pmf_get_power_source(); + else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) + return POWER_SOURCE_DC; + else + return POWER_SOURCE_AC; +} + +int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms) +{ + struct cnqf_tran_params *tp; + int src, i, j; + u32 avg_power = 0; + + src = amd_pmf_cnqf_get_power_source(dev); + + if (dev->current_profile == PLATFORM_PROFILE_BALANCED) { + amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); + } else { + /* + * Return from here if the platform_profile is not balanced + * so that preference is given to user mode selection, rather + * than enforcing CnQF to run all the time (if enabled) + */ + return -EINVAL; + } + + for (i = 0; i < CNQF_TRANSITION_MAX; i++) { + config_store.trans_param[src][i].timer += time_lapsed_ms; + config_store.trans_param[src][i].total_power += socket_power; + config_store.trans_param[src][i].count++; + + tp = &config_store.trans_param[src][i]; + if (tp->timer >= tp->time_constant && tp->count) { + avg_power = tp->total_power / tp->count; + + /* Reset the indices */ + tp->timer = 0; + tp->total_power = 0; + tp->count = 0; + + if ((tp->shifting_up && avg_power >= tp->power_threshold) || + (!tp->shifting_up && avg_power <= tp->power_threshold)) { + tp->priority = true; + } else { + tp->priority = false; + } + } + } + + dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n", + avg_power, socket_power, state_as_str(config_store.current_mode)); + + for (j = 0; j < CNQF_TRANSITION_MAX; j++) { + /* apply the highest priority */ + if (config_store.trans_param[src][j].priority) { + if (config_store.current_mode != + config_store.trans_param[src][j].target_mode) { + config_store.current_mode = + config_store.trans_param[src][j].target_mode; + dev_dbg(dev->dev, "Moving to Mode :%s\n", + state_as_str(config_store.current_mode)); + amd_pmf_set_cnqf(dev, src, + config_store.current_mode, NULL); + } + break; + } + } + return 0; +} + +static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output out) +{ + struct cnqf_tran_params *tp; + + tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET]; + tp->time_constant = out.t_balanced_to_quiet; + tp->target_mode = CNQF_MODE_QUIET; + tp->shifting_up = false; + + tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; + tp->time_constant = out.t_balanced_to_perf; + tp->target_mode = CNQF_MODE_PERFORMANCE; + tp->shifting_up = true; + + tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; + tp->time_constant = out.t_quiet_to_balanced; + tp->target_mode = CNQF_MODE_BALANCE; + tp->shifting_up = true; + + tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; + tp->time_constant = out.t_perf_to_balanced; + tp->target_mode = CNQF_MODE_BALANCE; + tp->shifting_up = false; + + tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; + tp->time_constant = out.t_turbo_to_perf; + tp->target_mode = CNQF_MODE_PERFORMANCE; + tp->shifting_up = false; + + tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO]; + tp->time_constant = out.t_perf_to_turbo; + tp->target_mode = CNQF_MODE_TURBO; + tp->shifting_up = true; +} + +static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output out) +{ + struct cnqf_mode_settings *ms; + + /* Quiet Mode */ + ms = &config_store.mode_set[idx][CNQF_MODE_QUIET]; + ms->power_floor = out.ps[APMF_CNQF_QUIET].pfloor; + ms->power_control.fppt = out.ps[APMF_CNQF_QUIET].fppt; + ms->power_control.sppt = out.ps[APMF_CNQF_QUIET].sppt; + ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_QUIET].sppt_apu_only; + ms->power_control.spl = out.ps[APMF_CNQF_QUIET].spl; + ms->power_control.stt_min = out.ps[APMF_CNQF_QUIET].stt_min_limit; + ms->power_control.stt_skin_temp[STT_TEMP_APU] = + out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU]; + ms->power_control.stt_skin_temp[STT_TEMP_HS2] = + out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out.ps[APMF_CNQF_QUIET].fan_id; + + /* Balance Mode */ + ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE]; + ms->power_floor = out.ps[APMF_CNQF_BALANCE].pfloor; + ms->power_control.fppt = out.ps[APMF_CNQF_BALANCE].fppt; + ms->power_control.sppt = out.ps[APMF_CNQF_BALANCE].sppt; + ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_BALANCE].sppt_apu_only; + ms->power_control.spl = out.ps[APMF_CNQF_BALANCE].spl; + ms->power_control.stt_min = out.ps[APMF_CNQF_BALANCE].stt_min_limit; + ms->power_control.stt_skin_temp[STT_TEMP_APU] = + out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU]; + ms->power_control.stt_skin_temp[STT_TEMP_HS2] = + out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out.ps[APMF_CNQF_BALANCE].fan_id; + + /* Performance Mode */ + ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE]; + ms->power_floor = out.ps[APMF_CNQF_PERFORMANCE].pfloor; + ms->power_control.fppt = out.ps[APMF_CNQF_PERFORMANCE].fppt; + ms->power_control.sppt = out.ps[APMF_CNQF_PERFORMANCE].sppt; + ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_PERFORMANCE].sppt_apu_only; + ms->power_control.spl = out.ps[APMF_CNQF_PERFORMANCE].spl; + ms->power_control.stt_min = out.ps[APMF_CNQF_PERFORMANCE].stt_min_limit; + ms->power_control.stt_skin_temp[STT_TEMP_APU] = + out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU]; + ms->power_control.stt_skin_temp[STT_TEMP_HS2] = + out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out.ps[APMF_CNQF_PERFORMANCE].fan_id; + + /* Turbo Mode */ + ms = &config_store.mode_set[idx][CNQF_MODE_TURBO]; + ms->power_floor = out.ps[APMF_CNQF_TURBO].pfloor; + ms->power_control.fppt = out.ps[APMF_CNQF_TURBO].fppt; + ms->power_control.sppt = out.ps[APMF_CNQF_TURBO].sppt; + ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_TURBO].sppt_apu_only; + ms->power_control.spl = out.ps[APMF_CNQF_TURBO].spl; + ms->power_control.stt_min = out.ps[APMF_CNQF_TURBO].stt_min_limit; + ms->power_control.stt_skin_temp[STT_TEMP_APU] = + out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU]; + ms->power_control.stt_skin_temp[STT_TEMP_HS2] = + out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2]; + ms->fan_control.fan_id = out.ps[APMF_CNQF_TURBO].fan_id; +} + +static int amd_pmf_check_flags(struct amd_pmf_dev *dev) +{ + struct apmf_dyn_slider_output out = {}; + + if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC)) + apmf_get_dyn_slider_def_ac(dev, &out); + else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) + apmf_get_dyn_slider_def_dc(dev, &out); + + return out.flags; +} + +static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev) +{ + struct apmf_dyn_slider_output out; + int i, j, ret; + + for (i = 0; i < POWER_SOURCE_MAX; i++) { + if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i)) + continue; + + if (i == POWER_SOURCE_AC) + ret = apmf_get_dyn_slider_def_ac(dev, &out); + else + ret = apmf_get_dyn_slider_def_dc(dev, &out); + if (ret) { + dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret); + return ret; + } + + amd_pmf_update_mode_set(i, out); + amd_pmf_update_trans_data(i, out); + amd_pmf_update_power_threshold(i); + + for (j = 0; j < CNQF_MODE_MAX; j++) { + if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO) + config_store.mode_set[i][j].fan_control.manual = false; + else + config_store.mode_set[i][j].fan_control.manual = true; + } + } + + /* set to initial default values */ + config_store.current_mode = CNQF_MODE_BALANCE; + + return 0; +} + +void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev) +{ + cancel_delayed_work_sync(&dev->work_buffer); +} + +int amd_pmf_init_cnqf(struct amd_pmf_dev *dev) +{ + int ret, src; + + /* + * Note the caller of this function has already checked that both + * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported. + */ + + ret = amd_pmf_load_defaults_cnqf(dev); + if (ret < 0) + return ret; + + amd_pmf_init_metrics_table(dev); + + dev->cnqf_supported = true; + dev->cnqf_enabled = amd_pmf_check_flags(dev); + + /* update the thermal for CnQF */ + if (dev->cnqf_enabled && dev->current_profile == PLATFORM_PROFILE_BALANCED) { + src = amd_pmf_cnqf_get_power_source(dev); + amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); + } + + return 0; +} diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index a675ca969331..99be1e6d57d3 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -123,6 +123,11 @@ static void amd_pmf_get_metrics(struct work_struct *work) amd_pmf_trans_automode(dev, socket_power, time_elapsed_ms); } + if (dev->cnqf_enabled) { + /* Apply the CnQF transition */ + amd_pmf_trans_cnqf(dev, socket_power, time_elapsed_ms); + } + dev->start_time = ktime_to_ms(ktime_get()); schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms)); mutex_unlock(&dev->update_mutex); @@ -252,6 +257,8 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) static void amd_pmf_init_features(struct amd_pmf_dev *dev) { + int ret; + /* Enable Static Slider */ if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { amd_pmf_init_sps(dev); @@ -262,6 +269,12 @@ static void amd_pmf_init_features(struct amd_pmf_dev *dev) if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) { amd_pmf_init_auto_mode(dev); dev_dbg(dev->dev, "Auto Mode Init done\n"); + } else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) || + is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) { + /* Enable Cool n Quiet Framework (CnQF) */ + ret = amd_pmf_init_cnqf(dev); + if (ret) + dev_warn(dev->dev, "CnQF Init failed\n"); } } @@ -270,8 +283,12 @@ static void amd_pmf_deinit_features(struct amd_pmf_dev *dev) if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) amd_pmf_deinit_sps(dev); - if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) + if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) { amd_pmf_deinit_auto_mode(dev); + } else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) || + is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) { + amd_pmf_deinit_cnqf(dev); + } } static const struct acpi_device_id amd_pmf_acpi_ids[] = { diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 0a72a395c2ef..24dd6fbff24c 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -22,6 +22,8 @@ #define APMF_FUNC_AUTO_MODE 5 #define APMF_FUNC_SET_FAN_IDX 7 #define APMF_FUNC_STATIC_SLIDER_GRANULAR 9 +#define APMF_FUNC_DYN_SLIDER_AC 11 +#define APMF_FUNC_DYN_SLIDER_DC 12 /* Message Definitions */ #define SET_SPL 0x03 /* SPL: Sustained Power Limit */ @@ -165,6 +167,8 @@ struct amd_pmf_dev { int socket_power_history_idx; bool amt_enabled; struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */ + bool cnqf_enabled; + bool cnqf_supported; }; struct apmf_sps_prop_granular { @@ -294,6 +298,93 @@ struct apmf_auto_mode { u32 fan_id_quiet; } __packed; +/* CnQF Layer */ +enum cnqf_trans_priority { + CNQF_TRANSITION_TO_TURBO, /* Any other mode to Turbo Mode */ + CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE, /* quiet/balance to Performance Mode */ + CNQF_TRANSITION_FROM_QUIET_TO_BALANCE, /* Quiet Mode to Balance Mode */ + CNQF_TRANSITION_TO_QUIET, /* Any other mode to Quiet Mode */ + CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE, /* Performance/Turbo to Balance Mode */ + CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE, /* Turbo mode to Performance Mode */ + CNQF_TRANSITION_MAX, +}; + +enum cnqf_mode { + CNQF_MODE_QUIET, + CNQF_MODE_BALANCE, + CNQF_MODE_PERFORMANCE, + CNQF_MODE_TURBO, + CNQF_MODE_MAX, +}; + +enum apmf_cnqf_pos { + APMF_CNQF_TURBO, + APMF_CNQF_PERFORMANCE, + APMF_CNQF_BALANCE, + APMF_CNQF_QUIET, + APMF_CNQF_MAX, +}; + +struct cnqf_mode_settings { + struct power_table_control power_control; + struct fan_table_control fan_control; + u32 power_floor; +}; + +struct cnqf_tran_params { + u32 time_constant; /* minimum time required to switch to next mode */ + u32 power_delta; /* minimum power required to switch to next mode */ + u32 power_threshold; + u32 timer; /* elapsed time. if timer > timethreshold, it will move to next mode */ + u32 total_power; + u32 count; + bool priority; + bool shifting_up; + enum cnqf_mode target_mode; +}; + +struct cnqf_power_delta { + u32 to_turbo; + u32 balance_to_perf; + u32 quiet_to_balance; + u32 to_quiet; + u32 perf_to_balance; + u32 turbo_to_perf; +}; + +struct cnqf_config { + struct cnqf_tran_params trans_param[POWER_SOURCE_MAX][CNQF_TRANSITION_MAX]; + struct cnqf_mode_settings mode_set[POWER_SOURCE_MAX][CNQF_MODE_MAX]; + struct power_table_control defaults; + enum cnqf_mode current_mode; + struct cnqf_power_delta power_delta[POWER_SOURCE_MAX]; + u32 power_src; + u32 avg_power; +}; + +struct apmf_cnqf_power_set { + u32 pfloor; + u32 fppt; + u32 sppt; + u32 sppt_apu_only; + u32 spl; + u32 stt_min_limit; + u8 stt_skintemp[STT_TEMP_COUNT]; + u32 fan_id; +} __packed; + +struct apmf_dyn_slider_output { + u16 size; + u16 flags; + u32 t_perf_to_turbo; + u32 t_balanced_to_perf; + u32 t_quiet_to_balanced; + u32 t_balanced_to_quiet; + u32 t_perf_to_balanced; + u32 t_turbo_to_perf; + struct apmf_cnqf_power_set ps[APMF_CNQF_MAX]; +} __packed; + /* Core Layer */ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev); void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev); @@ -324,4 +415,12 @@ int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event); int amd_pmf_reset_amt(struct amd_pmf_dev *dev); void amd_pmf_handle_amt(struct amd_pmf_dev *dev); + +/* CnQF Layer */ +int apmf_get_dyn_slider_def_ac(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data); +int apmf_get_dyn_slider_def_dc(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data); +int amd_pmf_init_cnqf(struct amd_pmf_dev *dev); +void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev); +int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms); + #endif /* PMF_H */ -- cgit v1.2.3 From 3dae5825295d7b3284fc349cd6bfa641f4033e16 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 22 Sep 2022 18:42:01 +0530 Subject: platform/x86/amd/pmf: Add sysfs to toggle CnQF Whether to turn CnQF on/off by default upon driver load would be decided by a BIOS flag. Add a sysfs node to provide a way to the user whether to use static slider or CnQF . Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220922131202.56529-3-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/cnqf.c | 60 +++++++++++++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/core.c | 6 ++++ drivers/platform/x86/amd/pmf/pmf.h | 1 + 3 files changed, 67 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c index 27fc3f909960..927f3c8cd971 100644 --- a/drivers/platform/x86/amd/pmf/cnqf.c +++ b/drivers/platform/x86/amd/pmf/cnqf.c @@ -302,6 +302,66 @@ static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev) return 0; } +static ssize_t cnqf_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); + int mode, result, src; + bool input; + + mode = amd_pmf_get_pprof_modes(pdev); + if (mode < 0) + return mode; + + result = kstrtobool(buf, &input); + if (result) + return result; + + src = amd_pmf_cnqf_get_power_source(pdev); + pdev->cnqf_enabled = input; + + if (pdev->cnqf_enabled && pdev->current_profile == PLATFORM_PROFILE_BALANCED) { + amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL); + } else { + if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) + amd_pmf_update_slider(pdev, SLIDER_OP_SET, mode, NULL); + } + + dev_dbg(pdev->dev, "Received CnQF %s\n", input ? "on" : "off"); + return count; +} + +static ssize_t cnqf_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", pdev->cnqf_enabled ? "on" : "off"); +} + +static DEVICE_ATTR_RW(cnqf_enable); + +static umode_t cnqf_feature_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); + + return pdev->cnqf_supported ? attr->mode : 0; +} + +static struct attribute *cnqf_feature_attrs[] = { + &dev_attr_cnqf_enable.attr, + NULL +}; + +const struct attribute_group cnqf_feature_attribute_group = { + .is_visible = cnqf_feature_is_visible, + .attrs = cnqf_feature_attrs, +}; + void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev) { cancel_delayed_work_sync(&dev->work_buffer); diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index 99be1e6d57d3..44fe30726b62 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -391,10 +391,16 @@ static int amd_pmf_remove(struct platform_device *pdev) return 0; } +static const struct attribute_group *amd_pmf_driver_groups[] = { + &cnqf_feature_attribute_group, + NULL, +}; + static struct platform_driver amd_pmf_driver = { .driver = { .name = "amd-pmf", .acpi_match_table = amd_pmf_acpi_ids, + .dev_groups = amd_pmf_driver_groups, }, .probe = amd_pmf_probe, .remove = amd_pmf_remove, diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 24dd6fbff24c..097f3f5d33a3 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -422,5 +422,6 @@ int apmf_get_dyn_slider_def_dc(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_ int amd_pmf_init_cnqf(struct amd_pmf_dev *dev); void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev); int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms); +extern const struct attribute_group cnqf_feature_attribute_group; #endif /* PMF_H */ -- cgit v1.2.3 From 22ee98cb696e95b05a188756d479d382d93559ef Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Fri, 23 Sep 2022 18:47:24 +0530 Subject: platform/x86/amd/pmf: install notify handler after acpi init It is observed that when thinkpad_acpi driver loads before amd-pmf driver, thinkpad_acpi driver sends the AMT "on" event and the request immediately will be part of the PMF BIOS "pending requests". With the current amd-pmf code, as soon as the amd-pmf driver gets probed, it calls apmf_acpi_init() where the notify handler will be installed. Handler callback would call amd_pmf_handle_amt() where the amd_pmf_set_automode() shall update the auto-mode thermals. In this case, the auto-mode config_store shall have "zeros", as the auto mode init gets called during the later stage. To fix this, change the order of the acpi notifer install and call it after the auto mode initialization is done. Fixes: 7d77dcc83ada ("platform/x86/amd/pmf: Handle AMT and CQL events for Auto mode") Cc: Mario Limonciello Cc: Mark Pearson Cc: Patil Rajesh Reddy Signed-off-by: Shyam Sundar S K Reviewed-by: Mario Limonciello Link: https://lore.kernel.org/r/20220923131724.1812685-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/acpi.c | 38 +++++++++++++++++++++---------------- drivers/platform/x86/amd/pmf/core.c | 1 + drivers/platform/x86/amd/pmf/pmf.h | 1 + 3 files changed, 24 insertions(+), 16 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index cb46a7252414..b445c91aa52e 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -233,6 +233,28 @@ static int apmf_get_system_params(struct amd_pmf_dev *dev) return 0; } +int apmf_install_handler(struct amd_pmf_dev *pmf_dev) +{ + acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); + acpi_status status; + + /* Install the APMF Notify handler */ + if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) && + is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS)) { + status = acpi_install_notify_handler(ahandle, ACPI_ALL_NOTIFY, + apmf_event_handler, pmf_dev); + if (ACPI_FAILURE(status)) { + dev_err(pmf_dev->dev, "failed to install notify handler\n"); + return -ENODEV; + } + + /* Call the handler once manually to catch up with possibly missed notifies. */ + apmf_event_handler(ahandle, 0, pmf_dev); + } + + return 0; +} + void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev) { acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); @@ -247,8 +269,6 @@ void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev) int apmf_acpi_init(struct amd_pmf_dev *pmf_dev) { - acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); - acpi_status status; int ret; ret = apmf_if_verify_interface(pmf_dev); @@ -269,20 +289,6 @@ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev) schedule_delayed_work(&pmf_dev->heart_beat, 0); } - /* Install the APMF Notify handler */ - if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) && - is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS)) { - status = acpi_install_notify_handler(ahandle, - ACPI_ALL_NOTIFY, - apmf_event_handler, pmf_dev); - if (ACPI_FAILURE(status)) { - dev_err(pmf_dev->dev, "failed to install notify handler\n"); - return -ENODEV; - } - /* Call the handler once manually to catch up with possibly missed notifies. */ - apmf_event_handler(ahandle, 0, pmf_dev); - } - out: return ret; } diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index a675ca969331..785d2ba5ec4f 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -352,6 +352,7 @@ static int amd_pmf_probe(struct platform_device *pdev) apmf_acpi_init(dev); platform_set_drvdata(pdev, dev); amd_pmf_init_features(dev); + apmf_install_handler(dev); amd_pmf_dbgfs_register(dev); mutex_init(&dev->lock); diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 0a72a395c2ef..1ae4c70a18b2 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -301,6 +301,7 @@ int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index); int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data); int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev); int amd_pmf_get_power_source(void); +int apmf_install_handler(struct amd_pmf_dev *pmf_dev); /* SPS Layer */ int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf); -- cgit v1.2.3 From 9732f9c7b4a0c18820cbf9c74f7c8abde60f2834 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 22 Sep 2022 22:21:18 +0530 Subject: platform/x86/amd/pmf: Remove unused power_delta instances Initial version of the PMF ACPI documentation had the concept of "power_delta" which is removed in the recent revisions. So the entire cnqf_power_delta structure is never used/updated. Hence removing it. Fixes: 1738061c9ec8 ("platform/x86/amd/pmf: Add support for CnQF") Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220922165118.163165-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/cnqf.c | 12 ++++++------ drivers/platform/x86/amd/pmf/pmf.h | 11 ----------- 2 files changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c index 927f3c8cd971..668c7c0fea83 100644 --- a/drivers/platform/x86/amd/pmf/cnqf.c +++ b/drivers/platform/x86/amd/pmf/cnqf.c @@ -45,27 +45,27 @@ static void amd_pmf_update_power_threshold(int src) tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET]; ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; - tp->power_threshold = ts->power_floor - tp->power_delta; + tp->power_threshold = ts->power_floor; tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO]; ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; - tp->power_threshold = ts->power_floor - tp->power_delta; + tp->power_threshold = ts->power_floor; tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; - tp->power_threshold = ts->power_floor - tp->power_delta; + tp->power_threshold = ts->power_floor; tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; - tp->power_threshold = ts->power_floor - tp->power_delta; + tp->power_threshold = ts->power_floor; tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; ts = &config_store.mode_set[src][CNQF_MODE_QUIET]; - tp->power_threshold = ts->power_floor - tp->power_delta; + tp->power_threshold = ts->power_floor; tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; ts = &config_store.mode_set[src][CNQF_MODE_TURBO]; - tp->power_threshold = ts->power_floor - tp->power_delta; + tp->power_threshold = ts->power_floor; } static const char *state_as_str(unsigned int state) diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 097f3f5d33a3..e5dc3ae238c7 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -333,7 +333,6 @@ struct cnqf_mode_settings { struct cnqf_tran_params { u32 time_constant; /* minimum time required to switch to next mode */ - u32 power_delta; /* minimum power required to switch to next mode */ u32 power_threshold; u32 timer; /* elapsed time. if timer > timethreshold, it will move to next mode */ u32 total_power; @@ -343,21 +342,11 @@ struct cnqf_tran_params { enum cnqf_mode target_mode; }; -struct cnqf_power_delta { - u32 to_turbo; - u32 balance_to_perf; - u32 quiet_to_balance; - u32 to_quiet; - u32 perf_to_balance; - u32 turbo_to_perf; -}; - struct cnqf_config { struct cnqf_tran_params trans_param[POWER_SOURCE_MAX][CNQF_TRANSITION_MAX]; struct cnqf_mode_settings mode_set[POWER_SOURCE_MAX][CNQF_MODE_MAX]; struct power_table_control defaults; enum cnqf_mode current_mode; - struct cnqf_power_delta power_delta[POWER_SOURCE_MAX]; u32 power_src; u32 avg_power; }; -- cgit v1.2.3 From bbfa903b4f9a0a76719f386367fed5e64187f577 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 23 Sep 2022 06:32:33 +0000 Subject: platform/x86: dell-smbios-base: Use sysfs_emit() Replace the open-code with sysfs_emit() to simplify the code. Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220923063233.239091-1-ye.xingchen@zte.com.cn Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-smbios-base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c index fc086b66f70b..e61bfaf8b5c4 100644 --- a/drivers/platform/x86/dell/dell-smbios-base.c +++ b/drivers/platform/x86/dell/dell-smbios-base.c @@ -441,7 +441,7 @@ static ssize_t location_show(struct device *dev, i = match_attribute(dev, attr); if (i > 0) - return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location); + return sysfs_emit(buf, "%08x", da_tokens[i].location); return 0; } @@ -455,7 +455,7 @@ static ssize_t value_show(struct device *dev, i = match_attribute(dev, attr); if (i > 0) - return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value); + return sysfs_emit(buf, "%08x", da_tokens[i].value); return 0; } -- cgit v1.2.3 From 76a13da75d3ae5acc3cbc02eef558d8faa12e846 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 23 Sep 2022 06:33:14 +0000 Subject: platform/x86: intel-uncore-freq: Use sysfs_emit() to instead of scnprintf() Replace the open-code with sysfs_emit() to simplify the code. Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220923063314.239146-1-ye.xingchen@zte.com.cn Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c index 84eabd6156bb..cb24de9e97dc 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -113,7 +113,7 @@ show_uncore_perf_status(current_freq_khz); struct uncore_data *data = container_of(attr, struct uncore_data,\ member_name##_dev_attr);\ \ - return scnprintf(buf, PAGE_SIZE, "%u\n", \ + return sysfs_emit(buf, "%u\n", \ data->member_name); \ } \ -- cgit v1.2.3 From d443fcad6f644a98f2b2cee6a2bfd7e6620d2fe5 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 23 Sep 2022 11:47:59 +0200 Subject: platform/x86: compal-laptop: Get rid of a few forward declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declarations for static symbols are useless repetition (unless there are cyclic dependencies). By changing the order of a few symbols two forward declarations can be dropped. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220923094759.87804-1-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/compal-laptop.c | 151 +++++++++++++++++------------------ 1 file changed, 74 insertions(+), 77 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 0942f50bd793..72e1523edd31 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -721,16 +721,6 @@ static struct attribute *compal_hwmon_attrs[] = { }; ATTRIBUTE_GROUPS(compal_hwmon); -static int compal_probe(struct platform_device *); -static int compal_remove(struct platform_device *); -static struct platform_driver compal_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = compal_probe, - .remove = compal_remove, -}; - static enum power_supply_property compal_bat_properties[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, @@ -965,6 +955,80 @@ err_wifi: return ret; } +static int compal_probe(struct platform_device *pdev) +{ + int err; + struct compal_data *data; + struct device *hwmon_dev; + struct power_supply_config psy_cfg = {}; + + if (!extra_features) + return 0; + + /* Fan control */ + data = devm_kzalloc(&pdev->dev, sizeof(struct compal_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + initialize_fan_control_data(data); + + err = sysfs_create_group(&pdev->dev.kobj, &compal_platform_attr_group); + if (err) + return err; + + hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, + "compal", data, + compal_hwmon_groups); + if (IS_ERR(hwmon_dev)) { + err = PTR_ERR(hwmon_dev); + goto remove; + } + + /* Power supply */ + initialize_power_supply_data(data); + psy_cfg.drv_data = data; + data->psy = power_supply_register(&compal_device->dev, &psy_bat_desc, + &psy_cfg); + if (IS_ERR(data->psy)) { + err = PTR_ERR(data->psy); + goto remove; + } + + platform_set_drvdata(pdev, data); + + return 0; + +remove: + sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group); + return err; +} + +static int compal_remove(struct platform_device *pdev) +{ + struct compal_data *data; + + if (!extra_features) + return 0; + + pr_info("Unloading: resetting fan control to motherboard\n"); + pwm_disable_control(); + + data = platform_get_drvdata(pdev); + power_supply_unregister(data->psy); + + sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group); + + return 0; +} + +static struct platform_driver compal_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = compal_probe, + .remove = compal_remove, +}; + static int __init compal_init(void) { int ret; @@ -1028,54 +1092,6 @@ err_backlight: return ret; } -static int compal_probe(struct platform_device *pdev) -{ - int err; - struct compal_data *data; - struct device *hwmon_dev; - struct power_supply_config psy_cfg = {}; - - if (!extra_features) - return 0; - - /* Fan control */ - data = devm_kzalloc(&pdev->dev, sizeof(struct compal_data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - initialize_fan_control_data(data); - - err = sysfs_create_group(&pdev->dev.kobj, &compal_platform_attr_group); - if (err) - return err; - - hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, - "compal", data, - compal_hwmon_groups); - if (IS_ERR(hwmon_dev)) { - err = PTR_ERR(hwmon_dev); - goto remove; - } - - /* Power supply */ - initialize_power_supply_data(data); - psy_cfg.drv_data = data; - data->psy = power_supply_register(&compal_device->dev, &psy_bat_desc, - &psy_cfg); - if (IS_ERR(data->psy)) { - err = PTR_ERR(data->psy); - goto remove; - } - - platform_set_drvdata(pdev, data); - - return 0; - -remove: - sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group); - return err; -} - static void __exit compal_cleanup(void) { platform_device_unregister(compal_device); @@ -1089,25 +1105,6 @@ static void __exit compal_cleanup(void) pr_info("Driver unloaded\n"); } -static int compal_remove(struct platform_device *pdev) -{ - struct compal_data *data; - - if (!extra_features) - return 0; - - pr_info("Unloading: resetting fan control to motherboard\n"); - pwm_disable_control(); - - data = platform_get_drvdata(pdev); - power_supply_unregister(data->psy); - - sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group); - - return 0; -} - - module_init(compal_init); module_exit(compal_cleanup); -- cgit v1.2.3 From a776bf77c98ddea32233e2480f565797900975ba Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 26 Sep 2022 17:40:11 -0700 Subject: platform/surface: Split memcpy() of struct ssam_event flexible array To work around a misbehavior of the compiler's ability to see into composite flexible array structs (as detailed in the coming memcpy() hardening series[1]), split the memcpy() of the header and the payload so no false positive run-time overflow warning will be generated. [1] https://lore.kernel.org/linux-hardening/20220901065914.1417829-2-keescook@chromium.org Cc: Maximilian Luz Cc: Hans de Goede Cc: Mark Gross Cc: platform-driver-x86@vger.kernel.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20220927004011.1942739-1-keescook@chromium.org Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_acpi_notify.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index 44e317970557..50500e562963 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -355,7 +355,8 @@ static u32 san_evt_bat_nf(struct ssam_event_notifier *nf, INIT_DELAYED_WORK(&work->work, san_evt_bat_workfn); work->dev = d->dev; - memcpy(&work->event, event, sizeof(struct ssam_event) + event->length); + work->event = *event; + memcpy(work->event.data, event->data, event->length); queue_delayed_work(san_wq, &work->work, delay); return SSAM_NOTIF_HANDLED; -- cgit v1.2.3 From b37fe34c83099ba5105115f8287c5546af1f0a05 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 22 Sep 2022 23:26:08 +0530 Subject: platform/x86/amd: pmc: remove CONFIG_DEBUG_FS checks Since linux/debugfs.h already has the stubs for the used debugfs functions when debugfs is not enabled, remove the #ifdef CONFIG_DEBUG_FS checks. Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220922175608.630046-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index e47e54b095af..047e47449ff9 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -153,9 +153,7 @@ struct amd_pmc_dev { struct device *dev; struct pci_dev *rdev; struct mutex lock; /* generic mutex lock */ -#if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *dbgfs_dir; -#endif /* CONFIG_DEBUG_FS */ }; static bool enable_stb; @@ -429,7 +427,6 @@ static struct attribute *pmc_attrs[] = { }; ATTRIBUTE_GROUPS(pmc); -#ifdef CONFIG_DEBUG_FS static int smu_fw_info_show(struct seq_file *s, void *unused) { struct amd_pmc_dev *dev = s->private; @@ -544,15 +541,6 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) &amd_pmc_stb_debugfs_fops); } } -#else -static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) -{ -} - -static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) -{ -} -#endif /* CONFIG_DEBUG_FS */ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) { -- cgit v1.2.3 From 4e3d731ba79e9d1bcbda668be7c3865dd02fddeb Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 27 Sep 2022 19:26:12 +0530 Subject: platform/x86/intel/wmi: thunderbolt: Use dev_groups callback Use .dev_groups callback instead of manual sysfs registration. Remove .probe and .remove callbacks as they become dummy after using .dev_groups. Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220927135612.1602491-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/wmi/thunderbolt.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/intel/wmi/thunderbolt.c b/drivers/platform/x86/intel/wmi/thunderbolt.c index 4ae87060d18b..fc333ff82d1e 100644 --- a/drivers/platform/x86/intel/wmi/thunderbolt.c +++ b/drivers/platform/x86/intel/wmi/thunderbolt.c @@ -51,26 +51,7 @@ static struct attribute *tbt_attrs[] = { &dev_attr_force_power.attr, NULL }; - -static const struct attribute_group tbt_attribute_group = { - .attrs = tbt_attrs, -}; - -static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev, - const void *context) -{ - int ret; - - ret = sysfs_create_group(&wdev->dev.kobj, &tbt_attribute_group); - kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE); - return ret; -} - -static void intel_wmi_thunderbolt_remove(struct wmi_device *wdev) -{ - sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group); - kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE); -} +ATTRIBUTE_GROUPS(tbt); static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = { { .guid_string = INTEL_WMI_THUNDERBOLT_GUID }, @@ -80,9 +61,8 @@ static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = { static struct wmi_driver intel_wmi_thunderbolt_driver = { .driver = { .name = "intel-wmi-thunderbolt", + .dev_groups = tbt_groups, }, - .probe = intel_wmi_thunderbolt_probe, - .remove = intel_wmi_thunderbolt_remove, .id_table = intel_wmi_thunderbolt_id_table, }; -- cgit v1.2.3 From c928df03bde92d70babeb22d500f528256758aee Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 29 Sep 2022 16:50:42 -0500 Subject: platform/x86/amd: pmc: Dump idle mask during "check" stage instead The idle mask is dumped during the "prepare" and "restore" stage right now, which helps to demonstrate issues only related to the first s2idle entry. If the system has entered s2idle once, but was woken up never breaking the s2idle loop but also never went back to sleep we might still have another issue to deal with however. Move the dynamic debugging message here so that we'll catch it on each iteration. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216516 Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220929215042.745-1-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 047e47449ff9..ce859b300712 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -719,8 +719,6 @@ static void amd_pmc_s2idle_prepare(void) } } - /* Dump the IdleMask before we send hint to SMU */ - amd_pmc_idlemask_read(pdev, pdev->dev, NULL); msg = amd_pmc_get_os_hint(pdev); rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0); if (rc) { @@ -738,6 +736,9 @@ static void amd_pmc_s2idle_check(void) struct amd_pmc_dev *pdev = &pmc; int rc; + /* Dump the IdleMask before we add to the STB */ + amd_pmc_idlemask_read(pdev, pdev->dev, NULL); + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_CHECK); if (rc) dev_err(pdev->dev, "error writing to STB: %d\n", rc); @@ -757,9 +758,6 @@ static void amd_pmc_s2idle_restore(void) /* Let SMU know that we are looking for stats */ amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0); - /* Dump the IdleMask to see the blockers */ - amd_pmc_idlemask_read(pdev, pdev->dev, NULL); - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_RESTORE); if (rc) dev_err(pdev->dev, "error writing to STB: %d\n", rc); -- cgit v1.2.3 From 8d05fc039456517d2c246c7b202891188ba40c4d Mon Sep 17 00:00:00 2001 From: Barnabás Pőcze Date: Fri, 30 Sep 2022 10:59:14 +0000 Subject: platform/x86: use PLATFORM_DEVID_NONE instead of -1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the `PLATFORM_DEVID_NONE` constant instead of hard-coding -1 when creating a platform device. No functional changes are intended. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20220930104857.2796923-1-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/acer-wmi.c | 2 +- drivers/platform/x86/acerhdf.c | 2 +- drivers/platform/x86/amd/hsmp.c | 2 +- drivers/platform/x86/amilo-rfkill.c | 3 ++- drivers/platform/x86/asus-laptop.c | 2 +- drivers/platform/x86/compal-laptop.c | 2 +- drivers/platform/x86/dell/alienware-wmi.c | 2 +- drivers/platform/x86/dell/dcdbas.c | 2 +- drivers/platform/x86/dell/dell-laptop.c | 2 +- drivers/platform/x86/dell/dell_rbu.c | 2 +- drivers/platform/x86/eeepc-laptop.c | 2 +- drivers/platform/x86/fujitsu-laptop.c | 2 +- drivers/platform/x86/hdaps.c | 2 +- drivers/platform/x86/hp-wmi.c | 2 +- drivers/platform/x86/huawei-wmi.c | 2 +- drivers/platform/x86/intel/oaktrail.c | 2 +- drivers/platform/x86/mlx-platform.c | 2 +- drivers/platform/x86/msi-laptop.c | 2 +- drivers/platform/x86/panasonic-laptop.c | 2 +- drivers/platform/x86/samsung-laptop.c | 2 +- drivers/platform/x86/sony-laptop.c | 2 +- drivers/platform/x86/tc1100-wmi.c | 2 +- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- drivers/platform/x86/topstar-laptop.c | 2 +- drivers/platform/x86/winmate-fm07-keys.c | 2 +- 25 files changed, 27 insertions(+), 26 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 9610742fe6aa..18224f9a5bc0 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -2463,7 +2463,7 @@ static int __init acer_wmi_init(void) goto error_platform_register; } - acer_platform_device = platform_device_alloc("acer-wmi", -1); + acer_platform_device = platform_device_alloc("acer-wmi", PLATFORM_DEVID_NONE); if (!acer_platform_device) { err = -ENOMEM; goto error_device_alloc; diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index 3463629f8764..d2c0fc38c201 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -676,7 +676,7 @@ static int __init acerhdf_register_platform(void) if (err) return err; - acerhdf_dev = platform_device_alloc("acerhdf", -1); + acerhdf_dev = platform_device_alloc("acerhdf", PLATFORM_DEVID_NONE); if (!acerhdf_dev) { err = -ENOMEM; goto err_device_alloc; diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c index a0c54b838c11..521c6a229362 100644 --- a/drivers/platform/x86/amd/hsmp.c +++ b/drivers/platform/x86/amd/hsmp.c @@ -392,7 +392,7 @@ static int __init hsmp_plt_init(void) if (ret) return ret; - amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, -1); + amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE); if (!amd_hsmp_platdev) { ret = -ENOMEM; goto drv_unregister; diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c index 493e169c8f61..3e313c4d538d 100644 --- a/drivers/platform/x86/amilo-rfkill.c +++ b/drivers/platform/x86/amilo-rfkill.c @@ -150,7 +150,8 @@ static int __init amilo_rfkill_init(void) if (rc) return rc; - amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, -1, + amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, + PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(amilo_rfkill_pdev)) { rc = PTR_ERR(amilo_rfkill_pdev); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 4d2d32bfbe2a..47b2f8bb6fb5 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1633,7 +1633,7 @@ static int asus_platform_init(struct asus_laptop *asus) { int result; - asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1); + asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, PLATFORM_DEVID_NONE); if (!asus->platform_device) return -ENOMEM; platform_set_drvdata(asus->platform_device, asus); diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 72e1523edd31..e10d2f64dfad 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -1060,7 +1060,7 @@ static int __init compal_init(void) if (ret) goto err_backlight; - compal_device = platform_device_alloc(DRIVER_NAME, -1); + compal_device = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE); if (!compal_device) { ret = -ENOMEM; goto err_platform_driver; diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c index f21248255529..a34e07ef2c79 100644 --- a/drivers/platform/x86/dell/alienware-wmi.c +++ b/drivers/platform/x86/dell/alienware-wmi.c @@ -791,7 +791,7 @@ static int __init alienware_wmi_init(void) ret = platform_driver_register(&platform_driver); if (ret) goto fail_platform_driver; - platform_device = platform_device_alloc("alienware-wmi", -1); + platform_device = platform_device_alloc("alienware-wmi", PLATFORM_DEVID_NONE); if (!platform_device) { ret = -ENOMEM; goto fail_platform_device1; diff --git a/drivers/platform/x86/dell/dcdbas.c b/drivers/platform/x86/dell/dcdbas.c index 42beafbc54b2..0ecb7b164750 100644 --- a/drivers/platform/x86/dell/dcdbas.c +++ b/drivers/platform/x86/dell/dcdbas.c @@ -716,7 +716,7 @@ static struct platform_driver dcdbas_driver = { static const struct platform_device_info dcdbas_dev_info __initconst = { .name = DRIVER_NAME, - .id = -1, + .id = PLATFORM_DEVID_NONE, .dma_mask = DMA_BIT_MASK(32), }; diff --git a/drivers/platform/x86/dell/dell-laptop.c b/drivers/platform/x86/dell/dell-laptop.c index 1321687d923e..e92c3ad06d69 100644 --- a/drivers/platform/x86/dell/dell-laptop.c +++ b/drivers/platform/x86/dell/dell-laptop.c @@ -2193,7 +2193,7 @@ static int __init dell_init(void) ret = platform_driver_register(&platform_driver); if (ret) goto fail_platform_driver; - platform_device = platform_device_alloc("dell-laptop", -1); + platform_device = platform_device_alloc("dell-laptop", PLATFORM_DEVID_NONE); if (!platform_device) { ret = -ENOMEM; goto fail_platform_device1; diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c index e9f4b30dcafa..9f51e0fcab04 100644 --- a/drivers/platform/x86/dell/dell_rbu.c +++ b/drivers/platform/x86/dell/dell_rbu.c @@ -645,7 +645,7 @@ static int __init dcdrbu_init(void) spin_lock_init(&rbu_data.lock); init_packet_head(); - rbu_device = platform_device_register_simple("dell_rbu", -1, NULL, 0); + rbu_device = platform_device_register_simple("dell_rbu", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(rbu_device)) { pr_err("platform_device_register_simple failed\n"); return PTR_ERR(rbu_device); diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index ba08c9235f76..a388a28b6f2a 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -444,7 +444,7 @@ static int eeepc_platform_init(struct eeepc_laptop *eeepc) { int result; - eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1); + eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, PLATFORM_DEVID_NONE); if (!eeepc->platform_device) return -ENOMEM; platform_set_drvdata(eeepc->platform_device, eeepc); diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 80929380ec7e..b543d117b12c 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -543,7 +543,7 @@ static int fujitsu_laptop_platform_add(struct acpi_device *device) struct fujitsu_laptop *priv = acpi_driver_data(device); int ret; - priv->pf_device = platform_device_alloc("fujitsu-laptop", -1); + priv->pf_device = platform_device_alloc("fujitsu-laptop", PLATFORM_DEVID_NONE); if (!priv->pf_device) return -ENOMEM; diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c index 9996485f5295..f11f726d2062 100644 --- a/drivers/platform/x86/hdaps.c +++ b/drivers/platform/x86/hdaps.c @@ -547,7 +547,7 @@ static int __init hdaps_init(void) if (ret) goto out_region; - pdev = platform_device_register_simple("hdaps", -1, NULL, 0); + pdev = platform_device_register_simple("hdaps", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(pdev)) { ret = PTR_ERR(pdev); goto out_driver; diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index da0d25c67e57..627a6d0eaf83 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -1519,7 +1519,7 @@ static int __init hp_wmi_init(void) if (bios_capable) { hp_wmi_platform_dev = - platform_device_register_simple("hp-wmi", -1, NULL, 0); + platform_device_register_simple("hp-wmi", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(hp_wmi_platform_dev)) { err = PTR_ERR(hp_wmi_platform_dev); goto err_destroy_input; diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index eac3e6b4ea11..5873c2663a65 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -871,7 +871,7 @@ static __init int huawei_wmi_init(void) if (err) goto pdrv_err; - pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0); + pdev = platform_device_register_simple("huawei-wmi", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(pdev)) { err = PTR_ERR(pdev); goto pdev_err; diff --git a/drivers/platform/x86/intel/oaktrail.c b/drivers/platform/x86/intel/oaktrail.c index 1a09a75bd16d..7c5c623630c1 100644 --- a/drivers/platform/x86/intel/oaktrail.c +++ b/drivers/platform/x86/intel/oaktrail.c @@ -317,7 +317,7 @@ static int __init oaktrail_init(void) goto err_driver_reg; } - oaktrail_device = platform_device_alloc(DRIVER_NAME, -1); + oaktrail_device = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE); if (!oaktrail_device) { pr_warn("Unable to allocate platform device\n"); ret = -ENOMEM; diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 5e072a0666f4..2fac05a17a5c 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -5181,7 +5181,7 @@ static int __init mlxplat_init(void) if (!dmi_check_system(mlxplat_dmi_table)) return -ENODEV; - mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1, + mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE, mlxplat_lpc_resources, ARRAY_SIZE(mlxplat_lpc_resources)); diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 2f850396e9a7..6b18ec543ac3 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -1066,7 +1066,7 @@ static int __init msi_init(void) /* Register platform stuff */ - msipf_device = platform_device_alloc("msi-laptop-pf", -1); + msipf_device = platform_device_alloc("msi-laptop-pf", PLATFORM_DEVID_NONE); if (!msipf_device) { ret = -ENOMEM; goto fail_platform_driver; diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index d9a095d2c0eb..ad3083f9946d 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -1034,7 +1034,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) /* optical drive initialization */ if (ACPI_SUCCESS(check_optd_present())) { pcc->platform = platform_device_register_simple("panasonic", - -1, NULL, 0); + PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(pcc->platform)) { result = PTR_ERR(pcc->platform); goto out_backlight; diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index cc30cf08f32d..b4aa8ba35d2d 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1474,7 +1474,7 @@ static int __init samsung_platform_init(struct samsung_laptop *samsung) { struct platform_device *pdev; - pdev = platform_device_register_simple("samsung", -1, NULL, 0); + pdev = platform_device_register_simple("samsung", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(pdev)) return PTR_ERR(pdev); diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 07ef05f727a2..765fcaba4d12 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -584,7 +584,7 @@ static int sony_pf_add(void) if (ret) goto out; - sony_pf_device = platform_device_alloc("sony-laptop", -1); + sony_pf_device = platform_device_alloc("sony-laptop", PLATFORM_DEVID_NONE); if (!sony_pf_device) { ret = -ENOMEM; goto out_platform_registered; diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c index 9072eb302618..ded26213c420 100644 --- a/drivers/platform/x86/tc1100-wmi.c +++ b/drivers/platform/x86/tc1100-wmi.c @@ -233,7 +233,7 @@ static int __init tc1100_init(void) if (!wmi_has_guid(GUID)) return -ENODEV; - tc1100_device = platform_device_alloc("tc1100-wmi", -1); + tc1100_device = platform_device_alloc("tc1100-wmi", PLATFORM_DEVID_NONE); if (!tc1100_device) return -ENOMEM; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 8fbe21ebcc52..6a823b850a77 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -11715,7 +11715,7 @@ static int __init thinkpad_acpi_module_init(void) tp_features.quirks = dmi_id->driver_data; /* Device initialization */ - tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1, + tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(tpacpi_pdev)) { ret = PTR_ERR(tpacpi_pdev); @@ -11726,7 +11726,7 @@ static int __init thinkpad_acpi_module_init(void) } tpacpi_sensors_pdev = platform_device_register_simple( TPACPI_HWMON_DRVR_NAME, - -1, NULL, 0); + PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(tpacpi_sensors_pdev)) { ret = PTR_ERR(tpacpi_sensors_pdev); tpacpi_sensors_pdev = NULL; diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c index f7761d98c0fd..6d18fbf8762b 100644 --- a/drivers/platform/x86/topstar-laptop.c +++ b/drivers/platform/x86/topstar-laptop.c @@ -192,7 +192,7 @@ static int topstar_platform_init(struct topstar_laptop *topstar) { int err; - topstar->platform = platform_device_alloc(TOPSTAR_LAPTOP_CLASS, -1); + topstar->platform = platform_device_alloc(TOPSTAR_LAPTOP_CLASS, PLATFORM_DEVID_NONE); if (!topstar->platform) return -ENOMEM; diff --git a/drivers/platform/x86/winmate-fm07-keys.c b/drivers/platform/x86/winmate-fm07-keys.c index 2c90c5c7eca2..465ffad81a65 100644 --- a/drivers/platform/x86/winmate-fm07-keys.c +++ b/drivers/platform/x86/winmate-fm07-keys.c @@ -161,7 +161,7 @@ static int __init fm07keys_init(void) return ret; } - dev = platform_device_register_simple(DRV_NAME, -1, NULL, 0); + dev = platform_device_register_simple(DRV_NAME, PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(dev)) { ret = PTR_ERR(dev); pr_err("fm07keys: failed to allocate device, err = %d\n", ret); -- cgit v1.2.3