Re: [PATCH v2] platform/x86: lg-laptop: Add operation region support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Armin,

On 8/26/24 10:09 PM, Armin Wolf wrote:
> Am 19.08.24 um 13:37 schrieb Hans de Goede:
> 
>> Hi,
>>
>> On 8/13/24 4:29 AM, Armin Wolf wrote:
>>> The LEGX0820 ACPI device is expected to provide a custom operation
>>> region:
>>>
>>>     OperationRegion (XIN1, 0x8F, Zero, 0x04B0)
>>>          Field (XIN1, AnyAcc, Lock, Preserve)
>>>          {
>>>              DMSG,   8,
>>>              HDAP,   8,
>>>              Offset (0x03),
>>>              AFNM,   8,
>>>              Offset (0x10),
>>>              P80B,   8,
>>>              P81B,   8,
>>>              P82B,   8,
>>>              P83B,   8,
>>>              P84B,   8,
>>>              P85B,   8,
>>>              P86B,   8,
>>>              P87B,   8,
>>>              Offset (0x20),
>>>              DTTM,   8,
>>>              TMP1,   8,
>>>              LTP1,   8,
>>>              HTP1,   8,
>>>              TMP2,   8,
>>>              LTP2,   8,
>>>              HTP2,   8,
>>>              Offset (0x3E8),
>>>              PMSG,   1600
>>>          }
>>>
>>> The PMSG field is used by AML code to log debug messages when DMSG is
>>> true. Since those debug messages are already logged using the standard
>>> ACPI Debug object, we set DMSG unconditionally to 0x00 and ignore any
>>> writes to PMSG.
>>>
>>> The TMPx, LTPx, HTPx and AFNM fields are used to inform the driver when
>>> the temperature/(presumably) trip points/fan mode changes. This only
>>> happens when the DTTM flag is set.
>>>
>>> Unfortunately we have to implement support for this operation region
>>> because the AML codes uses code constructs like this one:
>>>
>>>     If (((\_SB.XINI.PLAV != Zero) && (\_SB.XINI.DTTM != Zero)))
>>>
>>> The PLAV field gets set to 1 when the driver registers its address space
>>> handler, so by default XIN1 should not be accessed.
>>>
>>> However ACPI does not use short-circuit evaluation when evaluating
>>> logical conditions. This causes the DTTM field to be accessed even
>>> when PLAV is 0, which results in an ACPI error.
>>> Since this check happens inside various thermal-related ACPI control
>>> methods, various thermal zone become unusable since any attempt to
>>> read their temperature results in an ACPI error.
>>>
>>> Fix this by providing support for this operation region. I suspect
>>> that the problem does not happen under Windows (which seemingly does
>>> not use short-circuit evaluation either) because the necessary driver
>>> comes preinstalled with the machine.
>>>
>>> Tested-by: Chris <ghostwind@xxxxxxxxx>
>>> Signed-off-by: Armin Wolf <W_Armin@xxxxxx>
>> Thanks, patch looks good to me:
>>
>> Reviewed-by: Hans de Goede <hdegoede@xxxxxxxxxx>
>>
>> Regards,
>>
>> Hans
>>
> Any updates on this? I would prefer to have this merged for the upcoming 6.12 kernel since
> without this patch many LG notebooks have unusable thermal zones.

This patch has already been merged and already is in linux-next,
but I see that I forgot to send my usual email confirming that
I merged it, sorry.

Regards,

Hans




