From 700b256be9e8f1079638d630a3b2a60590963023 Mon Sep 17 00:00:00 2001 From: Chang Liu Date: Thu, 16 Nov 2017 10:35:07 +0800 Subject: platform/x86: alienware-wmi: lightbar LED support for Dell Inspiron 5675 Inspiron 5675 lightbar compatible with WMI interface on alienware, the difference lies in the zone number and color control. Add Inspiron 5675 DMI quirks to detect by dmi_check_system(). Signed-off-by: Chang Liu Acked-by: Mario Limonciello [andy: massaged commit message] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/alienware-wmi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 4eb8e1a472b2..9d7dbd925065 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -68,6 +68,14 @@ struct quirk_entry { static struct quirk_entry *quirks; + +static struct quirk_entry quirk_inspiron5675 = { + .num_zones = 2, + .hdmi_mux = 0, + .amplifier = 0, + .deepslp = 0, +}; + static struct quirk_entry quirk_unknown = { .num_zones = 2, .hdmi_mux = 0, @@ -171,6 +179,15 @@ static const struct dmi_system_id alienware_quirks[] __initconst = { }, .driver_data = &quirk_asm201, }, + { + .callback = dmi_matched, + .ident = "Dell Inc. Inspiron 5675", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"), + }, + .driver_data = &quirk_inspiron5675, + }, {} }; -- cgit v1.2.3 From db2582afa7444a0ce6bb1ebf1431715969a10b06 Mon Sep 17 00:00:00 2001 From: Kiernan Hager Date: Mon, 20 Nov 2017 14:18:44 -0700 Subject: platform/x86: asus-nb-wmi: Support ALS on the Zenbook UX430UQ This patch adds support for ALS on the Zenbook UX430UQ to the asus_nb_wmi driver. It also renames "quirk_asus_ux330uak" to "quirk_asus_forceals" because it is now used for more than one model of computer, and should thus have a more general name. Signed-off-by: Kiernan Hager [andy: massaged commit message, fixed indentation and commas in the code] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 5269a01d9bdd..136ff2b4cce5 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -111,7 +111,7 @@ static struct quirk_entry quirk_asus_x550lb = { .xusb2pr = 0x01D9, }; -static struct quirk_entry quirk_asus_ux330uak = { +static struct quirk_entry quirk_asus_forceals = { .wmi_force_als_set = true, }; @@ -387,7 +387,7 @@ static const struct dmi_system_id asus_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"), }, - .driver_data = &quirk_asus_ux330uak, + .driver_data = &quirk_asus_forceals, }, { .callback = dmi_matched, @@ -398,6 +398,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_x550lb, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX430UQ", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"), + }, + .driver_data = &quirk_asus_forceals, + }, {}, }; -- cgit v1.2.3 From 75971febd9b14a517c14e83fccf6a961b4c759f1 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Tue, 21 Nov 2017 13:30:44 +0800 Subject: platform/x86: Add Acer Wireless Radio Control driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New Acer laptops in 2018 will have a separate ACPI device for notifications from the airplane mode hotkey. The device name in the DSDT is SMKB and its ACPI _HID is 10251229. For these models, when the airplane mode hotkey (Fn+F3) pressed, a query 0x02 is started in the Embedded Controller, and all this query does is a notify SMKB with the value 0x80. Scope (_SB.PCI0.LPCB.EC0) { (...) Method (_Q02, 0, NotSerialized) // _Qxx: EC Query { HKEV (0x2, One) Notify (SMKB, 0x80) // Status Change } } Based on code from asus-wireless Signed-off-by: Chris Chiu Reviewed-by: João Paulo Rechi Vita Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 14 +++++++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/acer-wireless.c | 71 ++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 drivers/platform/x86/acer-wireless.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2c745e8ccad6..9d2a6d642f33 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -36,6 +36,20 @@ config ACER_WMI If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M here. +config ACER_WIRELESS + tristate "Acer Wireless Radio Control Driver" + depends on ACPI + depends on INPUT + ---help--- + The Acer Wireless Radio Control handles the airplane mode hotkey + present on new Acer laptops. + + Say Y or M here if you have an Acer notebook with an airplane mode + hotkey. + + If you choose to compile this driver as a module the module will be + called acer-wireless. + config ACERHDF tristate "Acer Aspire One temperature and fan driver" depends on ACPI && THERMAL diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index c32b34a72467..2996536bf54e 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o +obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o obj-$(CONFIG_ACERHDF) += acerhdf.o obj-$(CONFIG_HP_ACCEL) += hp_accel.o obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o diff --git a/drivers/platform/x86/acer-wireless.c b/drivers/platform/x86/acer-wireless.c new file mode 100644 index 000000000000..858037987b33 --- /dev/null +++ b/drivers/platform/x86/acer-wireless.c @@ -0,0 +1,71 @@ +/* + * Acer Wireless Radio Control Driver + * + * Copyright (C) 2017 Endless Mobile, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +static const struct acpi_device_id acer_wireless_acpi_ids[] = { + {"10251229", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids); + +static void acer_wireless_notify(struct acpi_device *adev, u32 event) +{ + struct input_dev *idev = acpi_driver_data(adev); + + dev_dbg(&adev->dev, "event=%#x\n", event); + if (event != 0x80) { + dev_notice(&adev->dev, "Unknown SMKB event: %#x\n", event); + return; + } + input_report_key(idev, KEY_RFKILL, 1); + input_report_key(idev, KEY_RFKILL, 0); + input_sync(idev); +} + +static int acer_wireless_add(struct acpi_device *adev) +{ + struct input_dev *idev; + + idev = devm_input_allocate_device(&adev->dev); + if (!idev) + return -ENOMEM; + + adev->driver_data = idev; + idev->name = "Acer Wireless Radio Control"; + idev->phys = "acer-wireless/input0"; + idev->id.bustype = BUS_HOST; + idev->id.vendor = PCI_VENDOR_ID_AI; + idev->id.product = 0x1229; + set_bit(EV_KEY, idev->evbit); + set_bit(KEY_RFKILL, idev->keybit); + + return input_register_device(idev); +} + +static struct acpi_driver acer_wireless_driver = { + .name = "Acer Wireless Radio Control Driver", + .class = "hotkey", + .ids = acer_wireless_acpi_ids, + .ops = { + .add = acer_wireless_add, + .notify = acer_wireless_notify, + }, +}; +module_acpi_driver(acer_wireless_driver); + +MODULE_DESCRIPTION("Acer Wireless Radio Control Driver"); +MODULE_AUTHOR("Chris Chiu "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 19a525d80836ff969b34bdf8a502c05c5eaf5f75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Nov 2017 20:24:02 +0100 Subject: platform/x86: Add support for Dollar Cove TI power button This provides a new input driver for supporting the power button on Dollar Cove TI PMIC, found on Cherrytrail-based devices. The patch is based on the original work by Intel, found at: https://github.com/01org/ProductionKernelQuilts Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=193891 Reviewed-by: Mika Westerberg Signed-off-by: Takashi Iwai Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 11 ++++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_chtdc_ti_pwrbtn.c | 93 ++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 drivers/platform/x86/intel_chtdc_ti_pwrbtn.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 9d2a6d642f33..88bf2f46b7a4 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1184,6 +1184,17 @@ config SILEAD_DMI with the OS-image for the device. This option supplies the missing information. Enable this for x86 tablets with Silead touchscreens. +config INTEL_CHTDC_TI_PWRBTN + tristate "Intel Cherry Trail Dollar Cove TI power button driver" + depends on INTEL_SOC_PMIC_CHTDC_TI + depends on INPUT + ---help--- + This option adds a power button driver driver for Dollar Cove TI + PMIC on Intel Cherry Trail devices. + + To compile this driver as a module, choose M here: the module + will be called intel_chtdc_ti_pwrbtn. + endif # X86_PLATFORM_DEVICES config PMC_ATOM diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2996536bf54e..4f92dbf30900 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -89,3 +89,4 @@ obj-$(CONFIG_PMC_ATOM) += pmc_atom.o obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o +obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o diff --git a/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c new file mode 100644 index 000000000000..38b8e7cfe88c --- /dev/null +++ b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c @@ -0,0 +1,93 @@ +/* + * Power-button driver for Dollar Cove TI PMIC + * Copyright (C) 2014 Intel Corp + * Copyright (c) 2017 Takashi Iwai + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHTDC_TI_SIRQ_REG 0x3 +#define SIRQ_PWRBTN_REL BIT(0) + +static irqreturn_t chtdc_ti_pwrbtn_interrupt(int irq, void *dev_id) +{ + struct input_dev *input = dev_id; + struct device *dev = input->dev.parent; + struct regmap *regmap = dev_get_drvdata(dev); + int state; + + if (!regmap_read(regmap, CHTDC_TI_SIRQ_REG, &state)) { + dev_dbg(dev, "SIRQ_REG=0x%x\n", state); + input_report_key(input, KEY_POWER, !(state & SIRQ_PWRBTN_REL)); + input_sync(input); + } + + return IRQ_HANDLED; +} + +static int chtdc_ti_pwrbtn_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent); + struct input_dev *input; + int irq, err; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + input->name = pdev->name; + input->phys = "power-button/input0"; + input->id.bustype = BUS_HOST; + input_set_capability(input, EV_KEY, KEY_POWER); + err = input_register_device(input); + if (err) + return err; + + dev_set_drvdata(dev, pmic->regmap); + + err = devm_request_threaded_irq(dev, irq, NULL, + chtdc_ti_pwrbtn_interrupt, + 0, KBUILD_MODNAME, input); + if (err) + return err; + + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, irq); + return 0; +} + +static int chtdc_ti_pwrbtn_remove(struct platform_device *pdev) +{ + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + return 0; +} + +static const struct platform_device_id chtdc_ti_pwrbtn_id_table[] = { + { .name = "chtdc_ti_pwrbtn" }, + {}, +}; +MODULE_DEVICE_TABLE(platform, chtdc_ti_pwrbtn_id_table); + +static struct platform_driver chtdc_ti_pwrbtn_driver = { + .driver = { + .name = KBUILD_MODNAME, + }, + .probe = chtdc_ti_pwrbtn_probe, + .remove = chtdc_ti_pwrbtn_remove, + .id_table = chtdc_ti_pwrbtn_id_table, +}; +module_platform_driver(chtdc_ti_pwrbtn_driver); + +MODULE_DESCRIPTION("Power-button driver for Dollar Cove TI PMIC"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2448f44f31625610ddeafc9c7642da8a78d93c7b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 22 Nov 2017 16:50:33 +0100 Subject: platform/x86: intel_int0002_vgpio: Remove IRQF_NO_THREAD irq flag Remove the IRQF_NO_THREAD irq flag, there is no need for it and it breaks irq-sharing with the "acpi" irq when passing "threadirqs" on the kernel cmdline, as the acpi/osl.c code does not pass IRQF_NO_THREAD. Signed-off-by: Hans de Goede Reported-by: Oleksandr Natalenko Tested-by: Oleksandr Natalenko Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_int0002_vgpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c index f7b67e898abc..a473dc51b18d 100644 --- a/drivers/platform/x86/intel_int0002_vgpio.c +++ b/drivers/platform/x86/intel_int0002_vgpio.c @@ -180,7 +180,7 @@ static int int0002_probe(struct platform_device *pdev) * to gpiochip_set_chained_irqchip, because the irq is shared. */ ret = devm_request_irq(dev, irq, int0002_irq, - IRQF_SHARED | IRQF_NO_THREAD, "INT0002", chip); + IRQF_SHARED, "INT0002", chip); if (ret) { dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret); return ret; -- cgit v1.2.3 From 9c916549c0345a054431abdc4f2d9ba48e856f80 Mon Sep 17 00:00:00 2001 From: "Chakravarty, Souvik K" Date: Fri, 24 Nov 2017 19:04:41 +0530 Subject: platform/x86: intel_pmc_ipc: Add read64 API Add intel_pmc_gcr_read64() API for reading from 64-bit GCR registers. This API will be called from intel_telemetry. Update description of intel_pmc_gcr_read(). Signed-off-by: Souvik Kumar Chakravarty Signed-off-by: Andy Shevchenko --- arch/x86/include/asm/intel_pmc_ipc.h | 6 ++++++ drivers/platform/x86/intel_pmc_ipc.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h index 528ed4be4393..9e7adcdbe031 100644 --- a/arch/x86/include/asm/intel_pmc_ipc.h +++ b/arch/x86/include/asm/intel_pmc_ipc.h @@ -38,6 +38,7 @@ int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, u32 outlen); int intel_pmc_s0ix_counter_read(u64 *data); int intel_pmc_gcr_read(u32 offset, u32 *data); +int intel_pmc_gcr_read64(u32 offset, u64 *data); int intel_pmc_gcr_write(u32 offset, u32 data); int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val); @@ -70,6 +71,11 @@ static inline int intel_pmc_gcr_read(u32 offset, u32 *data) return -EINVAL; } +static inline int intel_pmc_gcr_read64(u32 offset, u64 *data) +{ + return -EINVAL; +} + static inline int intel_pmc_gcr_write(u32 offset, u32 data) { return -EINVAL; diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index e03fa31446ca..e7edc8c63936 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -215,11 +215,11 @@ static inline int is_gcr_valid(u32 offset) } /** - * intel_pmc_gcr_read() - Read PMC GCR register + * intel_pmc_gcr_read() - Read a 32-bit PMC GCR register * @offset: offset of GCR register from GCR address base * @data: data pointer for storing the register output * - * Reads the PMC GCR register of given offset. + * Reads the 32-bit PMC GCR register at given offset. * * Return: negative value on error or 0 on success. */ @@ -243,6 +243,35 @@ int intel_pmc_gcr_read(u32 offset, u32 *data) } EXPORT_SYMBOL_GPL(intel_pmc_gcr_read); +/** + * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register + * @offset: offset of GCR register from GCR address base + * @data: data pointer for storing the register output + * + * Reads the 64-bit PMC GCR register at given offset. + * + * Return: negative value on error or 0 on success. + */ +int intel_pmc_gcr_read64(u32 offset, u64 *data) +{ + int ret; + + spin_lock(&ipcdev.gcr_lock); + + ret = is_gcr_valid(offset); + if (ret < 0) { + spin_unlock(&ipcdev.gcr_lock); + return ret; + } + + *data = readq(ipcdev.gcr_mem_base + offset); + + spin_unlock(&ipcdev.gcr_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64); + /** * intel_pmc_gcr_write() - Write PMC GCR register * @offset: offset of GCR register from GCR address base -- cgit v1.2.3 From 0946a05fd220a24e7f3843011ef696578d02aa29 Mon Sep 17 00:00:00 2001 From: "Chakravarty, Souvik K" Date: Fri, 24 Nov 2017 19:04:42 +0530 Subject: platform/x86: intel_telemetry: Fix suspend stats Suspend stats are not reported consistently due to a limitation in the PMC firmware. This limitation causes a delay in updating the s0ix counters and residencies in the telemetry log upon s0ix exit. As a consequence, reading these counters from the suspend-exit notifier may result in zero read. This patch fixes this issue by cross-verifying the s0ix residencies from the GCR TELEM registers in case the counters are not incremented in the telemetry log after suspend. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=197833 Reported-and-tested-by: Rajneesh Bhardwaj Signed-off-by: Souvik Kumar Chakravarty Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_telemetry_debugfs.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c index 4249e8267bbc..5bc4f208cc8b 100644 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ b/drivers/platform/x86/intel_telemetry_debugfs.c @@ -890,6 +890,31 @@ static int pm_suspend_exit_cb(void) goto out; } + /* + * Due to some design limitations in the firmware, sometimes the + * counters do not get updated by the time we reach here. As a + * workaround, we try to see if this was a genuine case of sleep + * failure or not by cross-checking from PMC GCR registers directly. + */ + if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp && + suspend_deep_ctr_exit == suspend_deep_ctr_temp) { + ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_SHLW_S0IX_REG, + &suspend_shlw_res_exit); + if (ret < 0) + goto out; + + ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_DEEP_S0IX_REG, + &suspend_deep_res_exit); + if (ret < 0) + goto out; + + if (suspend_shlw_res_exit > suspend_shlw_res_temp) + suspend_shlw_ctr_exit++; + + if (suspend_deep_res_exit > suspend_deep_res_temp) + suspend_deep_ctr_exit++; + } + suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp; suspend_deep_ctr_exit -= suspend_deep_ctr_temp; suspend_shlw_res_exit -= suspend_shlw_res_temp; -- cgit v1.2.3 From ffd623d4c5315a9767a5ee183159baf7295219a6 Mon Sep 17 00:00:00 2001 From: "Chakravarty, Souvik K" Date: Fri, 24 Nov 2017 19:04:43 +0530 Subject: platform/x86: intel_telemetry: Improve S0ix logs Suspend with shallow wakes is not a useful parameter since the phenomena does not exist on deployed devices and is only a parameter of use during device power-on phase. The field always reads zero. Additionally there are other easier methods to detect it, e.g., if the S0ix counter increments by more than one during suspend. Hence the field is superfluous and can be removed. This patch also slightly renames the S0ix total field for better viewability. Signed-off-by: Souvik Kumar Chakravarty Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_telemetry_debugfs.c | 45 ++++---------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c index 5bc4f208cc8b..97aae982d2bd 100644 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ b/drivers/platform/x86/intel_telemetry_debugfs.c @@ -98,10 +98,6 @@ static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp; static u64 suspend_shlw_res_temp, suspend_deep_res_temp; struct telemetry_susp_stats { - u32 shlw_swake_ctr; - u32 deep_swake_ctr; - u64 shlw_swake_res; - u64 deep_swake_res; u32 shlw_ctr; u32 deep_ctr; u64 shlw_res; @@ -598,19 +594,15 @@ static int telem_soc_states_show(struct seq_file *s, void *unused) seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n", s0ix_shlw_ctr - - conf->suspend_stats.shlw_ctr - - conf->suspend_stats.shlw_swake_ctr, + conf->suspend_stats.shlw_ctr, (u64)((s0ix_shlw_res - - conf->suspend_stats.shlw_res - - conf->suspend_stats.shlw_swake_res)*10/192)); + conf->suspend_stats.shlw_res)*10/192)); seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n", s0ix_deep_ctr - - conf->suspend_stats.deep_ctr - - conf->suspend_stats.deep_swake_ctr, + conf->suspend_stats.deep_ctr, (u64)((s0ix_deep_res - - conf->suspend_stats.deep_res - - conf->suspend_stats.deep_swake_res)*10/192)); + conf->suspend_stats.deep_res)*10/192)); seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n", conf->suspend_stats.shlw_ctr, @@ -620,13 +612,7 @@ static int telem_soc_states_show(struct seq_file *s, void *unused) conf->suspend_stats.deep_ctr, (u64)(conf->suspend_stats.deep_res*10)/192); - seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n", - conf->suspend_stats.shlw_swake_ctr + - conf->suspend_stats.deep_swake_ctr, - (u64)((conf->suspend_stats.shlw_swake_res + - conf->suspend_stats.deep_swake_res)*10/192)); - - seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr, + seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr, (u64)(s0ix_total_res*10/192)); seq_puts(s, "\n-------------------------------------------------\n"); seq_puts(s, "\t\tDEVICE STATES\n"); @@ -920,23 +906,15 @@ static int pm_suspend_exit_cb(void) suspend_shlw_res_exit -= suspend_shlw_res_temp; suspend_deep_res_exit -= suspend_deep_res_temp; - if (suspend_shlw_ctr_exit == 1) { + if (suspend_shlw_ctr_exit != 0) { conf->suspend_stats.shlw_ctr += suspend_shlw_ctr_exit; conf->suspend_stats.shlw_res += suspend_shlw_res_exit; } - /* Shallow Wakes Case */ - else if (suspend_shlw_ctr_exit > 1) { - conf->suspend_stats.shlw_swake_ctr += - suspend_shlw_ctr_exit; - - conf->suspend_stats.shlw_swake_res += - suspend_shlw_res_exit; - } - if (suspend_deep_ctr_exit == 1) { + if (suspend_deep_ctr_exit != 0) { conf->suspend_stats.deep_ctr += suspend_deep_ctr_exit; @@ -944,15 +922,6 @@ static int pm_suspend_exit_cb(void) suspend_deep_res_exit; } - /* Shallow Wakes Case */ - else if (suspend_deep_ctr_exit > 1) { - conf->suspend_stats.deep_swake_ctr += - suspend_deep_ctr_exit; - - conf->suspend_stats.deep_swake_res += - suspend_deep_res_exit; - } - out: suspend_prep_ok = 0; return NOTIFY_OK; -- cgit v1.2.3 From c622cbe5d11657a12c473356826017fed0c7669e Mon Sep 17 00:00:00 2001 From: "Chakravarty, Souvik K" Date: Fri, 24 Nov 2017 19:04:44 +0530 Subject: platform/x86: intel_telemetry: Remove redundancies This patch removes unnecessary header files and newlines. It also fixes some alignment issues. Signed-off-by: Souvik Kumar Chakravarty Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_telemetry_debugfs.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c index 97aae982d2bd..ffd0474b0531 100644 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ b/drivers/platform/x86/intel_telemetry_debugfs.c @@ -23,7 +23,6 @@ */ #include #include -#include #include #include #include @@ -32,11 +31,10 @@ #include #include #include -#include #include -#define DRIVER_NAME "telemetry_soc_debugfs" -#define DRIVER_VERSION "1.0.0" +#define DRIVER_NAME "telemetry_soc_debugfs" +#define DRIVER_VERSION "1.0.0" /* ApolloLake SoC Event-IDs */ #define TELEM_APL_PSS_PSTATES_ID 0x2802 @@ -246,7 +244,6 @@ static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = { {"PRTC", 25}, }; - struct telemetry_debugfs_conf { struct telemetry_susp_stats suspend_stats; struct dentry *telemetry_dbg_dir; @@ -381,7 +378,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused) TELEM_APL_MASK_PCS_STATE; } - TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id, conf->pss_idle_evts - 1, pss_idle, evtlog[index].telem_evtlog, @@ -401,7 +397,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused) conf->pcs_s0ix_blkd_data, TELEM_MASK_BYTE); - TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id, conf->pss_wakeup_evts, pss_s0ix_wakeup, @@ -494,7 +489,6 @@ static const struct file_operations telem_pss_ops = { .release = single_release, }; - static int telem_ioss_states_show(struct seq_file *s, void *unused) { struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; @@ -613,7 +607,7 @@ static int telem_soc_states_show(struct seq_file *s, void *unused) (u64)(conf->suspend_stats.deep_res*10)/192); seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr, - (u64)(s0ix_total_res*10/192)); + (u64)(s0ix_total_res*10/192)); seq_puts(s, "\n-------------------------------------------------\n"); seq_puts(s, "\t\tDEVICE STATES\n"); seq_puts(s, "-------------------------------------------------\n"); @@ -758,7 +752,6 @@ static const struct file_operations telem_pss_trc_verb_ops = { .release = single_release, }; - static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused) { u32 verbosity; -- cgit v1.2.3 From e20a8e771dc66361aecd8e23eef3de6048604ac2 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Thu, 2 Nov 2017 21:25:24 +0100 Subject: platform/x86: dell-laptop: Fix keyboard max lighting for Dell Latitude E6410 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This machine reports number of keyboard backlight led levels, instead of value of the last led level index. Therefore max_brightness properly needs to be subtracted by 1 to match led max_brightness API. Signed-off-by: Pali Rohár Reported-by: Gabriel M. Elder Link: https://bugzilla.kernel.org/show_bug.cgi?id=196913 Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-laptop.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index bf897b1832b1..cd4725e7e0b5 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -37,6 +37,7 @@ struct quirk_entry { u8 touchpad_led; + u8 kbd_led_levels_off_1; int needs_kbd_timeouts; /* @@ -67,6 +68,10 @@ static struct quirk_entry quirk_dell_xps13_9333 = { .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, }; +static struct quirk_entry quirk_dell_latitude_e6410 = { + .kbd_led_levels_off_1 = 1, +}; + static struct platform_driver platform_driver = { .driver = { .name = "dell-laptop", @@ -269,6 +274,15 @@ static const struct dmi_system_id dell_quirks[] __initconst = { }, .driver_data = &quirk_dell_xps13_9333, }, + { + .callback = dmi_matched, + .ident = "Dell Latitude E6410", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6410"), + }, + .driver_data = &quirk_dell_latitude_e6410, + }, { } }; @@ -1149,6 +1163,9 @@ static int kbd_get_info(struct kbd_info *info) units = (buffer->output[2] >> 8) & 0xFF; info->levels = (buffer->output[2] >> 16) & 0xFF; + if (quirks && quirks->kbd_led_levels_off_1 && info->levels) + info->levels--; + if (units & BIT(0)) info->seconds = (buffer->output[3] >> 0) & 0xFF; if (units & BIT(1)) -- cgit v1.2.3 From 1e478ac1989314798c3db7a91c44f52854402db6 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sat, 11 Nov 2017 23:20:23 +0100 Subject: platform/x86: dell-laptop: Use bool in struct quirk_entry for true/false fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In struct quirk_entry some boolean fields used int, some u8 type. Change them all to bool type. Signed-off-by: Pali Rohár Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-laptop.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index cd4725e7e0b5..629d96048b63 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -36,10 +36,10 @@ #include "dell-smbios.h" struct quirk_entry { - u8 touchpad_led; - u8 kbd_led_levels_off_1; + bool touchpad_led; + bool kbd_led_levels_off_1; - int needs_kbd_timeouts; + bool needs_kbd_timeouts; /* * Ordered list of timeouts expressed in seconds. * The list must end with -1 @@ -50,7 +50,7 @@ struct quirk_entry { static struct quirk_entry *quirks; static struct quirk_entry quirk_dell_vostro_v130 = { - .touchpad_led = 1, + .touchpad_led = true, }; static int __init dmi_matched(const struct dmi_system_id *dmi) @@ -64,12 +64,12 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) * is used then BIOS silently set timeout to 0 without any error message. */ static struct quirk_entry quirk_dell_xps13_9333 = { - .needs_kbd_timeouts = 1, + .needs_kbd_timeouts = true, .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, }; static struct quirk_entry quirk_dell_latitude_e6410 = { - .kbd_led_levels_off_1 = 1, + .kbd_led_levels_off_1 = true, }; static struct platform_driver platform_driver = { -- cgit v1.2.3 From 1c828496228deb7a080362bbdf8e70c50bc924b4 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Thu, 9 Nov 2017 23:44:32 +0100 Subject: platform/x86: intel-vbtn: support SW_TABLET_MODE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Event code 0xcc is emitted by several convertibles (Dell XPS 12 9Q33 BIOS A8, Dell XPS 13 2in1 9365, HP Spectre x360, Lenovo Thinkpad Helix) when entering tablet mode, and 0xcd on return to laptop mode. Signed-off-by: Stefan Brüns Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-vbtn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 58c5ff36523a..ae55be91a64b 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -42,6 +42,8 @@ static const struct key_entry intel_vbtn_keymap[] = { { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ + { KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */ + { KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */ { KE_END }, }; -- cgit v1.2.3 From 95f38fd46cc5e45a0d5224f486e805d17ea3d93f Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Thu, 9 Nov 2017 23:44:33 +0100 Subject: platform/x86: intel-vbtn: Support separate press/release events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently all key events use autorelease, but this forbids use as a modifier key. As all event codes come in even/odd pairs, we can lookup the key type (KE_KEY/KE_IGNORE) for the key up event corresponding to the currently handled key down event. If the key up is ignored, we keep setting the autorelease flag for the key down. Signed-off-by: Stefan Brüns Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-vbtn.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index ae55be91a64b..e3f6375af85c 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -76,14 +76,27 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) { struct platform_device *device = context; struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); + const struct key_entry *ke_rel; + bool autorelease; if (priv->wakeup_mode) { if (sparse_keymap_entry_from_scancode(priv->input_dev, event)) { pm_wakeup_hard_event(&device->dev); return; } - } else if (sparse_keymap_report_event(priv->input_dev, event, 1, true)) { - return; + } else { + /* Use the fact press/release come in even/odd pairs */ + if ((event & 1) && sparse_keymap_report_event(priv->input_dev, + event, 0, false)) + return; + + ke_rel = sparse_keymap_entry_from_scancode(priv->input_dev, + event | 1); + autorelease = !ke_rel || ke_rel->type == KE_IGNORE; + + if (sparse_keymap_report_event(priv->input_dev, event, 1, + autorelease)) + return; } dev_dbg(&device->dev, "unknown event index 0x%x\n", event); } -- cgit v1.2.3 From 4982327ff6755377a8a66e84113f496f3a6c53bc Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Thu, 9 Nov 2017 23:44:34 +0100 Subject: Input: add KEY_ROTATE_LOCK_TOGGLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The key has the same use as the SW_ROTATE_LOCK, but is used on devices where the state is not tracked by the hardware but has to be handled in software. Signed-off-by: Stefan Brüns Signed-off-by: Darren Hart (VMware) --- include/uapi/linux/input-event-codes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 061fa62958a2..53fbae27b280 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -594,6 +594,7 @@ #define BTN_DPAD_RIGHT 0x223 #define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ +#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */ #define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ #define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ -- cgit v1.2.3 From 3d5d95d316b6fb3863a633293beb4e1e69dc7693 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Thu, 9 Nov 2017 23:44:35 +0100 Subject: platform/x86: intel-vbtn: support KEY_ROTATE_LOCK_TOGGLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rotate Lock button event is emitted on the XPS 12 (BIOS A8, but not on BIOS A2). Signed-off-by: Stefan Brüns Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-vbtn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index e3f6375af85c..a484bcc6393b 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -42,6 +42,8 @@ static const struct key_entry intel_vbtn_keymap[] = { { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ + { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */ + { KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */ { KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */ { KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */ { KE_END }, -- cgit v1.2.3 From 9678d0ef77d71a25e2194606238d9cb5b544c0f3 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Thu, 9 Nov 2017 23:44:36 +0100 Subject: platform/x86: intel-vbtn: support panel front button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Lenovo Helix 2 and Dell XPS 12 (9Q33) have an extra button on the front showing a 'Windows' logo, both reporting event codes 0xC2/0xC3 on press/release. On the Dell, both press/release are distinct events while on the Helix 2 both events are generated on release. Tested on XPS 12, for info on the Helix 2 see: https://www.spinics.net/lists/ibm-acpi-devel/msg03982.html Signed-off-by: Stefan Brüns Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-vbtn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index a484bcc6393b..0861efe490d0 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -38,6 +38,8 @@ static const struct acpi_device_id intel_vbtn_ids[] = { static const struct key_entry intel_vbtn_keymap[] = { { KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */ { KE_IGNORE, 0xC1, { KEY_POWER } }, /* power key release */ + { KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* 'Windows' key press */ + { KE_KEY, 0xC3, { KEY_LEFTMETA } }, /* 'Windows' key release */ { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */ { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ -- cgit v1.2.3 From 1c3fdf125ef416227e43fdedf6b5097c41e8c467 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Fri, 8 Dec 2017 14:57:54 -0800 Subject: platform/x86: intel-vbtn: Simplify autorelease logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new notify_handler logic determining if autorelease should be used or not is a bit awkward, and can result in more than one call to sparse_keymap_report_event for the same event (scancode). The nesting and long lines also made it difficult to read. Simplify the logic by eliminating a level of nesting with a goto and always calculate autorelease and val so we can make a single call to sparse_keymap_report_event. Signed-off-by: Darren Hart (VMware) Reviewed-by: Stefan Brüns Tested-by: Stefan Brüns Cc: AceLan Kao --- drivers/platform/x86/intel-vbtn.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 0861efe490d0..5fc4315f7382 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -80,6 +80,7 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) { struct platform_device *device = context; struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); + unsigned int val = !(event & 1); /* Even=press, Odd=release */ const struct key_entry *ke_rel; bool autorelease; @@ -88,20 +89,20 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) pm_wakeup_hard_event(&device->dev); return; } - } else { - /* Use the fact press/release come in even/odd pairs */ - if ((event & 1) && sparse_keymap_report_event(priv->input_dev, - event, 0, false)) - return; + goto out_unknown; + } - ke_rel = sparse_keymap_entry_from_scancode(priv->input_dev, - event | 1); - autorelease = !ke_rel || ke_rel->type == KE_IGNORE; + /* + * Even press events are autorelease if there is no corresponding odd + * release event, or if the odd event is KE_IGNORE. + */ + ke_rel = sparse_keymap_entry_from_scancode(priv->input_dev, event | 1); + autorelease = val && (!ke_rel || ke_rel->type == KE_IGNORE); - if (sparse_keymap_report_event(priv->input_dev, event, 1, - autorelease)) - return; - } + if (sparse_keymap_report_event(priv->input_dev, event, val, autorelease)) + return; + +out_unknown: dev_dbg(&device->dev, "unknown event index 0x%x\n", event); } -- cgit v1.2.3 From ba3a33876e92e000d7aa37eaf6581a7333c58560 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Sat, 2 Dec 2017 21:45:31 +0800 Subject: platform/x86: ideapad-laptop: Remove unnecessary else Address the following checkpatch warning by removing unnecessary else blocks: WARNING: else is not generally useful after a break or return Signed-off-by: Jiaxun Yang Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/ideapad-laptop.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 53ab4e0f8962..9f2a4bc58df0 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -124,10 +124,10 @@ static int read_method_int(acpi_handle handle, const char *method, int *val) if (ACPI_FAILURE(status)) { *val = -1; return -1; - } else { - *val = result; - return 0; } + *val = result; + return 0; + } static int method_gbmd(acpi_handle handle, unsigned long *ret) @@ -164,10 +164,10 @@ static int method_vpcr(acpi_handle handle, int cmd, int *ret) if (ACPI_FAILURE(status)) { *ret = -1; return -1; - } else { - *ret = result; - return 0; } + *ret = result; + return 0; + } static int method_vpcw(acpi_handle handle, int cmd, int data) -- cgit v1.2.3 From f1395edbcec81dafa1c5fff3ef9c0ab04c6fe78d Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Sat, 2 Dec 2017 21:45:32 +0800 Subject: platform/x86: ideapad-laptop: Use __func__ instead of write_ec_cmd in pr_err Address the following checkpatch warning by using __func__ instead: WARNING: Prefer using '"%s...", __func__' to using 'write_ec_cmd', this function's name, in a string Signed-off-by: Jiaxun Yang Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/ideapad-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 9f2a4bc58df0..37a88938bbaa 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -231,7 +231,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) if (val == 0) return 0; } - pr_err("timeout in write_ec_cmd\n"); + pr_err("timeout in %s\n", __func__); return -1; } -- cgit v1.2.3 From ae7c8cba32218592657130b34dc28f4d82aa755f Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Sat, 2 Dec 2017 21:45:34 +0800 Subject: platform/x86: ideapad-laptop: add lenovo RESCUER R720-15IKBN to no_hw_rfkill_list This model does not have a hardware rfkill switch, add it to the no_hw_rfkill_list to prevent the radio always being blocked. Reported-by: Roger Jargoyhen Signed-off-by: Jiaxun Yang Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 37a88938bbaa..5ab638d4d243 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -963,6 +963,13 @@ static void ideapad_wmi_notify(u32 value, void *context) * report all radios as hardware-blocked. */ static const struct dmi_system_id no_hw_rfkill_list[] = { + { + .ident = "Lenovo RESCUER R720-15IKBN", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "80WW"), + }, + }, { .ident = "Lenovo G40-30", .matches = { -- cgit v1.2.3 From 960652046899ff2fb4bd37e1e38836e3a67c27bf Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Fri, 8 Dec 2017 15:52:49 -0800 Subject: MAINTAINERS: Update tree for platform-drivers-x86 Update the tree listed for X86 PLATFORM DRIVERS to its new top level reposority at infradead. The old one is an alias to the new one, but we prefer to remove the "user/dvhart" from the URL. Signed-off-by: Darren Hart (VMware) --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index aa71ab52fd76..825acf165c2d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14863,7 +14863,7 @@ X86 PLATFORM DRIVERS M: Darren Hart M: Andy Shevchenko L: platform-driver-x86@vger.kernel.org -T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git +T: git git://git.infradead.org/linux-platform-drivers-x86.git S: Maintained F: drivers/platform/x86/ F: drivers/platform/olpc/ -- cgit v1.2.3 From 9cd5cf3710a04e6bab8efac08c241bfce2795c02 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 4 Dec 2017 10:26:17 +1000 Subject: platform/x86: asus-wireless: send an EV_SYN/SYN_REPORT between state changes Sending the switch state change twice within the same frame is invalid evdev protocol and only works if the client handles keys immediately as well. Processing events immediately is incorrect, it forces a fake order of events that does not exist on the device. Recent versions of libinput changed to only process the device state and SYN_REPORT time, so now the key event is lost. https://bugs.freedesktop.org/show_bug.cgi?id=104041 Signed-off-by: Peter Hutterer Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/asus-wireless.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index f3796164329e..d4aeac3477f5 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -118,6 +118,7 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event) return; } input_report_key(data->idev, KEY_RFKILL, 1); + input_sync(data->idev); input_report_key(data->idev, KEY_RFKILL, 0); input_sync(data->idev); } -- cgit v1.2.3 From 91c73e809233e8f93278458b2818fd577c3deb02 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 11 Dec 2017 13:54:27 +0300 Subject: platform/x86: dell-wmi: check for kmalloc() errors This allocation won't fail in the current kernel because it's small but not checking for kmalloc() failures introduces static checker warnings so let's fix it. Signed-off-by: Dan Carpenter Reviewed-by: Mario Limonciello Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-wmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 39d2f4518483..fb25b20df316 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -639,6 +639,8 @@ static int dell_wmi_events_set_enabled(bool enable) int ret; buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL); + if (!buffer) + return -ENOMEM; buffer->cmd_class = CLASS_INFO; buffer->cmd_select = SELECT_APP_REGISTRATION; buffer->input[0] = 0x10000; -- cgit v1.2.3 From c454a99d4ce1cebb5b4dc742309187c05b4b17ee Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 7 Dec 2017 11:40:23 +0800 Subject: intel-hid: add a DMI quirk to support Wacom MobileStudio Pro HEBC method reports capabilities of 5 button array but Wacom MobileStudio Pro does not have this control method. A DMI quirk was created to enable 5 button array for this system. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=197991 Reported-by: Jason Gerecke Signed-off-by: Alex Hung Tested-by: Jason Gerecke Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-hid.c | 41 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index f470279c4c10..d1a01311c1a2 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -25,6 +25,7 @@ #include #include #include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alex Hung"); @@ -73,6 +74,24 @@ static const struct key_entry intel_array_keymap[] = { { KE_END }, }; +static const struct dmi_system_id button_array_table[] = { + { + .ident = "Wacom MobileStudio Pro 13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"), + DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 13"), + }, + }, + { + .ident = "Wacom MobileStudio Pro 16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"), + DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"), + }, + }, + { } +}; + struct intel_hid_priv { struct input_dev *input_dev; struct input_dev *array; @@ -263,10 +282,27 @@ wakeup: ev_index); } +static bool button_array_present(struct platform_device *device) +{ + acpi_handle handle = ACPI_HANDLE(&device->dev); + unsigned long long event_cap; + acpi_status status; + bool supported = false; + + status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); + if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) + supported = true; + + if (dmi_check_system(button_array_table)) + supported = true; + + return supported; +} + static int intel_hid_probe(struct platform_device *device) { acpi_handle handle = ACPI_HANDLE(&device->dev); - unsigned long long event_cap, mode; + unsigned long long mode; struct intel_hid_priv *priv; acpi_status status; int err; @@ -299,8 +335,7 @@ static int intel_hid_probe(struct platform_device *device) } /* Setup 5 button array */ - status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); - if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) { + if (button_array_present(device)) { dev_info(&device->dev, "platform supports 5 button array\n"); err = intel_button_array_input_setup(device); if (err) -- cgit v1.2.3 From f4c12d4dee085dbb3e205e401539158588667b46 Mon Sep 17 00:00:00 2001 From: Bernhard Übelacker Date: Sun, 26 Nov 2017 19:32:58 +0100 Subject: platform/x86: silead_dmi: Add touchscreen info for SurfTab twin 10.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add touchscreen info for the Trekstor SurfTab twin 10.1 ST10432-8 tablet. Resolution based on output of evemu-record. Signed-off-by: Bernhard Übelacker Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/silead_dmi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 266535c2a72f..9a3da53202cb 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -67,6 +67,21 @@ static const struct silead_ts_dmi_data dexp_ursus_7w_data = { .properties = dexp_ursus_7w_props, }; +static const struct property_entry surftab_twin_10_1_st10432_8_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1900), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3670-surftab-twin-10-1-st10432-8.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct silead_ts_dmi_data surftab_twin_10_1_st10432_8_data = { + .acpi_name = "MSSL1680:00", + .properties = surftab_twin_10_1_st10432_8_props, +}; + static const struct property_entry surftab_wintron70_st70416_6_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 884), PROPERTY_ENTRY_U32("touchscreen-size-y", 632), @@ -198,6 +213,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "7W"), }, }, + { + /* TrekStor SurfTab twin 10.1 ST10432-8 */ + .driver_data = (void *)&surftab_twin_10_1_st10432_8_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"), + }, + }, { /* Trekstor Surftab Wintron 7.0 ST70416-6 */ .driver_data = (void *)&surftab_wintron70_st70416_6_data, -- cgit v1.2.3 From 170e9a53be728716dae9a9b426b6195355e5cb82 Mon Sep 17 00:00:00 2001 From: Nerijus Baliunas Date: Mon, 11 Dec 2017 00:02:13 +0200 Subject: platform/x86: silead_dmi: Add support for the Onda oBook 20 Plus tablet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add touchscreen platform data for the Onda oBook 20 Plus tablet. Firmware for this is available here: https://github.com/onitake/gsl-firmware/blob/master/firmware/linux/silead/gsl3676-onda-obook-20-plus.fw Signed-off-by: Nerijus Baliūnas Acked-by: Hans de Goede [andy: massaged title and wrote commit message] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/silead_dmi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 9a3da53202cb..89bd924fb8dc 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -186,6 +186,23 @@ static const struct silead_ts_dmi_data digma_citi_e200_data = { .properties = digma_citi_e200_props, }; +static const struct property_entry onda_obook_20_plus_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct silead_ts_dmi_data onda_obook_20_plus_data = { + .acpi_name = "MSSL1680:00", + .properties = onda_obook_20_plus_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -294,6 +311,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), }, }, + { + /* Onda oBook 20 Plus */ + .driver_data = (void *)&onda_obook_20_plus_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ONDA"), + DMI_MATCH(DMI_PRODUCT_NAME, "OBOOK 20 PLUS"), + }, + }, { }, }; -- cgit v1.2.3 From d2d541e8397c5db65139a17e32df6acd372f04df Mon Sep 17 00:00:00 2001 From: Maruyama Shohei Date: Wed, 20 Dec 2017 11:30:08 +0100 Subject: platform/x86: silead_dmi: add entry for Chuwi Hi8 tablet This commit add entry for Chuwi Hi8 tablet. Signed-off-by: Shohei Maruyama Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/silead_dmi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 89bd924fb8dc..21fdce159877 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -203,6 +203,20 @@ static const struct silead_ts_dmi_data onda_obook_20_plus_data = { .properties = onda_obook_20_plus_props, }; +static const struct property_entry chuwi_hi8_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), + { } +}; + +static const struct silead_ts_dmi_data chuwi_hi8_data = { + .acpi_name = "MSSL0001:00", + .properties = chuwi_hi8_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -319,6 +333,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "OBOOK 20 PLUS"), }, }, + { + /* Chuwi Hi8 */ + .driver_data = (void *)&chuwi_hi8_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), + DMI_MATCH(DMI_PRODUCT_NAME, "S806"), + }, + }, { }, }; -- cgit v1.2.3 From f1905b980f27e40ef28667949667e156e96611fb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 Dec 2017 11:30:09 +0100 Subject: platform/x86: silead_dmi: Add entry for the Chuwi Vi8 tablet Add touchscreen platform data for the Chuwi Vi8 tablet. Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/silead_dmi.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 21fdce159877..09b589fb79d4 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -217,6 +217,21 @@ static const struct silead_ts_dmi_data chuwi_hi8_data = { .properties = chuwi_hi8_props, }; +static const struct property_entry chuwi_vi8_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1724), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct silead_ts_dmi_data chuwi_vi8_data = { + .acpi_name = "MSSL1680:00", + .properties = chuwi_vi8_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -341,6 +356,15 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "S806"), }, }, + { + /* Chuwi Vi8 (CWI506) */ + .driver_data = (void *)&chuwi_vi8_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "i86"), + DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), + }, + }, { }, }; -- cgit v1.2.3 From 1ea74a560c7b5bf94fe41818f04dedcefcd17b55 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Dec 2017 16:29:07 +0200 Subject: platform/x86: pmc_atom: introduce DEFINE_SHOW_ATTRIBUTE() macro This macro deduplicates a lot of similar code in the pmc_atom.c module. Targeting to be moved to seq_file.h eventually. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/pmc_atom.c | 56 +++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index 77bac859342d..4b3c37b6288c 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -208,6 +208,20 @@ static const struct pmc_data cht_data = { .clks = cht_clks, }; +#define DEFINE_SHOW_ATTRIBUTE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __name ## _show, inode->i_private); \ +} \ + \ +static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) { return readl(pmc->regmap + reg_offset); @@ -309,17 +323,7 @@ static int pmc_dev_state_show(struct seq_file *s, void *unused) return 0; } -static int pmc_dev_state_open(struct inode *inode, struct file *file) -{ - return single_open(file, pmc_dev_state_show, inode->i_private); -} - -static const struct file_operations pmc_dev_state_ops = { - .open = pmc_dev_state_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(pmc_dev_state); static int pmc_pss_state_show(struct seq_file *s, void *unused) { @@ -336,17 +340,7 @@ static int pmc_pss_state_show(struct seq_file *s, void *unused) return 0; } -static int pmc_pss_state_open(struct inode *inode, struct file *file) -{ - return single_open(file, pmc_pss_state_show, inode->i_private); -} - -static const struct file_operations pmc_pss_state_ops = { - .open = pmc_pss_state_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(pmc_pss_state); static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) { @@ -367,17 +361,7 @@ static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) return 0; } -static int pmc_sleep_tmr_open(struct inode *inode, struct file *file) -{ - return single_open(file, pmc_sleep_tmr_show, inode->i_private); -} - -static const struct file_operations pmc_sleep_tmr_ops = { - .open = pmc_sleep_tmr_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr); static void pmc_dbgfs_unregister(struct pmc_dev *pmc) { @@ -395,17 +379,17 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc) pmc->dbgfs_dir = dir; f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO, - dir, pmc, &pmc_dev_state_ops); + dir, pmc, &pmc_dev_state_fops); if (!f) goto err; f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO, - dir, pmc, &pmc_pss_state_ops); + dir, pmc, &pmc_pss_state_fops); if (!f) goto err; f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, - dir, pmc, &pmc_sleep_tmr_ops); + dir, pmc, &pmc_sleep_tmr_fops); if (!f) goto err; -- cgit v1.2.3 From 842b854459462a6065d3595f8485601800bbf5d3 Mon Sep 17 00:00:00 2001 From: "Shih-Yuan Lee (FourDollars)" Date: Tue, 19 Dec 2017 17:39:49 +0800 Subject: platform/x86: dell-wmi: Add an event created by Dell Latitude 5495 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Dell Latitude 5495 has the mic mute key. Signed-off-by: Shih-Yuan Lee (FourDollars) Reviewed-by: Pali Rohár Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-wmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index fb25b20df316..2c9927430d85 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -261,6 +261,9 @@ static const u16 bios_to_linux_keycode[256] = { * override them. */ static const struct key_entry dell_wmi_keymap_type_0010[] = { + /* Mic mute */ + { KE_KEY, 0x150, { KEY_MICMUTE } }, + /* Fn-lock */ { KE_IGNORE, 0x151, { KEY_RESERVED } }, -- cgit v1.2.3 From 064cbc4f6a1e910771e6c29cb819b6ee9eb881fc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Nov 2017 14:32:39 +0100 Subject: platform/x86: samsung-laptop: Grammar s/are can/can/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Andy Shevchenko --- Documentation/ABI/testing/sysfs-driver-samsung-laptop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop index 63c1ad0212fc..34d3a3359cf4 100644 --- a/Documentation/ABI/testing/sysfs-driver-samsung-laptop +++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop @@ -3,7 +3,7 @@ Date: January 1, 2010 KernelVersion: 2.6.33 Contact: Greg Kroah-Hartman Description: Some Samsung laptops have different "performance levels" - that are can be modified by a function key, and by this + that can be modified by a function key, and by this sysfs file. These values don't always make a whole lot of sense, but some users like to modify them to keep their fans quiet at all costs. Reading from this file -- cgit v1.2.3 From 26befef00eb2ae37939a189a5d03c4c7b600e6f9 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 14 Nov 2017 17:14:14 +0100 Subject: platform/x86: thinkpad_acpi: Accept flat mode for type 4 multi mode status On the X1 Yoga 2nd Generation and most likely other notebooks the FLAT mode is reported. Decode it correctly rather than warning about an unexpected multi mode status to be reported. Signed-off-by: Benjamin Berg Cc: Peter FP1 Zhang Reviewed-by: Lyude Paul Signed-off-by: Andy Shevchenko --- drivers/platform/x86/thinkpad_acpi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 117be48ff4de..7dcbd97710a9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2113,12 +2113,10 @@ static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode) TP_ACPI_MULTI_MODE_FLAT; break; case 4: - valid_modes = TP_ACPI_MULTI_MODE_LAPTOP | - TP_ACPI_MULTI_MODE_TABLET | - TP_ACPI_MULTI_MODE_STAND | - TP_ACPI_MULTI_MODE_TENT; - break; case 5: + /* In mode 4, FLAT is not specified as a valid mode. However, + * it can be seen at least on the X1 Yoga 2nd Generation. + */ valid_modes = TP_ACPI_MULTI_MODE_LAPTOP | TP_ACPI_MULTI_MODE_FLAT | TP_ACPI_MULTI_MODE_TABLET | -- cgit v1.2.3 From 1b46f17d687a431c423f970a5d292c6fcd478afb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 12 Dec 2017 17:40:54 +0100 Subject: platform/x86: Add driver for GPD pocket custom fan controller Add a driver for the GPD pocket device's custom fan controller, which gets controlled through 2 GPIOs listed in a FAN02501 ACPI device. Cc: James Suggested-by: James Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- MAINTAINERS | 6 ++ drivers/platform/x86/Kconfig | 12 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/gpd-pocket-fan.c | 193 ++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 drivers/platform/x86/gpd-pocket-fan.c diff --git a/MAINTAINERS b/MAINTAINERS index 825acf165c2d..bc4d77695918 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5947,6 +5947,12 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/input/touchscreen/goodix.c +GPD POCKET FAN DRIVER +M: Hans de Goede +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/gpd-pocket-fan.c + GPIO ACPI SUPPORT M: Mika Westerberg M: Andy Shevchenko diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 88bf2f46b7a4..8a07df54a67e 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -258,6 +258,18 @@ config AMILO_RFKILL This is a driver for enabling wifi on some Fujitsu-Siemens Amilo laptops. +config GPD_POCKET_FAN + tristate "GPD Pocket Fan Controller support" + depends on ACPI + depends on THERMAL + ---help--- + Driver for the GPD Pocket vendor specific FAN02501 ACPI device + which controls the fan speed on the GPD Pocket. + + Without this driver the fan on the Pocket will stay off independent + of the CPU temperature. Say Y or M if the kernel may be used on a + GPD pocket. + config TC1100_WMI tristate "HP Compaq TC1100 Tablet WMI Extras" depends on !X86_64 diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 4f92dbf30900..57f37e55786a 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_HP_ACCEL) += hp_accel.o obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o obj-$(CONFIG_HP_WMI) += hp-wmi.o obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o +obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c new file mode 100644 index 000000000000..c6f4d89b1437 --- /dev/null +++ b/drivers/platform/x86/gpd-pocket-fan.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GPD Pocket fan controller driver + * + * Copyright (C) 2017 Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include + +static int temp_limits[3] = { 55000, 60000, 65000 }; +module_param_array(temp_limits, int, NULL, 0444); +MODULE_PARM_DESC(temp_limits, + "Milli-celcius values above which the fan speed increases"); + +static int hysteresis = 3000; +module_param(hysteresis, int, 0444); +MODULE_PARM_DESC(hysteresis, + "Hysteresis in milli-celcius before lowering the fan speed"); + +struct gpd_pocket_fan_data { + struct device *dev; + struct thermal_zone_device *dts0; + struct thermal_zone_device *dts1; + struct gpio_desc *gpio0; + struct gpio_desc *gpio1; + struct delayed_work work; + int last_speed; +}; + +static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data *fan, int speed) +{ + if (speed == fan->last_speed) + return; + + gpiod_direction_output(fan->gpio0, !!(speed & 1)); + gpiod_direction_output(fan->gpio1, !!(speed & 2)); + + fan->last_speed = speed; +} + +static void gpd_pocket_fan_worker(struct work_struct *work) +{ + struct gpd_pocket_fan_data *fan = + container_of(work, struct gpd_pocket_fan_data, work.work); + int t0, t1, temp, speed, i; + + if (thermal_zone_get_temp(fan->dts0, &t0) || + thermal_zone_get_temp(fan->dts1, &t1)) { + dev_warn(fan->dev, "Error getting temperature\n"); + queue_delayed_work(system_wq, &fan->work, + msecs_to_jiffies(1000)); + return; + } + + temp = max(t0, t1); + + speed = fan->last_speed; + + /* Determine minimum speed */ + for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { + if (temp < temp_limits[i]) + break; + } + if (speed < i) + speed = i; + + /* Use hysteresis before lowering speed again */ + for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { + if (temp <= (temp_limits[i] - hysteresis)) + break; + } + if (speed > i) + speed = i; + + if (fan->last_speed <= 0 && speed) + speed = 3; /* kick start motor */ + + gpd_pocket_fan_set_speed(fan, speed); + + /* When mostly idle (low temp/speed), slow down the poll interval. */ + queue_delayed_work(system_wq, &fan->work, + msecs_to_jiffies(4000 / (speed + 1))); +} + +static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan) +{ + fan->last_speed = -1; + mod_delayed_work(system_wq, &fan->work, 0); +} + +static int gpd_pocket_fan_probe(struct platform_device *pdev) +{ + struct gpd_pocket_fan_data *fan; + int i; + + for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { + if (temp_limits[i] < 40000 || temp_limits[i] > 70000) { + dev_err(&pdev->dev, "Invalid temp-limit %d (must be between 40000 and 70000)\n", + temp_limits[i]); + return -EINVAL; + } + } + if (hysteresis < 1000 || hysteresis > 10000) { + dev_err(&pdev->dev, "Invalid hysteresis %d (must be between 1000 and 10000)\n", + hysteresis); + return -EINVAL; + } + + fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); + if (!fan) + return -ENOMEM; + + fan->dev = &pdev->dev; + INIT_DELAYED_WORK(&fan->work, gpd_pocket_fan_worker); + + /* Note this returns a "weak" reference which we don't need to free */ + fan->dts0 = thermal_zone_get_zone_by_name("soc_dts0"); + if (IS_ERR(fan->dts0)) + return -EPROBE_DEFER; + + fan->dts1 = thermal_zone_get_zone_by_name("soc_dts1"); + if (IS_ERR(fan->dts1)) + return -EPROBE_DEFER; + + fan->gpio0 = devm_gpiod_get_index(fan->dev, NULL, 0, GPIOD_ASIS); + if (IS_ERR(fan->gpio0)) + return PTR_ERR(fan->gpio0); + + fan->gpio1 = devm_gpiod_get_index(fan->dev, NULL, 1, GPIOD_ASIS); + if (IS_ERR(fan->gpio1)) + return PTR_ERR(fan->gpio1); + + gpd_pocket_fan_force_update(fan); + + platform_set_drvdata(pdev, fan); + return 0; +} + +static int gpd_pocket_fan_remove(struct platform_device *pdev) +{ + struct gpd_pocket_fan_data *fan = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&fan->work); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int gpd_pocket_fan_suspend(struct device *dev) +{ + struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev); + + gpd_pocket_fan_set_speed(fan, 0); + return 0; +} + +static int gpd_pocket_fan_resume(struct device *dev) +{ + struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev); + + gpd_pocket_fan_force_update(fan); + return 0; +} +#endif +static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops, + gpd_pocket_fan_suspend, + gpd_pocket_fan_resume); + +static struct acpi_device_id gpd_pocket_fan_acpi_match[] = { + { "FAN02501" }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, gpd_pocket_fan_acpi_match); + +static struct platform_driver gpd_pocket_fan_driver = { + .probe = gpd_pocket_fan_probe, + .remove = gpd_pocket_fan_remove, + .driver = { + .name = "gpd_pocket_fan", + .acpi_match_table = gpd_pocket_fan_acpi_match, + .pm = &gpd_pocket_fan_pm_ops, + }, +}; + +module_platform_driver(gpd_pocket_fan_driver); +MODULE_AUTHOR("Hans de Goede Date: Sat, 23 Dec 2017 02:01:22 +0000 Subject: platform/x86: dell-laptop: make some local functions static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following sparse warnings: drivers/platform/x86/dell-laptop.c:289:6: warning: symbol 'dell_set_arguments' was not declared. Should it be static? drivers/platform/x86/dell-laptop.c:298:5: warning: symbol 'dell_send_request' was not declared. Should it be static? Signed-off-by: Wei Yongjun Reviewed-by: Pali Rohár Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 629d96048b63..a94936a5b6c7 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -286,7 +286,7 @@ static const struct dmi_system_id dell_quirks[] __initconst = { { } }; -void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) +static void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) { memset(buffer, 0, sizeof(struct calling_interface_buffer)); buffer->input[0] = arg0; @@ -295,7 +295,7 @@ void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) buffer->input[3] = arg3; } -int dell_send_request(u16 class, u16 select) +static int dell_send_request(u16 class, u16 select) { int ret; -- cgit v1.2.3 From 2aeb2c3a2bdc45245d38a20b71205a223748e8a2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 25 Dec 2017 13:45:25 +0100 Subject: platform/x86: silead_dmi: Add entry for the Trekstor Primebook C13 Add touchscreen platform data for the Trekstor Primebook C13 laptop. Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/silead_dmi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 09b589fb79d4..713446ee3b61 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -232,6 +232,21 @@ static const struct silead_ts_dmi_data chuwi_vi8_data = { .properties = chuwi_vi8_props, }; +static const struct property_entry trekstor_primebook_c13_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 2624), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1920), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-trekstor-primebook-c13.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct silead_ts_dmi_data trekstor_primebook_c13_data = { + .acpi_name = "MSSL1680:00", + .properties = trekstor_primebook_c13_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -365,6 +380,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), }, }, + { + /* Trekstor Primebook C13 */ + .driver_data = (void *)&trekstor_primebook_c13_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), + }, + }, { }, }; -- cgit v1.2.3 From a346aa204020f30c7b9152da675f431246c70160 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 2 Jan 2018 19:39:27 +0100 Subject: platform/x86: silead_dmi: Add entry for the Teclast X98 Plus II Add touchscreen platform data for the Teclast X98 Plus II tablet. Signed-off-by: Paul Cercueil Acked-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 713446ee3b61..ee8d8e844eb0 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -247,6 +247,22 @@ static const struct silead_ts_dmi_data trekstor_primebook_c13_data = { .properties = trekstor_primebook_c13_props, }; +static const struct property_entry teclast_x98plus2_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 2048), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1686-teclast_x98plus2.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct silead_ts_dmi_data teclast_x98plus2_data = { + .acpi_name = "MSSL1680:00", + .properties = teclast_x98plus2_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -388,6 +404,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), }, }, + { + /* Teclast X98 Plus II */ + .driver_data = (void *)&teclast_x98plus2_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), + }, + }, { }, }; -- cgit v1.2.3 From 9a1a6259184794773019aa2d242e15d81168fc18 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 3 Jan 2018 12:49:29 +0100 Subject: platform/x86: wmi: Call acpi_wmi_init() later Calling acpi_wmi_init() at the subsys_initcall() level causes ordering issues to appear on some systems and they are difficult to reproduce, because there is no guaranteed ordering between subsys_initcall() calls, so they may occur in different orders on different systems. In particular, commit 86d9f48534e8 (mm/slab: fix kmemcg cache creation delayed issue) exposed one of these issues where genl_init() and acpi_wmi_init() are both called at the same initcall level, but the former must run before the latter so as to avoid a NULL pointer dereference. For this reason, move the acpi_wmi_init() invocation to the initcall_sync level which should still be early enough for things to work correctly in the WMI land. Link: https://marc.info/?t=151274596700002&r=1&w=2 Reported-by: Jonathan McDowell Reported-by: Joonsoo Kim Tested-by: Jonathan McDowell Signed-off-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- 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 791449a2370f..daa68acbc900 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1458,5 +1458,5 @@ static void __exit acpi_wmi_exit(void) class_unregister(&wmi_bus_class); } -subsys_initcall(acpi_wmi_init); +subsys_initcall_sync(acpi_wmi_init); module_exit(acpi_wmi_exit); -- cgit v1.2.3 From 28d71ae92182334421d642297f3b2bf642526c12 Mon Sep 17 00:00:00 2001 From: Olle Liljenzin Date: Sun, 7 Jan 2018 20:53:12 +0100 Subject: platform/x86: ideapad-laptop: Add Y720-15IKB to no_hw_rfkill Lenovo Legion Y720-15IKB is another Lenovo model without a hw rfkill switch, resulting in wifi always reported as hard blocked. Add the model to the list of models without rfkill switch. Signed-off-by: Olle Liljenzin Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 5ab638d4d243..b2bbddd09a52 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1110,6 +1110,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"), }, }, + { + .ident = "Lenovo Legion Y720-15IKB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"), + }, + }, { .ident = "Lenovo Legion Y720-15IKBN", .matches = { -- cgit v1.2.3 From 4f258cf4012e24b92b0db7b7b7a8ee883e13782b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 14 Jan 2018 21:11:18 -0800 Subject: platform/x86: have ACPI_CMPC use depends instead of select for INPUT Drivers should not 'select' a subsystem. Instead they should depend on it. If the subsystem is disabled, the user probably did that for a purpose and one driver shouldn't be changing that. This also makes all platform/x86/ drivers consistent w.r.t depending on INPUT instead of selecting it. Signed-off-by: Randy Dunlap Cc: Andy Shevchenko Cc: platform-driver-x86@vger.kernel.org Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 8a07df54a67e..de51952f0a92 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -838,9 +838,8 @@ config TOSHIBA_WMI config ACPI_CMPC tristate "CMPC Laptop Extras" - depends on ACPI + depends on ACPI && INPUT depends on RFKILL || RFKILL=n - select INPUT select BACKLIGHT_CLASS_DEVICE help Support for Intel Classmate PC ACPI devices, including some -- cgit v1.2.3 From 12d614a0dcaee9668c641fcaa9f524da861a765e Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Thu, 11 Jan 2018 16:40:31 +0530 Subject: platform/x86: intel_pmc_core: Remove unused EXPORTED API Though ChromeOs uses the exported API as part of their S0ix failsafe mechanism, there is no active consumer of this API in upstream kernel. We can revisit this when ChromeOs kernel team is able to get their S0ix failsafe framework in mainline. Cc: Derek Basehore Cc: Rajat Jain Link: https://patchwork.kernel.org/patch/9831229/ Suggested-by: Andriy Shevchenko Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 32 -------------------------------- drivers/platform/x86/intel_pmc_core.h | 1 - 2 files changed, 33 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 17e08b42b0a9..00748472a55e 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -146,37 +146,6 @@ static inline u32 pmc_core_adjust_slp_s0_step(u32 value) return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP; } -/** - * intel_pmc_slp_s0_counter_read() - Read SLP_S0 residency. - * @data: Out param that contains current SLP_S0 count. - * - * This API currently supports Intel Skylake SoC and Sunrise - * Point Platform Controller Hub. Future platform support - * should be added for platforms that support low power modes - * beyond Package C10 state. - * - * SLP_S0_RESIDENCY counter counts in 100 us granularity per - * step hence function populates the multiplied value in out - * parameter @data. - * - * Return: an error code or 0 on success. - */ -int intel_pmc_slp_s0_counter_read(u32 *data) -{ - struct pmc_dev *pmcdev = &pmc; - const struct pmc_reg_map *map = pmcdev->map; - u32 value; - - if (!pmcdev->has_slp_s0_res) - return -EACCES; - - value = pmc_core_reg_read(pmcdev, map->slp_s0_offset); - *data = pmc_core_adjust_slp_s0_step(value); - - return 0; -} -EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read); - static int pmc_core_dev_state_get(void *data, u64 *val) { struct pmc_dev *pmcdev = data; @@ -548,7 +517,6 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) if (err < 0) dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); - pmc.has_slp_s0_res = true; return 0; } diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 3d225a9cc09f..ecff50356c71 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -178,7 +178,6 @@ struct pmc_dev { #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *dbgfs_dir; #endif /* CONFIG_DEBUG_FS */ - bool has_slp_s0_res; int pmc_xram_read_bit; struct mutex lock; /* generic mutex lock for PMC Core */ }; -- cgit v1.2.3 From 8c9180dd2c2a5f1356121cd87b373d9881b41c65 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Thu, 11 Jan 2018 16:40:32 +0530 Subject: platform/x86: intel_pmc_core: Remove unused variable base_address field is redundant and unused in the driver so get rid of it. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index ecff50356c71..c6169fe0edf2 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -135,7 +135,6 @@ struct pmc_bit_map { * @pll_sts: Maps name of PLL to corresponding bit status * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit - * @base_address: Base address of PWRMBASE defined in BIOS writer guide * @regmap_length: Length of memory to map from PWRMBASE address to access * @ppfear0_offset: PWRMBASE offset to to read PPFEAR* * @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from @@ -152,7 +151,6 @@ struct pmc_reg_map { const struct pmc_bit_map *pll_sts; const u32 slp_s0_offset; const u32 ltr_ignore_offset; - const u32 base_address; const int regmap_length; const u32 ppfear0_offset; const int ppfear_buckets; -- cgit v1.2.3 From 7fc658923a599f3ad68dbccec59b6631c6352455 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Thu, 11 Jan 2018 16:40:33 +0530 Subject: platform/x86: intel_pmc_core: Fix kernel doc for pmc_dev Fix invalid field information and add missing fields in kernel doc comments. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index c6169fe0edf2..e3be1d2b08cd 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -160,12 +160,14 @@ struct pmc_reg_map { /** * struct pmc_dev - pmc device structure - * @base_addr: comtains pmc base address + * @base_addr: contains pmc base address * @regbase: pointer to io-remapped memory location - * @dbgfs_dir: path to debug fs interface - * @feature_available: flag to indicate whether - * the feature is available - * on a particular platform or not. + * @map: pointer to pmc_reg_map struct that contains platform + * specific attributes + * @dbgfs_dir: path to debugfs interface + * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers + * used to read MPHY PG and PLL status are available + * @mutex_lock: mutex to complete one transcation * * pmc_dev contains info about power management controller device. */ -- cgit v1.2.3 From 2854a0aa822c11ea8538ebfe94a62e20ab570e2b Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 11 Jan 2018 16:40:34 +0530 Subject: platform/x86: intel_pmc_core: Change driver to a module Allow the driver to be a module since builtin_pci_driver funtionality is no longer needed. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 2 +- drivers/platform/x86/intel_pmc_core.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index de51952f0a92..1c251eb130ab 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -974,7 +974,7 @@ config INTEL_IMR If you are running on a Galileo/Quark say Y here. config INTEL_PMC_CORE - bool "Intel PMC Core driver" + tristate "Intel PMC Core driver" depends on PCI ---help--- The Intel Platform Controller Hub for Intel Core SoCs provides access diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 00748472a55e..44353034718a 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include #include @@ -124,6 +124,7 @@ static const struct pci_device_id pmc_pci_ids[] = { (kernel_ulong_t)&spt_reg_map }, { 0, }, }; +MODULE_DEVICE_TABLE(pci, pmc_pci_ids); static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset) { @@ -520,10 +521,20 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) return 0; } +static void pmc_core_remove(struct pci_dev *dev) +{ + pmc_core_dbgfs_unregister(&pmc); + mutex_destroy(&pmc.lock); +} + static struct pci_driver intel_pmc_core_driver = { .name = "intel_pmc_core", .id_table = pmc_pci_ids, .probe = pmc_core_probe, + .remove = pmc_core_remove, }; -builtin_pci_driver(intel_pmc_core_driver); +module_pci_driver(intel_pmc_core_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel PMC Core Driver"); -- cgit v1.2.3 From 1f644da7e920cb83403818efa88ebfb6d1528264 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Thu, 11 Jan 2018 16:40:35 +0530 Subject: platform/x86: intel_pmc_core: Fix file permission warnings Symbolic permissions 'S_IRUGO' are not preferred. This patch changes the debugfs files to use octal permissions '0644' or '0444' as needed by the attribute. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 44353034718a..cf8b3b34a979 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -414,31 +414,27 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) return -ENOMEM; pmcdev->dbgfs_dir = dir; - file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO, + file = debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev, &pmc_core_dev_state); if (!file) goto err; - file = debugfs_create_file("pch_ip_power_gating_status", - S_IFREG | S_IRUGO, dir, pmcdev, - &pmc_core_ppfear_ops); + file = debugfs_create_file("pch_ip_power_gating_status", 0444, + dir, pmcdev, &pmc_core_ppfear_ops); if (!file) goto err; - file = debugfs_create_file("mphy_core_lanes_power_gating_status", - S_IFREG | S_IRUGO, dir, pmcdev, - &pmc_core_mphy_pg_ops); + file = debugfs_create_file("mphy_core_lanes_power_gating_status", 0444, + dir, pmcdev, &pmc_core_mphy_pg_ops); if (!file) goto err; - file = debugfs_create_file("pll_status", - S_IFREG | S_IRUGO, dir, pmcdev, + file = debugfs_create_file("pll_status", 0444, dir, pmcdev, &pmc_core_pll_ops); if (!file) goto err; - file = debugfs_create_file("ltr_ignore", - S_IFREG | S_IRUGO, dir, pmcdev, + file = debugfs_create_file("ltr_ignore", 0644, dir, pmcdev, &pmc_core_ltr_ignore_ops); if (!file) -- cgit v1.2.3 From c4abf92d4fac7dcac0717410e9242714c35a27f2 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Thu, 11 Jan 2018 16:40:36 +0530 Subject: platform/x86: intel_pmc_core: Update Kconfig This adds list of supported features by this driver to the Kconfig. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 1c251eb130ab..aaca22fb45b9 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -983,7 +983,10 @@ config INTEL_PMC_CORE exposed by the Power Management Controller. Supported features: - - SLP_S0_RESIDENCY counter. + - SLP_S0_RESIDENCY counter + - PCH IP Power Gating status + - LTR Ignore + - MPHY/PLL gating status (Sunrisepoint PCH only) config IBM_RTL tristate "Device driver to enable PRTL support" -- cgit v1.2.3 From 4d6bde512a86c32df3a1f289d2b4cd04b17758d1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 11 Jan 2018 15:14:39 +0100 Subject: platform/x86: dell-laptop: Filter out spurious keyboard backlight change events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some Dell XPS models WMI events of type 0x0000 reporting a keycode of 0xe00c get reported when the brightness of the LCD panel changes. This leads to us reporting false-positive kbd_led change events to userspace which in turn leads to the kbd backlight OSD showing when it should not. We already read the current keyboard backlight brightness value when reporting events because the led_classdev_notify_brightness_hw_changed API requires this. Compare this value to the last known value and filter out duplicate events, fixing this. Note the fixed issue is esp. a problem on XPS models with an ambient light sensor and automatic brightness adjustments turned on, this causes the kbd backlight OSD to show all the time there. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1514969 Fixes: 9c656b0799 ("platform/x86: dell-*: Call new led hw_changed API ...") Acked-by: Pali Rohár Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index a94936a5b6c7..2ca389b48398 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1133,6 +1133,7 @@ static u8 kbd_previous_mode_bit; static bool kbd_led_present; static DEFINE_MUTEX(kbd_led_mutex); +static enum led_brightness kbd_led_level; /* * NOTE: there are three ways to set the keyboard backlight level. @@ -1947,6 +1948,7 @@ static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev) static int kbd_led_level_set(struct led_classdev *led_cdev, enum led_brightness value) { + enum led_brightness new_value = value; struct kbd_state state; struct kbd_state new_state; u16 num; @@ -1976,6 +1978,9 @@ static int kbd_led_level_set(struct led_classdev *led_cdev, } out: + if (ret == 0) + kbd_led_level = new_value; + mutex_unlock(&kbd_led_mutex); return ret; } @@ -2003,6 +2008,9 @@ static int __init kbd_led_init(struct device *dev) if (kbd_led.max_brightness) kbd_led.max_brightness--; } + + kbd_led_level = kbd_led_level_get(NULL); + ret = led_classdev_register(dev, &kbd_led); if (ret) kbd_led_present = false; @@ -2027,13 +2035,25 @@ static void kbd_led_exit(void) static int dell_laptop_notifier_call(struct notifier_block *nb, unsigned long action, void *data) { + bool changed = false; + enum led_brightness new_kbd_led_level; + switch (action) { case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED: if (!kbd_led_present) break; - led_classdev_notify_brightness_hw_changed(&kbd_led, - kbd_led_level_get(&kbd_led)); + mutex_lock(&kbd_led_mutex); + new_kbd_led_level = kbd_led_level_get(&kbd_led); + if (kbd_led_level != new_kbd_led_level) { + kbd_led_level = new_kbd_led_level; + changed = true; + } + mutex_unlock(&kbd_led_mutex); + + if (changed) + led_classdev_notify_brightness_hw_changed(&kbd_led, + kbd_led_level); break; } -- cgit v1.2.3 From 4245c155421bf37c2c684ec74915fd535e737b03 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 16 Jan 2018 20:24:15 +0100 Subject: platform/x86: silead_dmi: Add entry for newer BIOS for Trekstor Surftab 7.0 Some versions of the Trekstor Surftab 7.0 ship with a newer BIOS which uses different DMI strings. Signed-off-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index ee8d8e844eb0..048a82f12f8c 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -308,6 +308,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), }, }, + { + /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */ + .driver_data = (void *)&surftab_wintron70_st70416_6_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, + "SurfTab wintron 7.0 ST70416-6"), + /* Exact match, different versions need different fw */ + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"), + }, + }, { /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */ .driver_data = (void *)&surftab_wintron70_st70416_6_data, -- cgit v1.2.3 From 587d8628fb71c3bfae29fb2bbe84c1478c59bac8 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 12 Jan 2018 12:04:45 +0100 Subject: platform/x86: thinkpad_acpi: suppress warning about palm detection This patch prevents the thinkpad_acpi driver from warning about 2 event codes returned for keyboard palm-detection. No behavioral changes, other than suppressing the warning in the kernel log. The events are still forwarded via acpi-netlink channels. We could, optionally, decide to forward the event through a input-switch on the tpacpi input device. However, so far no suitable input-code exists, and no similar drivers report such events. Hence, leave it an acpi event for now. Note that the event-codes are named based on empirical studies. On the ThinkPad X1 5th Gen the sensor can be found underneath the arrow key. Cc: Matthew Thode Signed-off-by: David Herrmann Acked-by: Henrique de Moraes Holschuh Signed-off-by: Andy Shevchenko --- drivers/platform/x86/thinkpad_acpi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7dcbd97710a9..d5eaf3b1edba 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -214,6 +214,10 @@ enum tpacpi_hkey_event_t { /* AC-related events */ TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */ + /* Further user-interface events */ + TP_HKEY_EV_PALM_DETECTED = 0x60b0, /* palm hoveres keyboard */ + TP_HKEY_EV_PALM_UNDETECTED = 0x60b1, /* palm removed */ + /* Misc */ TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ }; @@ -4077,6 +4081,12 @@ static bool hotkey_notify_6xxx(const u32 hkey, *send_acpi_ev = false; break; + case TP_HKEY_EV_PALM_DETECTED: + case TP_HKEY_EV_PALM_UNDETECTED: + /* palm detected hovering the keyboard, forward to user-space + * via netlink for consumption */ + return true; + default: pr_warn("unknown possible thermal alarm or keyboard event received\n"); known = false; -- cgit v1.2.3 From c58a4f2215f7290a8263b57dd098f0b9b40581bc Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Tue, 23 Jan 2018 18:33:38 +0000 Subject: platform/x86: silead_dmi: Add Teclast X3 Plus tablet support Add touchscreen platform data for the Teclast X3 Plus tablet. Reviewed-by: Hans de Goede Signed-off-by: Alberto Ponces Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 048a82f12f8c..3a624090191d 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -263,6 +263,20 @@ static const struct silead_ts_dmi_data teclast_x98plus2_data = { .properties = teclast_x98plus2_props, }; +static const struct property_entry teclast_x3_plus_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct silead_ts_dmi_data teclast_x3_plus_data = { + .acpi_name = "MSSL1680:00", + .properties = teclast_x3_plus_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -423,6 +437,15 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), }, }, + { + /* Teclast X3 Plus */ + .driver_data = (void *)&teclast_x3_plus_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_MATCH(DMI_PRODUCT_NAME, "X3 Plus"), + DMI_MATCH(DMI_BOARD_NAME, "X3 Plus"), + }, + }, { }, }; -- cgit v1.2.3 From fe486138788ba435ffa918c8d7aba05a77b6289a Mon Sep 17 00:00:00 2001 From: Alexander Abrosimov Date: Fri, 26 Jan 2018 01:48:57 +0300 Subject: platform/x86: dell-laptop: Add 2-in-1 devices to the DMI whitelist SMBIOS 3.0.0 Specification introduced new Chassis Types field values for 2-in-1 devices like tablets, convertibles and detachables. Dell's Inspiron 2-in-1 and XPS 2-in-1 fall into this category and they have to be added to the DMI whitelist, so rfkill and backlight can be controlled for them as for other laptops. Signed-off-by: Alexander Abrosimov Reviewed-by: Mario Limonciello Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-laptop.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 2ca389b48398..fc2dfc85e014 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -109,6 +109,42 @@ static const struct dmi_system_id dell_device_table[] __initconst = { DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/ }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/ + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/ + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/ + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/ + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/ + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/ + }, + }, { .ident = "Dell Computer Corporation", .matches = { -- cgit v1.2.3 From 7dc5ff66c2c1d42ea55800548e0e28cc0d206c98 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 5 Jan 2018 08:56:48 -0600 Subject: platform/x86: dell-smbios: Correct notation for filtering The class/select were mistakenly put into octal notation but intended to be in decimal notation. Suggested-by: Pali Rohar Signed-off-by: Mario Limonciello Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-smbios.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 6a60db515bda..8541cde4cb7d 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -65,10 +65,10 @@ static struct smbios_call call_whitelist[] = { /* calls that are explicitly blacklisted */ static struct smbios_call call_blacklist[] = { - {0x0000, 01, 07}, /* manufacturing use */ - {0x0000, 06, 05}, /* manufacturing use */ - {0x0000, 11, 03}, /* write once */ - {0x0000, 11, 07}, /* write once */ + {0x0000, 1, 7}, /* manufacturing use */ + {0x0000, 6, 5}, /* manufacturing use */ + {0x0000, 11, 3}, /* write once */ + {0x0000, 11, 7}, /* write once */ {0x0000, 11, 11}, /* write once */ {0x0000, 19, -1}, /* diagnostics */ /* handled by kernel: dell-laptop */ -- cgit v1.2.3 From 750e0f570b7145870d40f07337f3356c18e0abd4 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 19 Jan 2018 14:28:20 +0530 Subject: platform/x86: intel_pmc_core: Refactor debugfs entries When on a platform if we can't show MPHY and PLL status, don't even bother to create a debugfs entry as it will fail anyway. In fact unless OEM builds a special BIOS for test, it will fail on every production system. This will help to add future platform support where we can't support these entries. Suggested-by: Andy Shevchenko Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 38 +++++++++++++---------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index cf8b3b34a979..da924d3bb3e5 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -407,43 +407,33 @@ static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) { - struct dentry *dir, *file; + struct dentry *dir; dir = debugfs_create_dir("pmc_core", NULL); if (!dir) return -ENOMEM; pmcdev->dbgfs_dir = dir; - file = debugfs_create_file("slp_s0_residency_usec", 0444, - dir, pmcdev, &pmc_core_dev_state); - if (!file) - goto err; - file = debugfs_create_file("pch_ip_power_gating_status", 0444, - dir, pmcdev, &pmc_core_ppfear_ops); - if (!file) - goto err; + debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev, + &pmc_core_dev_state); - file = debugfs_create_file("mphy_core_lanes_power_gating_status", 0444, - dir, pmcdev, &pmc_core_mphy_pg_ops); - if (!file) - goto err; + debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev, + &pmc_core_ppfear_ops); - file = debugfs_create_file("pll_status", 0444, dir, pmcdev, - &pmc_core_pll_ops); - if (!file) - goto err; + debugfs_create_file("ltr_ignore", 0644, dir, pmcdev, + &pmc_core_ltr_ignore_ops); - file = debugfs_create_file("ltr_ignore", 0644, dir, pmcdev, - &pmc_core_ltr_ignore_ops); + if (pmcdev->map->pll_sts) + debugfs_create_file("pll_status", 0444, dir, pmcdev, + &pmc_core_pll_ops); - if (!file) - goto err; + if (pmcdev->map->mphy_sts) + debugfs_create_file("mphy_core_lanes_power_gating_status", + 0444, dir, pmcdev, + &pmc_core_mphy_pg_ops); return 0; -err: - pmc_core_dbgfs_unregister(pmcdev); - return -ENODEV; } #else static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) -- cgit v1.2.3 From 21ae43570940f8393a80369f62a3880bd64daad8 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 19 Jan 2018 14:28:21 +0530 Subject: platform/x86: intel_pmc_core: Substitute PCI with CPUID enumeration The Only use of PCI device enumeration here is to get the PMC base address which is a fixed value i.e. 0xFE000000. On some platforms this can be read through a non standard PCI BAR. But after Kabylake, PMC is not exposed as a PCI device anymore. There are other non standard methods like ACPI LPIT which can also be used for obtaining this value. For simplicity, this value can be hardcoded as it won't change. Since we don't have a PMC PCI device on any platform after Kabylake, this creates a foundation for future SoC support. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Srinivas Pandruvada Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 89 ++++++++++++----------------------- drivers/platform/x86/intel_pmc_core.h | 3 +- 2 files changed, 32 insertions(+), 60 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index da924d3bb3e5..e3b98fcceb57 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -18,12 +18,12 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include -#include #include #include -#include #include #include @@ -119,13 +119,6 @@ static const struct pmc_reg_map spt_reg_map = { .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT, }; -static const struct pci_device_id pmc_pci_ids[] = { - { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), - (kernel_ulong_t)&spt_reg_map }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, pmc_pci_ids); - static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset) { return readb(pmcdev->regbase + offset); @@ -448,79 +441,59 @@ static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) static const struct x86_cpu_id intel_pmc_core_ids[] = { { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, - (kernel_ulong_t)NULL}, + (kernel_ulong_t)&spt_reg_map}, { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT, - (kernel_ulong_t)NULL}, + (kernel_ulong_t)&spt_reg_map}, { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT, - (kernel_ulong_t)NULL}, + (kernel_ulong_t)&spt_reg_map}, { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT, - (kernel_ulong_t)NULL}, + (kernel_ulong_t)&spt_reg_map}, {} }; -static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) +MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids); + +static int __init pmc_core_probe(void) { - struct device *ptr_dev = &dev->dev; struct pmc_dev *pmcdev = &pmc; const struct x86_cpu_id *cpu_id; - const struct pmc_reg_map *map = (struct pmc_reg_map *)id->driver_data; int err; cpu_id = x86_match_cpu(intel_pmc_core_ids); - if (!cpu_id) { - dev_dbg(&dev->dev, "PMC Core: cpuid mismatch.\n"); - return -EINVAL; - } - - err = pcim_enable_device(dev); - if (err < 0) { - dev_dbg(&dev->dev, "PMC Core: failed to enable Power Management Controller.\n"); - return err; - } - - err = pci_read_config_dword(dev, - SPT_PMC_BASE_ADDR_OFFSET, - &pmcdev->base_addr); - if (err < 0) { - dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n"); - return err; - } - pmcdev->base_addr &= PMC_BASE_ADDR_MASK; - dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr); - - pmcdev->regbase = devm_ioremap_nocache(ptr_dev, - pmcdev->base_addr, - SPT_PMC_MMIO_REG_LEN); - if (!pmcdev->regbase) { - dev_dbg(&dev->dev, "PMC Core: ioremap failed.\n"); + if (!cpu_id) + return -ENODEV; + + pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data; + pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT; + pmcdev->regbase = ioremap(pmcdev->base_addr, + pmcdev->map->regmap_length); + if (!pmcdev->regbase) return -ENOMEM; - } mutex_init(&pmcdev->lock); - pmcdev->map = map; pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); err = pmc_core_dbgfs_register(pmcdev); - if (err < 0) - dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); + if (err < 0) { + pr_warn(" debugfs register failed.\n"); + iounmap(pmcdev->regbase); + return err; + } + pr_info(" initialized\n"); return 0; } +module_init(pmc_core_probe) -static void pmc_core_remove(struct pci_dev *dev) +static void __exit pmc_core_remove(void) { - pmc_core_dbgfs_unregister(&pmc); - mutex_destroy(&pmc.lock); -} - -static struct pci_driver intel_pmc_core_driver = { - .name = "intel_pmc_core", - .id_table = pmc_pci_ids, - .probe = pmc_core_probe, - .remove = pmc_core_remove, -}; + struct pmc_dev *pmcdev = &pmc; -module_pci_driver(intel_pmc_core_driver); + pmc_core_dbgfs_unregister(pmcdev); + mutex_destroy(&pmcdev->lock); + iounmap(pmcdev->regbase); +} +module_exit(pmc_core_remove) MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel PMC Core Driver"); diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index e3be1d2b08cd..9df4a60a179f 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -21,8 +21,7 @@ #ifndef PMC_CORE_H #define PMC_CORE_H -/* Sunrise Point Power Management Controller PCI Device ID */ -#define SPT_PMC_PCI_DEVICE_ID 0x9d21 +#define PMC_BASE_ADDR_DEFAULT 0xFE000000 #define SPT_PMC_BASE_ADDR_OFFSET 0x48 #define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c -- cgit v1.2.3 From 00f8b2fce4da2296bafc1de6a46510a13ef60938 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 19 Jan 2018 14:28:24 +0530 Subject: platform/x86: intel_pmc_core: Convert to ICPU macro Use ICPU macro to refactor code related to x86_cpu_id for better readability. Suggested-by: Andy Shevchenko Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index e3b98fcceb57..f971ca1a6ed2 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -32,6 +32,9 @@ #include "intel_pmc_core.h" +#define ICPU(model, data) \ + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (kernel_ulong_t)data } + static struct pmc_dev pmc; static const struct pmc_bit_map spt_pll_map[] = { @@ -440,14 +443,10 @@ static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) #endif /* CONFIG_DEBUG_FS */ static const struct x86_cpu_id intel_pmc_core_ids[] = { - { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, - (kernel_ulong_t)&spt_reg_map}, - { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT, - (kernel_ulong_t)&spt_reg_map}, - { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT, - (kernel_ulong_t)&spt_reg_map}, - { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT, - (kernel_ulong_t)&spt_reg_map}, + ICPU(INTEL_FAM6_SKYLAKE_MOBILE, &spt_reg_map), + ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, &spt_reg_map), + ICPU(INTEL_FAM6_KABYLAKE_MOBILE, &spt_reg_map), + ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, &spt_reg_map), {} }; -- cgit v1.2.3 From d890acf728aefc47fd90733d5fef1dff89857748 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 19 Jan 2018 21:47:07 +0100 Subject: platform/x86: GPD pocket fan: Set speed to max on get_temp failure When we fail to get the temperature, assume the worst and set the speed to max. While at it introduce a define for MAX_SPEED. Cc: James Suggested-by: James Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/gpd-pocket-fan.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c index c6f4d89b1437..1fdf2205730d 100644 --- a/drivers/platform/x86/gpd-pocket-fan.c +++ b/drivers/platform/x86/gpd-pocket-fan.c @@ -13,6 +13,8 @@ #include #include +#define MAX_SPEED 3 + static int temp_limits[3] = { 55000, 60000, 65000 }; module_param_array(temp_limits, int, NULL, 0444); MODULE_PARM_DESC(temp_limits, @@ -53,9 +55,8 @@ static void gpd_pocket_fan_worker(struct work_struct *work) if (thermal_zone_get_temp(fan->dts0, &t0) || thermal_zone_get_temp(fan->dts1, &t1)) { dev_warn(fan->dev, "Error getting temperature\n"); - queue_delayed_work(system_wq, &fan->work, - msecs_to_jiffies(1000)); - return; + speed = MAX_SPEED; + goto set_speed; } temp = max(t0, t1); @@ -79,8 +80,9 @@ static void gpd_pocket_fan_worker(struct work_struct *work) speed = i; if (fan->last_speed <= 0 && speed) - speed = 3; /* kick start motor */ + speed = MAX_SPEED; /* kick start motor */ +set_speed: gpd_pocket_fan_set_speed(fan, speed); /* When mostly idle (low temp/speed), slow down the poll interval. */ -- cgit v1.2.3 From 594ce6db326e3a2bff9a8e04cc333dea5467b020 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 19 Jan 2018 21:47:08 +0100 Subject: platform/x86: GPD pocket fan: Use a min-speed of 2 while charging Newer versions of the GPD pocket BIOS set the fan-speed to 2 when a charger gets plugged in while the device is off. Mirror this in our fan driver and use a minimum speed of 2 while charging, Cc: James Suggested-by: James Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/gpd-pocket-fan.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c index 1fdf2205730d..2652eb40e5bc 100644 --- a/drivers/platform/x86/gpd-pocket-fan.c +++ b/drivers/platform/x86/gpd-pocket-fan.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,11 @@ module_param(hysteresis, int, 0444); MODULE_PARM_DESC(hysteresis, "Hysteresis in milli-celcius before lowering the fan speed"); +static int speed_on_ac = 2; +module_param(speed_on_ac, int, 0444); +MODULE_PARM_DESC(speed_on_ac, + "minimum fan speed to allow when system is powered by AC"); + struct gpd_pocket_fan_data { struct device *dev; struct thermal_zone_device *dts0; @@ -46,11 +52,19 @@ static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data *fan, int speed) fan->last_speed = speed; } +static int gpd_pocket_fan_min_speed(void) +{ + if (power_supply_is_system_supplied()) + return speed_on_ac; + else + return 0; +} + static void gpd_pocket_fan_worker(struct work_struct *work) { struct gpd_pocket_fan_data *fan = container_of(work, struct gpd_pocket_fan_data, work.work); - int t0, t1, temp, speed, i; + int t0, t1, temp, speed, min_speed, i; if (thermal_zone_get_temp(fan->dts0, &t0) || thermal_zone_get_temp(fan->dts1, &t1)) { @@ -62,9 +76,10 @@ static void gpd_pocket_fan_worker(struct work_struct *work) temp = max(t0, t1); speed = fan->last_speed; + min_speed = gpd_pocket_fan_min_speed(); /* Determine minimum speed */ - for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { + for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) { if (temp < temp_limits[i]) break; } @@ -72,7 +87,7 @@ static void gpd_pocket_fan_worker(struct work_struct *work) speed = i; /* Use hysteresis before lowering speed again */ - for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { + for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) { if (temp <= (temp_limits[i] - hysteresis)) break; } @@ -113,6 +128,11 @@ static int gpd_pocket_fan_probe(struct platform_device *pdev) hysteresis); return -EINVAL; } + if (speed_on_ac < 0 || speed_on_ac > MAX_SPEED) { + dev_err(&pdev->dev, "Invalid speed_on_ac %d (must be between 0 and 3)\n", + speed_on_ac); + return -EINVAL; + } fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); if (!fan) @@ -157,7 +177,7 @@ static int gpd_pocket_fan_suspend(struct device *dev) { struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev); - gpd_pocket_fan_set_speed(fan, 0); + gpd_pocket_fan_set_speed(fan, gpd_pocket_fan_min_speed()); return 0; } -- cgit v1.2.3 From e5778689a9653c0f364efbbd6b9bdd0527e7d8cb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 19 Jan 2018 21:47:09 +0100 Subject: platform/x86: GPD pocket fan: Stop work on suspend Stop the work on suspend, otherwise it may run between our suspend method running and the system suspending, possibly restarting the fan which we've just stopped. Note we already requeue the work on resume, so that we get a fresh speed at resume. Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/gpd-pocket-fan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c index 2652eb40e5bc..2d645c505f81 100644 --- a/drivers/platform/x86/gpd-pocket-fan.c +++ b/drivers/platform/x86/gpd-pocket-fan.c @@ -177,6 +177,7 @@ static int gpd_pocket_fan_suspend(struct device *dev) { struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev); + cancel_delayed_work_sync(&fan->work); gpd_pocket_fan_set_speed(fan, gpd_pocket_fan_min_speed()); return 0; } -- cgit v1.2.3 From d6fa7588fd7a8def4c747c0c574ce85d453e3788 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 24 Jan 2018 19:35:45 +0100 Subject: Revert "apple-gmux: lock iGP IO to protect from vgaarb changes" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 4eebd5a4e726 ("apple-gmux: lock iGP IO to protect from vgaarb changes") amended this driver's ->probe hook to lock decoding of normal (non-legacy) I/O space accesses to the integrated GPU on dual-GPU MacBook Pros. The lock stays in place until the driver is unbound. The change was made to work around an issue with the out-of-tree nvidia graphics driver (available at http://www.nvidia.com/object/unix.html). It contains the following sequence in nvidia/nv.c: #if defined(CONFIG_VGA_ARB) && !defined(NVCPU_PPC64LE) #if defined(VGA_DEFAULT_DEVICE) vga_tryget(VGA_DEFAULT_DEVICE, VGA_RSRC_LEGACY_MASK); #endif vga_set_legacy_decoding(dev, VGA_RSRC_NONE); #endif This code was reported to cause deadlocks with VFIO already in 2013: https://devtalk.nvidia.com/default/topic/545560 I've reported the issue to Nvidia developers once more in 2017: https://www.spinics.net/lists/dri-devel/msg138754.html On the MacBookPro10,1, this code apparently breaks backlight control (which is handled by apple-gmux via an I/O region starting at 0x700), as reported by Petri Hodju: https://bugzilla.kernel.org/show_bug.cgi?id=86121 I tried to replicate Petri's observations on my MacBook9,1, which uses the same Intel Ivy Bridge + Nvidia GeForce GT 650M architecture, to no avail. On my machine apple-gmux' I/O region remains accessible even with the nvidia driver loaded and commit 4eebd5a4e726 reverted. Petri reported that apple-gmux becomes accessible again after a suspend/resume cycle because the BIOS changed the VGA routing on the root port to the Nvidia GPU. Perhaps this is a BIOS issue after all that can be fixed with an update? In any case, the change made by commit 4eebd5a4e726 has turned out to cause two new issues: * Wilfried Klaebe reports a deadlock when launching Xorg because it opens /dev/vga_arbiter and calls vga_get(), but apple-gmux is holding a lock on I/O space indefinitely. It looks like apple-gmux' current behavior is an abuse of the vgaarb API as locks are not meant to be held for longer periods: https://bugzilla.kernel.org/show_bug.cgi?id=88861#c11 https://bugzilla.kernel.org/attachment.cgi?id=217541 * On dual GPU MacBook Pros introduced since 2013, the integrated GPU is powergated on boot und thus becomes invisible to Linux unless a custom EFI protocol is used to leave it powered on. (A patch exists but is not in mainline yet due to several negative side effects.) On these machines, locking I/O to the integrated GPU (as done by 4eebd5a4e726) fails and backlight control is therefore broken: https://bugzilla.kernel.org/show_bug.cgi?id=105051 So let's revert commit 4eebd5a4e726 please. Users experiencing the issue with the proprietary nvidia driver can comment out the above- quoted problematic code as a workaround (or try updating the BIOS). Cc: Petri Hodju Cc: Bjorn Helgaas Cc: Bruno Prémont Cc: Andy Ritger Cc: Ronald Tschalär Tested-by: Wilfried Klaebe Signed-off-by: Lukas Wunner Cc: stable@vger.kernel.org Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/apple-gmux.c | 48 +-------------------------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 623d322447a2..7c4eb86c851e 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -54,7 +53,6 @@ struct apple_gmux_data { bool indexed; struct mutex index_lock; - struct pci_dev *pdev; struct backlight_device *bdev; /* switcheroo data */ @@ -599,23 +597,6 @@ static int gmux_resume(struct device *dev) return 0; } -static struct pci_dev *gmux_get_io_pdev(void) -{ - struct pci_dev *pdev = NULL; - - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) { - u16 cmd; - - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_IO)) - continue; - - return pdev; - } - - return NULL; -} - static int is_thunderbolt(struct device *dev, void *data) { return to_pci_dev(dev)->is_thunderbolt; @@ -631,7 +612,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) int ret = -ENXIO; acpi_status status; unsigned long long gpe; - struct pci_dev *pdev = NULL; if (apple_gmux_data) return -EBUSY; @@ -682,7 +662,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ver_minor = (version >> 16) & 0xff; ver_release = (version >> 8) & 0xff; } else { - pr_info("gmux device not present or IO disabled\n"); + pr_info("gmux device not present\n"); ret = -ENODEV; goto err_release; } @@ -690,23 +670,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, ver_release, (gmux_data->indexed ? "indexed" : "classic")); - /* - * Apple systems with gmux are EFI based and normally don't use - * VGA. In addition changing IO+MEM ownership between IGP and dGPU - * disables IO/MEM used for backlight control on some systems. - * Lock IO+MEM to GPU with active IO to prevent switch. - */ - pdev = gmux_get_io_pdev(); - if (pdev && vga_tryget(pdev, - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) { - pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n", - pci_name(pdev)); - ret = -EBUSY; - goto err_release; - } else if (pdev) - pr_info("locked IO for PCI:%s\n", pci_name(pdev)); - gmux_data->pdev = pdev; - memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_PLATFORM; props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); @@ -822,10 +785,6 @@ err_enable_gpe: err_notify: backlight_device_unregister(bdev); err_release: - if (gmux_data->pdev) - vga_put(gmux_data->pdev, - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); - pci_dev_put(pdev); release_region(gmux_data->iostart, gmux_data->iolen); err_free: kfree(gmux_data); @@ -845,11 +804,6 @@ static void gmux_remove(struct pnp_dev *pnp) &gmux_notify_handler); } - if (gmux_data->pdev) { - vga_put(gmux_data->pdev, - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); - pci_dev_put(gmux_data->pdev); - } backlight_device_unregister(gmux_data->bdev); release_region(gmux_data->iostart, gmux_data->iolen); -- cgit v1.2.3 From 1f976f6978bf6156ce822eb279ac86c519b10329 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 17 Jan 2018 18:21:53 +0000 Subject: platform/x86: Move Mellanox platform hotplug driver to platform/mellanox In preparation for making the hotplug driver build for different architectures, move mlxcpld-hotplug.c to platform/mellanox and the header to include/linux/platform_data as mlxreg.h to reflect the new interface changes to come. Replace references to CPLD with REG throughout the files, consistent with the new name. Signed-off-by: Vadim Pasternak Acked-by: Andy Shevchenko [dvhart: update copyright, rewrite commit message] Signed-off-by: Darren Hart (VMware) --- MAINTAINERS | 7 +- drivers/platform/Kconfig | 2 + drivers/platform/Makefile | 1 + drivers/platform/mellanox/Kconfig | 25 ++ drivers/platform/mellanox/Makefile | 6 + drivers/platform/mellanox/mlxreg-hotplug.c | 514 +++++++++++++++++++++++++ drivers/platform/x86/Kconfig | 8 - drivers/platform/x86/Makefile | 1 - drivers/platform/x86/mlx-platform.c | 18 +- drivers/platform/x86/mlxcpld-hotplug.c | 515 -------------------------- include/linux/platform_data/mlxcpld-hotplug.h | 99 ----- include/linux/platform_data/mlxreg.h | 98 +++++ 12 files changed, 659 insertions(+), 635 deletions(-) create mode 100644 drivers/platform/mellanox/Kconfig create mode 100644 drivers/platform/mellanox/Makefile create mode 100644 drivers/platform/mellanox/mlxreg-hotplug.c delete mode 100644 drivers/platform/x86/mlxcpld-hotplug.c delete mode 100644 include/linux/platform_data/mlxcpld-hotplug.h create mode 100644 include/linux/platform_data/mlxreg.h diff --git a/MAINTAINERS b/MAINTAINERS index bc4d77695918..c07e1144688a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8860,12 +8860,13 @@ W: http://www.mellanox.com Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/mellanox/mlxfw/ -MELLANOX MLX CPLD HOTPLUG DRIVER +MELLANOX HARDWARE PLATFORM SUPPORT +M: Andy Shevchenko +M: Darren Hart M: Vadim Pasternak L: platform-driver-x86@vger.kernel.org S: Supported -F: drivers/platform/x86/mlxcpld-hotplug.c -F: include/linux/platform_data/mlxcpld-hotplug.h +F: drivers/platform/mellanox/ MELLANOX MLX4 core VPI driver M: Tariq Toukan diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index c11db8bceea1..d4c2e424a700 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -8,3 +8,5 @@ endif source "drivers/platform/goldfish/Kconfig" source "drivers/platform/chrome/Kconfig" + +source "drivers/platform/mellanox/Kconfig" diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index d3a6630266a0..4b2ce58bcd9c 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_X86) += x86/ +obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/ obj-$(CONFIG_MIPS) += mips/ obj-$(CONFIG_OLPC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig new file mode 100644 index 000000000000..d73529203327 --- /dev/null +++ b/drivers/platform/mellanox/Kconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Platform support for Mellanox hardware +# + +menuconfig MELLANOX_PLATFORM + bool "Platform support for Mellanox hardware" + depends on X86 || COMPILE_TEST + ---help--- + Say Y here to get to see options for platform support for + Mellanox systems. This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if MELLANOX_PLATFORM + +config MLXREG_HOTPLUG + tristate "Mellanox platform hotplug driver support" + depends on HWMON + depends on I2C + ---help--- + This driver handles hot-plug events for the power suppliers, power + cables and fans on the wide range Mellanox IB and Ethernet systems. + +endif # MELLANOX_PLATFORM diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile new file mode 100644 index 000000000000..7c8385e497a8 --- /dev/null +++ b/drivers/platform/mellanox/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for linux/drivers/platform/mellanox +# Mellanox Platform-Specific Drivers +# +obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c new file mode 100644 index 000000000000..5cfc82ba34be --- /dev/null +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016-2018 Vadim Pasternak + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Offset of event and mask registers from status register */ +#define MLXREG_HOTPLUG_EVENT_OFF 1 +#define MLXREG_HOTPLUG_MASK_OFF 2 +#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 + +#define MLXREG_HOTPLUG_ATTRS_NUM 8 + +/** + * enum mlxreg_hotplug_attr_type - sysfs attributes for hotplug events: + * @MLXREG_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute; + * @MLXREG_HOTPLUG_ATTR_TYPE_PWR: power cable attribute; + * @MLXREG_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute; + */ +enum mlxreg_hotplug_attr_type { + MLXREG_HOTPLUG_ATTR_TYPE_PSU, + MLXREG_HOTPLUG_ATTR_TYPE_PWR, + MLXREG_HOTPLUG_ATTR_TYPE_FAN, +}; + +/** + * struct mlxreg_hotplug_priv_data - platform private data: + * @irq: platform interrupt number; + * @pdev: platform device; + * @plat: platform data; + * @hwmon: hwmon device; + * @mlxreg_hotplug_attr: sysfs attributes array; + * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; + * @group: sysfs attribute group; + * @groups: list of sysfs attribute group for hwmon registration; + * @dwork: delayed work template; + * @lock: spin lock; + * @aggr_cache: last value of aggregation register status; + * @psu_cache: last value of PSU register status; + * @pwr_cache: last value of power register status; + * @fan_cache: last value of FAN register status; + */ +struct mlxreg_hotplug_priv_data { + int irq; + struct platform_device *pdev; + struct mlxreg_hotplug_platform_data *plat; + struct device *hwmon; + struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_NUM + 1]; + struct sensor_device_attribute_2 + mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_NUM]; + struct attribute_group group; + const struct attribute_group *groups[2]; + struct delayed_work dwork; + spinlock_t lock; + u8 aggr_cache; + u8 psu_cache; + u8 pwr_cache; + u8 fan_cache; +}; + +static ssize_t mlxreg_hotplug_attr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + u8 reg_val = 0; + + switch (nr) { + case MLXREG_HOTPLUG_ATTR_TYPE_PSU: + /* Bit = 0 : PSU is present. */ + reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index)); + break; + + case MLXREG_HOTPLUG_ATTR_TYPE_PWR: + /* Bit = 1 : power cable is attached. */ + reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index % + priv->plat->pwr_count)); + break; + + case MLXREG_HOTPLUG_ATTR_TYPE_FAN: + /* Bit = 0 : FAN is present. */ + reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index % + priv->plat->fan_count)); + break; + } + + return sprintf(buf, "%u\n", reg_val); +} + +#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i] +#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i] +static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) +{ + int num_attrs = priv->plat->psu_count + priv->plat->pwr_count + + priv->plat->fan_count; + int i; + + priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * + sizeof(struct attribute *), + GFP_KERNEL); + if (!priv->group.attrs) + return -ENOMEM; + + for (i = 0; i < num_attrs; i++) { + PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr; + + if (i < priv->plat->psu_count) { + PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, "psu%u", i + 1); + PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PSU; + } else if (i < priv->plat->psu_count + priv->plat->pwr_count) { + PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, "pwr%u", i % + priv->plat->pwr_count + 1); + PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PWR; + } else { + PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, "fan%u", i % + priv->plat->fan_count + 1); + PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_FAN; + } + + if (!PRIV_ATTR(i)->name) { + dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", + i + 1); + return -ENOMEM; + } + + PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name; + PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO; + PRIV_DEV_ATTR(i).dev_attr.show = mlxreg_hotplug_attr_show; + PRIV_DEV_ATTR(i).index = i; + sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr); + } + + priv->group.attrs = priv->mlxreg_hotplug_attr; + priv->groups[0] = &priv->group; + priv->groups[1] = NULL; + + return 0; +} + +static int mlxreg_hotplug_device_create(struct device *dev, + struct mlxreg_hotplug_device *item) +{ + item->adapter = i2c_get_adapter(item->bus); + if (!item->adapter) { + dev_err(dev, "Failed to get adapter for bus %d\n", + item->bus); + return -EFAULT; + } + + item->client = i2c_new_device(item->adapter, &item->brdinfo); + if (!item->client) { + dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", + item->brdinfo.type, item->bus, item->brdinfo.addr); + i2c_put_adapter(item->adapter); + item->adapter = NULL; + return -EFAULT; + } + + return 0; +} + +static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item) +{ + if (item->client) { + i2c_unregister_device(item->client); + item->client = NULL; + } + + if (item->adapter) { + i2c_put_adapter(item->adapter); + item->adapter = NULL; + } +} + +static inline void +mlxreg_hotplug_work_helper(struct device *dev, + struct mlxreg_hotplug_device *item, u8 is_inverse, + u16 offset, u8 mask, u8 *cache) +{ + u8 val, asserted; + int bit; + + /* Mask event. */ + outb(0, offset + MLXREG_HOTPLUG_MASK_OFF); + /* Read status. */ + val = inb(offset) & mask; + asserted = *cache ^ val; + *cache = val; + + /* + * Validate if item related to received signal type is valid. + * It should never happen, excepted the situation when some + * piece of hardware is broken. In such situation just produce + * error message and return. Caller must continue to handle the + * signals from other devices if any. + */ + if (unlikely(!item)) { + dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n", + offset, mask); + return; + } + + for_each_set_bit(bit, (unsigned long *)&asserted, 8) { + if (val & BIT(bit)) { + if (is_inverse) + mlxreg_hotplug_device_destroy(item + bit); + else + mlxreg_hotplug_device_create(dev, item + bit); + } else { + if (is_inverse) + mlxreg_hotplug_device_create(dev, item + bit); + else + mlxreg_hotplug_device_destroy(item + bit); + } + } + + /* Acknowledge event. */ + outb(0, offset + MLXREG_HOTPLUG_EVENT_OFF); + /* Unmask event. */ + outb(mask, offset + MLXREG_HOTPLUG_MASK_OFF); +} + +/* + * mlxreg_hotplug_work_handler - performs traversing of CPLD interrupt + * registers according to the below hierarchy schema: + * + * Aggregation registers (status/mask) + * PSU registers: *---* + * *-----------------* | | + * |status/event/mask|----->| * | + * *-----------------* | | + * Power registers: | | + * *-----------------* | | + * |status/event/mask|----->| * |---> CPU + * *-----------------* | | + * FAN registers: + * *-----------------* | | + * |status/event/mask|----->| * | + * *-----------------* | | + * *---* + * In case some system changed are detected: FAN in/out, PSU in/out, power + * cable attached/detached, relevant device is created or destroyed. + */ +static void mlxreg_hotplug_work_handler(struct work_struct *work) +{ + struct mlxreg_hotplug_priv_data *priv = container_of(work, + struct mlxreg_hotplug_priv_data, dwork.work); + u8 val, aggr_asserted; + unsigned long flags; + + /* Mask aggregation event. */ + outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF); + /* Read aggregation status. */ + val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask; + aggr_asserted = priv->aggr_cache ^ val; + priv->aggr_cache = val; + + /* Handle PSU configuration changes. */ + if (aggr_asserted & priv->plat->top_aggr_psu_mask) + mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu, + 1, priv->plat->psu_reg_offset, + priv->plat->psu_mask, + &priv->psu_cache); + + /* Handle power cable configuration changes. */ + if (aggr_asserted & priv->plat->top_aggr_pwr_mask) + mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr, + 0, priv->plat->pwr_reg_offset, + priv->plat->pwr_mask, + &priv->pwr_cache); + + /* Handle FAN configuration changes. */ + if (aggr_asserted & priv->plat->top_aggr_fan_mask) + mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan, + 1, priv->plat->fan_reg_offset, + priv->plat->fan_mask, + &priv->fan_cache); + + if (aggr_asserted) { + spin_lock_irqsave(&priv->lock, flags); + + /* + * It is possible, that some signals have been inserted, while + * interrupt has been masked by mlxreg_hotplug_work_handler. + * In this case such signals will be missed. In order to handle + * these signals delayed work is canceled and work task + * re-scheduled for immediate execution. It allows to handle + * missed signals, if any. In other case work handler just + * validates that no new signals have been received during + * masking. + */ + cancel_delayed_work(&priv->dwork); + schedule_delayed_work(&priv->dwork, 0); + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + + /* Unmask aggregation event (no need acknowledge). */ + outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + + MLXREG_HOTPLUG_AGGR_MASK_OFF); +} + +static void mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) +{ + /* Clear psu presense event. */ + outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); + /* Set psu initial status as mask and unmask psu event. */ + priv->psu_cache = priv->plat->psu_mask; + outb(priv->plat->psu_mask, priv->plat->psu_reg_offset + + MLXREG_HOTPLUG_MASK_OFF); + + /* Clear power cable event. */ + outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); + /* Keep power initial status as zero and unmask power event. */ + outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset + + MLXREG_HOTPLUG_MASK_OFF); + + /* Clear fan presense event. */ + outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); + /* Set fan initial status as mask and unmask fan event. */ + priv->fan_cache = priv->plat->fan_mask; + outb(priv->plat->fan_mask, priv->plat->fan_reg_offset + + MLXREG_HOTPLUG_MASK_OFF); + + /* Keep aggregation initial status as zero and unmask events. */ + outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + + MLXREG_HOTPLUG_AGGR_MASK_OFF); + + /* Invoke work handler for initializing hot plug devices setting. */ + mlxreg_hotplug_work_handler(&priv->dwork.work); + + enable_irq(priv->irq); +} + +static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) +{ + int i; + + disable_irq(priv->irq); + cancel_delayed_work_sync(&priv->dwork); + + /* Mask aggregation event. */ + outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF); + + /* Mask psu presense event. */ + outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_MASK_OFF); + /* Clear psu presense event. */ + outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); + + /* Mask power cable event. */ + outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_MASK_OFF); + /* Clear power cable event. */ + outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); + + /* Mask fan presense event. */ + outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_MASK_OFF); + /* Clear fan presense event. */ + outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); + + /* Remove all the attached devices. */ + for (i = 0; i < priv->plat->psu_count; i++) + mlxreg_hotplug_device_destroy(priv->plat->psu + i); + + for (i = 0; i < priv->plat->pwr_count; i++) + mlxreg_hotplug_device_destroy(priv->plat->pwr + i); + + for (i = 0; i < priv->plat->fan_count; i++) + mlxreg_hotplug_device_destroy(priv->plat->fan + i); +} + +static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) +{ + struct mlxreg_hotplug_priv_data *priv = + (struct mlxreg_hotplug_priv_data *)dev; + + /* Schedule work task for immediate execution.*/ + schedule_delayed_work(&priv->dwork, 0); + + return IRQ_HANDLED; +} + +static int mlxreg_hotplug_probe(struct platform_device *pdev) +{ + struct mlxreg_hotplug_platform_data *pdata; + struct mlxreg_hotplug_priv_data *priv; + int err; + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "Failed to get platform data.\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdev = pdev; + priv->plat = pdata; + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(&pdev->dev, "Failed to get platform irq: %d\n", + priv->irq); + return priv->irq; + } + + err = devm_request_irq(&pdev->dev, priv->irq, + mlxreg_hotplug_irq_handler, 0, pdev->name, + priv); + if (err) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", err); + return err; + } + disable_irq(priv->irq); + + INIT_DELAYED_WORK(&priv->dwork, mlxreg_hotplug_work_handler); + spin_lock_init(&priv->lock); + + err = mlxreg_hotplug_attr_init(priv); + if (err) { + dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err); + return err; + } + + priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, + "mlxreg_hotplug", priv, priv->groups); + if (IS_ERR(priv->hwmon)) { + dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", + PTR_ERR(priv->hwmon)); + return PTR_ERR(priv->hwmon); + } + + platform_set_drvdata(pdev, priv); + + /* Perform initial interrupts setup. */ + mlxreg_hotplug_set_irq(priv); + + return 0; +} + +static int mlxreg_hotplug_remove(struct platform_device *pdev) +{ + struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev); + + /* Clean interrupts setup. */ + mlxreg_hotplug_unset_irq(priv); + + return 0; +} + +static struct platform_driver mlxreg_hotplug_driver = { + .driver = { + .name = "mlxreg-hotplug", + }, + .probe = mlxreg_hotplug_probe, + .remove = mlxreg_hotplug_remove, +}; + +module_platform_driver(mlxreg_hotplug_driver); + +MODULE_AUTHOR("Vadim Pasternak "); +MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:mlxreg-hotplug"); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index aaca22fb45b9..53f52f9df2c5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1169,14 +1169,6 @@ config MLX_PLATFORM If you have a Mellanox system, say Y or M here. -config MLX_CPLD_PLATFORM - tristate "Mellanox platform hotplug driver support" - select HWMON - select I2C - ---help--- - This driver handles hot-plug events for the power suppliers, power - cables and fans on the wide range Mellanox IB and Ethernet systems. - config INTEL_TURBO_MAX_3 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" depends on X86_64 && SCHED_MC_PRIO diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 57f37e55786a..c388608ad2a3 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -88,6 +88,5 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o obj-$(CONFIG_PMC_ATOM) += pmc_atom.o obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o -obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 504256c3660d..0fbec1f1ca40 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #define MLX_PLAT_DEVICE_NAME "mlxplat" @@ -138,7 +138,7 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { }; /* Platform hotplug devices */ -static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = { +static struct mlxreg_hotplug_device mlxplat_mlxcpld_psu[] = { { .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, .bus = 10, @@ -149,7 +149,7 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = { }, }; -static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = { +static struct mlxreg_hotplug_device mlxplat_mlxcpld_pwr[] = { { .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, .bus = 10, @@ -160,7 +160,7 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = { }, }; -static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = { +static struct mlxreg_hotplug_device mlxplat_mlxcpld_fan[] = { { .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, .bus = 11, @@ -181,7 +181,7 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = { /* Platform hotplug default data */ static -struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = { +struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_default_data = { .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, @@ -203,7 +203,7 @@ struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = { /* Platform hotplug MSN21xx system family data */ static -struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { +struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, @@ -213,11 +213,11 @@ struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { }; static struct resource mlxplat_mlxcpld_resources[] = { - [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), + [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), }; static struct platform_device *mlxplat_dev; -static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug; +static struct mlxreg_hotplug_platform_data *mlxplat_hotplug; static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { @@ -329,7 +329,7 @@ static int __init mlxplat_init(void) } priv->pdev_hotplug = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxcpld-hotplug", + &mlxplat_dev->dev, "mlxreg-hotplug", PLATFORM_DEVID_NONE, mlxplat_mlxcpld_resources, ARRAY_SIZE(mlxplat_mlxcpld_resources), diff --git a/drivers/platform/x86/mlxcpld-hotplug.c b/drivers/platform/x86/mlxcpld-hotplug.c deleted file mode 100644 index aff3686b3b37..000000000000 --- a/drivers/platform/x86/mlxcpld-hotplug.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * drivers/platform/x86/mlxcpld-hotplug.c - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. - * Copyright (c) 2016 Vadim Pasternak - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Offset of event and mask registers from status register */ -#define MLXCPLD_HOTPLUG_EVENT_OFF 1 -#define MLXCPLD_HOTPLUG_MASK_OFF 2 -#define MLXCPLD_HOTPLUG_AGGR_MASK_OFF 1 - -#define MLXCPLD_HOTPLUG_ATTRS_NUM 8 - -/** - * enum mlxcpld_hotplug_attr_type - sysfs attributes for hotplug events: - * @MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute; - * @MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: power cable attribute; - * @MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute; - */ -enum mlxcpld_hotplug_attr_type { - MLXCPLD_HOTPLUG_ATTR_TYPE_PSU, - MLXCPLD_HOTPLUG_ATTR_TYPE_PWR, - MLXCPLD_HOTPLUG_ATTR_TYPE_FAN, -}; - -/** - * struct mlxcpld_hotplug_priv_data - platform private data: - * @irq: platform interrupt number; - * @pdev: platform device; - * @plat: platform data; - * @hwmon: hwmon device; - * @mlxcpld_hotplug_attr: sysfs attributes array; - * @mlxcpld_hotplug_dev_attr: sysfs sensor device attribute array; - * @group: sysfs attribute group; - * @groups: list of sysfs attribute group for hwmon registration; - * @dwork: delayed work template; - * @lock: spin lock; - * @aggr_cache: last value of aggregation register status; - * @psu_cache: last value of PSU register status; - * @pwr_cache: last value of power register status; - * @fan_cache: last value of FAN register status; - */ -struct mlxcpld_hotplug_priv_data { - int irq; - struct platform_device *pdev; - struct mlxcpld_hotplug_platform_data *plat; - struct device *hwmon; - struct attribute *mlxcpld_hotplug_attr[MLXCPLD_HOTPLUG_ATTRS_NUM + 1]; - struct sensor_device_attribute_2 - mlxcpld_hotplug_dev_attr[MLXCPLD_HOTPLUG_ATTRS_NUM]; - struct attribute_group group; - const struct attribute_group *groups[2]; - struct delayed_work dwork; - spinlock_t lock; - u8 aggr_cache; - u8 psu_cache; - u8 pwr_cache; - u8 fan_cache; -}; - -static ssize_t mlxcpld_hotplug_attr_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev); - int index = to_sensor_dev_attr_2(attr)->index; - int nr = to_sensor_dev_attr_2(attr)->nr; - u8 reg_val = 0; - - switch (nr) { - case MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: - /* Bit = 0 : PSU is present. */ - reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index)); - break; - - case MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: - /* Bit = 1 : power cable is attached. */ - reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index % - priv->plat->pwr_count)); - break; - - case MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: - /* Bit = 0 : FAN is present. */ - reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index % - priv->plat->fan_count)); - break; - } - - return sprintf(buf, "%u\n", reg_val); -} - -#define PRIV_ATTR(i) priv->mlxcpld_hotplug_attr[i] -#define PRIV_DEV_ATTR(i) priv->mlxcpld_hotplug_dev_attr[i] -static int mlxcpld_hotplug_attr_init(struct mlxcpld_hotplug_priv_data *priv) -{ - int num_attrs = priv->plat->psu_count + priv->plat->pwr_count + - priv->plat->fan_count; - int i; - - priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * - sizeof(struct attribute *), - GFP_KERNEL); - if (!priv->group.attrs) - return -ENOMEM; - - for (i = 0; i < num_attrs; i++) { - PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr; - - if (i < priv->plat->psu_count) { - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, - GFP_KERNEL, "psu%u", i + 1); - PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PSU; - } else if (i < priv->plat->psu_count + priv->plat->pwr_count) { - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, - GFP_KERNEL, "pwr%u", i % - priv->plat->pwr_count + 1); - PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PWR; - } else { - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, - GFP_KERNEL, "fan%u", i % - priv->plat->fan_count + 1); - PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_FAN; - } - - if (!PRIV_ATTR(i)->name) { - dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", - i + 1); - return -ENOMEM; - } - - PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name; - PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO; - PRIV_DEV_ATTR(i).dev_attr.show = mlxcpld_hotplug_attr_show; - PRIV_DEV_ATTR(i).index = i; - sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr); - } - - priv->group.attrs = priv->mlxcpld_hotplug_attr; - priv->groups[0] = &priv->group; - priv->groups[1] = NULL; - - return 0; -} - -static int mlxcpld_hotplug_device_create(struct device *dev, - struct mlxcpld_hotplug_device *item) -{ - item->adapter = i2c_get_adapter(item->bus); - if (!item->adapter) { - dev_err(dev, "Failed to get adapter for bus %d\n", - item->bus); - return -EFAULT; - } - - item->client = i2c_new_device(item->adapter, &item->brdinfo); - if (!item->client) { - dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", - item->brdinfo.type, item->bus, item->brdinfo.addr); - i2c_put_adapter(item->adapter); - item->adapter = NULL; - return -EFAULT; - } - - return 0; -} - -static void mlxcpld_hotplug_device_destroy(struct mlxcpld_hotplug_device *item) -{ - if (item->client) { - i2c_unregister_device(item->client); - item->client = NULL; - } - - if (item->adapter) { - i2c_put_adapter(item->adapter); - item->adapter = NULL; - } -} - -static inline void -mlxcpld_hotplug_work_helper(struct device *dev, - struct mlxcpld_hotplug_device *item, u8 is_inverse, - u16 offset, u8 mask, u8 *cache) -{ - u8 val, asserted; - int bit; - - /* Mask event. */ - outb(0, offset + MLXCPLD_HOTPLUG_MASK_OFF); - /* Read status. */ - val = inb(offset) & mask; - asserted = *cache ^ val; - *cache = val; - - /* - * Validate if item related to received signal type is valid. - * It should never happen, excepted the situation when some - * piece of hardware is broken. In such situation just produce - * error message and return. Caller must continue to handle the - * signals from other devices if any. - */ - if (unlikely(!item)) { - dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n", - offset, mask); - return; - } - - for_each_set_bit(bit, (unsigned long *)&asserted, 8) { - if (val & BIT(bit)) { - if (is_inverse) - mlxcpld_hotplug_device_destroy(item + bit); - else - mlxcpld_hotplug_device_create(dev, item + bit); - } else { - if (is_inverse) - mlxcpld_hotplug_device_create(dev, item + bit); - else - mlxcpld_hotplug_device_destroy(item + bit); - } - } - - /* Acknowledge event. */ - outb(0, offset + MLXCPLD_HOTPLUG_EVENT_OFF); - /* Unmask event. */ - outb(mask, offset + MLXCPLD_HOTPLUG_MASK_OFF); -} - -/* - * mlxcpld_hotplug_work_handler - performs traversing of CPLD interrupt - * registers according to the below hierarchy schema: - * - * Aggregation registers (status/mask) - * PSU registers: *---* - * *-----------------* | | - * |status/event/mask|----->| * | - * *-----------------* | | - * Power registers: | | - * *-----------------* | | - * |status/event/mask|----->| * |---> CPU - * *-----------------* | | - * FAN registers: - * *-----------------* | | - * |status/event/mask|----->| * | - * *-----------------* | | - * *---* - * In case some system changed are detected: FAN in/out, PSU in/out, power - * cable attached/detached, relevant device is created or destroyed. - */ -static void mlxcpld_hotplug_work_handler(struct work_struct *work) -{ - struct mlxcpld_hotplug_priv_data *priv = container_of(work, - struct mlxcpld_hotplug_priv_data, dwork.work); - u8 val, aggr_asserted; - unsigned long flags; - - /* Mask aggregation event. */ - outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); - /* Read aggregation status. */ - val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask; - aggr_asserted = priv->aggr_cache ^ val; - priv->aggr_cache = val; - - /* Handle PSU configuration changes. */ - if (aggr_asserted & priv->plat->top_aggr_psu_mask) - mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu, - 1, priv->plat->psu_reg_offset, - priv->plat->psu_mask, - &priv->psu_cache); - - /* Handle power cable configuration changes. */ - if (aggr_asserted & priv->plat->top_aggr_pwr_mask) - mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr, - 0, priv->plat->pwr_reg_offset, - priv->plat->pwr_mask, - &priv->pwr_cache); - - /* Handle FAN configuration changes. */ - if (aggr_asserted & priv->plat->top_aggr_fan_mask) - mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan, - 1, priv->plat->fan_reg_offset, - priv->plat->fan_mask, - &priv->fan_cache); - - if (aggr_asserted) { - spin_lock_irqsave(&priv->lock, flags); - - /* - * It is possible, that some signals have been inserted, while - * interrupt has been masked by mlxcpld_hotplug_work_handler. - * In this case such signals will be missed. In order to handle - * these signals delayed work is canceled and work task - * re-scheduled for immediate execution. It allows to handle - * missed signals, if any. In other case work handler just - * validates that no new signals have been received during - * masking. - */ - cancel_delayed_work(&priv->dwork); - schedule_delayed_work(&priv->dwork, 0); - - spin_unlock_irqrestore(&priv->lock, flags); - - return; - } - - /* Unmask aggregation event (no need acknowledge). */ - outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + - MLXCPLD_HOTPLUG_AGGR_MASK_OFF); -} - -static void mlxcpld_hotplug_set_irq(struct mlxcpld_hotplug_priv_data *priv) -{ - /* Clear psu presense event. */ - outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); - /* Set psu initial status as mask and unmask psu event. */ - priv->psu_cache = priv->plat->psu_mask; - outb(priv->plat->psu_mask, priv->plat->psu_reg_offset + - MLXCPLD_HOTPLUG_MASK_OFF); - - /* Clear power cable event. */ - outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); - /* Keep power initial status as zero and unmask power event. */ - outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset + - MLXCPLD_HOTPLUG_MASK_OFF); - - /* Clear fan presense event. */ - outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); - /* Set fan initial status as mask and unmask fan event. */ - priv->fan_cache = priv->plat->fan_mask; - outb(priv->plat->fan_mask, priv->plat->fan_reg_offset + - MLXCPLD_HOTPLUG_MASK_OFF); - - /* Keep aggregation initial status as zero and unmask events. */ - outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + - MLXCPLD_HOTPLUG_AGGR_MASK_OFF); - - /* Invoke work handler for initializing hot plug devices setting. */ - mlxcpld_hotplug_work_handler(&priv->dwork.work); - - enable_irq(priv->irq); -} - -static void mlxcpld_hotplug_unset_irq(struct mlxcpld_hotplug_priv_data *priv) -{ - int i; - - disable_irq(priv->irq); - cancel_delayed_work_sync(&priv->dwork); - - /* Mask aggregation event. */ - outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); - - /* Mask psu presense event. */ - outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); - /* Clear psu presense event. */ - outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); - - /* Mask power cable event. */ - outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); - /* Clear power cable event. */ - outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); - - /* Mask fan presense event. */ - outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); - /* Clear fan presense event. */ - outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); - - /* Remove all the attached devices. */ - for (i = 0; i < priv->plat->psu_count; i++) - mlxcpld_hotplug_device_destroy(priv->plat->psu + i); - - for (i = 0; i < priv->plat->pwr_count; i++) - mlxcpld_hotplug_device_destroy(priv->plat->pwr + i); - - for (i = 0; i < priv->plat->fan_count; i++) - mlxcpld_hotplug_device_destroy(priv->plat->fan + i); -} - -static irqreturn_t mlxcpld_hotplug_irq_handler(int irq, void *dev) -{ - struct mlxcpld_hotplug_priv_data *priv = - (struct mlxcpld_hotplug_priv_data *)dev; - - /* Schedule work task for immediate execution.*/ - schedule_delayed_work(&priv->dwork, 0); - - return IRQ_HANDLED; -} - -static int mlxcpld_hotplug_probe(struct platform_device *pdev) -{ - struct mlxcpld_hotplug_platform_data *pdata; - struct mlxcpld_hotplug_priv_data *priv; - int err; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "Failed to get platform data.\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->pdev = pdev; - priv->plat = pdata; - - priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq: %d\n", - priv->irq); - return priv->irq; - } - - err = devm_request_irq(&pdev->dev, priv->irq, - mlxcpld_hotplug_irq_handler, 0, pdev->name, - priv); - if (err) { - dev_err(&pdev->dev, "Failed to request irq: %d\n", err); - return err; - } - disable_irq(priv->irq); - - INIT_DELAYED_WORK(&priv->dwork, mlxcpld_hotplug_work_handler); - spin_lock_init(&priv->lock); - - err = mlxcpld_hotplug_attr_init(priv); - if (err) { - dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err); - return err; - } - - priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, - "mlxcpld_hotplug", priv, priv->groups); - if (IS_ERR(priv->hwmon)) { - dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", - PTR_ERR(priv->hwmon)); - return PTR_ERR(priv->hwmon); - } - - platform_set_drvdata(pdev, priv); - - /* Perform initial interrupts setup. */ - mlxcpld_hotplug_set_irq(priv); - - return 0; -} - -static int mlxcpld_hotplug_remove(struct platform_device *pdev) -{ - struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev); - - /* Clean interrupts setup. */ - mlxcpld_hotplug_unset_irq(priv); - - return 0; -} - -static struct platform_driver mlxcpld_hotplug_driver = { - .driver = { - .name = "mlxcpld-hotplug", - }, - .probe = mlxcpld_hotplug_probe, - .remove = mlxcpld_hotplug_remove, -}; - -module_platform_driver(mlxcpld_hotplug_driver); - -MODULE_AUTHOR("Vadim Pasternak "); -MODULE_DESCRIPTION("Mellanox CPLD hotplug platform driver"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("platform:mlxcpld-hotplug"); diff --git a/include/linux/platform_data/mlxcpld-hotplug.h b/include/linux/platform_data/mlxcpld-hotplug.h deleted file mode 100644 index e4cfcffaa6f4..000000000000 --- a/include/linux/platform_data/mlxcpld-hotplug.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * include/linux/platform_data/mlxcpld-hotplug.h - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. - * Copyright (c) 2016 Vadim Pasternak - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H -#define __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H - -/** - * struct mlxcpld_hotplug_device - I2C device data: - * @adapter: I2C device adapter; - * @client: I2C device client; - * @brdinfo: device board information; - * @bus: I2C bus, where device is attached; - * - * Structure represents I2C hotplug device static data (board topology) and - * dynamic data (related kernel objects handles). - */ -struct mlxcpld_hotplug_device { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info brdinfo; - u16 bus; -}; - -/** - * struct mlxcpld_hotplug_platform_data - device platform data: - * @top_aggr_offset: offset of top aggregation interrupt register; - * @top_aggr_mask: top aggregation interrupt common mask; - * @top_aggr_psu_mask: top aggregation interrupt PSU mask; - * @psu_reg_offset: offset of PSU interrupt register; - * @psu_mask: PSU interrupt mask; - * @psu_count: number of equipped replaceable PSUs; - * @psu: pointer to PSU devices data array; - * @top_aggr_pwr_mask: top aggregation interrupt power mask; - * @pwr_reg_offset: offset of power interrupt register - * @pwr_mask: power interrupt mask; - * @pwr_count: number of power sources; - * @pwr: pointer to power devices data array; - * @top_aggr_fan_mask: top aggregation interrupt FAN mask; - * @fan_reg_offset: offset of FAN interrupt register; - * @fan_mask: FAN interrupt mask; - * @fan_count: number of equipped replaceable FANs; - * @fan: pointer to FAN devices data array; - * - * Structure represents board platform data, related to system hotplug events, - * like FAN, PSU, power cable insertion and removing. This data provides the - * number of hot-pluggable devices and hardware description for event handling. - */ -struct mlxcpld_hotplug_platform_data { - u16 top_aggr_offset; - u8 top_aggr_mask; - u8 top_aggr_psu_mask; - u16 psu_reg_offset; - u8 psu_mask; - u8 psu_count; - struct mlxcpld_hotplug_device *psu; - u8 top_aggr_pwr_mask; - u16 pwr_reg_offset; - u8 pwr_mask; - u8 pwr_count; - struct mlxcpld_hotplug_device *pwr; - u8 top_aggr_fan_mask; - u16 fan_reg_offset; - u8 fan_mask; - u8 fan_count; - struct mlxcpld_hotplug_device *fan; -}; - -#endif /* __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H */ diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h new file mode 100644 index 000000000000..8dcbb8e21ee2 --- /dev/null +++ b/include/linux/platform_data/mlxreg.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Vadim Pasternak + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LINUX_PLATFORM_DATA_MLXREG_H +#define __LINUX_PLATFORM_DATA_MLXREG_H + +/** + * struct mlxreg_hotplug_device - I2C device data: + * @adapter: I2C device adapter; + * @client: I2C device client; + * @brdinfo: device board information; + * @bus: I2C bus, where device is attached; + * + * Structure represents I2C hotplug device static data (board topology) and + * dynamic data (related kernel objects handles). + */ +struct mlxreg_hotplug_device { + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info brdinfo; + u16 bus; +}; + +/** + * struct mlxreg_hotplug_platform_data - device platform data: + * @top_aggr_offset: offset of top aggregation interrupt register; + * @top_aggr_mask: top aggregation interrupt common mask; + * @top_aggr_psu_mask: top aggregation interrupt PSU mask; + * @psu_reg_offset: offset of PSU interrupt register; + * @psu_mask: PSU interrupt mask; + * @psu_count: number of equipped replaceable PSUs; + * @psu: pointer to PSU devices data array; + * @top_aggr_pwr_mask: top aggregation interrupt power mask; + * @pwr_reg_offset: offset of power interrupt register + * @pwr_mask: power interrupt mask; + * @pwr_count: number of power sources; + * @pwr: pointer to power devices data array; + * @top_aggr_fan_mask: top aggregation interrupt FAN mask; + * @fan_reg_offset: offset of FAN interrupt register; + * @fan_mask: FAN interrupt mask; + * @fan_count: number of equipped replaceable FANs; + * @fan: pointer to FAN devices data array; + * + * Structure represents board platform data, related to system hotplug events, + * like FAN, PSU, power cable insertion and removing. This data provides the + * number of hot-pluggable devices and hardware description for event handling. + */ +struct mlxreg_hotplug_platform_data { + u16 top_aggr_offset; + u8 top_aggr_mask; + u8 top_aggr_psu_mask; + u16 psu_reg_offset; + u8 psu_mask; + u8 psu_count; + struct mlxreg_hotplug_device *psu; + u8 top_aggr_pwr_mask; + u16 pwr_reg_offset; + u8 pwr_mask; + u8 pwr_count; + struct mlxreg_hotplug_device *pwr; + u8 top_aggr_fan_mask; + u16 fan_reg_offset; + u8 fan_mask; + u8 fan_count; + struct mlxreg_hotplug_device *fan; +}; + +#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ -- cgit v1.2.3 From 4abdbfa7331ef5a79a6f89d2d8061ac085878756 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 22 Jan 2018 18:34:49 -0800 Subject: platform/mellanox: mlxreg-hotplug: Remove unused wait.h include The driver does not make use of anything defined in wait.h. Signed-off-by: Vadim Pasternak Acked-by: Andy Shevchenko [dvhart: refactor into smaller functional changes, leave spinlock.h] Signed-off-by: Darren Hart (VMware) --- drivers/platform/mellanox/mlxreg-hotplug.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index 5cfc82ba34be..e55f57639cc1 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -42,7 +42,6 @@ #include #include #include -#include #include /* Offset of event and mask registers from status register */ -- cgit v1.2.3 From 3d838f5514ca5318f46bdb5b3f997cee66091695 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 22 Jan 2018 18:43:27 -0800 Subject: platform/mellanox: Rename i2c bus to nr Use Linux convention of nr instead of bus for i2c adapter number. Signed-off-by: Vadim Pasternak Acked-by: Andy Shevchenko [dvhart: refactored commit into smaller functional changes] Signed-off-by: Darren Hart (VMware) --- drivers/platform/mellanox/mlxreg-hotplug.c | 6 +++--- drivers/platform/x86/mlx-platform.c | 16 ++++++++-------- include/linux/platform_data/mlxreg.h | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index e55f57639cc1..752f756723e0 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -186,17 +186,17 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) static int mlxreg_hotplug_device_create(struct device *dev, struct mlxreg_hotplug_device *item) { - item->adapter = i2c_get_adapter(item->bus); + item->adapter = i2c_get_adapter(item->nr); if (!item->adapter) { dev_err(dev, "Failed to get adapter for bus %d\n", - item->bus); + item->nr); return -EFAULT; } item->client = i2c_new_device(item->adapter, &item->brdinfo); if (!item->client) { dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", - item->brdinfo.type, item->bus, item->brdinfo.addr); + item->brdinfo.type, item->nr, item->brdinfo.addr); i2c_put_adapter(item->adapter); item->adapter = NULL; return -EFAULT; diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 0fbec1f1ca40..56017143d6a9 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -141,41 +141,41 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { static struct mlxreg_hotplug_device mlxplat_mlxcpld_psu[] = { { .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, - .bus = 10, + .nr = 10, }, { .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, - .bus = 10, + .nr = 10, }, }; static struct mlxreg_hotplug_device mlxplat_mlxcpld_pwr[] = { { .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, - .bus = 10, + .nr = 10, }, { .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, - .bus = 10, + .nr = 10, }, }; static struct mlxreg_hotplug_device mlxplat_mlxcpld_fan[] = { { .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .bus = 11, + .nr = 11, }, { .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .bus = 12, + .nr = 12, }, { .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .bus = 13, + .nr = 13, }, { .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .bus = 14, + .nr = 14, }, }; diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index 8dcbb8e21ee2..ffbcb7886c62 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h @@ -39,7 +39,7 @@ * @adapter: I2C device adapter; * @client: I2C device client; * @brdinfo: device board information; - * @bus: I2C bus, where device is attached; + * @nr: I2C device adapter number, to which device is to be attached; * * Structure represents I2C hotplug device static data (board topology) and * dynamic data (related kernel objects handles). @@ -48,7 +48,7 @@ struct mlxreg_hotplug_device { struct i2c_adapter *adapter; struct i2c_client *client; struct i2c_board_info brdinfo; - u16 bus; + int nr; }; /** -- cgit v1.2.3 From 752849e69715fdc2190945f5532d70e8c80bf384 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 22 Jan 2018 18:50:20 -0800 Subject: platform/mellanox: Group create/destroy with attribute functions Move the mlxreg_hotplug_device_create and _destroy functions up with the related attribute functions. No functional changes. Signed-off-by: Vadim Pasternak Acked-by: Andy Shevchenko [dvhart: refactored commit into smaller functional changes] Signed-off-by: Darren Hart (VMware) --- drivers/platform/mellanox/mlxreg-hotplug.c | 70 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index 752f756723e0..e4f7e8efd397 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -98,6 +98,41 @@ struct mlxreg_hotplug_priv_data { u8 fan_cache; }; +static int mlxreg_hotplug_device_create(struct device *dev, + struct mlxreg_hotplug_device *item) +{ + item->adapter = i2c_get_adapter(item->nr); + if (!item->adapter) { + dev_err(dev, "Failed to get adapter for bus %d\n", + item->nr); + return -EFAULT; + } + + item->client = i2c_new_device(item->adapter, &item->brdinfo); + if (!item->client) { + dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", + item->brdinfo.type, item->nr, item->brdinfo.addr); + i2c_put_adapter(item->adapter); + item->adapter = NULL; + return -EFAULT; + } + + return 0; +} + +static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item) +{ + if (item->client) { + i2c_unregister_device(item->client); + item->client = NULL; + } + + if (item->adapter) { + i2c_put_adapter(item->adapter); + item->adapter = NULL; + } +} + static ssize_t mlxreg_hotplug_attr_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -183,41 +218,6 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) return 0; } -static int mlxreg_hotplug_device_create(struct device *dev, - struct mlxreg_hotplug_device *item) -{ - item->adapter = i2c_get_adapter(item->nr); - if (!item->adapter) { - dev_err(dev, "Failed to get adapter for bus %d\n", - item->nr); - return -EFAULT; - } - - item->client = i2c_new_device(item->adapter, &item->brdinfo); - if (!item->client) { - dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", - item->brdinfo.type, item->nr, item->brdinfo.addr); - i2c_put_adapter(item->adapter); - item->adapter = NULL; - return -EFAULT; - } - - return 0; -} - -static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item) -{ - if (item->client) { - i2c_unregister_device(item->client); - item->client = NULL; - } - - if (item->adapter) { - i2c_put_adapter(item->adapter); - item->adapter = NULL; - } -} - static inline void mlxreg_hotplug_work_helper(struct device *dev, struct mlxreg_hotplug_device *item, u8 is_inverse, -- cgit v1.2.3 From c6acad68eb2dbffd0497f91b206de5c362f59ee4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 22 Jan 2018 19:55:11 -0800 Subject: platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface Restructure mlxreg header for unification of hotplug item definitions. Unify hotplug items to allow any kind of item (power controller, fan eeprom, psu eeprom, asic health) in common way. Use a hardware independent regmap interface, enabling the support of hotplug events over programmable devices attached to different bus types, such as I2C, LPC, or SPI. Add a device node to the mlxreg_core_data structure. Signed-off-by: Vadim Pasternak Acked-by: Andy Shevchenko [dvhart: spelling corrections, refactor device node introduction] Signed-off-by: Darren Hart (VMware) --- drivers/platform/mellanox/Kconfig | 1 + drivers/platform/mellanox/mlxreg-hotplug.c | 614 +++++++++++++++++------------ drivers/platform/x86/mlx-platform.c | 231 ++++++++--- include/linux/platform_data/mlxreg.h | 126 ++++-- 4 files changed, 635 insertions(+), 337 deletions(-) diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig index d73529203327..0fb2568716bb 100644 --- a/drivers/platform/mellanox/Kconfig +++ b/drivers/platform/mellanox/Kconfig @@ -16,6 +16,7 @@ if MELLANOX_PLATFORM config MLXREG_HOTPLUG tristate "Mellanox platform hotplug driver support" + depends on REGMAP depends on HWMON depends on I2C ---help--- diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index e4f7e8efd397..bcb564fd9f04 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -37,99 +37,97 @@ #include #include #include -#include #include +#include #include #include #include +#include #include -/* Offset of event and mask registers from status register */ +/* Offset of event and mask registers from status register. */ #define MLXREG_HOTPLUG_EVENT_OFF 1 -#define MLXREG_HOTPLUG_MASK_OFF 2 +#define MLXREG_HOTPLUG_MASK_OFF 2 #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 -#define MLXREG_HOTPLUG_ATTRS_NUM 8 +/* ASIC health parameters. */ +#define MLXREG_HOTPLUG_HEALTH_MASK 0x02 +#define MLXREG_HOTPLUG_RST_CNTR 3 -/** - * enum mlxreg_hotplug_attr_type - sysfs attributes for hotplug events: - * @MLXREG_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute; - * @MLXREG_HOTPLUG_ATTR_TYPE_PWR: power cable attribute; - * @MLXREG_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute; - */ -enum mlxreg_hotplug_attr_type { - MLXREG_HOTPLUG_ATTR_TYPE_PSU, - MLXREG_HOTPLUG_ATTR_TYPE_PWR, - MLXREG_HOTPLUG_ATTR_TYPE_FAN, -}; +#define MLXREG_HOTPLUG_ATTRS_MAX 24 /** * struct mlxreg_hotplug_priv_data - platform private data: - * @irq: platform interrupt number; + * @irq: platform device interrupt number; * @pdev: platform device; * @plat: platform data; + * @dwork: delayed work template; + * @lock: spin lock; * @hwmon: hwmon device; * @mlxreg_hotplug_attr: sysfs attributes array; * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; * @group: sysfs attribute group; * @groups: list of sysfs attribute group for hwmon registration; - * @dwork: delayed work template; - * @lock: spin lock; + * @cell: location of top aggregation interrupt register; + * @mask: top aggregation interrupt common mask; * @aggr_cache: last value of aggregation register status; - * @psu_cache: last value of PSU register status; - * @pwr_cache: last value of power register status; - * @fan_cache: last value of FAN register status; */ struct mlxreg_hotplug_priv_data { int irq; + struct device *dev; struct platform_device *pdev; struct mlxreg_hotplug_platform_data *plat; + struct regmap *regmap; + struct delayed_work dwork_irq; + struct delayed_work dwork; + spinlock_t lock; /* sync with interrupt */ struct device *hwmon; - struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_NUM + 1]; + struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1]; struct sensor_device_attribute_2 - mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_NUM]; + mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX]; struct attribute_group group; const struct attribute_group *groups[2]; - struct delayed_work dwork; - spinlock_t lock; - u8 aggr_cache; - u8 psu_cache; - u8 pwr_cache; - u8 fan_cache; + u32 cell; + u32 mask; + u32 aggr_cache; + bool after_probe; }; static int mlxreg_hotplug_device_create(struct device *dev, - struct mlxreg_hotplug_device *item) + struct mlxreg_core_data *data) { - item->adapter = i2c_get_adapter(item->nr); - if (!item->adapter) { + data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); + if (!data->hpdev.adapter) { dev_err(dev, "Failed to get adapter for bus %d\n", - item->nr); + data->hpdev.nr); return -EFAULT; } - item->client = i2c_new_device(item->adapter, &item->brdinfo); - if (!item->client) { + data->hpdev.client = i2c_new_device(data->hpdev.adapter, + data->hpdev.brdinfo); + if (!data->hpdev.client) { dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", - item->brdinfo.type, item->nr, item->brdinfo.addr); - i2c_put_adapter(item->adapter); - item->adapter = NULL; + data->hpdev.brdinfo->type, data->hpdev.nr, + data->hpdev.brdinfo->addr); + + i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; return -EFAULT; } return 0; } -static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item) +static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) { - if (item->client) { - i2c_unregister_device(item->client); - item->client = NULL; + if (data->hpdev.client) { + i2c_unregister_device(data->hpdev.client); + data->hpdev.client = NULL; } - if (item->adapter) { - i2c_put_adapter(item->adapter); - item->adapter = NULL; + if (data->hpdev.adapter) { + i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; } } @@ -137,41 +135,76 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev); + struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev); + struct mlxreg_core_hotplug_platform_data *pdata; int index = to_sensor_dev_attr_2(attr)->index; int nr = to_sensor_dev_attr_2(attr)->nr; - u8 reg_val = 0; - - switch (nr) { - case MLXREG_HOTPLUG_ATTR_TYPE_PSU: - /* Bit = 0 : PSU is present. */ - reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index)); - break; - - case MLXREG_HOTPLUG_ATTR_TYPE_PWR: - /* Bit = 1 : power cable is attached. */ - reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index % - priv->plat->pwr_count)); - break; - - case MLXREG_HOTPLUG_ATTR_TYPE_FAN: - /* Bit = 0 : FAN is present. */ - reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index % - priv->plat->fan_count)); - break; + struct mlxreg_core_item *item; + struct mlxreg_core_data *data; + u32 regval; + int ret; + + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items + nr; + data = item->data + index; + + ret = regmap_read(priv->regmap, data->reg, ®val); + if (ret) + return ret; + + if (item->health) { + regval &= data->mask; + } else { + /* Bit = 0 : functional if item->inversed is true. */ + if (item->inversed) + regval = !(regval & data->mask); + else + regval = !!(regval & data->mask); } - return sprintf(buf, "%u\n", reg_val); + return sprintf(buf, "%u\n", regval); } #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i] #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i] + static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) { - int num_attrs = priv->plat->psu_count + priv->plat->pwr_count + - priv->plat->fan_count; - int i; + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_core_item *item; + struct mlxreg_core_data *data; + int num_attrs = 0, id = 0, i, j; + + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; + + /* Go over all kinds of items - psu, pwr, fan. */ + for (i = 0; i < pdata->counter; i++, item++) { + num_attrs += item->count; + data = item->data; + /* Go over all units within the item. */ + for (j = 0; j < item->count; j++, data++, id++) { + PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr; + PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, + data->label); + + if (!PRIV_ATTR(id)->name) { + dev_err(priv->dev, "Memory allocation failed for attr %d.\n", + id); + return -ENOMEM; + } + + PRIV_DEV_ATTR(id).dev_attr.attr.name = + PRIV_ATTR(id)->name; + PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444; + PRIV_DEV_ATTR(id).dev_attr.show = + mlxreg_hotplug_attr_show; + PRIV_DEV_ATTR(id).nr = i; + PRIV_DEV_ATTR(id).index = j; + sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr); + } + } priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * sizeof(struct attribute *), @@ -179,38 +212,6 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) if (!priv->group.attrs) return -ENOMEM; - for (i = 0; i < num_attrs; i++) { - PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr; - - if (i < priv->plat->psu_count) { - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, - GFP_KERNEL, "psu%u", i + 1); - PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PSU; - } else if (i < priv->plat->psu_count + priv->plat->pwr_count) { - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, - GFP_KERNEL, "pwr%u", i % - priv->plat->pwr_count + 1); - PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PWR; - } else { - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, - GFP_KERNEL, "fan%u", i % - priv->plat->fan_count + 1); - PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_FAN; - } - - if (!PRIV_ATTR(i)->name) { - dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", - i + 1); - return -ENOMEM; - } - - PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name; - PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO; - PRIV_DEV_ATTR(i).dev_attr.show = mlxreg_hotplug_attr_show; - PRIV_DEV_ATTR(i).index = i; - sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr); - } - priv->group.attrs = priv->mlxreg_hotplug_attr; priv->groups[0] = &priv->group; priv->groups[1] = NULL; @@ -218,20 +219,13 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) return 0; } -static inline void -mlxreg_hotplug_work_helper(struct device *dev, - struct mlxreg_hotplug_device *item, u8 is_inverse, - u16 offset, u8 mask, u8 *cache) +static void +mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, + struct mlxreg_core_item *item) { - u8 val, asserted; - int bit; - - /* Mask event. */ - outb(0, offset + MLXREG_HOTPLUG_MASK_OFF); - /* Read status. */ - val = inb(offset) & mask; - asserted = *cache ^ val; - *cache = val; + struct mlxreg_core_data *data; + u32 asserted, regval, bit; + int ret; /* * Validate if item related to received signal type is valid. @@ -241,86 +235,177 @@ mlxreg_hotplug_work_helper(struct device *dev, * signals from other devices if any. */ if (unlikely(!item)) { - dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n", - offset, mask); + dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n", + item->reg, item->mask); + return; } + /* Mask event. */ + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, + 0); + if (ret) + goto out; + + /* Read status. */ + ret = regmap_read(priv->regmap, item->reg, ®val); + if (ret) + goto out; + + /* Set asserted bits and save last status. */ + regval &= item->mask; + asserted = item->cache ^ regval; + item->cache = regval; + for_each_set_bit(bit, (unsigned long *)&asserted, 8) { - if (val & BIT(bit)) { - if (is_inverse) - mlxreg_hotplug_device_destroy(item + bit); + data = item->data + bit; + if (regval & BIT(bit)) { + if (item->inversed) + mlxreg_hotplug_device_destroy(data); else - mlxreg_hotplug_device_create(dev, item + bit); + mlxreg_hotplug_device_create(priv->dev, data); } else { - if (is_inverse) - mlxreg_hotplug_device_create(dev, item + bit); + if (item->inversed) + mlxreg_hotplug_device_create(priv->dev, data); else - mlxreg_hotplug_device_destroy(item + bit); + mlxreg_hotplug_device_destroy(data); } } /* Acknowledge event. */ - outb(0, offset + MLXREG_HOTPLUG_EVENT_OFF); + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, + 0); + if (ret) + goto out; + /* Unmask event. */ - outb(mask, offset + MLXREG_HOTPLUG_MASK_OFF); + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, + item->mask); + + out: + if (ret) + dev_err(priv->dev, "Failed to complete workqueue.\n"); +} + +static void +mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, + struct mlxreg_core_item *item) +{ + struct mlxreg_core_data *data = item->data; + u32 regval; + int i, ret; + + for (i = 0; i < item->count; i++, data++) { + /* Mask event. */ + ret = regmap_write(priv->regmap, data->reg + + MLXREG_HOTPLUG_MASK_OFF, 0); + if (ret) + goto out; + + /* Read status. */ + ret = regmap_read(priv->regmap, data->reg, ®val); + if (ret) + goto out; + + regval &= data->mask; + item->cache = regval; + if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { + if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) || + !priv->after_probe) { + mlxreg_hotplug_device_create(priv->dev, data); + data->attached = true; + } + } else { + if (data->attached) { + mlxreg_hotplug_device_destroy(data); + data->attached = false; + data->health_cntr = 0; + } + } + + /* Acknowledge event. */ + ret = regmap_write(priv->regmap, data->reg + + MLXREG_HOTPLUG_EVENT_OFF, 0); + if (ret) + goto out; + + /* Unmask event. */ + ret = regmap_write(priv->regmap, data->reg + + MLXREG_HOTPLUG_MASK_OFF, data->mask); + if (ret) + goto out; + } + + out: + if (ret) + dev_err(priv->dev, "Failed to complete workqueue.\n"); } /* - * mlxreg_hotplug_work_handler - performs traversing of CPLD interrupt + * mlxreg_hotplug_work_handler - performs traversing of device interrupt * registers according to the below hierarchy schema: * - * Aggregation registers (status/mask) - * PSU registers: *---* - * *-----------------* | | - * |status/event/mask|----->| * | - * *-----------------* | | - * Power registers: | | - * *-----------------* | | - * |status/event/mask|----->| * |---> CPU - * *-----------------* | | - * FAN registers: - * *-----------------* | | - * |status/event/mask|----->| * | - * *-----------------* | | - * *---* + * Aggregation registers (status/mask) + * PSU registers: *---* + * *-----------------* | | + * |status/event/mask|-----> | * | + * *-----------------* | | + * Power registers: | | + * *-----------------* | | + * |status/event/mask|-----> | * | + * *-----------------* | | + * FAN registers: | |--> CPU + * *-----------------* | | + * |status/event/mask|-----> | * | + * *-----------------* | | + * ASIC registers: | | + * *-----------------* | | + * |status/event/mask|-----> | * | + * *-----------------* | | + * *---* + * * In case some system changed are detected: FAN in/out, PSU in/out, power - * cable attached/detached, relevant device is created or destroyed. + * cable attached/detached, ASIC health good/bad, relevant device is created + * or destroyed. */ static void mlxreg_hotplug_work_handler(struct work_struct *work) { - struct mlxreg_hotplug_priv_data *priv = container_of(work, - struct mlxreg_hotplug_priv_data, dwork.work); - u8 val, aggr_asserted; + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_hotplug_priv_data *priv; + struct mlxreg_core_item *item; + u32 regval, aggr_asserted; unsigned long flags; + int i, ret; + + priv = container_of(work, struct mlxreg_hotplug_priv_data, + dwork_irq.work); + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; /* Mask aggregation event. */ - outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF); + ret = regmap_write(priv->regmap, pdata->cell + + MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); + if (ret < 0) + goto out; + /* Read aggregation status. */ - val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask; - aggr_asserted = priv->aggr_cache ^ val; - priv->aggr_cache = val; - - /* Handle PSU configuration changes. */ - if (aggr_asserted & priv->plat->top_aggr_psu_mask) - mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu, - 1, priv->plat->psu_reg_offset, - priv->plat->psu_mask, - &priv->psu_cache); - - /* Handle power cable configuration changes. */ - if (aggr_asserted & priv->plat->top_aggr_pwr_mask) - mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr, - 0, priv->plat->pwr_reg_offset, - priv->plat->pwr_mask, - &priv->pwr_cache); - - /* Handle FAN configuration changes. */ - if (aggr_asserted & priv->plat->top_aggr_fan_mask) - mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan, - 1, priv->plat->fan_reg_offset, - priv->plat->fan_mask, - &priv->fan_cache); + ret = regmap_read(priv->regmap, pdata->cell, ®val); + if (ret) + goto out; + + regval &= pdata->mask; + aggr_asserted = priv->aggr_cache ^ regval; + priv->aggr_cache = regval; + + /* Handle topology and health configuration changes. */ + for (i = 0; i < pdata->counter; i++, item++) { + if (aggr_asserted & item->aggr_mask) { + if (item->health) + mlxreg_hotplug_health_work_helper(priv, item); + else + mlxreg_hotplug_work_helper(priv, item); + } + } if (aggr_asserted) { spin_lock_irqsave(&priv->lock, flags); @@ -335,8 +420,8 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) * validates that no new signals have been received during * masking. */ - cancel_delayed_work(&priv->dwork); - schedule_delayed_work(&priv->dwork, 0); + cancel_delayed_work(&priv->dwork_irq); + schedule_delayed_work(&priv->dwork_irq, 0); spin_unlock_irqrestore(&priv->lock, flags); @@ -344,92 +429,119 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) } /* Unmask aggregation event (no need acknowledge). */ - outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + - MLXREG_HOTPLUG_AGGR_MASK_OFF); + ret = regmap_write(priv->regmap, pdata->cell + + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); + + out: + if (ret) + dev_err(priv->dev, "Failed to complete workqueue.\n"); } -static void mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) +static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) { - /* Clear psu presense event. */ - outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); - /* Set psu initial status as mask and unmask psu event. */ - priv->psu_cache = priv->plat->psu_mask; - outb(priv->plat->psu_mask, priv->plat->psu_reg_offset + - MLXREG_HOTPLUG_MASK_OFF); - - /* Clear power cable event. */ - outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); - /* Keep power initial status as zero and unmask power event. */ - outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset + - MLXREG_HOTPLUG_MASK_OFF); - - /* Clear fan presense event. */ - outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); - /* Set fan initial status as mask and unmask fan event. */ - priv->fan_cache = priv->plat->fan_mask; - outb(priv->plat->fan_mask, priv->plat->fan_reg_offset + - MLXREG_HOTPLUG_MASK_OFF); + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_core_item *item; + int i, ret; + + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; + + for (i = 0; i < pdata->counter; i++, item++) { + /* Clear group presense event. */ + ret = regmap_write(priv->regmap, item->reg + + MLXREG_HOTPLUG_EVENT_OFF, 0); + if (ret) + goto out; + + /* Set group initial status as mask and unmask group event. */ + if (item->inversed) { + item->cache = item->mask; + ret = regmap_write(priv->regmap, item->reg + + MLXREG_HOTPLUG_MASK_OFF, + item->mask); + if (ret) + goto out; + } + } /* Keep aggregation initial status as zero and unmask events. */ - outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + - MLXREG_HOTPLUG_AGGR_MASK_OFF); + ret = regmap_write(priv->regmap, pdata->cell + + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); + if (ret) + goto out; + + /* Keep low aggregation initial status as zero and unmask events. */ + if (pdata->cell_low) { + ret = regmap_write(priv->regmap, pdata->cell_low + + MLXREG_HOTPLUG_AGGR_MASK_OFF, + pdata->mask_low); + if (ret) + goto out; + } /* Invoke work handler for initializing hot plug devices setting. */ - mlxreg_hotplug_work_handler(&priv->dwork.work); + mlxreg_hotplug_work_handler(&priv->dwork_irq.work); + out: + if (ret) + dev_err(priv->dev, "Failed to set interrupts.\n"); enable_irq(priv->irq); + return ret; } static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) { - int i; + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_core_item *item; + struct mlxreg_core_data *data; + int count, i, j; + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; disable_irq(priv->irq); - cancel_delayed_work_sync(&priv->dwork); - - /* Mask aggregation event. */ - outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF); - - /* Mask psu presense event. */ - outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_MASK_OFF); - /* Clear psu presense event. */ - outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); - - /* Mask power cable event. */ - outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_MASK_OFF); - /* Clear power cable event. */ - outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); - - /* Mask fan presense event. */ - outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_MASK_OFF); - /* Clear fan presense event. */ - outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); - - /* Remove all the attached devices. */ - for (i = 0; i < priv->plat->psu_count; i++) - mlxreg_hotplug_device_destroy(priv->plat->psu + i); + cancel_delayed_work_sync(&priv->dwork_irq); - for (i = 0; i < priv->plat->pwr_count; i++) - mlxreg_hotplug_device_destroy(priv->plat->pwr + i); + /* Mask low aggregation event, if defined. */ + if (pdata->cell_low) + regmap_write(priv->regmap, pdata->cell_low + + MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); - for (i = 0; i < priv->plat->fan_count; i++) - mlxreg_hotplug_device_destroy(priv->plat->fan + i); + /* Mask aggregation event. */ + regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, + 0); + + /* Clear topology configurations. */ + for (i = 0; i < pdata->counter; i++, item++) { + data = item->data; + /* Mask group presense event. */ + regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF, + 0); + /* Clear group presense event. */ + regmap_write(priv->regmap, data->reg + + MLXREG_HOTPLUG_EVENT_OFF, 0); + + /* Remove all the attached devices in group. */ + count = item->count; + for (j = 0; j < count; j++, data++) + mlxreg_hotplug_device_destroy(data); + } } static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) { - struct mlxreg_hotplug_priv_data *priv = - (struct mlxreg_hotplug_priv_data *)dev; + struct mlxreg_hotplug_priv_data *priv; + + priv = (struct mlxreg_hotplug_priv_data *)dev; /* Schedule work task for immediate execution.*/ - schedule_delayed_work(&priv->dwork, 0); + schedule_delayed_work(&priv->dwork_irq, 0); return IRQ_HANDLED; } static int mlxreg_hotplug_probe(struct platform_device *pdev) { - struct mlxreg_hotplug_platform_data *pdata; + struct mlxreg_core_hotplug_platform_data *pdata; struct mlxreg_hotplug_priv_data *priv; int err; @@ -443,31 +555,42 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->pdev = pdev; - priv->plat = pdata; - - priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq: %d\n", - priv->irq); - return priv->irq; + if (pdata->irq) { + priv->irq = pdata->irq; + } else { + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(&pdev->dev, "Failed to get platform irq: %d\n", + priv->irq); + return priv->irq; + } } + priv->regmap = pdata->regmap; + priv->dev = pdev->dev.parent; + priv->pdev = pdev; + err = devm_request_irq(&pdev->dev, priv->irq, - mlxreg_hotplug_irq_handler, 0, pdev->name, - priv); + mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING + | IRQF_SHARED, "mlxreg-hotplug", priv); if (err) { dev_err(&pdev->dev, "Failed to request irq: %d\n", err); return err; } - disable_irq(priv->irq); - INIT_DELAYED_WORK(&priv->dwork, mlxreg_hotplug_work_handler); + disable_irq(priv->irq); spin_lock_init(&priv->lock); + INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); + /* Perform initial interrupts setup. */ + mlxreg_hotplug_set_irq(priv); + + priv->after_probe = true; + dev_set_drvdata(&pdev->dev, priv); err = mlxreg_hotplug_attr_init(priv); if (err) { - dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err); + dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", + err); return err; } @@ -479,17 +602,12 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) return PTR_ERR(priv->hwmon); } - platform_set_drvdata(pdev, priv); - - /* Perform initial interrupts setup. */ - mlxreg_hotplug_set_irq(priv); - return 0; } static int mlxreg_hotplug_remove(struct platform_device *pdev) { - struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev); + struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); /* Clean interrupts setup. */ mlxreg_hotplug_unset_irq(priv); diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 56017143d6a9..03c9e7a76d89 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -35,20 +35,22 @@ #include #include #include +#include #include #include #include #include +#include #define MLX_PLAT_DEVICE_NAME "mlxplat" /* LPC bus IO offsets */ #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 -#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a -#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 -#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 -#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 +#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a +#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 +#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 +#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda @@ -138,78 +140,194 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { }; /* Platform hotplug devices */ -static struct mlxreg_hotplug_device mlxplat_mlxcpld_psu[] = { +static struct i2c_board_info mlxplat_mlxcpld_psu[] = { { - .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, - .nr = 10, + I2C_BOARD_INFO("24c02", 0x51), }, { - .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, - .nr = 10, + I2C_BOARD_INFO("24c02", 0x50), }, }; -static struct mlxreg_hotplug_device mlxplat_mlxcpld_pwr[] = { +static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { { - .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, - .nr = 10, + I2C_BOARD_INFO("dps460", 0x59), }, { - .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, - .nr = 10, + I2C_BOARD_INFO("dps460", 0x58), }, }; -static struct mlxreg_hotplug_device mlxplat_mlxcpld_fan[] = { +static struct i2c_board_info mlxplat_mlxcpld_fan[] = { { - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .nr = 11, + I2C_BOARD_INFO("24c32", 0x50), }, { - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .nr = 12, + I2C_BOARD_INFO("24c32", 0x50), }, { - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .nr = 13, + I2C_BOARD_INFO("24c32", 0x50), }, { - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, - .nr = 14, + I2C_BOARD_INFO("24c32", 0x50), }, }; /* Platform hotplug default data */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { + { + .label = "psu1", + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], + .hpdev.nr = 10, + }, + { + .label = "psu2", + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], + .hpdev.nr = 10, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { + { + .label = "pwr1", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], + .hpdev.nr = 10, + }, + { + .label = "pwr2", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], + .hpdev.nr = 10, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { + { + .label = "fan1", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0], + .hpdev.nr = 11, + }, + { + .label = "fan2", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1], + .hpdev.nr = 12, + }, + { + .label = "fan3", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2], + .hpdev.nr = 13, + }, + { + .label = "fan4", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3], + .hpdev.nr = 14, + }, +}; + +static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { + { + .data = mlxplat_mlxcpld_default_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = MLXPLAT_CPLD_FAN_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), + .inversed = 1, + .health = false, + }, +}; + static -struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_default_data = { - .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, - .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, - .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, - .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, - .psu_mask = MLXPLAT_CPLD_PSU_MASK, - .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu), - .psu = mlxplat_mlxcpld_psu, - .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, - .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, - .pwr_mask = MLXPLAT_CPLD_PWR_MASK, - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), - .pwr = mlxplat_mlxcpld_pwr, - .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, - .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR, - .fan_mask = MLXPLAT_CPLD_FAN_MASK, - .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan), - .fan = mlxplat_mlxcpld_fan, +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { + .items = mlxplat_mlxcpld_default_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, }; /* Platform hotplug MSN21xx system family data */ +static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { + { + .data = mlxplat_mlxcpld_default_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), + .inversed = 0, + .health = false, + }, +}; + static -struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { - .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, - .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, - .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, - .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, - .pwr_mask = MLXPLAT_CPLD_PWR_MASK, - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { + .items = mlxplat_mlxcpld_msn21xx_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, +}; + +struct mlxplat_mlxcpld_regmap_context { + void __iomem *base; +}; + +static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx; + +static int +mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct mlxplat_mlxcpld_regmap_context *ctx = context; + + *val = ioread8(ctx->base + reg); + return 0; +} + +static int +mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct mlxplat_mlxcpld_regmap_context *ctx = context; + + iowrite8(val, ctx->base + reg); + return 0; +} + +static const struct regmap_config mlxplat_mlxcpld_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 255, + .reg_read = mlxplat_mlxcpld_reg_read, + .reg_write = mlxplat_mlxcpld_reg_write, }; static struct resource mlxplat_mlxcpld_resources[] = { @@ -217,7 +335,7 @@ static struct resource mlxplat_mlxcpld_resources[] = { }; static struct platform_device *mlxplat_dev; -static struct mlxreg_hotplug_platform_data *mlxplat_hotplug; +static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { @@ -328,6 +446,21 @@ static int __init mlxplat_init(void) } } + mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, + mlxplat_lpc_resources[1].start, 1); + if (IS_ERR(mlxplat_mlxcpld_regmap_ctx.base)) { + err = PTR_ERR(mlxplat_mlxcpld_regmap_ctx.base); + goto fail_platform_mux_register; + } + + mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, + &mlxplat_mlxcpld_regmap_ctx, + &mlxplat_mlxcpld_regmap_config); + if (IS_ERR(mlxplat_hotplug->regmap)) { + err = PTR_ERR(mlxplat_hotplug->regmap); + goto fail_platform_mux_register; + } + priv->pdev_hotplug = platform_device_register_resndata( &mlxplat_dev->dev, "mlxreg-hotplug", PLATFORM_DEVID_NONE, diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index ffbcb7886c62..fcdc707eab99 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h @@ -34,8 +34,11 @@ #ifndef __LINUX_PLATFORM_DATA_MLXREG_H #define __LINUX_PLATFORM_DATA_MLXREG_H +#define MLXREG_CORE_LABEL_MAX_SIZE 32 + /** * struct mlxreg_hotplug_device - I2C device data: + * * @adapter: I2C device adapter; * @client: I2C device client; * @brdinfo: device board information; @@ -47,52 +50,95 @@ struct mlxreg_hotplug_device { struct i2c_adapter *adapter; struct i2c_client *client; - struct i2c_board_info brdinfo; + struct i2c_board_info *brdinfo; int nr; }; /** - * struct mlxreg_hotplug_platform_data - device platform data: - * @top_aggr_offset: offset of top aggregation interrupt register; - * @top_aggr_mask: top aggregation interrupt common mask; - * @top_aggr_psu_mask: top aggregation interrupt PSU mask; - * @psu_reg_offset: offset of PSU interrupt register; - * @psu_mask: PSU interrupt mask; - * @psu_count: number of equipped replaceable PSUs; - * @psu: pointer to PSU devices data array; - * @top_aggr_pwr_mask: top aggregation interrupt power mask; - * @pwr_reg_offset: offset of power interrupt register - * @pwr_mask: power interrupt mask; - * @pwr_count: number of power sources; - * @pwr: pointer to power devices data array; - * @top_aggr_fan_mask: top aggregation interrupt FAN mask; - * @fan_reg_offset: offset of FAN interrupt register; - * @fan_mask: FAN interrupt mask; - * @fan_count: number of equipped replaceable FANs; - * @fan: pointer to FAN devices data array; + * struct mlxreg_core_data - attributes control data: + * + * @label: attribute label; + * @label: attribute register offset; + * @reg: attribute register; + * @mask: attribute access mask; + * @mode: access mode; + * @bit: attribute effective bit; + * @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; + */ +struct mlxreg_core_data { + char label[MLXREG_CORE_LABEL_MAX_SIZE]; + u32 reg; + u32 mask; + u32 bit; + umode_t mode; + struct device_node *np; + struct mlxreg_hotplug_device hpdev; + u8 health_cntr; + bool attached; +}; + +/** + * struct mlxreg_core_item - same type components controlled by the driver: + * + * @data: component data; + * @aggr_mask: group aggregation mask; + * @reg: group interrupt status register; + * @mask: group interrupt mask; + * @cache: last status value for elements fro the same group; + * @count: number of available elements in the group; + * @ind: element's index inside the group; + * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK; + * @health: true if device has health indication, false in other case; + */ +struct mlxreg_core_item { + struct mlxreg_core_data *data; + u32 aggr_mask; + u32 reg; + u32 mask; + u32 cache; + u8 count; + u8 ind; + u8 inversed; + u8 health; +}; + +/** + * struct mlxreg_core_platform_data - platform data: + * + * @led_data: led private data; + * @regmap: register map of parent device; + * @counter: number of led instances; + */ +struct mlxreg_core_platform_data { + struct mlxreg_core_data *data; + void *regmap; + int counter; +}; + +/** + * struct mlxreg_core_hotplug_platform_data - hotplug platform data: * - * Structure represents board platform data, related to system hotplug events, - * like FAN, PSU, power cable insertion and removing. This data provides the - * number of hot-pluggable devices and hardware description for event handling. + * @items: same type components with the hotplug capability; + * @irq: platform interrupt number; + * @regmap: register map of parent device; + * @counter: number of the components with the hotplug capability; + * @cell: location of top aggregation interrupt register; + * @mask: top aggregation interrupt common mask; + * @cell_low: location of low aggregation interrupt register; + * @mask_low: low aggregation interrupt common mask; */ -struct mlxreg_hotplug_platform_data { - u16 top_aggr_offset; - u8 top_aggr_mask; - u8 top_aggr_psu_mask; - u16 psu_reg_offset; - u8 psu_mask; - u8 psu_count; - struct mlxreg_hotplug_device *psu; - u8 top_aggr_pwr_mask; - u16 pwr_reg_offset; - u8 pwr_mask; - u8 pwr_count; - struct mlxreg_hotplug_device *pwr; - u8 top_aggr_fan_mask; - u16 fan_reg_offset; - u8 fan_mask; - u8 fan_count; - struct mlxreg_hotplug_device *fan; +struct mlxreg_core_hotplug_platform_data { + struct mlxreg_core_item *items; + int irq; + void *regmap; + int counter; + u32 cell; + u32 mask; + u32 cell_low; + u32 mask_low; }; #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ -- cgit v1.2.3 From 536180fe61a28a95341c69c952583a9f9ebf11f9 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 17 Jan 2018 18:21:54 +0000 Subject: platform/mellanox: mlxreg-hotplug: Enable building for ARM Add ARM in addition to X86 as supported architectures in the Mellanox Hotplug Platform driver Kconfig entry. Signed-off-by: Vadim Pasternak [dvhart: rewrite commit message] Signed-off-by: Darren Hart (VMware) --- drivers/platform/mellanox/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig index 0fb2568716bb..591bccdeaff9 100644 --- a/drivers/platform/mellanox/Kconfig +++ b/drivers/platform/mellanox/Kconfig @@ -5,7 +5,7 @@ menuconfig MELLANOX_PLATFORM bool "Platform support for Mellanox hardware" - depends on X86 || COMPILE_TEST + depends on X86 || ARM || COMPILE_TEST ---help--- Say Y here to get to see options for platform support for Mellanox systems. This option alone does not add any kernel code. -- cgit v1.2.3 From 5586c6ffead818abb1fa47162c411d58fed5c632 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 17 Jan 2018 18:20:57 +0000 Subject: platform/x86: mlx-platform: Allow compilation for 32 bit arch It makes mlx-platform available for 32 bit architecture. Signed-off-by: Vadim Pasternak Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 53f52f9df2c5..9a8f96465cdc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1159,7 +1159,6 @@ config INTEL_TELEMETRY config MLX_PLATFORM tristate "Mellanox Technologies platform support" - depends on X86_64 ---help--- This option enables system support for the Mellanox Technologies platform. The Mellanox systems provide data center networking -- cgit v1.2.3 From b4d3dbc472bb59fe3cdbbcce47a365641791e6fb Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 25 Jan 2018 14:02:53 -0800 Subject: platform/x86: mlx-platform: Document pdev_hotplug field Add missing description of pdev_hotplug in struct mlxplat_priv. Signed-off-by: Vadim Pasternak Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/mlx-platform.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 03c9e7a76d89..fa27ca8b03ba 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -83,6 +83,7 @@ /* mlxplat_priv - platform private data * @pdev_i2c - i2c controller platform device * @pdev_mux - array of mux platform devices + * @pdev_hotplug - hotplug platform devices */ struct mlxplat_priv { struct platform_device *pdev_i2c; -- cgit v1.2.3 From 0b78b1c2f43511cac53c5ab12b2235c31e3d41e5 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Fri, 26 Jan 2018 19:03:44 +0000 Subject: platform/x86: mlx-platform: Add IO access verification callbacks Add definitions for hotplug device masks and events offsets, in order to specify explicitly all hardware registers allowed for IO operations for all the drivers sharing register map with mlx-platform. Extend register map configuration with the sets of writable, readable and volatile registers to allow verification prior to the access. It prevents unexpected access to hardware registers by the drivers, sharing register map with mlx-platform. Extend register map configuration with cache type field in order to have ability to cache hardware register value, where possible. Use simple flat array type for register lookups, which is most suitable in case when the number of the registers is not too large. Add at the end of probing routine calls to regcache_mark_dirty and regcache_sync in order to sync register cache with hardware values. The first routine indicate that hardware registers value required sync, the second performs sync. Signed-off-by: Vadim Pasternak Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/mlx-platform.c | 77 +++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index fa27ca8b03ba..2d34aa87fd45 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -48,9 +48,18 @@ #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a +#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b +#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 +#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 #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_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_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda @@ -299,6 +308,64 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, }; +static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + return true; + } + return false; +} + +static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + return true; + } + return false; +} + +static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + return true; + } + return false; +} + struct mlxplat_mlxcpld_regmap_context { void __iomem *base; }; @@ -327,6 +394,10 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config = { .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_read = mlxplat_mlxcpld_reg_read, .reg_write = mlxplat_mlxcpld_reg_write, }; @@ -473,6 +544,12 @@ static int __init mlxplat_init(void) goto fail_platform_mux_register; } + /* Sync registers with hardware. */ + regcache_mark_dirty(mlxplat_hotplug->regmap); + err = regcache_sync(mlxplat_hotplug->regmap); + if (err) + goto fail_platform_mux_register; + return 0; fail_platform_mux_register: -- cgit v1.2.3 From 7805fa8d78d0ea8c9c5a6603960e8f23901c7f17 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Fri, 26 Jan 2018 19:03:45 +0000 Subject: platform/mellanox: mlxreg-hotplug: Add check for negative adapter number Verify before creation of hotplug device if the associated adapter number is negative. It could be in case hotplug event is not associated with hotplug device. Signed-off-by: Vadim Pasternak Signed-off-by: Darren Hart (VMware) --- drivers/platform/mellanox/mlxreg-hotplug.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index bcb564fd9f04..0dfa1ca0d05b 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -96,6 +96,13 @@ struct mlxreg_hotplug_priv_data { static int mlxreg_hotplug_device_create(struct device *dev, struct mlxreg_core_data *data) { + /* + * Return if adapter number is negative. It could be in case hotplug + * event is not associated with hotplug device. + */ + if (data->hpdev.nr < 0) + return 0; + data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); if (!data->hpdev.adapter) { dev_err(dev, "Failed to get adapter for bus %d\n", -- cgit v1.2.3 From 580d834fe166c695f37c942e9cd92d1743bdc5d4 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 22 Jan 2018 15:20:43 +0100 Subject: platform/x86: mlx-platform: fix module aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missing prefix 'pn' in MODULE_ALIAS lines causes the module to not load automatically. The driver should use MODULE_DEVICE_TABLE together with existing mlxplat_dmi_table instead. Fixes: 6613d18e9038 ("platform/x86: mlx-platform: Move module from arch/x86") Cc: Vadim Pasternak Cc: Bjørn Mork Cc: Andy Shevchenko Signed-off-by: Ivan Vecera Acked-by: Vadim Pasternak Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/mlx-platform.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 2d34aa87fd45..752476e83da4 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -476,6 +476,8 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { { } }; +MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); + static int __init mlxplat_init(void) { struct mlxplat_priv *priv; @@ -581,8 +583,3 @@ module_exit(mlxplat_exit); MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); MODULE_DESCRIPTION("Mellanox platform driver"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:"); -- cgit v1.2.3 From 4726098bcc4cf033dd57b6310de46ef3692debf5 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 31 Jan 2018 21:55:13 +0000 Subject: platform/x86: mlx-platform: Add hotplug device unregister to error path Add hotplug platform driver un-registration in case regmap cache synchronization failed. In such case hotplug platform driver registration should be rolled back. Signed-off-by: Vadim Pasternak Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/mlx-platform.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 752476e83da4..dfecba4407ac 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -550,10 +550,12 @@ static int __init mlxplat_init(void) regcache_mark_dirty(mlxplat_hotplug->regmap); err = regcache_sync(mlxplat_hotplug->regmap); if (err) - goto fail_platform_mux_register; + goto fail_platform_hotplug_register; return 0; +fail_platform_hotplug_register: + platform_device_unregister(priv->pdev_hotplug); fail_platform_mux_register: while (--i >= 0) platform_device_unregister(priv->pdev_mux[i]); -- cgit v1.2.3 From 941691ef2197944a202d7870dcd7da3fb0391c65 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Wed, 31 Jan 2018 11:50:22 +0530 Subject: platform/x86: intel_pmc_core: Remove unused header file Recently sent patch 'platform/x86: intel_pmc_core: Remove unused EXPORTED API' missed to remove the header file 'arch/x86/include/asm/pmc_core.h' which was solely used to declare the EXPORTED API 'intel_pmc_slp_s0_counter_read'. This patch provides the errata fix for the same. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- arch/x86/include/asm/pmc_core.h | 27 --------------------------- drivers/platform/x86/intel_pmc_core.c | 1 - 2 files changed, 28 deletions(-) delete mode 100644 arch/x86/include/asm/pmc_core.h diff --git a/arch/x86/include/asm/pmc_core.h b/arch/x86/include/asm/pmc_core.h deleted file mode 100644 index d4855f11136d..000000000000 --- a/arch/x86/include/asm/pmc_core.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Intel Core SoC Power Management Controller Header File - * - * Copyright (c) 2016, Intel Corporation. - * All Rights Reserved. - * - * Authors: Rajneesh Bhardwaj - * Vishwanath Somayaji - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#ifndef _ASM_PMC_CORE_H -#define _ASM_PMC_CORE_H - -/* API to read SLP_S0_RESIDENCY counter */ -int intel_pmc_slp_s0_counter_read(u32 *data); - -#endif /* _ASM_PMC_CORE_H */ diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index f971ca1a6ed2..5c401e17cfb6 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -28,7 +28,6 @@ #include #include -#include #include "intel_pmc_core.h" -- cgit v1.2.3 From 9862b43624a5450a097cc4122732857b869dbbca Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 31 Jan 2018 11:47:35 -0600 Subject: platform/x86: dell-laptop: Allocate buffer on heap rather than globally There is no longer a need for the buffer to be defined in first 4GB physical address space. Furthermore there may be race conditions with multiple different functions working on a module wide buffer causing incorrect results. Fixes: 549b4930f057658dc50d8010e66219233119a4d8 Suggested-by: Pali Rohar Signed-off-by: Mario Limonciello Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 188 ++++++++++++++++++++----------------- 1 file changed, 103 insertions(+), 85 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index fc2dfc85e014..a7b141992cb3 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -78,7 +78,6 @@ static struct platform_driver platform_driver = { } }; -static struct calling_interface_buffer *buffer; static struct platform_device *platform_device; static struct backlight_device *dell_backlight_device; static struct rfkill *wifi_rfkill; @@ -322,7 +321,8 @@ static const struct dmi_system_id dell_quirks[] __initconst = { { } }; -static void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) +static void dell_fill_request(struct calling_interface_buffer *buffer, + u32 arg0, u32 arg1, u32 arg2, u32 arg3) { memset(buffer, 0, sizeof(struct calling_interface_buffer)); buffer->input[0] = arg0; @@ -331,7 +331,8 @@ static void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) buffer->input[3] = arg3; } -static int dell_send_request(u16 class, u16 select) +static int dell_send_request(struct calling_interface_buffer *buffer, + u16 class, u16 select) { int ret; @@ -468,21 +469,22 @@ static int dell_rfkill_set(void *data, bool blocked) int disable = blocked ? 1 : 0; unsigned long radio = (unsigned long)data; int hwswitch_bit = (unsigned long)data - 1; + struct calling_interface_buffer buffer; int hwswitch; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret) return ret; - status = buffer->output[1]; + status = buffer.output[1]; - dell_set_arguments(0x2, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 0x2, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret) return ret; - hwswitch = buffer->output[1]; + hwswitch = buffer.output[1]; /* If the hardware switch controls this radio, and the hardware switch is disabled, always disable the radio */ @@ -490,8 +492,8 @@ static int dell_rfkill_set(void *data, bool blocked) (status & BIT(0)) && !(status & BIT(16))) disable = 1; - dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); return ret; } @@ -500,9 +502,11 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, { if (status & BIT(0)) { /* Has hw-switch, sync sw_state to BIOS */ + struct calling_interface_buffer buffer; int block = rfkill_blocked(rfkill); - dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0); - dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, + 1 | (radio << 8) | (block << 16), 0, 0, 0); + dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); } else { /* No hw-switch, sync BIOS state to sw_state */ rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); @@ -519,21 +523,22 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, static void dell_rfkill_query(struct rfkill *rfkill, void *data) { int radio = ((unsigned long)data & 0xF); + struct calling_interface_buffer buffer; int hwswitch; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - status = buffer->output[1]; + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); + status = buffer.output[1]; if (ret != 0 || !(status & BIT(0))) { return; } - dell_set_arguments(0, 0x2, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - hwswitch = buffer->output[1]; + dell_fill_request(&buffer, 0, 0x2, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); + hwswitch = buffer.output[1]; if (ret != 0) return; @@ -550,22 +555,23 @@ static struct dentry *dell_laptop_dir; static int dell_debugfs_show(struct seq_file *s, void *data) { + struct calling_interface_buffer buffer; int hwswitch_state; int hwswitch_ret; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret) return ret; - status = buffer->output[1]; + status = buffer.output[1]; - dell_set_arguments(0, 0x2, 0, 0); - hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 0, 0x2, 0, 0); + hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (hwswitch_ret) return hwswitch_ret; - hwswitch_state = buffer->output[1]; + hwswitch_state = buffer.output[1]; seq_printf(s, "return:\t%d\n", ret); seq_printf(s, "status:\t0x%X\n", status); @@ -646,22 +652,23 @@ static const struct file_operations dell_debugfs_fops = { static void dell_update_rfkill(struct work_struct *ignored) { + struct calling_interface_buffer buffer; int hwswitch = 0; int status; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - status = buffer->output[1]; + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); + status = buffer.output[1]; if (ret != 0) return; - dell_set_arguments(0, 0x2, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); + dell_fill_request(&buffer, 0, 0x2, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); if (ret == 0 && (status & BIT(0))) - hwswitch = buffer->output[1]; + hwswitch = buffer.output[1]; if (wifi_rfkill) { dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch); @@ -719,6 +726,7 @@ static struct notifier_block dell_laptop_rbtn_notifier = { static int __init dell_setup_rfkill(void) { + struct calling_interface_buffer buffer; int status, ret, whitelisted; const char *product; @@ -734,9 +742,9 @@ static int __init dell_setup_rfkill(void) if (!force_rfkill && !whitelisted) return 0; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); - status = buffer->output[1]; + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); + status = buffer.output[1]; /* dell wireless info smbios call is not supported */ if (ret != 0) @@ -889,6 +897,7 @@ static void dell_cleanup_rfkill(void) static int dell_send_intensity(struct backlight_device *bd) { + struct calling_interface_buffer buffer; struct calling_interface_token *token; int ret; @@ -896,17 +905,21 @@ static int dell_send_intensity(struct backlight_device *bd) if (!token) return -ENODEV; - dell_set_arguments(token->location, bd->props.brightness, 0, 0); + dell_fill_request(&buffer, + token->location, bd->props.brightness, 0, 0); if (power_supply_is_system_supplied() > 0) - ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_AC); + ret = dell_send_request(&buffer, + CLASS_TOKEN_WRITE, SELECT_TOKEN_AC); else - ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT); + ret = dell_send_request(&buffer, + CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT); return ret; } static int dell_get_intensity(struct backlight_device *bd) { + struct calling_interface_buffer buffer; struct calling_interface_token *token; int ret; @@ -914,14 +927,17 @@ static int dell_get_intensity(struct backlight_device *bd) if (!token) return -ENODEV; - dell_set_arguments(token->location, 0, 0, 0); + dell_fill_request(&buffer, token->location, 0, 0, 0); if (power_supply_is_system_supplied() > 0) - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC); + ret = dell_send_request(&buffer, + CLASS_TOKEN_READ, SELECT_TOKEN_AC); else - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_BAT); + ret = dell_send_request(&buffer, + CLASS_TOKEN_READ, SELECT_TOKEN_BAT); if (ret == 0) - ret = buffer->output[1]; + ret = buffer.output[1]; + return ret; } @@ -1186,31 +1202,33 @@ static enum led_brightness kbd_led_level; static int kbd_get_info(struct kbd_info *info) { + struct calling_interface_buffer buffer; u8 units; int ret; - dell_set_arguments(0, 0, 0, 0); - ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, + CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); if (ret) return ret; - info->modes = buffer->output[1] & 0xFFFF; - info->type = (buffer->output[1] >> 24) & 0xFF; - info->triggers = buffer->output[2] & 0xFF; - units = (buffer->output[2] >> 8) & 0xFF; - info->levels = (buffer->output[2] >> 16) & 0xFF; + info->modes = buffer.output[1] & 0xFFFF; + info->type = (buffer.output[1] >> 24) & 0xFF; + info->triggers = buffer.output[2] & 0xFF; + units = (buffer.output[2] >> 8) & 0xFF; + info->levels = (buffer.output[2] >> 16) & 0xFF; if (quirks && quirks->kbd_led_levels_off_1 && info->levels) info->levels--; if (units & BIT(0)) - info->seconds = (buffer->output[3] >> 0) & 0xFF; + info->seconds = (buffer.output[3] >> 0) & 0xFF; if (units & BIT(1)) - info->minutes = (buffer->output[3] >> 8) & 0xFF; + info->minutes = (buffer.output[3] >> 8) & 0xFF; if (units & BIT(2)) - info->hours = (buffer->output[3] >> 16) & 0xFF; + info->hours = (buffer.output[3] >> 16) & 0xFF; if (units & BIT(3)) - info->days = (buffer->output[3] >> 24) & 0xFF; + info->days = (buffer.output[3] >> 24) & 0xFF; return ret; } @@ -1270,31 +1288,34 @@ static int kbd_set_level(struct kbd_state *state, u8 level) static int kbd_get_state(struct kbd_state *state) { + struct calling_interface_buffer buffer; int ret; - dell_set_arguments(0x1, 0, 0, 0); - ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); + dell_fill_request(&buffer, 0, 0, 0, 0); + ret = dell_send_request(&buffer, + CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); if (ret) return ret; - state->mode_bit = ffs(buffer->output[1] & 0xFFFF); + state->mode_bit = ffs(buffer.output[1] & 0xFFFF); if (state->mode_bit != 0) state->mode_bit--; - state->triggers = (buffer->output[1] >> 16) & 0xFF; - state->timeout_value = (buffer->output[1] >> 24) & 0x3F; - state->timeout_unit = (buffer->output[1] >> 30) & 0x3; - state->als_setting = buffer->output[2] & 0xFF; - state->als_value = (buffer->output[2] >> 8) & 0xFF; - state->level = (buffer->output[2] >> 16) & 0xFF; - state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F; - state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3; + state->triggers = (buffer.output[1] >> 16) & 0xFF; + state->timeout_value = (buffer.output[1] >> 24) & 0x3F; + state->timeout_unit = (buffer.output[1] >> 30) & 0x3; + state->als_setting = buffer.output[2] & 0xFF; + state->als_value = (buffer.output[2] >> 8) & 0xFF; + state->level = (buffer.output[2] >> 16) & 0xFF; + state->timeout_value_ac = (buffer.output[2] >> 24) & 0x3F; + state->timeout_unit_ac = (buffer.output[2] >> 30) & 0x3; return ret; } static int kbd_set_state(struct kbd_state *state) { + struct calling_interface_buffer buffer; int ret; u32 input1; u32 input2; @@ -1307,8 +1328,9 @@ static int kbd_set_state(struct kbd_state *state) input2 |= (state->level & 0xFF) << 16; input2 |= (state->timeout_value_ac & 0x3F) << 24; input2 |= (state->timeout_unit_ac & 0x3) << 30; - dell_set_arguments(0x2, input1, input2, 0); - ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); + dell_fill_request(&buffer, 0x2, input1, input2, 0); + ret = dell_send_request(&buffer, + CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); return ret; } @@ -1335,6 +1357,7 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) static int kbd_set_token_bit(u8 bit) { + struct calling_interface_buffer buffer; struct calling_interface_token *token; int ret; @@ -1345,14 +1368,15 @@ static int kbd_set_token_bit(u8 bit) if (!token) return -EINVAL; - dell_set_arguments(token->location, token->value, 0, 0); - ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); + dell_fill_request(&buffer, token->location, token->value, 0, 0); + ret = dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); return ret; } static int kbd_get_token_bit(u8 bit) { + struct calling_interface_buffer buffer; struct calling_interface_token *token; int ret; int val; @@ -1364,9 +1388,9 @@ static int kbd_get_token_bit(u8 bit) if (!token) return -EINVAL; - dell_set_arguments(token->location, 0, 0, 0); - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_STD); - val = buffer->output[1]; + dell_fill_request(&buffer, token->location, 0, 0, 0); + ret = dell_send_request(&buffer, CLASS_TOKEN_READ, SELECT_TOKEN_STD); + val = buffer.output[1]; if (ret) return ret; @@ -2102,6 +2126,7 @@ static struct notifier_block dell_laptop_notifier = { int dell_micmute_led_set(int state) { + struct calling_interface_buffer buffer; struct calling_interface_token *token; if (state == 0) @@ -2114,8 +2139,8 @@ int dell_micmute_led_set(int state) if (!token) return -ENODEV; - dell_set_arguments(token->location, token->value, 0, 0); - dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); + dell_fill_request(&buffer, token->location, token->value, 0, 0); + dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); return state; } @@ -2146,13 +2171,6 @@ static int __init dell_init(void) if (ret) goto fail_platform_device2; - buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - goto fail_buffer; - } - - ret = dell_setup_rfkill(); if (ret) { @@ -2177,10 +2195,13 @@ static int __init dell_init(void) token = dell_smbios_find_token(BRIGHTNESS_TOKEN); if (token) { - dell_set_arguments(token->location, 0, 0, 0); - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC); + struct calling_interface_buffer buffer; + + dell_fill_request(&buffer, token->location, 0, 0, 0); + ret = dell_send_request(&buffer, + CLASS_TOKEN_READ, SELECT_TOKEN_AC); if (ret) - max_intensity = buffer->output[3]; + max_intensity = buffer.output[3]; } if (max_intensity) { @@ -2214,8 +2235,6 @@ static int __init dell_init(void) fail_get_brightness: backlight_device_unregister(dell_backlight_device); fail_backlight: - kfree(buffer); -fail_buffer: dell_cleanup_rfkill(); fail_rfkill: platform_device_del(platform_device); @@ -2235,7 +2254,6 @@ static void __exit dell_exit(void) touchpad_led_exit(); kbd_led_exit(); backlight_device_unregister(dell_backlight_device); - kfree(buffer); dell_cleanup_rfkill(); if (platform_device) { platform_device_unregister(platform_device); -- cgit v1.2.3 From 30323fb6d552c41997baca5292bf7001366cab57 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 29 Jan 2018 21:27:43 +0100 Subject: platform/x86: intel-vbtn: Support tablet mode switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some laptop like the Dell Inspiron 7000 series tablet mode switch implemented in Intel ACPI, the events to enter and exit the tablet mode are 0xCC and 0xCD This initializes the tablet/laptop mode at the correct value if the system booted in tablet mode (or the intel-vbtn module loaded with the device in tablet mode) Cc: platform-driver-x86@vger.kernel.org Cc: Matthew Garrett Cc: "Pali Rohár" Cc: Darren Hart Cc: Mario Limonciello Cc: Andy Shevchenko Cc: Stefan Brüns Signed-off-by: Marco Martin Reviewed-by: Mario Limonciello Acked-by: Pali Rohár [andy: fixed style of comments, indentation, and massaged commit message] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-vbtn.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 5fc4315f7382..101c100a3929 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -26,6 +26,9 @@ #include #include +/* When NOT in tablet mode, VGBS returns with the flag 0x40 */ +#define TABLET_MODE_FLAG 0x40 + MODULE_LICENSE("GPL"); MODULE_AUTHOR("AceLan Kao"); @@ -108,6 +111,7 @@ out_unknown: static int intel_vbtn_probe(struct platform_device *device) { + struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_handle handle = ACPI_HANDLE(&device->dev); struct intel_vbtn_priv *priv; acpi_status status; @@ -130,6 +134,23 @@ static int intel_vbtn_probe(struct platform_device *device) return err; } + /* + * VGBS being present and returning something means we have + * a tablet mode switch. + */ + status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); + if (ACPI_SUCCESS(status)) { + union acpi_object *obj = vgbs_output.pointer; + + if (obj && obj->type == ACPI_TYPE_INTEGER) { + int m = !(obj->integer.value & TABLET_MODE_FLAG); + + input_report_switch(priv->input_dev, SW_TABLET_MODE, m); + } + } + + kfree(vgbs_output.pointer); + status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler, -- cgit v1.2.3 From bd1b27e2c8ade686b0e9f6295b5cbe7c27ca01a4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 31 Jan 2018 19:54:06 +0200 Subject: platform/x86: intel-vbtn: Remove redundant inclusions Some headers are not needed since the driver can be built as module. Remove them. While here, sort headers alphabetically. Signed-off-by: Andy Shevchenko Reviewed-by: Darren Hart (VMware) Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-vbtn.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 101c100a3929..69bc39f8d61d 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -16,15 +16,13 @@ * */ +#include +#include +#include #include #include -#include -#include #include -#include -#include #include -#include /* When NOT in tablet mode, VGBS returns with the flag 0x40 */ #define TABLET_MODE_FLAG 0x40 -- cgit v1.2.3 From 00f49ee79777876c37f50aa137e96c52aee24205 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 31 Jan 2018 19:54:07 +0200 Subject: platform/x86: intel-vbtn: Replace License by SDPX identifier Replace License short header by SPDX identifier. Signed-off-by: Andy Shevchenko Reviewed-by: Darren Hart (VMware) Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-vbtn.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 69bc39f8d61d..b703d6f5b099 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -1,19 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Intel Virtual Button driver for Windows 8.1+ * * Copyright (C) 2016 AceLan Kao * Copyright (C) 2016 Alex Hung - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include -- cgit v1.2.3 From 9383bbadfe29fe8319e2245b75a508db9abd7b87 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 2 Feb 2018 19:13:33 +0530 Subject: ACPI / LPIT: Export lpit_read_residency_count_address() Export lpit_read_residency_count_address(), so that it can be used from drivers built as module. With the recent changes, the builtin_pci functionality of the intel_pmc_core driver is removed and now it can be built as a module to read this exported interface to calculate the PMC base address. Cc: Rafael J. Wysocki Cc: Len Brown Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Tested-by: Rajneesh Bhardwaj Signed-off-by: Srinivas Pandruvada Signed-off-by: Andy Shevchenko --- drivers/acpi/acpi_lpit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c index e94e478dd18b..cf4fc0161164 100644 --- a/drivers/acpi/acpi_lpit.c +++ b/drivers/acpi/acpi_lpit.c @@ -100,6 +100,7 @@ int lpit_read_residency_count_address(u64 *address) return 0; } +EXPORT_SYMBOL_GPL(lpit_read_residency_count_address); static void lpit_update_residency(struct lpit_residency_info *info, struct acpi_lpit_native *lpit_native) -- cgit v1.2.3 From 745698c37c08f48fb5ad3c0cb7ee955bd5701d4a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 2 Feb 2018 19:13:34 +0530 Subject: platform/x86: intel_pmc_core: Read base address from LPIT Read SLP_S0 address from ACPI LPIT table when present and use PMC specific SLP_S0 offset to get the base address of PMC MMIO. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Srinivas Pandruvada Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 5c401e17cfb6..bb80aed4c3c1 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -20,6 +20,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -455,6 +456,7 @@ static int __init pmc_core_probe(void) { struct pmc_dev *pmcdev = &pmc; const struct x86_cpu_id *cpu_id; + u64 slp_s0_addr; int err; cpu_id = x86_match_cpu(intel_pmc_core_ids); @@ -462,7 +464,12 @@ static int __init pmc_core_probe(void) return -ENODEV; pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data; - pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT; + + if (lpit_read_residency_count_address(&slp_s0_addr)) + pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT; + else + pmcdev->base_addr = slp_s0_addr - pmcdev->map->slp_s0_offset; + pmcdev->regbase = ioremap(pmcdev->base_addr, pmcdev->map->regmap_length); if (!pmcdev->regbase) -- cgit v1.2.3 From 850eb9fba3711e98bafebde26675d9c082c0ff48 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 2 Feb 2018 19:13:35 +0530 Subject: x86/cpu: Add Cannonlake to Intel family Add CPUID of Cannonlake (CNL) processors to Intel family list. Cc: Dave Hansen Cc: Thomas Gleixner cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: x86@kernel.org Reviewed-by: Thomas Gleixner Suggested-by: Tony Luck Signed-off-by: Megha Dey Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- arch/x86/include/asm/intel-family.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h index 35a6bc4da8ad..cf090e584202 100644 --- a/arch/x86/include/asm/intel-family.h +++ b/arch/x86/include/asm/intel-family.h @@ -10,6 +10,10 @@ * * Things ending in "2" are usually because we have no better * name for them. There's no processor called "SILVERMONT2". + * + * While adding a new CPUID for a new microarchitecture, add a new + * group to keep logically sorted out in chronological order. Within + * that group keep the CPUID for the variants sorted by model number. */ #define INTEL_FAM6_CORE_YONAH 0x0E @@ -49,6 +53,8 @@ #define INTEL_FAM6_KABYLAKE_MOBILE 0x8E #define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E +#define INTEL_FAM6_CANNONLAKE_MOBILE 0x66 + /* "Small Core" Processors (Atom) */ #define INTEL_FAM6_ATOM_PINEVIEW 0x1C -- cgit v1.2.3 From 291101f6a73566f5d1ab597784288c5bc85906fd Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 2 Feb 2018 19:13:36 +0530 Subject: platform/x86: intel_pmc_core: Add CannonLake PCH support This adds support for Cannonlake PCH which is used by Cannonlake and Coffeelake SoCs. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 85 +++++++++++++++++++++++++++++++++++ drivers/platform/x86/intel_pmc_core.h | 11 +++++ 2 files changed, 96 insertions(+) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index bb80aed4c3c1..a255c4b0f7a8 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -122,6 +122,90 @@ static const struct pmc_reg_map spt_reg_map = { .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT, }; +/* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */ +static const struct pmc_bit_map cnp_pfear_map[] = { + {"PMC", BIT(0)}, + {"OPI-DMI", BIT(1)}, + {"SPI/eSPI", BIT(2)}, + {"XHCI", BIT(3)}, + {"SPA", BIT(4)}, + {"SPB", BIT(5)}, + {"SPC", BIT(6)}, + {"GBE", BIT(7)}, + + {"SATA", BIT(0)}, + {"HDA_PGD0", BIT(1)}, + {"HDA_PGD1", BIT(2)}, + {"HDA_PGD2", BIT(3)}, + {"HDA_PGD3", BIT(4)}, + {"SPD", BIT(5)}, + {"LPSS", BIT(6)}, + {"LPC", BIT(7)}, + + {"SMB", BIT(0)}, + {"ISH", BIT(1)}, + {"P2SB", BIT(2)}, + {"NPK_VNN", BIT(3)}, + {"SDX", BIT(4)}, + {"SPE", BIT(5)}, + {"Fuse", BIT(6)}, + {"Res_23", BIT(7)}, + + {"CSME_FSC", BIT(0)}, + {"USB3_OTG", BIT(1)}, + {"EXI", BIT(2)}, + {"CSE", BIT(3)}, + {"csme_kvm", BIT(4)}, + {"csme_pmt", BIT(5)}, + {"csme_clink", BIT(6)}, + {"csme_ptio", BIT(7)}, + + {"csme_usbr", BIT(0)}, + {"csme_susram", BIT(1)}, + {"csme_smt1", BIT(2)}, + {"CSME_SMT4", BIT(3)}, + {"csme_sms2", BIT(4)}, + {"csme_sms1", BIT(5)}, + {"csme_rtc", BIT(6)}, + {"csme_psf", BIT(7)}, + + {"SBR0", BIT(0)}, + {"SBR1", BIT(1)}, + {"SBR2", BIT(2)}, + {"SBR3", BIT(3)}, + {"SBR4", BIT(4)}, + {"SBR5", BIT(5)}, + {"CSME_PECI", BIT(6)}, + {"PSF1", BIT(7)}, + + {"PSF2", BIT(0)}, + {"PSF3", BIT(1)}, + {"PSF4", BIT(2)}, + {"CNVI", BIT(3)}, + {"UFS0", BIT(4)}, + {"EMMC", BIT(5)}, + {"Res_6", BIT(6)}, + {"SBR6", BIT(7)}, + + {"SBR7", BIT(0)}, + {"NPK_AON", BIT(1)}, + {"HDA_PGD4", BIT(2)}, + {"HDA_PGD5", BIT(3)}, + {"HDA_PGD6", BIT(4)}, + {} +}; + +static const struct pmc_reg_map cnp_reg_map = { + .pfear_sts = cnp_pfear_map, + .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, + .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, + .regmap_length = CNP_PMC_MMIO_REG_LEN, + .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, + .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES, + .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, + .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, +}; + static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset) { return readb(pmcdev->regbase + offset); @@ -447,6 +531,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, &spt_reg_map), ICPU(INTEL_FAM6_KABYLAKE_MOBILE, &spt_reg_map), ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, &spt_reg_map), + ICPU(INTEL_FAM6_CANNONLAKE_MOBILE, &cnp_reg_map), {} }; diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 9df4a60a179f..8b7731e6dea2 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -121,6 +121,17 @@ enum ppfear_regs { #define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2) #define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3) +/* Cannonlake Power Management Controller register offsets */ +#define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET 0x193C +#define CNP_PMC_LTR_IGNORE_OFFSET 0x1B0C +#define CNP_PMC_PM_CFG_OFFSET 0x1818 +/* Cannonlake: PGD PFET Enable Ack Status Register(s) start */ +#define CNP_PMC_HOST_PPFEAR0A 0x1D90 + +#define CNP_PMC_MMIO_REG_LEN 0x2000 +#define CNP_PPFEAR_NUM_ENTRIES 8 +#define CNP_PMC_READ_DISABLE_BIT 22 + struct pmc_bit_map { const char *name; u32 bit_mask; -- cgit v1.2.3 From 661405bd817b209ac9bd4812c63d90873a7f2993 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 2 Feb 2018 19:13:37 +0530 Subject: platform/x86: intel_pmc_core: Special case for Coffeelake Intel CoffeeLake SoC uses CPU ID of KabyLake but has Cannonlake PCH, so in this case PMC register details from Cannonlake PCH must be used. In order to identify whether the given platform is Coffeelake, scan for the Sunrisepoint PMC PCI Id. KBL CPUID SPT PCIID ------------------------------------ KBL | Y | Y | ------------------------------------ CFL | Y | N | ------------------------------------ Signed-off-by: Srinivas Pandruvada Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 14 ++++++++++++++ drivers/platform/x86/intel_pmc_core.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index a255c4b0f7a8..43bbe74743d9 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -537,6 +538,11 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids); +static const struct pci_device_id pmc_pci_ids[] = { + { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 0}, + { 0, }, +}; + static int __init pmc_core_probe(void) { struct pmc_dev *pmcdev = &pmc; @@ -550,6 +556,14 @@ static int __init pmc_core_probe(void) pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data; + /* + * Coffeelake has CPU ID of Kabylake and Cannonlake PCH. So here + * Sunrisepoint PCH regmap can't be used. Use Cannonlake PCH regmap + * in this case. + */ + if (!pci_dev_present(pmc_pci_ids)) + pmcdev->map = &cnp_reg_map; + if (lpit_read_residency_count_address(&slp_s0_addr)) pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT; else diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 8b7731e6dea2..5fa5f97870aa 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -23,6 +23,8 @@ #define PMC_BASE_ADDR_DEFAULT 0xFE000000 +/* Sunrise Point Power Management Controller PCI Device ID */ +#define SPT_PMC_PCI_DEVICE_ID 0x9d21 #define SPT_PMC_BASE_ADDR_OFFSET 0x48 #define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c #define SPT_PMC_PM_CFG_OFFSET 0x18 -- cgit v1.2.3 From 8a0f5b6f33275eb0251e0e1b0716744f9d95415f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 6 Feb 2018 15:45:36 +0300 Subject: platform/x86: mlx-platform: Fix an ERR_PTR vs NULL issue devm_ioport_map() returns NULL on error but we accidentally check for error pointers instead. Fixes: c6acad68eb2d ("platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface") Signed-off-by: Dan Carpenter Acked-by: Vadim Pasternak Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/mlx-platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index dfecba4407ac..27de29961f5e 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -522,8 +522,8 @@ static int __init mlxplat_init(void) mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, mlxplat_lpc_resources[1].start, 1); - if (IS_ERR(mlxplat_mlxcpld_regmap_ctx.base)) { - err = PTR_ERR(mlxplat_mlxcpld_regmap_ctx.base); + if (!mlxplat_mlxcpld_regmap_ctx.base) { + err = -ENOMEM; goto fail_platform_mux_register; } -- cgit v1.2.3