Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'platform-drivers-x86-v6.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform driver updates from Ilpo Järvinen:

- amd/pmf: Report system state changes using existing input events

- asus-wmi: Zenbook 2023 camera LED disable support and fix TUF laptop
keyboard RGB LED sysfs interface

- dell-pc: Fan modes / platform profile support

- hp-wmi: Fix platform profile switching on Omen/Victus laptops

- intel/ISST: Use only TPMI interface when TPMI and legacy interfaces
are available

- intel/pmc: LTR restore support to pair with LTR ignore

- intel/tpmi: Performance Limit Reasons (PLR) and APIC <-> Punit CPU
numbering mapping support

- WMI: driver override support and docs improvements

- lenovo-yoga-c630: Support for EC (platform/arm64)

- platform/arm64: Fix build with COMPILE_TEST (broke after addition of
C630)

- tools: Intel Speed Select Turbo Ratio Limit fix

- Miscellaneous cleanups / refactoring / improvements

* tag 'platform-drivers-x86-v6.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (65 commits)
platform/x86: asus-wmi: fix TUF laptop RGB variant
platform/x86/intel/tpmi/plr: Fix output in plr_print_bits()
Docs/admin-guide: Remove pmf leftover reference from the index
platform/x86: ideapad-laptop: use cleanup.h
platform/x86: hp-wmi: Fix implementation of the platform_profile_omen_get function
platform: arm64: EC_LENOVO_YOGA_C630 should depend on ARCH_QCOM
platform: arm64: EC_ACER_ASPIRE1 should depend on ARCH_QCOM
platform/x86/amd/pmf: Remove update system state document
platform/x86/amd/pmf: Use existing input event codes to update system states
platform/x86: hp-wmi: Fix platform profile option switch bug on Omen and Victus laptops
platform/x86:intel/pmc: Add support to undo ltr_ignore
platform/x86:intel/pmc: Use the Elvis operator
platform/x86:intel/pmc: Use DEFINE_SHOW_STORE_ATTRIBUTE macro
platform/x86:intel/pmc: Remove unneeded min_t check
platform/x86:intel/pmc: Add support to show ltr_ignore value
platform/x86:intel/pmc: Move pmc assignment closer to first usage
platform/x86:intel/pmc: Convert index variables to be unsigned
platform/x86:intel/pmc: Simplify mutex usage with cleanup helpers
platform/x86:intel/pmc: Use the return value of pmc_core_send_msg
tools/power/x86/intel-speed-select: v1.20 release
...

+2299 -522
+9
Documentation/ABI/testing/debugfs-tpmi
··· 29 29 echo 0,0x20,0xff > mem_write 30 30 echo 1,64,64 > mem_write 31 31 Users: Debugging, any user space test suite 32 + 33 + What: /sys/kernel/debug/tpmi-<n>/plr/domain<n>/status 34 + Date: Aug 2024 35 + KernelVersion: 6.11 36 + Contact: Tero Kristo <tero.kristo@linux.intel.com> 37 + Description: 38 + Shows the currently active Performance Limit Reasons for die level and the 39 + individual CPUs under the die. The contents of this file are sticky, and 40 + clearing all the statuses can be done by writing "0\n" to this file.
+81
Documentation/ABI/testing/sysfs-bus-wmi
··· 1 + What: /sys/bus/wmi/devices/.../driver_override 2 + Date: February 2024 3 + Contact: Armin Wolf <W_Armin@gmx.de> 4 + Description: 5 + This file allows the driver for a device to be specified which 6 + will override standard ID table matching. 7 + When specified, only a driver with a name matching the value 8 + written to driver_override will have an opportunity to bind 9 + to the device. 10 + The override is specified by writing a string to the 11 + driver_override file (echo wmi-event-dummy > driver_override). 12 + The override may be cleared with an empty string (echo > \ 13 + driver_override) which returns the device to standard matching 14 + rules binding. 15 + Writing to driver_override does not automatically unbind the 16 + device from its current driver or make any attempt to automatically 17 + load the specified driver. If no driver with a matching name is 18 + currently loaded in the kernel, the device will not bind to any 19 + driver. 20 + This also allows devices to opt-out of driver binding using a 21 + driver_override name such as "none". Only a single driver may be 22 + specified in the override, there is no support for parsing delimiters. 23 + 24 + What: /sys/bus/wmi/devices/.../modalias 25 + Date: November 20:15 26 + Contact: Andy Lutomirski <luto@kernel.org> 27 + Description: 28 + This file contains the MODALIAS value emitted by uevent for a 29 + given WMI device. 30 + 31 + Format: wmi:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. 32 + 33 + What: /sys/bus/wmi/devices/.../guid 34 + Date: November 2015 35 + Contact: Andy Lutomirski <luto@kernel.org> 36 + Description: 37 + This file contains the GUID used to match WMI devices to 38 + compatible WMI drivers. This GUID is not necessarily unique 39 + inside a given machine, it is solely used to identify the 40 + interface exposed by a given WMI device. 41 + 42 + What: /sys/bus/wmi/devices/.../object_id 43 + Date: November 2015 44 + Contact: Andy Lutomirski <luto@kernel.org> 45 + Description: 46 + This file contains the WMI object ID used internally to construct 47 + the ACPI method names used by non-event WMI devices. It contains 48 + two ASCII letters. 49 + 50 + What: /sys/bus/wmi/devices/.../notify_id 51 + Date: November 2015 52 + Contact: Andy Lutomirski <luto@kernel.org> 53 + Description: 54 + This file contains the WMI notify ID used internally to map ACPI 55 + events to WMI event devices. It contains two ASCII letters. 56 + 57 + What: /sys/bus/wmi/devices/.../instance_count 58 + Date: November 2015 59 + Contact: Andy Lutomirski <luto@kernel.org> 60 + Description: 61 + This file contains the number of WMI object instances being 62 + present on a given WMI device. It contains a non-negative 63 + number. 64 + 65 + What: /sys/bus/wmi/devices/.../expensive 66 + Date: November 2015 67 + Contact: Andy Lutomirski <luto@kernel.org> 68 + Description: 69 + This file contains a boolean flag signaling if interacting with 70 + the given WMI device will consume significant CPU resources. 71 + The WMI driver core will take care of enabling/disabling such 72 + WMI devices. 73 + 74 + What: /sys/bus/wmi/devices/.../setable 75 + Date: May 2017 76 + Contact: Darren Hart (VMware) <dvhart@infradead.org> 77 + Description: 78 + This file contains a boolean flags signaling the data block 79 + aassociated with the given WMI device is writable. If the 80 + given WMI device is not associated with a data block, then 81 + this file will not exist.
-1
Documentation/admin-guide/index.rst
··· 121 121 parport 122 122 perf-security 123 123 pm/index 124 - pmf 125 124 pnp 126 125 rapidio 127 126 RAS/index
-24
Documentation/admin-guide/pmf.rst
··· 1 - .. SPDX-License-Identifier: GPL-2.0 2 - 3 - Set udev rules for PMF Smart PC Builder 4 - --------------------------------------- 5 - 6 - AMD PMF(Platform Management Framework) Smart PC Solution builder has to set the system states 7 - like S0i3, Screen lock, hibernate etc, based on the output actions provided by the PMF 8 - TA (Trusted Application). 9 - 10 - In order for this to work the PMF driver generates a uevent for userspace to react to. Below are 11 - sample udev rules that can facilitate this experience when a machine has PMF Smart PC solution builder 12 - enabled. 13 - 14 - Please add the following line(s) to 15 - ``/etc/udev/rules.d/99-local.rules``:: 16 - 17 - DRIVERS=="amd-pmf", ACTION=="change", ENV{EVENT_ID}=="0", RUN+="/usr/bin/systemctl suspend" 18 - DRIVERS=="amd-pmf", ACTION=="change", ENV{EVENT_ID}=="1", RUN+="/usr/bin/systemctl hibernate" 19 - DRIVERS=="amd-pmf", ACTION=="change", ENV{EVENT_ID}=="2", RUN+="/bin/loginctl lock-sessions" 20 - 21 - EVENT_ID values: 22 - 0= Put the system to S0i3/S2Idle 23 - 1= Put the system to hibernate 24 - 2= Lock the screen
+83
Documentation/devicetree/bindings/platform/lenovo,yoga-c630-ec.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/platform/lenovo,yoga-c630-ec.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Lenovo Yoga C630 Embedded Controller. 8 + 9 + maintainers: 10 + - Bjorn Andersson <andersson@kernel.org> 11 + 12 + description: 13 + The Qualcomm Snapdragon-based Lenovo Yoga C630 has an Embedded Controller 14 + (EC) which handles things such as battery and USB Type-C. This binding 15 + describes the interface, on an I2C bus, to this EC. 16 + 17 + properties: 18 + compatible: 19 + const: lenovo,yoga-c630-ec 20 + 21 + reg: 22 + const: 0x70 23 + 24 + '#address-cells': 25 + const: 1 26 + 27 + '#size-cells': 28 + const: 0 29 + 30 + interrupts: 31 + maxItems: 1 32 + 33 + patternProperties: 34 + '^connector@[01]$': 35 + $ref: /schemas/connector/usb-connector.yaml# 36 + 37 + properties: 38 + reg: 39 + maxItems: 1 40 + 41 + unevaluatedProperties: false 42 + 43 + required: 44 + - compatible 45 + - reg 46 + - interrupts 47 + 48 + additionalProperties: false 49 + 50 + examples: 51 + - |+ 52 + #include <dt-bindings/interrupt-controller/irq.h> 53 + i2c1 { 54 + clock-frequency = <400000>; 55 + 56 + #address-cells = <1>; 57 + #size-cells = <0>; 58 + 59 + embedded-controller@70 { 60 + compatible = "lenovo,yoga-c630-ec"; 61 + reg = <0x70>; 62 + 63 + interrupts-extended = <&tlmm 20 IRQ_TYPE_LEVEL_HIGH>; 64 + 65 + #address-cells = <1>; 66 + #size-cells = <0>; 67 + 68 + connector@0 { 69 + compatible = "usb-c-connector"; 70 + reg = <0>; 71 + power-role = "source"; 72 + data-role = "host"; 73 + }; 74 + 75 + connector@1 { 76 + compatible = "usb-c-connector"; 77 + reg = <1>; 78 + power-role = "source"; 79 + data-role = "host"; 80 + }; 81 + }; 82 + }; 83 + ...
+7
MAINTAINERS
··· 392 392 M: Armin Wolf <W_Armin@gmx.de> 393 393 L: platform-driver-x86@vger.kernel.org 394 394 S: Maintained 395 + F: Documentation/ABI/testing/sysfs-bus-wmi 395 396 F: Documentation/driver-api/wmi.rst 396 397 F: Documentation/wmi/ 397 398 F: drivers/platform/x86/wmi.c ··· 6194 6193 F: Documentation/ABI/obsolete/procfs-i8k 6195 6194 F: drivers/hwmon/dell-smm-hwmon.c 6196 6195 F: include/uapi/linux/i8k.h 6196 + 6197 + DELL PC DRIVER 6198 + M: Lyndon Sanche <lsanche@lyndeno.ca> 6199 + L: platform-driver-x86@vger.kernel.org 6200 + S: Maintained 6201 + F: drivers/platform/x86/dell/dell-pc.c 6197 6202 6198 6203 DELL REMOTE BIOS UPDATE DRIVER 6199 6204 M: Stuart Hayes <stuart.w.hayes@gmail.com>
+5 -6
arch/x86/platform/atom/punit_atom_debug.c
··· 165 165 static void punit_s2idle_check_unregister(void) {} 166 166 #endif 167 167 168 - #define X86_MATCH(model, data) \ 169 - X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \ 170 - X86_FEATURE_MWAIT, data) 168 + #define X86_MATCH(vfm, data) \ 169 + X86_MATCH_VFM_FEATURE(vfm, X86_FEATURE_MWAIT, data) 171 170 172 171 static const struct x86_cpu_id intel_punit_cpu_ids[] = { 173 - X86_MATCH(ATOM_SILVERMONT, &punit_device_byt), 174 - X86_MATCH(ATOM_SILVERMONT_MID, &punit_device_tng), 175 - X86_MATCH(ATOM_AIRMONT, &punit_device_cht), 172 + X86_MATCH(INTEL_ATOM_SILVERMONT, &punit_device_byt), 173 + X86_MATCH(INTEL_ATOM_SILVERMONT_MID, &punit_device_tng), 174 + X86_MATCH(INTEL_ATOM_AIRMONT, &punit_device_cht), 176 175 {} 177 176 }; 178 177 MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
+1 -1
drivers/platform/Makefile
··· 12 12 obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ 13 13 obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/ 14 14 obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ 15 - obj-$(CONFIG_ARM64) += arm64/ 15 + obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/
+17
drivers/platform/arm64/Kconfig
··· 18 18 19 19 config EC_ACER_ASPIRE1 20 20 tristate "Acer Aspire 1 Embedded Controller driver" 21 + depends on ARCH_QCOM || COMPILE_TEST 21 22 depends on I2C 22 23 depends on DRM 23 24 depends on POWER_SUPPLY ··· 32 31 This driver provides battery and AC status support for the mentioned 33 32 laptop where this information is not properly exposed via the 34 33 standard ACPI devices. 34 + 35 + config EC_LENOVO_YOGA_C630 36 + tristate "Lenovo Yoga C630 Embedded Controller driver" 37 + depends on ARCH_QCOM || COMPILE_TEST 38 + depends on I2C 39 + select AUXILIARY_BUS 40 + help 41 + Driver for the Embedded Controller in the Qualcomm Snapdragon-based 42 + Lenovo Yoga C630, which provides battery and power adapter 43 + information. 44 + 45 + This driver provides battery and AC status support for the mentioned 46 + laptop where this information is not properly exposed via the 47 + standard ACPI devices. 48 + 49 + Say M or Y here to include this support. 35 50 36 51 endif # ARM64_PLATFORM_DEVICES
+1
drivers/platform/arm64/Makefile
··· 6 6 # 7 7 8 8 obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o 9 + obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o
+291
drivers/platform/arm64/lenovo-yoga-c630.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2022-2024, Linaro Ltd 4 + * Authors: 5 + * Bjorn Andersson 6 + * Dmitry Baryshkov 7 + */ 8 + #include <linux/auxiliary_bus.h> 9 + #include <linux/cleanup.h> 10 + #include <linux/device.h> 11 + #include <linux/err.h> 12 + #include <linux/i2c.h> 13 + #include <linux/irqreturn.h> 14 + #include <linux/lockdep.h> 15 + #include <linux/module.h> 16 + #include <linux/mutex.h> 17 + #include <linux/notifier.h> 18 + #include <linux/slab.h> 19 + #include <linux/platform_data/lenovo-yoga-c630.h> 20 + 21 + #define LENOVO_EC_RESPONSE_REG 0x01 22 + #define LENOVO_EC_REQUEST_REG 0x02 23 + 24 + #define LENOVO_EC_UCSI_WRITE 0x20 25 + #define LENOVO_EC_UCSI_READ 0x21 26 + 27 + #define LENOVO_EC_READ_REG 0xb0 28 + #define LENOVO_EC_REQUEST_NEXT_EVENT 0x84 29 + 30 + #define LENOVO_EC_UCSI_VERSION 0x20 31 + 32 + struct yoga_c630_ec { 33 + struct i2c_client *client; 34 + struct mutex lock; 35 + struct blocking_notifier_head notifier_list; 36 + }; 37 + 38 + static int yoga_c630_ec_request(struct yoga_c630_ec *ec, u8 *req, size_t req_len, 39 + u8 *resp, size_t resp_len) 40 + { 41 + int ret; 42 + 43 + lockdep_assert_held(&ec->lock); 44 + 45 + ret = i2c_smbus_write_i2c_block_data(ec->client, LENOVO_EC_REQUEST_REG, 46 + req_len, req); 47 + if (ret < 0) 48 + return ret; 49 + 50 + return i2c_smbus_read_i2c_block_data(ec->client, LENOVO_EC_RESPONSE_REG, 51 + resp_len, resp); 52 + } 53 + 54 + int yoga_c630_ec_read8(struct yoga_c630_ec *ec, u8 addr) 55 + { 56 + u8 req[2] = { LENOVO_EC_READ_REG, }; 57 + int ret; 58 + u8 val; 59 + 60 + guard(mutex)(&ec->lock); 61 + 62 + req[1] = addr; 63 + ret = yoga_c630_ec_request(ec, req, sizeof(req), &val, 1); 64 + if (ret < 0) 65 + return ret; 66 + 67 + return val; 68 + } 69 + EXPORT_SYMBOL_GPL(yoga_c630_ec_read8); 70 + 71 + int yoga_c630_ec_read16(struct yoga_c630_ec *ec, u8 addr) 72 + { 73 + u8 req[2] = { LENOVO_EC_READ_REG, }; 74 + int ret; 75 + u8 msb; 76 + u8 lsb; 77 + 78 + /* don't overflow the address */ 79 + if (addr == 0xff) 80 + return -EINVAL; 81 + 82 + guard(mutex)(&ec->lock); 83 + 84 + req[1] = addr; 85 + ret = yoga_c630_ec_request(ec, req, sizeof(req), &lsb, 1); 86 + if (ret < 0) 87 + return ret; 88 + 89 + req[1] = addr + 1; 90 + ret = yoga_c630_ec_request(ec, req, sizeof(req), &msb, 1); 91 + if (ret < 0) 92 + return ret; 93 + 94 + return msb << 8 | lsb; 95 + } 96 + EXPORT_SYMBOL_GPL(yoga_c630_ec_read16); 97 + 98 + u16 yoga_c630_ec_ucsi_get_version(struct yoga_c630_ec *ec) 99 + { 100 + u8 req[3] = { 0xb3, 0xf2, }; 101 + int ret; 102 + u8 msb; 103 + u8 lsb; 104 + 105 + guard(mutex)(&ec->lock); 106 + 107 + req[2] = LENOVO_EC_UCSI_VERSION; 108 + ret = yoga_c630_ec_request(ec, req, sizeof(req), &lsb, 1); 109 + if (ret < 0) 110 + return ret; 111 + 112 + req[2] = LENOVO_EC_UCSI_VERSION + 1; 113 + ret = yoga_c630_ec_request(ec, req, sizeof(req), &msb, 1); 114 + if (ret < 0) 115 + return ret; 116 + 117 + return msb << 8 | lsb; 118 + } 119 + EXPORT_SYMBOL_GPL(yoga_c630_ec_ucsi_get_version); 120 + 121 + int yoga_c630_ec_ucsi_write(struct yoga_c630_ec *ec, 122 + const u8 req[YOGA_C630_UCSI_WRITE_SIZE]) 123 + { 124 + int ret; 125 + 126 + mutex_lock(&ec->lock); 127 + ret = i2c_smbus_write_i2c_block_data(ec->client, LENOVO_EC_UCSI_WRITE, 128 + YOGA_C630_UCSI_WRITE_SIZE, req); 129 + mutex_unlock(&ec->lock); 130 + 131 + return ret < 0 ? ret : 0; 132 + } 133 + EXPORT_SYMBOL_GPL(yoga_c630_ec_ucsi_write); 134 + 135 + int yoga_c630_ec_ucsi_read(struct yoga_c630_ec *ec, 136 + u8 resp[YOGA_C630_UCSI_READ_SIZE]) 137 + { 138 + int ret; 139 + 140 + mutex_lock(&ec->lock); 141 + ret = i2c_smbus_read_i2c_block_data(ec->client, LENOVO_EC_UCSI_READ, 142 + YOGA_C630_UCSI_READ_SIZE, resp); 143 + mutex_unlock(&ec->lock); 144 + 145 + return ret < 0 ? ret : 0; 146 + } 147 + EXPORT_SYMBOL_GPL(yoga_c630_ec_ucsi_read); 148 + 149 + static irqreturn_t yoga_c630_ec_thread_intr(int irq, void *data) 150 + { 151 + u8 req[] = { LENOVO_EC_REQUEST_NEXT_EVENT }; 152 + struct yoga_c630_ec *ec = data; 153 + u8 event; 154 + int ret; 155 + 156 + mutex_lock(&ec->lock); 157 + ret = yoga_c630_ec_request(ec, req, sizeof(req), &event, 1); 158 + mutex_unlock(&ec->lock); 159 + if (ret < 0) 160 + return IRQ_HANDLED; 161 + 162 + blocking_notifier_call_chain(&ec->notifier_list, event, ec); 163 + 164 + return IRQ_HANDLED; 165 + } 166 + 167 + /** 168 + * yoga_c630_ec_register_notify - Register a notifier callback for EC events. 169 + * @ec: Yoga C630 EC 170 + * @nb: Notifier block pointer to register 171 + * 172 + * Return: 0 on success or negative error code. 173 + */ 174 + int yoga_c630_ec_register_notify(struct yoga_c630_ec *ec, struct notifier_block *nb) 175 + { 176 + return blocking_notifier_chain_register(&ec->notifier_list, nb); 177 + } 178 + EXPORT_SYMBOL_GPL(yoga_c630_ec_register_notify); 179 + 180 + /** 181 + * yoga_c630_ec_unregister_notify - Unregister notifier callback for EC events. 182 + * @ec: Yoga C630 EC 183 + * @nb: Notifier block pointer to unregister 184 + * 185 + * Unregister a notifier callback that was previously registered with 186 + * yoga_c630_ec_register_notify(). 187 + */ 188 + void yoga_c630_ec_unregister_notify(struct yoga_c630_ec *ec, struct notifier_block *nb) 189 + { 190 + blocking_notifier_chain_unregister(&ec->notifier_list, nb); 191 + } 192 + EXPORT_SYMBOL_GPL(yoga_c630_ec_unregister_notify); 193 + 194 + static void yoga_c630_aux_release(struct device *dev) 195 + { 196 + struct auxiliary_device *adev = to_auxiliary_dev(dev); 197 + 198 + kfree(adev); 199 + } 200 + 201 + static void yoga_c630_aux_remove(void *data) 202 + { 203 + struct auxiliary_device *adev = data; 204 + 205 + auxiliary_device_delete(adev); 206 + auxiliary_device_uninit(adev); 207 + } 208 + 209 + static int yoga_c630_aux_init(struct device *parent, const char *name, 210 + struct yoga_c630_ec *ec) 211 + { 212 + struct auxiliary_device *adev; 213 + int ret; 214 + 215 + adev = kzalloc(sizeof(*adev), GFP_KERNEL); 216 + if (!adev) 217 + return -ENOMEM; 218 + 219 + adev->name = name; 220 + adev->id = 0; 221 + adev->dev.parent = parent; 222 + adev->dev.release = yoga_c630_aux_release; 223 + adev->dev.platform_data = ec; 224 + 225 + ret = auxiliary_device_init(adev); 226 + if (ret) { 227 + kfree(adev); 228 + return ret; 229 + } 230 + 231 + ret = auxiliary_device_add(adev); 232 + if (ret) { 233 + auxiliary_device_uninit(adev); 234 + return ret; 235 + } 236 + 237 + return devm_add_action_or_reset(parent, yoga_c630_aux_remove, adev); 238 + } 239 + 240 + static int yoga_c630_ec_probe(struct i2c_client *client) 241 + { 242 + struct device *dev = &client->dev; 243 + struct yoga_c630_ec *ec; 244 + int ret; 245 + 246 + ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); 247 + if (!ec) 248 + return -ENOMEM; 249 + 250 + mutex_init(&ec->lock); 251 + ec->client = client; 252 + BLOCKING_INIT_NOTIFIER_HEAD(&ec->notifier_list); 253 + 254 + ret = devm_request_threaded_irq(dev, client->irq, 255 + NULL, yoga_c630_ec_thread_intr, 256 + IRQF_ONESHOT, "yoga_c630_ec", ec); 257 + if (ret < 0) 258 + return dev_err_probe(dev, ret, "unable to request irq\n"); 259 + 260 + ret = yoga_c630_aux_init(dev, YOGA_C630_DEV_PSY, ec); 261 + if (ret) 262 + return ret; 263 + 264 + return yoga_c630_aux_init(dev, YOGA_C630_DEV_UCSI, ec); 265 + } 266 + 267 + 268 + static const struct of_device_id yoga_c630_ec_of_match[] = { 269 + { .compatible = "lenovo,yoga-c630-ec" }, 270 + {} 271 + }; 272 + MODULE_DEVICE_TABLE(of, yoga_c630_ec_of_match); 273 + 274 + static const struct i2c_device_id yoga_c630_ec_i2c_id_table[] = { 275 + { "yoga-c630-ec", }, 276 + {} 277 + }; 278 + MODULE_DEVICE_TABLE(i2c, yoga_c630_ec_i2c_id_table); 279 + 280 + static struct i2c_driver yoga_c630_ec_i2c_driver = { 281 + .driver = { 282 + .name = "yoga-c630-ec", 283 + .of_match_table = yoga_c630_ec_of_match 284 + }, 285 + .probe = yoga_c630_ec_probe, 286 + .id_table = yoga_c630_ec_i2c_id_table, 287 + }; 288 + module_i2c_driver(yoga_c630_ec_i2c_driver); 289 + 290 + MODULE_DESCRIPTION("Lenovo Yoga C630 Embedded Controller"); 291 + MODULE_LICENSE("GPL");
+2
drivers/platform/x86/amd/pmf/pmf.h
··· 12 12 #define PMF_H 13 13 14 14 #include <linux/acpi.h> 15 + #include <linux/input.h> 15 16 #include <linux/platform_profile.h> 16 17 17 18 #define POLICY_BUF_MAX_SZ 0x4b000 ··· 301 300 void __iomem *policy_base; 302 301 bool smart_pc_enabled; 303 302 u16 pmf_if_version; 303 + struct input_dev *pmf_idev; 304 304 }; 305 305 306 306 struct apmf_sps_prop_granular_v2 {
+53 -20
drivers/platform/x86/amd/pmf/tee-if.c
··· 62 62 param[0].u.memref.shm_offs = 0; 63 63 } 64 64 65 - static int amd_pmf_update_uevents(struct amd_pmf_dev *dev, u16 event) 65 + static void amd_pmf_update_uevents(struct amd_pmf_dev *dev, u16 event) 66 66 { 67 - char *envp[2] = {}; 68 - 69 - envp[0] = kasprintf(GFP_KERNEL, "EVENT_ID=%d", event); 70 - if (!envp[0]) 71 - return -EINVAL; 72 - 73 - kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, envp); 74 - 75 - kfree(envp[0]); 76 - return 0; 67 + input_report_key(dev->pmf_idev, event, 1); /* key press */ 68 + input_sync(dev->pmf_idev); 69 + input_report_key(dev->pmf_idev, event, 0); /* key release */ 70 + input_sync(dev->pmf_idev); 77 71 } 78 72 79 73 static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out) ··· 143 149 break; 144 150 145 151 case PMF_POLICY_SYSTEM_STATE: 146 - amd_pmf_update_uevents(dev, val); 152 + switch (val) { 153 + case 0: 154 + amd_pmf_update_uevents(dev, KEY_SLEEP); 155 + break; 156 + case 1: 157 + amd_pmf_update_uevents(dev, KEY_SUSPEND); 158 + break; 159 + case 2: 160 + amd_pmf_update_uevents(dev, KEY_SCREENLOCK); 161 + break; 162 + default: 163 + dev_err(dev->dev, "Invalid PMF policy system state: %d\n", val); 164 + } 165 + 147 166 dev_dbg(dev->dev, "update SYSTEM_STATE: %s\n", 148 167 amd_pmf_uevent_as_str(val)); 149 168 break; ··· 308 301 return -EINVAL; 309 302 310 303 /* re-alloc to the new buffer length of the policy binary */ 311 - new_policy_buf = kzalloc(length, GFP_KERNEL); 312 - if (!new_policy_buf) 313 - return -ENOMEM; 314 - 315 - if (copy_from_user(new_policy_buf, buf, length)) { 316 - kfree(new_policy_buf); 317 - return -EFAULT; 318 - } 304 + new_policy_buf = memdup_user(buf, length); 305 + if (IS_ERR(new_policy_buf)) 306 + return PTR_ERR(new_policy_buf); 319 307 320 308 kfree(dev->policy_buf); 321 309 dev->policy_buf = new_policy_buf; ··· 368 366 *id = sess_arg.session; 369 367 370 368 return rc; 369 + } 370 + 371 + static int amd_pmf_register_input_device(struct amd_pmf_dev *dev) 372 + { 373 + int err; 374 + 375 + dev->pmf_idev = devm_input_allocate_device(dev->dev); 376 + if (!dev->pmf_idev) 377 + return -ENOMEM; 378 + 379 + dev->pmf_idev->name = "PMF-TA output events"; 380 + dev->pmf_idev->phys = "amd-pmf/input0"; 381 + 382 + input_set_capability(dev->pmf_idev, EV_KEY, KEY_SLEEP); 383 + input_set_capability(dev->pmf_idev, EV_KEY, KEY_SCREENLOCK); 384 + input_set_capability(dev->pmf_idev, EV_KEY, KEY_SUSPEND); 385 + 386 + err = input_register_device(dev->pmf_idev); 387 + if (err) { 388 + dev_err(dev->dev, "Failed to register input device: %d\n", err); 389 + return err; 390 + } 391 + 392 + return 0; 371 393 } 372 394 373 395 static int amd_pmf_tee_init(struct amd_pmf_dev *dev) ··· 501 475 if (pb_side_load) 502 476 amd_pmf_open_pb(dev, dev->dbgfs_dir); 503 477 478 + ret = amd_pmf_register_input_device(dev); 479 + if (ret) 480 + goto error; 481 + 504 482 return 0; 505 483 506 484 error: ··· 515 485 516 486 void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev) 517 487 { 488 + if (dev->pmf_idev) 489 + input_unregister_device(dev->pmf_idev); 490 + 518 491 if (pb_side_load && dev->esbin) 519 492 amd_pmf_remove_pb(dev); 520 493
+5 -5
drivers/platform/x86/asus-tf103c-dock.c
··· 490 490 return; 491 491 } 492 492 493 - strscpy(board_info.type, "elan_i2c", I2C_NAME_SIZE); 493 + strscpy(board_info.type, "elan_i2c"); 494 494 board_info.addr = TF103C_DOCK_TP_ADDR; 495 495 board_info.dev_name = TF103C_DOCK_DEV_NAME "-tp"; 496 496 board_info.irq = dock->tp_irq; ··· 795 795 */ 796 796 dock->ec_client = client; 797 797 798 - strscpy(board_info.type, "tf103c-dock-intr", I2C_NAME_SIZE); 798 + strscpy(board_info.type, "tf103c-dock-intr"); 799 799 board_info.addr = TF103C_DOCK_INTR_ADDR; 800 800 board_info.dev_name = TF103C_DOCK_DEV_NAME "-intr"; 801 801 ··· 803 803 if (IS_ERR(dock->intr_client)) 804 804 return dev_err_probe(dev, PTR_ERR(dock->intr_client), "creating intr client\n"); 805 805 806 - strscpy(board_info.type, "tf103c-dock-kbd", I2C_NAME_SIZE); 806 + strscpy(board_info.type, "tf103c-dock-kbd"); 807 807 board_info.addr = TF103C_DOCK_KBD_ADDR; 808 808 board_info.dev_name = TF103C_DOCK_DEV_NAME "-kbd"; 809 809 ··· 846 846 dock->hid->vendor = 0x0b05; /* USB_VENDOR_ID_ASUSTEK */ 847 847 dock->hid->product = 0x0103; /* From TF-103-C */ 848 848 dock->hid->version = 0x0100; /* 1.0 */ 849 - strscpy(dock->hid->name, "Asus TF103C Dock Keyboard", sizeof(dock->hid->name)); 850 - strscpy(dock->hid->phys, dev_name(dev), sizeof(dock->hid->phys)); 849 + strscpy(dock->hid->name, "Asus TF103C Dock Keyboard"); 850 + strscpy(dock->hid->phys, dev_name(dev)); 851 851 852 852 ret = hid_add_device(dock->hid); 853 853 if (ret)
+40 -1
drivers/platform/x86/asus-wmi.c
··· 238 238 struct led_classdev lightbar_led; 239 239 int lightbar_led_wk; 240 240 struct led_classdev micmute_led; 241 + struct led_classdev camera_led; 241 242 struct workqueue_struct *led_workqueue; 242 243 struct work_struct tpd_led_work; 243 244 struct work_struct wlan_led_work; ··· 880 879 struct device_attribute *attr, 881 880 const char *buf, size_t count) 882 881 { 883 - struct asus_wmi *asus = dev_get_drvdata(dev); 884 882 u32 cmd, mode, r, g, b, speed; 883 + struct led_classdev *led; 884 + struct asus_wmi *asus; 885 885 int err; 886 + 887 + led = dev_get_drvdata(dev); 888 + asus = container_of(led, struct asus_wmi, kbd_led); 886 889 887 890 if (sscanf(buf, "%d %d %d %d %d %d", &cmd, &mode, &r, &g, &b, &speed) != 6) 888 891 return -EINVAL; ··· 1647 1642 return err < 0 ? err : 0; 1648 1643 } 1649 1644 1645 + static enum led_brightness camera_led_get(struct led_classdev *led_cdev) 1646 + { 1647 + struct asus_wmi *asus; 1648 + u32 result; 1649 + 1650 + asus = container_of(led_cdev, struct asus_wmi, camera_led); 1651 + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CAMERA_LED, &result); 1652 + 1653 + return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; 1654 + } 1655 + 1656 + static int camera_led_set(struct led_classdev *led_cdev, 1657 + enum led_brightness brightness) 1658 + { 1659 + int state = brightness != LED_OFF; 1660 + int err; 1661 + 1662 + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CAMERA_LED, state, NULL); 1663 + return err < 0 ? err : 0; 1664 + } 1665 + 1650 1666 static void asus_wmi_led_exit(struct asus_wmi *asus) 1651 1667 { 1652 1668 led_classdev_unregister(&asus->kbd_led); ··· 1675 1649 led_classdev_unregister(&asus->wlan_led); 1676 1650 led_classdev_unregister(&asus->lightbar_led); 1677 1651 led_classdev_unregister(&asus->micmute_led); 1652 + led_classdev_unregister(&asus->camera_led); 1678 1653 1679 1654 if (asus->led_workqueue) 1680 1655 destroy_workqueue(asus->led_workqueue); ··· 1763 1736 1764 1737 rv = led_classdev_register(&asus->platform_device->dev, 1765 1738 &asus->micmute_led); 1739 + if (rv) 1740 + goto error; 1741 + } 1742 + 1743 + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CAMERA_LED)) { 1744 + asus->camera_led.name = "asus::camera"; 1745 + asus->camera_led.max_brightness = 1; 1746 + asus->camera_led.brightness_get = camera_led_get; 1747 + asus->camera_led.brightness_set_blocking = camera_led_set; 1748 + 1749 + rv = led_classdev_register(&asus->platform_device->dev, 1750 + &asus->camera_led); 1766 1751 if (rv) 1767 1752 goto error; 1768 1753 }
+13
drivers/platform/x86/dell/Kconfig
··· 91 91 To compile this driver as a module, choose M here: the module will 92 92 be called dell-rbtn. 93 93 94 + config DELL_PC 95 + tristate "Dell PC Extras" 96 + default m 97 + depends on ACPI 98 + depends on DMI 99 + depends on DELL_SMBIOS 100 + select ACPI_PLATFORM_PROFILE 101 + help 102 + This driver adds support for controlling the fan modes via platform_profile 103 + on supported Dell systems regardless of formfactor. 104 + Module will simply do nothing if thermal management commands are not 105 + supported. 106 + 94 107 # 95 108 # The DELL_SMBIOS driver depends on ACPI_WMI and/or DCDBAS if those 96 109 # backends are selected. The "depends" line prevents a configuration
+1
drivers/platform/x86/dell/Makefile
··· 9 9 obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 10 10 obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o 11 11 obj-$(CONFIG_DELL_RBU) += dell_rbu.o 12 + obj-$(CONFIG_DELL_PC) += dell-pc.o 12 13 obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o 13 14 dell-smbios-objs := dell-smbios-base.o 14 15 dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
-23
drivers/platform/x86/dell/dell-laptop.c
··· 353 353 { } 354 354 }; 355 355 356 - static void dell_fill_request(struct calling_interface_buffer *buffer, 357 - u32 arg0, u32 arg1, u32 arg2, u32 arg3) 358 - { 359 - memset(buffer, 0, sizeof(struct calling_interface_buffer)); 360 - buffer->input[0] = arg0; 361 - buffer->input[1] = arg1; 362 - buffer->input[2] = arg2; 363 - buffer->input[3] = arg3; 364 - } 365 - 366 - static int dell_send_request(struct calling_interface_buffer *buffer, 367 - u16 class, u16 select) 368 - { 369 - int ret; 370 - 371 - buffer->cmd_class = class; 372 - buffer->cmd_select = select; 373 - ret = dell_smbios_call(buffer); 374 - if (ret != 0) 375 - return ret; 376 - return dell_smbios_error(buffer->output[0]); 377 - } 378 - 379 356 /* 380 357 * Derived from information in smbios-wireless-ctl: 381 358 *
+309
drivers/platform/x86/dell/dell-pc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Driver for Dell laptop extras 4 + * 5 + * Copyright (c) Lyndon Sanche <lsanche@lyndeno.ca> 6 + * 7 + * Based on documentation in the libsmbios package: 8 + * Copyright (C) 2005-2014 Dell Inc. 9 + */ 10 + 11 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 + 13 + #include <linux/bitfield.h> 14 + #include <linux/bits.h> 15 + #include <linux/dmi.h> 16 + #include <linux/err.h> 17 + #include <linux/init.h> 18 + #include <linux/kernel.h> 19 + #include <linux/module.h> 20 + #include <linux/platform_profile.h> 21 + #include <linux/slab.h> 22 + 23 + #include "dell-smbios.h" 24 + 25 + static const struct dmi_system_id dell_device_table[] __initconst = { 26 + { 27 + .ident = "Dell Inc.", 28 + .matches = { 29 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 30 + }, 31 + }, 32 + { 33 + .ident = "Dell Computer Corporation", 34 + .matches = { 35 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 36 + }, 37 + }, 38 + { } 39 + }; 40 + MODULE_DEVICE_TABLE(dmi, dell_device_table); 41 + 42 + /* Derived from smbios-thermal-ctl 43 + * 44 + * cbClass 17 45 + * cbSelect 19 46 + * User Selectable Thermal Tables(USTT) 47 + * cbArg1 determines the function to be performed 48 + * cbArg1 0x0 = Get Thermal Information 49 + * cbRES1 Standard return codes (0, -1, -2) 50 + * cbRES2, byte 0 Bitmap of supported thermal modes. A mode is supported if 51 + * its bit is set to 1 52 + * Bit 0 Balanced 53 + * Bit 1 Cool Bottom 54 + * Bit 2 Quiet 55 + * Bit 3 Performance 56 + * cbRES2, byte 1 Bitmap of supported Active Acoustic Controller (AAC) modes. 57 + * Each mode corresponds to the supported thermal modes in 58 + * byte 0. A mode is supported if its bit is set to 1. 59 + * Bit 0 AAC (Balanced) 60 + * Bit 1 AAC (Cool Bottom 61 + * Bit 2 AAC (Quiet) 62 + * Bit 3 AAC (Performance) 63 + * cbRes3, byte 0 Current Thermal Mode 64 + * Bit 0 Balanced 65 + * Bit 1 Cool Bottom 66 + * Bit 2 Quiet 67 + * Bit 3 Performanc 68 + * cbRes3, byte 1 AAC Configuration type 69 + * 0 Global (AAC enable/disable applies to all supported USTT modes) 70 + * 1 USTT mode specific 71 + * cbRes3, byte 2 Current Active Acoustic Controller (AAC) Mode 72 + * If AAC Configuration Type is Global, 73 + * 0 AAC mode disabled 74 + * 1 AAC mode enabled 75 + * If AAC Configuration Type is USTT mode specific (multiple bits may be set), 76 + * Bit 0 AAC (Balanced) 77 + * Bit 1 AAC (Cool Bottom 78 + * Bit 2 AAC (Quiet) 79 + * Bit 3 AAC (Performance) 80 + * cbRes3, byte 3 Current Fan Failure Mode 81 + * Bit 0 Minimal Fan Failure (at least one fan has failed, one fan working) 82 + * Bit 1 Catastrophic Fan Failure (all fans have failed) 83 + * 84 + * cbArg1 0x1 (Set Thermal Information), both desired thermal mode and 85 + * desired AAC mode shall be applied 86 + * cbArg2, byte 0 Desired Thermal Mode to set 87 + * (only one bit may be set for this parameter) 88 + * Bit 0 Balanced 89 + * Bit 1 Cool Bottom 90 + * Bit 2 Quiet 91 + * Bit 3 Performance 92 + * cbArg2, byte 1 Desired Active Acoustic Controller (AAC) Mode to set 93 + * If AAC Configuration Type is Global, 94 + * 0 AAC mode disabled 95 + * 1 AAC mode enabled 96 + * If AAC Configuration Type is USTT mode specific 97 + * (multiple bits may be set for this parameter), 98 + * Bit 0 AAC (Balanced) 99 + * Bit 1 AAC (Cool Bottom 100 + * Bit 2 AAC (Quiet) 101 + * Bit 3 AAC (Performance) 102 + */ 103 + 104 + #define DELL_ACC_GET_FIELD GENMASK(19, 16) 105 + #define DELL_ACC_SET_FIELD GENMASK(11, 8) 106 + #define DELL_THERMAL_SUPPORTED GENMASK(3, 0) 107 + 108 + static struct platform_profile_handler *thermal_handler; 109 + 110 + enum thermal_mode_bits { 111 + DELL_BALANCED = BIT(0), 112 + DELL_COOL_BOTTOM = BIT(1), 113 + DELL_QUIET = BIT(2), 114 + DELL_PERFORMANCE = BIT(3), 115 + }; 116 + 117 + static int thermal_get_mode(void) 118 + { 119 + struct calling_interface_buffer buffer; 120 + int state; 121 + int ret; 122 + 123 + dell_fill_request(&buffer, 0x0, 0, 0, 0); 124 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_THERMAL_MANAGEMENT); 125 + if (ret) 126 + return ret; 127 + state = buffer.output[2]; 128 + if (state & DELL_BALANCED) 129 + return DELL_BALANCED; 130 + else if (state & DELL_COOL_BOTTOM) 131 + return DELL_COOL_BOTTOM; 132 + else if (state & DELL_QUIET) 133 + return DELL_QUIET; 134 + else if (state & DELL_PERFORMANCE) 135 + return DELL_PERFORMANCE; 136 + else 137 + return -ENXIO; 138 + } 139 + 140 + static int thermal_get_supported_modes(int *supported_bits) 141 + { 142 + struct calling_interface_buffer buffer; 143 + int ret; 144 + 145 + dell_fill_request(&buffer, 0x0, 0, 0, 0); 146 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_THERMAL_MANAGEMENT); 147 + /* Thermal function not supported */ 148 + if (ret == -ENXIO) { 149 + *supported_bits = 0; 150 + return 0; 151 + } 152 + if (ret) 153 + return ret; 154 + *supported_bits = FIELD_GET(DELL_THERMAL_SUPPORTED, buffer.output[1]); 155 + return 0; 156 + } 157 + 158 + static int thermal_get_acc_mode(int *acc_mode) 159 + { 160 + struct calling_interface_buffer buffer; 161 + int ret; 162 + 163 + dell_fill_request(&buffer, 0x0, 0, 0, 0); 164 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_THERMAL_MANAGEMENT); 165 + if (ret) 166 + return ret; 167 + *acc_mode = FIELD_GET(DELL_ACC_GET_FIELD, buffer.output[3]); 168 + return 0; 169 + } 170 + 171 + static int thermal_set_mode(enum thermal_mode_bits state) 172 + { 173 + struct calling_interface_buffer buffer; 174 + int ret; 175 + int acc_mode; 176 + 177 + ret = thermal_get_acc_mode(&acc_mode); 178 + if (ret) 179 + return ret; 180 + 181 + dell_fill_request(&buffer, 0x1, FIELD_PREP(DELL_ACC_SET_FIELD, acc_mode) | state, 0, 0); 182 + return dell_send_request(&buffer, CLASS_INFO, SELECT_THERMAL_MANAGEMENT); 183 + } 184 + 185 + static int thermal_platform_profile_set(struct platform_profile_handler *pprof, 186 + enum platform_profile_option profile) 187 + { 188 + switch (profile) { 189 + case PLATFORM_PROFILE_BALANCED: 190 + return thermal_set_mode(DELL_BALANCED); 191 + case PLATFORM_PROFILE_PERFORMANCE: 192 + return thermal_set_mode(DELL_PERFORMANCE); 193 + case PLATFORM_PROFILE_QUIET: 194 + return thermal_set_mode(DELL_QUIET); 195 + case PLATFORM_PROFILE_COOL: 196 + return thermal_set_mode(DELL_COOL_BOTTOM); 197 + default: 198 + return -EOPNOTSUPP; 199 + } 200 + } 201 + 202 + static int thermal_platform_profile_get(struct platform_profile_handler *pprof, 203 + enum platform_profile_option *profile) 204 + { 205 + int ret; 206 + 207 + ret = thermal_get_mode(); 208 + if (ret < 0) 209 + return ret; 210 + 211 + switch (ret) { 212 + case DELL_BALANCED: 213 + *profile = PLATFORM_PROFILE_BALANCED; 214 + break; 215 + case DELL_PERFORMANCE: 216 + *profile = PLATFORM_PROFILE_PERFORMANCE; 217 + break; 218 + case DELL_COOL_BOTTOM: 219 + *profile = PLATFORM_PROFILE_COOL; 220 + break; 221 + case DELL_QUIET: 222 + *profile = PLATFORM_PROFILE_QUIET; 223 + break; 224 + default: 225 + return -EINVAL; 226 + } 227 + 228 + return 0; 229 + } 230 + 231 + static int thermal_init(void) 232 + { 233 + int ret; 234 + int supported_modes; 235 + 236 + /* If thermal commands are not supported, exit without error */ 237 + if (!dell_smbios_class_is_supported(CLASS_INFO)) 238 + return 0; 239 + 240 + /* If thermal modes are not supported, exit without error */ 241 + ret = thermal_get_supported_modes(&supported_modes); 242 + if (ret < 0) 243 + return ret; 244 + if (!supported_modes) 245 + return 0; 246 + 247 + thermal_handler = kzalloc(sizeof(*thermal_handler), GFP_KERNEL); 248 + if (!thermal_handler) 249 + return -ENOMEM; 250 + thermal_handler->profile_get = thermal_platform_profile_get; 251 + thermal_handler->profile_set = thermal_platform_profile_set; 252 + 253 + if (supported_modes & DELL_QUIET) 254 + set_bit(PLATFORM_PROFILE_QUIET, thermal_handler->choices); 255 + if (supported_modes & DELL_COOL_BOTTOM) 256 + set_bit(PLATFORM_PROFILE_COOL, thermal_handler->choices); 257 + if (supported_modes & DELL_BALANCED) 258 + set_bit(PLATFORM_PROFILE_BALANCED, thermal_handler->choices); 259 + if (supported_modes & DELL_PERFORMANCE) 260 + set_bit(PLATFORM_PROFILE_PERFORMANCE, thermal_handler->choices); 261 + 262 + /* Clean up if failed */ 263 + ret = platform_profile_register(thermal_handler); 264 + if (ret) { 265 + kfree(thermal_handler); 266 + thermal_handler = NULL; 267 + } 268 + 269 + return ret; 270 + } 271 + 272 + static void thermal_cleanup(void) 273 + { 274 + if (thermal_handler) { 275 + platform_profile_remove(); 276 + kfree(thermal_handler); 277 + } 278 + } 279 + 280 + static int __init dell_init(void) 281 + { 282 + int ret; 283 + 284 + if (!dmi_check_system(dell_device_table)) 285 + return -ENODEV; 286 + 287 + /* Do not fail module if thermal modes not supported, just skip */ 288 + ret = thermal_init(); 289 + if (ret) 290 + goto fail_thermal; 291 + 292 + return 0; 293 + 294 + fail_thermal: 295 + thermal_cleanup(); 296 + return ret; 297 + } 298 + 299 + static void __exit dell_exit(void) 300 + { 301 + thermal_cleanup(); 302 + } 303 + 304 + module_init(dell_init); 305 + module_exit(dell_exit); 306 + 307 + MODULE_AUTHOR("Lyndon Sanche <lsanche@lyndeno.ca>"); 308 + MODULE_DESCRIPTION("Dell PC driver"); 309 + MODULE_LICENSE("GPL");
+35
drivers/platform/x86/dell/dell-smbios-base.c
··· 77 77 /* handled by kernel: dell-laptop */ 78 78 {0x0000, CLASS_INFO, SELECT_RFKILL}, 79 79 {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT}, 80 + {0x0000, CLASS_INFO, SELECT_THERMAL_MANAGEMENT}, 80 81 }; 81 82 82 83 struct token_range { ··· 321 320 } 322 321 EXPORT_SYMBOL_GPL(dell_smbios_call); 323 322 323 + void dell_fill_request(struct calling_interface_buffer *buffer, 324 + u32 arg0, u32 arg1, u32 arg2, u32 arg3) 325 + { 326 + memset(buffer, 0, sizeof(struct calling_interface_buffer)); 327 + buffer->input[0] = arg0; 328 + buffer->input[1] = arg1; 329 + buffer->input[2] = arg2; 330 + buffer->input[3] = arg3; 331 + } 332 + EXPORT_SYMBOL_GPL(dell_fill_request); 333 + 334 + int dell_send_request(struct calling_interface_buffer *buffer, 335 + u16 class, u16 select) 336 + { 337 + int ret; 338 + 339 + buffer->cmd_class = class; 340 + buffer->cmd_select = select; 341 + ret = dell_smbios_call(buffer); 342 + if (ret != 0) 343 + return ret; 344 + return dell_smbios_error(buffer->output[0]); 345 + } 346 + EXPORT_SYMBOL_GPL(dell_send_request); 347 + 324 348 struct calling_interface_token *dell_smbios_find_token(int tokenid) 325 349 { 326 350 int i; ··· 381 355 blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); 382 356 } 383 357 EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); 358 + 359 + bool dell_smbios_class_is_supported(u16 class) 360 + { 361 + /* Classes over 30 always unsupported */ 362 + if (class > 30) 363 + return false; 364 + return da_supported_commands & (1 << class); 365 + } 366 + EXPORT_SYMBOL_GPL(dell_smbios_class_is_supported); 384 367 385 368 static void __init parse_da_table(const struct dmi_header *dm) 386 369 {
+7
drivers/platform/x86/dell/dell-smbios.h
··· 19 19 /* Classes and selects used only in kernel drivers */ 20 20 #define CLASS_KBD_BACKLIGHT 4 21 21 #define SELECT_KBD_BACKLIGHT 11 22 + #define SELECT_THERMAL_MANAGEMENT 19 22 23 23 24 /* Tokens used in kernel drivers, any of these 24 25 * should be filtered from userspace access ··· 65 64 struct calling_interface_buffer *buffer); 66 65 int dell_smbios_call(struct calling_interface_buffer *buffer); 67 66 67 + void dell_fill_request(struct calling_interface_buffer *buffer, 68 + u32 arg0, u32 arg1, u32 arg2, u32 arg3); 69 + int dell_send_request(struct calling_interface_buffer *buffer, 70 + u16 class, u16 select); 71 + 68 72 struct calling_interface_token *dell_smbios_find_token(int tokenid); 69 73 70 74 enum dell_laptop_notifier_actions { ··· 79 73 int dell_laptop_register_notifier(struct notifier_block *nb); 80 74 int dell_laptop_unregister_notifier(struct notifier_block *nb); 81 75 void dell_laptop_call_notifier(unsigned long action, void *data); 76 + bool dell_smbios_class_is_supported(u16 class); 82 77 83 78 /* for the supported backends */ 84 79 #ifdef CONFIG_DELL_SMBIOS_WMI
+1
drivers/platform/x86/hp/Kconfig
··· 40 40 depends on ACPI_WMI 41 41 depends on INPUT 42 42 depends on RFKILL || RFKILL = n 43 + select POWER_SUPPLY 43 44 select INPUT_SPARSEKMAP 44 45 select ACPI_PLATFORM_PROFILE 45 46 select HWMON
+5 -13
drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c
··· 52 52 { 53 53 struct enumeration_data *enum_data = &bioscfg_drv.enumeration_data[instance_id]; 54 54 55 - strscpy(enum_data->current_value, 56 - attr_value, 57 - sizeof(enum_data->current_value)); 55 + strscpy(enum_data->current_value, attr_value); 58 56 } 59 57 60 58 ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name, enumeration); ··· 172 174 case VALUE: 173 175 break; 174 176 case PATH: 175 - strscpy(enum_data->common.path, str_value, 176 - sizeof(enum_data->common.path)); 177 + strscpy(enum_data->common.path, str_value); 177 178 break; 178 179 case IS_READONLY: 179 180 enum_data->common.is_readonly = int_value; ··· 219 222 if (ret) 220 223 return -EINVAL; 221 224 222 - strscpy(enum_data->common.prerequisites[reqs], 223 - str_value, 224 - sizeof(enum_data->common.prerequisites[reqs])); 225 + strscpy(enum_data->common.prerequisites[reqs], str_value); 225 226 226 227 kfree(str_value); 227 228 str_value = NULL; ··· 231 236 break; 232 237 233 238 case ENUM_CURRENT_VALUE: 234 - strscpy(enum_data->current_value, 235 - str_value, sizeof(enum_data->current_value)); 239 + strscpy(enum_data->current_value, str_value); 236 240 break; 237 241 case ENUM_SIZE: 238 242 if (int_value > MAX_VALUES_SIZE) { ··· 272 278 * is greater than MAX_VALUES_SIZE 273 279 */ 274 280 if (size < MAX_VALUES_SIZE) 275 - strscpy(enum_data->possible_values[pos_values], 276 - str_value, 277 - sizeof(enum_data->possible_values[pos_values])); 281 + strscpy(enum_data->possible_values[pos_values], str_value); 278 282 279 283 kfree(str_value); 280 284 str_value = NULL;
+2 -5
drivers/platform/x86/hp/hp-bioscfg/int-attributes.c
··· 192 192 integer_data->current_value = int_value; 193 193 break; 194 194 case PATH: 195 - strscpy(integer_data->common.path, str_value, 196 - sizeof(integer_data->common.path)); 195 + strscpy(integer_data->common.path, str_value); 197 196 break; 198 197 case IS_READONLY: 199 198 integer_data->common.is_readonly = int_value; ··· 239 240 if (ret) 240 241 continue; 241 242 242 - strscpy(integer_data->common.prerequisites[reqs], 243 - str_value, 244 - sizeof(integer_data->common.prerequisites[reqs])); 243 + strscpy(integer_data->common.prerequisites[reqs], str_value); 245 244 kfree(str_value); 246 245 str_value = NULL; 247 246 }
+5 -13
drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c
··· 57 57 { 58 58 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance]; 59 59 60 - strscpy(ordered_list_data->current_value, 61 - attr_value, 62 - sizeof(ordered_list_data->current_value)); 60 + strscpy(ordered_list_data->current_value, attr_value); 63 61 } 64 62 65 63 ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name, ordered_list); ··· 177 179 /* Assign appropriate element value to corresponding field*/ 178 180 switch (eloc) { 179 181 case VALUE: 180 - strscpy(ordered_list_data->current_value, 181 - str_value, sizeof(ordered_list_data->current_value)); 182 + strscpy(ordered_list_data->current_value, str_value); 182 183 replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP); 183 184 break; 184 185 case PATH: 185 - strscpy(ordered_list_data->common.path, str_value, 186 - sizeof(ordered_list_data->common.path)); 186 + strscpy(ordered_list_data->common.path, str_value); 187 187 break; 188 188 case IS_READONLY: 189 189 ordered_list_data->common.is_readonly = int_value; ··· 223 227 if (ret) 224 228 continue; 225 229 226 - strscpy(ordered_list_data->common.prerequisites[reqs], 227 - str_value, 228 - sizeof(ordered_list_data->common.prerequisites[reqs])); 230 + strscpy(ordered_list_data->common.prerequisites[reqs], str_value); 229 231 230 232 kfree(str_value); 231 233 str_value = NULL; ··· 265 271 part = strsep(&part_tmp, COMMA_SEP); 266 272 267 273 for (olist_elem = 0; olist_elem < MAX_ELEMENTS_SIZE && part; olist_elem++) { 268 - strscpy(ordered_list_data->elements[olist_elem], 269 - part, 270 - sizeof(ordered_list_data->elements[olist_elem])); 274 + strscpy(ordered_list_data->elements[olist_elem], part); 271 275 part = strsep(&part_tmp, COMMA_SEP); 272 276 } 273 277 ordered_list_data->elements_size = olist_elem;
+5 -14
drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c
··· 101 101 102 102 if (!ret) { 103 103 if (is_current) 104 - strscpy(bioscfg_drv.password_data[id].current_password, 105 - buf_cp, 106 - sizeof(bioscfg_drv.password_data[id].current_password)); 104 + strscpy(bioscfg_drv.password_data[id].current_password, buf_cp); 107 105 else 108 - strscpy(bioscfg_drv.password_data[id].new_password, 109 - buf_cp, 110 - sizeof(bioscfg_drv.password_data[id].new_password)); 106 + strscpy(bioscfg_drv.password_data[id].new_password, buf_cp); 111 107 } 112 108 113 109 kfree(buf_cp); ··· 268 272 case VALUE: 269 273 break; 270 274 case PATH: 271 - strscpy(password_data->common.path, str_value, 272 - sizeof(password_data->common.path)); 275 + strscpy(password_data->common.path, str_value); 273 276 break; 274 277 case IS_READONLY: 275 278 password_data->common.is_readonly = int_value; ··· 310 315 if (ret) 311 316 break; 312 317 313 - strscpy(password_data->common.prerequisites[reqs], 314 - str_value, 315 - sizeof(password_data->common.prerequisites[reqs])); 318 + strscpy(password_data->common.prerequisites[reqs], str_value); 316 319 317 320 kfree(str_value); 318 321 str_value = NULL; ··· 352 359 if (ret) 353 360 break; 354 361 355 - strscpy(password_data->encodings[pos_values], 356 - str_value, 357 - sizeof(password_data->encodings[pos_values])); 362 + strscpy(password_data->encodings[pos_values], str_value); 358 363 kfree(str_value); 359 364 str_value = NULL; 360 365
+1 -2
drivers/platform/x86/hp/hp-bioscfg/spmobj-attributes.c
··· 365 365 /* Populate data for Secure Platform Management */ 366 366 bioscfg_drv.spm_data.attr_name_kobj = attr_name_kobj; 367 367 368 - strscpy(bioscfg_drv.spm_data.attribute_name, SPM_STR, 369 - sizeof(bioscfg_drv.spm_data.attribute_name)); 368 + strscpy(bioscfg_drv.spm_data.attribute_name, SPM_STR); 370 369 371 370 bioscfg_drv.spm_data.is_enabled = 0; 372 371 bioscfg_drv.spm_data.mechanism = 0;
+4 -8
drivers/platform/x86/hp/hp-bioscfg/string-attributes.c
··· 50 50 struct string_data *string_data = &bioscfg_drv.string_data[instance_id]; 51 51 52 52 /* Write settings to BIOS */ 53 - strscpy(string_data->current_value, attr_value, sizeof(string_data->current_value)); 53 + strscpy(string_data->current_value, attr_value); 54 54 } 55 55 56 56 /* ··· 178 178 /* Assign appropriate element value to corresponding field*/ 179 179 switch (eloc) { 180 180 case VALUE: 181 - strscpy(string_data->current_value, 182 - str_value, sizeof(string_data->current_value)); 181 + strscpy(string_data->current_value, str_value); 183 182 break; 184 183 case PATH: 185 - strscpy(string_data->common.path, str_value, 186 - sizeof(string_data->common.path)); 184 + strscpy(string_data->common.path, str_value); 187 185 break; 188 186 case IS_READONLY: 189 187 string_data->common.is_readonly = int_value; ··· 229 231 if (ret) 230 232 continue; 231 233 232 - strscpy(string_data->common.prerequisites[reqs], 233 - str_value, 234 - sizeof(string_data->common.prerequisites[reqs])); 234 + strscpy(string_data->common.prerequisites[reqs], str_value); 235 235 kfree(str_value); 236 236 str_value = NULL; 237 237 }
+171 -17
drivers/platform/x86/hp/hp-wmi.c
··· 24 24 #include <linux/platform_profile.h> 25 25 #include <linux/hwmon.h> 26 26 #include <linux/acpi.h> 27 + #include <linux/mutex.h> 28 + #include <linux/cleanup.h> 29 + #include <linux/power_supply.h> 27 30 #include <linux/rfkill.h> 28 31 #include <linux/string.h> 29 32 #include <linux/dmi.h> ··· 44 41 #define HP_OMEN_EC_THERMAL_PROFILE_FLAGS_OFFSET 0x62 45 42 #define HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET 0x63 46 43 #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95 44 + 45 + #define ACPI_AC_CLASS "ac_adapter" 47 46 48 47 #define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required 49 48 ··· 264 259 { KE_END, 0 } 265 260 }; 266 261 262 + /* 263 + * Mutex for the active_platform_profile variable, 264 + * see omen_powersource_event. 265 + */ 266 + static DEFINE_MUTEX(active_platform_profile_lock); 267 + 267 268 static struct input_dev *hp_wmi_input_dev; 268 269 static struct input_dev *camera_shutter_input_dev; 269 270 static struct platform_device *hp_wmi_platform_dev; 270 271 static struct platform_profile_handler platform_profile_handler; 272 + static struct notifier_block platform_power_source_nb; 273 + static enum platform_profile_option active_platform_profile; 271 274 static bool platform_profile_support; 272 275 static bool zero_insize_support; 273 276 ··· 1207 1194 return err; 1208 1195 } 1209 1196 1210 - static int platform_profile_omen_get(struct platform_profile_handler *pprof, 1211 - enum platform_profile_option *profile) 1197 + static int platform_profile_omen_get_ec(enum platform_profile_option *profile) 1212 1198 { 1213 1199 int tp; 1214 1200 ··· 1235 1223 return 0; 1236 1224 } 1237 1225 1226 + static int platform_profile_omen_get(struct platform_profile_handler *pprof, 1227 + enum platform_profile_option *profile) 1228 + { 1229 + /* 1230 + * We directly return the stored platform profile, as the embedded 1231 + * controller will not accept switching to the performance option when 1232 + * the conditions are not met (e.g. the laptop is not plugged in). 1233 + * 1234 + * If we directly return what the EC reports, the platform profile will 1235 + * immediately "switch back" to normal mode, which is against the 1236 + * expected behaviour from a userspace point of view, as described in 1237 + * the Platform Profile Section page of the kernel documentation. 1238 + * 1239 + * See also omen_powersource_event. 1240 + */ 1241 + guard(mutex)(&active_platform_profile_lock); 1242 + *profile = active_platform_profile; 1243 + 1244 + return 0; 1245 + } 1246 + 1238 1247 static bool has_omen_thermal_profile_ec_timer(void) 1239 1248 { 1240 1249 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME); ··· 1278 1245 return ec_write(HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET, value); 1279 1246 } 1280 1247 1281 - static int platform_profile_omen_set(struct platform_profile_handler *pprof, 1282 - enum platform_profile_option profile) 1248 + static int platform_profile_omen_set_ec(enum platform_profile_option profile) 1283 1249 { 1284 1250 int err, tp, tp_version; 1285 1251 enum hp_thermal_profile_omen_flags flags = 0; ··· 1328 1296 if (err < 0) 1329 1297 return err; 1330 1298 } 1299 + 1300 + return 0; 1301 + } 1302 + 1303 + static int platform_profile_omen_set(struct platform_profile_handler *pprof, 1304 + enum platform_profile_option profile) 1305 + { 1306 + int err; 1307 + 1308 + guard(mutex)(&active_platform_profile_lock); 1309 + 1310 + err = platform_profile_omen_set_ec(profile); 1311 + if (err < 0) 1312 + return err; 1313 + 1314 + active_platform_profile = profile; 1331 1315 1332 1316 return 0; 1333 1317 } ··· 1429 1381 board_name) >= 0; 1430 1382 } 1431 1383 1432 - static int platform_profile_victus_get(struct platform_profile_handler *pprof, 1433 - enum platform_profile_option *profile) 1384 + static int platform_profile_victus_get_ec(enum platform_profile_option *profile) 1434 1385 { 1435 1386 int tp; 1436 1387 ··· 1454 1407 return 0; 1455 1408 } 1456 1409 1457 - static int platform_profile_victus_set(struct platform_profile_handler *pprof, 1458 - enum platform_profile_option profile) 1410 + static int platform_profile_victus_get(struct platform_profile_handler *pprof, 1411 + enum platform_profile_option *profile) 1412 + { 1413 + /* Same behaviour as platform_profile_omen_get */ 1414 + return platform_profile_omen_get(pprof, profile); 1415 + } 1416 + 1417 + static int platform_profile_victus_set_ec(enum platform_profile_option profile) 1459 1418 { 1460 1419 int err, tp; 1461 1420 ··· 1486 1433 return 0; 1487 1434 } 1488 1435 1436 + static int platform_profile_victus_set(struct platform_profile_handler *pprof, 1437 + enum platform_profile_option profile) 1438 + { 1439 + int err; 1440 + 1441 + guard(mutex)(&active_platform_profile_lock); 1442 + 1443 + err = platform_profile_victus_set_ec(profile); 1444 + if (err < 0) 1445 + return err; 1446 + 1447 + active_platform_profile = profile; 1448 + 1449 + return 0; 1450 + } 1451 + 1452 + static int omen_powersource_event(struct notifier_block *nb, 1453 + unsigned long value, 1454 + void *data) 1455 + { 1456 + struct acpi_bus_event *event_entry = data; 1457 + enum platform_profile_option actual_profile; 1458 + int err; 1459 + 1460 + if (strcmp(event_entry->device_class, ACPI_AC_CLASS) != 0) 1461 + return NOTIFY_DONE; 1462 + 1463 + pr_debug("Received power source device event\n"); 1464 + 1465 + guard(mutex)(&active_platform_profile_lock); 1466 + 1467 + /* 1468 + * This handler can only be called on Omen and Victus models, so 1469 + * there's no need to call is_victus_thermal_profile() here. 1470 + */ 1471 + if (is_omen_thermal_profile()) 1472 + err = platform_profile_omen_get_ec(&actual_profile); 1473 + else 1474 + err = platform_profile_victus_get_ec(&actual_profile); 1475 + 1476 + if (err < 0) { 1477 + /* 1478 + * Although we failed to get the current platform profile, we 1479 + * still want the other event consumers to process it. 1480 + */ 1481 + pr_warn("Failed to read current platform profile (%d)\n", err); 1482 + return NOTIFY_DONE; 1483 + } 1484 + 1485 + /* 1486 + * If we're back on AC and that the user-chosen power profile is 1487 + * different from what the EC reports, we restore the user-chosen 1488 + * one. 1489 + */ 1490 + if (power_supply_is_system_supplied() <= 0 || 1491 + active_platform_profile == actual_profile) { 1492 + pr_debug("Platform profile update skipped, conditions unmet\n"); 1493 + return NOTIFY_DONE; 1494 + } 1495 + 1496 + if (is_omen_thermal_profile()) 1497 + err = platform_profile_omen_set_ec(active_platform_profile); 1498 + else 1499 + err = platform_profile_victus_set_ec(active_platform_profile); 1500 + 1501 + if (err < 0) { 1502 + pr_warn("Failed to restore platform profile (%d)\n", err); 1503 + return NOTIFY_DONE; 1504 + } 1505 + 1506 + return NOTIFY_OK; 1507 + } 1508 + 1509 + static int omen_register_powersource_event_handler(void) 1510 + { 1511 + int err; 1512 + 1513 + platform_power_source_nb.notifier_call = omen_powersource_event; 1514 + err = register_acpi_notifier(&platform_power_source_nb); 1515 + 1516 + if (err < 0) { 1517 + pr_warn("Failed to install ACPI power source notify handler\n"); 1518 + return err; 1519 + } 1520 + 1521 + return 0; 1522 + } 1523 + 1524 + static inline void omen_unregister_powersource_event_handler(void) 1525 + { 1526 + unregister_acpi_notifier(&platform_power_source_nb); 1527 + } 1528 + 1489 1529 static int thermal_profile_setup(void) 1490 1530 { 1491 1531 int err, tp; 1492 1532 1493 1533 if (is_omen_thermal_profile()) { 1494 - tp = omen_thermal_profile_get(); 1495 - if (tp < 0) 1496 - return tp; 1534 + err = platform_profile_omen_get_ec(&active_platform_profile); 1535 + if (err < 0) 1536 + return err; 1497 1537 1498 1538 /* 1499 1539 * call thermal profile write command to ensure that the 1500 1540 * firmware correctly sets the OEM variables 1501 1541 */ 1502 - 1503 - err = omen_thermal_profile_set(tp); 1542 + err = platform_profile_omen_set_ec(active_platform_profile); 1504 1543 if (err < 0) 1505 1544 return err; 1506 1545 ··· 1601 1456 1602 1457 set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices); 1603 1458 } else if (is_victus_thermal_profile()) { 1604 - tp = omen_thermal_profile_get(); 1605 - if (tp < 0) 1606 - return tp; 1459 + err = platform_profile_victus_get_ec(&active_platform_profile); 1460 + if (err < 0) 1461 + return err; 1607 1462 1608 1463 /* 1609 1464 * call thermal profile write command to ensure that the 1610 1465 * firmware correctly sets the OEM variables 1611 1466 */ 1612 - err = omen_thermal_profile_set(tp); 1467 + err = platform_profile_victus_set_ec(active_platform_profile); 1613 1468 if (err < 0) 1614 1469 return err; 1615 1470 ··· 1903 1758 goto err_unregister_device; 1904 1759 } 1905 1760 1761 + if (is_omen_thermal_profile() || is_victus_thermal_profile()) { 1762 + err = omen_register_powersource_event_handler(); 1763 + if (err) 1764 + goto err_unregister_device; 1765 + } 1766 + 1906 1767 return 0; 1907 1768 1908 1769 err_unregister_device: ··· 1923 1772 1924 1773 static void __exit hp_wmi_exit(void) 1925 1774 { 1775 + if (is_omen_thermal_profile() || is_victus_thermal_profile()) 1776 + omen_unregister_powersource_event_handler(); 1777 + 1926 1778 if (wmi_has_guid(HPWMI_EVENT_GUID)) 1927 1779 hp_wmi_input_destroy(); 1928 1780
+29 -38
drivers/platform/x86/ideapad-laptop.c
··· 13 13 #include <linux/bitfield.h> 14 14 #include <linux/bitops.h> 15 15 #include <linux/bug.h> 16 + #include <linux/cleanup.h> 16 17 #include <linux/debugfs.h> 17 18 #include <linux/device.h> 18 19 #include <linux/dmi.h> ··· 205 204 { 206 205 int ret; 207 206 208 - mutex_lock(&ideapad_shared_mutex); 207 + guard(mutex)(&ideapad_shared_mutex); 209 208 210 209 if (!ideapad_shared) { 211 210 ideapad_shared = priv; ··· 215 214 ret = -EINVAL; 216 215 } 217 216 218 - mutex_unlock(&ideapad_shared_mutex); 219 - 220 217 return ret; 221 218 } 222 219 223 220 static void ideapad_shared_exit(struct ideapad_private *priv) 224 221 { 225 - mutex_lock(&ideapad_shared_mutex); 222 + guard(mutex)(&ideapad_shared_mutex); 226 223 227 224 if (ideapad_shared == priv) 228 225 ideapad_shared = NULL; 229 - 230 - mutex_unlock(&ideapad_shared_mutex); 231 226 } 232 227 233 228 /* ··· 837 840 unsigned long output; 838 841 int err; 839 842 840 - err = mutex_lock_interruptible(&dytc->mutex); 841 - if (err) 842 - return err; 843 + scoped_guard(mutex_intr, &dytc->mutex) { 844 + if (profile == PLATFORM_PROFILE_BALANCED) { 845 + /* To get back to balanced mode we just issue a reset command */ 846 + err = eval_dytc(priv->adev->handle, DYTC_CMD_RESET, NULL); 847 + if (err) 848 + return err; 849 + } else { 850 + int perfmode; 843 851 844 - if (profile == PLATFORM_PROFILE_BALANCED) { 845 - /* To get back to balanced mode we just issue a reset command */ 846 - err = eval_dytc(priv->adev->handle, DYTC_CMD_RESET, NULL); 847 - if (err) 848 - goto unlock; 849 - } else { 850 - int perfmode; 852 + err = convert_profile_to_dytc(profile, &perfmode); 853 + if (err) 854 + return err; 851 855 852 - err = convert_profile_to_dytc(profile, &perfmode); 853 - if (err) 854 - goto unlock; 856 + /* Determine if we are in CQL mode. This alters the commands we do */ 857 + err = dytc_cql_command(priv, 858 + DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), 859 + &output); 860 + if (err) 861 + return err; 862 + } 855 863 856 - /* Determine if we are in CQL mode. This alters the commands we do */ 857 - err = dytc_cql_command(priv, DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), 858 - &output); 859 - if (err) 860 - goto unlock; 864 + /* Success - update current profile */ 865 + dytc->current_profile = profile; 866 + return 0; 861 867 } 862 868 863 - /* Success - update current profile */ 864 - dytc->current_profile = profile; 865 - 866 - unlock: 867 - mutex_unlock(&dytc->mutex); 868 - 869 - return err; 869 + return -EINTR; 870 870 } 871 871 872 872 static void dytc_profile_refresh(struct ideapad_private *priv) ··· 872 878 unsigned long output; 873 879 int err, perfmode; 874 880 875 - mutex_lock(&priv->dytc->mutex); 876 - err = dytc_cql_command(priv, DYTC_CMD_GET, &output); 877 - mutex_unlock(&priv->dytc->mutex); 881 + scoped_guard(mutex, &priv->dytc->mutex) 882 + err = dytc_cql_command(priv, DYTC_CMD_GET, &output); 878 883 if (err) 879 884 return; 880 885 ··· 1802 1809 struct ideapad_wmi_private *wpriv = dev_get_drvdata(&wdev->dev); 1803 1810 struct ideapad_private *priv; 1804 1811 1805 - mutex_lock(&ideapad_shared_mutex); 1812 + guard(mutex)(&ideapad_shared_mutex); 1806 1813 1807 1814 priv = ideapad_shared; 1808 1815 if (!priv) 1809 - goto unlock; 1816 + return; 1810 1817 1811 1818 switch (wpriv->event) { 1812 1819 case IDEAPAD_WMI_EVENT_ESC: ··· 1840 1847 1841 1848 break; 1842 1849 } 1843 - unlock: 1844 - mutex_unlock(&ideapad_shared_mutex); 1845 1850 } 1846 1851 1847 1852 static const struct ideapad_wmi_private ideapad_wmi_context_esc = {
+11
drivers/platform/x86/intel/Kconfig
··· 192 192 This driver checks to determine whether the device has Intel Smart 193 193 Connect enabled, and if so disables it. 194 194 195 + config INTEL_TPMI_POWER_DOMAINS 196 + tristate 197 + 195 198 config INTEL_TPMI 196 199 tristate "Intel Topology Aware Register and PM Capsule Interface (TPMI)" 197 200 depends on INTEL_VSEC 198 201 depends on X86_64 202 + select INTEL_TPMI_POWER_DOMAINS 199 203 help 200 204 The Intel Topology Aware Register and PM Capsule Interface (TPMI), 201 205 provides enumerable MMIO interface for power management features. ··· 208 204 209 205 To compile this driver as a module, choose M here: the module will 210 206 be called intel_vsec_tpmi. 207 + 208 + config INTEL_PLR_TPMI 209 + tristate "Intel SoC TPMI Power Limit Reasons driver" 210 + depends on INTEL_TPMI 211 + help 212 + This driver provides the TPMI power limit reasons status information 213 + via debugfs files. 211 214 212 215 config INTEL_TURBO_MAX_3 213 216 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
+4
drivers/platform/x86/intel/Makefile
··· 52 52 # TPMI drivers 53 53 intel_vsec_tpmi-y := tpmi.o 54 54 obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o 55 + obj-$(CONFIG_INTEL_PLR_TPMI) += intel_plr_tpmi.o 56 + 57 + intel_tpmi_power_domains-y := tpmi_power_domains.o 58 + obj-$(CONFIG_INTEL_TPMI_POWER_DOMAINS) += intel_tpmi_power_domains.o 55 59 56 60 # Intel Uncore drivers 57 61 intel-rst-y := rst.o
+3 -3
drivers/platform/x86/intel/chtwc_int33fe.c
··· 270 270 } 271 271 272 272 memset(&board_info, 0, sizeof(board_info)); 273 - strscpy(board_info.type, "max17047", I2C_NAME_SIZE); 273 + strscpy(board_info.type, "max17047"); 274 274 board_info.dev_name = "max17047"; 275 275 board_info.fwnode = fwnode; 276 276 data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); ··· 361 361 } 362 362 363 363 memset(&board_info, 0, sizeof(board_info)); 364 - strscpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); 364 + strscpy(board_info.type, "typec_fusb302"); 365 365 board_info.dev_name = "fusb302"; 366 366 board_info.fwnode = fwnode; 367 367 board_info.irq = fusb302_irq; ··· 381 381 memset(&board_info, 0, sizeof(board_info)); 382 382 board_info.dev_name = "pi3usb30532"; 383 383 board_info.fwnode = fwnode; 384 - strscpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); 384 + strscpy(board_info.type, "pi3usb30532"); 385 385 386 386 data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); 387 387 if (IS_ERR(data->pi3usb30532)) {
+7 -8
drivers/platform/x86/intel/ifs/core.c
··· 11 11 12 12 #include "ifs.h" 13 13 14 - #define X86_MATCH(model, array_gen) \ 15 - X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \ 16 - INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, array_gen) 14 + #define X86_MATCH(vfm, array_gen) \ 15 + X86_MATCH_VFM_FEATURE(vfm, X86_FEATURE_CORE_CAPABILITIES, array_gen) 17 16 18 17 static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { 19 - X86_MATCH(SAPPHIRERAPIDS_X, ARRAY_GEN0), 20 - X86_MATCH(EMERALDRAPIDS_X, ARRAY_GEN0), 21 - X86_MATCH(GRANITERAPIDS_X, ARRAY_GEN0), 22 - X86_MATCH(GRANITERAPIDS_D, ARRAY_GEN0), 23 - X86_MATCH(ATOM_CRESTMONT_X, ARRAY_GEN1), 18 + X86_MATCH(INTEL_SAPPHIRERAPIDS_X, ARRAY_GEN0), 19 + X86_MATCH(INTEL_EMERALDRAPIDS_X, ARRAY_GEN0), 20 + X86_MATCH(INTEL_GRANITERAPIDS_X, ARRAY_GEN0), 21 + X86_MATCH(INTEL_GRANITERAPIDS_D, ARRAY_GEN0), 22 + X86_MATCH(INTEL_ATOM_CRESTMONT_X, ARRAY_GEN1), 24 23 {} 25 24 }; 26 25 MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);
+354
drivers/platform/x86/intel/intel_plr_tpmi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Performance Limit Reasons via TPMI 4 + * 5 + * Copyright (c) 2024, Intel Corporation. 6 + */ 7 + 8 + #include <linux/array_size.h> 9 + #include <linux/auxiliary_bus.h> 10 + #include <linux/bitfield.h> 11 + #include <linux/bitmap.h> 12 + #include <linux/debugfs.h> 13 + #include <linux/device.h> 14 + #include <linux/err.h> 15 + #include <linux/gfp_types.h> 16 + #include <linux/intel_tpmi.h> 17 + #include <linux/io.h> 18 + #include <linux/iopoll.h> 19 + #include <linux/kstrtox.h> 20 + #include <linux/lockdep.h> 21 + #include <linux/module.h> 22 + #include <linux/mod_devicetable.h> 23 + #include <linux/mutex.h> 24 + #include <linux/seq_file.h> 25 + #include <linux/sprintf.h> 26 + #include <linux/types.h> 27 + 28 + #include "tpmi_power_domains.h" 29 + 30 + #define PLR_HEADER 0x00 31 + #define PLR_MAILBOX_INTERFACE 0x08 32 + #define PLR_MAILBOX_DATA 0x10 33 + #define PLR_DIE_LEVEL 0x18 34 + 35 + #define PLR_MODULE_ID_MASK GENMASK_ULL(19, 12) 36 + #define PLR_RUN_BUSY BIT_ULL(63) 37 + 38 + #define PLR_COMMAND_WRITE 1 39 + 40 + #define PLR_INVALID GENMASK_ULL(63, 0) 41 + 42 + #define PLR_TIMEOUT_US 5 43 + #define PLR_TIMEOUT_MAX_US 1000 44 + 45 + #define PLR_COARSE_REASON_BITS 32 46 + 47 + struct tpmi_plr; 48 + 49 + struct tpmi_plr_die { 50 + void __iomem *base; 51 + struct mutex lock; /* Protect access to PLR mailbox */ 52 + int package_id; 53 + int die_id; 54 + struct tpmi_plr *plr; 55 + }; 56 + 57 + struct tpmi_plr { 58 + struct dentry *dbgfs_dir; 59 + struct tpmi_plr_die *die_info; 60 + int num_dies; 61 + struct auxiliary_device *auxdev; 62 + }; 63 + 64 + static const char * const plr_coarse_reasons[] = { 65 + "FREQUENCY", 66 + "CURRENT", 67 + "POWER", 68 + "THERMAL", 69 + "PLATFORM", 70 + "MCP", 71 + "RAS", 72 + "MISC", 73 + "QOS", 74 + "DFC", 75 + }; 76 + 77 + static const char * const plr_fine_reasons[] = { 78 + "FREQUENCY_CDYN0", 79 + "FREQUENCY_CDYN1", 80 + "FREQUENCY_CDYN2", 81 + "FREQUENCY_CDYN3", 82 + "FREQUENCY_CDYN4", 83 + "FREQUENCY_CDYN5", 84 + "FREQUENCY_FCT", 85 + "FREQUENCY_PCS_TRL", 86 + "CURRENT_MTPMAX", 87 + "POWER_FAST_RAPL", 88 + "POWER_PKG_PL1_MSR_TPMI", 89 + "POWER_PKG_PL1_MMIO", 90 + "POWER_PKG_PL1_PCS", 91 + "POWER_PKG_PL2_MSR_TPMI", 92 + "POWER_PKG_PL2_MMIO", 93 + "POWER_PKG_PL2_PCS", 94 + "POWER_PLATFORM_PL1_MSR_TPMI", 95 + "POWER_PLATFORM_PL1_MMIO", 96 + "POWER_PLATFORM_PL1_PCS", 97 + "POWER_PLATFORM_PL2_MSR_TPMI", 98 + "POWER_PLATFORM_PL2_MMIO", 99 + "POWER_PLATFORM_PL2_PCS", 100 + "UNKNOWN(22)", 101 + "THERMAL_PER_CORE", 102 + "DFC_UFS", 103 + "PLATFORM_PROCHOT", 104 + "PLATFORM_HOT_VR", 105 + "UNKNOWN(27)", 106 + "UNKNOWN(28)", 107 + "MISC_PCS_PSTATE", 108 + }; 109 + 110 + static u64 plr_read(struct tpmi_plr_die *plr_die, int offset) 111 + { 112 + return readq(plr_die->base + offset); 113 + } 114 + 115 + static void plr_write(u64 val, struct tpmi_plr_die *plr_die, int offset) 116 + { 117 + writeq(val, plr_die->base + offset); 118 + } 119 + 120 + static int plr_read_cpu_status(struct tpmi_plr_die *plr_die, int cpu, 121 + u64 *status) 122 + { 123 + u64 regval; 124 + int ret; 125 + 126 + lockdep_assert_held(&plr_die->lock); 127 + 128 + regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); 129 + regval |= PLR_RUN_BUSY; 130 + 131 + plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); 132 + 133 + ret = readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, 134 + !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, 135 + PLR_TIMEOUT_MAX_US); 136 + if (ret) 137 + return ret; 138 + 139 + *status = plr_read(plr_die, PLR_MAILBOX_DATA); 140 + 141 + return 0; 142 + } 143 + 144 + static int plr_clear_cpu_status(struct tpmi_plr_die *plr_die, int cpu) 145 + { 146 + u64 regval; 147 + 148 + lockdep_assert_held(&plr_die->lock); 149 + 150 + regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); 151 + regval |= PLR_RUN_BUSY | PLR_COMMAND_WRITE; 152 + 153 + plr_write(0, plr_die, PLR_MAILBOX_DATA); 154 + 155 + plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); 156 + 157 + return readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, 158 + !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, 159 + PLR_TIMEOUT_MAX_US); 160 + } 161 + 162 + static void plr_print_bits(struct seq_file *s, u64 val, int bits) 163 + { 164 + const unsigned long mask[] = { BITMAP_FROM_U64(val) }; 165 + int bit, index; 166 + 167 + for_each_set_bit(bit, mask, bits) { 168 + const char *str = NULL; 169 + 170 + if (bit < PLR_COARSE_REASON_BITS) { 171 + if (bit < ARRAY_SIZE(plr_coarse_reasons)) 172 + str = plr_coarse_reasons[bit]; 173 + } else { 174 + index = bit - PLR_COARSE_REASON_BITS; 175 + if (index < ARRAY_SIZE(plr_fine_reasons)) 176 + str = plr_fine_reasons[index]; 177 + } 178 + 179 + if (str) 180 + seq_printf(s, " %s", str); 181 + else 182 + seq_printf(s, " UNKNOWN(%d)", bit); 183 + } 184 + 185 + if (!val) 186 + seq_puts(s, " none"); 187 + 188 + seq_putc(s, '\n'); 189 + } 190 + 191 + static int plr_status_show(struct seq_file *s, void *unused) 192 + { 193 + struct tpmi_plr_die *plr_die = s->private; 194 + int ret; 195 + u64 val; 196 + 197 + val = plr_read(plr_die, PLR_DIE_LEVEL); 198 + seq_puts(s, "cpus"); 199 + plr_print_bits(s, val, 32); 200 + 201 + guard(mutex)(&plr_die->lock); 202 + 203 + for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { 204 + if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) 205 + continue; 206 + 207 + if (plr_die->package_id != topology_physical_package_id(cpu)) 208 + continue; 209 + 210 + seq_printf(s, "cpu%d", cpu); 211 + ret = plr_read_cpu_status(plr_die, cpu, &val); 212 + if (ret) { 213 + dev_err(&plr_die->plr->auxdev->dev, "Failed to read PLR for cpu %d, ret=%d\n", 214 + cpu, ret); 215 + return ret; 216 + } 217 + 218 + plr_print_bits(s, val, 64); 219 + } 220 + 221 + return 0; 222 + } 223 + 224 + static ssize_t plr_status_write(struct file *filp, const char __user *ubuf, 225 + size_t count, loff_t *ppos) 226 + { 227 + struct seq_file *s = filp->private_data; 228 + struct tpmi_plr_die *plr_die = s->private; 229 + bool val; 230 + int ret; 231 + 232 + ret = kstrtobool_from_user(ubuf, count, &val); 233 + if (ret) 234 + return ret; 235 + 236 + if (val != 0) 237 + return -EINVAL; 238 + 239 + plr_write(0, plr_die, PLR_DIE_LEVEL); 240 + 241 + guard(mutex)(&plr_die->lock); 242 + 243 + for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { 244 + if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) 245 + continue; 246 + 247 + if (plr_die->package_id != topology_physical_package_id(cpu)) 248 + continue; 249 + 250 + plr_clear_cpu_status(plr_die, cpu); 251 + } 252 + 253 + return count; 254 + } 255 + DEFINE_SHOW_STORE_ATTRIBUTE(plr_status); 256 + 257 + static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) 258 + { 259 + struct intel_tpmi_plat_info *plat_info; 260 + struct dentry *dentry; 261 + int i, num_resources; 262 + struct resource *res; 263 + struct tpmi_plr *plr; 264 + void __iomem *base; 265 + char name[16]; 266 + int err; 267 + 268 + plat_info = tpmi_get_platform_data(auxdev); 269 + if (!plat_info) 270 + return dev_err_probe(&auxdev->dev, -EINVAL, "No platform info\n"); 271 + 272 + dentry = tpmi_get_debugfs_dir(auxdev); 273 + if (!dentry) 274 + return dev_err_probe(&auxdev->dev, -ENODEV, "No TPMI debugfs directory.\n"); 275 + 276 + num_resources = tpmi_get_resource_count(auxdev); 277 + if (!num_resources) 278 + return -EINVAL; 279 + 280 + plr = devm_kzalloc(&auxdev->dev, sizeof(*plr), GFP_KERNEL); 281 + if (!plr) 282 + return -ENOMEM; 283 + 284 + plr->die_info = devm_kcalloc(&auxdev->dev, num_resources, sizeof(*plr->die_info), 285 + GFP_KERNEL); 286 + if (!plr->die_info) 287 + return -ENOMEM; 288 + 289 + plr->num_dies = num_resources; 290 + plr->dbgfs_dir = debugfs_create_dir("plr", dentry); 291 + plr->auxdev = auxdev; 292 + 293 + for (i = 0; i < num_resources; i++) { 294 + res = tpmi_get_resource_at_index(auxdev, i); 295 + if (!res) { 296 + err = dev_err_probe(&auxdev->dev, -EINVAL, "No resource\n"); 297 + goto err; 298 + } 299 + 300 + base = devm_ioremap_resource(&auxdev->dev, res); 301 + if (IS_ERR(base)) { 302 + err = PTR_ERR(base); 303 + goto err; 304 + } 305 + 306 + plr->die_info[i].base = base; 307 + plr->die_info[i].package_id = plat_info->package_id; 308 + plr->die_info[i].die_id = i; 309 + plr->die_info[i].plr = plr; 310 + mutex_init(&plr->die_info[i].lock); 311 + 312 + if (plr_read(&plr->die_info[i], PLR_HEADER) == PLR_INVALID) 313 + continue; 314 + 315 + snprintf(name, sizeof(name), "domain%d", i); 316 + 317 + dentry = debugfs_create_dir(name, plr->dbgfs_dir); 318 + debugfs_create_file("status", 0444, dentry, &plr->die_info[i], 319 + &plr_status_fops); 320 + } 321 + 322 + auxiliary_set_drvdata(auxdev, plr); 323 + 324 + return 0; 325 + 326 + err: 327 + debugfs_remove_recursive(plr->dbgfs_dir); 328 + return err; 329 + } 330 + 331 + static void intel_plr_remove(struct auxiliary_device *auxdev) 332 + { 333 + struct tpmi_plr *plr = auxiliary_get_drvdata(auxdev); 334 + 335 + debugfs_remove_recursive(plr->dbgfs_dir); 336 + } 337 + 338 + static const struct auxiliary_device_id intel_plr_id_table[] = { 339 + { .name = "intel_vsec.tpmi-plr" }, 340 + {} 341 + }; 342 + MODULE_DEVICE_TABLE(auxiliary, intel_plr_id_table); 343 + 344 + static struct auxiliary_driver intel_plr_aux_driver = { 345 + .id_table = intel_plr_id_table, 346 + .remove = intel_plr_remove, 347 + .probe = intel_plr_probe, 348 + }; 349 + module_auxiliary_driver(intel_plr_aux_driver); 350 + 351 + MODULE_IMPORT_NS(INTEL_TPMI); 352 + MODULE_IMPORT_NS(INTEL_TPMI_POWER_DOMAIN); 353 + MODULE_DESCRIPTION("Intel TPMI PLR Driver"); 354 + MODULE_LICENSE("GPL");
+133 -129
drivers/platform/x86/intel/pmc/core.c
··· 87 87 struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 88 88 const struct pmc_reg_map *map = pmc->map; 89 89 u32 reg; 90 - int err; 91 90 92 91 if (!map->etr3_offset) 93 92 return -EOPNOTSUPP; 94 93 95 - mutex_lock(&pmcdev->lock); 94 + guard(mutex)(&pmcdev->lock); 96 95 97 96 /* check if CF9 is locked */ 98 97 reg = pmc_core_reg_read(pmc, map->etr3_offset); 99 - if (reg & ETR3_CF9LOCK) { 100 - err = -EACCES; 101 - goto out_unlock; 102 - } 98 + if (reg & ETR3_CF9LOCK) 99 + return -EACCES; 103 100 104 101 /* write CF9 global reset bit */ 105 102 reg |= ETR3_CF9GR; 106 103 pmc_core_reg_write(pmc, map->etr3_offset, reg); 107 104 108 105 reg = pmc_core_reg_read(pmc, map->etr3_offset); 109 - if (!(reg & ETR3_CF9GR)) { 110 - err = -EIO; 111 - goto out_unlock; 112 - } 106 + if (!(reg & ETR3_CF9GR)) 107 + return -EIO; 113 108 114 - err = 0; 115 - 116 - out_unlock: 117 - mutex_unlock(&pmcdev->lock); 118 - return err; 109 + return 0; 119 110 } 120 111 static umode_t etr3_is_visible(struct kobject *kobj, 121 112 struct attribute *attr, ··· 118 127 const struct pmc_reg_map *map = pmc->map; 119 128 u32 reg; 120 129 121 - mutex_lock(&pmcdev->lock); 122 - reg = pmc_core_reg_read(pmc, map->etr3_offset); 123 - mutex_unlock(&pmcdev->lock); 130 + scoped_guard(mutex, &pmcdev->lock) 131 + reg = pmc_core_reg_read(pmc, map->etr3_offset); 124 132 125 133 return reg & ETR3_CF9LOCK ? attr->mode & (SYSFS_PREALLOC | 0444) : attr->mode; 126 134 } ··· 135 145 if (!map->etr3_offset) 136 146 return -EOPNOTSUPP; 137 147 138 - mutex_lock(&pmcdev->lock); 139 - 140 - reg = pmc_core_reg_read(pmc, map->etr3_offset); 141 - reg &= ETR3_CF9GR | ETR3_CF9LOCK; 142 - 143 - mutex_unlock(&pmcdev->lock); 148 + scoped_guard(mutex, &pmcdev->lock) { 149 + reg = pmc_core_reg_read(pmc, map->etr3_offset); 150 + reg &= ETR3_CF9GR | ETR3_CF9LOCK; 151 + } 144 152 145 153 return sysfs_emit(buf, "0x%08x", reg); 146 154 } ··· 245 257 } 246 258 } 247 259 248 - static int pmc_core_lpm_get_arr_size(const struct pmc_bit_map **maps) 260 + static unsigned int pmc_core_lpm_get_arr_size(const struct pmc_bit_map **maps) 249 261 { 250 - int idx; 262 + unsigned int idx; 251 263 252 264 for (idx = 0; maps[idx]; idx++) 253 265 ;/* Nothing */ ··· 260 272 const char *str, 261 273 const struct pmc_bit_map **maps) 262 274 { 263 - int index, idx, len = 32, bit_mask, arr_size; 264 - u32 *lpm_regs; 275 + unsigned int index, idx, len = 32, arr_size; 276 + u32 bit_mask, *lpm_regs; 265 277 266 278 arr_size = pmc_core_lpm_get_arr_size(maps); 267 279 lpm_regs = kmalloc_array(arr_size, sizeof(*lpm_regs), GFP_KERNEL); ··· 314 326 static int pmc_core_ppfear_show(struct seq_file *s, void *unused) 315 327 { 316 328 struct pmc_dev *pmcdev = s->private; 317 - int i; 329 + unsigned int i; 318 330 319 331 for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 320 332 struct pmc *pmc = pmcdev->pmcs[i]; 321 333 const struct pmc_bit_map **maps; 322 334 u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES]; 323 - int index, iter, idx, ip = 0; 335 + unsigned int index, iter, idx, ip = 0; 324 336 325 337 if (!pmc) 326 338 continue; ··· 379 391 const struct pmc_bit_map *map = pmc->map->mphy_sts; 380 392 u32 mphy_core_reg_low, mphy_core_reg_high; 381 393 u32 val_low, val_high; 382 - int index, err = 0; 394 + unsigned int index; 395 + int err = 0; 383 396 384 397 if (pmcdev->pmc_xram_read_bit) { 385 398 seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); ··· 390 401 mphy_core_reg_low = (SPT_PMC_MPHY_CORE_STS_0 << 16); 391 402 mphy_core_reg_high = (SPT_PMC_MPHY_CORE_STS_1 << 16); 392 403 393 - mutex_lock(&pmcdev->lock); 404 + guard(mutex)(&pmcdev->lock); 394 405 395 - if (pmc_core_send_msg(pmc, &mphy_core_reg_low) != 0) { 396 - err = -EBUSY; 397 - goto out_unlock; 398 - } 406 + err = pmc_core_send_msg(pmc, &mphy_core_reg_low); 407 + if (err) 408 + return err; 399 409 400 410 msleep(10); 401 411 val_low = pmc_core_reg_read(pmc, SPT_PMC_MFPMC_OFFSET); 402 412 403 - if (pmc_core_send_msg(pmc, &mphy_core_reg_high) != 0) { 404 - err = -EBUSY; 405 - goto out_unlock; 406 - } 413 + err = pmc_core_send_msg(pmc, &mphy_core_reg_high); 414 + if (err) 415 + return err; 407 416 408 417 msleep(10); 409 418 val_high = pmc_core_reg_read(pmc, SPT_PMC_MFPMC_OFFSET); ··· 420 433 "Power gated"); 421 434 } 422 435 423 - out_unlock: 424 - mutex_unlock(&pmcdev->lock); 425 - return err; 436 + return 0; 426 437 } 427 438 DEFINE_SHOW_ATTRIBUTE(pmc_core_mphy_pg); 428 439 ··· 430 445 struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 431 446 const struct pmc_bit_map *map = pmc->map->pll_sts; 432 447 u32 mphy_common_reg, val; 433 - int index, err = 0; 448 + unsigned int index; 449 + int err = 0; 434 450 435 451 if (pmcdev->pmc_xram_read_bit) { 436 452 seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); ··· 439 453 } 440 454 441 455 mphy_common_reg = (SPT_PMC_MPHY_COM_STS_0 << 16); 442 - mutex_lock(&pmcdev->lock); 456 + guard(mutex)(&pmcdev->lock); 443 457 444 - if (pmc_core_send_msg(pmc, &mphy_common_reg) != 0) { 445 - err = -EBUSY; 446 - goto out_unlock; 447 - } 458 + err = pmc_core_send_msg(pmc, &mphy_common_reg); 459 + if (err) 460 + return err; 448 461 449 462 /* Observed PMC HW response latency for MTPMC-MFPMC is ~10 ms */ 450 463 msleep(10); ··· 455 470 map[index].bit_mask & val ? "Active" : "Idle"); 456 471 } 457 472 458 - out_unlock: 459 - mutex_unlock(&pmcdev->lock); 460 - return err; 473 + return 0; 461 474 } 462 475 DEFINE_SHOW_ATTRIBUTE(pmc_core_pll); 463 476 ··· 464 481 struct pmc *pmc; 465 482 const struct pmc_reg_map *map; 466 483 u32 reg; 467 - int pmc_index, ltr_index; 484 + unsigned int pmc_index; 485 + int ltr_index; 468 486 469 487 ltr_index = value; 470 488 /* For platforms with multiple pmcs, ltr index value given by user ··· 495 511 496 512 pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_index, ltr_index); 497 513 498 - mutex_lock(&pmcdev->lock); 514 + guard(mutex)(&pmcdev->lock); 499 515 500 516 reg = pmc_core_reg_read(pmc, map->ltr_ignore_offset); 501 517 if (ignore) ··· 504 520 reg &= ~BIT(ltr_index); 505 521 pmc_core_reg_write(pmc, map->ltr_ignore_offset, reg); 506 522 507 - mutex_unlock(&pmcdev->lock); 508 - 509 523 return 0; 524 + } 525 + 526 + static ssize_t pmc_core_ltr_write(struct pmc_dev *pmcdev, 527 + const char __user *userbuf, 528 + size_t count, int ignore) 529 + { 530 + u32 value; 531 + int err; 532 + 533 + err = kstrtou32_from_user(userbuf, count, 10, &value); 534 + if (err) 535 + return err; 536 + 537 + err = pmc_core_send_ltr_ignore(pmcdev, value, ignore); 538 + 539 + return err ?: count; 510 540 } 511 541 512 542 static ssize_t pmc_core_ltr_ignore_write(struct file *file, ··· 529 531 { 530 532 struct seq_file *s = file->private_data; 531 533 struct pmc_dev *pmcdev = s->private; 532 - u32 buf_size, value; 533 - int err; 534 534 535 - buf_size = min_t(u32, count, 64); 536 - 537 - err = kstrtou32_from_user(userbuf, buf_size, 10, &value); 538 - if (err) 539 - return err; 540 - 541 - err = pmc_core_send_ltr_ignore(pmcdev, value, 1); 542 - 543 - return err == 0 ? count : err; 535 + return pmc_core_ltr_write(pmcdev, userbuf, count, 1); 544 536 } 545 537 546 538 static int pmc_core_ltr_ignore_show(struct seq_file *s, void *unused) 547 539 { 548 540 return 0; 549 541 } 542 + DEFINE_SHOW_STORE_ATTRIBUTE(pmc_core_ltr_ignore); 550 543 551 - static int pmc_core_ltr_ignore_open(struct inode *inode, struct file *file) 544 + static ssize_t pmc_core_ltr_restore_write(struct file *file, 545 + const char __user *userbuf, 546 + size_t count, loff_t *ppos) 552 547 { 553 - return single_open(file, pmc_core_ltr_ignore_show, inode->i_private); 548 + struct seq_file *s = file->private_data; 549 + struct pmc_dev *pmcdev = s->private; 550 + 551 + return pmc_core_ltr_write(pmcdev, userbuf, count, 0); 554 552 } 555 553 556 - static const struct file_operations pmc_core_ltr_ignore_ops = { 557 - .open = pmc_core_ltr_ignore_open, 558 - .read = seq_read, 559 - .write = pmc_core_ltr_ignore_write, 560 - .llseek = seq_lseek, 561 - .release = single_release, 562 - }; 554 + static int pmc_core_ltr_restore_show(struct seq_file *s, void *unused) 555 + { 556 + return 0; 557 + } 558 + DEFINE_SHOW_STORE_ATTRIBUTE(pmc_core_ltr_restore); 563 559 564 560 static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset) 565 561 { ··· 561 569 const struct pmc_reg_map *map = pmc->map; 562 570 u32 fd; 563 571 564 - mutex_lock(&pmcdev->lock); 572 + guard(mutex)(&pmcdev->lock); 565 573 566 574 if (!reset && !slps0_dbg_latch) 567 - goto out_unlock; 575 + return; 568 576 569 577 fd = pmc_core_reg_read(pmc, map->slps0_dbg_offset); 570 578 if (reset) ··· 574 582 pmc_core_reg_write(pmc, map->slps0_dbg_offset, fd); 575 583 576 584 slps0_dbg_latch = false; 577 - 578 - out_unlock: 579 - mutex_unlock(&pmcdev->lock); 580 585 } 581 586 582 587 static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused) ··· 628 639 u64 decoded_snoop_ltr, decoded_non_snoop_ltr; 629 640 u32 ltr_raw_data, scale, val; 630 641 u16 snoop_ltr, nonsnoop_ltr; 631 - int i, index, ltr_index = 0; 642 + unsigned int i, index, ltr_index = 0; 632 643 633 644 for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 634 - struct pmc *pmc = pmcdev->pmcs[i]; 645 + struct pmc *pmc; 635 646 const struct pmc_bit_map *map; 647 + u32 ltr_ign_reg; 636 648 649 + pmc = pmcdev->pmcs[i]; 637 650 if (!pmc) 638 651 continue; 639 652 653 + scoped_guard(mutex, &pmcdev->lock) 654 + ltr_ign_reg = pmc_core_reg_read(pmc, pmc->map->ltr_ignore_offset); 655 + 640 656 map = pmc->map->ltr_show_sts; 641 657 for (index = 0; map[index].name; index++) { 658 + bool ltr_ign_data; 659 + 660 + if (index > pmc->map->ltr_ignore_max) 661 + ltr_ign_data = false; 662 + else 663 + ltr_ign_data = ltr_ign_reg & BIT(index); 664 + 642 665 decoded_snoop_ltr = decoded_non_snoop_ltr = 0; 643 666 ltr_raw_data = pmc_core_reg_read(pmc, 644 667 map[index].bit_mask); ··· 668 667 decoded_snoop_ltr = val * convert_ltr_scale(scale); 669 668 } 670 669 671 - seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\n", 670 + seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\tLTR_IGNORE: %d\n", 672 671 ltr_index, i, map[index].name, ltr_raw_data, 673 672 decoded_non_snoop_ltr, 674 - decoded_snoop_ltr); 673 + decoded_snoop_ltr, ltr_ign_data); 675 674 ltr_index++; 676 675 } 677 676 } ··· 728 727 struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 729 728 const int lpm_adj_x2 = pmc->map->lpm_res_counter_step_x2; 730 729 u32 offset = pmc->map->lpm_residency_offset; 731 - int i, mode; 730 + unsigned int i; 731 + int mode; 732 732 733 733 seq_printf(s, "%-10s %-15s\n", "Substate", "Residency"); 734 734 ··· 745 743 static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused) 746 744 { 747 745 struct pmc_dev *pmcdev = s->private; 748 - int i; 746 + unsigned int i; 749 747 750 748 for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 751 749 struct pmc *pmc = pmcdev->pmcs[i]; ··· 766 764 static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused) 767 765 { 768 766 struct pmc_dev *pmcdev = s->private; 769 - int i; 767 + unsigned int i; 770 768 771 769 for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 772 770 struct pmc *pmc = pmcdev->pmcs[i]; ··· 787 785 static void pmc_core_substate_req_header_show(struct seq_file *s, int pmc_index) 788 786 { 789 787 struct pmc_dev *pmcdev = s->private; 790 - int i, mode; 788 + unsigned int i; 789 + int mode; 791 790 792 791 seq_printf(s, "%30s |", "Element"); 793 792 pmc_for_each_mode(i, mode, pmcdev) ··· 802 799 struct pmc_dev *pmcdev = s->private; 803 800 u32 sts_offset; 804 801 u32 *lpm_req_regs; 805 - int num_maps, mp, pmc_index; 802 + unsigned int mp, pmc_index; 803 + int num_maps; 806 804 807 805 for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs); ++pmc_index) { 808 806 struct pmc *pmc = pmcdev->pmcs[pmc_index]; ··· 925 921 { 926 922 struct pmc_dev *pmcdev = s->private; 927 923 struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 924 + unsigned int idx; 928 925 bool c10; 929 926 u32 reg; 930 - int idx, mode; 927 + int mode; 931 928 932 929 reg = pmc_core_reg_read(pmc, pmc->map->lpm_sts_latch_en_offset); 933 930 if (reg & LPM_STS_LATCH_MODE) { ··· 960 955 struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 961 956 bool clear = false, c10 = false; 962 957 unsigned char buf[8]; 963 - int idx, m, mode; 958 + unsigned int idx; 959 + int m, mode; 964 960 u32 reg; 965 961 966 962 if (count > sizeof(buf) - 1) ··· 993 987 } 994 988 995 989 if (clear) { 996 - mutex_lock(&pmcdev->lock); 990 + guard(mutex)(&pmcdev->lock); 997 991 998 992 reg = pmc_core_reg_read(pmc, pmc->map->etr3_offset); 999 993 reg |= ETR3_CLEAR_LPM_EVENTS; 1000 994 pmc_core_reg_write(pmc, pmc->map->etr3_offset, reg); 1001 995 1002 - mutex_unlock(&pmcdev->lock); 1003 - 1004 996 return count; 1005 997 } 1006 998 1007 999 if (c10) { 1008 - mutex_lock(&pmcdev->lock); 1000 + guard(mutex)(&pmcdev->lock); 1009 1001 1010 1002 reg = pmc_core_reg_read(pmc, pmc->map->lpm_sts_latch_en_offset); 1011 1003 reg &= ~LPM_STS_LATCH_MODE; 1012 1004 pmc_core_reg_write(pmc, pmc->map->lpm_sts_latch_en_offset, reg); 1013 - 1014 - mutex_unlock(&pmcdev->lock); 1015 1005 1016 1006 return count; 1017 1007 } ··· 1017 1015 * and clear everything else. 1018 1016 */ 1019 1017 reg = LPM_STS_LATCH_MODE | BIT(mode); 1020 - mutex_lock(&pmcdev->lock); 1018 + guard(mutex)(&pmcdev->lock); 1021 1019 pmc_core_reg_write(pmc, pmc->map->lpm_sts_latch_en_offset, reg); 1022 - mutex_unlock(&pmcdev->lock); 1023 1020 1024 1021 return count; 1025 1022 } ··· 1029 1028 struct pmc *pmc = s->private; 1030 1029 const struct pmc_bit_map *map = pmc->map->msr_sts; 1031 1030 u64 pcstate_count; 1032 - int index; 1031 + unsigned int index; 1033 1032 1034 1033 for (index = 0; map[index].name ; index++) { 1035 1034 if (rdmsrl_safe(map[index].bit_mask, &pcstate_count)) ··· 1047 1046 1048 1047 static bool pmc_core_pri_verify(u32 lpm_pri, u8 *mode_order) 1049 1048 { 1050 - int i, j; 1049 + unsigned int i, j; 1051 1050 1052 1051 if (!lpm_pri) 1053 1052 return false; ··· 1082 1081 u8 mode_order[LPM_MAX_NUM_MODES]; 1083 1082 u32 lpm_pri; 1084 1083 u32 lpm_en; 1085 - int mode, i, p; 1084 + unsigned int i; 1085 + int mode, p; 1086 1086 1087 1087 /* Use LPM Maps to indicate support for substates */ 1088 1088 if (!pmc->map->lpm_num_maps) ··· 1230 1228 pmcdev, &pmc_core_ppfear_fops); 1231 1229 1232 1230 debugfs_create_file("ltr_ignore", 0644, dir, pmcdev, 1233 - &pmc_core_ltr_ignore_ops); 1231 + &pmc_core_ltr_ignore_fops); 1232 + 1233 + debugfs_create_file("ltr_restore", 0200, dir, pmcdev, &pmc_core_ltr_restore_fops); 1234 1234 1235 1235 debugfs_create_file("ltr_show", 0444, dir, pmcdev, &pmc_core_ltr_fops); 1236 1236 ··· 1297 1293 } 1298 1294 1299 1295 static const struct x86_cpu_id intel_pmc_core_ids[] = { 1300 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, spt_core_init), 1301 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, spt_core_init), 1302 - X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, spt_core_init), 1303 - X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, spt_core_init), 1304 - X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, cnp_core_init), 1305 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, icl_core_init), 1306 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI, icl_core_init), 1307 - X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, cnp_core_init), 1308 - X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, cnp_core_init), 1309 - X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, tgl_l_core_init), 1310 - X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, tgl_core_init), 1311 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT, tgl_l_core_init), 1312 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, icl_core_init), 1313 - X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, tgl_core_init), 1314 - X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, tgl_l_core_init), 1315 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, tgl_l_core_init), 1316 - X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, adl_core_init), 1317 - X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, tgl_l_core_init), 1318 - X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, adl_core_init), 1319 - X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, adl_core_init), 1320 - X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, mtl_core_init), 1321 - X86_MATCH_INTEL_FAM6_MODEL(ARROWLAKE, arl_core_init), 1322 - X86_MATCH_INTEL_FAM6_MODEL(LUNARLAKE_M, lnl_core_init), 1296 + X86_MATCH_VFM(INTEL_SKYLAKE_L, spt_core_init), 1297 + X86_MATCH_VFM(INTEL_SKYLAKE, spt_core_init), 1298 + X86_MATCH_VFM(INTEL_KABYLAKE_L, spt_core_init), 1299 + X86_MATCH_VFM(INTEL_KABYLAKE, spt_core_init), 1300 + X86_MATCH_VFM(INTEL_CANNONLAKE_L, cnp_core_init), 1301 + X86_MATCH_VFM(INTEL_ICELAKE_L, icl_core_init), 1302 + X86_MATCH_VFM(INTEL_ICELAKE_NNPI, icl_core_init), 1303 + X86_MATCH_VFM(INTEL_COMETLAKE, cnp_core_init), 1304 + X86_MATCH_VFM(INTEL_COMETLAKE_L, cnp_core_init), 1305 + X86_MATCH_VFM(INTEL_TIGERLAKE_L, tgl_l_core_init), 1306 + X86_MATCH_VFM(INTEL_TIGERLAKE, tgl_core_init), 1307 + X86_MATCH_VFM(INTEL_ATOM_TREMONT, tgl_l_core_init), 1308 + X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, icl_core_init), 1309 + X86_MATCH_VFM(INTEL_ROCKETLAKE, tgl_core_init), 1310 + X86_MATCH_VFM(INTEL_ALDERLAKE_L, tgl_l_core_init), 1311 + X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, tgl_l_core_init), 1312 + X86_MATCH_VFM(INTEL_ALDERLAKE, adl_core_init), 1313 + X86_MATCH_VFM(INTEL_RAPTORLAKE_P, tgl_l_core_init), 1314 + X86_MATCH_VFM(INTEL_RAPTORLAKE, adl_core_init), 1315 + X86_MATCH_VFM(INTEL_RAPTORLAKE_S, adl_core_init), 1316 + X86_MATCH_VFM(INTEL_METEORLAKE_L, mtl_core_init), 1317 + X86_MATCH_VFM(INTEL_ARROWLAKE, arl_core_init), 1318 + X86_MATCH_VFM(INTEL_LUNARLAKE_M, lnl_core_init), 1323 1319 {} 1324 1320 }; 1325 1321 ··· 1377 1373 static void pmc_core_clean_structure(struct platform_device *pdev) 1378 1374 { 1379 1375 struct pmc_dev *pmcdev = platform_get_drvdata(pdev); 1380 - int i; 1376 + unsigned int i; 1381 1377 1382 1378 for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 1383 1379 struct pmc *pmc = pmcdev->pmcs[i]; ··· 1540 1536 struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; 1541 1537 const struct pmc_bit_map **maps = pmc->map->lpm_sts; 1542 1538 int offset = pmc->map->lpm_status_offset; 1543 - int i; 1539 + unsigned int i; 1544 1540 1545 1541 /* Check if the syspend used S0ix */ 1546 1542 if (pm_suspend_via_firmware())
+8 -8
drivers/platform/x86/intel/pmc/pltdrv.c
··· 35 35 * other list may grow, but this list should not. 36 36 */ 37 37 static const struct x86_cpu_id intel_pmc_core_platform_ids[] = { 38 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &pmc_core_device), 39 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &pmc_core_device), 40 - X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &pmc_core_device), 41 - X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &pmc_core_device), 42 - X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &pmc_core_device), 43 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &pmc_core_device), 44 - X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &pmc_core_device), 45 - X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &pmc_core_device), 38 + X86_MATCH_VFM(INTEL_SKYLAKE_L, &pmc_core_device), 39 + X86_MATCH_VFM(INTEL_SKYLAKE, &pmc_core_device), 40 + X86_MATCH_VFM(INTEL_KABYLAKE_L, &pmc_core_device), 41 + X86_MATCH_VFM(INTEL_KABYLAKE, &pmc_core_device), 42 + X86_MATCH_VFM(INTEL_CANNONLAKE_L, &pmc_core_device), 43 + X86_MATCH_VFM(INTEL_ICELAKE_L, &pmc_core_device), 44 + X86_MATCH_VFM(INTEL_COMETLAKE, &pmc_core_device), 45 + X86_MATCH_VFM(INTEL_COMETLAKE_L, &pmc_core_device), 46 46 {} 47 47 }; 48 48 MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_platform_ids);
+49 -26
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
··· 718 718 .fops = &isst_if_char_driver_ops, 719 719 }; 720 720 721 - static const struct x86_cpu_id hpm_cpu_ids[] = { 722 - X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_D, NULL), 723 - X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_X, NULL), 724 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT, NULL), 725 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT_X, NULL), 726 - {} 727 - }; 728 - 729 721 static int isst_misc_reg(void) 730 722 { 731 723 mutex_lock(&punit_misc_dev_reg_lock); ··· 725 733 goto unlock_exit; 726 734 727 735 if (!misc_usage_count) { 728 - const struct x86_cpu_id *id; 729 - 730 - id = x86_match_cpu(hpm_cpu_ids); 731 - if (id) 732 - isst_hpm_support = true; 733 - 734 736 misc_device_ret = isst_if_cpu_info_init(); 735 737 if (misc_device_ret) 736 738 goto unlock_exit; ··· 772 786 */ 773 787 int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb) 774 788 { 775 - int ret; 776 - 777 789 if (device_type >= ISST_IF_DEV_MAX) 778 790 return -EINVAL; 791 + 792 + if (device_type < ISST_IF_DEV_TPMI && isst_hpm_support) 793 + return -ENODEV; 779 794 780 795 mutex_lock(&punit_misc_dev_open_lock); 781 796 /* Device is already open, we don't want to add new callbacks */ ··· 792 805 punit_callbacks[device_type].registered = 1; 793 806 mutex_unlock(&punit_misc_dev_open_lock); 794 807 795 - ret = isst_misc_reg(); 796 - if (ret) { 797 - /* 798 - * No need of mutex as the misc device register failed 799 - * as no one can open device yet. Hence no contention. 800 - */ 801 - punit_callbacks[device_type].registered = 0; 802 - return ret; 803 - } 804 808 return 0; 805 809 } 806 810 EXPORT_SYMBOL_GPL(isst_if_cdev_register); ··· 807 829 */ 808 830 void isst_if_cdev_unregister(int device_type) 809 831 { 810 - isst_misc_unreg(); 811 832 mutex_lock(&punit_misc_dev_open_lock); 812 833 punit_callbacks[device_type].def_ioctl = NULL; 813 834 punit_callbacks[device_type].registered = 0; ··· 815 838 mutex_unlock(&punit_misc_dev_open_lock); 816 839 } 817 840 EXPORT_SYMBOL_GPL(isst_if_cdev_unregister); 841 + 842 + #define SST_HPM_SUPPORTED 0x01 843 + #define SST_MBOX_SUPPORTED 0x02 844 + 845 + static const struct x86_cpu_id isst_cpu_ids[] = { 846 + X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, SST_HPM_SUPPORTED), 847 + X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, SST_HPM_SUPPORTED), 848 + X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, 0), 849 + X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, SST_HPM_SUPPORTED), 850 + X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, SST_HPM_SUPPORTED), 851 + X86_MATCH_VFM(INTEL_ICELAKE_D, 0), 852 + X86_MATCH_VFM(INTEL_ICELAKE_X, 0), 853 + X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, 0), 854 + X86_MATCH_VFM(INTEL_SKYLAKE_X, SST_MBOX_SUPPORTED), 855 + {} 856 + }; 857 + MODULE_DEVICE_TABLE(x86cpu, isst_cpu_ids); 858 + 859 + static int __init isst_if_common_init(void) 860 + { 861 + const struct x86_cpu_id *id; 862 + 863 + id = x86_match_cpu(isst_cpu_ids); 864 + if (!id) 865 + return -ENODEV; 866 + 867 + if (id->driver_data == SST_HPM_SUPPORTED) { 868 + isst_hpm_support = true; 869 + } else if (id->driver_data == SST_MBOX_SUPPORTED) { 870 + u64 data; 871 + 872 + /* Can fail only on some Skylake-X generations */ 873 + if (rdmsrl_safe(MSR_OS_MAILBOX_INTERFACE, &data) || 874 + rdmsrl_safe(MSR_OS_MAILBOX_DATA, &data)) 875 + return -ENODEV; 876 + } 877 + 878 + return isst_misc_reg(); 879 + } 880 + module_init(isst_if_common_init) 881 + 882 + static void __exit isst_if_common_exit(void) 883 + { 884 + isst_misc_unreg(); 885 + } 886 + module_exit(isst_if_common_exit) 818 887 819 888 MODULE_DESCRIPTION("ISST common interface module"); 820 889 MODULE_LICENSE("GPL v2");
+3
drivers/platform/x86/intel/speed_select_if/isst_if_common.h
··· 16 16 #define PCI_DEVICE_ID_INTEL_RAPL_PRIO_DEVID_1 0x3251 17 17 #define PCI_DEVICE_ID_INTEL_CFG_MBOX_DEVID_1 0x3259 18 18 19 + #define MSR_OS_MAILBOX_INTERFACE 0xB0 20 + #define MSR_OS_MAILBOX_DATA 0xB1 21 + 19 22 /* 20 23 * Validate maximum commands in a single request. 21 24 * This is enough to handle command to every core in one ioctl, or all
+1 -3
drivers/platform/x86/intel/speed_select_if/isst_if_mbox_msr.c
··· 21 21 22 22 #include "isst_if_common.h" 23 23 24 - #define MSR_OS_MAILBOX_INTERFACE 0xB0 25 - #define MSR_OS_MAILBOX_DATA 0xB1 26 24 #define MSR_OS_MAILBOX_BUSY_BIT 31 27 25 28 26 /* ··· 159 161 }; 160 162 161 163 static const struct x86_cpu_id isst_if_cpu_ids[] = { 162 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL), 164 + X86_MATCH_VFM(INTEL_SKYLAKE_X, NULL), 163 165 {} 164 166 }; 165 167 MODULE_DEVICE_TABLE(x86cpu, isst_if_cpu_ids);
+2 -2
drivers/platform/x86/intel/telemetry/debugfs.c
··· 308 308 }; 309 309 310 310 static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = { 311 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &telem_apl_debugfs_conf), 312 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &telem_apl_debugfs_conf), 311 + X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, &telem_apl_debugfs_conf), 312 + X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS, &telem_apl_debugfs_conf), 313 313 {} 314 314 }; 315 315 MODULE_DEVICE_TABLE(x86cpu, telemetry_debugfs_cpu_ids);
+2 -2
drivers/platform/x86/intel/telemetry/pltdrv.c
··· 177 177 }; 178 178 179 179 static const struct x86_cpu_id telemetry_cpu_ids[] = { 180 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &telem_apl_config), 181 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &telem_glk_config), 180 + X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, &telem_apl_config), 181 + X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS, &telem_glk_config), 182 182 {} 183 183 }; 184 184
+11
drivers/platform/x86/intel/tpmi.c
··· 357 357 } 358 358 EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI); 359 359 360 + struct dentry *tpmi_get_debugfs_dir(struct auxiliary_device *auxdev) 361 + { 362 + struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); 363 + struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); 364 + 365 + return tpmi_info->dbgfs_dir; 366 + } 367 + EXPORT_SYMBOL_NS_GPL(tpmi_get_debugfs_dir, INTEL_TPMI); 368 + 360 369 static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused) 361 370 { 362 371 struct intel_tpmi_info *tpmi_info = s->private; ··· 586 577 return "uncore"; 587 578 case TPMI_ID_SST: 588 579 return "sst"; 580 + case TPMI_ID_PLR: 581 + return "plr"; 589 582 default: 590 583 return NULL; 591 584 }
+235
drivers/platform/x86/intel/tpmi_power_domains.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Mapping of TPMI power domains CPU mapping 4 + * 5 + * Copyright (c) 2024, Intel Corporation. 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/cleanup.h> 10 + #include <linux/cpuhotplug.h> 11 + #include <linux/cpumask.h> 12 + #include <linux/errno.h> 13 + #include <linux/export.h> 14 + #include <linux/hashtable.h> 15 + #include <linux/module.h> 16 + #include <linux/mutex.h> 17 + #include <linux/overflow.h> 18 + #include <linux/slab.h> 19 + #include <linux/topology.h> 20 + #include <linux/types.h> 21 + 22 + #include <asm/cpu_device_id.h> 23 + #include <asm/intel-family.h> 24 + #include <asm/msr.h> 25 + 26 + #include "tpmi_power_domains.h" 27 + 28 + #define MSR_PM_LOGICAL_ID 0x54 29 + 30 + /* 31 + * Struct of MSR 0x54 32 + * [15:11] PM_DOMAIN_ID 33 + * [10:3] MODULE_ID (aka IDI_AGENT_ID) 34 + * [2:0] LP_ID 35 + * For Atom: 36 + * [2] Always 0 37 + * [1:0] core ID within module 38 + * For Core 39 + * [2:1] Always 0 40 + * [0] thread ID 41 + */ 42 + 43 + #define LP_ID_MASK GENMASK_ULL(2, 0) 44 + #define MODULE_ID_MASK GENMASK_ULL(10, 3) 45 + #define PM_DOMAIN_ID_MASK GENMASK_ULL(15, 11) 46 + 47 + /** 48 + * struct tpmi_cpu_info - Mapping information for a CPU 49 + * @hnode: Used to add mapping information to hash list 50 + * @linux_cpu: Linux CPU number 51 + * @pkg_id: Package ID of this CPU 52 + * @punit_thread_id: Punit thread id of this CPU 53 + * @punit_core_id: Punit core id 54 + * @punit_domain_id: Power domain id from Punit 55 + * 56 + * Structure to store mapping information for a Linux CPU 57 + * to a Punit core, thread and power domain. 58 + */ 59 + struct tpmi_cpu_info { 60 + struct hlist_node hnode; 61 + int linux_cpu; 62 + u8 pkg_id; 63 + u8 punit_thread_id; 64 + u8 punit_core_id; 65 + u8 punit_domain_id; 66 + }; 67 + 68 + static DEFINE_PER_CPU(struct tpmi_cpu_info, tpmi_cpu_info); 69 + 70 + /* The dynamically assigned cpu hotplug state to free later */ 71 + static enum cpuhp_state tpmi_hp_state __read_mostly; 72 + 73 + #define MAX_POWER_DOMAINS 8 74 + 75 + static cpumask_t *tpmi_power_domain_mask; 76 + 77 + /* Lock to protect tpmi_power_domain_mask and tpmi_cpu_hash */ 78 + static DEFINE_MUTEX(tpmi_lock); 79 + 80 + static const struct x86_cpu_id tpmi_cpu_ids[] = { 81 + X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, NULL), 82 + X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, NULL), 83 + X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, NULL), 84 + X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, NULL), 85 + {} 86 + }; 87 + MODULE_DEVICE_TABLE(x86cpu, tpmi_cpu_ids); 88 + 89 + static DECLARE_HASHTABLE(tpmi_cpu_hash, 8); 90 + 91 + static bool tpmi_domain_is_valid(struct tpmi_cpu_info *info) 92 + { 93 + return info->pkg_id < topology_max_packages() && 94 + info->punit_domain_id < MAX_POWER_DOMAINS; 95 + } 96 + 97 + int tpmi_get_linux_cpu_number(int package_id, int domain_id, int punit_core_id) 98 + { 99 + struct tpmi_cpu_info *info; 100 + int ret = -EINVAL; 101 + 102 + guard(mutex)(&tpmi_lock); 103 + hash_for_each_possible(tpmi_cpu_hash, info, hnode, punit_core_id) { 104 + if (info->punit_domain_id == domain_id && info->pkg_id == package_id) { 105 + ret = info->linux_cpu; 106 + break; 107 + } 108 + } 109 + 110 + return ret; 111 + } 112 + EXPORT_SYMBOL_NS_GPL(tpmi_get_linux_cpu_number, INTEL_TPMI_POWER_DOMAIN); 113 + 114 + int tpmi_get_punit_core_number(int cpu_no) 115 + { 116 + if (cpu_no >= num_possible_cpus()) 117 + return -EINVAL; 118 + 119 + return per_cpu(tpmi_cpu_info, cpu_no).punit_core_id; 120 + } 121 + EXPORT_SYMBOL_NS_GPL(tpmi_get_punit_core_number, INTEL_TPMI_POWER_DOMAIN); 122 + 123 + int tpmi_get_power_domain_id(int cpu_no) 124 + { 125 + if (cpu_no >= num_possible_cpus()) 126 + return -EINVAL; 127 + 128 + return per_cpu(tpmi_cpu_info, cpu_no).punit_domain_id; 129 + } 130 + EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_id, INTEL_TPMI_POWER_DOMAIN); 131 + 132 + cpumask_t *tpmi_get_power_domain_mask(int cpu_no) 133 + { 134 + struct tpmi_cpu_info *info; 135 + cpumask_t *mask; 136 + int index; 137 + 138 + if (cpu_no >= num_possible_cpus()) 139 + return NULL; 140 + 141 + info = &per_cpu(tpmi_cpu_info, cpu_no); 142 + if (!tpmi_domain_is_valid(info)) 143 + return NULL; 144 + 145 + index = info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id; 146 + guard(mutex)(&tpmi_lock); 147 + mask = &tpmi_power_domain_mask[index]; 148 + 149 + return mask; 150 + } 151 + EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_mask, INTEL_TPMI_POWER_DOMAIN); 152 + 153 + static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info) 154 + { 155 + u64 data; 156 + int ret; 157 + 158 + ret = rdmsrl_safe(MSR_PM_LOGICAL_ID, &data); 159 + if (ret) 160 + return ret; 161 + 162 + info->punit_domain_id = FIELD_GET(PM_DOMAIN_ID_MASK, data); 163 + if (info->punit_domain_id >= MAX_POWER_DOMAINS) 164 + return -EINVAL; 165 + 166 + info->punit_thread_id = FIELD_GET(LP_ID_MASK, data); 167 + info->punit_core_id = FIELD_GET(MODULE_ID_MASK, data); 168 + info->pkg_id = topology_physical_package_id(cpu); 169 + info->linux_cpu = cpu; 170 + 171 + return 0; 172 + } 173 + 174 + static int tpmi_cpu_online(unsigned int cpu) 175 + { 176 + struct tpmi_cpu_info *info = &per_cpu(tpmi_cpu_info, cpu); 177 + int ret, index; 178 + 179 + /* Don't fail CPU online for some bad mapping of CPUs */ 180 + ret = tpmi_get_logical_id(cpu, info); 181 + if (ret) 182 + return 0; 183 + 184 + index = info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id; 185 + 186 + guard(mutex)(&tpmi_lock); 187 + cpumask_set_cpu(cpu, &tpmi_power_domain_mask[index]); 188 + hash_add(tpmi_cpu_hash, &info->hnode, info->punit_core_id); 189 + 190 + return 0; 191 + } 192 + 193 + static int __init tpmi_init(void) 194 + { 195 + const struct x86_cpu_id *id; 196 + u64 data; 197 + int ret; 198 + 199 + id = x86_match_cpu(tpmi_cpu_ids); 200 + if (!id) 201 + return -ENODEV; 202 + 203 + /* Check for MSR 0x54 presence */ 204 + ret = rdmsrl_safe(MSR_PM_LOGICAL_ID, &data); 205 + if (ret) 206 + return ret; 207 + 208 + tpmi_power_domain_mask = kcalloc(size_mul(topology_max_packages(), MAX_POWER_DOMAINS), 209 + sizeof(*tpmi_power_domain_mask), GFP_KERNEL); 210 + if (!tpmi_power_domain_mask) 211 + return -ENOMEM; 212 + 213 + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 214 + "platform/x86/tpmi_power_domains:online", 215 + tpmi_cpu_online, NULL); 216 + if (ret < 0) { 217 + kfree(tpmi_power_domain_mask); 218 + return ret; 219 + } 220 + 221 + tpmi_hp_state = ret; 222 + 223 + return 0; 224 + } 225 + module_init(tpmi_init) 226 + 227 + static void __exit tpmi_exit(void) 228 + { 229 + cpuhp_remove_state(tpmi_hp_state); 230 + kfree(tpmi_power_domain_mask); 231 + } 232 + module_exit(tpmi_exit) 233 + 234 + MODULE_DESCRIPTION("TPMI Power Domains Mapping"); 235 + MODULE_LICENSE("GPL");
+18
drivers/platform/x86/intel/tpmi_power_domains.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Mapping of TPMI power domain and CPUs 4 + * 5 + * Copyright (c) 2024, Intel Corporation. 6 + */ 7 + 8 + #ifndef _TPMI_POWER_DOMAINS_H_ 9 + #define _TPMI_POWER_DOMAINS_H_ 10 + 11 + #include <linux/cpumask.h> 12 + 13 + int tpmi_get_linux_cpu_number(int package_id, int die_id, int punit_core_id); 14 + int tpmi_get_punit_core_number(int cpu_no); 15 + int tpmi_get_power_domain_id(int cpu_no); 16 + cpumask_t *tpmi_get_power_domain_mask(int cpu_no); 17 + 18 + #endif
+2 -2
drivers/platform/x86/intel/turbo_max_3.c
··· 114 114 } 115 115 116 116 static const struct x86_cpu_id itmt_legacy_cpu_ids[] = { 117 - X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, NULL), 118 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL), 117 + X86_MATCH_VFM(INTEL_BROADWELL_X, NULL), 118 + X86_MATCH_VFM(INTEL_SKYLAKE_X, NULL), 119 119 {} 120 120 }; 121 121
+27 -56
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
··· 19 19 static DEFINE_IDA(intel_uncore_ida); 20 20 21 21 /* callbacks for actual HW read/write */ 22 - static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max); 23 - static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max); 24 - static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq); 22 + static int (*uncore_read)(struct uncore_data *data, unsigned int *value, enum uncore_index index); 23 + static int (*uncore_write)(struct uncore_data *data, unsigned int input, enum uncore_index index); 25 24 26 25 static ssize_t show_domain_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 27 26 { ··· 43 44 return sprintf(buf, "%u\n", data->package_id); 44 45 } 45 46 46 - static ssize_t show_min_max_freq_khz(struct uncore_data *data, 47 - char *buf, int min_max) 47 + static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index index) 48 48 { 49 - unsigned int min, max; 49 + unsigned int value; 50 50 int ret; 51 51 52 52 mutex_lock(&uncore_lock); 53 - ret = uncore_read(data, &min, &max); 53 + ret = uncore_read(data, &value, index); 54 54 mutex_unlock(&uncore_lock); 55 55 if (ret) 56 56 return ret; 57 57 58 - if (min_max) 59 - return sprintf(buf, "%u\n", max); 60 - 61 - return sprintf(buf, "%u\n", min); 58 + return sprintf(buf, "%u\n", value); 62 59 } 63 60 64 - static ssize_t store_min_max_freq_khz(struct uncore_data *data, 65 - const char *buf, ssize_t count, 66 - int min_max) 61 + static ssize_t store_attr(struct uncore_data *data, const char *buf, ssize_t count, 62 + enum uncore_index index) 67 63 { 68 64 unsigned int input; 69 65 int ret; ··· 67 73 return -EINVAL; 68 74 69 75 mutex_lock(&uncore_lock); 70 - ret = uncore_write(data, input, min_max); 76 + ret = uncore_write(data, input, index); 71 77 mutex_unlock(&uncore_lock); 72 78 73 79 if (ret) ··· 76 82 return count; 77 83 } 78 84 79 - static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf) 80 - { 81 - unsigned int freq; 82 - int ret; 83 - 84 - mutex_lock(&uncore_lock); 85 - ret = uncore_read_freq(data, &freq); 86 - mutex_unlock(&uncore_lock); 87 - if (ret) 88 - return ret; 89 - 90 - return sprintf(buf, "%u\n", freq); 91 - } 92 - 93 - #define store_uncore_min_max(name, min_max) \ 85 + #define store_uncore_attr(name, index) \ 94 86 static ssize_t store_##name(struct kobject *kobj, \ 95 87 struct kobj_attribute *attr, \ 96 88 const char *buf, size_t count) \ 97 89 { \ 98 90 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ 99 91 \ 100 - return store_min_max_freq_khz(data, buf, count, \ 101 - min_max); \ 92 + return store_attr(data, buf, count, index); \ 102 93 } 103 94 104 - #define show_uncore_min_max(name, min_max) \ 95 + #define show_uncore_attr(name, index) \ 105 96 static ssize_t show_##name(struct kobject *kobj, \ 106 97 struct kobj_attribute *attr, char *buf)\ 107 98 { \ 108 99 struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ 109 100 \ 110 - return show_min_max_freq_khz(data, buf, min_max); \ 101 + return show_attr(data, buf, index); \ 111 102 } 112 103 113 - #define show_uncore_perf_status(name) \ 114 - static ssize_t show_##name(struct kobject *kobj, \ 115 - struct kobj_attribute *attr, char *buf)\ 116 - { \ 117 - struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ 118 - \ 119 - return show_perf_status_freq_khz(data, buf); \ 120 - } 104 + store_uncore_attr(min_freq_khz, UNCORE_INDEX_MIN_FREQ); 105 + store_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ); 121 106 122 - store_uncore_min_max(min_freq_khz, 0); 123 - store_uncore_min_max(max_freq_khz, 1); 107 + show_uncore_attr(min_freq_khz, UNCORE_INDEX_MIN_FREQ); 108 + show_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ); 124 109 125 - show_uncore_min_max(min_freq_khz, 0); 126 - show_uncore_min_max(max_freq_khz, 1); 127 - 128 - show_uncore_perf_status(current_freq_khz); 110 + show_uncore_attr(current_freq_khz, UNCORE_INDEX_CURRENT_FREQ); 129 111 130 112 #define show_uncore_data(member_name) \ 131 113 static ssize_t show_##member_name(struct kobject *kobj, \ ··· 168 198 data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr; 169 199 data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr; 170 200 171 - ret = uncore_read_freq(data, &freq); 201 + ret = uncore_read(data, &freq, UNCORE_INDEX_CURRENT_FREQ); 172 202 if (!ret) 173 203 data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr; 174 204 ··· 208 238 sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id); 209 239 } 210 240 211 - uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz); 241 + uncore_read(data, &data->initial_min_freq_khz, UNCORE_INDEX_MIN_FREQ); 242 + uncore_read(data, &data->initial_max_freq_khz, UNCORE_INDEX_MAX_FREQ); 212 243 213 244 ret = create_attr_group(data, data->name); 214 245 if (ret) { ··· 240 269 } 241 270 EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY); 242 271 243 - int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max), 244 - int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int set_max), 245 - int (*read_freq)(struct uncore_data *data, unsigned int *freq)) 272 + int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value, 273 + enum uncore_index index), 274 + int (*write)(struct uncore_data *data, unsigned int input, 275 + enum uncore_index index)) 246 276 { 247 277 mutex_lock(&uncore_lock); 248 278 249 - uncore_read = read_control_freq; 250 - uncore_write = write_control_freq; 251 - uncore_read_freq = read_freq; 279 + uncore_read = read; 280 + uncore_write = write; 252 281 253 282 if (!uncore_root_kobj) { 254 283 struct device *dev_root = bus_get_dev_root(&cpu_subsys);
+10 -3
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
··· 66 66 67 67 #define UNCORE_DOMAIN_ID_INVALID -1 68 68 69 - int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max), 70 - int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int min_max), 71 - int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq)); 69 + enum uncore_index { 70 + UNCORE_INDEX_MIN_FREQ, 71 + UNCORE_INDEX_MAX_FREQ, 72 + UNCORE_INDEX_CURRENT_FREQ, 73 + }; 74 + 75 + int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value, 76 + enum uncore_index index), 77 + int (*write)(struct uncore_data *data, unsigned int input, 78 + enum uncore_index index)); 72 79 void uncore_freq_common_exit(void); 73 80 int uncore_freq_add_entry(struct uncore_data *data, int cpu); 74 81 void uncore_freq_remove_die_entry(struct uncore_data *data);
+66 -35
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
··· 69 69 bool write_blocked; 70 70 }; 71 71 72 - #define UNCORE_GENMASK_MIN_RATIO GENMASK_ULL(21, 15) 73 - #define UNCORE_GENMASK_MAX_RATIO GENMASK_ULL(14, 8) 74 - #define UNCORE_GENMASK_CURRENT_RATIO GENMASK_ULL(6, 0) 72 + /* Bit definitions for STATUS register */ 73 + #define UNCORE_CURRENT_RATIO_MASK GENMASK_ULL(6, 0) 74 + 75 + /* Bit definitions for CONTROL register */ 76 + #define UNCORE_MAX_RATIO_MASK GENMASK_ULL(14, 8) 77 + #define UNCORE_MIN_RATIO_MASK GENMASK_ULL(21, 15) 75 78 76 79 /* Helper function to read MMIO offset for max/min control frequency */ 77 80 static void read_control_freq(struct tpmi_uncore_cluster_info *cluster_info, 78 - unsigned int *min, unsigned int *max) 81 + unsigned int *value, enum uncore_index index) 79 82 { 80 83 u64 control; 81 84 82 85 control = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX); 83 - *max = FIELD_GET(UNCORE_GENMASK_MAX_RATIO, control) * UNCORE_FREQ_KHZ_MULTIPLIER; 84 - *min = FIELD_GET(UNCORE_GENMASK_MIN_RATIO, control) * UNCORE_FREQ_KHZ_MULTIPLIER; 86 + if (index == UNCORE_INDEX_MAX_FREQ) 87 + *value = FIELD_GET(UNCORE_MAX_RATIO_MASK, control) * UNCORE_FREQ_KHZ_MULTIPLIER; 88 + else 89 + *value = FIELD_GET(UNCORE_MIN_RATIO_MASK, control) * UNCORE_FREQ_KHZ_MULTIPLIER; 85 90 } 86 91 87 - #define UNCORE_MAX_RATIO FIELD_MAX(UNCORE_GENMASK_MAX_RATIO) 92 + #define UNCORE_MAX_RATIO FIELD_MAX(UNCORE_MAX_RATIO_MASK) 88 93 89 - /* Callback for sysfs read for max/min frequencies. Called under mutex locks */ 90 - static int uncore_read_control_freq(struct uncore_data *data, unsigned int *min, 91 - unsigned int *max) 94 + /* Helper for sysfs read for max/min frequencies. Called under mutex locks */ 95 + static int uncore_read_control_freq(struct uncore_data *data, unsigned int *value, 96 + enum uncore_index index) 92 97 { 93 98 struct tpmi_uncore_cluster_info *cluster_info; 94 99 ··· 101 96 102 97 if (cluster_info->root_domain) { 103 98 struct tpmi_uncore_struct *uncore_root = cluster_info->uncore_root; 104 - int i, _min = 0, _max = 0; 99 + unsigned int min, max, v; 100 + int i; 105 101 106 - *min = UNCORE_MAX_RATIO * UNCORE_FREQ_KHZ_MULTIPLIER; 107 - *max = 0; 102 + min = UNCORE_MAX_RATIO * UNCORE_FREQ_KHZ_MULTIPLIER; 103 + max = 0; 108 104 109 105 /* 110 106 * Get the max/min by looking at each cluster. Get the lowest ··· 116 110 117 111 for (j = 0; j < uncore_root->pd_info[i].cluster_count; ++j) { 118 112 read_control_freq(&uncore_root->pd_info[i].cluster_infos[j], 119 - &_min, &_max); 120 - if (*min > _min) 121 - *min = _min; 122 - if (*max < _max) 123 - *max = _max; 113 + &v, index); 114 + if (v < min) 115 + min = v; 116 + if (v > max) 117 + max = v; 124 118 } 125 119 } 120 + 121 + if (index == UNCORE_INDEX_MIN_FREQ) 122 + *value = min; 123 + else 124 + *value = max; 125 + 126 126 return 0; 127 127 } 128 128 129 - read_control_freq(cluster_info, min, max); 129 + read_control_freq(cluster_info, value, index); 130 130 131 131 return 0; 132 132 } 133 133 134 134 /* Helper function to write MMIO offset for max/min control frequency */ 135 135 static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, unsigned int input, 136 - unsigned int min_max) 136 + unsigned int index) 137 137 { 138 138 u64 control; 139 139 140 140 control = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX); 141 141 142 - if (min_max) { 143 - control &= ~UNCORE_GENMASK_MAX_RATIO; 144 - control |= FIELD_PREP(UNCORE_GENMASK_MAX_RATIO, input); 142 + if (index == UNCORE_INDEX_MAX_FREQ) { 143 + control &= ~UNCORE_MAX_RATIO_MASK; 144 + control |= FIELD_PREP(UNCORE_MAX_RATIO_MASK, input); 145 145 } else { 146 - control &= ~UNCORE_GENMASK_MIN_RATIO; 147 - control |= FIELD_PREP(UNCORE_GENMASK_MIN_RATIO, input); 146 + control &= ~UNCORE_MIN_RATIO_MASK; 147 + control |= FIELD_PREP(UNCORE_MIN_RATIO_MASK, input); 148 148 } 149 149 150 150 writeq(control, (cluster_info->cluster_base + UNCORE_CONTROL_INDEX)); ··· 158 146 159 147 /* Callback for sysfs write for max/min frequencies. Called under mutex locks */ 160 148 static int uncore_write_control_freq(struct uncore_data *data, unsigned int input, 161 - unsigned int min_max) 149 + enum uncore_index index) 162 150 { 163 151 struct tpmi_uncore_cluster_info *cluster_info; 164 152 struct tpmi_uncore_struct *uncore_root; ··· 183 171 184 172 for (j = 0; j < uncore_root->pd_info[i].cluster_count; ++j) 185 173 write_control_freq(&uncore_root->pd_info[i].cluster_infos[j], 186 - input, min_max); 174 + input, index); 187 175 } 188 176 189 - if (min_max) 177 + if (index == UNCORE_INDEX_MAX_FREQ) 190 178 uncore_root->max_ratio = input; 191 179 else 192 180 uncore_root->min_ratio = input; ··· 194 182 return 0; 195 183 } 196 184 197 - if (min_max && uncore_root->max_ratio && uncore_root->max_ratio < input) 185 + if (index == UNCORE_INDEX_MAX_FREQ && uncore_root->max_ratio && 186 + uncore_root->max_ratio < input) 198 187 return -EINVAL; 199 188 200 - if (!min_max && uncore_root->min_ratio && uncore_root->min_ratio > input) 189 + if (index == UNCORE_INDEX_MIN_FREQ && uncore_root->min_ratio && 190 + uncore_root->min_ratio > input) 201 191 return -EINVAL; 202 192 203 - write_control_freq(cluster_info, input, min_max); 193 + write_control_freq(cluster_info, input, index); 204 194 205 195 return 0; 206 196 } 207 197 208 - /* Callback for sysfs read for the current uncore frequency. Called under mutex locks */ 198 + /* Helper for sysfs read for the current uncore frequency. Called under mutex locks */ 209 199 static int uncore_read_freq(struct uncore_data *data, unsigned int *freq) 210 200 { 211 201 struct tpmi_uncore_cluster_info *cluster_info; ··· 218 204 return -ENODATA; 219 205 220 206 status = readq((u8 __iomem *)cluster_info->cluster_base + UNCORE_STATUS_INDEX); 221 - *freq = FIELD_GET(UNCORE_GENMASK_CURRENT_RATIO, status) * UNCORE_FREQ_KHZ_MULTIPLIER; 207 + *freq = FIELD_GET(UNCORE_CURRENT_RATIO_MASK, status) * UNCORE_FREQ_KHZ_MULTIPLIER; 222 208 223 209 return 0; 210 + } 211 + 212 + /* Callback for sysfs read for TPMI uncore values. Called under mutex locks. */ 213 + static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncore_index index) 214 + { 215 + switch (index) { 216 + case UNCORE_INDEX_MIN_FREQ: 217 + case UNCORE_INDEX_MAX_FREQ: 218 + return uncore_read_control_freq(data, value, index); 219 + 220 + case UNCORE_INDEX_CURRENT_FREQ: 221 + return uncore_read_freq(data, value); 222 + 223 + default: 224 + break; 225 + } 226 + 227 + return -EOPNOTSUPP; 224 228 } 225 229 226 230 static void remove_cluster_entries(struct tpmi_uncore_struct *tpmi_uncore) ··· 291 259 return -EINVAL; 292 260 293 261 /* Register callbacks to uncore core */ 294 - ret = uncore_freq_common_init(uncore_read_control_freq, uncore_write_control_freq, 295 - uncore_read_freq); 262 + ret = uncore_freq_common_init(uncore_read, uncore_write_control_freq); 296 263 if (ret) 297 264 return ret; 298 265
+66 -42
drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
··· 14 14 * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 15 15 */ 16 16 17 + #include <linux/bitfield.h> 17 18 #include <linux/cpu.h> 18 19 #include <linux/module.h> 19 20 #include <linux/slab.h> ··· 37 36 #define MSR_UNCORE_PERF_STATUS 0x621 38 37 #define UNCORE_FREQ_KHZ_MULTIPLIER 100000 39 38 40 - static int uncore_read_control_freq(struct uncore_data *data, unsigned int *min, 41 - unsigned int *max) 39 + #define UNCORE_MAX_RATIO_MASK GENMASK_ULL(6, 0) 40 + #define UNCORE_MIN_RATIO_MASK GENMASK_ULL(14, 8) 41 + 42 + #define UNCORE_CURRENT_RATIO_MASK GENMASK_ULL(6, 0) 43 + 44 + static int uncore_read_control_freq(struct uncore_data *data, unsigned int *value, 45 + enum uncore_index index) 42 46 { 43 47 u64 cap; 44 48 int ret; ··· 55 49 if (ret) 56 50 return ret; 57 51 58 - *max = (cap & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; 59 - *min = ((cap & GENMASK(14, 8)) >> 8) * UNCORE_FREQ_KHZ_MULTIPLIER; 52 + if (index == UNCORE_INDEX_MAX_FREQ) 53 + *value = FIELD_GET(UNCORE_MAX_RATIO_MASK, cap) * UNCORE_FREQ_KHZ_MULTIPLIER; 54 + else 55 + *value = FIELD_GET(UNCORE_MIN_RATIO_MASK, cap) * UNCORE_FREQ_KHZ_MULTIPLIER; 60 56 61 57 return 0; 62 58 } 63 59 64 60 static int uncore_write_control_freq(struct uncore_data *data, unsigned int input, 65 - unsigned int min_max) 61 + enum uncore_index index) 66 62 { 67 63 int ret; 68 64 u64 cap; 69 65 70 66 input /= UNCORE_FREQ_KHZ_MULTIPLIER; 71 - if (!input || input > 0x7F) 67 + if (!input || input > FIELD_MAX(UNCORE_MAX_RATIO_MASK)) 72 68 return -EINVAL; 73 69 74 70 if (data->control_cpu < 0) ··· 80 72 if (ret) 81 73 return ret; 82 74 83 - if (min_max) { 84 - cap &= ~0x7F; 85 - cap |= input; 75 + if (index == UNCORE_INDEX_MAX_FREQ) { 76 + cap &= ~UNCORE_MAX_RATIO_MASK; 77 + cap |= FIELD_PREP(UNCORE_MAX_RATIO_MASK, input); 86 78 } else { 87 - cap &= ~GENMASK(14, 8); 88 - cap |= (input << 8); 79 + cap &= ~UNCORE_MIN_RATIO_MASK; 80 + cap |= FIELD_PREP(UNCORE_MIN_RATIO_MASK, input); 89 81 } 90 82 91 83 ret = wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, cap); ··· 109 101 if (ret) 110 102 return ret; 111 103 112 - *freq = (ratio & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; 104 + *freq = FIELD_GET(UNCORE_CURRENT_RATIO_MASK, ratio) * UNCORE_FREQ_KHZ_MULTIPLIER; 113 105 114 106 return 0; 107 + } 108 + 109 + static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncore_index index) 110 + { 111 + switch (index) { 112 + case UNCORE_INDEX_MIN_FREQ: 113 + case UNCORE_INDEX_MAX_FREQ: 114 + return uncore_read_control_freq(data, value, index); 115 + 116 + case UNCORE_INDEX_CURRENT_FREQ: 117 + return uncore_read_freq(data, value); 118 + 119 + default: 120 + break; 121 + } 122 + 123 + return -EOPNOTSUPP; 115 124 } 116 125 117 126 /* Caller provides protection */ ··· 222 197 }; 223 198 224 199 static const struct x86_cpu_id intel_uncore_cpu_ids[] = { 225 - X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, NULL), 226 - X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, NULL), 227 - X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, NULL), 228 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL), 229 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), 230 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), 231 - X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL), 232 - X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, NULL), 233 - X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL), 234 - X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL), 235 - X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL), 236 - X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, NULL), 237 - X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, NULL), 238 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL), 239 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL), 240 - X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, NULL), 241 - X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL), 242 - X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL), 243 - X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL), 244 - X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL), 245 - X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL), 246 - X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL), 247 - X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, NULL), 248 - X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, NULL), 249 - X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, NULL), 250 - X86_MATCH_INTEL_FAM6_MODEL(ARROWLAKE, NULL), 251 - X86_MATCH_INTEL_FAM6_MODEL(ARROWLAKE_H, NULL), 252 - X86_MATCH_INTEL_FAM6_MODEL(LUNARLAKE_M, NULL), 200 + X86_MATCH_VFM(INTEL_BROADWELL_G, NULL), 201 + X86_MATCH_VFM(INTEL_BROADWELL_X, NULL), 202 + X86_MATCH_VFM(INTEL_BROADWELL_D, NULL), 203 + X86_MATCH_VFM(INTEL_SKYLAKE_X, NULL), 204 + X86_MATCH_VFM(INTEL_ICELAKE_X, NULL), 205 + X86_MATCH_VFM(INTEL_ICELAKE_D, NULL), 206 + X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, NULL), 207 + X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, NULL), 208 + X86_MATCH_VFM(INTEL_KABYLAKE, NULL), 209 + X86_MATCH_VFM(INTEL_KABYLAKE_L, NULL), 210 + X86_MATCH_VFM(INTEL_COMETLAKE, NULL), 211 + X86_MATCH_VFM(INTEL_COMETLAKE_L, NULL), 212 + X86_MATCH_VFM(INTEL_CANNONLAKE_L, NULL), 213 + X86_MATCH_VFM(INTEL_ICELAKE, NULL), 214 + X86_MATCH_VFM(INTEL_ICELAKE_L, NULL), 215 + X86_MATCH_VFM(INTEL_ROCKETLAKE, NULL), 216 + X86_MATCH_VFM(INTEL_TIGERLAKE, NULL), 217 + X86_MATCH_VFM(INTEL_TIGERLAKE_L, NULL), 218 + X86_MATCH_VFM(INTEL_ALDERLAKE, NULL), 219 + X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL), 220 + X86_MATCH_VFM(INTEL_RAPTORLAKE, NULL), 221 + X86_MATCH_VFM(INTEL_RAPTORLAKE_P, NULL), 222 + X86_MATCH_VFM(INTEL_RAPTORLAKE_S, NULL), 223 + X86_MATCH_VFM(INTEL_METEORLAKE, NULL), 224 + X86_MATCH_VFM(INTEL_METEORLAKE_L, NULL), 225 + X86_MATCH_VFM(INTEL_ARROWLAKE, NULL), 226 + X86_MATCH_VFM(INTEL_ARROWLAKE_H, NULL), 227 + X86_MATCH_VFM(INTEL_LUNARLAKE_M, NULL), 253 228 {} 254 229 }; 255 230 MODULE_DEVICE_TABLE(x86cpu, intel_uncore_cpu_ids); ··· 273 248 if (!uncore_instances) 274 249 return -ENOMEM; 275 250 276 - ret = uncore_freq_common_init(uncore_read_control_freq, uncore_write_control_freq, 277 - uncore_read_freq); 251 + ret = uncore_freq_common_init(uncore_read, uncore_write_control_freq); 278 252 if (ret) 279 253 goto err_free; 280 254
+2 -1
drivers/platform/x86/intel_ips.c
··· 62 62 #include <drm/i915_drm.h> 63 63 #include <asm/msr.h> 64 64 #include <asm/processor.h> 65 + #include <asm/cpu_device_id.h> 65 66 #include "intel_ips.h" 66 67 67 68 #include <linux/io-64-nonatomic-lo-hi.h> ··· 1285 1284 struct ips_mcp_limits *limits = NULL; 1286 1285 u16 tdp; 1287 1286 1288 - if (!(boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 37)) { 1287 + if (!(boot_cpu_data.x86_vfm == INTEL_WESTMERE)) { 1289 1288 dev_info(ips->dev, "Non-IPS CPU detected.\n"); 1290 1289 return NULL; 1291 1290 }
+1 -1
drivers/platform/x86/intel_scu_wdt.c
··· 50 50 }; 51 51 52 52 static const struct x86_cpu_id intel_mid_cpu_ids[] = { 53 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &tangier_pdata), 53 + X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_MID, &tangier_pdata), 54 54 {} 55 55 }; 56 56
+1 -1
drivers/platform/x86/p2sb.c
··· 24 24 #define SPI_DEVFN_GOLDMONT PCI_DEVFN(13, 2) 25 25 26 26 static const struct x86_cpu_id p2sb_cpu_ids[] = { 27 - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, P2SB_DEVFN_GOLDMONT), 27 + X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, P2SB_DEVFN_GOLDMONT), 28 28 {} 29 29 }; 30 30
+2 -2
drivers/platform/x86/serial-multi-instantiate.c
··· 131 131 132 132 ctlr = spi_dev->controller; 133 133 134 - strscpy(spi_dev->modalias, inst_array[i].type, sizeof(spi_dev->modalias)); 134 + strscpy(spi_dev->modalias, inst_array[i].type); 135 135 136 136 ret = smi_get_irq(pdev, adev, &inst_array[i]); 137 137 if (ret < 0) { ··· 205 205 206 206 for (i = 0; i < count && inst_array[i].type; i++) { 207 207 memset(&board_info, 0, sizeof(board_info)); 208 - strscpy(board_info.type, inst_array[i].type, I2C_NAME_SIZE); 208 + strscpy(board_info.type, inst_array[i].type); 209 209 snprintf(name, sizeof(name), "%s-%s.%d", dev_name(dev), inst_array[i].type, i); 210 210 board_info.dev_name = name; 211 211
+2 -2
drivers/platform/x86/think-lmi.c
··· 1508 1508 if (!new_pwd) 1509 1509 return NULL; 1510 1510 1511 - strscpy(new_pwd->kbdlang, "us", TLMI_LANG_MAXLEN); 1511 + strscpy(new_pwd->kbdlang, "us"); 1512 1512 new_pwd->encoding = TLMI_ENCODING_ASCII; 1513 1513 new_pwd->pwd_type = pwd_type; 1514 1514 new_pwd->role = pwd_role; ··· 1582 1582 goto fail_clear_attr; 1583 1583 } 1584 1584 setting->index = i; 1585 - strscpy(setting->display_name, item, TLMI_SETTINGS_MAXLEN); 1585 + strscpy(setting->display_name, item); 1586 1586 /* If BIOS selections supported, load those */ 1587 1587 if (tlmi_priv.can_get_bios_selections) { 1588 1588 ret = tlmi_get_bios_selections(setting->display_name,
+2 -4
drivers/platform/x86/thinkpad_acpi.c
··· 7416 7416 data = card->private_data; 7417 7417 data->card = card; 7418 7418 7419 - strscpy(card->driver, TPACPI_ALSA_DRVNAME, 7420 - sizeof(card->driver)); 7421 - strscpy(card->shortname, TPACPI_ALSA_SHRTNAME, 7422 - sizeof(card->shortname)); 7419 + strscpy(card->driver, TPACPI_ALSA_DRVNAME); 7420 + strscpy(card->shortname, TPACPI_ALSA_SHRTNAME); 7423 7421 snprintf(card->mixername, sizeof(card->mixername), "ThinkPad EC %s", 7424 7422 (thinkpad_id.ec_version_str) ? 7425 7423 thinkpad_id.ec_version_str : "(unknown)");
+33
drivers/platform/x86/wmi.c
··· 772 772 } 773 773 static DEVICE_ATTR_RO(expensive); 774 774 775 + static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, 776 + char *buf) 777 + { 778 + struct wmi_device *wdev = to_wmi_device(dev); 779 + ssize_t ret; 780 + 781 + device_lock(dev); 782 + ret = sysfs_emit(buf, "%s\n", wdev->driver_override); 783 + device_unlock(dev); 784 + 785 + return ret; 786 + } 787 + 788 + static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, 789 + const char *buf, size_t count) 790 + { 791 + struct wmi_device *wdev = to_wmi_device(dev); 792 + int ret; 793 + 794 + ret = driver_set_override(dev, &wdev->driver_override, buf, count); 795 + if (ret < 0) 796 + return ret; 797 + 798 + return count; 799 + } 800 + static DEVICE_ATTR_RW(driver_override); 801 + 775 802 static struct attribute *wmi_attrs[] = { 776 803 &dev_attr_modalias.attr, 777 804 &dev_attr_guid.attr, 778 805 &dev_attr_instance_count.attr, 779 806 &dev_attr_expensive.attr, 807 + &dev_attr_driver_override.attr, 780 808 NULL 781 809 }; 782 810 ATTRIBUTE_GROUPS(wmi); ··· 873 845 { 874 846 struct wmi_block *wblock = dev_to_wblock(dev); 875 847 848 + kfree(wblock->dev.driver_override); 876 849 kfree(wblock); 877 850 } 878 851 ··· 882 853 struct wmi_driver *wmi_driver = drv_to_wdrv(driver); 883 854 struct wmi_block *wblock = dev_to_wblock(dev); 884 855 const struct wmi_device_id *id = wmi_driver->id_table; 856 + 857 + /* When driver_override is set, only bind to the matching driver */ 858 + if (wblock->dev.driver_override) 859 + return !strcmp(wblock->dev.driver_override, driver->name); 885 860 886 861 if (id == NULL) 887 862 return 0;
+2
include/linux/intel_tpmi.h
··· 21 21 TPMI_ID_PEM = 1, /* Power and Perf excursion Monitor */ 22 22 TPMI_ID_UNCORE = 2, /* Uncore Frequency Scaling */ 23 23 TPMI_ID_SST = 5, /* Speed Select Technology */ 24 + TPMI_ID_PLR = 0xc, /* Performance Limit Reasons */ 24 25 TPMI_CONTROL_ID = 0x80, /* Special ID for getting feature status */ 25 26 TPMI_INFO_ID = 0x81, /* Special ID for PCI BDF and Package ID information */ 26 27 }; ··· 54 53 int tpmi_get_resource_count(struct auxiliary_device *auxdev); 55 54 int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id, bool *read_blocked, 56 55 bool *write_blocked); 56 + struct dentry *tpmi_get_debugfs_dir(struct auxiliary_device *auxdev); 57 57 #endif
+44
include/linux/platform_data/lenovo-yoga-c630.h
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2022-2024, Linaro Ltd 4 + * Authors: 5 + * Bjorn Andersson 6 + * Dmitry Baryshkov 7 + */ 8 + 9 + #ifndef _LENOVO_YOGA_C630_DATA_H 10 + #define _LENOVO_YOGA_C630_DATA_H 11 + 12 + struct yoga_c630_ec; 13 + struct notifier_block; 14 + 15 + #define YOGA_C630_MOD_NAME "lenovo_yoga_c630" 16 + 17 + #define YOGA_C630_DEV_UCSI "ucsi" 18 + #define YOGA_C630_DEV_PSY "psy" 19 + 20 + int yoga_c630_ec_read8(struct yoga_c630_ec *ec, u8 addr); 21 + int yoga_c630_ec_read16(struct yoga_c630_ec *ec, u8 addr); 22 + 23 + int yoga_c630_ec_register_notify(struct yoga_c630_ec *ec, struct notifier_block *nb); 24 + void yoga_c630_ec_unregister_notify(struct yoga_c630_ec *ec, struct notifier_block *nb); 25 + 26 + #define YOGA_C630_UCSI_WRITE_SIZE 8 27 + #define YOGA_C630_UCSI_CCI_SIZE 4 28 + #define YOGA_C630_UCSI_DATA_SIZE 16 29 + #define YOGA_C630_UCSI_READ_SIZE (YOGA_C630_UCSI_CCI_SIZE + YOGA_C630_UCSI_DATA_SIZE) 30 + 31 + u16 yoga_c630_ec_ucsi_get_version(struct yoga_c630_ec *ec); 32 + int yoga_c630_ec_ucsi_write(struct yoga_c630_ec *ec, 33 + const u8 req[YOGA_C630_UCSI_WRITE_SIZE]); 34 + int yoga_c630_ec_ucsi_read(struct yoga_c630_ec *ec, 35 + u8 resp[YOGA_C630_UCSI_READ_SIZE]); 36 + 37 + #define LENOVO_EC_EVENT_USB 0x20 38 + #define LENOVO_EC_EVENT_UCSI 0x21 39 + #define LENOVO_EC_EVENT_HPD 0x22 40 + #define LENOVO_EC_EVENT_BAT_STATUS 0x24 41 + #define LENOVO_EC_EVENT_BAT_INFO 0x25 42 + #define LENOVO_EC_EVENT_BAT_ADPT_STATUS 0x37 43 + 44 + #endif
+4
include/linux/platform_data/x86/asus-wmi.h
··· 51 51 #define ASUS_WMI_DEVID_LED6 0x00020016 52 52 #define ASUS_WMI_DEVID_MICMUTE_LED 0x00040017 53 53 54 + /* Disable Camera LED */ 55 + #define ASUS_WMI_DEVID_CAMERA_LED_NEG 0x00060078 /* 0 = on (unused) */ 56 + #define ASUS_WMI_DEVID_CAMERA_LED 0x00060079 /* 1 = on */ 57 + 54 58 /* Backlight and Brightness */ 55 59 #define ASUS_WMI_DEVID_ALS_ENABLE 0x00050001 /* Ambient Light Sensor */ 56 60 #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
+4
include/linux/wmi.h
··· 16 16 * struct wmi_device - WMI device structure 17 17 * @dev: Device associated with this WMI device 18 18 * @setable: True for devices implementing the Set Control Method 19 + * @driver_override: Driver name to force a match; do not set directly, 20 + * because core frees it; use driver_set_override() to 21 + * set or clear it. 19 22 * 20 23 * This represents WMI devices discovered by the WMI driver core. 21 24 */ 22 25 struct wmi_device { 23 26 struct device dev; 24 27 bool setable; 28 + const char *driver_override; 25 29 }; 26 30 27 31 /**
+1 -1
tools/power/x86/intel-speed-select/isst-config.c
··· 16 16 int arg; 17 17 }; 18 18 19 - static const char *version_str = "v1.19"; 19 + static const char *version_str = "v1.20"; 20 20 21 21 static const int supported_api_ver = 3; 22 22 static struct isst_if_platform_info isst_platform_info;
+6
tools/power/x86/intel-speed-select/isst-core.c
··· 283 283 return 0; 284 284 } 285 285 286 + #define MSR_TRL_FREQ_MULTIPLIER 100 287 + 286 288 int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl) 287 289 { 288 290 unsigned long long msr_trl; ··· 311 309 msr_trl = 0; 312 310 for (i = 0; i < 8; ++i) { 313 311 unsigned long long _trl = trl[i]; 312 + 313 + /* MSR is always in 100 MHz unit */ 314 + if (isst_get_disp_freq_multiplier() == 1) 315 + _trl /= MSR_TRL_FREQ_MULTIPLIER; 314 316 315 317 msr_trl |= (_trl << (i * 8)); 316 318 }