>>> ---
>>> Changes since v1:
>>>   - attempts -> attempt
>>>   - sort defines in numerical order
>>>   - make lg_laptop_address_space_write() take a plain u64
>>>   - use BITS_PER_BYTE
>>>   - manually check fw_debug when handling fan mode updates
>>> ---
>>>   drivers/platform/x86/lg-laptop.c | 136 +++++++++++++++++++++++++++++++
>>>   1 file changed, 136 insertions(+)
>>>
>>> diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
>>> index 9c7857842caf..55d31d4fefd6 100644
>>> --- a/drivers/platform/x86/lg-laptop.c
>>> +++ b/drivers/platform/x86/lg-laptop.c
>>> @@ -8,6 +8,9 @@
>>>   #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>>
>>>   #include <linux/acpi.h>
>>> +#include <linux/bits.h>
>>> +#include <linux/device.h>
>>> +#include <linux/dev_printk.h>
>>>   #include <linux/dmi.h>
>>>   #include <linux/input.h>
>>>   #include <linux/input/sparse-keymap.h>
>>> @@ -31,6 +34,26 @@ MODULE_AUTHOR("Matan Ziv-Av");
>>>   MODULE_DESCRIPTION("LG WMI Hotkey Driver");
>>>   MODULE_LICENSE("GPL");
>>>
>>> +static bool fw_debug;
>>> +module_param(fw_debug, bool, 0);
>>> +MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages");
>>> +
>>> +#define LG_ADDRESS_SPACE_ID            0x8F
>>> +
>>> +#define LG_ADDRESS_SPACE_DEBUG_FLAG_ADR        0x00
>>> +#define LG_ADDRESS_SPACE_FAN_MODE_ADR        0x03
>>> +
>>> +#define LG_ADDRESS_SPACE_DTTM_FLAG_ADR        0x20
>>> +#define LG_ADDRESS_SPACE_CPU_TEMP_ADR        0x21
>>> +#define LG_ADDRESS_SPACE_CPU_TRIP_LOW_ADR    0x22
>>> +#define LG_ADDRESS_SPACE_CPU_TRIP_HIGH_ADR    0x23
>>> +#define LG_ADDRESS_SPACE_MB_TEMP_ADR        0x24
>>> +#define LG_ADDRESS_SPACE_MB_TRIP_LOW_ADR    0x25
>>> +#define LG_ADDRESS_SPACE_MB_TRIP_HIGH_ADR    0x26
>>> +
>>> +#define LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR    0x3E8
>>> +#define LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR    0x5E8
>>> +
>>>   #define WMI_EVENT_GUID0    "E4FB94F9-7F2B-4173-AD1A-CD1D95086248"
>>>   #define WMI_EVENT_GUID1    "023B133E-49D1-4E10-B313-698220140DC2"
>>>   #define WMI_EVENT_GUID2    "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6"
>>> @@ -646,6 +669,107 @@ static struct platform_driver pf_driver = {
>>>       }
>>>   };
>>>
>>> +static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physical_address address,
>>> +                         size_t size, u64 value)
>>> +{
>>> +    u8 byte;
>>> +
>>> +    /* Ignore any debug messages */
>>> +    if (address >= LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR &&
>>> +        address <= LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR)
>>> +        return AE_OK;
>>> +
>>> +    if (size != sizeof(byte))
>>> +        return AE_BAD_PARAMETER;
>>> +
>>> +    byte = value & 0xFF;
>>> +
>>> +    switch (address) {
>>> +    case LG_ADDRESS_SPACE_FAN_MODE_ADR:
>>> +        /*
>>> +         * The fan mode field is not affected by the DTTM flag, so we
>>> +         * have to manually check fw_debug.
>>> +         */
>>> +        if (fw_debug)
>>> +            dev_dbg(dev, "Fan mode set to mode %u\n", byte);
>>> +
>>> +        return AE_OK;
>>> +    case LG_ADDRESS_SPACE_CPU_TEMP_ADR:
>>> +        dev_dbg(dev, "CPU temperature is %u °C\n", byte);
>>> +        return AE_OK;
>>> +    case LG_ADDRESS_SPACE_CPU_TRIP_LOW_ADR:
>>> +        dev_dbg(dev, "CPU lower trip point set to %u °C\n", byte);
>>> +        return AE_OK;
>>> +    case LG_ADDRESS_SPACE_CPU_TRIP_HIGH_ADR:
>>> +        dev_dbg(dev, "CPU higher trip point set to %u °C\n", byte);
>>> +        return AE_OK;
>>> +    case LG_ADDRESS_SPACE_MB_TEMP_ADR:
>>> +        dev_dbg(dev, "Motherboard temperature is %u °C\n", byte);
>>> +        return AE_OK;
>>> +    case LG_ADDRESS_SPACE_MB_TRIP_LOW_ADR:
>>> +        dev_dbg(dev, "Motherboard lower trip point set to %u °C\n", byte);
>>> +        return AE_OK;
>>> +    case LG_ADDRESS_SPACE_MB_TRIP_HIGH_ADR:
>>> +        dev_dbg(dev, "Motherboard higher trip point set to %u °C\n", byte);
>>> +        return AE_OK;
>>> +    default:
>>> +        dev_notice_ratelimited(dev, "Ignoring write to unknown opregion address %llu\n",
>>> +                       address);
>>> +        return AE_OK;
>>> +    }
>>> +}
>>> +
>>> +static acpi_status lg_laptop_address_space_read(struct device *dev, acpi_physical_address address,
>>> +                        size_t size, u64 *value)
>>> +{
>>> +    if (size != 1)
>>> +        return AE_BAD_PARAMETER;
>>> +
>>> +    switch (address) {
>>> +    case LG_ADDRESS_SPACE_DEBUG_FLAG_ADR:
>>> +        /* Debug messages are already printed using the standard ACPI Debug object */
>>> +        *value = 0x00;
>>> +        return AE_OK;
>>> +    case LG_ADDRESS_SPACE_DTTM_FLAG_ADR:
>>> +        *value = fw_debug;
>>> +        return AE_OK;
>>> +    default:
>>> +        dev_notice_ratelimited(dev, "Attempt to read unknown opregion address %llu\n",
>>> +                       address);
>>> +        return AE_BAD_PARAMETER;
>>> +    }
>>> +}
>>> +
>>> +static acpi_status lg_laptop_address_space_handler(u32 function, acpi_physical_address address,
>>> +                           u32 bits, u64 *value, void *handler_context,
>>> +                           void *region_context)
>>> +{
>>> +    struct device *dev = handler_context;
>>> +    size_t size;
>>> +
>>> +    if (bits % BITS_PER_BYTE)
>>> +        return AE_BAD_PARAMETER;
>>> +
>>> +    size = bits / BITS_PER_BYTE;
>>> +
>>> +    switch (function) {
>>> +    case ACPI_READ:
>>> +        return lg_laptop_address_space_read(dev, address, size, value);
>>> +    case ACPI_WRITE:
>>> +        return lg_laptop_address_space_write(dev, address, size, *value);
>>> +    default:
>>> +        return AE_BAD_PARAMETER;
>>> +    }
>>> +}
>>> +
>>> +static void lg_laptop_remove_address_space_handler(void *data)
>>> +{
>>> +    struct acpi_device *device = data;
>>> +
>>> +    acpi_remove_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID,
>>> +                      &lg_laptop_address_space_handler);
>>> +}
>>> +
>>>   static int acpi_add(struct acpi_device *device)
>>>   {
>>>       struct platform_device_info pdev_info = {
>>> @@ -653,6 +777,7 @@ static int acpi_add(struct acpi_device *device)
>>>           .name = PLATFORM_NAME,
>>>           .id = PLATFORM_DEVID_NONE,
>>>       };
>>> +    acpi_status status;
>>>       int ret;
>>>       const char *product;
>>>       int year = 2017;
>>> @@ -660,6 +785,17 @@ static int acpi_add(struct acpi_device *device)
>>>       if (pf_device)
>>>           return 0;
>>>
>>> +    status = acpi_install_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID,
>>> +                            &lg_laptop_address_space_handler,
>>> +                            NULL, &device->dev);
>>> +    if (ACPI_FAILURE(status))
>>> +        return -ENODEV;
>>> +
>>> +    ret = devm_add_action_or_reset(&device->dev, lg_laptop_remove_address_space_handler,
>>> +                       device);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>>       ret = platform_driver_register(&pf_driver);
>>>       if (ret)
>>>           return ret;
>>> -- 
>>> 2.39.2
>>>
>>
> 





[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux