From 4c51ba9af42dff0ef6a2ca3edcefa76f3466959e Mon Sep 17 00:00:00 2001 From: Enver Balalic Date: Thu, 2 Sep 2021 20:22:34 +0200 Subject: [PATCH 001/106] platform/x86: hp-wmi: add support for omen laptops This patch adds support for HP Omen laptops. It adds support for most things that can be controlled via the Windows Omen Command Center application. - Fan speed monitoring through hwmon - Platform Profile support (cool, balanced, performance) - Max fan speed function toggle Also exposes the existing HDD temperature through hwmon since this driver didn't use hwmon before this patch. This patch has been tested on a 2020 HP Omen 15 (AMD) 15-en0023dx. - V1 Initial Patch - V2 Use standard hwmon ABI attributes Add existing non-standard "hddtemp" to hwmon - V3 Fix overflow issue in "hp_wmi_get_fan_speed" Map max fan speed value back to hwmon values on read Code style fixes Fix issue with returning values from "hp_wmi_hwmon_read", the value to return should be written to val and not just returned from the function - V4 Use DMI Board names to detect if a device should use the omen specific thermal profile method. Select HWMON instead of depending on it. Code style fixes. Replace some error codes with more specific/meaningful ones. Remove the HDD temperature from HWMON since we don't know what unit it's expressed in. Handle error from hp_wmi_hwmon_init - V5 Handle possible NULL from dmi_get_system_info() Use match_string function instead of manually checking Directly use is_omen_thermal_profile() without the static variable. Signed-off-by: Enver Balalic Acked-by: Guenter Roeck Link: https://lore.kernel.org/r/20210902182234.vtwl72n5rjql22qa@omen.localdomain Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/hp-wmi.c | 329 ++++++++++++++++++++++++++++++++-- 2 files changed, 318 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e21ea3d23e6f..1ebce7b775f2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -426,6 +426,7 @@ config HP_WMI depends on RFKILL || RFKILL = n select INPUT_SPARSEKMAP select ACPI_PLATFORM_PROFILE + select HWMON help Say Y here if you want to support WMI-based hotkeys on HP laptops and to read data from WMI such as docking or ambient light sensor state. diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 027a1467d009..8e31ffadf894 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -22,9 +22,11 @@ #include #include #include +#include #include #include #include +#include MODULE_AUTHOR("Matthew Garrett "); MODULE_DESCRIPTION("HP laptop WMI hotkeys driver"); @@ -39,6 +41,25 @@ MODULE_PARM_DESC(enable_tablet_mode_sw, "Enable SW_TABLET_MODE reporting (-1=aut #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4" +#define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95 + +/* DMI board names of devices that should use the omen specific path for + * thermal profiles. + * This was obtained by taking a look in the windows omen command center + * app and parsing a json file that they use to figure out what capabilities + * the device should have. + * A device is considered an omen if the DisplayName in that list contains + * "OMEN", and it can use the thermal profile stuff if the "Feature" array + * contains "PerformanceControl". + */ +static const char * const omen_thermal_profile_boards[] = { + "84DA", "84DB", "84DC", "8574", "8575", "860A", "87B5", "8572", "8573", + "8600", "8601", "8602", "8605", "8606", "8607", "8746", "8747", "8749", + "874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C", + "88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD", + "88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912", + "8917", "8918", "8949", "894A", "89EB" +}; enum hp_wmi_radio { HPWMI_WIFI = 0x0, @@ -89,10 +110,18 @@ enum hp_wmi_commandtype { HPWMI_THERMAL_PROFILE_QUERY = 0x4c, }; +enum hp_wmi_gm_commandtype { + HPWMI_FAN_SPEED_GET_QUERY = 0x11, + HPWMI_SET_PERFORMANCE_MODE = 0x1A, + HPWMI_FAN_SPEED_MAX_GET_QUERY = 0x26, + HPWMI_FAN_SPEED_MAX_SET_QUERY = 0x27, +}; + enum hp_wmi_command { HPWMI_READ = 0x01, HPWMI_WRITE = 0x02, HPWMI_ODM = 0x03, + HPWMI_GM = 0x20008, }; enum hp_wmi_hardware_mask { @@ -120,6 +149,12 @@ enum hp_wireless2_bits { HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, }; +enum hp_thermal_profile_omen { + HP_OMEN_THERMAL_PROFILE_DEFAULT = 0x00, + HP_OMEN_THERMAL_PROFILE_PERFORMANCE = 0x01, + HP_OMEN_THERMAL_PROFILE_COOL = 0x02, +}; + enum hp_thermal_profile { HP_THERMAL_PROFILE_PERFORMANCE = 0x00, HP_THERMAL_PROFILE_DEFAULT = 0x01, @@ -279,6 +314,24 @@ out_free: return ret; } +static int hp_wmi_get_fan_speed(int fan) +{ + u8 fsh, fsl; + char fan_data[4] = { fan, 0, 0, 0 }; + + int ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_GET_QUERY, HPWMI_GM, + &fan_data, sizeof(fan_data), + sizeof(fan_data)); + + if (ret != 0) + return -EINVAL; + + fsh = fan_data[2]; + fsl = fan_data[3]; + + return (fsh << 8) | fsl; +} + static int hp_wmi_read_int(int query) { int val = 0, ret; @@ -302,6 +355,73 @@ static int hp_wmi_hw_state(int mask) return !!(state & mask); } +static int omen_thermal_profile_set(int mode) +{ + char buffer[2] = {0, mode}; + int ret; + + if (mode < 0 || mode > 2) + return -EINVAL; + + ret = hp_wmi_perform_query(HPWMI_SET_PERFORMANCE_MODE, HPWMI_GM, + &buffer, sizeof(buffer), sizeof(buffer)); + + if (ret) + return ret < 0 ? ret : -EINVAL; + + return mode; +} + +static bool is_omen_thermal_profile(void) +{ + const char *board_name = dmi_get_system_info(DMI_BOARD_NAME); + + if (!board_name) + return false; + + return match_string(omen_thermal_profile_boards, + ARRAY_SIZE(omen_thermal_profile_boards), + board_name) >= 0; +} + +static int omen_thermal_profile_get(void) +{ + u8 data; + + int ret = ec_read(HP_OMEN_EC_THERMAL_PROFILE_OFFSET, &data); + + if (ret) + return ret; + + return data; +} + +static int hp_wmi_fan_speed_max_set(int enabled) +{ + int ret; + + ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_SET_QUERY, HPWMI_GM, + &enabled, sizeof(enabled), sizeof(enabled)); + + if (ret) + return ret < 0 ? ret : -EINVAL; + + return enabled; +} + +static int hp_wmi_fan_speed_max_get(void) +{ + int val = 0, ret; + + ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_GET_QUERY, HPWMI_GM, + &val, sizeof(val), sizeof(val)); + + if (ret) + return ret < 0 ? ret : -EINVAL; + + return val; +} + static int __init hp_wmi_bios_2008_later(void) { int state = 0; @@ -878,6 +998,58 @@ fail: return err; } +static int platform_profile_omen_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) +{ + int tp; + + tp = omen_thermal_profile_get(); + if (tp < 0) + return tp; + + switch (tp) { + case HP_OMEN_THERMAL_PROFILE_PERFORMANCE: + *profile = PLATFORM_PROFILE_PERFORMANCE; + break; + case HP_OMEN_THERMAL_PROFILE_DEFAULT: + *profile = PLATFORM_PROFILE_BALANCED; + break; + case HP_OMEN_THERMAL_PROFILE_COOL: + *profile = PLATFORM_PROFILE_COOL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int platform_profile_omen_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) +{ + int err, tp; + + switch (profile) { + case PLATFORM_PROFILE_PERFORMANCE: + tp = HP_OMEN_THERMAL_PROFILE_PERFORMANCE; + break; + case PLATFORM_PROFILE_BALANCED: + tp = HP_OMEN_THERMAL_PROFILE_DEFAULT; + break; + case PLATFORM_PROFILE_COOL: + tp = HP_OMEN_THERMAL_PROFILE_COOL; + break; + default: + return -EOPNOTSUPP; + } + + err = omen_thermal_profile_set(tp); + if (err < 0) + return err; + + return 0; +} + static int thermal_profile_get(void) { return hp_wmi_read_int(HPWMI_THERMAL_PROFILE_QUERY); @@ -945,20 +1117,39 @@ static int thermal_profile_setup(void) { int err, tp; - tp = thermal_profile_get(); - if (tp < 0) - return tp; + if (is_omen_thermal_profile()) { + tp = omen_thermal_profile_get(); + if (tp < 0) + return tp; - /* - * call thermal profile write command to ensure that the firmware correctly - * sets the OEM variables for the DPTF - */ - err = thermal_profile_set(tp); - if (err) - return err; + /* + * call thermal profile write command to ensure that the + * firmware correctly sets the OEM variables + */ - platform_profile_handler.profile_get = platform_profile_get, - platform_profile_handler.profile_set = platform_profile_set, + err = omen_thermal_profile_set(tp); + if (err < 0) + return err; + + platform_profile_handler.profile_get = platform_profile_omen_get; + platform_profile_handler.profile_set = platform_profile_omen_set; + } else { + tp = thermal_profile_get(); + + if (tp < 0) + return tp; + + /* + * call thermal profile write command to ensure that the + * firmware correctly sets the OEM variables for the DPTF + */ + err = thermal_profile_set(tp); + if (err) + return err; + + platform_profile_handler.profile_get = platform_profile_get; + platform_profile_handler.profile_set = platform_profile_set; + } set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices); set_bit(PLATFORM_PROFILE_BALANCED, platform_profile_handler.choices); @@ -973,8 +1164,11 @@ static int thermal_profile_setup(void) return 0; } +static int hp_wmi_hwmon_init(void); + static int __init hp_wmi_bios_setup(struct platform_device *device) { + int err; /* clear detected rfkill devices */ wifi_rfkill = NULL; bluetooth_rfkill = NULL; @@ -984,6 +1178,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) if (hp_wmi_rfkill_setup(device)) hp_wmi_rfkill2_setup(device); + err = hp_wmi_hwmon_init(); + + if (err < 0) + return err; + thermal_profile_setup(); return 0; @@ -1068,6 +1267,112 @@ static struct platform_driver hp_wmi_driver = { .remove = __exit_p(hp_wmi_bios_remove), }; +static umode_t hp_wmi_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_pwm: + return 0644; + case hwmon_fan: + if (hp_wmi_get_fan_speed(channel) >= 0) + return 0444; + break; + default: + return 0; + } + + return 0; +} + +static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + int ret; + + switch (type) { + case hwmon_fan: + ret = hp_wmi_get_fan_speed(channel); + + if (ret < 0) + return ret; + *val = ret; + return 0; + case hwmon_pwm: + switch (hp_wmi_fan_speed_max_get()) { + case 0: + /* 0 is automatic fan, which is 2 for hwmon */ + *val = 2; + return 0; + case 1: + /* 1 is max fan, which is 0 + * (no fan speed control) for hwmon + */ + *val = 0; + return 0; + default: + /* shouldn't happen */ + return -ENODATA; + } + default: + return -EINVAL; + } +} + +static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_pwm: + switch (val) { + case 0: + /* 0 is no fan speed control (max), which is 1 for us */ + return hp_wmi_fan_speed_max_set(1); + case 2: + /* 2 is automatic speed control, which is 0 for us */ + return hp_wmi_fan_speed_max_set(0); + default: + /* we don't support manual fan speed control */ + return -EINVAL; + } + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info *info[] = { + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT), + HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE), + NULL +}; + +static const struct hwmon_ops ops = { + .is_visible = hp_wmi_hwmon_is_visible, + .read = hp_wmi_hwmon_read, + .write = hp_wmi_hwmon_write, +}; + +static const struct hwmon_chip_info chip_info = { + .ops = &ops, + .info = info, +}; + +static int hp_wmi_hwmon_init(void) +{ + struct device *dev = &hp_wmi_platform_dev->dev; + struct device *hwmon; + + hwmon = devm_hwmon_device_register_with_info(dev, "hp", &hp_wmi_driver, + &chip_info, NULL); + + if (IS_ERR(hwmon)) { + dev_err(dev, "Could not register hp hwmon device\n"); + return PTR_ERR(hwmon); + } + + return 0; +} + static int __init hp_wmi_init(void) { int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); From ad62cd93198bde6644ecb5ff8f6f4c5394b5821a Mon Sep 17 00:00:00 2001 From: Daniel Dadap Date: Thu, 2 Sep 2021 19:38:39 -0500 Subject: [PATCH 002/106] platform/x86: Add driver for ACPI WMAA EC-based backlight control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A number of upcoming notebook computer designs drive the internal display panel's backlight PWM through the Embedded Controller (EC). This EC-based backlight control can be plumbed through to an ACPI "WMAA" method interface, which in turn can be wrapped by WMI with the GUID handle 603E9613-EF25-4338-A3D0-C46177516DB7. Add a new driver, aliased to the WMAA WMI GUID, to expose a sysfs backlight class driver to control backlight levels on systems with EC-driven backlights. Signed-off-by: Daniel Dadap Reviewed-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20210903003838.15797-1-ddadap@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 16 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/wmaa-backlight-wmi.c | 205 ++++++++++++++++++++++ 4 files changed, 228 insertions(+) create mode 100644 drivers/platform/x86/wmaa-backlight-wmi.c diff --git a/MAINTAINERS b/MAINTAINERS index eeb4c70b3d5b..72837339b3ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20246,6 +20246,12 @@ L: linux-wireless@vger.kernel.org S: Odd fixes F: drivers/net/wireless/wl3501* +WMAA BACKLIGHT DRIVER +M: Daniel Dadap +L: platform-driver-x86@vger.kernel.org +S: Supported +F: drivers/platform/x86/wmaa-backlight-wmi.c + WOLFSON MICROELECTRONICS DRIVERS L: patches@opensource.cirrus.com S: Supported diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 1ebce7b775f2..f3dbb0273884 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -91,6 +91,22 @@ config PEAQ_WMI help Say Y here if you want to support WMI-based hotkeys on PEAQ 2-in-1s. +config WMAA_BACKLIGHT_WMI + tristate "ACPI WMAA Backlight Driver" + depends on ACPI_WMI + depends on BACKLIGHT_CLASS_DEVICE + help + This driver provides a sysfs backlight interface for notebook + systems which expose the WMAA ACPI method and an associated WMI + wrapper to drive LCD backlight levels through the Embedded Controller + (EC). + + Say Y or M here if you want to control the backlight on a notebook + system with an EC-driven backlight using the ACPI WMAA method. + + If you choose to compile this driver as a module the module will be + called wmaa-backlight-wmi. + config XIAOMI_WMI tristate "Xiaomi WMI key driver" depends on ACPI_WMI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 69690e26bb6d..edde481c14ad 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o obj-$(CONFIG_MXM_WMI) += mxm-wmi.o obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o +obj-$(CONFIG_WMAA_BACKLIGHT_WMI) += wmaa-backlight-wmi.o obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o diff --git a/drivers/platform/x86/wmaa-backlight-wmi.c b/drivers/platform/x86/wmaa-backlight-wmi.c new file mode 100644 index 000000000000..f5c4f8337c2c --- /dev/null +++ b/drivers/platform/x86/wmaa-backlight-wmi.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +/** + * enum wmaa_method - WMI method IDs for ACPI WMAA + * @WMAA_METHOD_LEVEL: Get or set the brightness level, + * or get the maximum brightness level. + * @WMAA_METHOD_SOURCE: Get the source for backlight control. + */ +enum wmaa_method { + WMAA_METHOD_LEVEL = 1, + WMAA_METHOD_SOURCE = 2, + WMAA_METHOD_MAX +}; + +/** + * enum wmaa_mode - Operation mode for ACPI WMAA method + * @WMAA_MODE_GET: Get the current brightness level or source. + * @WMAA_MODE_SET: Set the brightness level. + * @WMAA_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This is only + * valid when the WMI method is %WMAA_METHOD_LEVEL. + */ +enum wmaa_mode { + WMAA_MODE_GET = 0, + WMAA_MODE_SET = 1, + WMAA_MODE_GET_MAX_LEVEL = 2, + WMAA_MODE_MAX +}; + +/** + * enum wmaa_source - Backlight brightness control source identification + * @WMAA_SOURCE_GPU: Backlight brightness is controlled by the GPU. + * @WMAA_SOURCE_EC: Backlight brightness is controlled by the system's + * Embedded Controller (EC). + * @WMAA_SOURCE_AUX: Backlight brightness is controlled over the DisplayPort + * AUX channel. + */ +enum wmaa_source { + WMAA_SOURCE_GPU = 1, + WMAA_SOURCE_EC = 2, + WMAA_SOURCE_AUX = 3, + WMAA_SOURCE_MAX +}; + +/** + * struct wmaa_args - arguments for the ACPI WMAA method + * @mode: Pass in an &enum wmaa_mode value to select between getting or + * setting a value. + * @val: In parameter for value to set when operating in %WMAA_MODE_SET + * mode. Not used in %WMAA_MODE_GET or %WMAA_MODE_GET_MAX_LEVEL mode. + * @ret: Out parameter returning retrieved value when operating in + * %WMAA_MODE_GET or %WMAA_MODE_GET_MAX_LEVEL mode. Not used in + * %WMAA_MODE_SET mode. + * @ignored: Padding; not used. The ACPI method expects a 24 byte params struct. + * + * This is the parameters structure for the ACPI WMAA 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 %WMAA_METHOD_LEVEL, or an &enum wmaa_source value + * when the WMI method ID is %WMAA_METHOD_SOURCE. + */ +struct wmaa_args { + u32 mode; + u32 val; + u32 ret; + u32 ignored[3]; +}; + +/** + * wmi_call_wmaa() - helper function for calling ACPI WMAA via its WMI wrapper + * @w: Pointer to the struct wmi_device identified by %WMAA_WMI_GUID + * @id: The method ID for the ACPI WMAA method (e.g. %WMAA_METHOD_LEVEL or + * %WMAA_METHOD_SOURCE) + * @mode: The operation to perform on the ACPI WMAA method (e.g. %WMAA_MODE_SET + * or %WMAA_MODE_GET) + * @val: Pointer to a value passed in by the caller when @mode is + * %WMAA_MODE_SET, or a value passed out to the caller when @mode is + * %WMAA_MODE_GET or %WMAA_MODE_GET_MAX_LEVEL. + * + * Returns 0 on success, or a negative error number on failure. + */ +static int wmi_call_wmaa(struct wmi_device *w, enum wmaa_method id, enum wmaa_mode mode, u32 *val) +{ + struct wmaa_args args = { + .mode = mode, + .val = 0, + .ret = 0, + }; + struct acpi_buffer buf = { (acpi_size)sizeof(args), &args }; + acpi_status status; + + if (id < WMAA_METHOD_LEVEL || id >= WMAA_METHOD_MAX || + mode < WMAA_MODE_GET || mode >= WMAA_MODE_MAX) + return -EINVAL; + + if (mode == WMAA_MODE_SET) + args.val = *val; + + status = wmidev_evaluate_method(w, 0, id, &buf, &buf); + if (ACPI_FAILURE(status)) { + dev_err(&w->dev, "ACPI WMAA failed: %s\n", + acpi_format_exception(status)); + return -EIO; + } + + if (mode != WMAA_MODE_SET) + *val = args.ret; + + return 0; +} + +static int wmaa_backlight_update_status(struct backlight_device *bd) +{ + struct wmi_device *wdev = bl_get_data(bd); + + return wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_SET, + &bd->props.brightness); +} + +static int wmaa_backlight_get_brightness(struct backlight_device *bd) +{ + struct wmi_device *wdev = bl_get_data(bd); + u32 level; + int ret; + + ret = wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_GET, &level); + if (ret < 0) + return ret; + + return level; +} + +static const struct backlight_ops wmaa_backlight_ops = { + .update_status = wmaa_backlight_update_status, + .get_brightness = wmaa_backlight_get_brightness, +}; + +static int wmaa_backlight_wmi_probe(struct wmi_device *wdev, const void *ctx) +{ + struct backlight_properties props = {}; + struct backlight_device *bdev; + u32 source; + int ret; + + ret = wmi_call_wmaa(wdev, WMAA_METHOD_SOURCE, WMAA_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 != WMAA_SOURCE_EC) + return -ENODEV; + + /* + * Identify this backlight device as a firmware device so that it can + * be prioritized over any exposed GPU-driven raw device(s). + */ + props.type = BACKLIGHT_FIRMWARE; + + ret = wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_GET_MAX_LEVEL, + &props.max_brightness); + if (ret) + return ret; + + ret = wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_GET, + &props.brightness); + if (ret) + return ret; + + bdev = devm_backlight_device_register(&wdev->dev, "wmaa_backlight", + &wdev->dev, wdev, + &wmaa_backlight_ops, &props); + return PTR_ERR_OR_ZERO(bdev); +} + +#define WMAA_WMI_GUID "603E9613-EF25-4338-A3D0-C46177516DB7" + +static const struct wmi_device_id wmaa_backlight_wmi_id_table[] = { + { .guid_string = WMAA_WMI_GUID }, + { } +}; +MODULE_DEVICE_TABLE(wmi, wmaa_backlight_wmi_id_table); + +static struct wmi_driver wmaa_backlight_wmi_driver = { + .driver = { + .name = "wmaa-backlight", + }, + .probe = wmaa_backlight_wmi_probe, + .id_table = wmaa_backlight_wmi_id_table, +}; +module_wmi_driver(wmaa_backlight_wmi_driver); + +MODULE_AUTHOR("Daniel Dadap "); +MODULE_DESCRIPTION("WMAA Backlight WMI driver"); +MODULE_LICENSE("GPL"); From 07ce4cfd292c1d99e76a4480d5c360d66dee2f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:54:57 +0000 Subject: [PATCH 003/106] platform/x86: wmi: fix kernel doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kernel doc erroneously specified `wmi_uninstall_notify_handler()` for the `wmi_remove_notify_handler()` function. Fix that. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-2-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index a76313006bdc..0b931629f0b0 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -551,7 +551,7 @@ wmi_notify_handler handler, void *data) EXPORT_SYMBOL_GPL(wmi_install_notify_handler); /** - * wmi_uninstall_notify_handler - Unregister handler for WMI events + * wmi_remove_notify_handler - Unregister handler for WMI events * @guid: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba * * Unregister handler for events sent to the ACPI-WMI mapper device. From 3ecace310f4dfd2b7ce666092f41c2e5ad60617c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:54:59 +0000 Subject: [PATCH 004/106] platform/x86: wmi: fix checkpatch warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following two checkpatch warnings: * "space required before the open parenthesis '('" * "that open brace { should be on the previous line" Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-3-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 0b931629f0b0..73ed17a53af5 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -488,7 +488,7 @@ static void wmi_notify_debug(u32 value, void *context) return; pr_info("DEBUG Event "); - switch(obj->type) { + switch (obj->type) { case ACPI_TYPE_BUFFER: pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length); break; @@ -1277,8 +1277,7 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, if (wblock->acpi_device->handle == handle && (block->flags & ACPI_WMI_EVENT) && - (block->notify_id == event)) - { + (block->notify_id == event)) { found_it = true; break; } From cd3e3d294e52480f132c0935b99d6d86e2310525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:02 +0000 Subject: [PATCH 005/106] platform/x86: wmi: remove commas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove commas that are after terminating entries in arrays. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-4-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 73ed17a53af5..67c09d81a676 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -714,7 +714,7 @@ static struct attribute *wmi_attrs[] = { &dev_attr_guid.attr, &dev_attr_instance_count.attr, &dev_attr_expensive.attr, - NULL, + NULL }; ATTRIBUTE_GROUPS(wmi); @@ -729,7 +729,7 @@ static DEVICE_ATTR_RO(notify_id); static struct attribute *wmi_event_attrs[] = { &dev_attr_notify_id.attr, - NULL, + NULL }; ATTRIBUTE_GROUPS(wmi_event); @@ -755,13 +755,13 @@ static DEVICE_ATTR_RO(setable); static struct attribute *wmi_data_attrs[] = { &dev_attr_object_id.attr, &dev_attr_setable.attr, - NULL, + NULL }; ATTRIBUTE_GROUPS(wmi_data); static struct attribute *wmi_method_attrs[] = { &dev_attr_object_id.attr, - NULL, + NULL }; ATTRIBUTE_GROUPS(wmi_method); From 9bf9ca95a16e0b9865ea09199fd6342f7f8ca049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:06 +0000 Subject: [PATCH 006/106] platform/x86: wmi: remove unnecessary initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The empty initializer `{ }` is enough to properly initialize the terminating acpi_device_id entry in the device table, so use that. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-5-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 67c09d81a676..6ad5962da59b 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -91,7 +91,7 @@ static int acpi_wmi_probe(struct platform_device *device); static const struct acpi_device_id wmi_device_ids[] = { {"PNP0C14", 0}, {"pnp0c14", 0}, - {"", 0}, + { } }; MODULE_DEVICE_TABLE(acpi, wmi_device_ids); From 43aacf838ef7384d985ef5385ecb0124f8c70007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:10 +0000 Subject: [PATCH 007/106] platform/x86: wmi: remove unnecessary initializations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some pointers are initialized when they are defined, but they are almost immediately reassigned in the following lines. Remove these superfluous assignments. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-6-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 6ad5962da59b..943f30eb45c3 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -177,7 +177,7 @@ static int get_subobj_info(acpi_handle handle, const char *pathname, static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) { - struct guid_block *block = NULL; + struct guid_block *block; char method[5]; acpi_status status; acpi_handle handle; @@ -251,8 +251,8 @@ EXPORT_SYMBOL_GPL(wmi_evaluate_method); acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) { - struct guid_block *block = NULL; - struct wmi_block *wblock = NULL; + struct guid_block *block; + struct wmi_block *wblock; acpi_handle handle; acpi_status status; struct acpi_object_list input; @@ -299,7 +299,7 @@ EXPORT_SYMBOL_GPL(wmidev_evaluate_method); static acpi_status __query_block(struct wmi_block *wblock, u8 instance, struct acpi_buffer *out) { - struct guid_block *block = NULL; + struct guid_block *block; acpi_handle handle; acpi_status status, wc_status = AE_ERROR; struct acpi_object_list input; @@ -405,8 +405,8 @@ EXPORT_SYMBOL_GPL(wmidev_block_query); acpi_status wmi_set_block(const char *guid_string, u8 instance, const struct acpi_buffer *in) { - struct guid_block *block = NULL; struct wmi_block *wblock = NULL; + struct guid_block *block; acpi_handle handle; struct acpi_object_list input; union acpi_object params[2]; @@ -811,8 +811,8 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver) static int wmi_char_open(struct inode *inode, struct file *filp) { const char *driver_name = filp->f_path.dentry->d_iname; - struct wmi_block *wblock = NULL; - struct wmi_block *next = NULL; + struct wmi_block *wblock; + struct wmi_block *next; list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { if (!wblock->dev.dev.driver) @@ -844,8 +844,8 @@ static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct wmi_ioctl_buffer __user *input = (struct wmi_ioctl_buffer __user *) arg; struct wmi_block *wblock = filp->private_data; - struct wmi_ioctl_buffer *buf = NULL; - struct wmi_driver *wdriver = NULL; + struct wmi_ioctl_buffer *buf; + struct wmi_driver *wdriver; int ret; if (_IOC_TYPE(cmd) != WMI_IOC) From 21397cac5daa58fdd47cffb8cda71f7a4bd2c13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:13 +0000 Subject: [PATCH 008/106] platform/x86: wmi: remove unnecessary variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `status` variable was assigned at the end, and then immediately returned. Remove it altogether, and return the previously assigned value directly. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-7-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 943f30eb45c3..97d46da47ff7 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -254,7 +254,6 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, struct guid_block *block; struct wmi_block *wblock; acpi_handle handle; - acpi_status status; struct acpi_object_list input; union acpi_object params[3]; char method[5] = "WM"; @@ -290,9 +289,7 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, strncat(method, block->object_id, 2); - status = acpi_evaluate_object(handle, method, &input, out); - - return status; + return acpi_evaluate_object(handle, method, &input, out); } EXPORT_SYMBOL_GPL(wmidev_evaluate_method); From 84eacf7e6413d5e2d2f4f9dddf9216c18a3631cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:16 +0000 Subject: [PATCH 009/106] platform/x86: wmi: remove unnecessary argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GUID block is available for `wmi_create_device()` through `wblock->gblock`. Use that consistently in the function instead of using a mix of `gblock` and `wblock->gblock`. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-8-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 97d46da47ff7..3154e6801eff 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1028,7 +1028,6 @@ static const struct device_type wmi_type_data = { }; static int wmi_create_device(struct device *wmi_bus_dev, - const struct guid_block *gblock, struct wmi_block *wblock, struct acpi_device *device) { @@ -1036,12 +1035,12 @@ static int wmi_create_device(struct device *wmi_bus_dev, char method[5]; int result; - if (gblock->flags & ACPI_WMI_EVENT) { + if (wblock->gblock.flags & ACPI_WMI_EVENT) { wblock->dev.dev.type = &wmi_type_event; goto out_init; } - if (gblock->flags & ACPI_WMI_METHOD) { + if (wblock->gblock.flags & ACPI_WMI_METHOD) { wblock->dev.dev.type = &wmi_type_method; mutex_init(&wblock->char_mutex); goto out_init; @@ -1091,7 +1090,7 @@ 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", gblock->guid); + dev_set_name(&wblock->dev.dev, "%pUL", wblock->gblock.guid); device_initialize(&wblock->dev.dev); @@ -1183,7 +1182,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) wblock->acpi_device = device; wblock->gblock = gblock[i]; - retval = wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device); + retval = wmi_create_device(wmi_bus_dev, wblock, device); if (retval) { kfree(wblock); continue; From c06a2fde798206941e8d56634e01872771482679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:20 +0000 Subject: [PATCH 010/106] platform/x86: wmi: remove unnecessary casts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Void pointers are implictly cast to arbitrary pointer types, so remove superfluous casts. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-9-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 3154e6801eff..f5cb5908725c 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -387,7 +387,7 @@ union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance) if (ACPI_FAILURE(__query_block(wblock, instance, &out))) return NULL; - return (union acpi_object *)out.pointer; + return out.pointer; } EXPORT_SYMBOL_GPL(wmidev_block_query); @@ -479,8 +479,7 @@ static void wmi_notify_debug(u32 value, void *context) return; } - obj = (union acpi_object *)response.pointer; - + obj = response.pointer; if (!obj) return; @@ -1148,7 +1147,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) if (ACPI_FAILURE(status)) return -ENXIO; - obj = (union acpi_object *) out.pointer; + obj = out.pointer; if (!obj) return -ENXIO; @@ -1307,8 +1306,7 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, } if (driver->notify) - driver->notify(&wblock->dev, - (union acpi_object *)evdata.pointer); + driver->notify(&wblock->dev, evdata.pointer); kfree(evdata.pointer); } else if (wblock->handler) { @@ -1335,7 +1333,7 @@ static int acpi_wmi_remove(struct platform_device *device) acpi_remove_address_space_handler(acpi_device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); wmi_free_devices(acpi_device); - device_unregister((struct device *)dev_get_drvdata(&device->dev)); + device_unregister(dev_get_drvdata(&device->dev)); return 0; } From e83c799270e15adfe1f6e7bcdf7a76db0f200e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:23 +0000 Subject: [PATCH 011/106] platform/x86: wmi: remove stray empty line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove an empty line after the last statement in `acpi_wmi_notify_handler()` which serves no purpose. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-10-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index f5cb5908725c..1ae42dcb4036 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1321,7 +1321,6 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, wblock->acpi_device->pnp.device_class, dev_name(&wblock->dev.dev), event, 0); - } static int acpi_wmi_remove(struct platform_device *device) From 1ebe62bec4120fd79967edbe990f2eea285a6e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:26 +0000 Subject: [PATCH 012/106] platform/x86: wmi: remove unnecessary checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `find_guid_context()` is only called from one place, and `wblock` and `wdriver` cannot be NULL there. So remove the currently redundant checks. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-11-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 1ae42dcb4036..147cc5086f2a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -135,8 +135,6 @@ static const void *find_guid_context(struct wmi_block *wblock, const struct wmi_device_id *id; guid_t guid_input; - if (wblock == NULL || wdriver == NULL) - return NULL; if (wdriver->id_table == NULL) return NULL; From 1c95ace78b6e8e8c88fdcc1b5d6dc6a186914e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:29 +0000 Subject: [PATCH 013/106] platform/x86: wmi: use BIT() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of manually creating the bit masks, use the `BIT()` macro to do it. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-12-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 147cc5086f2a..2edf0cf5137b 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -17,6 +17,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -70,10 +71,10 @@ struct wmi_block { * If the GUID data block is marked as expensive, we must enable and * explicitily disable data collection. */ -#define ACPI_WMI_EXPENSIVE 0x1 -#define ACPI_WMI_METHOD 0x2 /* GUID is a method */ -#define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */ -#define ACPI_WMI_EVENT 0x8 /* GUID is an event */ +#define ACPI_WMI_EXPENSIVE BIT(0) +#define ACPI_WMI_METHOD BIT(1) /* GUID is a method */ +#define ACPI_WMI_STRING BIT(2) /* GUID takes & returns a string */ +#define ACPI_WMI_EVENT BIT(3) /* GUID is an event */ static bool debug_event; module_param(debug_event, bool, 0444); From 285dd01a6cfeb442fdd89649b8ba7e73932aa795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:32 +0000 Subject: [PATCH 014/106] platform/x86: wmi: use bool instead of int MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `bool` type is more expressive for a yes/no kind of value, so use that as the type of the `enable` parameter of `wmi_method_enable()`. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-13-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 2edf0cf5137b..6494521802c7 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -174,7 +174,7 @@ static int get_subobj_info(acpi_handle handle, const char *pathname, return 0; } -static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) +static acpi_status wmi_method_enable(struct wmi_block *wblock, bool enable) { struct guid_block *block; char method[5]; @@ -534,7 +534,7 @@ wmi_notify_handler handler, void *data) block->handler = handler; block->handler_data = data; - wmi_status = wmi_method_enable(block, 1); + wmi_status = wmi_method_enable(block, true); if ((wmi_status != AE_OK) || ((wmi_status == AE_OK) && (status == AE_NOT_EXIST))) status = wmi_status; @@ -575,7 +575,7 @@ acpi_status wmi_remove_notify_handler(const char *guid) block->handler = wmi_notify_debug; status = AE_OK; } else { - wmi_status = wmi_method_enable(block, 0); + wmi_status = wmi_method_enable(block, false); block->handler = NULL; block->handler_data = NULL; if ((wmi_status != AE_OK) || @@ -919,7 +919,7 @@ static int wmi_dev_probe(struct device *dev) int ret = 0; char *buf; - if (ACPI_FAILURE(wmi_method_enable(wblock, 1))) + if (ACPI_FAILURE(wmi_method_enable(wblock, true))) dev_warn(dev, "failed to enable device -- probing anyway\n"); if (wdriver->probe) { @@ -970,7 +970,7 @@ probe_misc_failure: probe_string_failure: kfree(wblock->handler_data); probe_failure: - if (ACPI_FAILURE(wmi_method_enable(wblock, 0))) + if (ACPI_FAILURE(wmi_method_enable(wblock, false))) dev_warn(dev, "failed to disable device\n"); return ret; } @@ -990,7 +990,7 @@ static void wmi_dev_remove(struct device *dev) if (wdriver->remove) wdriver->remove(dev_to_wdev(dev)); - if (ACPI_FAILURE(wmi_method_enable(wblock, 0))) + if (ACPI_FAILURE(wmi_method_enable(wblock, false))) dev_warn(dev, "failed to disable device\n"); } @@ -1190,7 +1190,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) if (debug_event) { wblock->handler = wmi_notify_debug; - wmi_method_enable(wblock, 1); + wmi_method_enable(wblock, true); } } @@ -1207,7 +1207,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) dev_err(wmi_bus_dev, "failed to register %pUL\n", wblock->gblock.guid); if (debug_event) - wmi_method_enable(wblock, 0); + wmi_method_enable(wblock, false); list_del(&wblock->list); put_device(&wblock->dev.dev); } From 67f472fdacf4a691b1c3c20c27800b23ce31e2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:39 +0000 Subject: [PATCH 015/106] platform/x86: wmi: use guid_t and guid_equal() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of hard-coding a 16 long byte array, use the available `guid_t` type and related methods. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-15-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 6494521802c7..dc96cae71fd0 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -40,7 +40,7 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(wmi_block_list); struct guid_block { - char guid[16]; + guid_t guid; union { char object_id[2]; struct { @@ -121,7 +121,7 @@ static bool find_guid(const char *guid_string, struct wmi_block **out) list_for_each_entry(wblock, &wmi_block_list, list) { block = &wblock->gblock; - if (memcmp(block->guid, &guid_input, 16) == 0) { + if (guid_equal(&block->guid, &guid_input)) { if (out) *out = wblock; return true; @@ -143,7 +143,7 @@ static const void *find_guid_context(struct wmi_block *wblock, while (*id->guid_string) { if (guid_parse(id->guid_string, &guid_input)) continue; - if (!memcmp(wblock->gblock.guid, &guid_input, 16)) + if (guid_equal(&wblock->gblock.guid, &guid_input)) return id->context; id++; } @@ -445,7 +445,7 @@ EXPORT_SYMBOL_GPL(wmi_set_block); static void wmi_dump_wdg(const struct guid_block *g) { - pr_info("%pUL:\n", g->guid); + pr_info("%pUL:\n", &g->guid); if (g->flags & ACPI_WMI_EVENT) pr_info("\tnotify_id: 0x%02X\n", g->notify_id); else @@ -526,7 +526,7 @@ wmi_notify_handler handler, void *data) list_for_each_entry(block, &wmi_block_list, list) { acpi_status wmi_status; - if (memcmp(block->gblock.guid, &guid_input, 16) == 0) { + if (guid_equal(&block->gblock.guid, &guid_input)) { if (block->handler && block->handler != wmi_notify_debug) return AE_ALREADY_ACQUIRED; @@ -566,7 +566,7 @@ acpi_status wmi_remove_notify_handler(const char *guid) list_for_each_entry(block, &wmi_block_list, list) { acpi_status wmi_status; - if (memcmp(block->gblock.guid, &guid_input, 16) == 0) { + if (guid_equal(&block->gblock.guid, &guid_input)) { if (!block->handler || block->handler == wmi_notify_debug) return AE_NULL_ENTRY; @@ -672,7 +672,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "wmi:%pUL\n", wblock->gblock.guid); + return sprintf(buf, "wmi:%pUL\n", &wblock->gblock.guid); } static DEVICE_ATTR_RO(modalias); @@ -681,7 +681,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "%pUL\n", wblock->gblock.guid); + return sprintf(buf, "%pUL\n", &wblock->gblock.guid); } static DEVICE_ATTR_RO(guid); @@ -764,10 +764,10 @@ static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { struct wmi_block *wblock = dev_to_wblock(dev); - if (add_uevent_var(env, "MODALIAS=wmi:%pUL", wblock->gblock.guid)) + if (add_uevent_var(env, "MODALIAS=wmi:%pUL", &wblock->gblock.guid)) return -ENOMEM; - if (add_uevent_var(env, "WMI_GUID=%pUL", wblock->gblock.guid)) + if (add_uevent_var(env, "WMI_GUID=%pUL", &wblock->gblock.guid)) return -ENOMEM; return 0; @@ -795,7 +795,7 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver) if (WARN_ON(guid_parse(id->guid_string, &driver_guid))) continue; - if (!memcmp(&driver_guid, wblock->gblock.guid, 16)) + if (guid_equal(&driver_guid, &wblock->gblock.guid)) return 1; id++; @@ -1088,7 +1088,7 @@ 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); + dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid); device_initialize(&wblock->dev.dev); @@ -1108,12 +1108,12 @@ static void wmi_free_devices(struct acpi_device *device) } } -static bool guid_already_parsed(struct acpi_device *device, const u8 *guid) +static bool guid_already_parsed(struct acpi_device *device, const guid_t *guid) { struct wmi_block *wblock; list_for_each_entry(wblock, &wmi_block_list, list) { - if (memcmp(wblock->gblock.guid, guid, 16) == 0) { + if (guid_equal(&wblock->gblock.guid, guid)) { /* * Because we historically didn't track the relationship * between GUIDs and ACPI nodes, we don't know whether @@ -1168,7 +1168,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) * 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(device, &gblock[i].guid)) continue; wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); @@ -1205,7 +1205,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) retval = device_add(&wblock->dev.dev); if (retval) { dev_err(wmi_bus_dev, "failed to register %pUL\n", - wblock->gblock.guid); + &wblock->gblock.guid); if (debug_event) wmi_method_enable(wblock, false); list_del(&wblock->list); @@ -1314,7 +1314,7 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, } if (debug_event) - pr_info("DEBUG Event GUID: %pUL\n", wblock->gblock.guid); + pr_info("DEBUG Event GUID: %pUL\n", &wblock->gblock.guid); acpi_bus_generate_netlink_event( wblock->acpi_device->pnp.device_class, From dea878d88f9d0135d0024cf5955d03402b475e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:42 +0000 Subject: [PATCH 016/106] platform/x86: wmi: make GUID block packed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `guid_block` struct is overlaid onto a buffer coming from the _WDG ACPI object of the device. For this reason mark the struct packed and add assertions about sizes. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-16-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index dc96cae71fd0..7e294f596785 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -50,7 +51,10 @@ struct guid_block { }; u8 instance_count; u8 flags; -}; +} __packed; +static_assert(sizeof(typeof_member(struct guid_block, guid)) == 16); +static_assert(sizeof(struct guid_block) == 20); +static_assert(__alignof__(struct guid_block) == 1); struct wmi_block { struct wmi_device dev; From 6133913a820972e1710107f6f08b574e8e89d753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:45 +0000 Subject: [PATCH 017/106] platform/x86: wmi: use sysfs_emit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of `sprintf()` use the new `sysfs_emit()` function. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-17-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 7e294f596785..9ed862254597 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -676,7 +677,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "wmi:%pUL\n", &wblock->gblock.guid); + return sysfs_emit(buf, "wmi:%pUL\n", &wblock->gblock.guid); } static DEVICE_ATTR_RO(modalias); @@ -685,7 +686,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "%pUL\n", &wblock->gblock.guid); + return sysfs_emit(buf, "%pUL\n", &wblock->gblock.guid); } static DEVICE_ATTR_RO(guid); @@ -694,7 +695,7 @@ static ssize_t instance_count_show(struct device *dev, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "%d\n", (int)wblock->gblock.instance_count); + return sysfs_emit(buf, "%d\n", (int)wblock->gblock.instance_count); } static DEVICE_ATTR_RO(instance_count); @@ -703,8 +704,8 @@ static ssize_t expensive_show(struct device *dev, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "%d\n", - (wblock->gblock.flags & ACPI_WMI_EXPENSIVE) != 0); + return sysfs_emit(buf, "%d\n", + (wblock->gblock.flags & ACPI_WMI_EXPENSIVE) != 0); } static DEVICE_ATTR_RO(expensive); @@ -722,7 +723,7 @@ static ssize_t notify_id_show(struct device *dev, struct device_attribute *attr, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "%02X\n", (unsigned int)wblock->gblock.notify_id); + return sysfs_emit(buf, "%02X\n", (unsigned int)wblock->gblock.notify_id); } static DEVICE_ATTR_RO(notify_id); @@ -737,8 +738,8 @@ static ssize_t object_id_show(struct device *dev, struct device_attribute *attr, { struct wmi_block *wblock = dev_to_wblock(dev); - return sprintf(buf, "%c%c\n", wblock->gblock.object_id[0], - wblock->gblock.object_id[1]); + return sysfs_emit(buf, "%c%c\n", wblock->gblock.object_id[0], + wblock->gblock.object_id[1]); } static DEVICE_ATTR_RO(object_id); @@ -747,7 +748,7 @@ static ssize_t setable_show(struct device *dev, struct device_attribute *attr, { struct wmi_device *wdev = dev_to_wdev(dev); - return sprintf(buf, "%d\n", (int)wdev->setable); + return sysfs_emit(buf, "%d\n", (int)wdev->setable); } static DEVICE_ATTR_RO(setable); From 6e0bc588a0842dd740cb692d1398a48a26ed112c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:55:52 +0000 Subject: [PATCH 018/106] platform/x86: wmi: use !p to check for NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other parts of the code use the `!p` idiom to check for NULL pointers, convert `find_guid_context()` to do the same. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-19-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 9ed862254597..38364534e9eb 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -141,10 +141,10 @@ static const void *find_guid_context(struct wmi_block *wblock, const struct wmi_device_id *id; guid_t guid_input; - if (wdriver->id_table == NULL) + id = wdriver->id_table; + if (!id) return NULL; - id = wdriver->id_table; while (*id->guid_string) { if (guid_parse(id->guid_string, &guid_input)) continue; From 7410b8e634ce202f3f6a092431926c213d6c1f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:03 +0000 Subject: [PATCH 019/106] platform/x86: wmi: use sizeof(*p) in allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per the coding style guide, the preferred way to pass the size of objects to allocator functions is `sizeof(*p)`. Use that. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-20-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 38364534e9eb..91350af097d6 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1176,7 +1176,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) if (guid_already_parsed(device, &gblock[i].guid)) continue; - wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); + wblock = kzalloc(sizeof(*wblock), GFP_KERNEL); if (!wblock) { retval = -ENOMEM; break; From 1ce69d2b96203da5819b207dc03dba7adf92cb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:07 +0000 Subject: [PATCH 020/106] platform/x86: wmi: remove variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `block` variable is assigned and only used once, the code shorter and probably clearer without it; so remove it. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-21-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 91350af097d6..163969a8beac 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -118,15 +118,12 @@ static bool find_guid(const char *guid_string, struct wmi_block **out) { guid_t guid_input; struct wmi_block *wblock; - struct guid_block *block; if (guid_parse(guid_string, &guid_input)) return false; list_for_each_entry(wblock, &wmi_block_list, list) { - block = &wblock->gblock; - - if (guid_equal(&block->guid, &guid_input)) { + if (guid_equal(&wblock->gblock.guid, &guid_input)) { if (out) *out = wblock; return true; From f5431bf1e6781e876bdc8ae10fb1e7da6f1aa9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:10 +0000 Subject: [PATCH 021/106] platform/x86: wmi: move variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move some variables in order to keep them in the narrowest possible scope. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-22-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 163969a8beac..a00842897f82 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -136,13 +136,14 @@ static const void *find_guid_context(struct wmi_block *wblock, struct wmi_driver *wdriver) { const struct wmi_device_id *id; - guid_t guid_input; id = wdriver->id_table; if (!id) return NULL; while (*id->guid_string) { + guid_t guid_input; + if (guid_parse(id->guid_string, &guid_input)) continue; if (guid_equal(&wblock->gblock.guid, &guid_input)) @@ -604,7 +605,6 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) { struct acpi_object_list input; union acpi_object params[1]; - struct guid_block *gblock; struct wmi_block *wblock; input.count = 1; @@ -613,7 +613,7 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) params[0].integer.value = event; list_for_each_entry(wblock, &wmi_block_list, list) { - gblock = &wblock->gblock; + struct guid_block *gblock = &wblock->gblock; if ((gblock->flags & ACPI_WMI_EVENT) && (gblock->notify_id == event)) @@ -1264,12 +1264,11 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, void *context) { - struct guid_block *block; struct wmi_block *wblock; bool found_it = false; list_for_each_entry(wblock, &wmi_block_list, list) { - block = &wblock->gblock; + struct guid_block *block = &wblock->gblock; if (wblock->acpi_device->handle == handle && (block->flags & ACPI_WMI_EVENT) && From bba08f358f79300720ef5332a445abbe4b49ff4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:13 +0000 Subject: [PATCH 022/106] platform/x86: wmi: align arguments of functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align the arguments of * wmi_evaluate_method() * wmi_install_notify_handler() * wmidev_evaluate_method() * find_guid_context() * acpi_wmi_ec_space_handler() * wmi_char_read() Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-23-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index a00842897f82..faf36e7f0d56 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -133,7 +133,7 @@ static bool find_guid(const char *guid_string, struct wmi_block **out) } static const void *find_guid_context(struct wmi_block *wblock, - struct wmi_driver *wdriver) + struct wmi_driver *wdriver) { const struct wmi_device_id *id; @@ -228,8 +228,8 @@ EXPORT_SYMBOL_GPL(set_required_buffer_size); * * Call an ACPI-WMI method */ -acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, -u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) +acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method_id, + const struct acpi_buffer *in, struct acpi_buffer *out) { struct wmi_block *wblock = NULL; @@ -250,8 +250,8 @@ EXPORT_SYMBOL_GPL(wmi_evaluate_method); * * Call an ACPI-WMI method */ -acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, - u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) +acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 method_id, + const struct acpi_buffer *in, struct acpi_buffer *out) { struct guid_block *block; struct wmi_block *wblock; @@ -514,7 +514,8 @@ static void wmi_notify_debug(u32 value, void *context) * Register a handler for events sent to the ACPI-WMI mapper device. */ acpi_status wmi_install_notify_handler(const char *guid, -wmi_notify_handler handler, void *data) + wmi_notify_handler handler, + void *data) { struct wmi_block *block; acpi_status status = AE_NOT_EXIST; @@ -827,7 +828,7 @@ static int wmi_char_open(struct inode *inode, struct file *filp) } static ssize_t wmi_char_read(struct file *filp, char __user *buffer, - size_t length, loff_t *offset) + size_t length, loff_t *offset) { struct wmi_block *wblock = filp->private_data; @@ -1226,8 +1227,8 @@ out_free_pointer: */ static acpi_status acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, - u32 bits, u64 *value, - void *handler_context, void *region_context) + u32 bits, u64 *value, + void *handler_context, void *region_context) { int result = 0, i = 0; u8 temp = 0; From 1c23ab912810f7d204c2f5873b3b8eaa05da7815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:16 +0000 Subject: [PATCH 023/106] platform/x86: wmi: improve debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the event identifier number in addition to the already printed information, and use %u for printing unsigned values in `wmi_notify_debug()`. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-24-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index faf36e7f0d56..3880d5f2a8dd 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -485,10 +485,10 @@ static void wmi_notify_debug(u32 value, void *context) if (!obj) return; - pr_info("DEBUG Event "); + pr_info("DEBUG: event 0x%02X ", value); switch (obj->type) { case ACPI_TYPE_BUFFER: - pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length); + pr_cont("BUFFER_TYPE - length %u\n", obj->buffer.length); break; case ACPI_TYPE_STRING: pr_cont("STRING_TYPE - %s\n", obj->string.pointer); @@ -497,7 +497,7 @@ static void wmi_notify_debug(u32 value, void *context) pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value); break; case ACPI_TYPE_PACKAGE: - pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count); + pr_cont("PACKAGE_TYPE - %u elements\n", obj->package.count); break; default: pr_cont("object type 0x%X\n", obj->type); @@ -1316,7 +1316,7 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, } if (debug_event) - pr_info("DEBUG Event GUID: %pUL\n", &wblock->gblock.guid); + pr_info("DEBUG: GUID %pUL event 0x%02X\n", &wblock->gblock.guid, event); acpi_bus_generate_netlink_event( wblock->acpi_device->pnp.device_class, From 1975718c488a39128f1f515b23ae61a5a214cc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:26 +0000 Subject: [PATCH 024/106] platform/x86: wmi: do not fail if disabling fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, `__query_block()` would fail if the second WCxx method call failed. However, the WQxx method might have succeeded, and potentially allocated memory for the result. Instead of throwing away the result and potentially leaking memory, ignore the result of the second WCxx call. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-25-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 3880d5f2a8dd..f4f68b31eb6a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -352,7 +352,14 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance, * the WQxx method failed - we should disable collection anyway. */ if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) { - status = acpi_execute_simple_method(handle, wc_method, 0); + /* + * Ignore whether this WCxx call succeeds or not since + * the previously executed WQxx method call might have + * succeeded, and returning the failing status code + * of this call would throw away the result of the WQxx + * call, potentially leaking memory. + */ + acpi_execute_simple_method(handle, wc_method, 0); } return status; From 736b48aae5e83b5fab16fc9f31354d2cf863aa79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:29 +0000 Subject: [PATCH 025/106] platform/x86: wmi: simplify error handling logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code carries out the following ACPI status mapping: AE_NOT_FOUND -> AE_OK AE_OK -> AE_OK AE_$X -> AE_$X That is, everything is mapped to itself, except AE_NOT_FOUND. The current code does not do it in the most straighforward way. Simplify the logic. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-26-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index f4f68b31eb6a..7753836571fe 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -189,11 +189,10 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, bool enable) snprintf(method, 5, "WE%02X", block->notify_id); status = acpi_execute_simple_method(handle, method, enable); - - if (status != AE_OK && status != AE_NOT_FOUND) - return status; - else + if (status == AE_NOT_FOUND) return AE_OK; + + return status; } /* From e7b2e33449e22fdbaa0247d96f31543affe6163d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:32 +0000 Subject: [PATCH 026/106] platform/x86: wmi: introduce helper to convert driver to WMI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a helper function which wraps the appropriate `container_of()` macro invocation to convert a `struct device_driver` to `struct wmi_driver`. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-27-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 7753836571fe..5746fb96222a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -673,6 +673,11 @@ static struct wmi_device *dev_to_wdev(struct device *dev) return container_of(dev, struct wmi_device, dev); } +static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv) +{ + return container_of(drv, struct wmi_driver, driver); +} + /* * sysfs interface */ @@ -791,8 +796,7 @@ static void wmi_dev_release(struct device *dev) static int wmi_dev_match(struct device *dev, struct device_driver *driver) { - struct wmi_driver *wmi_driver = - container_of(driver, struct wmi_driver, driver); + struct wmi_driver *wmi_driver = drv_to_wdrv(driver); struct wmi_block *wblock = dev_to_wblock(dev); const struct wmi_device_id *id = wmi_driver->id_table; @@ -889,8 +893,7 @@ static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } /* let the driver do any filtering and do the call */ - wdriver = container_of(wblock->dev.dev.driver, - struct wmi_driver, driver); + wdriver = drv_to_wdrv(wblock->dev.dev.driver); if (!try_module_get(wdriver->driver.owner)) { ret = -EBUSY; goto out_ioctl; @@ -923,8 +926,7 @@ static const struct file_operations wmi_fops = { static int wmi_dev_probe(struct device *dev) { struct wmi_block *wblock = dev_to_wblock(dev); - struct wmi_driver *wdriver = - container_of(dev->driver, struct wmi_driver, driver); + struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); int ret = 0; char *buf; @@ -987,8 +989,7 @@ probe_failure: static void wmi_dev_remove(struct device *dev) { struct wmi_block *wblock = dev_to_wblock(dev); - struct wmi_driver *wdriver = - container_of(dev->driver, struct wmi_driver, driver); + struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); if (wdriver->filter_callback) { misc_deregister(&wblock->char_dev); @@ -1290,15 +1291,12 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, /* If a driver is bound, then notify the driver. */ if (wblock->dev.dev.driver) { - struct wmi_driver *driver; + struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); struct acpi_object_list input; union acpi_object params[1]; struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_status status; - driver = container_of(wblock->dev.dev.driver, - struct wmi_driver, driver); - input.count = 1; input.pointer = params; params[0].type = ACPI_TYPE_INTEGER; From 57f2ce89211383947cdf93502ad53cf0d18b65fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:35 +0000 Subject: [PATCH 027/106] platform/x86: wmi: introduce helper to generate method names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of "manually" constructing the ACPI method name and hard-coding sizes in WMI functions, introduce a helper method which generates the method name for an arbitrary WMI block. Furthermore, save the appropriate buffer size into a macro. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-28-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 42 ++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 5746fb96222a..2bad1ff38291 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -195,6 +195,22 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, bool enable) return status; } +#define WMI_ACPI_METHOD_NAME_SIZE 5 + +static inline void get_acpi_method_name(const struct wmi_block *wblock, + const char method, + char buffer[static WMI_ACPI_METHOD_NAME_SIZE]) +{ + static_assert(ARRAY_SIZE(wblock->gblock.object_id) == 2); + static_assert(WMI_ACPI_METHOD_NAME_SIZE >= 5); + + buffer[0] = 'W'; + buffer[1] = method; + buffer[2] = wblock->gblock.object_id[0]; + buffer[3] = wblock->gblock.object_id[1]; + buffer[4] = '\0'; +} + /* * Exported WMI functions */ @@ -257,7 +273,7 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met acpi_handle handle; struct acpi_object_list input; union acpi_object params[3]; - char method[5] = "WM"; + char method[WMI_ACPI_METHOD_NAME_SIZE]; wblock = container_of(wdev, struct wmi_block, dev); block = &wblock->gblock; @@ -288,7 +304,7 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met params[2].buffer.pointer = in->pointer; } - strncat(method, block->object_id, 2); + get_acpi_method_name(wblock, 'M', method); return acpi_evaluate_object(handle, method, &input, out); } @@ -302,8 +318,8 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance, acpi_status status, wc_status = AE_ERROR; struct acpi_object_list input; union acpi_object wq_params[1]; - char method[5]; - char wc_method[5] = "WC"; + char wc_method[WMI_ACPI_METHOD_NAME_SIZE]; + char method[WMI_ACPI_METHOD_NAME_SIZE]; if (!out) return AE_BAD_PARAMETER; @@ -331,7 +347,7 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance, * enable collection. */ if (block->flags & ACPI_WMI_EXPENSIVE) { - strncat(wc_method, block->object_id, 2); + get_acpi_method_name(wblock, 'C', wc_method); /* * Some GUIDs break the specification by declaring themselves @@ -341,9 +357,7 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance, wc_status = acpi_execute_simple_method(handle, wc_method, 1); } - strcpy(method, "WQ"); - strncat(method, block->object_id, 2); - + get_acpi_method_name(wblock, 'Q', method); status = acpi_evaluate_object(handle, method, &input, out); /* @@ -415,7 +429,7 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, acpi_handle handle; struct acpi_object_list input; union acpi_object params[2]; - char method[5] = "WS"; + char method[WMI_ACPI_METHOD_NAME_SIZE]; if (!guid_string || !in) return AE_BAD_DATA; @@ -446,7 +460,7 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, params[1].buffer.length = in->length; params[1].buffer.pointer = in->pointer; - strncat(method, block->object_id, 2); + get_acpi_method_name(wblock, 'S', method); return acpi_evaluate_object(handle, method, &input, NULL); } @@ -1040,7 +1054,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, struct acpi_device *device) { struct acpi_device_info *info; - char method[5]; + char method[WMI_ACPI_METHOD_NAME_SIZE]; int result; if (wblock->gblock.flags & ACPI_WMI_EVENT) { @@ -1059,8 +1073,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, * required per the WMI documentation. If it is not present, * we ignore this data block. */ - strcpy(method, "WQ"); - strncat(method, wblock->gblock.object_id, 2); + get_acpi_method_name(wblock, 'Q', method); result = get_subobj_info(device->handle, method, &info); if (result) { @@ -1087,8 +1100,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, kfree(info); - strcpy(method, "WS"); - strncat(method, wblock->gblock.object_id, 2); + get_acpi_method_name(wblock, 'S', method); result = get_subobj_info(device->handle, method, NULL); if (result == 0) From 51142a0886bd34ec3c6e478739484a85b3b81cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:38 +0000 Subject: [PATCH 028/106] platform/x86: wmi: introduce helper to determine type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce helper function to determine the appropriate ACPI type for the input parameter. This also fixes the following checkpatch warning: "braces {} are not necessary for any arm of this statement". Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-29-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 2bad1ff38291..a78b37cb8041 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -211,6 +211,14 @@ static inline void get_acpi_method_name(const struct wmi_block *wblock, buffer[4] = '\0'; } +static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wblock) +{ + if (wblock->gblock.flags & ACPI_WMI_STRING) + return ACPI_TYPE_STRING; + else + return ACPI_TYPE_BUFFER; +} + /* * Exported WMI functions */ @@ -295,11 +303,7 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met if (in) { input.count = 3; - if (block->flags & ACPI_WMI_STRING) { - params[2].type = ACPI_TYPE_STRING; - } else { - params[2].type = ACPI_TYPE_BUFFER; - } + params[2].type = get_param_acpi_type(wblock); params[2].buffer.length = in->length; params[2].buffer.pointer = in->pointer; } @@ -451,12 +455,7 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, input.pointer = params; params[0].type = ACPI_TYPE_INTEGER; params[0].integer.value = instance; - - if (block->flags & ACPI_WMI_STRING) { - params[1].type = ACPI_TYPE_STRING; - } else { - params[1].type = ACPI_TYPE_BUFFER; - } + params[1].type = get_param_acpi_type(wblock); params[1].buffer.length = in->length; params[1].buffer.pointer = in->pointer; From 25be44f6e2fc9dd117ba6e18fa58317a2015af17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:41 +0000 Subject: [PATCH 029/106] platform/x86: wmi: introduce helper to retrieve event data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, `acpi_wmi_notify_handler()` and `wmi_get_event_data()` shared more or less the exact same code to query the data for a particular event. Introduce a function to get rid of the duplication, and use it from `acpi_wmi_notify_handler()` and `wmi_get_event_data()`. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-30-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 42 ++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index a78b37cb8041..441d4ddd6fbf 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -219,6 +219,22 @@ static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wbloc return ACPI_TYPE_BUFFER; } +static acpi_status get_event_data(const struct wmi_block *wblock, struct acpi_buffer *out) +{ + union acpi_object param = { + .integer = { + .type = ACPI_TYPE_INTEGER, + .value = wblock->gblock.notify_id, + } + }; + struct acpi_object_list input = { + .count = 1, + .pointer = ¶m, + }; + + return acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, out); +} + /* * Exported WMI functions */ @@ -623,22 +639,13 @@ EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); */ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) { - struct acpi_object_list input; - union acpi_object params[1]; struct wmi_block *wblock; - input.count = 1; - input.pointer = params; - params[0].type = ACPI_TYPE_INTEGER; - params[0].integer.value = event; - list_for_each_entry(wblock, &wmi_block_list, list) { struct guid_block *gblock = &wblock->gblock; - if ((gblock->flags & ACPI_WMI_EVENT) && - (gblock->notify_id == event)) - return acpi_evaluate_object(wblock->acpi_device->handle, - "_WED", &input, out); + if ((gblock->flags & ACPI_WMI_EVENT) && gblock->notify_id == event) + return get_event_data(wblock, out); } return AE_NOT_FOUND; @@ -1303,21 +1310,12 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, /* If a driver is bound, then notify the driver. */ if (wblock->dev.dev.driver) { struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); - struct acpi_object_list input; - union acpi_object params[1]; struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_status status; - input.count = 1; - input.pointer = params; - params[0].type = ACPI_TYPE_INTEGER; - params[0].integer.value = event; - - status = acpi_evaluate_object(wblock->acpi_device->handle, - "_WED", &input, &evdata); + status = get_event_data(wblock, &evdata); if (ACPI_FAILURE(status)) { - dev_warn(&wblock->dev.dev, - "failed to get event data\n"); + dev_warn(&wblock->dev.dev, "failed to get event data\n"); return; } From b0179b805eed104eb3b2319c23ccbfa717c18897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 4 Sep 2021 17:56:44 +0000 Subject: [PATCH 030/106] platform/x86: wmi: more detailed error reporting in find_guid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make `find_guid()` return an acpi_status, and make it handle NULL pointer GUID strings; and adapt users accordingly. Signed-off-by: Barnabás Pőcze Link: https://lore.kernel.org/r/20210904175450.156801-31-pobrn@protonmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 43 ++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 441d4ddd6fbf..e6997be206f1 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -114,22 +114,27 @@ static struct platform_driver acpi_wmi_driver = { * GUID parsing functions */ -static bool find_guid(const char *guid_string, struct wmi_block **out) +static acpi_status find_guid(const char *guid_string, struct wmi_block **out) { guid_t guid_input; struct wmi_block *wblock; + if (!guid_string) + return AE_BAD_PARAMETER; + if (guid_parse(guid_string, &guid_input)) - return false; + return AE_BAD_PARAMETER; list_for_each_entry(wblock, &wmi_block_list, list) { if (guid_equal(&wblock->gblock.guid, &guid_input)) { if (out) *out = wblock; - return true; + + return AE_OK; } } - return false; + + return AE_NOT_FOUND; } static const void *find_guid_context(struct wmi_block *wblock, @@ -271,9 +276,12 @@ acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method const struct acpi_buffer *in, struct acpi_buffer *out) { struct wmi_block *wblock = NULL; + acpi_status status; + + status = find_guid(guid_string, &wblock); + if (ACPI_FAILURE(status)) + return status; - if (!find_guid(guid_string, &wblock)) - return AE_ERROR; return wmidev_evaluate_method(&wblock->dev, instance, method_id, in, out); } @@ -410,12 +418,11 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance, struct acpi_buffer *out) { struct wmi_block *wblock; + acpi_status status; - if (!guid_string) - return AE_BAD_PARAMETER; - - if (!find_guid(guid_string, &wblock)) - return AE_ERROR; + status = find_guid(guid_string, &wblock); + if (ACPI_FAILURE(status)) + return status; return __query_block(wblock, instance, out); } @@ -450,12 +457,14 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, struct acpi_object_list input; union acpi_object params[2]; char method[WMI_ACPI_METHOD_NAME_SIZE]; + acpi_status status; - if (!guid_string || !in) + if (!in) return AE_BAD_DATA; - if (!find_guid(guid_string, &wblock)) - return AE_ERROR; + status = find_guid(guid_string, &wblock); + if (ACPI_FAILURE(status)) + return status; block = &wblock->gblock; handle = wblock->acpi_device->handle; @@ -660,7 +669,7 @@ EXPORT_SYMBOL_GPL(wmi_get_event_data); */ bool wmi_has_guid(const char *guid_string) { - return find_guid(guid_string, NULL); + return ACPI_SUCCESS(find_guid(guid_string, NULL)); } EXPORT_SYMBOL_GPL(wmi_has_guid); @@ -675,8 +684,10 @@ EXPORT_SYMBOL_GPL(wmi_has_guid); char *wmi_get_acpi_device_uid(const char *guid_string) { struct wmi_block *wblock = NULL; + acpi_status status; - if (!find_guid(guid_string, &wblock)) + status = find_guid(guid_string, &wblock); + if (ACPI_FAILURE(status)) return NULL; return acpi_device_uid(wblock->acpi_device); From 1f88e0a22f7cef04e2ef7eeb5252b061e5842d6b Mon Sep 17 00:00:00 2001 From: Jules Irenge Date: Sun, 12 Sep 2021 02:17:41 +0100 Subject: [PATCH 031/106] platform/x86: acer-wmi: use __packed instead of __attribute__((packed)) checkpatch.pl tool warns about using __attribute__((packed)) "WARNING: __packed is preferred over __attribute__((packed))" To fix this __attribute__((packed)) is replaced by __packed Signed-off-by: Jules Irenge Link: https://lore.kernel.org/r/20210912011741.30495-1-jbi.octave@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/acer-wmi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 694b45ed06a2..9c6943e401a6 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -138,7 +138,7 @@ struct event_return_value { u16 reserved1; u8 kbd_dock_state; u8 reserved2; -} __attribute__((packed)); +} __packed; /* * GUID3 Get Device Status device flags @@ -172,33 +172,33 @@ struct func_input_params { u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */ u8 app_mask; /* Bit mask to app_status */ u8 reserved; -} __attribute__((packed)); +} __packed; struct func_return_value { u8 error_code; /* Error Code */ u8 ec_return_value; /* EC Return Value */ u16 reserved; -} __attribute__((packed)); +} __packed; struct wmid3_gds_set_input_param { /* Set Device Status input parameter */ u8 function_num; /* Function Number */ u8 hotkey_number; /* Hotkey Number */ u16 devices; /* Set Device */ u8 volume_value; /* Volume Value */ -} __attribute__((packed)); +} __packed; struct wmid3_gds_get_input_param { /* Get Device Status input parameter */ u8 function_num; /* Function Number */ u8 hotkey_number; /* Hotkey Number */ u16 devices; /* Get Device */ -} __attribute__((packed)); +} __packed; struct wmid3_gds_return_value { /* Get Device Status return value*/ u8 error_code; /* Error Code */ u8 ec_return_value; /* EC Return Value */ u16 devices; /* Current Device Status */ u32 reserved; -} __attribute__((packed)); +} __packed; struct hotkey_function_type_aa { u8 type; @@ -210,7 +210,7 @@ struct hotkey_function_type_aa { u16 display_func_bitmap; u16 others_func_bitmap; u8 commun_fn_key_number; -} __attribute__((packed)); +} __packed; /* * Interface capability flags From 7b6bf51de9746b43ec56567a0297378cd0172946 Mon Sep 17 00:00:00 2001 From: "K Naduvalath, Sumesh" Date: Mon, 13 Sep 2021 10:40:56 +0530 Subject: [PATCH 032/106] platform/x86: Add Intel ishtp eclite driver This driver is for accessing the PSE (Programmable Service Engine) - an Embedded Controller like IP - using ISHTP (Integratd Sensor Hub Transport Protocol) to get battery, thermal and UCSI (USB Type-C Connector System Software Interface) related data from the platform. Signed-off-by: K Naduvalath, Sumesh Reviewed-by: Mark Gross Link: https://lore.kernel.org/r/20210913051056.28736-1-sumesh.k.naduvalath@intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- MAINTAINERS | 6 + drivers/platform/x86/intel/Kconfig | 16 + drivers/platform/x86/intel/Makefile | 1 + drivers/platform/x86/intel/ishtp_eclite.c | 701 ++++++++++++++++++++++ 4 files changed, 724 insertions(+) create mode 100644 drivers/platform/x86/intel/ishtp_eclite.c diff --git a/MAINTAINERS b/MAINTAINERS index 72837339b3ae..949eb8ce6e72 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9479,6 +9479,12 @@ L: linux-crypto@vger.kernel.org S: Maintained F: drivers/crypto/ixp4xx_crypto.c +INTEL ISHTP ECLITE DRIVER +M: Sumesh K Naduvalath +L: platform-driver-x86@vger.kernel.org +S: Supported +F: drivers/platform/x86/intel/ishtp_eclite.c + INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT M: Krzysztof Halasa S: Maintained diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index 0b21468e1bd0..38ce3e344589 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -102,6 +102,22 @@ config INTEL_CHTDC_TI_PWRBTN To compile this driver as a module, choose M here: the module will be called intel_chtdc_ti_pwrbtn. +config INTEL_ISHTP_ECLITE + tristate "Intel ISHTP eclite controller Driver" + depends on INTEL_ISH_HID + depends on ACPI + help + This driver is for accessing the PSE (Programmable Service Engine) - + an Embedded Controller like IP - using ISHTP (Integrated Sensor Hub + Transport Protocol) to get battery, thermal and UCSI (USB Type-C + Connector System Software Interface) related data from the platform. + Users who don't want to use discrete Embedded Controller on Intel's + Elkhartlake platform can leverage this integrated solution of + ECLite which is part of PSE subsystem. + + To compile this driver as a module, choose M here: the module + will be called intel_ishtp_eclite. + config INTEL_MRFLD_PWRBTN tristate "Intel Merrifield Basin Cove power button driver" depends on INTEL_SOC_PMIC_MRFLD diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 8b3a3f7bab49..7c24be2423d8 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -21,6 +21,7 @@ intel-vbtn-y := vbtn.o obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o # Intel miscellaneous drivers +obj-$(CONFIG_INTEL_ISHTP_ECLITE) += ishtp_eclite.o intel_int0002_vgpio-y := int0002_vgpio.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o intel_oaktrail-y := oaktrail.o diff --git a/drivers/platform/x86/intel/ishtp_eclite.c b/drivers/platform/x86/intel/ishtp_eclite.c new file mode 100644 index 000000000000..12fc98a48657 --- /dev/null +++ b/drivers/platform/x86/intel/ishtp_eclite.c @@ -0,0 +1,701 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel ECLite opregion driver for talking to ECLite firmware running on + * Intel Integrated Sensor Hub (ISH) using ISH Transport Protocol (ISHTP) + * + * Copyright (c) 2021, Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ECLITE_DATA_OPREGION_ID 0x9E +#define ECLITE_CMD_OPREGION_ID 0x9F + +#define ECL_MSG_DATA 0x1 +#define ECL_MSG_EVENT 0x2 + +#define ECL_ISH_READ 0x1 +#define ECL_ISH_WRITE 0x2 +#define ECL_ISH_HEADER_VERSION 0 + +#define ECL_CL_RX_RING_SIZE 16 +#define ECL_CL_TX_RING_SIZE 8 + +#define ECL_DATA_OPR_BUFLEN 384 +#define ECL_EVENTS_NOTIFY 333 + +#define cmd_opr_offsetof(element) offsetof(struct opregion_cmd, element) +#define cl_data_to_dev(opr_dev) ishtp_device((opr_dev)->cl_device) + +#ifndef BITS_TO_BYTES +#define BITS_TO_BYTES(x) ((x) / 8) +#endif + +struct opregion_cmd { + unsigned int command; + unsigned int offset; + unsigned int length; + unsigned int event_id; +}; + +struct opregion_data { + char data[ECL_DATA_OPR_BUFLEN]; +}; + +struct opregion_context { + struct opregion_cmd cmd_area; + struct opregion_data data_area; +}; + +struct ecl_message_header { + unsigned int version:2; + unsigned int data_type:2; + unsigned int request_type:2; + unsigned int offset:9; + unsigned int data_len:9; + unsigned int event:8; +}; + +struct ecl_message { + struct ecl_message_header header; + char payload[ECL_DATA_OPR_BUFLEN]; +}; + +struct ishtp_opregion_dev { + struct opregion_context opr_context; + struct ishtp_cl *ecl_ishtp_cl; + struct ishtp_cl_device *cl_device; + struct ishtp_fw_client *fw_client; + struct ishtp_cl_rb *rb; + struct acpi_device *adev; + unsigned int dsm_event_id; + unsigned int ish_link_ready; + unsigned int ish_read_done; + unsigned int acpi_init_done; + wait_queue_head_t read_wait; + struct work_struct event_work; + struct work_struct reset_work; + /* lock for opregion context */ + struct mutex lock; + +}; + +/* eclite ishtp client UUID: 6a19cc4b-d760-4de3-b14d-f25ebd0fbcd9 */ +static const guid_t ecl_ishtp_guid = + GUID_INIT(0x6a19cc4b, 0xd760, 0x4de3, + 0xb1, 0x4d, 0xf2, 0x5e, 0xbd, 0xf, 0xbc, 0xd9); + +/* ACPI DSM UUID: 91d936a7-1f01-49c6-a6b4-72f00ad8d8a5 */ +static const guid_t ecl_acpi_guid = + GUID_INIT(0x91d936a7, 0x1f01, 0x49c6, 0xa6, + 0xb4, 0x72, 0xf0, 0x0a, 0xd8, 0xd8, 0xa5); + +/** + * ecl_ish_cl_read() - Read data from eclite FW + * + * @opr_dev: pointer to opregion device + * + * This function issues a read request to eclite FW and waits until it + * receives a response. When response is received the read data is copied to + * opregion buffer. + */ +static int ecl_ish_cl_read(struct ishtp_opregion_dev *opr_dev) +{ + struct ecl_message_header header; + int len, rv; + + if (!opr_dev->ish_link_ready) + return -EIO; + + if ((opr_dev->opr_context.cmd_area.offset + + opr_dev->opr_context.cmd_area.length) > ECL_DATA_OPR_BUFLEN) { + return -EINVAL; + } + + header.version = ECL_ISH_HEADER_VERSION; + header.data_type = ECL_MSG_DATA; + header.request_type = ECL_ISH_READ; + header.offset = opr_dev->opr_context.cmd_area.offset; + header.data_len = opr_dev->opr_context.cmd_area.length; + header.event = opr_dev->opr_context.cmd_area.event_id; + len = sizeof(header); + + opr_dev->ish_read_done = false; + rv = ishtp_cl_send(opr_dev->ecl_ishtp_cl, (uint8_t *)&header, len); + if (rv) { + dev_err(cl_data_to_dev(opr_dev), "ish-read : send failed\n"); + return -EIO; + } + + dev_dbg(cl_data_to_dev(opr_dev), + "[ish_rd] Req: off : %x, len : %x\n", + header.offset, + header.data_len); + + rv = wait_event_interruptible_timeout(opr_dev->read_wait, + opr_dev->ish_read_done, + 2 * HZ); + if (!rv) { + dev_err(cl_data_to_dev(opr_dev), + "[ish_rd] No response from firmware\n"); + return -EIO; + } + + return 0; +} + +/** + * ecl_ish_cl_write() - This function writes data to eclite FW. + * + * @opr_dev: pointer to opregion device + * + * This function writes data to eclite FW. + */ +static int ecl_ish_cl_write(struct ishtp_opregion_dev *opr_dev) +{ + struct ecl_message message; + int len; + + if (!opr_dev->ish_link_ready) + return -EIO; + + if ((opr_dev->opr_context.cmd_area.offset + + opr_dev->opr_context.cmd_area.length) > ECL_DATA_OPR_BUFLEN) { + return -EINVAL; + } + + message.header.version = ECL_ISH_HEADER_VERSION; + message.header.data_type = ECL_MSG_DATA; + message.header.request_type = ECL_ISH_WRITE; + message.header.offset = opr_dev->opr_context.cmd_area.offset; + message.header.data_len = opr_dev->opr_context.cmd_area.length; + message.header.event = opr_dev->opr_context.cmd_area.event_id; + len = sizeof(struct ecl_message_header) + message.header.data_len; + + memcpy(message.payload, + opr_dev->opr_context.data_area.data + message.header.offset, + message.header.data_len); + + dev_dbg(cl_data_to_dev(opr_dev), + "[ish_wr] off : %x, len : %x\n", + message.header.offset, + message.header.data_len); + + return ishtp_cl_send(opr_dev->ecl_ishtp_cl, (uint8_t *)&message, len); +} + +static acpi_status +ecl_opregion_cmd_handler(u32 function, acpi_physical_address address, + u32 bits, u64 *value64, + void *handler_context, void *region_context) +{ + struct ishtp_opregion_dev *opr_dev; + struct opregion_cmd *cmd; + acpi_status status = AE_OK; + + if (!region_context || !value64) + return AE_BAD_PARAMETER; + + if (function == ACPI_READ) + return AE_ERROR; + + opr_dev = (struct ishtp_opregion_dev *)region_context; + + mutex_lock(&opr_dev->lock); + + cmd = &opr_dev->opr_context.cmd_area; + + switch (address) { + case cmd_opr_offsetof(command): + cmd->command = (u32)*value64; + + if (cmd->command == ECL_ISH_READ) + status = ecl_ish_cl_read(opr_dev); + else if (cmd->command == ECL_ISH_WRITE) + status = ecl_ish_cl_write(opr_dev); + else + status = AE_ERROR; + break; + case cmd_opr_offsetof(offset): + cmd->offset = (u32)*value64; + break; + case cmd_opr_offsetof(length): + cmd->length = (u32)*value64; + break; + case cmd_opr_offsetof(event_id): + cmd->event_id = (u32)*value64; + break; + default: + status = AE_ERROR; + } + + mutex_unlock(&opr_dev->lock); + + return status; +} + +static acpi_status +ecl_opregion_data_handler(u32 function, acpi_physical_address address, + u32 bits, u64 *value64, + void *handler_context, void *region_context) +{ + struct ishtp_opregion_dev *opr_dev; + unsigned int bytes = BITS_TO_BYTES(bits); + void *data_addr; + + if (!region_context || !value64) + return AE_BAD_PARAMETER; + + if (address + bytes > ECL_DATA_OPR_BUFLEN) + return AE_BAD_PARAMETER; + + opr_dev = (struct ishtp_opregion_dev *)region_context; + + mutex_lock(&opr_dev->lock); + + data_addr = &opr_dev->opr_context.data_area.data[address]; + + if (function == ACPI_READ) { + memcpy(value64, data_addr, bytes); + } else if (function == ACPI_WRITE) { + memcpy(data_addr, value64, bytes); + } else { + mutex_unlock(&opr_dev->lock); + return AE_BAD_PARAMETER; + } + + mutex_unlock(&opr_dev->lock); + + return AE_OK; +} + +static int acpi_find_eclite_device(struct ishtp_opregion_dev *opr_dev) +{ + struct acpi_device *adev; + + /* Find ECLite device and save reference */ + adev = acpi_dev_get_first_match_dev("INTC1035", NULL, -1); + if (!adev) { + dev_err(cl_data_to_dev(opr_dev), "eclite ACPI device not found\n"); + return -ENODEV; + } + + opr_dev->adev = adev; + + return 0; +} + +static int acpi_opregion_init(struct ishtp_opregion_dev *opr_dev) +{ + acpi_status status; + + status = acpi_install_address_space_handler(opr_dev->adev->handle, + ECLITE_CMD_OPREGION_ID, + ecl_opregion_cmd_handler, + NULL, opr_dev); + if (ACPI_FAILURE(status)) { + dev_err(cl_data_to_dev(opr_dev), + "cmd space handler install failed\n"); + return -ENODEV; + } + + status = acpi_install_address_space_handler(opr_dev->adev->handle, + ECLITE_DATA_OPREGION_ID, + ecl_opregion_data_handler, + NULL, opr_dev); + if (ACPI_FAILURE(status)) { + dev_err(cl_data_to_dev(opr_dev), + "data space handler install failed\n"); + + acpi_remove_address_space_handler(opr_dev->adev->handle, + ECLITE_CMD_OPREGION_ID, + ecl_opregion_cmd_handler); + return -ENODEV; + } + opr_dev->acpi_init_done = true; + + dev_dbg(cl_data_to_dev(opr_dev), "Opregion handlers are installed\n"); + + return 0; +} + +static void acpi_opregion_deinit(struct ishtp_opregion_dev *opr_dev) +{ + acpi_remove_address_space_handler(opr_dev->adev->handle, + ECLITE_CMD_OPREGION_ID, + ecl_opregion_cmd_handler); + + acpi_remove_address_space_handler(opr_dev->adev->handle, + ECLITE_DATA_OPREGION_ID, + ecl_opregion_data_handler); + opr_dev->acpi_init_done = false; +} + +static void ecl_acpi_invoke_dsm(struct work_struct *work) +{ + struct ishtp_opregion_dev *opr_dev; + union acpi_object *obj; + + opr_dev = container_of(work, struct ishtp_opregion_dev, event_work); + if (!opr_dev->acpi_init_done) + return; + + obj = acpi_evaluate_dsm(opr_dev->adev->handle, &ecl_acpi_guid, 0, + opr_dev->dsm_event_id, NULL); + if (!obj) { + dev_warn(cl_data_to_dev(opr_dev), "_DSM fn call failed\n"); + return; + } + + dev_dbg(cl_data_to_dev(opr_dev), "Exec DSM function code: %d success\n", + opr_dev->dsm_event_id); + + ACPI_FREE(obj); +} + +static void ecl_ish_process_rx_data(struct ishtp_opregion_dev *opr_dev) +{ + struct ecl_message *message = + (struct ecl_message *)opr_dev->rb->buffer.data; + + dev_dbg(cl_data_to_dev(opr_dev), + "[ish_rd] Resp: off : %x, len : %x\n", + message->header.offset, + message->header.data_len); + + if ((message->header.offset + message->header.data_len) > + ECL_DATA_OPR_BUFLEN) { + return; + } + + memcpy(opr_dev->opr_context.data_area.data + message->header.offset, + message->payload, message->header.data_len); + + opr_dev->ish_read_done = true; + wake_up_interruptible(&opr_dev->read_wait); +} + +static void ecl_ish_process_rx_event(struct ishtp_opregion_dev *opr_dev) +{ + struct ecl_message_header *header = + (struct ecl_message_header *)opr_dev->rb->buffer.data; + + dev_dbg(cl_data_to_dev(opr_dev), + "[ish_ev] Evt received: %8x\n", header->event); + + opr_dev->dsm_event_id = header->event; + schedule_work(&opr_dev->event_work); +} + +static int ecl_ish_cl_enable_events(struct ishtp_opregion_dev *opr_dev, + bool config_enable) +{ + struct ecl_message message; + int len; + + message.header.version = ECL_ISH_HEADER_VERSION; + message.header.data_type = ECL_MSG_DATA; + message.header.request_type = ECL_ISH_WRITE; + message.header.offset = ECL_EVENTS_NOTIFY; + message.header.data_len = 1; + message.payload[0] = config_enable; + + len = sizeof(struct ecl_message_header) + message.header.data_len; + + return ishtp_cl_send(opr_dev->ecl_ishtp_cl, (uint8_t *)&message, len); +} + +static void ecl_ishtp_cl_event_cb(struct ishtp_cl_device *cl_device) +{ + struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device); + struct ishtp_opregion_dev *opr_dev; + struct ecl_message_header *header; + struct ishtp_cl_rb *rb; + + opr_dev = ishtp_get_client_data(ecl_ishtp_cl); + while ((rb = ishtp_cl_rx_get_rb(opr_dev->ecl_ishtp_cl)) != NULL) { + opr_dev->rb = rb; + header = (struct ecl_message_header *)rb->buffer.data; + + if (header->data_type == ECL_MSG_DATA) + ecl_ish_process_rx_data(opr_dev); + else if (header->data_type == ECL_MSG_EVENT) + ecl_ish_process_rx_event(opr_dev); + else + /* Got an event with wrong data_type, ignore it */ + dev_err(cl_data_to_dev(opr_dev), + "[ish_cb] Received wrong data_type\n"); + + ishtp_cl_io_rb_recycle(rb); + } +} + +static int ecl_ishtp_cl_init(struct ishtp_cl *ecl_ishtp_cl) +{ + struct ishtp_opregion_dev *opr_dev = + ishtp_get_client_data(ecl_ishtp_cl); + struct ishtp_fw_client *fw_client; + struct ishtp_device *dev; + int rv; + + rv = ishtp_cl_link(ecl_ishtp_cl); + if (rv) { + dev_err(cl_data_to_dev(opr_dev), "ishtp_cl_link failed\n"); + return rv; + } + + dev = ishtp_get_ishtp_device(ecl_ishtp_cl); + + /* Connect to FW client */ + ishtp_set_tx_ring_size(ecl_ishtp_cl, ECL_CL_TX_RING_SIZE); + ishtp_set_rx_ring_size(ecl_ishtp_cl, ECL_CL_RX_RING_SIZE); + + fw_client = ishtp_fw_cl_get_client(dev, &ecl_ishtp_guid); + if (!fw_client) { + dev_err(cl_data_to_dev(opr_dev), "fw client not found\n"); + return -ENOENT; + } + + ishtp_cl_set_fw_client_id(ecl_ishtp_cl, + ishtp_get_fw_client_id(fw_client)); + + ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_CONNECTING); + + rv = ishtp_cl_connect(ecl_ishtp_cl); + if (rv) { + dev_err(cl_data_to_dev(opr_dev), "client connect failed\n"); + + ishtp_cl_unlink(ecl_ishtp_cl); + return rv; + } + + dev_dbg(cl_data_to_dev(opr_dev), "Host connected to fw client\n"); + + return 0; +} + +static void ecl_ishtp_cl_deinit(struct ishtp_cl *ecl_ishtp_cl) +{ + ishtp_cl_unlink(ecl_ishtp_cl); + ishtp_cl_flush_queues(ecl_ishtp_cl); + ishtp_cl_free(ecl_ishtp_cl); +} + +static void ecl_ishtp_cl_reset_handler(struct work_struct *work) +{ + struct ishtp_opregion_dev *opr_dev; + struct ishtp_cl_device *cl_device; + struct ishtp_cl *ecl_ishtp_cl; + int rv; + int retry; + + opr_dev = container_of(work, struct ishtp_opregion_dev, reset_work); + + opr_dev->ish_link_ready = false; + + cl_device = opr_dev->cl_device; + ecl_ishtp_cl = opr_dev->ecl_ishtp_cl; + + ecl_ishtp_cl_deinit(ecl_ishtp_cl); + + ecl_ishtp_cl = ishtp_cl_allocate(cl_device); + if (!ecl_ishtp_cl) + return; + + ishtp_set_drvdata(cl_device, ecl_ishtp_cl); + ishtp_set_client_data(ecl_ishtp_cl, opr_dev); + + opr_dev->ecl_ishtp_cl = ecl_ishtp_cl; + + for (retry = 0; retry < 3; ++retry) { + rv = ecl_ishtp_cl_init(ecl_ishtp_cl); + if (!rv) + break; + } + if (rv) { + ishtp_cl_free(ecl_ishtp_cl); + opr_dev->ecl_ishtp_cl = NULL; + dev_err(cl_data_to_dev(opr_dev), + "[ish_rst] Reset failed. Link not ready.\n"); + return; + } + + ishtp_register_event_cb(cl_device, ecl_ishtp_cl_event_cb); + dev_info(cl_data_to_dev(opr_dev), + "[ish_rst] Reset Success. Link ready.\n"); + + opr_dev->ish_link_ready = true; + + if (opr_dev->acpi_init_done) + return; + + rv = acpi_opregion_init(opr_dev); + if (rv) { + dev_err(cl_data_to_dev(opr_dev), + "ACPI opregion init failed\n"); + } +} + +static int ecl_ishtp_cl_probe(struct ishtp_cl_device *cl_device) +{ + struct ishtp_cl *ecl_ishtp_cl; + struct ishtp_opregion_dev *opr_dev; + int rv; + + opr_dev = devm_kzalloc(ishtp_device(cl_device), sizeof(*opr_dev), + GFP_KERNEL); + if (!opr_dev) + return -ENOMEM; + + ecl_ishtp_cl = ishtp_cl_allocate(cl_device); + if (!ecl_ishtp_cl) + return -ENOMEM; + + ishtp_set_drvdata(cl_device, ecl_ishtp_cl); + ishtp_set_client_data(ecl_ishtp_cl, opr_dev); + opr_dev->ecl_ishtp_cl = ecl_ishtp_cl; + opr_dev->cl_device = cl_device; + + init_waitqueue_head(&opr_dev->read_wait); + INIT_WORK(&opr_dev->event_work, ecl_acpi_invoke_dsm); + INIT_WORK(&opr_dev->reset_work, ecl_ishtp_cl_reset_handler); + + /* Initialize ish client device */ + rv = ecl_ishtp_cl_init(ecl_ishtp_cl); + if (rv) { + dev_err(cl_data_to_dev(opr_dev), "Client init failed\n"); + goto err_exit; + } + + dev_dbg(cl_data_to_dev(opr_dev), "eclite-ishtp client initialised\n"); + + opr_dev->ish_link_ready = true; + mutex_init(&opr_dev->lock); + + rv = acpi_find_eclite_device(opr_dev); + if (rv) { + dev_err(cl_data_to_dev(opr_dev), "ECLite ACPI ID not found\n"); + goto err_exit; + } + + /* Register a handler for eclite fw events */ + ishtp_register_event_cb(cl_device, ecl_ishtp_cl_event_cb); + + /* Now init opregion handlers */ + rv = acpi_opregion_init(opr_dev); + if (rv) { + dev_err(cl_data_to_dev(opr_dev), "ACPI opregion init failed\n"); + goto err_exit; + } + + /* Reprobe devices depending on ECLite - battery, fan, etc. */ + acpi_dev_clear_dependencies(opr_dev->adev); + + return 0; +err_exit: + ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_DISCONNECTING); + ishtp_cl_disconnect(ecl_ishtp_cl); + ecl_ishtp_cl_deinit(ecl_ishtp_cl); + + return rv; +} + +static void ecl_ishtp_cl_remove(struct ishtp_cl_device *cl_device) +{ + struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device); + struct ishtp_opregion_dev *opr_dev = + ishtp_get_client_data(ecl_ishtp_cl); + + if (opr_dev->acpi_init_done) + acpi_opregion_deinit(opr_dev); + + acpi_dev_put(opr_dev->adev); + + ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_DISCONNECTING); + ishtp_cl_disconnect(ecl_ishtp_cl); + ecl_ishtp_cl_deinit(ecl_ishtp_cl); + + cancel_work_sync(&opr_dev->reset_work); + cancel_work_sync(&opr_dev->event_work); +} + +static int ecl_ishtp_cl_reset(struct ishtp_cl_device *cl_device) +{ + struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device); + struct ishtp_opregion_dev *opr_dev = + ishtp_get_client_data(ecl_ishtp_cl); + + schedule_work(&opr_dev->reset_work); + + return 0; +} + +static int ecl_ishtp_cl_suspend(struct device *device) +{ + struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device); + struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device); + struct ishtp_opregion_dev *opr_dev = + ishtp_get_client_data(ecl_ishtp_cl); + + if (acpi_target_system_state() == ACPI_STATE_S0) + return 0; + + acpi_opregion_deinit(opr_dev); + ecl_ish_cl_enable_events(opr_dev, false); + + return 0; +} + +static int ecl_ishtp_cl_resume(struct device *device) +{ + /* A reset is expected to call after an Sx. At this point + * we are not sure if the link is up or not to restore anything, + * so do nothing in resume path + */ + return 0; +} + +static const struct dev_pm_ops ecl_ishtp_pm_ops = { + .suspend = ecl_ishtp_cl_suspend, + .resume = ecl_ishtp_cl_resume, +}; + +static struct ishtp_cl_driver ecl_ishtp_cl_driver = { + .name = "ishtp-eclite", + .guid = &ecl_ishtp_guid, + .probe = ecl_ishtp_cl_probe, + .remove = ecl_ishtp_cl_remove, + .reset = ecl_ishtp_cl_reset, + .driver.pm = &ecl_ishtp_pm_ops, +}; + +static int __init ecl_ishtp_init(void) +{ + return ishtp_cl_driver_register(&ecl_ishtp_cl_driver, THIS_MODULE); +} + +static void __exit ecl_ishtp_exit(void) +{ + return ishtp_cl_driver_unregister(&ecl_ishtp_cl_driver); +} + +late_initcall(ecl_ishtp_init); +module_exit(ecl_ishtp_exit); + +MODULE_DESCRIPTION("ISH ISHTP eclite client opregion driver"); +MODULE_AUTHOR("K Naduvalath, Sumesh "); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("ishtp:*"); From 9cfe02023cf67a36c2dfb05d1ea3eb79811a8720 Mon Sep 17 00:00:00 2001 From: Sanket Goswami Date: Thu, 16 Sep 2021 18:11:30 +0530 Subject: [PATCH 033/106] platform/x86: amd-pmc: Check s0i3 cycle status As the PM firmware returns the status of the last s0i3 in the smu_metrics structure, the existing name "s0i3_cyclecount" seems to be a misnomer. Change it accordingly to "s0i3_last_entry_status". Signed-off-by: Sanket Goswami Acked-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20210916124130.2581-1-Sanket.Goswami@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index d6a7c896ac86..8c2016e02470 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -133,7 +133,7 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3 struct smu_metrics { u32 table_version; u32 hint_count; - u32 s0i3_cyclecount; + u32 s0i3_last_entry_status; u32 timein_s0i2; u64 timeentering_s0i3_lastcapture; u64 timeentering_s0i3_totaltime; @@ -162,7 +162,8 @@ static int smu_fw_info_show(struct seq_file *s, void *unused) seq_puts(s, "\n=== SMU Statistics ===\n"); seq_printf(s, "Table Version: %d\n", table.table_version); seq_printf(s, "Hint Count: %d\n", table.hint_count); - seq_printf(s, "S0i3 Cycle Count: %d\n", table.s0i3_cyclecount); + seq_printf(s, "Last S0i3 Status: %s\n", table.s0i3_last_entry_status ? "Success" : + "Unknown/Fail"); seq_printf(s, "Time (in us) to S0i3: %lld\n", table.timeentering_s0i3_lastcapture); seq_printf(s, "Time (in us) in S0i3: %lld\n", table.timein_s0i3_lastcapture); From f6045de1f53268131ea75a99b210b869dcc150b2 Mon Sep 17 00:00:00 2001 From: Sanket Goswami Date: Thu, 16 Sep 2021 18:10:02 +0530 Subject: [PATCH 034/106] platform/x86: amd-pmc: Export Idlemask values based on the APU IdleMask is the metric used by the PM firmware to know the status of each of the Hardware IP blocks monitored by the PM firmware. Knowing this value is key to get the information of s2idle suspend/resume status. This value is mapped to PMC scratch registers, retrieve them accordingly based on the CPU family and the underlying firmware support. Co-developed-by: Shyam Sundar S K Signed-off-by: Shyam Sundar S K Signed-off-by: Sanket Goswami Reviewed-by: Mario Limonciello Link: https://lore.kernel.org/r/20210916124002.2529-1-Sanket.Goswami@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index 8c2016e02470..1303366c31af 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -29,6 +29,10 @@ #define AMD_PMC_REGISTER_RESPONSE 0x980 #define AMD_PMC_REGISTER_ARGUMENT 0x9BC +/* PMC Scratch Registers */ +#define AMD_PMC_SCRATCH_REG_CZN 0x94 +#define AMD_PMC_SCRATCH_REG_YC 0xD14 + /* Base address of SMU for mapping physical address to virtual address */ #define AMD_PMC_SMU_INDEX_ADDRESS 0xB8 #define AMD_PMC_SMU_INDEX_DATA 0xBC @@ -110,6 +114,10 @@ struct amd_pmc_dev { u32 base_addr; u32 cpu_id; u32 active_ips; +/* SMU version information */ + u16 major; + u16 minor; + u16 rev; struct device *dev; struct mutex lock; /* generic mutex lock */ #if IS_ENABLED(CONFIG_DEBUG_FS) @@ -202,6 +210,66 @@ 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->major = (val >> 16) & GENMASK(15, 0); + dev->minor = (val >> 8) & GENMASK(7, 0); + dev->rev = (val >> 0) & GENMASK(7, 0); + + dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev); + + return 0; +} + +static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, + struct seq_file *s) +{ + u32 val; + + switch (pdev->cpu_id) { + case AMD_CPU_ID_CZN: + val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN); + break; + case AMD_CPU_ID_YC: + val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC); + break; + default: + return -EINVAL; + } + + if (dev) + dev_dbg(pdev->dev, "SMU idlemask s0i3: 0x%x\n", val); + + if (s) + seq_printf(s, "SMU idlemask : 0x%x\n", val); + + return 0; +} + +static int amd_pmc_idlemask_show(struct seq_file *s, void *unused) +{ + struct amd_pmc_dev *dev = s->private; + int rc; + + if (dev->major > 56 || (dev->major >= 55 && dev->minor >= 37)) { + rc = amd_pmc_idlemask_read(dev, NULL, s); + if (rc) + return rc; + } else { + seq_puts(s, "Unsupported SMU version for Idlemask\n"); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(amd_pmc_idlemask); + static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) { debugfs_remove_recursive(dev->dbgfs_dir); @@ -214,6 +282,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) &smu_fw_info_fops); debugfs_create_file("s0ix_stats", 0644, dev->dbgfs_dir, dev, &s0ix_stats_fops); + debugfs_create_file("amd_pmc_idlemask", 0644, dev->dbgfs_dir, dev, + &amd_pmc_idlemask_fops); } #else static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) @@ -350,6 +420,8 @@ static int __maybe_unused amd_pmc_suspend(struct device *dev) amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0); amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0); + /* Dump the IdleMask before we send hint to SMU */ + amd_pmc_idlemask_read(pdev, dev, NULL); msg = amd_pmc_get_os_hint(pdev); rc = amd_pmc_send_cmd(pdev, 1, NULL, msg, 0); if (rc) @@ -372,6 +444,9 @@ static int __maybe_unused amd_pmc_resume(struct device *dev) if (rc) dev_err(pdev->dev, "resume failed\n"); + /* Dump the IdleMask to see the blockers */ + amd_pmc_idlemask_read(pdev, dev, NULL); + return 0; } @@ -458,6 +533,7 @@ static int amd_pmc_probe(struct platform_device *pdev) if (err) dev_err(dev->dev, "SMU debugging info not supported on this platform\n"); + amd_pmc_get_smu_version(dev); platform_set_drvdata(pdev, dev); amd_pmc_dbgfs_register(dev); return 0; From 8f84a3973c6a2b714b7a494a3568ef8866f81058 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 19:00:53 +0200 Subject: [PATCH 035/106] platform: lg-laptop: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for ACPI driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210916170054.136790-1-krzysztof.kozlowski@canonical.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/lg-laptop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index 88b551caeaaf..7e9351c36389 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -60,7 +60,6 @@ MODULE_ALIAS("wmi:" WMI_EVENT_GUID2); MODULE_ALIAS("wmi:" WMI_EVENT_GUID3); MODULE_ALIAS("wmi:" WMI_METHOD_WMAB); MODULE_ALIAS("wmi:" WMI_METHOD_WMBB); -MODULE_ALIAS("acpi*:LGEX0815:*"); static struct platform_device *pf_device; static struct input_dev *wmi_input_dev; From d24236cb7cf2319d47fac2bed458b6d4eae76b24 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 17 Sep 2021 21:48:29 -0700 Subject: [PATCH 036/106] platform/x86: dell: fix DELL_WMI_PRIVACY dependencies & build error When DELL_WMI=y, DELL_WMI_PRIVACY=y, and LEDS_TRIGGER_AUDIO=m, there is a linker error since the LEDS trigger code is built as a loadable module. This happens because DELL_WMI_PRIVACY is a bool that depends on a tristate (LEDS_TRIGGER_AUDIO=m), which can be dangerous. ld: drivers/platform/x86/dell/dell-wmi-privacy.o: in function `dell_privacy_wmi_probe': dell-wmi-privacy.c:(.text+0x3df): undefined reference to `ledtrig_audio_get' Fixes: 8af9fa37b8a3 ("platform/x86: dell-privacy: Add support for Dell hardware privacy") Signed-off-by: Randy Dunlap Cc: Perry Yuan Cc: Dell.Client.Kernel@dell.com Cc: platform-driver-x86@vger.kernel.org Cc: Hans de Goede Cc: Mark Gross Link: https://lore.kernel.org/r/20210918044829.19222-1-rdunlap@infradead.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index 821aba31821c..42513eab1d06 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -166,8 +166,7 @@ config DELL_WMI config DELL_WMI_PRIVACY bool "Dell WMI Hardware Privacy Support" - depends on DELL_WMI - depends on LEDS_TRIGGER_AUDIO + depends on LEDS_TRIGGER_AUDIO = y || DELL_WMI = LEDS_TRIGGER_AUDIO help This option adds integration with the "Dell Hardware Privacy" feature of Dell laptops to the dell-wmi driver. From cf5585f92164c0395afea3038b0b4f2201fe8e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Mon, 20 Sep 2021 18:03:12 +0200 Subject: [PATCH 037/106] platform/x86/intel: hid: Add DMI switches allow list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices, even non convertible ones, can send incorrect SW_TABLET_MODE reports. Add an allow list and accept such reports only from devices in it. Bug reported for Dell XPS 17 9710 on: https://gitlab.freedesktop.org/libinput/libinput/-/issues/662 Reported-by: Tobias Gurtzick Suggested-by: Hans de Goede Tested-by: Tobias Gurtzick Signed-off-by: José Expósito Link: https://lore.kernel.org/r/20210920160312.9787-1-jose.exposito89@gmail.com [hdegoede@redhat.com: Check dmi_switches_auto_add_allow_list only once] Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/hid.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c index a33a5826e81a..08598942a6d7 100644 --- a/drivers/platform/x86/intel/hid.c +++ b/drivers/platform/x86/intel/hid.c @@ -118,12 +118,30 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = { { } }; +/* + * Some devices, even non convertible ones, can send incorrect SW_TABLET_MODE + * reports. Accept such reports only from devices in this list. + */ +static const struct dmi_system_id dmi_auto_add_switch[] = { + { + .matches = { + DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "31" /* Convertible */), + }, + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "32" /* Detachable */), + }, + }, + {} /* Array terminator */ +}; + struct intel_hid_priv { struct input_dev *input_dev; struct input_dev *array; struct input_dev *switches; bool wakeup_mode; - bool dual_accel; + bool auto_add_switch; }; #define HID_EVENT_FILTER_UUID "eeec56b3-4442-408f-a792-4edd4d758054" @@ -452,10 +470,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) * Some convertible have unreliable VGBS return which could cause incorrect * SW_TABLET_MODE report, in these cases we enable support when receiving * the first event instead of during driver setup. - * - * See dual_accel_detect.h for more info on the dual_accel check. */ - if (!priv->switches && !priv->dual_accel && (event == 0xcc || event == 0xcd)) { + if (!priv->switches && priv->auto_add_switch && (event == 0xcc || event == 0xcd)) { dev_info(&device->dev, "switch event received, enable switches supports\n"); err = intel_hid_switches_setup(device); if (err) @@ -596,7 +612,8 @@ static int intel_hid_probe(struct platform_device *device) return -ENOMEM; dev_set_drvdata(&device->dev, priv); - priv->dual_accel = dual_accel_detect(); + /* See dual_accel_detect.h for more info on the dual_accel check. */ + priv->auto_add_switch = dmi_check_system(dmi_auto_add_switch) && !dual_accel_detect(); err = intel_hid_input_setup(device); if (err) { From 6ffd9639382f2acff671c3de2e9cb3875fbf7e5d Mon Sep 17 00:00:00 2001 From: Tobias Jakobi Date: Tue, 21 Sep 2021 12:07:02 +0200 Subject: [PATCH 038/106] platform/x86: gigabyte-wmi: add support for B550I Aorus Pro AX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested with a AMD Ryzen 7 5800X. Signed-off-by: Tobias Jakobi Acked-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20210921100702.3838-1-tjakobi@math.uni-bielefeld.de Signed-off-by: Hans de Goede --- drivers/platform/x86/gigabyte-wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c index 7f3a03f937f6..d53634c8a6e0 100644 --- a/drivers/platform/x86/gigabyte-wmi.c +++ b/drivers/platform/x86/gigabyte-wmi.c @@ -144,6 +144,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE V2"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 GAMING X V2"), + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550I AORUS PRO AX"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"), From 5fbd827eb9c224c33a5f263ee543a75fe957faa3 Mon Sep 17 00:00:00 2001 From: Troy Rollo Date: Sat, 18 Sep 2021 17:31:30 +1000 Subject: [PATCH 039/106] platform/x86: dell-wmi: Recognise or support new switches Adds support for: - Dell Inspiron 2in1 tablet mode switch notifications. These are delivered by a type 0x0011 message with code 0xe070, followed by a flag (1 for laptop mode, 0 for tablet mode). - Recognising (but not otherwise processing) the Dell Ultra Performance mode request switch. This is delivered by a type 0x0012 message with code 0x000d, followed by a parameter that is either 1 or 2. It is not clear what (if anything) should be done with this notification, so it is ignored. Signed-off-by: Troy Rollo Link: https://lore.kernel.org/r/20210918073131.2966942-1-linux2021@troy.rollo.name Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-base.c | 76 ++++++++++++++++++++--- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c index 089c125e18f7..e07d3ba85a3f 100644 --- a/drivers/platform/x86/dell/dell-wmi-base.c +++ b/drivers/platform/x86/dell/dell-wmi-base.c @@ -40,6 +40,7 @@ static bool wmi_requires_smbios_request; struct dell_wmi_priv { struct input_dev *input_dev; + struct input_dev *tabletswitch_dev; u32 interface_version; }; @@ -309,6 +310,9 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = { * Keymap for WMI events of type 0x0011 */ static const struct key_entry dell_wmi_keymap_type_0011[] = { + /* Reflex keyboard switch on 2n1 devices */ + { KE_IGNORE, 0xe070, { KEY_RESERVED } }, + /* Battery unplugged */ { KE_IGNORE, 0xfff0, { KEY_RESERVED } }, @@ -340,21 +344,55 @@ 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[] = { + /* Ultra-performance mode switch request */ + { KE_IGNORE, 0x000d, { KEY_RESERVED } }, + /* Fn-lock button pressed */ { KE_IGNORE, 0xe035, { KEY_RESERVED } }, }; -static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code) +static void dell_wmi_switch_event(struct input_dev **subdev, + const char *devname, + int switchid, + int value) +{ + if (!*subdev) { + struct input_dev *dev = input_allocate_device(); + + if (!dev) { + pr_warn("could not allocate device for %s\n", devname); + return; + } + __set_bit(EV_SW, (dev)->evbit); + __set_bit(switchid, (dev)->swbit); + + (dev)->name = devname; + (dev)->id.bustype = BUS_HOST; + if (input_register_device(dev)) { + input_free_device(dev); + pr_warn("could not register device for %s\n", devname); + return; + } + *subdev = dev; + } + + input_report_switch(*subdev, switchid, value); + input_sync(*subdev); +} + +static int dell_wmi_process_key(struct wmi_device *wdev, int type, int code, u16 *buffer, int remaining) { struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); const struct key_entry *key; + int used = 0; + int value = 1; key = sparse_keymap_entry_from_scancode(priv->input_dev, (type << 16) | code); if (!key) { pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n", type, code); - return; + return 0; } pr_debug("Key with type 0x%04x and code 0x%04x pressed\n", type, code); @@ -363,16 +401,27 @@ static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code) if ((key->keycode == KEY_BRIGHTNESSUP || key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video_handles_brightness_key_presses()) - return; + return 0; if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request) - return; + return 0; - if (key->keycode == KEY_KBDILLUMTOGGLE) + if (key->keycode == KEY_KBDILLUMTOGGLE) { dell_laptop_call_notifier( DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL); + } else if (type == 0x0011 && code == 0xe070 && remaining > 0) { + dell_wmi_switch_event(&priv->tabletswitch_dev, + "Dell tablet mode switch", + SW_TABLET_MODE, !buffer[0]); + return 1; + } else if (type == 0x0012 && code == 0x000d && remaining > 0) { + value = (buffer[2] == 2); + used = 1; + } - sparse_keymap_report_entry(priv->input_dev, key, 1, true); + sparse_keymap_report_entry(priv->input_dev, key, value, true); + + return used; } static void dell_wmi_notify(struct wmi_device *wdev, @@ -430,21 +479,26 @@ static void dell_wmi_notify(struct wmi_device *wdev, case 0x0000: /* One key pressed or event occurred */ if (len > 2) dell_wmi_process_key(wdev, buffer_entry[1], - buffer_entry[2]); + buffer_entry[2], + buffer_entry + 3, + len - 3); /* Extended data is currently ignored */ break; case 0x0010: /* Sequence of keys pressed */ case 0x0011: /* Sequence of events occurred */ for (i = 2; i < len; ++i) - dell_wmi_process_key(wdev, buffer_entry[1], - buffer_entry[i]); + i += dell_wmi_process_key(wdev, buffer_entry[1], + buffer_entry[i], + buffer_entry + i, + len - i - 1); break; case 0x0012: if ((len > 4) && dell_privacy_process_event(buffer_entry[1], buffer_entry[3], buffer_entry[4])) /* dell_privacy_process_event has handled the event */; else if (len > 2) - dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2]); + dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2], + buffer_entry + 3, len - 3); break; default: /* Unknown event */ pr_info("Unknown WMI event type 0x%x\n", @@ -661,6 +715,8 @@ static void dell_wmi_input_destroy(struct wmi_device *wdev) struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); input_unregister_device(priv->input_dev); + if (priv->tabletswitch_dev) + input_unregister_device(priv->tabletswitch_dev); } /* From 40635cd32f0d83573a558dc30e9ba3469e769249 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 28 Sep 2021 16:16:06 +0200 Subject: [PATCH 040/106] platform/x86: amd-pmc: Fix compilation when CONFIG_DEBUGFS is disabled The amd_pmc_get_smu_version() and amd_pmc_idlemask_read() functions are used in the probe / suspend/resume code, so they are also used when CONFIG_DEBUGFS is disabled, move them outside of the #ifdef CONFIG_DEBUGFS block. Note this purely moves the code to above the #ifdef CONFIG_DEBUGFS, the code is completely unchanged. Fixes: f6045de1f532 ("platform/x86: amd-pmc: Export Idlemask values based on the APU") Cc: Shyam Sundar S K Cc: Sanket Goswami Reported-by: Nathan Chancellor Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 86 +++++++++++++++++----------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index 1303366c31af..f185c43bbaa4 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -155,6 +155,49 @@ struct smu_metrics { u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX]; } __packed; +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->major = (val >> 16) & GENMASK(15, 0); + dev->minor = (val >> 8) & GENMASK(7, 0); + dev->rev = (val >> 0) & GENMASK(7, 0); + + dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev); + + return 0; +} + +static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, + struct seq_file *s) +{ + u32 val; + + switch (pdev->cpu_id) { + case AMD_CPU_ID_CZN: + val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN); + break; + case AMD_CPU_ID_YC: + val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC); + break; + default: + return -EINVAL; + } + + if (dev) + dev_dbg(pdev->dev, "SMU idlemask s0i3: 0x%x\n", val); + + if (s) + seq_printf(s, "SMU idlemask : 0x%x\n", val); + + return 0; +} + #ifdef CONFIG_DEBUG_FS static int smu_fw_info_show(struct seq_file *s, void *unused) { @@ -210,49 +253,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->major = (val >> 16) & GENMASK(15, 0); - dev->minor = (val >> 8) & GENMASK(7, 0); - dev->rev = (val >> 0) & GENMASK(7, 0); - - dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev); - - return 0; -} - -static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, - struct seq_file *s) -{ - u32 val; - - switch (pdev->cpu_id) { - case AMD_CPU_ID_CZN: - val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN); - break; - case AMD_CPU_ID_YC: - val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC); - break; - default: - return -EINVAL; - } - - if (dev) - dev_dbg(pdev->dev, "SMU idlemask s0i3: 0x%x\n", val); - - if (s) - seq_printf(s, "SMU idlemask : 0x%x\n", val); - - return 0; -} - static int amd_pmc_idlemask_show(struct seq_file *s, void *unused) { struct amd_pmc_dev *dev = s->private; From 9c93f8f4fc8cd938bc0ee8d121809c6941e03347 Mon Sep 17 00:00:00 2001 From: Sanket Goswami Date: Tue, 21 Sep 2021 17:29:10 +0530 Subject: [PATCH 041/106] platform/x86: amd-pmc: Send command to dump data after clearing OS_HINT It was reported that the resume stats received from the firmware are always zero. This happens because the SMU expects the driver to send the command to dump the log data after clearing the OS_HINT. Adjust the order of the commands sent to SMU. Signed-off-by: Shyam Sundar S K Signed-off-by: Sanket Goswami Link: https://lore.kernel.org/r/20210921115910.19401-1-Sanket.Goswami@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index f185c43bbaa4..d4d2ba886f4e 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -436,14 +436,14 @@ static int __maybe_unused amd_pmc_resume(struct device *dev) int rc; u8 msg; - /* Let SMU know that we are looking for stats */ - amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0); - msg = amd_pmc_get_os_hint(pdev); rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, 0); if (rc) dev_err(pdev->dev, "resume failed\n"); + /* 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, dev, NULL); From 7dbcaf743df5a0b51694c9b070e30d702fdb3fe6 Mon Sep 17 00:00:00 2001 From: Sanket Goswami Date: Tue, 21 Sep 2021 17:30:20 +0530 Subject: [PATCH 042/106] platform/x86: amd-pmc: Add a message to print resume time info Add a message to print the resume time information obtained from the smu_metrics structure. Signed-off-by: Shyam Sundar S K Signed-off-by: Sanket Goswami Link: https://lore.kernel.org/r/20210921120020.19454-1-Sanket.Goswami@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index d4d2ba886f4e..548432a2ea65 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -217,6 +217,8 @@ static int smu_fw_info_show(struct seq_file *s, void *unused) "Unknown/Fail"); seq_printf(s, "Time (in us) to S0i3: %lld\n", table.timeentering_s0i3_lastcapture); seq_printf(s, "Time (in us) in S0i3: %lld\n", table.timein_s0i3_lastcapture); + seq_printf(s, "Time (in us) to resume from S0i3: %lld\n", + table.timeto_resume_to_os_lastcapture); seq_puts(s, "\n=== Active time (in us) ===\n"); for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx++) { From 6a684635478c03db92727c9fa217c660f6c3abc3 Mon Sep 17 00:00:00 2001 From: Mark Gross Date: Tue, 21 Sep 2021 06:53:58 -0700 Subject: [PATCH 043/106] update email addresses. Change all email addresses for Mark Gross to use markgross@kernel.org. Signed-off-by: Mark Gross Link: https://lore.kernel.org/r/20210921135358.85143-1-markgross@kernel.org Signed-off-by: Hans de Goede --- MAINTAINERS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 949eb8ce6e72..db8186530b0b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6683,7 +6683,7 @@ S: Supported F: drivers/edac/dmc520_edac.c EDAC-E752X -M: Mark Gross +M: Mark Gross L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/e752x_edac.c @@ -11985,7 +11985,7 @@ F: drivers/net/ethernet/mellanox/mlxfw/ MELLANOX HARDWARE PLATFORM SUPPORT M: Hans de Goede -M: Mark Gross +M: Mark Gross M: Vadim Pasternak L: platform-driver-x86@vger.kernel.org S: Supported @@ -12437,7 +12437,7 @@ F: drivers/platform/surface/surface_gpe.c MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT M: Hans de Goede -M: Mark Gross +M: Mark Gross M: Maximilian Luz L: platform-driver-x86@vger.kernel.org S: Maintained @@ -18465,7 +18465,7 @@ S: Supported F: drivers/net/ethernet/tehuti/* TELECOM CLOCK DRIVER FOR MCPL0010 -M: Mark Gross +M: Mark Gross S: Supported F: drivers/char/tlclk.c @@ -20387,7 +20387,7 @@ F: arch/x86/mm/ X86 PLATFORM DRIVERS M: Hans de Goede -M: Mark Gross +M: Mark Gross L: platform-driver-x86@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git From 599482c58ebd007f24f8eba99fbda5d957e773e5 Mon Sep 17 00:00:00 2001 From: Kelly Anderson Date: Sat, 25 Sep 2021 22:39:00 -0600 Subject: [PATCH 044/106] platform/x86: ideapad-laptop: Add platform support for Ideapad 5 Pro 16ACH6-82L5 Adding support specifically for Ideapad 5 Pro 16ACH6-82L5 by adding a allow list that can validate notebooks for which dytc_version is less than 5, and seem to work fine at dytc_version 4. This code has been tested to work properly on the specified system. Signed-off-by: Kelly Anderson Link: https://lore.kernel.org/r/11840239.O9o76ZdvQC@comer.internal Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/ideapad-laptop.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index e7a1299e3776..2771a05ea5e2 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -868,6 +868,18 @@ static void dytc_profile_refresh(struct ideapad_private *priv) } } +static const struct dmi_system_id ideapad_dytc_v4_allow_table[] = { + { + /* Ideapad 5 Pro 16ACH6 */ + .ident = "LENOVO 82L5", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "82L5") + } + }, + {} +}; + static int ideapad_dytc_profile_init(struct ideapad_private *priv) { int err, dytc_version; @@ -882,12 +894,21 @@ static int ideapad_dytc_profile_init(struct ideapad_private *priv) return err; /* Check DYTC is enabled and supports mode setting */ - if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output)) + if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output)) { + dev_info(&priv->platform_device->dev, "DYTC_QUERY_ENABLE_BIT returned false\n"); return -ENODEV; + } dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; - if (dytc_version < 5) - return -ENODEV; + + if (dytc_version < 5) { + if (dytc_version < 4 || !dmi_check_system(ideapad_dytc_v4_allow_table)) { + dev_info(&priv->platform_device->dev, + "DYTC_VERSION is less than 4 or is not allowed: %d\n", + dytc_version); + return -ENODEV; + } + } priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL); if (!priv->dytc) From c99ca78d67a67e2828be417ed4006f1a3c0addb5 Mon Sep 17 00:00:00 2001 From: Len Baker Date: Sun, 26 Sep 2021 13:19:08 +0200 Subject: [PATCH 045/106] platform/x86: thinkpad_acpi: Switch to common use of attributes As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. So, to avoid open-coded arithmetic in the kzalloc() call inside the create_attr_set() function the code must be refactored. Using the struct_size() helper is the fast solution but it is better to switch this code to common use of attributes. Then, remove all the custom code to manage hotkey attributes and use the attribute_group structure instead, refactoring the code accordingly. Also, to manage the optional hotkey attributes (hotkey_tablet_mode and hotkey_radio_sw) use the is_visible callback from the same structure. Moreover, now the hotkey_init_tablet_mode() function never returns a negative number. So, the check after the call can be safely removed. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments Suggested-by: Greg Kroah-Hartman Signed-off-by: Len Baker Link: https://lore.kernel.org/r/20210926111908.6950-1-len.baker@gmx.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 139 +++++---------------------- 1 file changed, 26 insertions(+), 113 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 50ff04c84650..07b9710d500e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1001,79 +1001,6 @@ static struct platform_driver tpacpi_hwmon_pdriver = { * sysfs support helpers */ -struct attribute_set { - unsigned int members, max_members; - struct attribute_group group; -}; - -struct attribute_set_obj { - struct attribute_set s; - struct attribute *a; -} __attribute__((packed)); - -static struct attribute_set *create_attr_set(unsigned int max_members, - const char *name) -{ - struct attribute_set_obj *sobj; - - if (max_members == 0) - return NULL; - - /* Allocates space for implicit NULL at the end too */ - sobj = kzalloc(sizeof(struct attribute_set_obj) + - max_members * sizeof(struct attribute *), - GFP_KERNEL); - if (!sobj) - return NULL; - sobj->s.max_members = max_members; - sobj->s.group.attrs = &sobj->a; - sobj->s.group.name = name; - - return &sobj->s; -} - -#define destroy_attr_set(_set) \ - kfree(_set) - -/* not multi-threaded safe, use it in a single thread per set */ -static int add_to_attr_set(struct attribute_set *s, struct attribute *attr) -{ - if (!s || !attr) - return -EINVAL; - - if (s->members >= s->max_members) - return -ENOMEM; - - s->group.attrs[s->members] = attr; - s->members++; - - return 0; -} - -static int add_many_to_attr_set(struct attribute_set *s, - struct attribute **attr, - unsigned int count) -{ - int i, res; - - for (i = 0; i < count; i++) { - res = add_to_attr_set(s, attr[i]); - if (res) - return res; - } - - return 0; -} - -static void delete_attr_set(struct attribute_set *s, struct kobject *kobj) -{ - sysfs_remove_group(kobj, &s->group); - destroy_attr_set(s); -} - -#define register_attr_set_with_sysfs(_attr_set, _kobj) \ - sysfs_create_group(_kobj, &_attr_set->group) - static int parse_strtoul(const char *buf, unsigned long max, unsigned long *value) { @@ -2042,8 +1969,6 @@ static u32 hotkey_acpi_mask; /* events enabled in firmware */ static u16 *hotkey_keycode_map; -static struct attribute_set *hotkey_dev_attributes; - static void tpacpi_driver_event(const unsigned int hkey_event); static void hotkey_driver_event(const unsigned int scancode); static void hotkey_poll_setup(const bool may_warn); @@ -3089,7 +3014,7 @@ static const struct attribute_group adaptive_kbd_attr_group = { /* --------------------------------------------------------------------- */ -static struct attribute *hotkey_attributes[] __initdata = { +static struct attribute *hotkey_attributes[] = { &dev_attr_hotkey_enable.attr, &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_bios_mask.attr, @@ -3103,6 +3028,26 @@ static struct attribute *hotkey_attributes[] __initdata = { &dev_attr_hotkey_source_mask.attr, &dev_attr_hotkey_poll_freq.attr, #endif + NULL +}; + +static umode_t hotkey_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + if (attr == &dev_attr_hotkey_tablet_mode.attr) { + if (!tp_features.hotkey_tablet) + return 0; + } else if (attr == &dev_attr_hotkey_radio_sw.attr) { + if (!tp_features.hotkey_wlsw) + return 0; + } + + return attr->mode; +} + +static const struct attribute_group hotkey_attr_group = { + .is_visible = hotkey_attr_is_visible, + .attrs = hotkey_attributes, }; /* @@ -3161,9 +3106,7 @@ static void hotkey_exit(void) hotkey_poll_stop_sync(); mutex_unlock(&hotkey_mutex); #endif - - if (hotkey_dev_attributes) - delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); + sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, "restoring original HKEY status and mask\n"); @@ -3249,11 +3192,6 @@ static int hotkey_init_tablet_mode(void) pr_info("Tablet mode switch found (type: %s), currently in %s mode\n", type, in_tablet_mode ? "tablet" : "laptop"); - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_tablet_mode.attr); - if (res) - return -1; - return in_tablet_mode; } @@ -3515,19 +3453,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) tpacpi_disable_brightness_delay(); - /* MUST have enough space for all attributes to be added to - * hotkey_dev_attributes */ - hotkey_dev_attributes = create_attr_set( - ARRAY_SIZE(hotkey_attributes) + 2, - NULL); - if (!hotkey_dev_attributes) - return -ENOMEM; - res = add_many_to_attr_set(hotkey_dev_attributes, - hotkey_attributes, - ARRAY_SIZE(hotkey_attributes)); - if (res) - goto err_exit; - /* mask not supported on 600e/x, 770e, 770x, A21e, A2xm/p, A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking for HKEY interface version 0x100 */ @@ -3636,18 +3561,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) pr_info("radio switch found; radios are %s\n", enabled(status, 0)); } - if (tp_features.hotkey_wlsw) - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_radio_sw.attr); - res = hotkey_init_tablet_mode(); - if (res < 0) - goto err_exit; - - tabletsw_state = res; - - res = register_attr_set_with_sysfs(hotkey_dev_attributes, - &tpacpi_pdev->dev.kobj); + tabletsw_state = hotkey_init_tablet_mode(); + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); if (res) goto err_exit; @@ -3746,11 +3662,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) return 0; err_exit: - delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, - &adaptive_kbd_attr_group); - - hotkey_dev_attributes = NULL; + sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); + sysfs_remove_group(&tpacpi_pdev->dev.kobj, &adaptive_kbd_attr_group); return (res < 0) ? res : 1; } From 2166cc2657fe73fe2b2fb052689a1bf4bb8715bb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Sep 2021 13:10:51 +0200 Subject: [PATCH 046/106] ABI: sysfs-platform-dell-privacy-wmi: correct ABI entries As described at Documentation/ABI/README doesn't contain an Attribute: field. The way sysfs ABI is supposed to work is that each different attribute would have a separate file. So, the right way to map this would be like: /sys/.../dell_privacy_supported_type/mic_mute /sys/.../dell_privacy_supported_type/camera_shutter /sys/.../dell_privacy_current_state/mic_mute /sys/.../dell_privacy_current_state/camera_shutter However, it seems to late to fix that, as this was merged already on Kernel 5.13, and a change right now would be a regression. So, instead, let's at least fix the entry to match the expected format. While here, fix the format of the contact, which is not a valid e-mail URL. This should also fix the current warnings produced when building the docs: Documentation/ABI/testing/sysfs-platform-dell-privacy-wmi:35: WARNING: Unexpected indentation. Documentation/ABI/testing/sysfs-platform-dell-privacy-wmi:2: WARNING: Unexpected indentation. Fixes: 8af9fa37b8a3 ("platform/x86: dell-privacy: Add support for Dell hardware privacy") Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/42846621fdf2bf206feb114d06b14cbc47475fb5.1632740376.git.mchehab+huawei@kernel.org Signed-off-by: Hans de Goede --- .../testing/sysfs-platform-dell-privacy-wmi | 60 ++++++++++++------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-platform-dell-privacy-wmi b/Documentation/ABI/testing/sysfs-platform-dell-privacy-wmi index 7f9e18705861..1f1f274a6979 100644 --- a/Documentation/ABI/testing/sysfs-platform-dell-privacy-wmi +++ b/Documentation/ABI/testing/sysfs-platform-dell-privacy-wmi @@ -1,55 +1,71 @@ What: /sys/bus/wmi/devices/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type Date: Apr 2021 KernelVersion: 5.13 -Contact: "perry.yuan@dell.com>" +Contact: "" Description: Display which dell hardware level privacy devices are supported “Dell Privacy” is a set of HW, FW, and SW features to enhance Dell’s commitment to platform privacy for MIC, Camera, and ePrivacy screens. The supported hardware privacy devices are: -Attributes: - Microphone Mute: + + Attributes: + Microphone Mute: Identifies the local microphone can be muted by hardware, no applications is available to capture system mic sound - Camera Shutter: + Camera Shutter: Identifies camera shutter controlled by hardware, which is a micromechanical shutter assembly that is built onto the camera module to block capturing images from outside the laptop - supported: + Values: + + supported: The privacy device is supported by this system - unsupported: + unsupported: The privacy device is not supported on this system - For example to check which privacy devices are supported: + For example to check which privacy devices are supported:: - # cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type - [Microphone Mute] [supported] - [Camera Shutter] [supported] - [ePrivacy Screen] [unsupported] + # cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type + [Microphone Mute] [supported] + [Camera Shutter] [supported] + [ePrivacy Screen] [unsupported] What: /sys/bus/wmi/devices/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state Date: Apr 2021 KernelVersion: 5.13 -Contact: "perry.yuan@dell.com>" +Contact: "" Description: Allow user space to check current dell privacy device state. Describes the Device State class exposed by BIOS which can be consumed by various applications interested in knowing the Privacy feature capabilities -Attributes: - muted: - Identifies the privacy device is turned off and cannot send stream to OS applications - unmuted: - Identifies the privacy device is turned on ,audio or camera driver can get - stream from mic and camera module to OS applications + Attributes: + Microphone: + Identifies the local microphone can be muted by hardware, no applications + is available to capture system mic sound - For example to check all supported current privacy device states: + Camera Shutter: + Identifies camera shutter controlled by hardware, which is a micromechanical + shutter assembly that is built onto the camera module to block capturing images + from outside the laptop - # cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state - [Microphone] [unmuted] - [Camera Shutter] [unmuted] + Values: + muted: + Identifies the privacy device is turned off + and cannot send stream to OS applications + + unmuted: + Identifies the privacy device is turned on, + audio or camera driver can get stream from mic + and camera module to OS applications + + For example to check all supported current privacy device states:: + + # cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state + [Microphone] [unmuted] + [Camera Shutter] [unmuted] From 10317dda79325f75e88d12a616e5043efe498338 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Sep 2021 13:10:56 +0200 Subject: [PATCH 047/106] ABI: sysfs-platform-intel-pmc: add blank lines to make it valid for ReST The ReST format requires blank lines before/after identation changes, for it to properly detect lists. Fixes: ee7abc105e2b ("platform/x86: intel_pmc_core: export platform global reset bits via etr3 sysfs file") Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/3673e1a255ad4100c933af215b60d68ba126f820.1632740376.git.mchehab+huawei@kernel.org Signed-off-by: Hans de Goede --- Documentation/ABI/testing/sysfs-platform-intel-pmc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-platform-intel-pmc b/Documentation/ABI/testing/sysfs-platform-intel-pmc index ef199af75ab0..f31d59b21f9b 100644 --- a/Documentation/ABI/testing/sysfs-platform-intel-pmc +++ b/Documentation/ABI/testing/sysfs-platform-intel-pmc @@ -11,8 +11,10 @@ Description: to take effect. Display global reset setting bits for PMC. + * bit 31 - global reset is locked * bit 20 - global reset is set + Writing bit 20 value to the etr3 will induce a platform "global reset" upon consequent platform reset, in case the register is not locked. From 452dcfab995437888106a5af6730363f67efdf79 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 27 Sep 2021 17:22:13 +0300 Subject: [PATCH 048/106] platform/mellanox: mlxreg-io: Fix argument base in kstrtou32() call Change kstrtou32() argument 'base' to be zero instead of 'len'. It works by chance for setting one bit value, but it is not supposed to work in case value passed to mlxreg_io_attr_store() is greater than 1. It works for example, for: echo 1 > /sys/devices/platform/mlxplat/mlxreg-io/hwmon/.../jtag_enable But it will fail for: echo n > /sys/devices/platform/mlxplat/mlxreg-io/hwmon/.../jtag_enable, where n > 1. The flow for input buffer conversion is as below: _kstrtoull(const char *s, unsigned int base, unsigned long long *res) calls: rv = _parse_integer(s, base, &_res); For the second case, where n > 1: - _parse_integer() converts 's' to 'val'. For n=2, 'len' is set to 2 (string buffer is 0x32 0x0a), for n=3 'len' is set to 3 (string buffer 0x33 0x0a), etcetera. - 'base' is equal or greater then '2' (length of input buffer). As a result, _parse_integer() exits with result zero (rv): rv = 0; while (1) { ... if (val >= base)-> (2 >= 2) break; ... rv++; ... } And _kstrtoull() in their turn will fail: if (rv == 0) return -EINVAL; Fixes: 5ec4a8ace06c ("platform/mellanox: Introduce support for Mellanox register access driver") Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20210927142214.2613929-2-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c index 7646708d57e4..a023ec02126b 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -141,7 +141,7 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, return -EINVAL; /* Convert buffer to input value. */ - ret = kstrtou32(buf, len, &input_val); + ret = kstrtou32(buf, 0, &input_val); if (ret) return ret; From 5fd56f11838da1580cc77743c08cf02c9cd48380 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 27 Sep 2021 17:22:14 +0300 Subject: [PATCH 049/106] platform/mellanox: mlxreg-io: Fix read access of n-bytes size attributes Fix shift argument for function rol32(). It should be provided in bits, while was provided in bytes. Fixes: 86148190a7db ("platform/mellanox: mlxreg-io: Add support for complex attributes") Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20210927142214.2613929-3-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c index a023ec02126b..a916cd89cbbe 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -98,7 +98,7 @@ mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val, if (ret) goto access_error; - *regval |= rol32(val, regsize * i); + *regval |= rol32(val, regsize * i * 8); } } From a499f93f3d5225a214831c9fd88f9f18e2d8cb3d Mon Sep 17 00:00:00 2001 From: Daniel Dadap Date: Mon, 27 Sep 2021 15:23:58 -0500 Subject: [PATCH 050/106] platform/x86: Remove "WMAA" from identifier names in wmaa-backlight-wmi.c The "wmaa" in the name of the wmaa-backlight-wmi driver was named after the ACPI method handle for EC-based backlight control on the systems this driver was tested on during development. However, this "WMAA" handle is generated by the WMI compilation process, and isn't actually a part of the backlight control mechanism which this driver supports. Since the "WMAA" handle isn't actually a part of the firmware backlight interface, the various identifiers in this driver using "WMAA" or "wmaa" aren't actually appropriate. As a common denominator across the systems supported by this driver is that they are hybrid graphics systems with NVIDIA GPUs, using "nvidia" in the driver name seems more appropriate than "wmaa". Update the driver to remove "wmaa" and "WMAA" in identifier names where they appear. The kerneldoc comments for the enum wmi_brightness_method values are replaced with the verbatim text from the decompiled BMF code for this WMI class. Signed-off-by: Daniel Dadap Link: https://lore.kernel.org/r/20210927202359.13684-1-ddadap@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/wmaa-backlight-wmi.c | 174 +++++++++++----------- 1 file changed, 91 insertions(+), 83 deletions(-) diff --git a/drivers/platform/x86/wmaa-backlight-wmi.c b/drivers/platform/x86/wmaa-backlight-wmi.c index f5c4f8337c2c..61e37194df70 100644 --- a/drivers/platform/x86/wmaa-backlight-wmi.c +++ b/drivers/platform/x86/wmaa-backlight-wmi.c @@ -11,63 +11,64 @@ #include /** - * enum wmaa_method - WMI method IDs for ACPI WMAA - * @WMAA_METHOD_LEVEL: Get or set the brightness level, - * or get the maximum brightness level. - * @WMAA_METHOD_SOURCE: Get the source for backlight control. + * 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 wmaa_method { - WMAA_METHOD_LEVEL = 1, - WMAA_METHOD_SOURCE = 2, - WMAA_METHOD_MAX +enum wmi_brightness_method { + WMI_BRIGHTNESS_METHOD_LEVEL = 1, + WMI_BRIGHTNESS_METHOD_SOURCE = 2, + WMI_BRIGHTNESS_METHOD_MAX }; /** - * enum wmaa_mode - Operation mode for ACPI WMAA method - * @WMAA_MODE_GET: Get the current brightness level or source. - * @WMAA_MODE_SET: Set the brightness level. - * @WMAA_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This is only - * valid when the WMI method is %WMAA_METHOD_LEVEL. + * 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 wmaa_mode { - WMAA_MODE_GET = 0, - WMAA_MODE_SET = 1, - WMAA_MODE_GET_MAX_LEVEL = 2, - WMAA_MODE_MAX +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 wmaa_source - Backlight brightness control source identification - * @WMAA_SOURCE_GPU: Backlight brightness is controlled by the GPU. - * @WMAA_SOURCE_EC: Backlight brightness is controlled by the system's - * Embedded Controller (EC). - * @WMAA_SOURCE_AUX: Backlight brightness is controlled over the DisplayPort - * AUX channel. + * 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 wmaa_source { - WMAA_SOURCE_GPU = 1, - WMAA_SOURCE_EC = 2, - WMAA_SOURCE_AUX = 3, - WMAA_SOURCE_MAX +enum wmi_brightness_source { + WMI_BRIGHTNESS_SOURCE_GPU = 1, + WMI_BRIGHTNESS_SOURCE_EC = 2, + WMI_BRIGHTNESS_SOURCE_AUX = 3, + WMI_BRIGHTNESS_SOURCE_MAX }; /** - * struct wmaa_args - arguments for the ACPI WMAA method - * @mode: Pass in an &enum wmaa_mode value to select between getting or - * setting a value. - * @val: In parameter for value to set when operating in %WMAA_MODE_SET - * mode. Not used in %WMAA_MODE_GET or %WMAA_MODE_GET_MAX_LEVEL mode. + * 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 - * %WMAA_MODE_GET or %WMAA_MODE_GET_MAX_LEVEL mode. Not used in - * %WMAA_MODE_SET mode. + * %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 ACPI WMAA 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 %WMAA_METHOD_LEVEL, or an &enum wmaa_source value - * when the WMI method ID is %WMAA_METHOD_SOURCE. + * 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 wmaa_args { +struct wmi_brightness_args { u32 mode; u32 val; u32 ret; @@ -75,21 +76,21 @@ struct wmaa_args { }; /** - * wmi_call_wmaa() - helper function for calling ACPI WMAA via its WMI wrapper - * @w: Pointer to the struct wmi_device identified by %WMAA_WMI_GUID - * @id: The method ID for the ACPI WMAA method (e.g. %WMAA_METHOD_LEVEL or - * %WMAA_METHOD_SOURCE) - * @mode: The operation to perform on the ACPI WMAA method (e.g. %WMAA_MODE_SET - * or %WMAA_MODE_GET) + * wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method + * @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID + * @id: The WMI method ID to call (e.g. %WMI_BRIGHTNESS_METHOD_LEVEL or + * %WMI_BRIGHTNESS_METHOD_SOURCE) + * @mode: The operation to perform on the method (e.g. %WMI_BRIGHTNESS_MODE_SET + * or %WMI_BRIGHTNESS_MODE_GET) * @val: Pointer to a value passed in by the caller when @mode is - * %WMAA_MODE_SET, or a value passed out to the caller when @mode is - * %WMAA_MODE_GET or %WMAA_MODE_GET_MAX_LEVEL. + * %WMI_BRIGHTNESS_MODE_SET, or a value passed out to caller when @mode + * is %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL. * * Returns 0 on success, or a negative error number on failure. */ -static int wmi_call_wmaa(struct wmi_device *w, enum wmaa_method id, enum wmaa_mode mode, u32 *val) +static int wmi_brightness_notify(struct wmi_device *w, enum wmi_brightness_method id, enum wmi_brightness_mode mode, u32 *val) { - struct wmaa_args args = { + struct wmi_brightness_args args = { .mode = mode, .val = 0, .ret = 0, @@ -97,60 +98,64 @@ static int wmi_call_wmaa(struct wmi_device *w, enum wmaa_method id, enum wmaa_mo struct acpi_buffer buf = { (acpi_size)sizeof(args), &args }; acpi_status status; - if (id < WMAA_METHOD_LEVEL || id >= WMAA_METHOD_MAX || - mode < WMAA_MODE_GET || mode >= WMAA_MODE_MAX) + if (id < WMI_BRIGHTNESS_METHOD_LEVEL || + id >= WMI_BRIGHTNESS_METHOD_MAX || + mode < WMI_BRIGHTNESS_MODE_GET || mode >= WMI_BRIGHTNESS_MODE_MAX) return -EINVAL; - if (mode == WMAA_MODE_SET) + if (mode == WMI_BRIGHTNESS_MODE_SET) args.val = *val; status = wmidev_evaluate_method(w, 0, id, &buf, &buf); if (ACPI_FAILURE(status)) { - dev_err(&w->dev, "ACPI WMAA failed: %s\n", + dev_err(&w->dev, "EC backlight control failed: %s\n", acpi_format_exception(status)); return -EIO; } - if (mode != WMAA_MODE_SET) + if (mode != WMI_BRIGHTNESS_MODE_SET) *val = args.ret; return 0; } -static int wmaa_backlight_update_status(struct backlight_device *bd) +static int nvidia_wmi_ec_backlight_update_status(struct backlight_device *bd) { struct wmi_device *wdev = bl_get_data(bd); - return wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_SET, - &bd->props.brightness); + return wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL, + WMI_BRIGHTNESS_MODE_SET, + &bd->props.brightness); } -static int wmaa_backlight_get_brightness(struct backlight_device *bd) +static int nvidia_wmi_ec_backlight_get_brightness(struct backlight_device *bd) { struct wmi_device *wdev = bl_get_data(bd); u32 level; int ret; - ret = wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_GET, &level); + ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL, + WMI_BRIGHTNESS_MODE_GET, &level); if (ret < 0) return ret; return level; } -static const struct backlight_ops wmaa_backlight_ops = { - .update_status = wmaa_backlight_update_status, - .get_brightness = wmaa_backlight_get_brightness, +static const struct backlight_ops nvidia_wmi_ec_backlight_ops = { + .update_status = nvidia_wmi_ec_backlight_update_status, + .get_brightness = nvidia_wmi_ec_backlight_get_brightness, }; -static int wmaa_backlight_wmi_probe(struct wmi_device *wdev, const void *ctx) +static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ctx) { struct backlight_properties props = {}; struct backlight_device *bdev; u32 source; int ret; - ret = wmi_call_wmaa(wdev, WMAA_METHOD_SOURCE, WMAA_MODE_GET, &source); + ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_SOURCE, + WMI_BRIGHTNESS_MODE_GET, &source); if (ret) return ret; @@ -158,7 +163,7 @@ static int wmaa_backlight_wmi_probe(struct wmi_device *wdev, const void *ctx) * 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 != WMAA_SOURCE_EC) + if (source != WMI_BRIGHTNESS_SOURCE_EC) return -ENODEV; /* @@ -167,39 +172,42 @@ static int wmaa_backlight_wmi_probe(struct wmi_device *wdev, const void *ctx) */ props.type = BACKLIGHT_FIRMWARE; - ret = wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_GET_MAX_LEVEL, - &props.max_brightness); + ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL, + WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL, + &props.max_brightness); if (ret) return ret; - ret = wmi_call_wmaa(wdev, WMAA_METHOD_LEVEL, WMAA_MODE_GET, - &props.brightness); + ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL, + WMI_BRIGHTNESS_MODE_GET, &props.brightness); if (ret) return ret; - bdev = devm_backlight_device_register(&wdev->dev, "wmaa_backlight", + bdev = devm_backlight_device_register(&wdev->dev, + "nvidia_wmi_ec_backlight", &wdev->dev, wdev, - &wmaa_backlight_ops, &props); + &nvidia_wmi_ec_backlight_ops, + &props); return PTR_ERR_OR_ZERO(bdev); } -#define WMAA_WMI_GUID "603E9613-EF25-4338-A3D0-C46177516DB7" +#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7" -static const struct wmi_device_id wmaa_backlight_wmi_id_table[] = { - { .guid_string = WMAA_WMI_GUID }, +static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table[] = { + { .guid_string = WMI_BRIGHTNESS_GUID }, { } }; -MODULE_DEVICE_TABLE(wmi, wmaa_backlight_wmi_id_table); +MODULE_DEVICE_TABLE(wmi, nvidia_wmi_ec_backlight_id_table); -static struct wmi_driver wmaa_backlight_wmi_driver = { +static struct wmi_driver nvidia_wmi_ec_backlight_driver = { .driver = { - .name = "wmaa-backlight", + .name = "nvidia-wmi-ec-backlight", }, - .probe = wmaa_backlight_wmi_probe, - .id_table = wmaa_backlight_wmi_id_table, + .probe = nvidia_wmi_ec_backlight_probe, + .id_table = nvidia_wmi_ec_backlight_id_table, }; -module_wmi_driver(wmaa_backlight_wmi_driver); +module_wmi_driver(nvidia_wmi_ec_backlight_driver); MODULE_AUTHOR("Daniel Dadap "); -MODULE_DESCRIPTION("WMAA Backlight WMI driver"); +MODULE_DESCRIPTION("NVIDIA WMI EC Backlight driver"); MODULE_LICENSE("GPL"); From ca16d33bd86246bf91d089c8ba78b9b214574b12 Mon Sep 17 00:00:00 2001 From: Daniel Dadap Date: Mon, 27 Sep 2021 15:23:59 -0500 Subject: [PATCH 051/106] platform/x86: Rename wmaa-backlight-wmi to nvidia-wmi-ec-backlight Rename the wmaa-backlight-wmi driver and associated KConfig option to remove the remaining references to the "WMAA" ACPI handle which was used in the previous name. The driver has already been updated to remove internal references to "WMAA". As part of the renaming, the components in the name have been rearranged to reflect the standard vendor_wmi_feature pattern. Signed-off-by: Daniel Dadap Link: https://lore.kernel.org/r/20210927202359.13684-2-ddadap@nvidia.com Signed-off-by: Hans de Goede --- MAINTAINERS | 12 ++++++------ drivers/platform/x86/Kconfig | 15 +++++++-------- drivers/platform/x86/Makefile | 2 +- ...-backlight-wmi.c => nvidia-wmi-ec-backlight.c} | 0 4 files changed, 14 insertions(+), 15 deletions(-) rename drivers/platform/x86/{wmaa-backlight-wmi.c => nvidia-wmi-ec-backlight.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index db8186530b0b..7041c6591a53 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13389,6 +13389,12 @@ S: Maintained F: drivers/video/fbdev/nvidia/ F: drivers/video/fbdev/riva/ +NVIDIA WMI EC BACKLIGHT DRIVER +M: Daniel Dadap +L: platform-driver-x86@vger.kernel.org +S: Supported +F: drivers/platform/x86/nvidia-wmi-ec-backlight.c + NVM EXPRESS DRIVER M: Keith Busch M: Jens Axboe @@ -20252,12 +20258,6 @@ L: linux-wireless@vger.kernel.org S: Odd fixes F: drivers/net/wireless/wl3501* -WMAA BACKLIGHT DRIVER -M: Daniel Dadap -L: platform-driver-x86@vger.kernel.org -S: Supported -F: drivers/platform/x86/wmaa-backlight-wmi.c - WOLFSON MICROELECTRONICS DRIVERS L: patches@opensource.cirrus.com S: Supported diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f3dbb0273884..520da0a6acd1 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -91,21 +91,20 @@ config PEAQ_WMI help Say Y here if you want to support WMI-based hotkeys on PEAQ 2-in-1s. -config WMAA_BACKLIGHT_WMI - tristate "ACPI WMAA Backlight Driver" +config NVIDIA_WMI_EC_BACKLIGHT + tristate "EC Backlight Driver for Hybrid Graphics Notebook Systems" depends on ACPI_WMI depends on BACKLIGHT_CLASS_DEVICE help - This driver provides a sysfs backlight interface for notebook - systems which expose the WMAA ACPI method and an associated WMI - wrapper to drive LCD backlight levels through the Embedded Controller - (EC). + This driver provides a sysfs backlight interface for notebook systems + which are equipped with NVIDIA hybrid graphics and drive LCD backlight + levels through the Embedded Controller (EC). Say Y or M here if you want to control the backlight on a notebook - system with an EC-driven backlight using the ACPI WMAA method. + system with an EC-driven backlight. If you choose to compile this driver as a module the module will be - called wmaa-backlight-wmi. + called nvidia-wmi-ec-backlight. config XIAOMI_WMI tristate "Xiaomi WMI key driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index edde481c14ad..0d046ed70da1 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -11,8 +11,8 @@ obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o # WMI drivers obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o obj-$(CONFIG_MXM_WMI) += mxm-wmi.o +obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o -obj-$(CONFIG_WMAA_BACKLIGHT_WMI) += wmaa-backlight-wmi.o obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o diff --git a/drivers/platform/x86/wmaa-backlight-wmi.c b/drivers/platform/x86/nvidia-wmi-ec-backlight.c similarity index 100% rename from drivers/platform/x86/wmaa-backlight-wmi.c rename to drivers/platform/x86/nvidia-wmi-ec-backlight.c From 6550ba689343811ef1d4b87be8d273988d4648d5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 11 Oct 2021 15:23:38 +0200 Subject: [PATCH 052/106] platform/x86: dell: Make DELL_WMI_PRIVACY depend on DELL_WMI DELL_WMI_PRIVACY is a feature toggle for the main dell-wmi driver, so it must depend on the Kconfig option which enables the main dell-wmi driver. Fixes: 8af9fa37b8a3 ("platform/x86: dell-privacy: Add support for Dell hardware privacy") Reported-by: Randy Dunlap Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211011132338.407571-1-hdegoede@redhat.com --- drivers/platform/x86/dell/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index 42513eab1d06..2fffa57e596e 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -167,6 +167,7 @@ config DELL_WMI config DELL_WMI_PRIVACY bool "Dell WMI Hardware Privacy Support" depends on LEDS_TRIGGER_AUDIO = y || DELL_WMI = LEDS_TRIGGER_AUDIO + depends on DELL_WMI help This option adds integration with the "Dell Hardware Privacy" feature of Dell laptops to the dell-wmi driver. From f32c34d6cfbb3d1f1c26f223cb549cca9767cfbd Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Tue, 28 Sep 2021 03:19:30 -0700 Subject: [PATCH 053/106] platform/x86: intel_scu_ipc: Fix busy loop expiry time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macro IPC_TIMEOUT is already in jiffies (it is also used like that elsewhere in the file when calling wait_for_completion_timeout()). Don’t convert it using helper functions for the purposes of calculating the busy loop expiry time. Fixes: e7b7ab3847c9 (“platform/x86: intel_scu_ipc: Sleeping is fine when polling”) Signed-off-by: Prashant Malani Cc: Benson Leung Reviewed-by: Mika Westerberg Link: https://lore.kernel.org/r/20210928101932.2543937-2-pmalani@chromium.org Signed-off-by: Hans de Goede --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index bfa0cc20750d..cfb249da2a7b 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -232,7 +232,7 @@ static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset) /* Wait till scu status is busy */ static inline int busy_loop(struct intel_scu_ipc_dev *scu) { - unsigned long end = jiffies + msecs_to_jiffies(IPC_TIMEOUT); + unsigned long end = jiffies + IPC_TIMEOUT; do { u32 status; From 7f0224dea7634052c6d5652d7928c4c23695906d Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Tue, 28 Sep 2021 03:19:32 -0700 Subject: [PATCH 054/106] platform/x86: intel_scu_ipc: Increase virtual timeout to 10s Commit a7d53dbbc70a ("platform/x86: intel_scu_ipc: Increase virtual timeout from 3 to 5 seconds") states that the recommended timeout range is 5-10 seconds. Adjust the timeout value to the higher of those i.e 10 seconds, to account for situations where the 5 seconds is insufficient for disconnect command success. Signed-off-by: Prashant Malani Cc: Benson Leung Reviewed-by: Mika Westerberg Link: https://lore.kernel.org/r/20210928101932.2543937-3-pmalani@chromium.org Signed-off-by: Hans de Goede --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index cfb249da2a7b..d71a1dce781c 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -75,7 +75,7 @@ struct intel_scu_ipc_dev { #define IPC_READ_BUFFER 0x90 /* Timeout in jiffies */ -#define IPC_TIMEOUT (5 * HZ) +#define IPC_TIMEOUT (10 * HZ) static struct intel_scu_ipc_dev *ipcdev; /* Only one for now */ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ From c01bc8e4e8409aa7b66208b1b503707bd1957254 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Tue, 28 Sep 2021 03:19:34 -0700 Subject: [PATCH 055/106] platform/x86: intel_scu_ipc: Update timeout value in comment The comment decribing the IPC timeout hadn't been updated when the actual timeout was changed from 3 to 5 seconds in commit a7d53dbbc70a ("platform/x86: intel_scu_ipc: Increase virtual timeout from 3 to 5 seconds") . Since the value is anyway updated to 10s now, take this opportunity to update the value in the comment too. Signed-off-by: Prashant Malani Cc: Benson Leung Reviewed-by: Mika Westerberg Link: https://lore.kernel.org/r/20210928101932.2543937-4-pmalani@chromium.org Signed-off-by: Hans de Goede --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index d71a1dce781c..7cc9089d1e14 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -247,7 +247,7 @@ static inline int busy_loop(struct intel_scu_ipc_dev *scu) return -ETIMEDOUT; } -/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */ +/* Wait till ipc ioc interrupt is received or timeout in 10 HZ */ static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu) { int status; From 432cce21b66c49b1951d046d3ffc5d52fdad6265 Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 2 Oct 2021 14:18:39 +1000 Subject: [PATCH 056/106] platform/x86: amd-pmc: Add alternative acpi id for PMC controller The Surface Laptop 4 AMD has used the AMD0005 to identify this controller instead of using the appropriate ACPI ID AMDI0005. Include AMD0005 in the acpi id list. Link: https://github.com/linux-surface/acpidumps/tree/master/surface_laptop_4_amd Link: https://gist.github.com/nakato/2a1a7df1a45fe680d7a08c583e1bf863 Cc: # 5.14+ Signed-off-by: Sachi King Reviewed-by: Mario Limonciello Link: https://lore.kernel.org/r/20211002041840.2058647-1-nakato@nakato.io Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index 548432a2ea65..b7b6ad4629a7 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -555,6 +555,7 @@ static const struct acpi_device_id amd_pmc_acpi_ids[] = { {"AMDI0006", 0}, {"AMDI0007", 0}, {"AMD0004", 0}, + {"AMD0005", 0}, { } }; MODULE_DEVICE_TABLE(acpi, amd_pmc_acpi_ids); From 95384b3e47afa04d7dfa014f6a52662852645578 Mon Sep 17 00:00:00 2001 From: "Zephaniah E. Loss-Cutler-Hull" Date: Mon, 4 Oct 2021 21:48:55 -0700 Subject: [PATCH 057/106] platform/x86: gigabyte-wmi: add support for B550 AORUS ELITE AX V2 This works just fine on my system. Signed-off-by: Zephaniah E. Loss-Cutler-Hull Cc: Link: https://lore.kernel.org/r/20211005044855.1429724-1-zephaniah@gmail.com Signed-off-by: Hans de Goede --- drivers/platform/x86/gigabyte-wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c index d53634c8a6e0..658bab4b7964 100644 --- a/drivers/platform/x86/gigabyte-wmi.c +++ b/drivers/platform/x86/gigabyte-wmi.c @@ -141,6 +141,7 @@ static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev) static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M S2H V2"), + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE AX V2"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE V2"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 GAMING X V2"), From 0b243c003e11897bd443ae9be4eda76a57ff732a Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Fri, 8 Oct 2021 23:46:08 +0100 Subject: [PATCH 058/106] platform/x86: intel_skl_int3472: Correct null check The int3472-discrete driver can enter an error path after initialising int3472->clock.ena_gpio, but before it has registered the clock. This will cause a NULL pointer dereference, because clkdev_drop() is not null aware. Instead of guarding the call to skl_int3472_unregister_clock() by checking for .ena_gpio, check specifically for the presence of the clk_lookup, which will guarantee clkdev_create() has already been called. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=214453 Fixes: 7540599a5ef1 ("platform/x86: intel_skl_int3472: Provide skl_int3472_unregister_clock()") Signed-off-by: Daniel Scally Link: https://lore.kernel.org/r/20211008224608.415949-1-djrscally@gmail.com Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c index 9fe0a2527e1c..e59d79c7e82f 100644 --- a/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c +++ b/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c @@ -401,7 +401,7 @@ int skl_int3472_discrete_remove(struct platform_device *pdev) gpiod_remove_lookup_table(&int3472->gpios); - if (int3472->clock.ena_gpio) + if (int3472->clock.cl) skl_int3472_unregister_clock(int3472); gpiod_put(int3472->clock.ena_gpio); From 85303db36b6e170917a7bc6aae4898c31a5272a0 Mon Sep 17 00:00:00 2001 From: Shravan S Date: Wed, 6 Oct 2021 13:05:25 +0530 Subject: [PATCH 059/106] platform/x86: int1092: Fix non sequential device mode handling SAR information from BIOS may come in non sequential pattern. To overcome the issue, a check is made to extract the right SAR information using the device mode which is currently being used. Remove .owner field if calls are used which set it automatically. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Shravan S Link: https://lore.kernel.org/r/20211006073525.1332925-1-s.shravan@intel.com Signed-off-by: Hans de Goede Reviewed-by: Hans de Goede --- MAINTAINERS | 2 +- .../platform/x86/intel/int1092/intel_sar.c | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7041c6591a53..6d6135915073 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9302,7 +9302,7 @@ S: Maintained F: drivers/platform/x86/intel/atomisp2/led.c INTEL BIOS SAR INT1092 DRIVER -M: Shravan S +M: Shravan Sudhakar M: Intel Corporation L: platform-driver-x86@vger.kernel.org S: Maintained diff --git a/drivers/platform/x86/intel/int1092/intel_sar.c b/drivers/platform/x86/intel/int1092/intel_sar.c index 379560fe5df9..e03943e6380a 100644 --- a/drivers/platform/x86/intel/int1092/intel_sar.c +++ b/drivers/platform/x86/intel/int1092/intel_sar.c @@ -42,12 +42,20 @@ static void update_sar_data(struct wwan_sar_context *context) if (config->device_mode_info && context->sar_data.device_mode < config->total_dev_mode) { - struct wwan_device_mode_info *dev_mode = - &config->device_mode_info[context->sar_data.device_mode]; + int itr = 0; - context->sar_data.antennatable_index = dev_mode->antennatable_index; - context->sar_data.bandtable_index = dev_mode->bandtable_index; - context->sar_data.sartable_index = dev_mode->sartable_index; + for (itr = 0; itr < config->total_dev_mode; itr++) { + if (context->sar_data.device_mode == + config->device_mode_info[itr].device_mode) { + struct wwan_device_mode_info *dev_mode = + &config->device_mode_info[itr]; + + context->sar_data.antennatable_index = dev_mode->antennatable_index; + context->sar_data.bandtable_index = dev_mode->bandtable_index; + context->sar_data.sartable_index = dev_mode->sartable_index; + break; + } + } } } @@ -305,7 +313,6 @@ static struct platform_driver sar_driver = { .remove = sar_remove, .driver = { .name = DRVNAME, - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(sar_device_ids) } }; @@ -313,4 +320,4 @@ module_platform_driver(sar_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Platform device driver for INTEL MODEM BIOS SAR"); -MODULE_AUTHOR("Shravan S "); +MODULE_AUTHOR("Shravan Sudhakar "); From aafa1cafedca7c64d6a43cd21488d28d1d1be884 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:30 +0300 Subject: [PATCH 060/106] platform_data/mlxreg: Add new type to support modular systems Add new types for the Nvidia modular systems MSN4800 which could be equipped with the different types of replaceable line cards. Add new type to specify the kind of hotplug events for the line cards. The line card events are generated by the programmable device located on the main board. This device implements interrupt controller logic. Line card interrupts are associated with different line cards states during its initialization: insertion, security signature validation, power good state, security validation, hardware-firmware synchronization state, line card PHYs readiness state, firmware availability for line card ports. Also under some circumstances hardware can generate thermal shutdown for particular line card. Add new type specifying the action, which should be performed when particular hotplug event is received. This action defines in which way hotplug event should be handled by hotplug driver. There are the next actions types: - Connect I2C device with empty 'platform_data' field according to the platform topology, if device is configured (for example, power unit micro-controller driver, when power unit is connected to power source (this is what is currently supported). - Connect device with 'platform_data' field set according to the platform topology. The purpose is to pass 'platform_data' through hotplug driver to underlying device (for example line card driver). - No device is associated with hotplug event - just send "udev" event (this is what is currently supported). Extend structure 'mlxreg_hotplug_device' with hotplug action field. Extend structure 'mlxreg_core_data' with: - Registers for line card power and enabling control. - Slot number field, to indicate at which physical slot replaceable line card device is located. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-2-vadimp@nvidia.com Signed-off-by: Hans de Goede --- include/linux/platform_data/mlxreg.h | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index 101333fe2b8d..49f0e15a10dd 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h @@ -24,6 +24,51 @@ enum mlxreg_wdt_type { MLX_WDT_TYPE3, }; +/** + * enum mlxreg_hotplug_kind - kind of hotplug entry + * + * @MLXREG_HOTPLUG_DEVICE_NA: do not care; + * @MLXREG_HOTPLUG_LC_PRESENT: entry for line card presence in/out events; + * @MLXREG_HOTPLUG_LC_VERIFIED: entry for line card verification status events + * coming after line card security signature validation; + * @MLXREG_HOTPLUG_LC_POWERED: entry for line card power on/off events; + * @MLXREG_HOTPLUG_LC_SYNCED: entry for line card synchronization events, coming + * after hardware-firmware synchronization handshake; + * @MLXREG_HOTPLUG_LC_READY: entry for line card ready events, indicating line card + PHYs ready / unready state; + * @MLXREG_HOTPLUG_LC_ACTIVE: entry for line card active events, indicating firmware + * availability / unavailability for the ports on line card; + * @MLXREG_HOTPLUG_LC_THERMAL: entry for line card thermal shutdown events, positive + * event indicates that system should power off the line + * card for which this event has been received; + */ +enum mlxreg_hotplug_kind { + MLXREG_HOTPLUG_DEVICE_NA = 0, + MLXREG_HOTPLUG_LC_PRESENT = 1, + MLXREG_HOTPLUG_LC_VERIFIED = 2, + MLXREG_HOTPLUG_LC_POWERED = 3, + MLXREG_HOTPLUG_LC_SYNCED = 4, + MLXREG_HOTPLUG_LC_READY = 5, + MLXREG_HOTPLUG_LC_ACTIVE = 6, + MLXREG_HOTPLUG_LC_THERMAL = 7, +}; + +/** + * enum mlxreg_hotplug_device_action - hotplug device action required for + * driver's connectivity + * + * @MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION: probe device for 'on' event, remove + * for 'off' event; + * @MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION: probe platform device for 'on' + * event, remove for 'off' event; + * @MLXREG_HOTPLUG_DEVICE_NO_ACTION: no connectivity action is required; + */ +enum mlxreg_hotplug_device_action { + MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION = 0, + MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION = 1, + MLXREG_HOTPLUG_DEVICE_NO_ACTION = 2, +}; + /** * struct mlxreg_hotplug_device - I2C device data: * @@ -31,6 +76,7 @@ enum mlxreg_wdt_type { * @client: I2C device client; * @brdinfo: device board information; * @nr: I2C device adapter number, to which device is to be attached; + * @action: action to be performed upon event receiving; * * Structure represents I2C hotplug device static data (board topology) and * dynamic data (related kernel objects handles). @@ -40,6 +86,7 @@ struct mlxreg_hotplug_device { struct i2c_client *client; struct i2c_board_info *brdinfo; int nr; + enum mlxreg_hotplug_device_action action; }; /** @@ -51,12 +98,16 @@ struct mlxreg_hotplug_device { * @bit: attribute effective bit; * @capability: attribute capability register; * @reg_prsnt: attribute presence register; + * @reg_sync: attribute synch register; + * @reg_pwr: attribute power register; + * @reg_ena: attribute enable register; * @mode: access mode; * @np - pointer to node platform associated with attribute; * @hpdev - hotplug device data; * @health_cntr: dynamic device health indication counter; * @attached: true if device has been attached after good health indication; * @regnum: number of registers occupied by multi-register attribute; + * @slot: slot number, at which device is located; */ struct mlxreg_core_data { char label[MLXREG_CORE_LABEL_MAX_SIZE]; @@ -65,18 +116,23 @@ struct mlxreg_core_data { u32 bit; u32 capability; u32 reg_prsnt; + u32 reg_sync; + u32 reg_pwr; + u32 reg_ena; umode_t mode; struct device_node *np; struct mlxreg_hotplug_device hpdev; u32 health_cntr; bool attached; u8 regnum; + u8 slot; }; /** * struct mlxreg_core_item - same type components controlled by the driver: * * @data: component data; + * @kind: kind of hotplug attribute; * @aggr_mask: group aggregation mask; * @reg: group interrupt status register; * @mask: group interrupt mask; @@ -89,6 +145,7 @@ struct mlxreg_core_data { */ struct mlxreg_core_item { struct mlxreg_core_data *data; + enum mlxreg_hotplug_kind kind; u32 aggr_mask; u32 reg; u32 mask; From a5d8f57edfb44a3f036152258d844c21c0436382 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:31 +0300 Subject: [PATCH 061/106] platform/x86: mlx-platform: Add initial support for new modular system Add initial chassis management support for Nvidia modular Ethernet switch systems MSN4800, providing a high performance switching solution for Enterprise Data Centers (EDC) for building Ethernet based clusters, High-Performance Computing (HPC) and embedded environments. This system could be equipped with the different types of replaceable line cards and management board. The first system flavor will support the line card type MSN4800-C16 equipped with Lattice CPLD devices aimed for system and ASIC control, one Nvidia FPGA for gearboxes (PHYs) management, and four Nvidia gearboxes for the port control and with 16x100GbE QSFP28 ports and also with various devices for electrical control. The system is equipped with eight slots for line cards, four slots for power supplies and six slots for fans. It could be configured as fully populated or with even only one line card. The line cards are hot-pluggable. In the future when more line card flavors are to be available (for example line cards with 8x200Gb Eth port, with 4x400 Eth ports, or with some kind of smart cards for offloading purpose), any type of line card could be inserted at any slot. The system is based on Nvidia Spectrum-3 ASIC. The switch height is 4U and it fits standard rack size. System could be configured as fully populated or with even only one line card. The line cards are hot-pluggable. Line cards are connected to the chassis through I2C interface for the chassis management operations and through PCIe for the networking operations. Future line cards could be connected to the chassis through InfiniBand fabric, instead of PCIe. The first type of line card supports 16x100GbE QSFP28 Ethernet ports. Those line cards equipped with the programmable devices aimed for system control of Nvidia Ethernet switch ASIC control, Nvidia FPGA, Nvidia gearboxes (PHYs). The next coming card generations are supposed to support: - Line cards with 8x200Gbe QSFP28 Ethernet ports. - Line cards with 4x400Gbe QSFP-DD Ethernet ports. - Smart cards equipped with Nvidia ARM CPU for offloading and for fast access to the storage (EBoF). - Fabric cards for inter-connection. The basic system initialization flow with input signals from the programmable device to kernel hotplug driver and with OS response to some of these signals is depicted below. lc#n_prsnt *-> Input: line card presence in/out events. Informational event. Required action - 'udev' event generation for logging. lc#n_verified *-> Input: line card verification status events coming after line card security signature validation by hardware. Required action - connect line card driver and initialized line card devices feeding from system auxiliary power domain. lc#n_pwr <-* Output: line card power on / off from OS. Action should be performed by platform power management driver. lc#n_powered *-> Input: line card power on/off events coming after line card "power good" on/off events, mean that line card power up sequence has been successfully completed or line card "power good" status has been dropped. Required action - connect line card devices feeding from system main power domain. lc#n_synced *-> Input: line card synchronization events, coming after hardware-firmware synchronization handshake. Required action - to enable line card, in case lc#n_ready has been received before. lc#n_ready *-> Input: line card ready events, indicating line card PHYs ready / unready states. Required action - enable line card, in case lc#n_synced has been received before. lc#n_enable <-* Output: line card enable from OS - release FPGA and PHYs line card devices from reset state. Action should be performed by platform power management driver. lc#n_active *-> Input: when line card "active event" is received for particular line card, its network, hardware monitoring and thermal interfaces should be configured according to the configuration obtained from the firmware. When opposite "inactive event" is received all the above interfaces should be teared down. Required action - connect / disconnect the above line card interfaces through ASIC I2C chassis management driver. For initial support: - Define new system type 'VMOD0011' to support new modular system. - Provide initial platform configuration for new system type. - Extend the registers definitions. - Add support for modular system registers related to line card specific events - insertion/removal, power on/off, verification and activation. - Add hotplug configuration for the above events. - Add configurations for hotplug actions for the modular system. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-3-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 1655 ++++++++++++++++++++++++++- 1 file changed, 1653 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 8bce3da32a42..a30af1fc5c75 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -30,6 +30,7 @@ #define MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET 0x06 #define MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET 0x08 #define MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET 0x0a +#define MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET 0x1c #define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET 0x1f @@ -38,13 +39,20 @@ #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 +#define MLXPLAT_CPLD_LPC_REG_LED6_OFFSET 0x25 +#define MLXPLAT_CPLD_LPC_REG_LED7_OFFSET 0x26 #define MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION 0x2a #define MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET 0x2b +#define MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET 0x2d #define MLXPLAT_CPLD_LPC_REG_GP0_OFFSET 0x2e +#define MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET 0x2f #define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 #define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 #define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 #define MLXPLAT_CPLD_LPC_REG_WP2_OFFSET 0x33 +#define MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE 0x34 +#define MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET 0x35 +#define MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET 0x36 #define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b @@ -57,15 +65,39 @@ #define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 +#define MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET 0x56 +#define MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET 0x57 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65 #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66 +#define MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET 0x70 +#define MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET 0x71 +#define MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET 0x72 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a +#define MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET 0x9a +#define MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET 0x9b +#define MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET 0x9c +#define MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET 0x9d +#define MLXPLAT_CPLD_LPC_REG_LC_PG_EVENT_OFFSET 0x9e +#define MLXPLAT_CPLD_LPC_REG_LC_PG_MASK_OFFSET 0x9f +#define MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET 0xa0 +#define MLXPLAT_CPLD_LPC_REG_LC_RD_EVENT_OFFSET 0xa1 +#define MLXPLAT_CPLD_LPC_REG_LC_RD_MASK_OFFSET 0xa2 +#define MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET 0xa3 +#define MLXPLAT_CPLD_LPC_REG_LC_SN_EVENT_OFFSET 0xa4 +#define MLXPLAT_CPLD_LPC_REG_LC_SN_MASK_OFFSET 0xa5 +#define MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET 0xa6 +#define MLXPLAT_CPLD_LPC_REG_LC_OK_EVENT_OFFSET 0xa7 +#define MLXPLAT_CPLD_LPC_REG_LC_OK_MASK_OFFSET 0xa8 +#define MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET 0xa9 +#define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa +#define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab +#define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2 #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8 #define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 @@ -99,12 +131,14 @@ #define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7 #define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8 #define MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET 0xf9 +#define MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET 0xfa #define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb #define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda #define MLXPLAT_CPLD_LPC_I2C_CH3_OFF 0xdc +#define MLXPLAT_CPLD_LPC_I2C_CH4_OFF 0xdd #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ @@ -116,6 +150,9 @@ #define MLXPLAT_CPLD_LPC_REG3 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ MLXPLAT_CPLD_LPC_I2C_CH3_OFF) | \ MLXPLAT_CPLD_LPC_PIO_OFFSET) +#define MLXPLAT_CPLD_LPC_REG4 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ + MLXPLAT_CPLD_LPC_I2C_CH4_OFF) | \ + MLXPLAT_CPLD_LPC_PIO_OFFSET) /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ #define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04 @@ -128,6 +165,24 @@ #define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 #define MLXPLAT_CPLD_AGGR_MASK_COMEX BIT(0) +#define MLXPLAT_CPLD_AGGR_MASK_LC BIT(3) +#define MLXPLAT_CPLD_AGGR_MASK_MODULAR (MLXPLAT_CPLD_AGGR_MASK_NG_DEF | \ + MLXPLAT_CPLD_AGGR_MASK_COMEX | \ + MLXPLAT_CPLD_AGGR_MASK_LC) +#define MLXPLAT_CPLD_AGGR_MASK_LC_PRSNT BIT(0) +#define MLXPLAT_CPLD_AGGR_MASK_LC_RDY BIT(1) +#define MLXPLAT_CPLD_AGGR_MASK_LC_PG BIT(2) +#define MLXPLAT_CPLD_AGGR_MASK_LC_SCRD BIT(3) +#define MLXPLAT_CPLD_AGGR_MASK_LC_SYNC BIT(4) +#define MLXPLAT_CPLD_AGGR_MASK_LC_ACT BIT(5) +#define MLXPLAT_CPLD_AGGR_MASK_LC_SDWN BIT(6) +#define MLXPLAT_CPLD_AGGR_MASK_LC_LOW (MLXPLAT_CPLD_AGGR_MASK_LC_PRSNT | \ + MLXPLAT_CPLD_AGGR_MASK_LC_RDY | \ + MLXPLAT_CPLD_AGGR_MASK_LC_PG | \ + MLXPLAT_CPLD_AGGR_MASK_LC_SCRD | \ + MLXPLAT_CPLD_AGGR_MASK_LC_SYNC | \ + MLXPLAT_CPLD_AGGR_MASK_LC_ACT | \ + MLXPLAT_CPLD_AGGR_MASK_LC_SDWN) #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) @@ -149,6 +204,9 @@ MLXPLAT_CPLD_AGGR_MASK_CARRIER) #define MLXPLAT_CPLD_LOW_AGGRCX_MASK 0xc1 +/* Masks for aggregation for modular systems */ +#define MLXPLAT_CPLD_LPC_LC_MASK GENMASK(7, 0) + /* Default I2C parent bus number */ #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 @@ -163,9 +221,12 @@ #define MLXPLAT_CPLD_CH1 2 #define MLXPLAT_CPLD_CH2 10 #define MLXPLAT_CPLD_CH3 18 +#define MLXPLAT_CPLD_CH2_ETH_MODULAR 3 +#define MLXPLAT_CPLD_CH3_ETH_MODULAR 43 +#define MLXPLAT_CPLD_CH4_ETH_MODULAR 51 /* Number of LPC attached MUX platform devices */ -#define MLXPLAT_CPLD_LPC_MUX_DEVS 3 +#define MLXPLAT_CPLD_LPC_MUX_DEVS 4 /* Hotplug devices adapter numbers */ #define MLXPLAT_CPLD_NR_NONE -1 @@ -175,6 +236,11 @@ #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 +#define MLXPLAT_CPLD_NR_ASIC 3 +#define MLXPLAT_CPLD_NR_LC_BASE 34 + +#define MLXPLAT_CPLD_NR_LC_SET(nr) (MLXPLAT_CPLD_NR_LC_BASE + (nr)) +#define MLXPLAT_CPLD_LC_ADDR 0x32 /* Masks and default values for watchdogs */ #define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1) @@ -190,6 +256,11 @@ #define MLXPLAT_CPLD_WD3_DFLT_TIMEOUT 600 #define MLXPLAT_CPLD_WD_MAX_DEVS 2 +#define MLXPLAT_CPLD_LPC_SYSIRQ 17 + +/* Minimum power required for turning on Ethernet modular system (WATT) */ +#define MLXPLAT_CPLD_ETH_MODULAR_PWR_MIN 50 + /* mlxplat_priv - platform private data * @pdev_i2c - i2c controller platform device * @pdev_mux - array of mux platform devices @@ -318,6 +389,58 @@ static struct i2c_mux_reg_platform_data mlxplat_extended_mux_data[] = { }; +/* Platform channels for modular system family */ +static const int mlxplat_modular_upper_channel[] = { 1 }; +static const int mlxplat_modular_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40 +}; + +/* Platform modular mux data */ +static struct i2c_mux_reg_platform_data mlxplat_modular_mux_data[] = { + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH1, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG4, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_modular_upper_channel, + .n_values = ARRAY_SIZE(mlxplat_modular_upper_channel), + }, + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH2_ETH_MODULAR, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_modular_channels, + .n_values = ARRAY_SIZE(mlxplat_modular_channels), + }, + { + .parent = MLXPLAT_CPLD_CH1, + .base_nr = MLXPLAT_CPLD_CH3_ETH_MODULAR, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG3, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_msn21xx_channels, + .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), + }, + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH4_ETH_MODULAR, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_msn21xx_channels, + .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), + }, +}; + /* Platform hotplug devices */ static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { { @@ -968,6 +1091,764 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; +static struct mlxreg_core_data mlxplat_mlxcpld_modular_pwr_items_data[] = { + { + .label = "pwr1", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, + { + .label = "pwr2", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, + { + .label = "pwr3", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_ext_pwr[0], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, + { + .label = "pwr4", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_ext_pwr[1], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, +}; + +static +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_lc_act = { + .irq = MLXPLAT_CPLD_LPC_SYSIRQ, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_asic_items_data[] = { + { + .label = "asic1", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + +static struct i2c_board_info mlxplat_mlxcpld_lc_i2c_dev[] = { + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, + { + I2C_BOARD_INFO("mlxreg-lc", MLXPLAT_CPLD_LC_ADDR), + .platform_data = &mlxplat_mlxcpld_lc_act, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { + { + .label = "lc1_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 1, + }, + { + .label = "lc2_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 2, + }, + { + .label = "lc3_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 3, + }, + { + .label = "lc4_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 4, + }, + { + .label = "lc5_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(4), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 5, + }, + { + .label = "lc6_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(5), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 6, + }, + { + .label = "lc7_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(6), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 7, + }, + { + .label = "lc8_present", + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = BIT(7), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 8, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { + { + .label = "lc1_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(0), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 1, + }, + { + .label = "lc2_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(1), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 2, + }, + { + .label = "lc3_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(2), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 3, + }, + { + .label = "lc4_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(3), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 4, + }, + { + .label = "lc5_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(4), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 5, + }, + { + .label = "lc6_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(5), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 6, + }, + { + .label = "lc7_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(6), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 7, + }, + { + .label = "lc8_verified", + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = BIT(7), + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .reg_sync = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .reg_pwr = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .reg_ena = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .slot = 8, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { + { + .label = "lc1_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 1, + }, + { + .label = "lc2_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 2, + }, + { + .label = "lc3_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 3, + }, + { + .label = "lc4_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 4, + }, + { + .label = "lc5_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(4), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 5, + }, + { + .label = "lc6_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(5), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 6, + }, + { + .label = "lc7_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(6), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 7, + }, + { + .label = "lc8_powered", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = BIT(7), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 8, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { + { + .label = "lc1_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 1, + }, + { + .label = "lc2_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 2, + }, + { + .label = "lc3_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 3, + }, + { + .label = "lc4_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 4, + }, + { + .label = "lc5_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(4), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 5, + }, + { + .label = "lc6_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(5), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 6, + }, + { + .label = "lc7_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(6), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 7, + }, + { + .label = "lc8_ready", + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = BIT(7), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 8, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { + { + .label = "lc1_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 1, + }, + { + .label = "lc2_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 2, + }, + { + .label = "lc3_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 3, + }, + { + .label = "lc4_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 4, + }, + { + .label = "lc5_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(4), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 5, + }, + { + .label = "lc6_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(5), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 6, + }, + { + .label = "lc7_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(6), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 7, + }, + { + .label = "lc8_synced", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = BIT(7), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 8, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { + { + .label = "lc1_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 1, + }, + { + .label = "lc2_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 2, + }, + { + .label = "lc3_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 3, + }, + { + .label = "lc4_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 4, + }, + { + .label = "lc5_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(4), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 5, + }, + { + .label = "lc6_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(5), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 6, + }, + { + .label = "lc7_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(6), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 7, + }, + { + .label = "lc8_active", + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = BIT(7), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 8, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { + { + .label = "lc1_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 1, + }, + { + .label = "lc2_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 2, + }, + { + .label = "lc3_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 3, + }, + { + .label = "lc4_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 4, + }, + { + .label = "lc5_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(4), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 5, + }, + { + .label = "lc6_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(5), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 6, + }, + { + .label = "lc7_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(6), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 7, + }, + { + .label = "lc8_shutdown", + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = BIT(7), + .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], + .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), + .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .slot = 8, + }, +}; + +static struct mlxreg_core_item mlxplat_mlxcpld_modular_items[] = { + { + .data = mlxplat_mlxcpld_ext_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_EXT_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, + .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_psu_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_EXT_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, + .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_pwr_items_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_ng_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = MLXPLAT_CPLD_FAN_NG_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_asic_items_data), + .inversed = 0, + .health = true, + }, + { + .data = mlxplat_mlxcpld_modular_lc_pr_items_data, + .kind = MLXREG_HOTPLUG_LC_PRESENT, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_LC, + .reg = MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET, + .mask = MLXPLAT_CPLD_LPC_LC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_lc_pr_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_lc_ver_items_data, + .kind = MLXREG_HOTPLUG_LC_VERIFIED, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_LC, + .reg = MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET, + .mask = MLXPLAT_CPLD_LPC_LC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_lc_ver_items_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_lc_pg_data, + .kind = MLXREG_HOTPLUG_LC_POWERED, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_LC, + .reg = MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET, + .mask = MLXPLAT_CPLD_LPC_LC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_lc_pg_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_lc_ready_data, + .kind = MLXREG_HOTPLUG_LC_READY, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_LC, + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, + .mask = MLXPLAT_CPLD_LPC_LC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_lc_ready_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_lc_synced_data, + .kind = MLXREG_HOTPLUG_LC_SYNCED, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_LC, + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, + .mask = MLXPLAT_CPLD_LPC_LC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_lc_synced_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_lc_act_data, + .kind = MLXREG_HOTPLUG_LC_ACTIVE, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_LC, + .reg = MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET, + .mask = MLXPLAT_CPLD_LPC_LC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_lc_act_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_modular_lc_sd_data, + .kind = MLXREG_HOTPLUG_LC_THERMAL, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_LC, + .reg = MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET, + .mask = MLXPLAT_CPLD_LPC_LC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_lc_sd_data), + .inversed = 0, + .health = false, + }, +}; + +static +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_modular_data = { + .items = mlxplat_mlxcpld_modular_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_MODULAR, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, +}; + /* Platform led default data */ static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { { @@ -1283,6 +2164,158 @@ static struct mlxreg_core_platform_data mlxplat_comex_100G_led_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_100G_led_data), }; +/* Platform led for data for modular systems */ +static struct mlxreg_core_data mlxplat_mlxcpld_modular_led_data[] = { + { + .label = "status:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "psu:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan1:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(0), + }, + { + .label = "fan1:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(0), + }, + { + .label = "fan2:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(1), + }, + { + .label = "fan2:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(1), + }, + { + .label = "fan3:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(2), + }, + { + .label = "fan3:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(2), + }, + { + .label = "fan4:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(3), + }, + { + .label = "fan4:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(3), + }, + { + .label = "fan5:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(4), + }, + { + .label = "fan5:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(4), + }, + { + .label = "fan6:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(5), + }, + { + .label = "fan6:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(5), + }, + { + .label = "fan7:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(6), + }, + { + .label = "fan7:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(6), + }, + { + .label = "uid:blue", + .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan_front:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan_front:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "mgmt:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED7_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "mgmt:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED7_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_modular_led_data = { + .data = mlxplat_mlxcpld_modular_led_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_led_data), +}; + /* Platform register access default */ static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { { @@ -1814,6 +2847,484 @@ static struct mlxreg_core_platform_data mlxplat_default_ng_regs_io_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_regs_io_data), }; +/* Platform register access for modular systems families data */ +static struct mlxreg_core_data mlxplat_mlxcpld_modular_regs_io_data[] = { + { + .label = "cpld1_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld2_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld3_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld4_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld1_pn", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "cpld2_pn", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "cpld3_pn", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "cpld4_pn", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "cpld1_version_min", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld2_version_min", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld3_version_min", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld4_version_min", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD4_MVER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "lc1_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0644, + }, + { + .label = "lc2_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0644, + }, + { + .label = "lc3_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0644, + }, + { + .label = "lc4_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0644, + }, + { + .label = "lc5_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, + { + .label = "lc6_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0644, + }, + { + .label = "lc7_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + }, + { + .label = "lc8_enable", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0644, + }, + { + .label = "reset_long_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_short_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_fu", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_mgmt_dc_dc_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_sys_comex_bios", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_sw_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_reload", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_comex_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_platform", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_soc", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_pwr_off_from_carrier", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, + { + .label = "reset_swb_wd", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_swb_aux_pwr_or_fu", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_swb_dc_dc_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_swb_12v_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_system", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_thermal_spc_or_pciesw", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, + { + .label = "bios_safe_mode", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "bios_active_image", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "bios_auth_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "bios_upgrade_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, + { + .label = "voltreg_update_status", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, + .mask = MLXPLAT_CPLD_VOLTREG_UPD_MASK, + .bit = 5, + .mode = 0444, + }, + { + .label = "vpd_wp", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0644, + }, + { + .label = "pcie_asic_reset_dis", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, + { + .label = "shutdown_unlock", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0644, + }, + { + .label = "lc1_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0200, + }, + { + .label = "lc2_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0200, + }, + { + .label = "lc3_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, + { + .label = "lc4_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "lc5_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0200, + }, + { + .label = "lc6_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0200, + }, + { + .label = "lc7_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0200, + }, + { + .label = "lc8_rst_mask", + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0200, + }, + { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0200, + }, + { + .label = "psu2_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0200, + }, + { + .label = "pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, + { + .label = "pwr_down", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "psu3_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0200, + }, + { + .label = "psu4_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0200, + }, + { + .label = "auto_power_mode", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + }, + { + .label = "pm_mgmt_en", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0644, + }, + { + .label = "jtag_enable", + .reg = MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE, + .mask = GENMASK(3, 0), + .bit = 1, + .mode = 0644, + }, + { + .label = "safe_bios_dis", + .reg = MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0644, + }, + { + .label = "safe_bios_dis_wp", + .reg = MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0644, + }, + { + .label = "asic_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .bit = 1, + .mode = 0444, + }, + { + .label = "fan_dir", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "lc1_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0644, + }, + { + .label = "lc2_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0644, + }, + { + .label = "lc3_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0644, + }, + { + .label = "lc4_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0644, + }, + { + .label = "lc5_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, + { + .label = "lc6_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0644, + }, + { + .label = "lc7_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + }, + { + .label = "lc8_pwr", + .reg = MLXPLAT_CPLD_LPC_REG_LC_PWR_ON, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0644, + }, + { + .label = "config1", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "config2", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "ufm_version", + .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_modular_regs_io_data = { + .data = mlxplat_mlxcpld_modular_regs_io_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_regs_io_data), +}; + /* Platform FAN default */ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { { @@ -2152,16 +3663,23 @@ static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type3[] = { static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED6_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED7_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE: + case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: @@ -2174,6 +3692,23 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: @@ -2202,6 +3737,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET: @@ -2210,13 +3746,20 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED6_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED7_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE: + case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: @@ -2237,6 +3780,30 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: @@ -2270,6 +3837,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: @@ -2289,6 +3857,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET: @@ -2297,11 +3866,18 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED6_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED7_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE: + case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: @@ -2322,6 +3898,30 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PG_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_RD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_OK_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: @@ -2349,6 +3949,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: @@ -2382,6 +3983,16 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = { { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, }; +static const struct reg_default mlxplat_mlxcpld_regmap_eth_modular[] = { + { MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 0x61 }, + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET, + MLXPLAT_CPLD_AGGR_MASK_LC_LOW }, +}; + struct mlxplat_mlxcpld_regmap_context { void __iomem *base; }; @@ -2462,8 +4073,22 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = { .reg_write = mlxplat_mlxcpld_reg_write, }; +static const struct regmap_config mlxplat_mlxcpld_regmap_config_eth_modular = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 255, + .cache_type = REGCACHE_FLAT, + .writeable_reg = mlxplat_mlxcpld_writeable_reg, + .readable_reg = mlxplat_mlxcpld_readable_reg, + .volatile_reg = mlxplat_mlxcpld_volatile_reg, + .reg_defaults = mlxplat_mlxcpld_regmap_eth_modular, + .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_eth_modular), + .reg_read = mlxplat_mlxcpld_reg_read, + .reg_write = mlxplat_mlxcpld_reg_write, +}; + static struct resource mlxplat_mlxcpld_resources[] = { - [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), + [0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"), }; static struct platform_device *mlxplat_dev; @@ -2640,6 +4265,26 @@ static int __init mlxplat_dmi_ng400_matched(const struct dmi_system_id *dmi) return 1; } +static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) +{ + int i; + + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; + mlxplat_mux_num = ARRAY_SIZE(mlxplat_modular_mux_data); + mlxplat_mux_data = mlxplat_modular_mux_data; + mlxplat_hotplug = &mlxplat_mlxcpld_modular_data; + mlxplat_hotplug->deferred_nr = MLXPLAT_CPLD_CH4_ETH_MODULAR; + mlxplat_led = &mlxplat_modular_led_data; + mlxplat_regs_io = &mlxplat_modular_regs_io_data; + mlxplat_fan = &mlxplat_default_fan_data; + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_eth_modular; + + return 1; +} + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { { .callback = mlxplat_dmi_default_matched, @@ -2689,6 +4334,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"), }, }, + { + .callback = mlxplat_dmi_modular_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0011"), + }, + }, { .callback = mlxplat_dmi_msn274x_matched, .matches = { From bb1023b6da379985ff888dcd7bc601735d02267a Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:32 +0300 Subject: [PATCH 062/106] platform/mellanox: mlxreg-hotplug: Extend logic for hotplug devices operations Extend the structure 'mlxreg_hotplug_device" with platform device field to allow transition of the register map and system interrupt line number to underlying hotplug devices, sharing the same register map and same interrupt line with 'mlxreg-hotplug' driver. Extend logic for hotplug devices creation and removing according to the action associated with the hotplug device description. Previously hotplug driver was capable to attach / de-attach upon hotplug events only I2C devices handled by simple I2C drivers. Now it should be able to attach also devices handled by the platform drivers. The motivation is to allow transition of platform data like: - system interrupt line number, sharing with 'mlxreg-hotplug' to underlying hotplug devices. - shared register map of programmable devices on main board to underlying hotplug devices. Additioanlly the number of 'sysfs' attributes is increased, since modular system defines more 'sysfs' attributes. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-4-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-hotplug.c | 127 +++++++++++++++------ include/linux/platform_data/mlxreg.h | 24 ++++ 2 files changed, 114 insertions(+), 37 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index b013445147dd..117bc3f395fd 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -28,7 +28,7 @@ /* ASIC good health mask. */ #define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02 -#define MLXREG_HOTPLUG_ATTRS_MAX 24 +#define MLXREG_HOTPLUG_ATTRS_MAX 128 #define MLXREG_HOTPLUG_NOT_ASSERT 3 /** @@ -89,9 +89,20 @@ mlxreg_hotplug_udev_event_send(struct kobject *kobj, return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp); } -static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, - struct mlxreg_core_data *data) +static void +mlxreg_hotplug_pdata_export(void *pdata, void *regmap) { + struct mlxreg_core_hotplug_platform_data *dev_pdata = pdata; + + /* Export regmap to underlying device. */ + dev_pdata->regmap = regmap; +} + +static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, + struct mlxreg_core_data *data, + enum mlxreg_hotplug_kind kind) +{ + struct i2c_board_info *brdinfo = data->hpdev.brdinfo; struct mlxreg_core_hotplug_platform_data *pdata; struct i2c_client *client; @@ -106,46 +117,88 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, return 0; pdata = dev_get_platdata(&priv->pdev->dev); - data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr + - pdata->shift_nr); - if (!data->hpdev.adapter) { - dev_err(priv->dev, "Failed to get adapter for bus %d\n", - data->hpdev.nr + pdata->shift_nr); - return -EFAULT; + switch (data->hpdev.action) { + case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION: + data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr + + pdata->shift_nr); + if (!data->hpdev.adapter) { + dev_err(priv->dev, "Failed to get adapter for bus %d\n", + data->hpdev.nr + pdata->shift_nr); + return -EFAULT; + } + + /* Export platform data to underlying device. */ + if (brdinfo->platform_data) + mlxreg_hotplug_pdata_export(brdinfo->platform_data, pdata->regmap); + + client = i2c_new_client_device(data->hpdev.adapter, + brdinfo); + if (IS_ERR(client)) { + dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", + brdinfo->type, data->hpdev.nr + + pdata->shift_nr, brdinfo->addr); + + i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; + return PTR_ERR(client); + } + + data->hpdev.client = client; + break; + case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION: + /* Export platform data to underlying device. */ + if (data->hpdev.brdinfo && data->hpdev.brdinfo->platform_data) + mlxreg_hotplug_pdata_export(data->hpdev.brdinfo->platform_data, + pdata->regmap); + /* Pass parent hotplug device handle to underlying device. */ + data->notifier = data->hpdev.notifier; + data->hpdev.pdev = platform_device_register_resndata(&priv->pdev->dev, + brdinfo->type, + data->hpdev.nr, + NULL, 0, data, + sizeof(*data)); + if (IS_ERR(data->hpdev.pdev)) + return PTR_ERR(data->hpdev.pdev); + + break; + default: + break; } - client = i2c_new_client_device(data->hpdev.adapter, - data->hpdev.brdinfo); - if (IS_ERR(client)) { - dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", - data->hpdev.brdinfo->type, data->hpdev.nr + - pdata->shift_nr, data->hpdev.brdinfo->addr); - - i2c_put_adapter(data->hpdev.adapter); - data->hpdev.adapter = NULL; - return PTR_ERR(client); - } - - data->hpdev.client = client; + if (data->hpdev.notifier && data->hpdev.notifier->user_handler) + return data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 1); return 0; } static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv, - struct mlxreg_core_data *data) + struct mlxreg_core_data *data, + enum mlxreg_hotplug_kind kind) { /* Notify user by sending hwmon uevent. */ mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false); + if (data->hpdev.notifier && data->hpdev.notifier->user_handler) + data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 0); - if (data->hpdev.client) { - i2c_unregister_device(data->hpdev.client); - data->hpdev.client = NULL; - } + switch (data->hpdev.action) { + case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION: + if (data->hpdev.client) { + i2c_unregister_device(data->hpdev.client); + data->hpdev.client = NULL; + } - if (data->hpdev.adapter) { - i2c_put_adapter(data->hpdev.adapter); - data->hpdev.adapter = NULL; + if (data->hpdev.adapter) { + i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; + } + break; + case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION: + if (data->hpdev.pdev) + platform_device_unregister(data->hpdev.pdev); + break; + default: + break; } } @@ -317,14 +370,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, data = item->data + bit; if (regval & BIT(bit)) { if (item->inversed) - mlxreg_hotplug_device_destroy(priv, data); + mlxreg_hotplug_device_destroy(priv, data, item->kind); else - mlxreg_hotplug_device_create(priv, data); + mlxreg_hotplug_device_create(priv, data, item->kind); } else { if (item->inversed) - mlxreg_hotplug_device_create(priv, data); + mlxreg_hotplug_device_create(priv, data, item->kind); else - mlxreg_hotplug_device_destroy(priv, data); + mlxreg_hotplug_device_destroy(priv, data, item->kind); } } @@ -381,7 +434,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, * ASIC is in steady state. Connect associated * device, if configured. */ - mlxreg_hotplug_device_create(priv, data); + mlxreg_hotplug_device_create(priv, data, item->kind); data->attached = true; } } else { @@ -391,7 +444,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, * in steady state. Disconnect associated * device, if it has been connected. */ - mlxreg_hotplug_device_destroy(priv, data); + mlxreg_hotplug_device_destroy(priv, data, item->kind); data->attached = false; data->health_cntr = 0; } @@ -630,7 +683,7 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) /* Remove all the attached devices in group. */ count = item->count; for (j = 0; j < count; j++, data++) - mlxreg_hotplug_device_destroy(priv, data); + mlxreg_hotplug_device_destroy(priv, data, item->kind); } } diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index 49f0e15a10dd..3122d550dc00 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h @@ -69,6 +69,19 @@ enum mlxreg_hotplug_device_action { MLXREG_HOTPLUG_DEVICE_NO_ACTION = 2, }; +/** + * struct mlxreg_core_hotplug_notifier - hotplug notifier block: + * + * @identity: notifier identity name; + * @handle: user handle to be passed by user handler function; + * @user_handler: user handler function associated with the event; + */ +struct mlxreg_core_hotplug_notifier { + char identity[MLXREG_CORE_LABEL_MAX_SIZE]; + void *handle; + int (*user_handler)(void *handle, enum mlxreg_hotplug_kind kind, u8 action); +}; + /** * struct mlxreg_hotplug_device - I2C device data: * @@ -76,7 +89,11 @@ enum mlxreg_hotplug_device_action { * @client: I2C device client; * @brdinfo: device board information; * @nr: I2C device adapter number, to which device is to be attached; + * @pdev: platform device, if device is instantiated as a platform device; * @action: action to be performed upon event receiving; + * @handle: user handle to be passed by user handler function; + * @user_handler: user handler function associated with the event; + * @notifier: pointer to event notifier block; * * Structure represents I2C hotplug device static data (board topology) and * dynamic data (related kernel objects handles). @@ -86,7 +103,11 @@ struct mlxreg_hotplug_device { struct i2c_client *client; struct i2c_board_info *brdinfo; int nr; + struct platform_device *pdev; enum mlxreg_hotplug_device_action action; + void *handle; + int (*user_handler)(void *handle, enum mlxreg_hotplug_kind kind, u8 action); + struct mlxreg_core_hotplug_notifier *notifier; }; /** @@ -104,10 +125,12 @@ struct mlxreg_hotplug_device { * @mode: access mode; * @np - pointer to node platform associated with attribute; * @hpdev - hotplug device data; + * @notifier: pointer to event notifier block; * @health_cntr: dynamic device health indication counter; * @attached: true if device has been attached after good health indication; * @regnum: number of registers occupied by multi-register attribute; * @slot: slot number, at which device is located; + * @secured: if set indicates that entry access is secured; */ struct mlxreg_core_data { char label[MLXREG_CORE_LABEL_MAX_SIZE]; @@ -122,6 +145,7 @@ struct mlxreg_core_data { umode_t mode; struct device_node *np; struct mlxreg_hotplug_device hpdev; + struct mlxreg_core_hotplug_notifier *notifier; u32 health_cntr; bool attached; u8 regnum; From 67eb006cc1d167db33de2fe87988198b9806e794 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:33 +0300 Subject: [PATCH 063/106] platform/x86: mlx-platform: Configure notifier callbacks for modular system Add event notifier callbacks for modular system line cards. These callbacks are to be passed to "mlxreg-hotplug" driver by line card driver during probing. Then, when any line card related hotplug event is received (insertion ,power, synch, ready), hotplug driver will invoke callback for the relevant line card. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-5-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 83 +++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index a30af1fc5c75..2ab499686564 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -1171,6 +1171,33 @@ static struct i2c_board_info mlxplat_mlxcpld_lc_i2c_dev[] = { }, }; +static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_modular_lc_notifier[] = { + { + .identity = "lc1", + }, + { + .identity = "lc2", + }, + { + .identity = "lc3", + }, + { + .identity = "lc4", + }, + { + .identity = "lc5", + }, + { + .identity = "lc6", + }, + { + .identity = "lc7", + }, + { + .identity = "lc8", + }, +}; + static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { { .label = "lc1_present", @@ -1179,6 +1206,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[0], .slot = 1, }, { @@ -1188,6 +1216,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[1], .slot = 2, }, { @@ -1197,6 +1226,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[2], .slot = 3, }, { @@ -1206,6 +1236,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[3], .slot = 4, }, { @@ -1215,6 +1246,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[4], .slot = 5, }, { @@ -1224,6 +1256,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[5], .slot = 6, }, { @@ -1233,6 +1266,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[6], .slot = 7, }, { @@ -1242,6 +1276,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pr_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[7], .slot = 8, }, }; @@ -1258,6 +1293,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[0], .slot = 1, }, { @@ -1271,6 +1307,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[1], .slot = 2, }, { @@ -1284,6 +1321,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[2], .slot = 3, }, { @@ -1297,6 +1335,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[3], .slot = 4, }, { @@ -1310,6 +1349,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[4], .slot = 5, }, { @@ -1323,6 +1363,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[5], .slot = 6, }, { @@ -1336,6 +1377,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[6], .slot = 7, }, { @@ -1349,6 +1391,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ver_items_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), .hpdev.action = MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[7], .slot = 8, }, }; @@ -1361,6 +1404,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[0], .slot = 1, }, { @@ -1370,6 +1414,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[1], .slot = 2, }, { @@ -1379,6 +1424,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[2], .slot = 3, }, { @@ -1388,6 +1434,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[3], .slot = 4, }, { @@ -1397,6 +1444,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[4], .slot = 5, }, { @@ -1406,6 +1454,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[5], .slot = 6, }, { @@ -1415,6 +1464,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[6], .slot = 7, }, { @@ -1424,6 +1474,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_pg_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[7], .slot = 8, }, }; @@ -1436,6 +1487,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[0], .slot = 1, }, { @@ -1445,6 +1497,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[1], .slot = 2, }, { @@ -1454,6 +1507,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[2], .slot = 3, }, { @@ -1463,6 +1517,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[3], .slot = 4, }, { @@ -1472,6 +1527,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[4], .slot = 5, }, { @@ -1481,6 +1537,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[5], .slot = 6, }, { @@ -1490,6 +1547,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[6], .slot = 7, }, { @@ -1499,6 +1557,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_ready_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[7], .slot = 8, }, }; @@ -1511,6 +1570,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[0], .slot = 1, }, { @@ -1520,6 +1580,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[1], .slot = 2, }, { @@ -1529,6 +1590,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[2], .slot = 3, }, { @@ -1538,6 +1600,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[3], .slot = 4, }, { @@ -1547,6 +1610,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[4], .slot = 5, }, { @@ -1556,6 +1620,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[5], .slot = 6, }, { @@ -1565,6 +1630,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[6], .slot = 7, }, { @@ -1574,6 +1640,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_synced_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[7], .slot = 8, }, }; @@ -1586,6 +1653,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[0], .slot = 1, }, { @@ -1595,6 +1663,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[1], .slot = 2, }, { @@ -1604,6 +1673,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[2], .slot = 3, }, { @@ -1613,6 +1683,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[3], .slot = 4, }, { @@ -1622,6 +1693,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[4], .slot = 5, }, { @@ -1631,6 +1703,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[5], .slot = 6, }, { @@ -1640,6 +1713,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[6], .slot = 7, }, { @@ -1649,6 +1723,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_act_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[7], .slot = 8, }, }; @@ -1661,6 +1736,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[0], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(0), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[0], .slot = 1, }, { @@ -1670,6 +1746,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[1], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(1), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[1], .slot = 2, }, { @@ -1679,6 +1756,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[2], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(2), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[2], .slot = 3, }, { @@ -1688,6 +1766,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[3], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(3), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[3], .slot = 4, }, { @@ -1697,6 +1776,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[4], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(4), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[4], .slot = 5, }, { @@ -1706,6 +1786,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[5], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(5), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[5], .slot = 6, }, { @@ -1715,6 +1796,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[6], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(6), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[6], .slot = 7, }, { @@ -1724,6 +1806,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_lc_sd_data[] = { .hpdev.brdinfo = &mlxplat_mlxcpld_lc_i2c_dev[7], .hpdev.nr = MLXPLAT_CPLD_NR_LC_SET(7), .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_modular_lc_notifier[7], .slot = 8, }, }; From bbfd79c681706e2be8cdf95e2711b9ff9c669ae4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:34 +0300 Subject: [PATCH 064/106] platform/mellanox: mlxreg-io: Extend number of hwmon attributes Extend maximum number of the attributes, exposed to 'sysfs'. It is requires in order to support modular systems, which provide more attributes for system control, statuses and info. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-6-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c index a916cd89cbbe..2c2686d5c2fc 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -18,7 +18,7 @@ /* Attribute parameters. */ #define MLXREG_IO_ATT_SIZE 10 -#define MLXREG_IO_ATT_NUM 48 +#define MLXREG_IO_ATT_NUM 96 /** * struct mlxreg_io_priv_data - driver's private data: From 9d93d7877c9158d059028681b66a0c192f85c64d Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:35 +0300 Subject: [PATCH 065/106] platform_data/mlxreg: Add new field for secured access Extend structure 'mlxreg_core_data' with the field "secured". The purpose of this field is to restrict access to some attributes, if kernel is configured with security options, like: LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY. Access to some attributes, which for example, allow burning of some hardware components, like FPGA, CPLD, SPI, etcetera can break the system. In case user does not want to allow such access, it can disable it by setting security options. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-7-vadimp@nvidia.com Signed-off-by: Hans de Goede --- include/linux/platform_data/mlxreg.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index 3122d550dc00..40185f9d7c14 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h @@ -150,6 +150,7 @@ struct mlxreg_core_data { bool attached; u8 regnum; u8 slot; + u8 secured; }; /** From 62f9529b8d5c87b89c3d9698405014bc8f370fbd Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:36 +0300 Subject: [PATCH 066/106] platform/mellanox: mlxreg-lc: Add initial support for Nvidia line card devices Provide support for the Nvidia MSN4800-XX line cards for MSN4800 Ethernet modular switch system, providing a high performance switching solution for Enterprise Data Centers (EDC) for building Ethernet based clusters, High-Performance Computing (HPC) and embedded environments. Initial version provides support for line card type MSN4800-C16. This type of line card is equipped with: - Lattice CPLD device, used for system and ports control. - four Nvidia gearbox devices, used for port splitting. - FPGA device, used for gearboxes management. - 16x100G QSFP28 ports. - hotpswap controllers, voltage regulators, analog-to-digital convertors, nvram devices. - status LED. During initialization driver creates: - line card's I2C tree through "i2c-mux-mlxcpd" driver. - line card's LED objects through "leds-mlxreg" driver. - line card's CPLD register space input / output "hwmon" attributes for line control and monitoring through "mlxreg-io" driver. These attributes provide CPLD and FPAG versioning, control for upgradable components burning, NVRAM devices write protection, line card revision, line card power consuming, line card reset cause indication, etcetera. Lattice CPLD device and nvram devices are feeding from auxiliary power domain and accessible, when line card is powered off. These devices are connected by line card driver probing routine, invoked after line card security verification is done by hardware and event lc#n_verified is received for line card located in slot #n. Gearboxes, FPGA, hotpswap controllers, voltage regulators, analog-to-digital convertors are feeding from main power domain. These devices are connected after power good event "lc#n_powered" is received for line card located in slot #n. The driver 'mlxreg-lc' is driven by 'mlxreg-hotplug' driver following relevant "hotplug" events. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-8-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/mellanox/Kconfig | 12 + drivers/platform/mellanox/Makefile | 1 + drivers/platform/mellanox/mlxreg-lc.c | 906 ++++++++++++++++++++++++++ 3 files changed, 919 insertions(+) create mode 100644 drivers/platform/mellanox/mlxreg-lc.c diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig index edd17e1a1f88..d4c5c170bca0 100644 --- a/drivers/platform/mellanox/Kconfig +++ b/drivers/platform/mellanox/Kconfig @@ -34,6 +34,18 @@ config MLXREG_IO to system resets operation, system reset causes monitoring and some kinds of mux selection. +config MLXREG_LC + tristate "Mellanox line card platform driver support" + depends on REGMAP + depends on HWMON + depends on I2C + help + This driver provides support for the Mellanox MSN4800-XX line cards, + which are the part of MSN4800 Ethernet modular switch systems + providing a high performance switching solution for Enterprise Data + Centers (EDC) for building Ethernet based clusters, High-Performance + Computing (HPC) and embedded environments. + config MLXBF_TMFIFO tristate "Mellanox BlueField SoC TmFifo platform driver" depends on ARM64 diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile index 000ddaa74c98..a4868366ff18 100644 --- a/drivers/platform/mellanox/Makefile +++ b/drivers/platform/mellanox/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o +obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c new file mode 100644 index 000000000000..0b7f58feb701 --- /dev/null +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -0,0 +1,906 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Nvidia line card driver + * + * Copyright (C) 2020 Nvidia Technologies Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* I2C bus IO offsets */ +#define MLXREG_LC_REG_CPLD1_VER_OFFSET 0x2500 +#define MLXREG_LC_REG_FPGA1_VER_OFFSET 0x2501 +#define MLXREG_LC_REG_CPLD1_PN_OFFSET 0x2504 +#define MLXREG_LC_REG_FPGA1_PN_OFFSET 0x2506 +#define MLXREG_LC_REG_RESET_CAUSE_OFFSET 0x251d +#define MLXREG_LC_REG_LED1_OFFSET 0x2520 +#define MLXREG_LC_REG_GP0_OFFSET 0x252e +#define MLXREG_LC_REG_FIELD_UPGRADE 0x2534 +#define MLXREG_LC_CHANNEL_I2C_REG 0x25dc +#define MLXREG_LC_REG_CPLD1_MVER_OFFSET 0x25de +#define MLXREG_LC_REG_FPGA1_MVER_OFFSET 0x25df +#define MLXREG_LC_REG_MAX_POWER_OFFSET 0x25f1 +#define MLXREG_LC_REG_CONFIG_OFFSET 0x25fb +#define MLXREG_LC_REG_MAX 0x3fff + +/** + * enum mlxreg_lc_type - line cards types + * + * @MLXREG_LC_SN4800_C16: 100GbE line card with 16 QSFP28 ports; + */ +enum mlxreg_lc_type { + MLXREG_LC_SN4800_C16 = 0x0000, +}; + +/** + * enum mlxreg_lc_state - line cards state + * + * @MLXREG_LC_INITIALIZED: line card is initialized; + * @MLXREG_LC_POWERED: line card is powered; + * @MLXREG_LC_SYNCED: line card is synchronized between hardware and firmware; + */ +enum mlxreg_lc_state { + MLXREG_LC_INITIALIZED = BIT(0), + MLXREG_LC_POWERED = BIT(1), + MLXREG_LC_SYNCED = BIT(2), +}; + +#define MLXREG_LC_CONFIGURED (MLXREG_LC_INITIALIZED | MLXREG_LC_POWERED | MLXREG_LC_SYNCED) + +/* mlxreg_lc - device private data + * @dev: platform device; + * @lock: line card lock; + * @par_regmap: parent device regmap handle; + * @data: pltaform core data; + * @io_data: register access platform data; + * @led_data: LED platform data ; + * @mux_data: MUX platform data; + * @led: LED device; + * @io_regs: register access device; + * @mux_brdinfo: mux configuration; + * @mux: mux devices; + * @aux_devs: I2C devices feeding by auxiliary power; + * @aux_devs_num: number of I2C devices feeding by auxiliary power; + * @main_devs: I2C devices feeding by main power; + * @main_devs_num: number of I2C devices feeding by main power; + * @state: line card state; + */ +struct mlxreg_lc { + struct device *dev; + struct mutex lock; /* line card access lock */ + void *par_regmap; + struct mlxreg_core_data *data; + struct mlxreg_core_platform_data *io_data; + struct mlxreg_core_platform_data *led_data; + struct mlxcpld_mux_plat_data *mux_data; + struct platform_device *led; + struct platform_device *io_regs; + struct i2c_board_info *mux_brdinfo; + struct platform_device *mux; + struct mlxreg_hotplug_device *aux_devs; + int aux_devs_num; + struct mlxreg_hotplug_device *main_devs; + int main_devs_num; + enum mlxreg_lc_state state; +}; + +static bool mlxreg_lc_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MLXREG_LC_REG_LED1_OFFSET: + case MLXREG_LC_REG_GP0_OFFSET: + case MLXREG_LC_REG_FIELD_UPGRADE: + case MLXREG_LC_CHANNEL_I2C_REG: + return true; + } + return false; +} + +static bool mlxreg_lc_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MLXREG_LC_REG_CPLD1_VER_OFFSET: + case MLXREG_LC_REG_FPGA1_VER_OFFSET: + case MLXREG_LC_REG_CPLD1_PN_OFFSET: + case MLXREG_LC_REG_FPGA1_PN_OFFSET: + case MLXREG_LC_REG_RESET_CAUSE_OFFSET: + case MLXREG_LC_REG_LED1_OFFSET: + case MLXREG_LC_REG_GP0_OFFSET: + case MLXREG_LC_REG_FIELD_UPGRADE: + case MLXREG_LC_CHANNEL_I2C_REG: + case MLXREG_LC_REG_CPLD1_MVER_OFFSET: + case MLXREG_LC_REG_FPGA1_MVER_OFFSET: + case MLXREG_LC_REG_MAX_POWER_OFFSET: + case MLXREG_LC_REG_CONFIG_OFFSET: + return true; + } + return false; +} + +static bool mlxreg_lc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MLXREG_LC_REG_CPLD1_VER_OFFSET: + case MLXREG_LC_REG_FPGA1_VER_OFFSET: + case MLXREG_LC_REG_CPLD1_PN_OFFSET: + case MLXREG_LC_REG_FPGA1_PN_OFFSET: + case MLXREG_LC_REG_RESET_CAUSE_OFFSET: + case MLXREG_LC_REG_LED1_OFFSET: + case MLXREG_LC_REG_GP0_OFFSET: + case MLXREG_LC_REG_FIELD_UPGRADE: + case MLXREG_LC_CHANNEL_I2C_REG: + case MLXREG_LC_REG_CPLD1_MVER_OFFSET: + case MLXREG_LC_REG_FPGA1_MVER_OFFSET: + case MLXREG_LC_REG_MAX_POWER_OFFSET: + case MLXREG_LC_REG_CONFIG_OFFSET: + return true; + } + return false; +} + +static const struct reg_default mlxreg_lc_regmap_default[] = { + { MLXREG_LC_CHANNEL_I2C_REG, 0x00 }, +}; + +/* Configuration for the register map of a device with 2 bytes address space. */ +static const struct regmap_config mlxreg_lc_regmap_conf = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MLXREG_LC_REG_MAX, + .cache_type = REGCACHE_FLAT, + .writeable_reg = mlxreg_lc_writeable_reg, + .readable_reg = mlxreg_lc_readable_reg, + .volatile_reg = mlxreg_lc_volatile_reg, + .reg_defaults = mlxreg_lc_regmap_default, + .num_reg_defaults = ARRAY_SIZE(mlxreg_lc_regmap_default), +}; + +/* Default channels vector. + * It contains only the channels, which physically connected to the devices, + * empty channels are skipped. + */ +static int mlxreg_lc_chan[] = { + 0x04, 0x05, 0x06, 0x07, 0x08, 0x10, 0x20, 0x21, 0x22, 0x23, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, + 0x4e, 0x4f +}; + +/* Defaul mux configuration. */ +static struct mlxcpld_mux_plat_data mlxreg_lc_mux_data[] = { + { + .chan_ids = mlxreg_lc_chan, + .num_adaps = ARRAY_SIZE(mlxreg_lc_chan), + .sel_reg_addr = MLXREG_LC_CHANNEL_I2C_REG, + .reg_size = 2, + }, +}; + +/* Defaul mux board info. */ +static struct i2c_board_info mlxreg_lc_mux_brdinfo = { + I2C_BOARD_INFO("i2c-mux-mlxcpld", 0x32), +}; + +/* Line card default auxiliary power static devices. */ +static struct i2c_board_info mlxreg_lc_aux_pwr_devices[] = { + { + I2C_BOARD_INFO("24c32", 0x51), + }, + { + I2C_BOARD_INFO("24c32", 0x51), + }, +}; + +/* Line card default auxiliary power board info. */ +static struct mlxreg_hotplug_device mlxreg_lc_aux_pwr_brdinfo[] = { + { + .brdinfo = &mlxreg_lc_aux_pwr_devices[0], + .nr = 3, + }, + { + .brdinfo = &mlxreg_lc_aux_pwr_devices[1], + .nr = 4, + }, +}; + +/* Line card default main power static devices. */ +static struct i2c_board_info mlxreg_lc_main_pwr_devices[] = { + { + I2C_BOARD_INFO("mp2975", 0x62), + }, + { + I2C_BOARD_INFO("mp2975", 0x64), + }, + { + I2C_BOARD_INFO("max11603", 0x6d), + }, + { + I2C_BOARD_INFO("lm25066", 0x15), + }, +}; + +/* Line card default main power board info. */ +static struct mlxreg_hotplug_device mlxreg_lc_main_pwr_brdinfo[] = { + { + .brdinfo = &mlxreg_lc_main_pwr_devices[0], + .nr = 0, + }, + { + .brdinfo = &mlxreg_lc_main_pwr_devices[1], + .nr = 0, + }, + { + .brdinfo = &mlxreg_lc_main_pwr_devices[2], + .nr = 1, + }, + { + .brdinfo = &mlxreg_lc_main_pwr_devices[3], + .nr = 2, + }, +}; + +/* LED default data. */ +static struct mlxreg_core_data mlxreg_lc_led_data[] = { + { + .label = "status:green", + .reg = MLXREG_LC_REG_LED1_OFFSET, + .mask = GENMASK(7, 4), + }, + { + .label = "status:orange", + .reg = MLXREG_LC_REG_LED1_OFFSET, + .mask = GENMASK(7, 4), + }, +}; + +static struct mlxreg_core_platform_data mlxreg_lc_led = { + .identity = "pci", + .data = mlxreg_lc_led_data, + .counter = ARRAY_SIZE(mlxreg_lc_led_data), +}; + +/* Default register access data. */ +static struct mlxreg_core_data mlxreg_lc_io_data[] = { + { + .label = "cpld1_version", + .reg = MLXREG_LC_REG_CPLD1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "fpga1_version", + .reg = MLXREG_LC_REG_FPGA1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld1_pn", + .reg = MLXREG_LC_REG_CPLD1_PN_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "fpga1_pn", + .reg = MLXREG_LC_REG_FPGA1_PN_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "cpld1_version_min", + .reg = MLXREG_LC_REG_CPLD1_MVER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "fpga1_version_min", + .reg = MLXREG_LC_REG_FPGA1_MVER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "reset_fpga_not_done", + .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_ref", + .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_dc_dc_pwr_fail", + .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_from_chassis", + .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_pwr_off_from_chassis", + .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_line_card", + .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "reset_line_card_pwr_en", + .reg = MLXREG_LC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, + { + .label = "cpld_upgrade_en", + .reg = MLXREG_LC_REG_FIELD_UPGRADE, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0644, + .secured = 1, + }, + { + .label = "fpga_upgrade_en", + .reg = MLXREG_LC_REG_FIELD_UPGRADE, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0644, + .secured = 1, + }, + { + .label = "qsfp_pwr_en", + .reg = MLXREG_LC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0644, + }, + { + .label = "vpd_wp", + .reg = MLXREG_LC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0644, + .secured = 1, + }, + { + .label = "agb_spi_burn_en", + .reg = MLXREG_LC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0644, + .secured = 1, + }, + { + .label = "fpga_spi_burn_en", + .reg = MLXREG_LC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + .secured = 1, + }, + { + .label = "max_power", + .reg = MLXREG_LC_REG_MAX_POWER_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "config", + .reg = MLXREG_LC_REG_CONFIG_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, +}; + +static struct mlxreg_core_platform_data mlxreg_lc_regs_io = { + .data = mlxreg_lc_io_data, + .counter = ARRAY_SIZE(mlxreg_lc_io_data), +}; + +static int +mlxreg_lc_create_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotplug_device *devs, + int size) +{ + struct mlxreg_hotplug_device *dev = devs; + int i; + + /* Create static I2C device feeding by auxiliary or main power. */ + for (i = 0; i < size; i++, dev++) { + dev->client = i2c_new_client_device(dev->adapter, dev->brdinfo); + if (IS_ERR(dev->client)) { + dev_err(mlxreg_lc->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", + dev->brdinfo->type, dev->nr, dev->brdinfo->addr); + + dev->adapter = NULL; + goto fail_create_static_devices; + } + } + + return 0; + +fail_create_static_devices: + while (--i >= 0) { + dev = devs + i; + i2c_unregister_device(dev->client); + dev->client = NULL; + } + return IS_ERR(dev->client); +} + +static void +mlxreg_lc_destroy_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotplug_device *devs, + int size) +{ + struct mlxreg_hotplug_device *dev = devs; + int i; + + /* Destroy static I2C device feeding by auxiliary or main power. */ + for (i = 0; i < size; i++, dev++) { + if (dev->client) { + i2c_unregister_device(dev->client); + dev->client = NULL; + } + } +} + +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; + + if (action) + regval |= BIT(mlxreg_lc->data->slot - 1); + else + regval &= ~BIT(mlxreg_lc->data->slot - 1); + + err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval); + +regmap_read_fail: + mutex_unlock(&mlxreg_lc->lock); + return err; +} + +static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action) +{ + u32 regval; + int err; + + /* + * Hardware holds the line card after powering on in the disabled state. Holding line card + * in disabled state protects access to the line components, like FPGA and gearboxes. + * Line card should be enabled in order to get it in operational state. Line card could be + * disabled for moving it to non-operational state. Enabling line card does not affect the + * 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; + + if (action) + regval |= BIT(mlxreg_lc->data->slot - 1); + else + regval &= ~BIT(mlxreg_lc->data->slot - 1); + + err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, regval); + +regmap_read_fail: + mutex_unlock(&mlxreg_lc->lock); + return err; +} + +static int +mlxreg_lc_sn4800_c16_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, + struct mlxreg_core_data *data) +{ + struct device *dev = &data->hpdev.client->dev; + + /* Set line card configuration according to the type. */ + mlxreg_lc->mux_data = mlxreg_lc_mux_data; + mlxreg_lc->io_data = &mlxreg_lc_regs_io; + mlxreg_lc->led_data = &mlxreg_lc_led; + mlxreg_lc->mux_brdinfo = &mlxreg_lc_mux_brdinfo; + + mlxreg_lc->aux_devs = devm_kmemdup(dev, mlxreg_lc_aux_pwr_brdinfo, + sizeof(mlxreg_lc_aux_pwr_brdinfo), GFP_KERNEL); + if (!mlxreg_lc->aux_devs) + return -ENOMEM; + mlxreg_lc->aux_devs_num = ARRAY_SIZE(mlxreg_lc_aux_pwr_brdinfo); + mlxreg_lc->main_devs = devm_kmemdup(dev, mlxreg_lc_main_pwr_brdinfo, + sizeof(mlxreg_lc_main_pwr_brdinfo), GFP_KERNEL); + if (!mlxreg_lc->main_devs) + return -ENOMEM; + mlxreg_lc->main_devs_num = ARRAY_SIZE(mlxreg_lc_main_pwr_brdinfo); + + return 0; +} + +static void +mlxreg_lc_state_update(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action) +{ + mutex_lock(&mlxreg_lc->lock); + + if (action) + mlxreg_lc->state |= state; + else + mlxreg_lc->state &= ~state; + + mutex_unlock(&mlxreg_lc->lock); +} + +/* + * Callback is to be called from mlxreg-hotplug driver to notify about line card about received + * event. + */ +static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, u8 action) +{ + struct mlxreg_lc *mlxreg_lc = handle; + int err = 0; + + 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)) + return 0; + + switch (kind) { + case MLXREG_HOTPLUG_LC_SYNCED: + /* + * Synchronization event - hardware and firmware are synchronized. Power on/off + * line card - to allow/disallow main power source. + */ + mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED, action); + /* Power line card if it is not powered yet. */ + if (!(mlxreg_lc->state & MLXREG_LC_POWERED) && action) { + err = mlxreg_lc_power_on_off(mlxreg_lc, 1); + if (err) + return err; + } + /* In case line card is configured - enable it. */ + if (mlxreg_lc->state & MLXREG_LC_CONFIGURED && action) + err = mlxreg_lc_enable_disable(mlxreg_lc, 1); + break; + case MLXREG_HOTPLUG_LC_POWERED: + /* Power event - attach or de-attach line card device feeding by the main power. */ + if (action) { + /* Do not create devices, if line card is already powered. */ + if (mlxreg_lc->state & MLXREG_LC_POWERED) { + /* In case line card is configured - enable it. */ + if (mlxreg_lc->state & MLXREG_LC_CONFIGURED) + err = mlxreg_lc_enable_disable(mlxreg_lc, 1); + return err; + } + err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs, + mlxreg_lc->main_devs_num); + if (err) + return err; + + /* In case line card is already in ready state - enable it. */ + if (mlxreg_lc->state & MLXREG_LC_CONFIGURED) + err = mlxreg_lc_enable_disable(mlxreg_lc, 1); + } else { + mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs, + mlxreg_lc->main_devs_num); + } + mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED, action); + break; + case MLXREG_HOTPLUG_LC_READY: + /* + * Ready event – enable line card by releasing it from reset or disable it by put + * to reset state. + */ + err = mlxreg_lc_enable_disable(mlxreg_lc, !!action); + break; + case MLXREG_HOTPLUG_LC_THERMAL: + /* Thermal shutdown event – power off line card. */ + if (action) + err = mlxreg_lc_power_on_off(mlxreg_lc, 0); + break; + default: + break; + } + + return err; +} + +/* + * Callback is to be called from i2c-mux-mlxcpld driver to indicate that all adapter devices has + * been created. + */ +static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent, + struct i2c_adapter *adapters[]) +{ + struct mlxreg_hotplug_device *main_dev, *aux_dev; + struct mlxreg_lc *mlxreg_lc = handle; + u32 regval; + int i, err; + + /* Update I2C devices feeding by auxiliary power. */ + aux_dev = mlxreg_lc->aux_devs; + for (i = 0; i < mlxreg_lc->aux_devs_num; i++, aux_dev++) { + aux_dev->adapter = adapters[aux_dev->nr]; + aux_dev->nr = adapters[aux_dev->nr]->nr; + } + + err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->aux_devs, + mlxreg_lc->aux_devs_num); + if (err) + return err; + + /* Update I2C devices feeding by main power. */ + main_dev = mlxreg_lc->main_devs; + for (i = 0; i < mlxreg_lc->main_devs_num; i++, main_dev++) { + main_dev->adapter = adapters[main_dev->nr]; + main_dev->nr = adapters[main_dev->nr]->nr; + } + + /* Verify if line card is powered. */ + err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, ®val); + if (err) + goto mlxreg_lc_regmap_read_power_fail; + + if (regval & mlxreg_lc->data->mask) { + err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs, + mlxreg_lc->main_devs_num); + if (err) + goto mlxreg_lc_create_static_devices_failed; + + mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED, 1); + } + + /* Verify if line card is synchronized. */ + err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_sync, ®val); + if (err) + goto mlxreg_lc_regmap_read_sync_fail; + + /* 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); + if (mlxreg_lc->state & ~MLXREG_LC_POWERED) { + err = mlxreg_lc_power_on_off(mlxreg_lc, 1); + if (err) + goto mlxreg_lc_regmap_power_on_off_fail; + } + } + + mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_INITIALIZED, 1); + + return 0; + +mlxreg_lc_regmap_power_on_off_fail: +mlxreg_lc_regmap_read_sync_fail: + if (mlxreg_lc->state & MLXREG_LC_POWERED) + mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs, + mlxreg_lc->main_devs_num); +mlxreg_lc_create_static_devices_failed: + mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs, mlxreg_lc->aux_devs_num); +mlxreg_lc_regmap_read_power_fail: + return err; +} + +static int +mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, + struct mlxreg_core_data *data) +{ + struct device *dev = &data->hpdev.client->dev; + int lsb, err; + u32 regval; + + /* Validate line card type. */ + err = regmap_read(regmap, MLXREG_LC_REG_CONFIG_OFFSET, &lsb); + err = (!err) ? regmap_read(regmap, MLXREG_LC_REG_CONFIG_OFFSET, ®val) : err; + if (err) + return err; + regval = (regval & GENMASK(7, 0)) << 8 | (lsb & GENMASK(7, 0)); + switch (regval) { + case MLXREG_LC_SN4800_C16: + err = mlxreg_lc_sn4800_c16_config_init(mlxreg_lc, regmap, data); + if (err) + return err; + break; + default: + return -ENODEV; + } + + /* Create mux infrastructure. */ + mlxreg_lc->mux_data->handle = mlxreg_lc; + mlxreg_lc->mux_data->completion_notify = mlxreg_lc_completion_notify; + mlxreg_lc->mux_brdinfo->platform_data = mlxreg_lc->mux_data; + mlxreg_lc->mux = platform_device_register_resndata(dev, "i2c-mux-mlxcpld", data->hpdev.nr, + NULL, 0, mlxreg_lc->mux_data, + sizeof(*mlxreg_lc->mux_data)); + if (IS_ERR(mlxreg_lc->mux)) + return PTR_ERR(mlxreg_lc->mux); + + /* Register IO access driver. */ + if (mlxreg_lc->io_data) { + mlxreg_lc->io_data->regmap = regmap; + mlxreg_lc->io_regs = + platform_device_register_resndata(dev, "mlxreg-io", data->hpdev.nr, NULL, 0, + mlxreg_lc->io_data, sizeof(*mlxreg_lc->io_data)); + if (IS_ERR(mlxreg_lc->io_regs)) { + err = PTR_ERR(mlxreg_lc->io_regs); + goto fail_register_io; + } + } + + /* Register LED driver. */ + if (mlxreg_lc->led_data) { + mlxreg_lc->led_data->regmap = regmap; + mlxreg_lc->led = + platform_device_register_resndata(dev, "leds-mlxreg", data->hpdev.nr, NULL, 0, + mlxreg_lc->led_data, + sizeof(*mlxreg_lc->led_data)); + if (IS_ERR(mlxreg_lc->led)) { + err = PTR_ERR(mlxreg_lc->led); + goto fail_register_led; + } + } + + return 0; + +fail_register_led: + if (mlxreg_lc->io_regs) + platform_device_unregister(mlxreg_lc->io_regs); +fail_register_io: + if (mlxreg_lc->mux) + platform_device_unregister(mlxreg_lc->mux); + + return err; +} + +static void mlxreg_lc_config_exit(struct mlxreg_lc *mlxreg_lc) +{ + /* Unregister LED driver. */ + if (mlxreg_lc->led) + platform_device_unregister(mlxreg_lc->led); + /* Unregister IO access driver. */ + if (mlxreg_lc->io_regs) + platform_device_unregister(mlxreg_lc->io_regs); + /* Remove mux infrastructure. */ + if (mlxreg_lc->mux) + platform_device_unregister(mlxreg_lc->mux); +} + +static int mlxreg_lc_probe(struct platform_device *pdev) +{ + struct mlxreg_core_hotplug_platform_data *par_pdata; + struct mlxreg_core_data *data; + struct mlxreg_lc *mlxreg_lc; + void *regmap; + int i, err; + + data = dev_get_platdata(&pdev->dev); + if (!data) + return -EINVAL; + + mlxreg_lc = devm_kzalloc(&pdev->dev, sizeof(*mlxreg_lc), GFP_KERNEL); + if (!mlxreg_lc) + return -ENOMEM; + + 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->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); + if (!data->hpdev.adapter) { + dev_err(&pdev->dev, "Failed to get adapter for bus %d\n", + data->hpdev.nr); + return -EFAULT; + } + + /* Create device at the top of line card I2C tree.*/ + data->hpdev.client = i2c_new_client_device(data->hpdev.adapter, + data->hpdev.brdinfo); + if (IS_ERR(data->hpdev.client)) { + dev_err(&pdev->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); + + i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; + return PTR_ERR(data->hpdev.client); + } + + regmap = devm_regmap_init_i2c(data->hpdev.client, + &mlxreg_lc_regmap_conf); + if (IS_ERR(regmap)) { + err = PTR_ERR(regmap); + goto mlxreg_lc_probe_fail; + } + + /* Set default registers. */ + for (i = 0; i < mlxreg_lc_regmap_conf.num_reg_defaults; i++) { + err = regmap_write(regmap, mlxreg_lc_regmap_default[i].reg, + mlxreg_lc_regmap_default[i].def); + if (err) + goto mlxreg_lc_probe_fail; + } + + /* Sync registers with hardware. */ + regcache_mark_dirty(regmap); + err = regcache_sync(regmap); + if (err) + goto mlxreg_lc_probe_fail; + + par_pdata = data->hpdev.brdinfo->platform_data; + mlxreg_lc->par_regmap = par_pdata->regmap; + mlxreg_lc->data = data; + mlxreg_lc->dev = &pdev->dev; + platform_set_drvdata(pdev, mlxreg_lc); + + /* Configure line card. */ + err = mlxreg_lc_config_init(mlxreg_lc, regmap, data); + if (err) + goto mlxreg_lc_probe_fail; + + return err; + +mlxreg_lc_probe_fail: + i2c_put_adapter(data->hpdev.adapter); + return err; +} + +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); + + /* Clear event notification callback. */ + if (data->notifier) { + data->notifier->user_handler = NULL; + data->notifier->handle = NULL; + } + + /* Destroy static I2C device feeding by main power. */ + mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs, + mlxreg_lc->main_devs_num); + /* Destroy static I2C device feeding by auxiliary power. */ + mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs, mlxreg_lc->aux_devs_num); + /* Unregister underlying drivers. */ + mlxreg_lc_config_exit(mlxreg_lc); + if (data->hpdev.client) { + i2c_unregister_device(data->hpdev.client); + data->hpdev.client = NULL; + i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; + } + + return 0; +} + +static struct platform_driver mlxreg_lc_driver = { + .probe = mlxreg_lc_probe, + .remove = mlxreg_lc_remove, + .driver = { + .name = "mlxreg-lc", + }, +}; + +module_platform_driver(mlxreg_lc_driver); + +MODULE_AUTHOR("Vadim Pasternak "); +MODULE_DESCRIPTION("Nvidia line card platform driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:mlxreg-lc"); From 527cd54d49ddf3dbbd54566609f8e905bc17c843 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:37 +0300 Subject: [PATCH 067/106] Documentation/ABI: Add new attributes for mlxreg-io sysfs interfaces Add documentation for the new attributes: - "bios_active_image"; "bios_auth_fail"; "bios_upgrade_fail"; "bios_safe_mode" to represent various BIOS statuses. - "lc{n}_enable" - for put/release the line card to/from enable state. - "lc{n}_pwr" - for power on/off the line card. - "lc{n}_rst_mask" - for line card reset state enforced by ASIC, when it sets it due to some abnormal ASIC behavior. - "psu3_on"; "psu4_on" - for connection/disconnection power supply unit to/from the power source. - "pm_mgmt_en" - for setting power management control ownership. When power management control is provided by hardware, it means that hardware will automatically power off one or more line cards in case system power budget is under power required for feeding all powered on line cards. It could be a case, when some of power units lost power good state. - "shutdown_unlock" - for unlocking system after hardware or firmware thermal shutdown, which causes locking of the all interfaces to ASIC. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-9-vadimp@nvidia.com Signed-off-by: Hans de Goede --- .../ABI/stable/sysfs-driver-mlxreg-io | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io index b2553df2e786..6ef6979c9448 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io @@ -223,3 +223,141 @@ Description: These files show with which CPLD part numbers and minor system. The files are read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/bios_active_image +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/bios_auth_fail +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/bios_upgrade_fail +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: The files represent BIOS statuses: + - bios_active_image: location of current active BIOS image: + 0: Top, 1: Bottom. + The reported value should correspond to value expected by OS + in case of BIOS safe mode is 0. This bit is related to Intel + top-swap feature of DualBios on the same flash. + - bios_auth_fail: BIOS upgrade is failed because provided BIOS + image is not signed correctly. + - bios_upgrade_fail: BIOS upgrade is failed by some other + reason not because authentication. For example due to + physical SPI flash problem. + + The files are read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc1_enable +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc2_enable +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc3_enable +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc4_enable +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc5_enable +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc6_enable +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc7_enable +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc8_enable +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files allow line cards enable state control. + Expected behavior: + When lc{n}_enable is written 1, related line card is released + from the reset state, when 0 - is hold in reset state. + + The files are read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc1_pwr +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc2_pwr +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc3_pwr +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc4_pwr +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc5_pwr +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc6_pwr +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc7_pwr +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc8_pwr +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files switching line cards power on and off. + Expected behavior: + When lc{n}_pwr is written 1, related line card is powered + on, when written 0 - powered off. + + The files are read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc1_rst_mask +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc2_rst_mask +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc3_rst_mask +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc4_rst_mask +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc5_rst_mask +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc6_rst_mask +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc7_rst_mask +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/lc8_rst_mask +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files clear line card reset bit enforced by ASIC, when it + sets it due to some abnormal ASIC behavior. + Expected behavior: + When lc{n}_rst_mask is written 1, related line card reset bit + is cleared, when written 0 - no effect. + + The files are write only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/os_started +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: This file, when written 1, indicates to programmable devices + that OS is taking control over it. + + The file is read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pm_mgmt_en +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: This file assigns power management control ownership. + When power management control is provided by hardware, hardware + will automatically power off one or more line previously + powered line cards in case system power budget is getting + insufficient. It could be in case when some of power units lost + power good state. + When pm_mgmt_en is written 1, power management control by + software is enabled, 0 - power management control by hardware. + Note that for any setting of pm_mgmt_en attribute hardware will + not allow to power on any new line card in case system power + budget is insufficient. + Same in case software will try to power on several line cards + at once - hardware will power line cards while system has + enough power budget. + Default is 0. + + The file is read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/psu3_on +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/psu4_on +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files switching power supply units on and off. + Expected behavior: + When psu3_on or psu4_on is written 1, related unit will be + disconnected from the power source, when written 0 - connected. + + The files are write only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/shutdown_unlock +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: This file allows to unlock ASIC after thermal shutdown event. + When system thermal shutdown is enforced by ASIC, ASIC is + getting locked and after system boot it will not be available. + Software can decide to unlock it by setting this attribute to + 1 and then perform system power cycle by setting pwr_cycle + attribute to 1 (power cycle of main power domain). + Before setting shutdown_unlock to 1 it is recommended to + validate that system reboot cause is reset_asic_thermal or + reset_thermal_spc_or_pciesw. + In case shutdown_unlock is not set 1, the only way to release + ASIC from locking - is full system power cycle through the + external power distribution unit. + Default is 1. + + The file is read/write. From 5b0a315c3db548646e2cc9707d8a82d818a3c956 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:32:38 +0300 Subject: [PATCH 068/106] Documentation/ABI: Add new line card attributes for mlxreg-io sysfs interfaces Add documentation for the new attributes for line cards: - CPLDs versioning. - Write protection control for 'nvram' devices. - Line card reset reasons. - Enabling burning of FPGA and CPLDs. - Enabling burning of FPGA and gearbox SPI flashes, - Enabling power of whole line card. - Enabling power of QSFP ports equipped on line card. - The maximum powered required for line card feeding. - Line card configuration Id. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20211002093238.3771419-10-vadimp@nvidia.com Signed-off-by: Hans de Goede --- .../ABI/stable/sysfs-driver-mlxreg-io | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io index 6ef6979c9448..c84795ccecad 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io @@ -361,3 +361,106 @@ Description: This file allows to unlock ASIC after thermal shutdown event. Default is 1. The file is read/write. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/cpld1_pn +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/cpld1_version +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/cpld1_version_min +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files show with which CPLD major and minor versions + and part number has been burned CPLD device on line card. + + The files are read only. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/fpga1_pn +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/fpga1_version +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/fpga1_version_min +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files show with which FPGA major and minor versions + and part number has been burned FPGA device on line card. + + The files are read only. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/vpd_wp +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: This file allow to overwrite line card VPD hardware write + protection mode. When attribute is set 1 - write protection is + disabled, when 0 - enabled. + Default is 0. + If the system is in locked-down mode writing this file will not + be allowed. + The purpose if this file is to allow line card VPD burning + during production flow. + + The file is read/write. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/reset_aux_pwr_or_ref +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/reset_dc_dc_pwr_fail +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/reset_fpga_not_done +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/reset_from_chassis +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/reset_line_card +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/reset_pwr_off_from_chassis +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files show the line reset cause, as following: power + auxiliary outage or power refresh, DC-to-DC power failure, FPGA reset + failed, line card reset failed, power off from chassis. + Value 1 in file means this is reset cause, 0 - otherwise. Only one of + the above causes could be 1 at the same time, representing only last + reset cause. + + The files are read only. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/cpld_upgrade_en +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/fpga_upgrade_en +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files allow CPLD and FPGA burning. Value 1 in file means burning + is enabled, 0 - otherwise. + If the system is in locked-down mode writing these files will + not be allowed. + The purpose of these files to allow line card CPLD and FPGA + upgrade through the JTAG daisy-chain. + + The files are read/write. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/qsfp_pwr_en +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/pwr_en +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files allow to power on/off all QSFP ports and whole line card. + The attributes are set 1 for power on, 0 - for power off. + + The files are read/write. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/agb_spi_burn_en +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/fpga_spi_burn_en +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files allow gearboxes and FPGA SPI flash burning. + The attributes are set 1 to enable burning, 0 - to disable. + If the system is in locked-down mode writing these files will + not be allowed. + The purpose of these files to allow line card Gearboxes and FPGA + burning during production flow. + + The file is read/write. + +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/max_power +What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/i2c-*/*-0032/mlxreg-io.*/hwmon/hwmon*/config +Date: October 2021 +KernelVersion: 5.16 +Contact: Vadim Pasternak +Description: These files provide the maximum powered required for line card + feeding and line card configuration Id. + + The files are read only. From 249606d37d205eb2f9a6f2c8ecb8bd77b53e5d3e Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 2 Oct 2021 12:36:09 +0300 Subject: [PATCH 069/106] platform/x86: mlx-platform: Add support for multiply cooling devices Add new registers to support systems with multiply cooling devices. Modular systems support up-to four cooling devices. This capability is detected according to the registers initial setting. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Link: https://lore.kernel.org/r/20211002093609.3771576-1-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 2ab499686564..7606165980c3 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -120,12 +120,15 @@ #define MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET 0xe7 #define MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET 0xe8 #define MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET 0xe9 +#define MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET 0xea #define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET 0xeb #define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET 0xec #define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET 0xed #define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xee #define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xef #define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xf0 +#define MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET 0xf3 +#define MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET 0xf4 #define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf5 #define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6 #define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7 @@ -3414,6 +3417,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { .label = "pwm1", .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, }, + { + .label = "pwm2", + .reg = MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET, + }, + { + .label = "pwm3", + .reg = MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET, + }, + { + .label = "pwm4", + .reg = MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET, + }, { .label = "tacho1", .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, @@ -3803,6 +3818,9 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; } @@ -3902,6 +3920,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: @@ -4014,6 +4035,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: @@ -4069,6 +4093,9 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = { static const struct reg_default mlxplat_mlxcpld_regmap_eth_modular[] = { { MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 0x61 }, { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET, 0x00 }, { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, From 95563d45b5da9cdd07496bf54f0d83f25d679847 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 6 Oct 2021 14:21:59 -0600 Subject: [PATCH 070/106] platform/x86: system76_acpi: Report temperature and fan speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a hwmon interface to report CPU/GPU temperature and fan speed. sensors now reports an ACPI interface with the entries: system76_acpi-acpi-0 Adapter: ACPI interface CPU fan: 0 RPM GPU fan: 0 RPM CPU temp: +47.0°C GPU temp: +0.0°C Signed-off-by: Jeremy Soller Signed-off-by: Tim Crawford Link: https://lore.kernel.org/r/20211006202202.7479-2-tcrawford@system76.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/system76_acpi.c | 222 ++++++++++++++++++++++++++- 1 file changed, 218 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index c14fd22ba196..2a78ac64d689 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -10,6 +10,8 @@ */ #include +#include +#include #include #include #include @@ -24,6 +26,9 @@ struct system76_data { enum led_brightness kb_brightness; enum led_brightness kb_toggle_brightness; int kb_color; + struct device *therm; + union acpi_object *nfan; + union acpi_object *ntmp; }; static const struct acpi_device_id device_ids[] = { @@ -63,9 +68,57 @@ static int system76_get(struct system76_data *data, char *method) handle = acpi_device_handle(data->acpi_dev); status = acpi_evaluate_integer(handle, method, NULL, &ret); if (ACPI_SUCCESS(status)) - return (int)ret; - else - return -1; + return ret; + return -ENODEV; +} + +// Get a System76 ACPI device value by name with index +static int system76_get_index(struct system76_data *data, char *method, int index) +{ + union acpi_object obj; + struct acpi_object_list obj_list; + acpi_handle handle; + acpi_status status; + unsigned long long ret = 0; + + obj.type = ACPI_TYPE_INTEGER; + obj.integer.value = index; + obj_list.count = 1; + obj_list.pointer = &obj; + + handle = acpi_device_handle(data->acpi_dev); + status = acpi_evaluate_integer(handle, method, &obj_list, &ret); + if (ACPI_SUCCESS(status)) + return ret; + return -ENODEV; +} + +// Get a System76 ACPI device object by name +static int system76_get_object(struct system76_data *data, char *method, union acpi_object **obj) +{ + acpi_handle handle; + acpi_status status; + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; + + handle = acpi_device_handle(data->acpi_dev); + status = acpi_evaluate_object(handle, method, NULL, &buf); + if (ACPI_SUCCESS(status)) { + *obj = buf.pointer; + return 0; + } + + return -ENODEV; +} + +// Get a name from a System76 ACPI device object +static char *system76_name(union acpi_object *obj, int index) +{ + if (obj && obj->type == ACPI_TYPE_PACKAGE && index <= obj->package.count) { + if (obj->package.elements[index].type == ACPI_TYPE_STRING) + return obj->package.elements[index].string.pointer; + } + + return NULL; } // Set a System76 ACPI device value by name @@ -270,6 +323,146 @@ static void kb_led_hotkey_color(struct system76_data *data) kb_led_notify(data); } +static umode_t thermal_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct system76_data *data = drvdata; + + switch (type) { + case hwmon_fan: + case hwmon_pwm: + if (system76_name(data->nfan, channel)) + return 0444; + break; + + case hwmon_temp: + if (system76_name(data->ntmp, channel)) + return 0444; + break; + + default: + return 0; + } + + return 0; +} + +static int thermal_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + struct system76_data *data = dev_get_drvdata(dev); + int raw; + + switch (type) { + case hwmon_fan: + if (attr == hwmon_fan_input) { + raw = system76_get_index(data, "GFAN", channel); + if (raw < 0) + return raw; + *val = (raw >> 8) & 0xFFFF; + return 0; + } + break; + + case hwmon_pwm: + if (attr == hwmon_pwm_input) { + raw = system76_get_index(data, "GFAN", channel); + if (raw < 0) + return raw; + *val = raw & 0xFF; + return 0; + } + break; + + case hwmon_temp: + if (attr == hwmon_temp_input) { + raw = system76_get_index(data, "GTMP", channel); + if (raw < 0) + return raw; + *val = raw * 1000; + return 0; + } + break; + + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + +static int thermal_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, const char **str) +{ + struct system76_data *data = dev_get_drvdata(dev); + + switch (type) { + case hwmon_fan: + if (attr == hwmon_fan_label) { + *str = system76_name(data->nfan, channel); + if (*str) + return 0; + } + break; + + case hwmon_temp: + if (attr == hwmon_temp_label) { + *str = system76_name(data->ntmp, channel); + if (*str) + return 0; + } + break; + + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + +static const struct hwmon_ops thermal_ops = { + .is_visible = thermal_is_visible, + .read = thermal_read, + .read_string = thermal_read_string, +}; + +// Allocate up to 8 fans and temperatures +static const struct hwmon_channel_info *thermal_channel_info[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + NULL +}; + +static const struct hwmon_chip_info thermal_chip_info = { + .ops = &thermal_ops, + .info = thermal_channel_info, +}; + // Handle ACPI notification static void system76_notify(struct acpi_device *acpi_dev, u32 event) { @@ -346,7 +539,26 @@ static int system76_add(struct acpi_device *acpi_dev) return err; } + err = system76_get_object(data, "NFAN", &data->nfan); + if (err) + goto error; + + err = system76_get_object(data, "NTMP", &data->ntmp); + if (err) + goto error; + + data->therm = devm_hwmon_device_register_with_info(&acpi_dev->dev, + "system76_acpi", data, &thermal_chip_info, NULL); + err = PTR_ERR_OR_ZERO(data->therm); + if (err) + goto error; + return 0; + +error: + kfree(data->ntmp); + kfree(data->nfan); + return err; } // Remove a System76 ACPI device @@ -359,9 +571,11 @@ static int system76_remove(struct acpi_device *acpi_dev) device_remove_file(data->kb_led.dev, &kb_led_color_dev_attr); devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led); - devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led); + kfree(data->nfan); + kfree(data->ntmp); + system76_get(data, "FINI"); return 0; From 0de30fc684b3883be73602b7557661951319a9b9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 6 Oct 2021 14:22:00 -0600 Subject: [PATCH 071/106] platform/x86: system76_acpi: Replace Fn+F2 function for OLED models System76 laptops models with OLED displays do not support the default Fn+F2 behavior of turning the embedded display on and off. Some models instead introduce a new notify event that is used to lock the screen so the OS will put the display in a low power state. Signed-off-by: Jeremy Soller Signed-off-by: Tim Crawford Link: https://lore.kernel.org/r/20211006202202.7479-3-tcrawford@system76.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/system76_acpi.c | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index 2a78ac64d689..9e525b51a267 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ struct system76_data { struct device *therm; union acpi_object *nfan; union acpi_object *ntmp; + struct input_dev *input; }; static const struct acpi_device_id device_ids[] = { @@ -463,6 +465,15 @@ static const struct hwmon_chip_info thermal_chip_info = { .info = thermal_channel_info, }; +static void input_key(struct system76_data *data, unsigned int code) +{ + input_report_key(data->input, code, 1); + input_sync(data->input); + + input_report_key(data->input, code, 0); + input_sync(data->input); +} + // Handle ACPI notification static void system76_notify(struct acpi_device *acpi_dev, u32 event) { @@ -485,6 +496,9 @@ static void system76_notify(struct acpi_device *acpi_dev, u32 event) case 0x84: kb_led_hotkey_color(data); break; + case 0x85: + input_key(data, KEY_SCREENLOCK); + break; } } @@ -539,6 +553,20 @@ static int system76_add(struct acpi_device *acpi_dev) return err; } + data->input = devm_input_allocate_device(&acpi_dev->dev); + if (!data->input) + return -ENOMEM; + + data->input->name = "System76 ACPI Hotkeys"; + data->input->phys = "system76_acpi/input0"; + data->input->id.bustype = BUS_HOST; + data->input->dev.parent = &acpi_dev->dev; + input_set_capability(data->input, EV_KEY, KEY_SCREENLOCK); + + err = input_register_device(data->input); + if (err) + goto error; + err = system76_get_object(data, "NFAN", &data->nfan); if (err) goto error; @@ -558,6 +586,7 @@ static int system76_add(struct acpi_device *acpi_dev) error: kfree(data->ntmp); kfree(data->nfan); + input_free_device(data->input); return err; } From 76f7eba3e0a248af4cc4f302d95031fa2fb65fab Mon Sep 17 00:00:00 2001 From: Tim Crawford Date: Wed, 6 Oct 2021 14:22:01 -0600 Subject: [PATCH 072/106] platform/x86: system76_acpi: Add battery charging thresholds System76 laptops running open source EC firmware support configuring charging thresholds through ACPI methods. Expose this functionality through the standard sysfs entries charge_control_{start,end}_threshold. Signed-off-by: Tim Crawford Link: https://lore.kernel.org/r/20211006202202.7479-4-tcrawford@system76.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/system76_acpi.c | 157 +++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index 9e525b51a267..70d0490e23f5 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -18,8 +18,12 @@ #include #include #include +#include +#include #include +#include + struct system76_data { struct acpi_device *acpi_dev; struct led_classdev ap_led; @@ -143,6 +147,154 @@ static int system76_set(struct system76_data *data, char *method, int value) return -1; } +#define BATTERY_THRESHOLD_INVALID 0xFF + +enum { + THRESHOLD_START, + THRESHOLD_END, +}; + +static ssize_t battery_get_threshold(int which, char *buf) +{ + struct acpi_object_list input; + union acpi_object param; + acpi_handle handle; + acpi_status status; + unsigned long long ret = BATTERY_THRESHOLD_INVALID; + + handle = ec_get_handle(); + if (!handle) + return -ENODEV; + + input.count = 1; + input.pointer = ¶m; + // Start/stop selection + param.type = ACPI_TYPE_INTEGER; + param.integer.value = which; + + status = acpi_evaluate_integer(handle, "GBCT", &input, &ret); + if (ACPI_FAILURE(status)) + return -EIO; + if (ret == BATTERY_THRESHOLD_INVALID) + return -EINVAL; + + return sysfs_emit(buf, "%d\n", (int)ret); +} + +static ssize_t battery_set_threshold(int which, const char *buf, size_t count) +{ + struct acpi_object_list input; + union acpi_object params[2]; + acpi_handle handle; + acpi_status status; + unsigned int value; + int ret; + + handle = ec_get_handle(); + if (!handle) + return -ENODEV; + + ret = kstrtouint(buf, 10, &value); + if (ret) + return ret; + + if (value > 100) + return -EINVAL; + + input.count = 2; + input.pointer = params; + // Start/stop selection + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = which; + // Threshold value + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = value; + + status = acpi_evaluate_object(handle, "SBCT", &input, NULL); + if (ACPI_FAILURE(status)) + return -EIO; + + return count; +} + +static ssize_t charge_control_start_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return battery_get_threshold(THRESHOLD_START, buf); +} + +static ssize_t charge_control_start_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return battery_set_threshold(THRESHOLD_START, buf, count); +} + +static DEVICE_ATTR_RW(charge_control_start_threshold); + +static ssize_t charge_control_end_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return battery_get_threshold(THRESHOLD_END, buf); +} + +static ssize_t charge_control_end_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return battery_set_threshold(THRESHOLD_END, buf, count); +} + +static DEVICE_ATTR_RW(charge_control_end_threshold); + +static struct attribute *system76_battery_attrs[] = { + &dev_attr_charge_control_start_threshold.attr, + &dev_attr_charge_control_end_threshold.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(system76_battery); + +static int system76_battery_add(struct power_supply *battery) +{ + // System76 EC only supports 1 battery + if (strcmp(battery->desc->name, "BAT0") != 0) + return -ENODEV; + + if (device_add_groups(&battery->dev, system76_battery_groups)) + return -ENODEV; + + return 0; +} + +static int system76_battery_remove(struct power_supply *battery) +{ + device_remove_groups(&battery->dev, system76_battery_groups); + return 0; +} + +static struct acpi_battery_hook system76_battery_hook = { + .add_battery = system76_battery_add, + .remove_battery = system76_battery_remove, + .name = "System76 Battery Extension", +}; + +static void system76_battery_init(void) +{ + acpi_handle handle; + + handle = ec_get_handle(); + if (handle && acpi_has_method(handle, "GBCT")) + battery_hook_register(&system76_battery_hook); +} + +static void system76_battery_exit(void) +{ + acpi_handle handle; + + handle = ec_get_handle(); + if (handle && acpi_has_method(handle, "GBCT")) + battery_hook_unregister(&system76_battery_hook); +} + // Get the airplane mode LED brightness static enum led_brightness ap_led_get(struct led_classdev *led) { @@ -581,6 +733,8 @@ static int system76_add(struct acpi_device *acpi_dev) if (err) goto error; + system76_battery_init(); + return 0; error: @@ -596,6 +750,9 @@ static int system76_remove(struct acpi_device *acpi_dev) struct system76_data *data; data = acpi_driver_data(acpi_dev); + + system76_battery_exit(); + if (data->kb_color >= 0) device_remove_file(data->kb_led.dev, &kb_led_color_dev_attr); From 603a7dd08f881e1b5c754429dac5af6c29992528 Mon Sep 17 00:00:00 2001 From: Tim Crawford Date: Wed, 6 Oct 2021 14:22:02 -0600 Subject: [PATCH 073/106] platform/x86: system76_acpi: Add attribute group for kb_led_color Create the attribute groups for kb_led_color and set the `groups` field in kb_led. While touching it, also change its show method to use sysfs_emit() instead of sprintf(). Signed-off-by: Tim Crawford Link: https://lore.kernel.org/r/20211006202202.7479-5-tcrawford@system76.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/system76_acpi.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index 70d0490e23f5..b3c8178420b1 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -348,7 +348,7 @@ static ssize_t kb_led_color_show( led = (struct led_classdev *)dev->driver_data; data = container_of(led, struct system76_data, kb_led); - return sprintf(buf, "%06X\n", data->kb_color); + return sysfs_emit(buf, "%06X\n", data->kb_color); } // Set the keyboard LED color @@ -376,7 +376,7 @@ static ssize_t kb_led_color_store( return size; } -static const struct device_attribute kb_led_color_dev_attr = { +static struct device_attribute dev_attr_kb_led_color = { .attr = { .name = "color", .mode = 0644, @@ -385,6 +385,13 @@ static const struct device_attribute kb_led_color_dev_attr = { .store = kb_led_color_store, }; +static struct attribute *system76_kb_led_color_attrs[] = { + &dev_attr_kb_led_color.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(system76_kb_led_color); + // Notify that the keyboard LED was changed by hardware static void kb_led_notify(struct system76_data *data) { @@ -685,6 +692,7 @@ static int system76_add(struct acpi_device *acpi_dev) data->kb_led.brightness_set_blocking = kb_led_set; if (acpi_has_method(acpi_device_handle(data->acpi_dev), "SKBC")) { data->kb_led.max_brightness = 255; + data->kb_led.groups = system76_kb_led_color_groups; data->kb_toggle_brightness = 72; data->kb_color = 0xffffff; system76_set(data, "SKBC", data->kb_color); @@ -696,15 +704,6 @@ static int system76_add(struct acpi_device *acpi_dev) if (err) return err; - if (data->kb_color >= 0) { - err = device_create_file( - data->kb_led.dev, - &kb_led_color_dev_attr - ); - if (err) - return err; - } - data->input = devm_input_allocate_device(&acpi_dev->dev); if (!data->input) return -ENOMEM; @@ -753,9 +752,6 @@ static int system76_remove(struct acpi_device *acpi_dev) system76_battery_exit(); - if (data->kb_color >= 0) - device_remove_file(data->kb_led.dev, &kb_led_color_dev_attr); - devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led); devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led); From 5558871360f3fed77b432e9257f3bf90fca7580e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Oct 2021 18:10:55 +0200 Subject: [PATCH 074/106] surface: surface3-wmi: Use ACPI_COMPANION() directly The ACPI_HANDLE() macro is a wrapper arond the ACPI_COMPANION() macro and the ACPI handle produced by the former comes from the ACPI device object produced by the latter, so it is way more straightforward to evaluate the latter directly instead of passing the handle produced by the former to acpi_bus_get_device(). Modify s3_wmi_check_platform_device() accordingly (no intentional functional impact). Signed-off-by: Rafael J. Wysocki Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/12896717.uLZWGnKmhe@kreacher Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface3-wmi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c index fcd1d4fb94d5..09ac9cfc40d8 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -139,13 +139,12 @@ static acpi_status s3_wmi_attach_spi_device(acpi_handle handle, static int s3_wmi_check_platform_device(struct device *dev, void *data) { - struct acpi_device *adev, *ts_adev = NULL; - acpi_handle handle; + struct acpi_device *adev = ACPI_COMPANION(dev); + struct acpi_device *ts_adev = NULL; acpi_status status; /* ignore non ACPI devices */ - handle = ACPI_HANDLE(dev); - if (!handle || acpi_bus_get_device(handle, &adev)) + if (!adev) return 0; /* check for LID ACPI switch */ @@ -159,7 +158,7 @@ static int s3_wmi_check_platform_device(struct device *dev, void *data) strlen(SPI_CTL_OBJ_NAME))) return 0; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, adev->handle, 1, s3_wmi_attach_spi_device, NULL, &ts_adev, NULL); if (ACPI_FAILURE(status)) From 7c7ba5de7f534c4b563b4add4d430b2186f7ed17 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Oct 2021 18:12:31 +0200 Subject: [PATCH 075/106] surface: surface3_power: Drop redundant acpi_bus_get_device() call If the ACPI companion of a given device is not present, the result of the ACPI_HANDLE() evaluation for it will be NULL, so calling acpi_bus_get_device() on ACPI_HANDLE() result in order to validate it is redundant. Drop the redundant acpi_bus_get_device() call from mshw0011_notify() along with a local variable related to it. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/3160001.aeNJFYEL58@kreacher Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface3_power.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/surface/surface3_power.c b/drivers/platform/surface/surface3_power.c index 90c1568ea4e0..abac3eec565e 100644 --- a/drivers/platform/surface/surface3_power.c +++ b/drivers/platform/surface/surface3_power.c @@ -159,12 +159,11 @@ mshw0011_notify(struct mshw0011_data *cdata, u8 arg1, u8 arg2, unsigned int *ret_value) { union acpi_object *obj; - struct acpi_device *adev; acpi_handle handle; unsigned int i; handle = ACPI_HANDLE(&cdata->adp1->dev); - if (!handle || acpi_bus_get_device(handle, &adev)) + if (!handle) return -ENODEV; obj = acpi_evaluate_dsm_typed(handle, &mshw0011_guid, arg1, arg2, NULL, From 043449e7516106826346d9923a81da0310a387de Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Oct 2021 18:13:51 +0200 Subject: [PATCH 076/106] platform: x86: ideapad-laptop: Use ACPI_COMPANION() directly The ACPI_HANDLE() macro is a wrapper arond the ACPI_COMPANION() macro and the ACPI handle produced by the former comes from the ACPI device object produced by the latter, so it is way more straightforward to evaluate the latter directly instead of passing the handle produced by the former to acpi_bus_get_device(). Modify ideapad_acpi_add() accordingly (no intentional functional impact). Signed-off-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/8000884.T7Z3S40VBb@kreacher Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/ideapad-laptop.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 2771a05ea5e2..3ccb7b71dfb1 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1555,17 +1555,13 @@ static void ideapad_check_features(struct ideapad_private *priv) static int ideapad_acpi_add(struct platform_device *pdev) { + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct ideapad_private *priv; - struct acpi_device *adev; acpi_status status; unsigned long cfg; int err, i; - err = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev); - if (err) - return -ENODEV; - - if (eval_int(adev->handle, "_CFG", &cfg)) + if (!adev || eval_int(adev->handle, "_CFG", &cfg)) return -ENODEV; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); From 2d5b0755b754fcb39598df87b3a8656a569e9979 Mon Sep 17 00:00:00 2001 From: Qing Wang Date: Thu, 14 Oct 2021 23:50:40 -0700 Subject: [PATCH 077/106] platform/x86: panasonic-laptop: Replace snprintf in show functions with sysfs_emit show() must not use snprintf() when formatting the value to be returned to user space. Fix the coccicheck warnings: WARNING: use scnprintf or sprintf. Use sysfs_emit instead of scnprintf or sprintf makes more sense. Signed-off-by: Qing Wang Link: https://lore.kernel.org/r/1634280641-4862-1-git-send-email-wangqing@vivo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/panasonic-laptop.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index d4f444401496..37850d07987d 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -470,7 +470,7 @@ static ssize_t numbatt_show(struct device *dev, struct device_attribute *attr, if (!acpi_pcc_retrieve_biosdata(pcc)) return -EIO; - return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]); + return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]); } static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr, @@ -482,7 +482,7 @@ static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr, if (!acpi_pcc_retrieve_biosdata(pcc)) return -EIO; - return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_LCD_TYPE]); + return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]); } static ssize_t mute_show(struct device *dev, struct device_attribute *attr, @@ -494,7 +494,7 @@ static ssize_t mute_show(struct device *dev, struct device_attribute *attr, if (!acpi_pcc_retrieve_biosdata(pcc)) return -EIO; - return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_MUTE]); + return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_MUTE]); } static ssize_t mute_store(struct device *dev, struct device_attribute *attr, @@ -524,7 +524,7 @@ static ssize_t sticky_key_show(struct device *dev, struct device_attribute *attr if (!acpi_pcc_retrieve_biosdata(pcc)) return -EIO; - return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sticky_key); + return sysfs_emit(buf, "%u\n", pcc->sticky_key); } static ssize_t sticky_key_store(struct device *dev, struct device_attribute *attr, @@ -566,7 +566,7 @@ static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr, result = -EIO; break; } - return snprintf(buf, PAGE_SIZE, "%u\n", result); + return sysfs_emit(buf, "%u\n", result); } static ssize_t eco_mode_store(struct device *dev, struct device_attribute *attr, @@ -625,7 +625,7 @@ static ssize_t ac_brightness_show(struct device *dev, struct device_attribute *a if (!acpi_pcc_retrieve_biosdata(pcc)) return -EIO; - return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]); + return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]); } static ssize_t ac_brightness_store(struct device *dev, struct device_attribute *attr, @@ -655,7 +655,7 @@ static ssize_t dc_brightness_show(struct device *dev, struct device_attribute *a if (!acpi_pcc_retrieve_biosdata(pcc)) return -EIO; - return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]); + return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]); } static ssize_t dc_brightness_store(struct device *dev, struct device_attribute *attr, @@ -685,7 +685,7 @@ static ssize_t current_brightness_show(struct device *dev, struct device_attribu if (!acpi_pcc_retrieve_biosdata(pcc)) return -EIO; - return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]); + return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]); } static ssize_t current_brightness_store(struct device *dev, struct device_attribute *attr, @@ -710,7 +710,7 @@ static ssize_t current_brightness_store(struct device *dev, struct device_attrib static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", get_optd_power_state()); + return sysfs_emit(buf, "%d\n", get_optd_power_state()); } static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr, From 33ce79be2784bb7c327ef0f3be184936238c91d3 Mon Sep 17 00:00:00 2001 From: Ye Guojin Date: Mon, 18 Oct 2021 09:17:50 +0000 Subject: [PATCH 078/106] platform/x86: thinkpad_acpi: Fix coccinelle warnings coccicheck complains about the use of snprintf() in sysfs show functions: WARNING use scnprintf or sprintf Use sysfs_emit instead of scnprintf or sprintf makes more sense. Reported-by: Zeal Robot Signed-off-by: Ye Guojin Link: https://lore.kernel.org/r/20211018091750.858826-1-ye.guojin@zte.com.cn Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 07b9710d500e..cd5c3a04dba3 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1275,7 +1275,7 @@ static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id, return status; } - return snprintf(buf, PAGE_SIZE, "%d\n", + return sysfs_emit(buf, "%d\n", (status == TPACPI_RFK_RADIO_ON) ? 1 : 0); } @@ -1368,14 +1368,14 @@ static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) /* interface_version --------------------------------------------------- */ static ssize_t interface_version_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); + return sysfs_emit(buf, "0x%08x\n", TPACPI_SYSFS_VERSION); } static DRIVER_ATTR_RO(interface_version); /* debug_level --------------------------------------------------------- */ static ssize_t debug_level_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); + return sysfs_emit(buf, "0x%04x\n", dbg_level); } static ssize_t debug_level_store(struct device_driver *drv, const char *buf, @@ -1395,7 +1395,7 @@ static DRIVER_ATTR_RW(debug_level); /* version ------------------------------------------------------------- */ static ssize_t version_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s v%s\n", + return sysfs_emit(buf, "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); } static DRIVER_ATTR_RO(version); @@ -1407,7 +1407,7 @@ static DRIVER_ATTR_RO(version); /* wlsw_emulstate ------------------------------------------------------ */ static ssize_t wlsw_emulstate_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wlsw_emulstate); + return sysfs_emit(buf, "%d\n", !!tpacpi_wlsw_emulstate); } static ssize_t wlsw_emulstate_store(struct device_driver *drv, const char *buf, @@ -1430,7 +1430,7 @@ static DRIVER_ATTR_RW(wlsw_emulstate); /* bluetooth_emulstate ------------------------------------------------- */ static ssize_t bluetooth_emulstate_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_bluetooth_emulstate); + return sysfs_emit(buf, "%d\n", !!tpacpi_bluetooth_emulstate); } static ssize_t bluetooth_emulstate_store(struct device_driver *drv, @@ -1450,7 +1450,7 @@ static DRIVER_ATTR_RW(bluetooth_emulstate); /* wwan_emulstate ------------------------------------------------- */ static ssize_t wwan_emulstate_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wwan_emulstate); + return sysfs_emit(buf, "%d\n", !!tpacpi_wwan_emulstate); } static ssize_t wwan_emulstate_store(struct device_driver *drv, const char *buf, @@ -1470,7 +1470,7 @@ static DRIVER_ATTR_RW(wwan_emulstate); /* uwb_emulstate ------------------------------------------------- */ static ssize_t uwb_emulstate_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_uwb_emulstate); + return sysfs_emit(buf, "%d\n", !!tpacpi_uwb_emulstate); } static ssize_t uwb_emulstate_store(struct device_driver *drv, const char *buf, @@ -2678,7 +2678,7 @@ static ssize_t hotkey_enable_show(struct device *dev, if (res) return res; - return snprintf(buf, PAGE_SIZE, "%d\n", status); + return sysfs_emit(buf, "%d\n", status); } static ssize_t hotkey_enable_store(struct device *dev, @@ -2706,7 +2706,7 @@ static ssize_t hotkey_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_user_mask); + return sysfs_emit(buf, "0x%08x\n", hotkey_user_mask); } static ssize_t hotkey_mask_store(struct device *dev, @@ -2754,7 +2754,7 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, { printk_deprecated_attribute("hotkey_bios_mask", "This attribute is useless."); - return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); + return sysfs_emit(buf, "0x%08x\n", hotkey_orig_mask); } static DEVICE_ATTR_RO(hotkey_bios_mask); @@ -2764,7 +2764,7 @@ static ssize_t hotkey_all_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%08x\n", + return sysfs_emit(buf, "0x%08x\n", hotkey_all_mask | hotkey_source_mask); } @@ -2775,7 +2775,7 @@ static ssize_t hotkey_adaptive_all_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%08x\n", + return sysfs_emit(buf, "0x%08x\n", hotkey_adaptive_all_mask | hotkey_source_mask); } @@ -2786,7 +2786,7 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%08x\n", + return sysfs_emit(buf, "0x%08x\n", (hotkey_all_mask | hotkey_source_mask) & ~hotkey_reserved_mask); } @@ -2800,7 +2800,7 @@ static ssize_t hotkey_source_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask); + return sysfs_emit(buf, "0x%08x\n", hotkey_source_mask); } static ssize_t hotkey_source_mask_store(struct device *dev, @@ -2851,7 +2851,7 @@ static ssize_t hotkey_poll_freq_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq); + return sysfs_emit(buf, "%d\n", hotkey_poll_freq); } static ssize_t hotkey_poll_freq_store(struct device *dev, @@ -2893,7 +2893,7 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, /* Opportunistic update */ tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF)); - return snprintf(buf, PAGE_SIZE, "%d\n", + return sysfs_emit(buf, "%d\n", (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); } @@ -2916,7 +2916,7 @@ static ssize_t hotkey_tablet_mode_show(struct device *dev, if (res < 0) return res; - return snprintf(buf, PAGE_SIZE, "%d\n", !!s); + return sysfs_emit(buf, "%d\n", !!s); } static DEVICE_ATTR_RO(hotkey_tablet_mode); @@ -2933,7 +2933,7 @@ static ssize_t hotkey_wakeup_reason_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason); + return sysfs_emit(buf, "%d\n", hotkey_wakeup_reason); } static DEVICE_ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL); @@ -2949,7 +2949,7 @@ static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack); + return sysfs_emit(buf, "%d\n", hotkey_autosleep_ack); } static DEVICE_ATTR(wakeup_hotunplug_complete, S_IRUGO, @@ -2984,7 +2984,7 @@ static ssize_t adaptive_kbd_mode_show(struct device *dev, if (current_mode < 0) return current_mode; - return snprintf(buf, PAGE_SIZE, "%d\n", current_mode); + return sysfs_emit(buf, "%d\n", current_mode); } static ssize_t adaptive_kbd_mode_store(struct device *dev, @@ -6334,7 +6334,7 @@ static ssize_t thermal_temp_input_show(struct device *dev, if (value == TPACPI_THERMAL_SENSOR_NA) return -ENXIO; - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } #define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ @@ -8567,7 +8567,7 @@ static ssize_t fan_pwm1_enable_show(struct device *dev, } else mode = 1; - return snprintf(buf, PAGE_SIZE, "%d\n", mode); + return sysfs_emit(buf, "%d\n", mode); } static ssize_t fan_pwm1_enable_store(struct device *dev, @@ -8633,7 +8633,7 @@ static ssize_t fan_pwm1_show(struct device *dev, if (status > 7) status = 7; - return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); + return sysfs_emit(buf, "%u\n", (status * 255) / 7); } static ssize_t fan_pwm1_store(struct device *dev, @@ -8686,7 +8686,7 @@ static ssize_t fan_fan1_input_show(struct device *dev, if (res < 0) return res; - return snprintf(buf, PAGE_SIZE, "%u\n", speed); + return sysfs_emit(buf, "%u\n", speed); } static DEVICE_ATTR(fan1_input, S_IRUGO, fan_fan1_input_show, NULL); @@ -8703,7 +8703,7 @@ static ssize_t fan_fan2_input_show(struct device *dev, if (res < 0) return res; - return snprintf(buf, PAGE_SIZE, "%u\n", speed); + return sysfs_emit(buf, "%u\n", speed); } static DEVICE_ATTR(fan2_input, S_IRUGO, fan_fan2_input_show, NULL); @@ -8711,7 +8711,7 @@ static DEVICE_ATTR(fan2_input, S_IRUGO, fan_fan2_input_show, NULL); /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ static ssize_t fan_watchdog_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); + return sysfs_emit(buf, "%u\n", fan_watchdog_maxinterval); } static ssize_t fan_watchdog_store(struct device_driver *drv, const char *buf, From fd96e35ea7b95f1e216277805be89d66e4ae962d Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 18 Oct 2021 11:25:37 -0700 Subject: [PATCH 079/106] platform/x86: thinkpad_acpi: Fix bitwise vs. logical warning A new warning in clang points out a use of bitwise OR with boolean expressions in this driver: drivers/platform/x86/thinkpad_acpi.c:9061:11: error: use of bitwise '|' with boolean operands [-Werror,-Wbitwise-instead-of-logical] else if ((strlencmp(cmd, "level disengaged") == 0) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ || drivers/platform/x86/thinkpad_acpi.c:9061:11: note: cast one or both operands to int to silence this warning 1 error generated. This should clearly be a logical OR so change it to fix the warning. Fixes: fe98a52ce754 ("ACPI: thinkpad-acpi: add sysfs support to fan subdriver") Link: https://github.com/ClangBuiltLinux/linux/issues/1476 Reported-by: Tor Vic Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20211018182537.2316800-1-nathan@kernel.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cd5c3a04dba3..9c632df734bb 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9058,7 +9058,7 @@ static int fan_write_cmd_level(const char *cmd, int *rc) if (strlencmp(cmd, "level auto") == 0) level = TP_EC_FAN_AUTO; - else if ((strlencmp(cmd, "level disengaged") == 0) | + else if ((strlencmp(cmd, "level disengaged") == 0) || (strlencmp(cmd, "level full-speed") == 0)) level = TP_EC_FAN_FULLSPEED; else if (sscanf(cmd, "level %d", &level) != 1) From cd45c9bf8b43cd387e167cf166ae5c517f56d658 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 18 Oct 2021 16:33:22 +0200 Subject: [PATCH 080/106] ASoC: Intel: Move soc_intel_is_foo() helpers to a generic header The soc_intel_is_foo() helpers from sound/soc/intel/common/soc-intel-quirks.h are useful outside of the sound subsystem too. Move these to include/linux/platform_data/x86/soc.h, so that other code can use them too. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Acked-by: Mark Brown Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211018143324.296961-2-hdegoede@redhat.com --- include/linux/platform_data/x86/soc.h | 65 +++++++++++++++++++++++ sound/soc/intel/common/soc-intel-quirks.h | 51 ++---------------- 2 files changed, 68 insertions(+), 48 deletions(-) create mode 100644 include/linux/platform_data/x86/soc.h diff --git a/include/linux/platform_data/x86/soc.h b/include/linux/platform_data/x86/soc.h new file mode 100644 index 000000000000..da05f425587a --- /dev/null +++ b/include/linux/platform_data/x86/soc.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Helpers for Intel SoC model detection + * + * Copyright (c) 2019, Intel Corporation. + */ + +#ifndef __PLATFORM_DATA_X86_SOC_H +#define __PLATFORM_DATA_X86_SOC_H + +#if IS_ENABLED(CONFIG_X86) + +#include +#include + +#define SOC_INTEL_IS_CPU(soc, type) \ +static inline bool soc_intel_is_##soc(void) \ +{ \ + static const struct x86_cpu_id soc##_cpu_ids[] = { \ + X86_MATCH_INTEL_FAM6_MODEL(type, NULL), \ + {} \ + }; \ + const struct x86_cpu_id *id; \ + \ + id = x86_match_cpu(soc##_cpu_ids); \ + if (id) \ + return true; \ + return false; \ +} + +SOC_INTEL_IS_CPU(byt, ATOM_SILVERMONT); +SOC_INTEL_IS_CPU(cht, ATOM_AIRMONT); +SOC_INTEL_IS_CPU(apl, ATOM_GOLDMONT); +SOC_INTEL_IS_CPU(glk, ATOM_GOLDMONT_PLUS); +SOC_INTEL_IS_CPU(cml, KABYLAKE_L); + +#else /* IS_ENABLED(CONFIG_X86) */ + +static inline bool soc_intel_is_byt(void) +{ + return false; +} + +static inline bool soc_intel_is_cht(void) +{ + return false; +} + +static inline bool soc_intel_is_apl(void) +{ + return false; +} + +static inline bool soc_intel_is_glk(void) +{ + return false; +} + +static inline bool soc_intel_is_cml(void) +{ + return false; +} +#endif /* IS_ENABLED(CONFIG_X86) */ + +#endif /* __PLATFORM_DATA_X86_SOC_H */ diff --git a/sound/soc/intel/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h index a93987ab7f4d..de4e550c5b34 100644 --- a/sound/soc/intel/common/soc-intel-quirks.h +++ b/sound/soc/intel/common/soc-intel-quirks.h @@ -9,34 +9,13 @@ #ifndef _SND_SOC_INTEL_QUIRKS_H #define _SND_SOC_INTEL_QUIRKS_H +#include + #if IS_ENABLED(CONFIG_X86) #include -#include -#include #include -#define SOC_INTEL_IS_CPU(soc, type) \ -static inline bool soc_intel_is_##soc(void) \ -{ \ - static const struct x86_cpu_id soc##_cpu_ids[] = { \ - X86_MATCH_INTEL_FAM6_MODEL(type, NULL), \ - {} \ - }; \ - const struct x86_cpu_id *id; \ - \ - id = x86_match_cpu(soc##_cpu_ids); \ - if (id) \ - return true; \ - return false; \ -} - -SOC_INTEL_IS_CPU(byt, ATOM_SILVERMONT); -SOC_INTEL_IS_CPU(cht, ATOM_AIRMONT); -SOC_INTEL_IS_CPU(apl, ATOM_GOLDMONT); -SOC_INTEL_IS_CPU(glk, ATOM_GOLDMONT_PLUS); -SOC_INTEL_IS_CPU(cml, KABYLAKE_L); - static inline bool soc_intel_is_byt_cr(struct platform_device *pdev) { /* @@ -114,30 +93,6 @@ static inline bool soc_intel_is_byt_cr(struct platform_device *pdev) return false; } -static inline bool soc_intel_is_byt(void) -{ - return false; -} - -static inline bool soc_intel_is_cht(void) -{ - return false; -} - -static inline bool soc_intel_is_apl(void) -{ - return false; -} - -static inline bool soc_intel_is_glk(void) -{ - return false; -} - -static inline bool soc_intel_is_cml(void) -{ - return false; -} #endif - #endif /* _SND_SOC_INTEL_QUIRKS_H */ +#endif /* _SND_SOC_INTEL_QUIRKS_H */ From 693841b74262f1c0483d8e72f83a97999e923433 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 18 Oct 2021 16:33:23 +0200 Subject: [PATCH 081/106] platform/x86: intel_int0002_vgpio: Use the new soc_intel_is_byt()/_cht() helpers Use the new soc_intel_is_byt()/_cht() helpers to clean things up a bit. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211018143324.296961-3-hdegoede@redhat.com --- drivers/platform/x86/intel/int0002_vgpio.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/intel/int0002_vgpio.c b/drivers/platform/x86/intel/int0002_vgpio.c index 569342aa8926..617dbf98980e 100644 --- a/drivers/platform/x86/intel/int0002_vgpio.c +++ b/drivers/platform/x86/intel/int0002_vgpio.c @@ -34,13 +34,11 @@ #include #include #include +#include #include #include #include -#include -#include - #define DRV_NAME "INT0002 Virtual GPIO" /* For some reason the virtual GPIO pin tied to the GPE is numbered pin 2 */ @@ -151,12 +149,6 @@ static struct irq_chip int0002_irqchip = { .irq_set_wake = int0002_irq_set_wake, }; -static const struct x86_cpu_id int0002_cpu_ids[] = { - X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, NULL), - X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL), - {} -}; - static void int0002_init_irq_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, unsigned int ngpios) @@ -167,15 +159,13 @@ static void int0002_init_irq_valid_mask(struct gpio_chip *chip, static int int0002_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct x86_cpu_id *cpu_id; struct int0002_data *int0002; struct gpio_irq_chip *girq; struct gpio_chip *chip; int irq, ret; /* Menlow has a different INT0002 device? */ - cpu_id = x86_match_cpu(int0002_cpu_ids); - if (!cpu_id) + if (!soc_intel_is_byt() && !soc_intel_is_cht()) return -ENODEV; irq = platform_get_irq(pdev, 0); From 5ecc1e94782218b77b9bf7ae8ac53990f5ca4a7a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 18 Oct 2021 16:33:24 +0200 Subject: [PATCH 082/106] Input: axp20x-pek - Use new soc_intel_is_cht() helper Use the new soc_intel_is_cht() helper to find out if we are running on a CHT device rather then checking the ACPI _HRV field. This is more reliable (some CHT devices have been found where the _HRV for the PMIC is 2 rather then 3) and leads to a nice cleanup. Reviewed-by: Andy Shevchenko Acked-by: Dmitry Torokhov Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211018143324.296961-4-hdegoede@redhat.com --- drivers/input/misc/axp20x-pek.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 9c6386b2af33..e09b1fae42e1 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -255,41 +256,24 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, return 0; } -#ifdef CONFIG_ACPI -static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek, - struct platform_device *pdev) +static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek) { - unsigned long long hrv = 0; - acpi_status status; - if (IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY) && axp20x_pek->axp20x->variant == AXP288_ID) { - status = acpi_evaluate_integer(ACPI_HANDLE(pdev->dev.parent), - "_HRV", NULL, &hrv); - if (ACPI_FAILURE(status)) - dev_err(&pdev->dev, "Failed to get PMIC hardware revision\n"); - /* * On Cherry Trail platforms (hrv == 3), do not register the * input device if there is an "INTCFD9" or "ACPI0011" gpio * button ACPI device, as that handles the power button too, * and otherwise we end up reporting all presses twice. */ - if (hrv == 3 && (acpi_dev_present("INTCFD9", NULL, -1) || + if (soc_intel_is_cht() && + (acpi_dev_present("INTCFD9", NULL, -1) || acpi_dev_present("ACPI0011", NULL, -1))) return false; - } return true; } -#else -static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek, - struct platform_device *pdev) -{ - return true; -} -#endif static int axp20x_pek_probe(struct platform_device *pdev) { @@ -321,7 +305,7 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek->irq_dbf = regmap_irq_get_virq( axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbf); - if (axp20x_pek_should_register_input(axp20x_pek, pdev)) { + if (axp20x_pek_should_register_input(axp20x_pek)) { error = axp20x_pek_probe_input_device(axp20x_pek, pdev); if (error) return error; From 86af1d02d458379ae53031fabad560f10f8bdadd Mon Sep 17 00:00:00 2001 From: Santosh Kumar Yadav Date: Wed, 20 Oct 2021 14:36:34 +0200 Subject: [PATCH 083/106] platform/x86: Support for EC-connected GPIOs for identify LED/button on Barco P50 board Add a driver providing access to the GPIOs for the identify button and led present on Barco P50 board, based on the pcengines-apuv2.c driver. There is unfortunately no suitable ACPI entry for the EC communication interface, so instead bind to boards with "P50" as their DMI product family and hard code the I/O port number (0x299). The driver also hooks up the leds-gpio and gpio-keys-polled drivers to the GPIOs, so they are finally exposed as: LED: /sys/class/leds/identify Button: (/proc/bus/input/devices) I: Bus=0019 Vendor=0001 Product=0001 Version=0100 N: Name="identify" P: Phys=gpio-keys-polled/input0 S: Sysfs=/devices/platform/barco-p50-gpio/gpio-keys-polled/input/input10 U: Uniq= H: Handlers=event10 B: PROP=0 B: EV=3 B: KEY=1000000 0 0 0 0 0 0 Signed-off-by: Santosh Kumar Yadav Signed-off-by: Peter Korsgaard Link: https://lore.kernel.org/r/20211020123634.2638-1-peter@korsgaard.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 10 + drivers/platform/x86/Makefile | 3 + drivers/platform/x86/barco-p50-gpio.c | 436 ++++++++++++++++++++++++++ 4 files changed, 455 insertions(+) create mode 100644 drivers/platform/x86/barco-p50-gpio.c diff --git a/MAINTAINERS b/MAINTAINERS index 6d6135915073..ebdfc74e841d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3215,6 +3215,12 @@ F: drivers/video/backlight/ F: include/linux/backlight.h F: include/linux/pwm_backlight.h +BARCO P50 GPIO DRIVER +M: Santosh Kumar Yadav +M: Peter Korsgaard +S: Maintained +F: drivers/platform/x86/barco-p50-gpio.c + BATMAN ADVANCED M: Marek Lindner M: Simon Wunderlich diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 520da0a6acd1..9fd0c15d77a8 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -729,6 +729,16 @@ config PCENGINES_APU2 To compile this driver as a module, choose M here: the module will be called pcengines-apuv2. +config BARCO_P50_GPIO + tristate "Barco P50 GPIO driver for identify LED/button" + depends on GPIOLIB + help + This driver provides access to the GPIOs for the identify button + and led present on Barco P50 board. + + To compile this driver as a module, choose M here: the module + will be called barco-p50-gpio. + config SAMSUNG_LAPTOP tristate "Samsung Laptop driver" depends on RFKILL || RFKILL = n diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 0d046ed70da1..219478061683 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -81,6 +81,9 @@ obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o # PC Engines obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o +# Barco +obj-$(CONFIG_BARCO_P50_GPIO) += barco-p50-gpio.o + # Samsung obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c new file mode 100644 index 000000000000..ca0b2564c407 --- /dev/null +++ b/drivers/platform/x86/barco-p50-gpio.c @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Support for EC-connected GPIOs for identify + * LED/button on Barco P50 board + * + * Copyright (C) 2021 Barco NV + * Author: Santosh Kumar Yadav + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRIVER_NAME "barco-p50-gpio" + +/* GPIO lines */ +#define P50_GPIO_LINE_LED 0 +#define P50_GPIO_LINE_BTN 1 + +/* GPIO IO Ports */ +#define P50_GPIO_IO_PORT_BASE 0x299 + +#define P50_PORT_DATA 0x00 +#define P50_PORT_CMD 0x01 + +#define P50_STATUS_OBF 0x01 /* EC output buffer full */ +#define P50_STATUS_IBF 0x02 /* EC input buffer full */ + +#define P50_CMD_READ 0xa0 +#define P50_CMD_WRITE 0x50 + +/* EC mailbox registers */ +#define P50_MBOX_REG_CMD 0x00 +#define P50_MBOX_REG_STATUS 0x01 +#define P50_MBOX_REG_PARAM 0x02 +#define P50_MBOX_REG_DATA 0x03 + +#define P50_MBOX_CMD_READ_GPIO 0x11 +#define P50_MBOX_CMD_WRITE_GPIO 0x12 +#define P50_MBOX_CMD_CLEAR 0xff + +#define P50_MBOX_STATUS_SUCCESS 0x01 + +#define P50_MBOX_PARAM_LED 0x12 +#define P50_MBOX_PARAM_BTN 0x13 + + +struct p50_gpio { + struct gpio_chip gc; + struct mutex lock; + unsigned long base; + struct platform_device *leds_pdev; + struct platform_device *keys_pdev; +}; + +static struct platform_device *gpio_pdev; + +static int gpio_params[] = { + [P50_GPIO_LINE_LED] = P50_MBOX_PARAM_LED, + [P50_GPIO_LINE_BTN] = P50_MBOX_PARAM_BTN, +}; + +static const char * const gpio_names[] = { + [P50_GPIO_LINE_LED] = "identify-led", + [P50_GPIO_LINE_BTN] = "identify-button", +}; + + +static struct gpiod_lookup_table p50_gpio_led_table = { + .dev_id = "leds-gpio", + .table = { + GPIO_LOOKUP_IDX(DRIVER_NAME, P50_GPIO_LINE_LED, NULL, 0, GPIO_ACTIVE_HIGH), + {} + } +}; + +/* GPIO LEDs */ +static struct gpio_led leds[] = { + { .name = "identify" } +}; + +static struct gpio_led_platform_data leds_pdata = { + .num_leds = ARRAY_SIZE(leds), + .leds = leds, +}; + +/* GPIO keyboard */ +static struct gpio_keys_button buttons[] = { + { + .code = KEY_RESTART, + .gpio = P50_GPIO_LINE_BTN, + .active_low = 1, + .type = EV_KEY, + .value = 1, + }, +}; + +static struct gpio_keys_platform_data keys_pdata = { + .buttons = buttons, + .nbuttons = ARRAY_SIZE(buttons), + .poll_interval = 100, + .rep = 0, + .name = "identify", +}; + + +/* low level access routines */ + +static int p50_wait_ec(struct p50_gpio *p50, int mask, int expected) +{ + int i, val; + + for (i = 0; i < 100; i++) { + val = inb(p50->base + P50_PORT_CMD) & mask; + if (val == expected) + return 0; + usleep_range(500, 2000); + } + + dev_err(p50->gc.parent, "Timed out waiting for EC (0x%x)\n", val); + return -ETIMEDOUT; +} + + +static int p50_read_mbox_reg(struct p50_gpio *p50, int reg) +{ + int ret; + + ret = p50_wait_ec(p50, P50_STATUS_IBF, 0); + if (ret) + return ret; + + /* clear output buffer flag, prevent unfinished commands */ + inb(p50->base + P50_PORT_DATA); + + /* cmd/address */ + outb(P50_CMD_READ | reg, p50->base + P50_PORT_CMD); + + ret = p50_wait_ec(p50, P50_STATUS_OBF, P50_STATUS_OBF); + if (ret) + return ret; + + return inb(p50->base + P50_PORT_DATA); +} + +static int p50_write_mbox_reg(struct p50_gpio *p50, int reg, int val) +{ + int ret; + + ret = p50_wait_ec(p50, P50_STATUS_IBF, 0); + if (ret) + return ret; + + /* cmd/address */ + outb(P50_CMD_WRITE | reg, p50->base + P50_PORT_CMD); + + ret = p50_wait_ec(p50, P50_STATUS_IBF, 0); + if (ret) + return ret; + + /* data */ + outb(val, p50->base + P50_PORT_DATA); + + return 0; +} + + +/* mbox routines */ + +static int p50_wait_mbox_idle(struct p50_gpio *p50) +{ + int i, val; + + for (i = 0; i < 1000; i++) { + val = p50_read_mbox_reg(p50, P50_MBOX_REG_CMD); + /* cmd is 0 when idle */ + if (val <= 0) + return val; + + usleep_range(500, 2000); + } + + dev_err(p50->gc.parent, "Timed out waiting for EC mbox idle (CMD: 0x%x)\n", val); + + return -ETIMEDOUT; +} + +static int p50_send_mbox_cmd(struct p50_gpio *p50, int cmd, int param, int data) +{ + int ret; + + ret = p50_wait_mbox_idle(p50); + if (ret) + return ret; + + ret = p50_write_mbox_reg(p50, P50_MBOX_REG_DATA, data); + if (ret) + return ret; + + ret = p50_write_mbox_reg(p50, P50_MBOX_REG_PARAM, param); + if (ret) + return ret; + + ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, cmd); + if (ret) + return ret; + + ret = p50_wait_mbox_idle(p50); + if (ret) + return ret; + + ret = p50_read_mbox_reg(p50, P50_MBOX_REG_STATUS); + if (ret < 0) + return ret; + + if (ret == P50_MBOX_STATUS_SUCCESS) + return 0; + + dev_err(p50->gc.parent, "Mbox command failed (CMD=0x%x STAT=0x%x PARAM=0x%x DATA=0x%x)\n", + cmd, ret, param, data); + + return -EIO; +} + + +/* gpio routines */ + +static int p50_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + switch (offset) { + case P50_GPIO_LINE_BTN: + return GPIO_LINE_DIRECTION_IN; + + case P50_GPIO_LINE_LED: + return GPIO_LINE_DIRECTION_OUT; + + default: + return -EINVAL; + } +} + +static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct p50_gpio *p50 = gpiochip_get_data(gc); + int ret; + + mutex_lock(&p50->lock); + + ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0); + if (ret == 0) + ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA); + + mutex_unlock(&p50->lock); + + return ret; +} + +static void p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct p50_gpio *p50 = gpiochip_get_data(gc); + + mutex_lock(&p50->lock); + + p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, gpio_params[offset], value); + + mutex_unlock(&p50->lock); +} + +static int p50_gpio_probe(struct platform_device *pdev) +{ + struct p50_gpio *p50; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(&pdev->dev, "Cannot get I/O ports\n"); + return -ENODEV; + } + + if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "Unable to reserve I/O region\n"); + return -EBUSY; + } + + p50 = devm_kzalloc(&pdev->dev, sizeof(*p50), GFP_KERNEL); + if (!p50) + return -ENOMEM; + + platform_set_drvdata(pdev, p50); + mutex_init(&p50->lock); + p50->base = res->start; + p50->gc.owner = THIS_MODULE; + p50->gc.parent = &pdev->dev; + p50->gc.label = dev_name(&pdev->dev); + p50->gc.ngpio = ARRAY_SIZE(gpio_names); + p50->gc.names = gpio_names; + p50->gc.can_sleep = true; + p50->gc.base = -1; + p50->gc.get_direction = p50_gpio_get_direction; + p50->gc.get = p50_gpio_get; + p50->gc.set = p50_gpio_set; + + + /* reset mbox */ + ret = p50_wait_mbox_idle(p50); + if (ret) + return ret; + + ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, P50_MBOX_CMD_CLEAR); + if (ret) + return ret; + + ret = p50_wait_mbox_idle(p50); + if (ret) + return ret; + + + ret = devm_gpiochip_add_data(&pdev->dev, &p50->gc, p50); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip: %d\n", ret); + return ret; + } + + gpiod_add_lookup_table(&p50_gpio_led_table); + + p50->leds_pdev = platform_device_register_data(&pdev->dev, + "leds-gpio", PLATFORM_DEVID_NONE, &leds_pdata, sizeof(leds_pdata)); + + if (IS_ERR(p50->leds_pdev)) { + ret = PTR_ERR(p50->leds_pdev); + dev_err(&pdev->dev, "Could not register leds-gpio: %d\n", ret); + goto err_leds; + } + + /* gpio-keys-polled uses old-style gpio interface, pass the right identifier */ + buttons[0].gpio += p50->gc.base; + + p50->keys_pdev = + platform_device_register_data(&pdev->dev, "gpio-keys-polled", + PLATFORM_DEVID_NONE, + &keys_pdata, sizeof(keys_pdata)); + + if (IS_ERR(p50->keys_pdev)) { + ret = PTR_ERR(p50->keys_pdev); + dev_err(&pdev->dev, "Could not register gpio-keys-polled: %d\n", ret); + goto err_keys; + } + + return 0; + +err_keys: + platform_device_unregister(p50->leds_pdev); +err_leds: + gpiod_remove_lookup_table(&p50_gpio_led_table); + + return ret; +} + +static int p50_gpio_remove(struct platform_device *pdev) +{ + struct p50_gpio *p50 = platform_get_drvdata(pdev); + + platform_device_unregister(p50->keys_pdev); + platform_device_unregister(p50->leds_pdev); + + gpiod_remove_lookup_table(&p50_gpio_led_table); + + return 0; +} + +static struct platform_driver p50_gpio_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = p50_gpio_probe, + .remove = p50_gpio_remove, +}; + +/* Board setup */ +static const struct dmi_system_id dmi_ids[] __initconst = { + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Barco"), + DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "P50") + }, + }, + {} +}; +MODULE_DEVICE_TABLE(dmi, dmi_ids); + +static int __init p50_module_init(void) +{ + struct resource res = DEFINE_RES_IO(P50_GPIO_IO_PORT_BASE, P50_PORT_CMD + 1); + + if (!dmi_first_match(dmi_ids)) + return -ENODEV; + + platform_driver_register(&p50_gpio_driver); + + gpio_pdev = platform_device_register_simple(DRIVER_NAME, PLATFORM_DEVID_NONE, &res, 1); + if (IS_ERR(gpio_pdev)) { + pr_err("failed registering %s: %ld\n", DRIVER_NAME, PTR_ERR(gpio_pdev)); + platform_driver_unregister(&p50_gpio_driver); + return PTR_ERR(gpio_pdev); + } + + return 0; +} + +static void __exit p50_module_exit(void) +{ + platform_device_unregister(gpio_pdev); + platform_driver_unregister(&p50_gpio_driver); +} + +module_init(p50_module_init); +module_exit(p50_module_exit); + +MODULE_AUTHOR("Santosh Kumar Yadav, Barco NV "); +MODULE_DESCRIPTION("Barco P50 identify GPIOs driver"); +MODULE_LICENSE("GPL"); From 4c9dbf8622797eee44e9a4f7327d3d04aa4d1d5f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 20 Oct 2021 11:29:45 -0500 Subject: [PATCH 084/106] platform/x86: amd-pmc: adjust arguments for `amd_pmc_send_cmd` Currently the "argument" for the "message" is listed as a boolean value. This works well for the commands used currently, but an additional upcoming command will pass more data in the message. Expand it to be a full 32 bit value. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20211020162946.10537-1-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index b7b6ad4629a7..99ac50616bc3 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -126,7 +126,7 @@ struct amd_pmc_dev { }; static struct amd_pmc_dev pmc; -static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret); +static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset) { @@ -337,7 +337,7 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value); } -static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret) +static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret) { int rc; u32 val; @@ -356,7 +356,7 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg amd_pmc_reg_write(dev, AMD_PMC_REGISTER_RESPONSE, 0); /* Write argument into response register */ - amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, set); + amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, arg); /* Write message ID to message ID register */ amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg); From 59348401ebed9f0e8ffe2d5b9cf1de30ecb24dde Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 20 Oct 2021 11:29:46 -0500 Subject: [PATCH 085/106] platform/x86: amd-pmc: Add special handling for timer based S0i3 wakeup RTC based wakeup from s0i3 doesn't work properly on some Green Sardine platforms. Because of this, a newer SMU for Green Sardine has the ability to pass wakeup time as argument of the upper 16 bits of OS_HINT message. With older firmware setting the timer value in OS_HINT will cause firmware to reject the hint, so only run this path on: 1) Green Sardine 2) Minimum SMU FW 3) RTC alarm armed during s0i3 entry Using this method has some limitations that the s0i3 wakeup will need to be between 4 seconds and 18 hours, so check those boundary conditions as well and abort the suspend if RTC is armed for too short or too long of a duration. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20211020162946.10537-2-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 60 +++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index 99ac50616bc3..678bf6874c63 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -17,9 +17,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -412,20 +414,76 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) return -EINVAL; } +static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) +{ + struct rtc_device *rtc_device; + time64_t then, now, duration; + struct rtc_wkalrm alarm; + struct rtc_time tm; + int rc; + + if (pdev->major < 64 || (pdev->major == 64 && pdev->minor < 53)) + return 0; + + rtc_device = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE); + if (!rtc_device) + return 0; + rc = rtc_read_alarm(rtc_device, &alarm); + if (rc) + return rc; + if (!alarm.enabled) { + dev_dbg(pdev->dev, "alarm not enabled\n"); + return 0; + } + rc = rtc_valid_tm(&alarm.time); + if (rc) + return rc; + rc = rtc_read_time(rtc_device, &tm); + if (rc) + return rc; + then = rtc_tm_to_time64(&alarm.time); + now = rtc_tm_to_time64(&tm); + duration = then-now; + + /* in the past */ + if (then < now) + return 0; + + /* will be stored in upper 16 bits of s0i3 hint argument, + * so timer wakeup from s0i3 is limited to ~18 hours or less + */ + if (duration <= 4 || duration > U16_MAX) + return -EINVAL; + + *arg |= (duration << 16); + rc = rtc_alarm_irq_enable(rtc_device, 0); + dev_info(pdev->dev, "wakeup timer programmed for %lld seconds\n", duration); + + return rc; +} + static int __maybe_unused amd_pmc_suspend(struct device *dev) { struct amd_pmc_dev *pdev = dev_get_drvdata(dev); int rc; u8 msg; + u32 arg = 1; /* Reset and Start SMU logging - to monitor the s0i3 stats */ amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0); amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0); + /* Activate CZN specific RTC functionality */ + if (pdev->cpu_id == AMD_CPU_ID_CZN) { + rc = amd_pmc_verify_czn_rtc(pdev, &arg); + if (rc < 0) + return rc; + } + /* Dump the IdleMask before we send hint to SMU */ amd_pmc_idlemask_read(pdev, dev, NULL); msg = amd_pmc_get_os_hint(pdev); - rc = amd_pmc_send_cmd(pdev, 1, NULL, msg, 0); + rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0); if (rc) dev_err(pdev->dev, "suspend failed\n"); From ef51b9a520f04875da3e5175fddbdb6980e9ab3a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 21 Oct 2021 13:10:53 +0200 Subject: [PATCH 086/106] platform/surface: gpe: Add support for Surface Laptop Studio The new Surface Laptop Studio uses GPEs for lid events as well. Add an entry for that so that the lid can be used to wake the device. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20211021111053.564133-1-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_gpe.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c index 86f6991b1215..c1775db29efb 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -26,6 +26,11 @@ static const struct property_entry lid_device_props_l17[] = { {}, }; +static const struct property_entry lid_device_props_l4B[] = { + PROPERTY_ENTRY_U32("gpe", 0x4B), + {}, +}; + static const struct property_entry lid_device_props_l4D[] = { PROPERTY_ENTRY_U32("gpe", 0x4D), {}, @@ -158,6 +163,14 @@ static const struct dmi_system_id dmi_lid_device_table[] = { }, .driver_data = (void *)lid_device_props_l4D, }, + { + .ident = "Surface Laptop Studio", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop Studio"), + }, + .driver_data = (void *)lid_device_props_l4B, + }, { } }; From 4f042e40199ce8bac6bc2b853e81744ee4ea759c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 21 Oct 2021 15:09:02 +0200 Subject: [PATCH 087/106] platform/surface: aggregator_registry: Add support for Surface Laptop Studio Add support for the Surface Laptop Studio. In contrast to previous Surface Laptop models, this one has its HID devices attached to target ID 1 (instead of 2). It also has a couple more of them, including a new notifier for when the pen is stashed / taken out of its place, a "Sys Control" device, and two other unidentified HID devices with unknown usages. Battery and performance profile interfaces remain the same. Cc: stable@vger.kernel.org # 5.14+ Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20211021130904.862610-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../surface/surface_aggregator_registry.c | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 4428c4330229..1679811eff50 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -77,6 +77,42 @@ 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 = { + .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 = { + .name = "ssam:01:15:01:02:00", + .parent = &ssam_node_root, +}; + +/* HID touchpad (TID1). */ +static const struct software_node ssam_node_hid_tid1_touchpad = { + .name = "ssam:01:15:01:03:00", + .parent = &ssam_node_root, +}; + +/* HID device instance 6 (TID1, unknown HID device). */ +static const struct software_node ssam_node_hid_tid1_iid6 = { + .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 = { + .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 = { + .name = "ssam:01:15:01:08:00", + .parent = &ssam_node_root, +}; + /* HID keyboard. */ static const struct software_node ssam_node_hid_main_keyboard = { .name = "ssam:01:15:02:01:00", @@ -159,6 +195,21 @@ static const struct software_node *ssam_node_group_sl3[] = { NULL, }; +/* Devices for Surface Laptop Studio. */ +static const struct software_node *ssam_node_group_sls[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_tmp_pprof, + &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_sysctrl, + NULL, +}; + /* Devices for Surface Laptop Go. */ static const struct software_node *ssam_node_group_slg1[] = { &ssam_node_root, @@ -507,6 +558,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { /* Surface Laptop Go 1 */ { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + /* Surface Laptop Studio */ + { "MSHW0123", (unsigned long)ssam_node_group_sls }, + { }, }; MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match); From dc0fd0acb6e0e8025a0a43ada54513b216254fac Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 21 Oct 2021 15:09:03 +0200 Subject: [PATCH 088/106] HID: surface-hid: Use correct event registry for managing HID events Until now, we have only ever seen the REG-category registry being used on devices addressed with target ID 2. In fact, we have only ever seen Surface Aggregator Module (SAM) HID devices with target ID 2. For those devices, the registry also has to be addressed with target ID 2. Some devices, like the new Surface Laptop Studio, however, address their HID devices on target ID 1. As a result of this, any target ID 2 commands time out. This includes event management commands addressed to the target ID 2 REG-category registry. For these devices, the registry has to be addressed via target ID 1 instead. We therefore assume that the target ID of the registry to be used depends on the target ID of the respective device. Implement this accordingly. Note that we currently allow the surface HID driver to only load against devices with target ID 2, so these timeouts are not happening (yet). This is just a preparation step before we allow the driver to load against all target IDs. Cc: stable@vger.kernel.org # 5.14+ Signed-off-by: Maximilian Luz Acked-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211021130904.862610-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/hid/surface-hid/surface_hid.c | 2 +- include/linux/surface_aggregator/controller.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c index a3a70e4f3f6c..daa452367c0b 100644 --- a/drivers/hid/surface-hid/surface_hid.c +++ b/drivers/hid/surface-hid/surface_hid.c @@ -209,7 +209,7 @@ static int surface_hid_probe(struct ssam_device *sdev) shid->notif.base.priority = 1; shid->notif.base.fn = ssam_hid_event_fn; - shid->notif.event.reg = SSAM_EVENT_REGISTRY_REG; + shid->notif.event.reg = SSAM_EVENT_REGISTRY_REG(sdev->uid.target); shid->notif.event.id.target_category = sdev->uid.category; shid->notif.event.id.instance = sdev->uid.instance; shid->notif.event.mask = SSAM_EVENT_MASK_STRICT; diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index 068e1982ad37..74bfdffaf7b0 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -792,8 +792,8 @@ enum ssam_event_mask { #define SSAM_EVENT_REGISTRY_KIP \ SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, 0x02, 0x27, 0x28) -#define SSAM_EVENT_REGISTRY_REG \ - SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, 0x02, 0x01, 0x02) +#define SSAM_EVENT_REGISTRY_REG(tid)\ + SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, tid, 0x01, 0x02) /** * enum ssam_event_notifier_flags - Flags for event notifiers. From ab5fe33925c6b03f646a1153771dab047548e4d8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 21 Oct 2021 15:09:04 +0200 Subject: [PATCH 089/106] HID: surface-hid: Allow driver matching for target ID 1 devices Until now we have only ever seen HID devices with target ID 2. The new Surface Laptop Studio however uses HID devices with target ID 1. Allow matching this driver to those as well. Cc: stable@vger.kernel.org # 5.14+ Signed-off-by: Maximilian Luz Acked-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211021130904.862610-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/hid/surface-hid/surface_hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c index daa452367c0b..d4aa8c81903a 100644 --- a/drivers/hid/surface-hid/surface_hid.c +++ b/drivers/hid/surface-hid/surface_hid.c @@ -230,7 +230,7 @@ static void surface_hid_remove(struct ssam_device *sdev) } static const struct ssam_device_id surface_hid_match[] = { - { SSAM_SDEV(HID, 0x02, SSAM_ANY_IID, 0x00) }, + { SSAM_SDEV(HID, SSAM_ANY_TID, SSAM_ANY_IID, 0x00) }, { }, }; MODULE_DEVICE_TABLE(ssam, surface_hid_match); From b8d4d35074fddb00e27bfa3acf5f4f8b0696a1af Mon Sep 17 00:00:00 2001 From: Mikalai Ramanovich Date: Fri, 15 Oct 2021 22:13:22 +0300 Subject: [PATCH 090/106] platform/x86: wmi: change notification handler type Since AML code on some Xiaomi laptops notifies the WMI hotkey with 0x20 event, we need ACPI_ALL_NOTIFY here to be able to handle it. Signed-off-by: Mikalai Ramanovich Link: https://lore.kernel.org/r/20211015191322.73388-1-nikolay.romanovich.00@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/wmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index e6997be206f1..c34341f4da76 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1352,7 +1352,7 @@ static int acpi_wmi_remove(struct platform_device *device) { struct acpi_device *acpi_device = ACPI_COMPANION(&device->dev); - acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY, + acpi_remove_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY, acpi_wmi_notify_handler); acpi_remove_address_space_handler(acpi_device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); @@ -1385,7 +1385,7 @@ static int acpi_wmi_probe(struct platform_device *device) } status = acpi_install_notify_handler(acpi_device->handle, - ACPI_DEVICE_NOTIFY, + ACPI_ALL_NOTIFY, acpi_wmi_notify_handler, NULL); if (ACPI_FAILURE(status)) { @@ -1414,7 +1414,7 @@ err_remove_busdev: device_unregister(wmi_bus_dev); err_remove_notify_handler: - acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY, + acpi_remove_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY, acpi_wmi_notify_handler); err_remove_ec_handler: From 164e32717cbde87a2df27183b985631b49701fad Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 21 Oct 2021 15:02:43 -0600 Subject: [PATCH 091/106] docs: ABI: fix documentation warning in sysfs-driver-mlxreg-io The use of a Sphinx list within this ABI file caused the following warning: Documentation/ABI/stable/sysfs-driver-mlxreg-io:230: WARNING: Unexpected indentation. Documentation/ABI/stable/sysfs-driver-mlxreg-io:230: WARNING: Block quote ends without a blank line; unexpected unindent. Remove the bullets to make the warning go away and get proper formatting. Reported-by: Stephen Rothwell Signed-off-by: Jonathan Corbet Signed-off-by: Hans de Goede --- .../ABI/stable/sysfs-driver-mlxreg-io | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io index c84795ccecad..12c3f895cd2f 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io @@ -231,16 +231,19 @@ Date: October 2021 KernelVersion: 5.16 Contact: Vadim Pasternak Description: The files represent BIOS statuses: - - bios_active_image: location of current active BIOS image: - 0: Top, 1: Bottom. - The reported value should correspond to value expected by OS - in case of BIOS safe mode is 0. This bit is related to Intel - top-swap feature of DualBios on the same flash. - - bios_auth_fail: BIOS upgrade is failed because provided BIOS - image is not signed correctly. - - bios_upgrade_fail: BIOS upgrade is failed by some other - reason not because authentication. For example due to - physical SPI flash problem. + + bios_active_image: location of current active BIOS image: + 0: Top, 1: Bottom. + The reported value should correspond to value expected by OS + in case of BIOS safe mode is 0. This bit is related to Intel + top-swap feature of DualBios on the same flash. + + bios_auth_fail: BIOS upgrade is failed because provided BIOS + image is not signed correctly. + + bios_upgrade_fail: BIOS upgrade is failed by some other + reason not because authentication. For example due to + physical SPI flash problem. The files are read only. From 21d91e20793ddac46d61d56e5304825a2897553a Mon Sep 17 00:00:00 2001 From: Ye Guojin Date: Fri, 22 Oct 2021 09:07:22 +0000 Subject: [PATCH 092/106] platform/x86: lg-laptop: replace snprintf in show functions with sysfs_emit coccicheck complains about the use of snprintf() in sysfs show functions: WARNING use scnprintf or sprintf Use sysfs_emit instead of scnprintf or sprintf makes more sense. Reported-by: Zeal Robot Signed-off-by: Ye Guojin Link: https://lore.kernel.org/r/20211022090722.1065457-1-ye.guojin@zte.com.cn Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/lg-laptop.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index 7e9351c36389..ae9293024c77 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -330,7 +330,7 @@ static ssize_t fan_mode_show(struct device *dev, status = r->integer.value & 0x01; kfree(r); - return snprintf(buffer, PAGE_SIZE, "%d\n", status); + return sysfs_emit(buffer, "%d\n", status); } static ssize_t usb_charge_store(struct device *dev, @@ -372,7 +372,7 @@ static ssize_t usb_charge_show(struct device *dev, kfree(r); - return snprintf(buffer, PAGE_SIZE, "%d\n", status); + return sysfs_emit(buffer, "%d\n", status); } static ssize_t reader_mode_store(struct device *dev, @@ -414,7 +414,7 @@ static ssize_t reader_mode_show(struct device *dev, kfree(r); - return snprintf(buffer, PAGE_SIZE, "%d\n", status); + return sysfs_emit(buffer, "%d\n", status); } static ssize_t fn_lock_store(struct device *dev, @@ -455,7 +455,7 @@ static ssize_t fn_lock_show(struct device *dev, status = !!r->buffer.pointer[0]; kfree(r); - return snprintf(buffer, PAGE_SIZE, "%d\n", status); + return sysfs_emit(buffer, "%d\n", status); } static ssize_t battery_care_limit_store(struct device *dev, @@ -520,7 +520,7 @@ static ssize_t battery_care_limit_show(struct device *dev, if (status != 80 && status != 100) status = 0; - return snprintf(buffer, PAGE_SIZE, "%d\n", status); + return sysfs_emit(buffer, "%d\n", status); } static DEVICE_ATTR_RW(fan_mode); From c4b9ad6bf99007f67a4d0bbd83fd15d1bdd0222f Mon Sep 17 00:00:00 2001 From: Ye Guojin Date: Fri, 22 Oct 2021 09:08:51 +0000 Subject: [PATCH 093/106] platform/x86: sony-laptop: replace snprintf in show functions with sysfs_emit coccicheck complains about the use of snprintf() in sysfs show functions: WARNING use scnprintf or sprintf Use sysfs_emit instead of scnprintf or sprintf makes more sense. Reported-by: Zeal Robot Signed-off-by: Ye Guojin Link: https://lore.kernel.org/r/20211022090851.1065538-1-ye.guojin@zte.com.cn Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/sony-laptop.c | 46 ++++++++++++------------------ 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 704813374922..d8d0c0bed5e9 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -964,7 +964,7 @@ static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *a if (item->validate) value = item->validate(SNC_VALIDATE_OUT, value); - return snprintf(buffer, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buffer, "%d\n", value); } static ssize_t sony_nc_sysfs_store(struct device *dev, @@ -1811,9 +1811,7 @@ static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev, static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev, struct device_attribute *attr, char *buffer) { - ssize_t count = 0; - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode); - return count; + return sysfs_emit(buffer, "%d\n", kbdbl_ctl->mode); } static int __sony_nc_kbd_backlight_timeout_set(u8 value) @@ -1855,9 +1853,7 @@ static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev, static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev, struct device_attribute *attr, char *buffer) { - ssize_t count = 0; - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout); - return count; + return sysfs_emit(buffer, "%d\n", kbdbl_ctl->timeout); } static int sony_nc_kbd_backlight_setup(struct platform_device *pd, @@ -2051,21 +2047,18 @@ static ssize_t sony_nc_battery_care_limit_show(struct device *dev, break; } - return snprintf(buffer, PAGE_SIZE, "%d\n", status); + return sysfs_emit(buffer, "%d\n", status); } static ssize_t sony_nc_battery_care_health_show(struct device *dev, struct device_attribute *attr, char *buffer) { - ssize_t count = 0; unsigned int health; if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health)) return -EIO; - count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff); - - return count; + return sysfs_emit(buffer, "%d\n", health & 0xff); } static int sony_nc_battery_care_setup(struct platform_device *pd, @@ -2215,15 +2208,12 @@ static ssize_t sony_nc_thermal_mode_store(struct device *dev, static ssize_t sony_nc_thermal_mode_show(struct device *dev, struct device_attribute *attr, char *buffer) { - ssize_t count = 0; int mode = sony_nc_thermal_mode_get(); if (mode < 0) return mode; - count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]); - - return count; + return sysfs_emit(buffer, "%s\n", snc_thermal_profiles[mode]); } static int sony_nc_thermal_setup(struct platform_device *pd) @@ -2361,7 +2351,7 @@ static ssize_t sony_nc_lid_resume_show(struct device *dev, while (pos < LID_RESUME_MAX) { if (&lid_ctl->attrs[pos].attr == &attr->attr) - return snprintf(buffer, PAGE_SIZE, "%d\n", + return sysfs_emit(buffer, "%d\n", (lid_ctl->status >> pos) & 0x01); pos++; } @@ -2493,7 +2483,7 @@ static ssize_t sony_nc_gfx_switch_status_show(struct device *dev, if (pos < 0) return pos; - return snprintf(buffer, PAGE_SIZE, "%s\n", + return sysfs_emit(buffer, "%s\n", pos == SPEED ? "speed" : pos == STAMINA ? "stamina" : pos == AUTO ? "auto" : "unknown"); @@ -2568,7 +2558,7 @@ static ssize_t sony_nc_highspeed_charging_show(struct device *dev, if (sony_call_snc_handle(0x0131, 0x0100, &result)) return -EIO; - return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01); + return sysfs_emit(buffer, "%d\n", result & 0x01); } static int sony_nc_highspeed_charging_setup(struct platform_device *pd) @@ -2642,7 +2632,7 @@ static ssize_t sony_nc_lowbatt_show(struct device *dev, if (sony_call_snc_handle(0x0121, 0x0200, &result)) return -EIO; - return snprintf(buffer, PAGE_SIZE, "%d\n", result & 1); + return sysfs_emit(buffer, "%d\n", result & 1); } static int sony_nc_lowbatt_setup(struct platform_device *pd) @@ -2708,7 +2698,7 @@ static ssize_t sony_nc_hsfan_show(struct device *dev, if (sony_call_snc_handle(0x0149, 0x0100, &result)) return -EIO; - return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01); + return sysfs_emit(buffer, "%d\n", result & 0x01); } static ssize_t sony_nc_fanspeed_show(struct device *dev, @@ -2719,7 +2709,7 @@ static ssize_t sony_nc_fanspeed_show(struct device *dev, if (sony_call_snc_handle(0x0149, 0x0300, &result)) return -EIO; - return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff); + return sysfs_emit(buffer, "%d\n", result & 0xff); } static int sony_nc_fanspeed_setup(struct platform_device *pd) @@ -2815,7 +2805,7 @@ static ssize_t sony_nc_usb_charge_show(struct device *dev, if (sony_call_snc_handle(0x0155, 0x0000, &result)) return -EIO; - return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01); + return sysfs_emit(buffer, "%d\n", result & 0x01); } static int sony_nc_usb_charge_setup(struct platform_device *pd) @@ -2870,7 +2860,7 @@ static ssize_t sony_nc_panelid_show(struct device *dev, if (sony_call_snc_handle(0x011D, 0x0000, &result)) return -EIO; - return snprintf(buffer, PAGE_SIZE, "%d\n", result); + return sysfs_emit(buffer, "%d\n", result); } static int sony_nc_panelid_setup(struct platform_device *pd) @@ -2998,7 +2988,7 @@ static ssize_t sony_nc_touchpad_show(struct device *dev, if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result)) return -EINVAL; - return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01)); + return sysfs_emit(buffer, "%d\n", !(result & 0x01)); } static int sony_nc_touchpad_setup(struct platform_device *pd, @@ -3915,7 +3905,7 @@ static ssize_t sony_pic_wwanpower_show(struct device *dev, { ssize_t count; mutex_lock(&spic_dev.lock); - count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power); + count = sysfs_emit(buffer, "%d\n", spic_dev.wwan_power); mutex_unlock(&spic_dev.lock); return count; } @@ -3954,7 +3944,7 @@ static ssize_t sony_pic_bluetoothpower_show(struct device *dev, { ssize_t count = 0; mutex_lock(&spic_dev.lock); - count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power); + count = sysfs_emit(buffer, "%d\n", spic_dev.bluetooth_power); mutex_unlock(&spic_dev.lock); return count; } @@ -3996,7 +3986,7 @@ static ssize_t sony_pic_fanspeed_show(struct device *dev, if (sony_pic_get_fanspeed(&value)) return -EIO; - return snprintf(buffer, PAGE_SIZE, "%d\n", value); + return sysfs_emit(buffer, "%d\n", value); } #define SPIC_ATTR(_name, _mode) \ From 9527cdff7832b96552ea3cf3fea7f0789fe94e5a Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Fri, 22 Oct 2021 14:46:12 +0200 Subject: [PATCH 094/106] platform/x86: barco-p50-gpio: use KEY_VENDOR for button instead of KEY_RESTART It turns out that systemd-logind by default listens for KEY_RESTART input events and reboots the machine, which isn't great - So use KEY_VENDOR for the vendor specific identify button instead to not conflict. Signed-off-by: Peter Korsgaard Link: https://lore.kernel.org/r/20211022124612.19780-1-peter@korsgaard.com Signed-off-by: Hans de Goede --- drivers/platform/x86/barco-p50-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c index ca0b2564c407..f5c72e33f9ae 100644 --- a/drivers/platform/x86/barco-p50-gpio.c +++ b/drivers/platform/x86/barco-p50-gpio.c @@ -101,7 +101,7 @@ static struct gpio_led_platform_data leds_pdata = { /* GPIO keyboard */ static struct gpio_keys_button buttons[] = { { - .code = KEY_RESTART, + .code = KEY_VENDOR, .gpio = P50_GPIO_LINE_BTN, .active_low = 1, .type = EV_KEY, From fc3341b4b55f46ad0846a22ae149d94bac6ce40b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 22 Oct 2021 17:48:40 +0200 Subject: [PATCH 095/106] platform/x86: system76_acpi: fix Kconfig dependencies When CONFIG_INPUT is disabled, this driver now fails to link: ld.lld: error: undefined symbol: devm_input_allocate_device >>> referenced by system76_acpi.c >>> platform/x86/system76_acpi.o:(system76_add) in archive drivers/built-in.a ld.lld: error: undefined symbol: input_set_capability >>> referenced by system76_acpi.c >>> platform/x86/system76_acpi.o:(system76_add) in archive drivers/built-in.a ld.lld: error: undefined symbol: devm_hwmon_device_register_with_info >>> referenced by system76_acpi.c >>> platform/x86/system76_acpi.o:(system76_add) in archive drivers/built-in.a ld.lld: error: undefined symbol: battery_hook_unregister >>> referenced by system76_acpi.c >>> platform/x86/system76_acpi.o:(system76_remove) in archive drivers/built-in.a Add Kconfig dependencies for each of these three. Fixes: 0de30fc684b3 ("platform/x86: system76_acpi: Replace Fn+F2 function for OLED models") Fixes: 95563d45b5da ("platform/x86: system76_acpi: Report temperature and fan speed") Fixes: 76f7eba3e0a2 ("platform/x86: system76_acpi: Add battery charging thresholds") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20211022154901.904984-1-arnd@kernel.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 9fd0c15d77a8..d4c079f4afc6 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -931,6 +931,9 @@ config SONYPI_COMPAT config SYSTEM76_ACPI tristate "System76 ACPI Driver" depends on ACPI + depends on ACPI_BATTERY + depends on HWMON + depends on INPUT select NEW_LEDS select LEDS_CLASS select LEDS_TRIGGERS From 2978891aff80e8dcae85f078213048a4bcd0ec2b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 Oct 2021 12:14:41 -0500 Subject: [PATCH 096/106] platform/x86: amd-pmc: fix compilation without CONFIG_RTC_SYSTOHC_DEVICE Just hardcode the RTC to "rtc0" which is the default for CONFIG_RTC_SYSTOHC_DEVICE and used by all standard x86 distros. Cc: Alexandre Belloni Suggested-by: Hans de Goede Fixes: 59348401ebed ("platform/x86: amd-pmc: Add special handling for timer based S0i3 wakeup") Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20211026171443.289-1-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index 678bf6874c63..b8d77a18e95a 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -425,7 +425,7 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) if (pdev->major < 64 || (pdev->major == 64 && pdev->minor < 53)) return 0; - rtc_device = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE); + rtc_device = rtc_class_open("rtc0"); if (!rtc_device) return 0; rc = rtc_read_alarm(rtc_device, &alarm); From 16a035a314060c4b12f70284302df448feb11bec Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 Oct 2021 12:14:42 -0500 Subject: [PATCH 097/106] platform/x86: amd-pmc: Downgrade dev_info message to dev_dbg For the majority of users this information will not be informative as they've chosen to program the RTC before going to sleep. Suggested-by: Alexandre Belloni Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20211026171443.289-2-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index b8d77a18e95a..81f3b9d79f43 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -457,7 +457,7 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) *arg |= (duration << 16); rc = rtc_alarm_irq_enable(rtc_device, 0); - dev_info(pdev->dev, "wakeup timer programmed for %lld seconds\n", duration); + dev_dbg(pdev->dev, "wakeup timer programmed for %lld seconds\n", duration); return rc; } From 9587f39277ef799ab3be7bb04b191bdf1a3e697a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 Oct 2021 12:14:43 -0500 Subject: [PATCH 098/106] platform/x86: amd-pmc: Drop check for valid alarm time This is already checked when calling rtc_read_alarm. Suggested-by: Alexandre Belloni Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20211026171443.289-3-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index 81f3b9d79f43..b7e50ed050a8 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -435,9 +435,6 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) dev_dbg(pdev->dev, "alarm not enabled\n"); return 0; } - rc = rtc_valid_tm(&alarm.time); - if (rc) - return rc; rc = rtc_read_time(rtc_device, &tm); if (rc) return rc; From d411e370978fcbf2135a51b43e9acabc879b304b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 Oct 2021 14:08:33 -0500 Subject: [PATCH 099/106] platform/x86: hp-wmi: rename platform_profile_* function symbols An upcoming change to platform profiles will export `platform_profile_get` as a symbol that can be used by other drivers. Avoid the collision. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20211026190835.10697-2-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/hp-wmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 8e31ffadf894..48a46466f086 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -1061,8 +1061,8 @@ static int thermal_profile_set(int thermal_profile) sizeof(thermal_profile), 0); } -static int platform_profile_get(struct platform_profile_handler *pprof, - enum platform_profile_option *profile) +static int hp_wmi_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) { int tp; @@ -1087,8 +1087,8 @@ static int platform_profile_get(struct platform_profile_handler *pprof, return 0; } -static int platform_profile_set(struct platform_profile_handler *pprof, - enum platform_profile_option profile) +static int hp_wmi_platform_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) { int err, tp; @@ -1147,8 +1147,8 @@ static int thermal_profile_setup(void) if (err) return err; - platform_profile_handler.profile_get = platform_profile_get; - platform_profile_handler.profile_set = platform_profile_set; + platform_profile_handler.profile_get = hp_wmi_platform_profile_get; + platform_profile_handler.profile_set = hp_wmi_platform_profile_set; } set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices); From 3aa539a584f6f65fc4e471274c8c8b443331eb52 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 26 Oct 2021 14:08:34 -0500 Subject: [PATCH 100/106] platform/x86: asus-wmi: rename platform_profile_* function symbols An upcoming change to platform profiles will export `platform_profile_get` as a symbol that can be used by other drivers. Avoid the collision. Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20211026190835.10697-3-mario.limonciello@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index e14fb5fa7324..8f067ac4e952 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -2169,8 +2169,8 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, static DEVICE_ATTR_RW(throttle_thermal_policy); /* Platform profile ***********************************************************/ -static int platform_profile_get(struct platform_profile_handler *pprof, - enum platform_profile_option *profile) +static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) { struct asus_wmi *asus; int tp; @@ -2196,8 +2196,8 @@ static int platform_profile_get(struct platform_profile_handler *pprof, return 0; } -static int platform_profile_set(struct platform_profile_handler *pprof, - enum platform_profile_option profile) +static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) { struct asus_wmi *asus; int tp; @@ -2236,8 +2236,8 @@ static int platform_profile_setup(struct asus_wmi *asus) dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n"); - asus->platform_profile_handler.profile_get = platform_profile_get; - asus->platform_profile_handler.profile_set = platform_profile_set; + asus->platform_profile_handler.profile_get = asus_wmi_platform_profile_get; + asus->platform_profile_handler.profile_set = asus_wmi_platform_profile_set; set_bit(PLATFORM_PROFILE_QUIET, asus->platform_profile_handler.choices); set_bit(PLATFORM_PROFILE_BALANCED, From 9045512ca6cdb221cd1ed32d483eac3c30c53bed Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 23 Oct 2021 12:40:20 +0300 Subject: [PATCH 101/106] platform/x86: mlx-platform: Extend FAN and LED configuration to support new MQM97xx systems Add support for new system types "MQM97xx", which is based on Mellanox Quantum-2 ASIC. It provides up to 64x400GB/s (IB) full bidirectional bandwidth per port using PAM-4 modulation. The system support 32 OSFP cages that can provide 64x400GB/s per port (two ports/cage). The system fits standard 1U racks. System is equipped with seven fan drawers and with per fan drawer LED on backport panel and uses two-bytes for exposing CPLD Part Number versions. System is recognized by "DMI_BOARD_NAME" match, when this field is set to "VMOD0010". Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20211023094022.4193813-2-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 56 ++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 7606165980c3..06fe58aaa23b 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -27,9 +27,13 @@ #define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET 0x02 #define MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET 0x03 #define MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET 0x04 +#define MLXPLAT_CPLD_LPC_REG_CPLD1_PN1_OFFSET 0x05 #define MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET 0x06 +#define MLXPLAT_CPLD_LPC_REG_CPLD2_PN1_OFFSET 0x07 #define MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET 0x08 +#define MLXPLAT_CPLD_LPC_REG_CPLD3_PN1_OFFSET 0x09 #define MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET 0x0a +#define MLXPLAT_CPLD_LPC_REG_CPLD4_PN1_OFFSET 0x0b #define MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET 0x1c #define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e @@ -127,6 +131,8 @@ #define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xee #define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xef #define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xf0 +#define MLXPLAT_CPLD_LPC_REG_TACHO13_OFFSET 0xf1 +#define MLXPLAT_CPLD_LPC_REG_TACHO14_OFFSET 0xf2 #define MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET 0xf3 #define MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET 0xf4 #define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf5 @@ -194,7 +200,7 @@ #define MLXPLAT_CPLD_PWR_EXT_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) -#define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) +#define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(6, 0) #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) @@ -933,6 +939,14 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { .bit = BIT(5), .hpdev.nr = MLXPLAT_CPLD_NR_NONE, }, + { + .label = "fan7", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(6), + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(6), + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, }; static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { @@ -2164,6 +2178,20 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, .bit = BIT(5), }, + { + .label = "fan7:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(6), + }, + { + .label = "fan7:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(6), + }, { .label = "uid:blue", .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, @@ -3526,6 +3554,20 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { .bit = BIT(3), .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, }, + { + .label = "tacho13", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO13_OFFSET, + .mask = GENMASK(7, 0), + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET, + .bit = BIT(4), + }, + { + .label = "tacho14", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO14_OFFSET, + .mask = GENMASK(7, 0), + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET, + .bit = BIT(5), + }, { .label = "conf", .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET, @@ -3835,9 +3877,13 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD1_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD3_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD4_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: @@ -3935,6 +3981,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO13_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO14_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: @@ -3958,9 +4006,13 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD1_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD3_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD4_PN1_OFFSET: case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: @@ -4050,6 +4102,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO13_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO14_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: From 4289fd4ad43afaed6d1515c573efe9e42a83219f Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 23 Oct 2021 12:40:21 +0300 Subject: [PATCH 102/106] platform/x86: mlx-platform: Add BIOS attributes for CoffeeLake COMEx based systems Extend systems of class VMOD0010 equipped with CoffeeLake COMEx module with BIOS related attributes to represent various BIOS statuses. These attributes "bios_active_image", "bios_auth_fail", "bios_upgrade_fail", "bios_safe_mode" has been already added to modular system. This all of them are already documented. - "bios_active_image" - location of current active BIOS image (0: Top, 1: Bottom. The reported value should correspond to value expected by OS in case of BIOS safe mode is 0. This bit is related to Intel top-swap feature of DualBios on the same flash. - "bios_auth_fail": BIOS upgrade is failed because provided BIOS image is not signed correctly. - "bios_upgrade_fail" BIOS upgrade is failed by some reason not related to authentication. For example, due to physical SPI flash problem. - "bios_safe_mod": - 0 : if BIOS is booted from a supposed active image; 1 : BIOS safe mechanism was enforced by hardware (CPLD). Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20211023094022.4193813-3-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 06fe58aaa23b..3d017e889ce5 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -2917,6 +2917,30 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .bit = GENMASK(7, 0), .mode = 0444, }, + { + .label = "bios_safe_mode", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "bios_active_image", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "bios_auth_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "bios_upgrade_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, { .label = "voltreg_update_status", .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, From 4616e54795cc8183ecf2a6cef6c7a9091cb1ae56 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 23 Oct 2021 12:40:22 +0300 Subject: [PATCH 103/106] platform/x86: mlx-platform: Add support for new system SGN2410 Add support for new system type, which is a water-cooling flavor of the VMOD001 system class, equipped with 48xSFP28 and 8xQSFP28 100G Ethernet ports. System is recognized by "DMI_BOARD_NAME" and " DMI_PRODUCT_SKU" matches, when these fields are set respectively to "VMOD001" and "HI138". Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20211023094022.4193813-4-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 113 ++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 3d017e889ce5..447044fdcb77 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -533,6 +533,21 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { }, }; +static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_wc_items_data[] = { + { + .label = "pwr1", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(0), + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "pwr2", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(1), + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { { .label = "fan1", @@ -661,6 +676,46 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; +static struct mlxreg_core_item mlxplat_mlxcpld_default_wc_items[] = { + { + .data = mlxplat_mlxcpld_comex_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_psu_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_pwr_wc_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_pwr_items_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, +}; + +static +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_wc_data = { + .items = mlxplat_mlxcpld_default_wc_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_wc_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, +}; + static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_comex_data = { .items = mlxplat_mlxcpld_comex_items, @@ -2018,6 +2073,35 @@ static struct mlxreg_core_platform_data mlxplat_default_led_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data), }; +/* Platform led default data for water cooling */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_led_wc_data[] = { + { + .label = "status:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "psu:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_led_wc_data = { + .data = mlxplat_mlxcpld_default_led_wc_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_wc_data), +}; + /* Platform led MSN21xx system family data */ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { { @@ -4311,6 +4395,28 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) return 1; } +static int __init mlxplat_dmi_default_wc_matched(const struct dmi_system_id *dmi) +{ + int i; + + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; + mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data); + mlxplat_mux_data = mlxplat_default_mux_data; + for (i = 0; i < mlxplat_mux_num; i++) { + mlxplat_mux_data[i].values = mlxplat_default_channels[i]; + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_default_channels[i]); + } + mlxplat_hotplug = &mlxplat_mlxcpld_default_wc_data; + mlxplat_hotplug->deferred_nr = + mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_wc_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; +} + static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) { int i; @@ -4474,6 +4580,13 @@ static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) } static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_wc_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI138"), + }, + }, { .callback = mlxplat_dmi_default_matched, .matches = { From 025a2fbd8ddc5fe6479bb5d2b0252ad9e789805f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 28 Oct 2021 03:28:45 +0200 Subject: [PATCH 104/106] platform/surface: aggregator_registry: Add initial support for Surface Pro 8 Add preliminary support for the Surface Pro 8 to the Surface Aggregator registry. This includes battery/charger status and platform profile support. In contrast to earlier Surface Pro generations, the keyboard cover is now also connected via the Surface Aggregator Module (whereas it was previously connected via USB or HID-over-I2C). To properly support the HID devices of that cover, however, more changes regarding hot-removal of Surface Aggregator client devices as well as a new device hub driver are required. We will address those things in a follow-up series, so do not add any HID device IDs just yet. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20211028012845.1887219-1-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../platform/surface/surface_aggregator_registry.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 1679811eff50..e70f4c63554e 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -228,6 +228,15 @@ static const struct software_node *ssam_node_group_sp7[] = { NULL, }; +static const struct software_node *ssam_node_group_sp8[] = { + &ssam_node_root, + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_tmp_pprof, + /* TODO: Add support for keyboard cover. */ + NULL, +}; + /* -- Device registry helper functions. ------------------------------------- */ @@ -534,6 +543,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { /* Surface Pro 7+ */ { "MSHW0119", (unsigned long)ssam_node_group_sp7 }, + /* Surface Pro 8 */ + { "MSHW0263", (unsigned long)ssam_node_group_sp8 }, + /* Surface Book 2 */ { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, From bf653b61cf5fb4a9b5a9c1a5a19dc5d5f5bd4172 Mon Sep 17 00:00:00 2001 From: Mark Stamp Date: Thu, 28 Oct 2021 11:48:24 +0200 Subject: [PATCH 105/106] platform/x86: touchscreen_dmi: Add info for the Viglen Connect 10 tablet Add touchscreen info for the Viglen Connect 10 tablet. Signed-off-by: Mark Stamp Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211028094824.84292-1-hdegoede@redhat.com --- drivers/platform/x86/touchscreen_dmi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 033f797861d8..fa8812039b82 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -938,6 +938,23 @@ static const struct ts_dmi_data trekstor_surftab_wintron70_data = { .properties = trekstor_surftab_wintron70_props, }; +static const struct property_entry viglen_connect_10_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1890), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_U32("touchscreen-fuzz-x", 6), + PROPERTY_ENTRY_U32("touchscreen-fuzz-y", 6), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-viglen-connect-10.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data viglen_connect_10_data = { + .acpi_name = "MSSL1680:00", + .properties = viglen_connect_10_props, +}; + static const struct property_entry vinga_twizzle_j116_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1920), PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), @@ -1521,6 +1538,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "YOURBOOK C11B"), }, }, + { + /* Viglen Connect 10 */ + .driver_data = (void *)&viglen_connect_10_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Viglen Ltd."), + DMI_MATCH(DMI_PRODUCT_NAME, "Connect 10'' Tablet PC"), + }, + }, { /* Vinga Twizzle J116 */ .driver_data = (void *)&vinga_twizzle_j116_data, From 97ae45953ea957887170078f488fd629dd1ce786 Mon Sep 17 00:00:00 2001 From: Tim Crawford Date: Sat, 30 Oct 2021 09:42:13 -0600 Subject: [PATCH 106/106] platform/x86: system76_acpi: Fix input device error handling Users on darp6 that do not have Open EC firmware have reported crashes on boot. Correct the error handling for the input device to fix it. Managed devices do not need to be explicitly unregistered or freed, as this is handled by devres. Drop the call to input_free_device. Fixes: 0de30fc684b3 ("platform/x86: system76_acpi: Replace Fn+F2 function for OLED models") Signed-off-by: Tim Crawford Link: https://lore.kernel.org/r/20211030154213.2515-1-tcrawford@system76.com Signed-off-by: Hans de Goede --- drivers/platform/x86/system76_acpi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index b3c8178420b1..8b292ee95a14 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -739,7 +739,6 @@ static int system76_add(struct acpi_device *acpi_dev) error: kfree(data->ntmp); kfree(data->nfan); - input_free_device(data->input); return err; }