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

Merge tag 'platform-drivers-x86-v5.5-1' of git://git.infradead.org/linux-platform-drivers-x86

Pull x86 platform driver updates from Andy Shevchenko:

- New bootctl driver for Mellanox BlueField SoC.

- New driver to support System76 laptops.

- Temperature monitoring and fan control on Acer Aspire 7551 is now
supported.

- Previously the Huawei driver handled only hotkeys. After the
conversion to WMI it has been expanded to support newer laptop
models.

- Big refactoring of intel-speed-select tools allows to use it on Intel
CascadeLake-N systems.

- Touchscreen support for ezpad 6 m4 and Schneider SCT101CTM tablets

- Miscellaneous clean ups and fixes here and there.

* tag 'platform-drivers-x86-v5.5-1' of git://git.infradead.org/linux-platform-drivers-x86: (59 commits)
platform/x86: hp-wmi: Fix ACPI errors caused by passing 0 as input size
platform/x86: hp-wmi: Fix ACPI errors caused by too small buffer
platform/x86: intel_pmc_core: Add Comet Lake (CML) platform support to intel_pmc_core driver
platform/x86: intel_pmc_core: Fix the SoC naming inconsistency
platform/mellanox: Fix Kconfig indentation
tools/power/x86/intel-speed-select: Display TRL buckets for just base config level
tools/power/x86/intel-speed-select: Ignore missing config level
platform/x86: touchscreen_dmi: Add info for the ezpad 6 m4 tablet
tools/power/x86/intel-speed-select: Increment version
tools/power/x86/intel-speed-select: Use core count for base-freq mask
tools/power/x86/intel-speed-select: Support platform with limited Intel(R) Speed Select
tools/power/x86/intel-speed-select: Use Frequency weight for CLOS
tools/power/x86/intel-speed-select: Make CLOS frequency in MHz
tools/power/x86/intel-speed-select: Use mailbox for CLOS_PM_QOS_CONFIG
tools/power/x86/intel-speed-select: Auto mode for CLX
tools/power/x86/intel-speed-select: Correct CLX-N frequency units
tools/power/x86/intel-speed-select: Change display of "avx" to "avx2"
tools/power/x86/intel-speed-select: Extend command set for perf-profile
Add touchscreen platform data for the Schneider SCT101CTM tablet
platform/x86: intel_int0002_vgpio: Pass irqchip when adding gpiochip
...

+3283 -589
+58
Documentation/ABI/testing/sysfs-platform-mellanox-bootctl
··· 1 + What: /sys/bus/platform/devices/MLNXBF04:00/driver/lifecycle_state 2 + Date: Oct 2019 3 + KernelVersion: 5.5 4 + Contact: "Liming Sun <lsun@mellanox.com>" 5 + Description: 6 + The Life-cycle state of the SoC, which could be one of the 7 + following values. 8 + Production - Production state and can be updated to secure 9 + GA Secured - Secure chip and not able to change state 10 + GA Non-Secured - Non-Secure chip and not able to change state 11 + RMA - Return Merchandise Authorization 12 + 13 + What: /sys/bus/platform/devices/MLNXBF04:00/driver/post_reset_wdog 14 + Date: Oct 2019 15 + KernelVersion: 5.5 16 + Contact: "Liming Sun <lsun@mellanox.com>" 17 + Description: 18 + The watchdog setting in seconds for the next booting. It's used 19 + to reboot the chip and recover it to the old state if the new 20 + boot partition fails. 21 + 22 + What: /sys/bus/platform/devices/MLNXBF04:00/driver/reset_action 23 + Date: Oct 2019 24 + KernelVersion: 5.5 25 + Contact: "Liming Sun <lsun@mellanox.com>" 26 + Description: 27 + The source of the boot stream for the next reset. It could be 28 + one of the following values. 29 + external - boot from external source (USB or PCIe) 30 + emmc - boot from the onchip eMMC 31 + emmc_legacy - boot from the onchip eMMC in legacy (slow) mode 32 + 33 + What: /sys/bus/platform/devices/MLNXBF04:00/driver/second_reset_action 34 + Date: Oct 2019 35 + KernelVersion: 5.5 36 + Contact: "Liming Sun <lsun@mellanox.com>" 37 + Description: 38 + Update the source of the boot stream after next reset. It could 39 + be one of the following values and will be applied after next 40 + reset. 41 + external - boot from external source (USB or PCIe) 42 + emmc - boot from the onchip eMMC 43 + emmc_legacy - boot from the onchip eMMC in legacy (slow) mode 44 + swap_emmc - swap the primary / secondary boot partition 45 + none - cancel the action 46 + 47 + What: /sys/bus/platform/devices/MLNXBF04:00/driver/secure_boot_fuse_state 48 + Date: Oct 2019 49 + KernelVersion: 5.5 50 + Contact: "Liming Sun <lsun@mellanox.com>" 51 + Description: 52 + The state of eFuse versions with the following values. 53 + InUse - burnt, valid and currently in use 54 + Used - burnt and valid 55 + Free - not burnt and free to use 56 + Skipped - not burnt but not free (skipped) 57 + Wasted - burnt and invalid 58 + Invalid - not burnt but marked as valid (error state).
+9 -1
MAINTAINERS
··· 295 295 F: drivers/net/ethernet/alteon/acenic* 296 296 297 297 ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER 298 - M: Peter Feuerer <peter@piie.net> 298 + M: Peter Kaestle <peter@piie.net> 299 299 L: platform-driver-x86@vger.kernel.org 300 300 W: http://piie.net/?section=acerhdf 301 301 S: Maintained ··· 10577 10577 M: Vadim Pasternak <vadimp@mellanox.com> 10578 10578 L: platform-driver-x86@vger.kernel.org 10579 10579 S: Supported 10580 + F: Documentation/ABI/testing/sysfs-platform-mellanox-bootctl 10580 10581 F: drivers/platform/mellanox/ 10581 10582 F: include/linux/platform_data/mlxreg.h 10582 10583 ··· 15948 15947 F: drivers/hwtracing/stm/ 15949 15948 F: include/linux/stm.h 15950 15949 F: include/uapi/linux/stm.h 15950 + 15951 + SYSTEM76 ACPI DRIVER 15952 + M: Jeremy Soller <jeremy@system76.com> 15953 + M: System76 Product Development <productdev@system76.com> 15954 + L: platform-driver-x86@vger.kernel.org 15955 + S: Maintained 15956 + F: drivers/platform/x86/system76_acpi.c 15951 15957 15952 15958 SYSV FILESYSTEM 15953 15959 M: Christoph Hellwig <hch@infradead.org>
+14 -2
drivers/platform/mellanox/Kconfig
··· 41 41 depends on VIRTIO_CONSOLE && VIRTIO_NET 42 42 help 43 43 Say y here to enable TmFifo support. The TmFifo driver provides 44 - platform driver support for the TmFifo which supports console 45 - and networking based on the virtio framework. 44 + platform driver support for the TmFifo which supports console 45 + and networking based on the virtio framework. 46 + 47 + config MLXBF_BOOTCTL 48 + tristate "Mellanox BlueField Firmware Boot Control driver" 49 + depends on ARM64 50 + depends on ACPI 51 + help 52 + The Mellanox BlueField firmware implements functionality to 53 + request swapping the primary and alternate eMMC boot partition, 54 + and to set up a watchdog that can undo that swap if the system 55 + does not boot up correctly. This driver provides sysfs access 56 + to the userspace tools, to be used in conjunction with the eMMC 57 + device driver to do necessary initial swap of the boot partition. 46 58 47 59 endif # MELLANOX_PLATFORM
+1
drivers/platform/mellanox/Makefile
··· 3 3 # Makefile for linux/drivers/platform/mellanox 4 4 # Mellanox Platform-Specific Drivers 5 5 # 6 + obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o 6 7 obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o 7 8 obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o 8 9 obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
+321
drivers/platform/mellanox/mlxbf-bootctl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Mellanox boot control driver 4 + * 5 + * This driver provides a sysfs interface for systems management 6 + * software to manage reset-time actions. 7 + * 8 + * Copyright (C) 2019 Mellanox Technologies 9 + */ 10 + 11 + #include <linux/acpi.h> 12 + #include <linux/arm-smccc.h> 13 + #include <linux/module.h> 14 + #include <linux/platform_device.h> 15 + 16 + #include "mlxbf-bootctl.h" 17 + 18 + #define MLXBF_BOOTCTL_SB_SECURE_MASK 0x03 19 + #define MLXBF_BOOTCTL_SB_TEST_MASK 0x0c 20 + 21 + #define MLXBF_SB_KEY_NUM 4 22 + 23 + /* UUID used to probe ATF service. */ 24 + static const char *mlxbf_bootctl_svc_uuid_str = 25 + "89c036b4-e7d7-11e6-8797-001aca00bfc4"; 26 + 27 + struct mlxbf_bootctl_name { 28 + u32 value; 29 + const char *name; 30 + }; 31 + 32 + static struct mlxbf_bootctl_name boot_names[] = { 33 + { MLXBF_BOOTCTL_EXTERNAL, "external" }, 34 + { MLXBF_BOOTCTL_EMMC, "emmc" }, 35 + { MLNX_BOOTCTL_SWAP_EMMC, "swap_emmc" }, 36 + { MLXBF_BOOTCTL_EMMC_LEGACY, "emmc_legacy" }, 37 + { MLXBF_BOOTCTL_NONE, "none" }, 38 + }; 39 + 40 + static const char * const mlxbf_bootctl_lifecycle_states[] = { 41 + [0] = "Production", 42 + [1] = "GA Secured", 43 + [2] = "GA Non-Secured", 44 + [3] = "RMA", 45 + }; 46 + 47 + /* ARM SMC call which is atomic and no need for lock. */ 48 + static int mlxbf_bootctl_smc(unsigned int smc_op, int smc_arg) 49 + { 50 + struct arm_smccc_res res; 51 + 52 + arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res); 53 + 54 + return res.a0; 55 + } 56 + 57 + /* Return the action in integer or an error code. */ 58 + static int mlxbf_bootctl_reset_action_to_val(const char *action) 59 + { 60 + int i; 61 + 62 + for (i = 0; i < ARRAY_SIZE(boot_names); i++) 63 + if (sysfs_streq(boot_names[i].name, action)) 64 + return boot_names[i].value; 65 + 66 + return -EINVAL; 67 + } 68 + 69 + /* Return the action in string. */ 70 + static const char *mlxbf_bootctl_action_to_string(int action) 71 + { 72 + int i; 73 + 74 + for (i = 0; i < ARRAY_SIZE(boot_names); i++) 75 + if (boot_names[i].value == action) 76 + return boot_names[i].name; 77 + 78 + return "invalid action"; 79 + } 80 + 81 + static ssize_t post_reset_wdog_show(struct device *dev, 82 + struct device_attribute *attr, char *buf) 83 + { 84 + int ret; 85 + 86 + ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_POST_RESET_WDOG, 0); 87 + if (ret < 0) 88 + return ret; 89 + 90 + return sprintf(buf, "%d\n", ret); 91 + } 92 + 93 + static ssize_t post_reset_wdog_store(struct device *dev, 94 + struct device_attribute *attr, 95 + const char *buf, size_t count) 96 + { 97 + unsigned long value; 98 + int ret; 99 + 100 + ret = kstrtoul(buf, 10, &value); 101 + if (ret) 102 + return ret; 103 + 104 + ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_POST_RESET_WDOG, value); 105 + if (ret < 0) 106 + return ret; 107 + 108 + return count; 109 + } 110 + 111 + static ssize_t mlxbf_bootctl_show(int smc_op, char *buf) 112 + { 113 + int action; 114 + 115 + action = mlxbf_bootctl_smc(smc_op, 0); 116 + if (action < 0) 117 + return action; 118 + 119 + return sprintf(buf, "%s\n", mlxbf_bootctl_action_to_string(action)); 120 + } 121 + 122 + static int mlxbf_bootctl_store(int smc_op, const char *buf, size_t count) 123 + { 124 + int ret, action; 125 + 126 + action = mlxbf_bootctl_reset_action_to_val(buf); 127 + if (action < 0) 128 + return action; 129 + 130 + ret = mlxbf_bootctl_smc(smc_op, action); 131 + if (ret < 0) 132 + return ret; 133 + 134 + return count; 135 + } 136 + 137 + static ssize_t reset_action_show(struct device *dev, 138 + struct device_attribute *attr, char *buf) 139 + { 140 + return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_RESET_ACTION, buf); 141 + } 142 + 143 + static ssize_t reset_action_store(struct device *dev, 144 + struct device_attribute *attr, 145 + const char *buf, size_t count) 146 + { 147 + return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_RESET_ACTION, buf, count); 148 + } 149 + 150 + static ssize_t second_reset_action_show(struct device *dev, 151 + struct device_attribute *attr, 152 + char *buf) 153 + { 154 + return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_SECOND_RESET_ACTION, buf); 155 + } 156 + 157 + static ssize_t second_reset_action_store(struct device *dev, 158 + struct device_attribute *attr, 159 + const char *buf, size_t count) 160 + { 161 + return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION, buf, 162 + count); 163 + } 164 + 165 + static ssize_t lifecycle_state_show(struct device *dev, 166 + struct device_attribute *attr, char *buf) 167 + { 168 + int lc_state; 169 + 170 + lc_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS, 171 + MLXBF_BOOTCTL_FUSE_STATUS_LIFECYCLE); 172 + if (lc_state < 0) 173 + return lc_state; 174 + 175 + lc_state &= 176 + MLXBF_BOOTCTL_SB_TEST_MASK | MLXBF_BOOTCTL_SB_SECURE_MASK; 177 + 178 + /* 179 + * If the test bits are set, we specify that the current state may be 180 + * due to using the test bits. 181 + */ 182 + if (lc_state & MLXBF_BOOTCTL_SB_TEST_MASK) { 183 + lc_state &= MLXBF_BOOTCTL_SB_SECURE_MASK; 184 + 185 + return sprintf(buf, "%s(test)\n", 186 + mlxbf_bootctl_lifecycle_states[lc_state]); 187 + } 188 + 189 + return sprintf(buf, "%s\n", mlxbf_bootctl_lifecycle_states[lc_state]); 190 + } 191 + 192 + static ssize_t secure_boot_fuse_state_show(struct device *dev, 193 + struct device_attribute *attr, 194 + char *buf) 195 + { 196 + int burnt, valid, key, key_state, buf_len = 0, upper_key_used = 0; 197 + const char *status; 198 + 199 + key_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS, 200 + MLXBF_BOOTCTL_FUSE_STATUS_KEYS); 201 + if (key_state < 0) 202 + return key_state; 203 + 204 + /* 205 + * key_state contains the bits for 4 Key versions, loaded from eFuses 206 + * after a hard reset. Lower 4 bits are a thermometer code indicating 207 + * key programming has started for key n (0000 = none, 0001 = version 0, 208 + * 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits 209 + * are a thermometer code indicating key programming has completed for 210 + * key n (same encodings as the start bits). This allows for detection 211 + * of an interruption in the progamming process which has left the key 212 + * partially programmed (and thus invalid). The process is to burn the 213 + * eFuse for the new key start bit, burn the key eFuses, then burn the 214 + * eFuse for the new key complete bit. 215 + * 216 + * For example 0000_0000: no key valid, 0001_0001: key version 0 valid, 217 + * 0011_0011: key 1 version valid, 0011_0111: key version 2 started 218 + * programming but did not complete, etc. The most recent key for which 219 + * both start and complete bit is set is loaded. On soft reset, this 220 + * register is not modified. 221 + */ 222 + for (key = MLXBF_SB_KEY_NUM - 1; key >= 0; key--) { 223 + burnt = key_state & BIT(key); 224 + valid = key_state & BIT(key + MLXBF_SB_KEY_NUM); 225 + 226 + if (burnt && valid) 227 + upper_key_used = 1; 228 + 229 + if (upper_key_used) { 230 + if (burnt) 231 + status = valid ? "Used" : "Wasted"; 232 + else 233 + status = valid ? "Invalid" : "Skipped"; 234 + } else { 235 + if (burnt) 236 + status = valid ? "InUse" : "Incomplete"; 237 + else 238 + status = valid ? "Invalid" : "Free"; 239 + } 240 + buf_len += sprintf(buf + buf_len, "%d:%s ", key, status); 241 + } 242 + buf_len += sprintf(buf + buf_len, "\n"); 243 + 244 + return buf_len; 245 + } 246 + 247 + static DEVICE_ATTR_RW(post_reset_wdog); 248 + static DEVICE_ATTR_RW(reset_action); 249 + static DEVICE_ATTR_RW(second_reset_action); 250 + static DEVICE_ATTR_RO(lifecycle_state); 251 + static DEVICE_ATTR_RO(secure_boot_fuse_state); 252 + 253 + static struct attribute *mlxbf_bootctl_attrs[] = { 254 + &dev_attr_post_reset_wdog.attr, 255 + &dev_attr_reset_action.attr, 256 + &dev_attr_second_reset_action.attr, 257 + &dev_attr_lifecycle_state.attr, 258 + &dev_attr_secure_boot_fuse_state.attr, 259 + NULL 260 + }; 261 + 262 + ATTRIBUTE_GROUPS(mlxbf_bootctl); 263 + 264 + static const struct acpi_device_id mlxbf_bootctl_acpi_ids[] = { 265 + {"MLNXBF04", 0}, 266 + {} 267 + }; 268 + 269 + MODULE_DEVICE_TABLE(acpi, mlxbf_bootctl_acpi_ids); 270 + 271 + static bool mlxbf_bootctl_guid_match(const guid_t *guid, 272 + const struct arm_smccc_res *res) 273 + { 274 + guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16, 275 + res->a2, res->a2 >> 8, res->a2 >> 16, 276 + res->a2 >> 24, res->a3, res->a3 >> 8, 277 + res->a3 >> 16, res->a3 >> 24); 278 + 279 + return guid_equal(guid, &id); 280 + } 281 + 282 + static int mlxbf_bootctl_probe(struct platform_device *pdev) 283 + { 284 + struct arm_smccc_res res = { 0 }; 285 + guid_t guid; 286 + int ret; 287 + 288 + /* Ensure we have the UUID we expect for this service. */ 289 + arm_smccc_smc(MLXBF_BOOTCTL_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); 290 + guid_parse(mlxbf_bootctl_svc_uuid_str, &guid); 291 + if (!mlxbf_bootctl_guid_match(&guid, &res)) 292 + return -ENODEV; 293 + 294 + /* 295 + * When watchdog is used, it sets boot mode to MLXBF_BOOTCTL_SWAP_EMMC 296 + * in case of boot failures. However it doesn't clear the state if there 297 + * is no failure. Restore the default boot mode here to avoid any 298 + * unnecessary boot partition swapping. 299 + */ 300 + ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_RESET_ACTION, 301 + MLXBF_BOOTCTL_EMMC); 302 + if (ret < 0) 303 + dev_warn(&pdev->dev, "Unable to reset the EMMC boot mode\n"); 304 + 305 + return 0; 306 + } 307 + 308 + static struct platform_driver mlxbf_bootctl_driver = { 309 + .probe = mlxbf_bootctl_probe, 310 + .driver = { 311 + .name = "mlxbf-bootctl", 312 + .groups = mlxbf_bootctl_groups, 313 + .acpi_match_table = mlxbf_bootctl_acpi_ids, 314 + } 315 + }; 316 + 317 + module_platform_driver(mlxbf_bootctl_driver); 318 + 319 + MODULE_DESCRIPTION("Mellanox boot control driver"); 320 + MODULE_LICENSE("GPL v2"); 321 + MODULE_AUTHOR("Mellanox Technologies");
+103
drivers/platform/mellanox/mlxbf-bootctl.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2019, Mellanox Technologies. All rights reserved. 4 + */ 5 + 6 + #ifndef __MLXBF_BOOTCTL_H__ 7 + #define __MLXBF_BOOTCTL_H__ 8 + 9 + /* 10 + * Request that the on-chip watchdog be enabled, or disabled, after 11 + * the next chip soft reset. This call does not affect the current 12 + * status of the on-chip watchdog. If non-zero, the argument 13 + * specifies the watchdog interval in seconds. If zero, the watchdog 14 + * will not be enabled after the next soft reset. Non-zero errors are 15 + * returned as documented below. 16 + */ 17 + #define MLXBF_BOOTCTL_SET_POST_RESET_WDOG 0x82000000 18 + 19 + /* 20 + * Query the status which has been requested for the on-chip watchdog 21 + * after the next chip soft reset. Returns the interval as set by 22 + * MLXBF_BOOTCTL_SET_POST_RESET_WDOG. 23 + */ 24 + #define MLXBF_BOOTCTL_GET_POST_RESET_WDOG 0x82000001 25 + 26 + /* 27 + * Request that a specific boot action be taken at the next soft 28 + * reset. By default, the boot action is set by external chip pins, 29 + * which are sampled on hard reset. Note that the boot action 30 + * requested by this call will persist on subsequent resets unless 31 + * this service, or the MLNX_SET_SECOND_RESET_ACTION service, is 32 + * invoked. See below for the available MLNX_BOOT_xxx parameter 33 + * values. Non-zero errors are returned as documented below. 34 + */ 35 + #define MLXBF_BOOTCTL_SET_RESET_ACTION 0x82000002 36 + 37 + /* 38 + * Return the specific boot action which will be taken at the next 39 + * soft reset. Returns the reset action (see below for the parameter 40 + * values for MLXBF_BOOTCTL_SET_RESET_ACTION). 41 + */ 42 + #define MLXBF_BOOTCTL_GET_RESET_ACTION 0x82000003 43 + 44 + /* 45 + * Request that a specific boot action be taken at the soft reset 46 + * after the next soft reset. For a specified valid boot mode, the 47 + * effect of this call is identical to that of invoking 48 + * MLXBF_BOOTCTL_SET_RESET_ACTION after the next chip soft reset; in 49 + * particular, after that reset, the action for the now next reset can 50 + * be queried with MLXBF_BOOTCTL_GET_RESET_ACTION and modified with 51 + * MLXBF_BOOTCTL_SET_RESET_ACTION. You may also specify the parameter as 52 + * MLNX_BOOT_NONE, which is equivalent to specifying that no call to 53 + * MLXBF_BOOTCTL_SET_RESET_ACTION be taken after the next chip soft reset. 54 + * This call does not affect the action to be taken at the next soft 55 + * reset. Non-zero errors are returned as documented below. 56 + */ 57 + #define MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION 0x82000004 58 + 59 + /* 60 + * Return the specific boot action which will be taken at the soft 61 + * reset after the next soft reset; this will be one of the valid 62 + * actions for MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION. 63 + */ 64 + #define MLXBF_BOOTCTL_GET_SECOND_RESET_ACTION 0x82000005 65 + 66 + /* 67 + * Return the fuse status of the current chip. The caller should specify 68 + * with the second argument if the state of the lifecycle fuses or the 69 + * version of secure boot fuse keys left should be returned. 70 + */ 71 + #define MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS 0x82000006 72 + 73 + /* Reset eMMC by programming the RST_N register. */ 74 + #define MLXBF_BOOTCTL_SET_EMMC_RST_N 0x82000007 75 + 76 + #define MLXBF_BOOTCTL_GET_DIMM_INFO 0x82000008 77 + 78 + /* SMC function IDs for SiP Service queries */ 79 + #define MLXBF_BOOTCTL_SIP_SVC_CALL_COUNT 0x8200ff00 80 + #define MLXBF_BOOTCTL_SIP_SVC_UID 0x8200ff01 81 + #define MLXBF_BOOTCTL_SIP_SVC_VERSION 0x8200ff03 82 + 83 + /* ARM Standard Service Calls version numbers */ 84 + #define MLXBF_BOOTCTL_SVC_VERSION_MAJOR 0x0 85 + #define MLXBF_BOOTCTL_SVC_VERSION_MINOR 0x2 86 + 87 + /* Number of svc calls defined. */ 88 + #define MLXBF_BOOTCTL_NUM_SVC_CALLS 12 89 + 90 + /* Valid reset actions for MLXBF_BOOTCTL_SET_RESET_ACTION. */ 91 + #define MLXBF_BOOTCTL_EXTERNAL 0 /* Not boot from eMMC */ 92 + #define MLXBF_BOOTCTL_EMMC 1 /* From primary eMMC boot partition */ 93 + #define MLNX_BOOTCTL_SWAP_EMMC 2 /* Swap eMMC boot partitions and reboot */ 94 + #define MLXBF_BOOTCTL_EMMC_LEGACY 3 /* From primary eMMC in legacy mode */ 95 + 96 + /* Valid arguments for requesting the fuse status. */ 97 + #define MLXBF_BOOTCTL_FUSE_STATUS_LIFECYCLE 0 /* Return lifecycle status. */ 98 + #define MLXBF_BOOTCTL_FUSE_STATUS_KEYS 1 /* Return secure boot key status */ 99 + 100 + /* Additional value to disable the MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION. */ 101 + #define MLXBF_BOOTCTL_NONE 0x7fffffff /* Don't change next boot action */ 102 + 103 + #endif /* __MLXBF_BOOTCTL_H__ */
+25 -10
drivers/platform/x86/Kconfig
··· 94 94 depends on RFKILL || RFKILL = n 95 95 depends on ACPI_VIDEO || ACPI_VIDEO = n 96 96 select INPUT_SPARSEKMAP 97 - select INPUT_POLLDEV 98 97 ---help--- 99 98 This is a driver for Asus laptops, Lenovo SL and the Pegatron 100 99 Lucid tablet. It may also support some MEDION, JVC or VICTOR ··· 622 623 config SENSORS_HDAPS 623 624 tristate "Thinkpad Hard Drive Active Protection System (hdaps)" 624 625 depends on INPUT 625 - select INPUT_POLLDEV 626 626 help 627 627 This driver provides support for the IBM Hard Drive Active Protection 628 628 System (hdaps), which provides an accelerometer and other misc. data. ··· 804 806 tristate "PEAQ 2-in-1 WMI hotkey driver" 805 807 depends on ACPI_WMI 806 808 depends on INPUT 807 - select INPUT_POLLDEV 808 809 help 809 810 Say Y here if you want to support WMI-based hotkeys on PEAQ 2-in-1s. 810 811 ··· 831 834 depends on ACPI_VIDEO || ACPI_VIDEO = n 832 835 depends on RFKILL || RFKILL = n 833 836 depends on IIO 834 - select INPUT_POLLDEV 835 837 select INPUT_SPARSEKMAP 836 838 ---help--- 837 839 This driver adds support for access to certain system settings ··· 927 931 This driver add support for the INT33FE ACPI device found on 928 932 some Intel Cherry Trail devices. 929 933 934 + There are two kinds of INT33FE ACPI device possible: for hardware 935 + with USB Type-C and Micro-B connectors. This driver supports both. 936 + 930 937 The INT33FE ACPI device has a CRS table with I2cSerialBusV2 931 - resources for 3 devices: Maxim MAX17047 Fuel Gauge Controller, 938 + resources for Fuel Gauge Controller and (in the Type-C variant) 932 939 FUSB302 USB Type-C Controller and PI3USB30532 USB switch. 933 940 This driver instantiates i2c-clients for these, so that standard 934 941 i2c drivers for these chips can bind to the them. 935 942 936 943 If you enable this driver it is advised to also select 937 - CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m. 944 + CONFIG_BATTERY_BQ27XXX=m or CONFIG_BATTERY_BQ27XXX_I2C=m for Micro-B 945 + device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m 946 + for Type-C device. 947 + 938 948 939 949 config INTEL_INT0002_VGPIO 940 950 tristate "Intel ACPI INT0002 Virtual GPIO driver" ··· 1307 1305 will be called intel_atomisp2_pm. 1308 1306 1309 1307 config HUAWEI_WMI 1310 - tristate "Huawei WMI hotkeys driver" 1308 + tristate "Huawei WMI laptop extras driver" 1309 + depends on ACPI_BATTERY 1311 1310 depends on ACPI_WMI 1312 1311 depends on INPUT 1313 1312 select INPUT_SPARSEKMAP ··· 1317 1314 select LEDS_TRIGGER_AUDIO 1318 1315 select NEW_LEDS 1319 1316 help 1320 - This driver provides support for Huawei WMI hotkeys. 1321 - It enables the missing keys and adds support to the micmute 1322 - LED found on some of these laptops. 1317 + This driver provides support for Huawei WMI hotkeys, battery charge 1318 + control, fn-lock, mic-mute LED, and other extra features. 1323 1319 1324 1320 To compile this driver as a module, choose M here: the module 1325 1321 will be called huawei-wmi. ··· 1338 1336 will be called pcengines-apuv2. 1339 1337 1340 1338 source "drivers/platform/x86/intel_speed_select_if/Kconfig" 1339 + 1340 + config SYSTEM76_ACPI 1341 + tristate "System76 ACPI Driver" 1342 + depends on ACPI 1343 + select NEW_LEDS 1344 + select LEDS_CLASS 1345 + select LEDS_TRIGGERS 1346 + help 1347 + This is a driver for System76 laptops running open firmware. It adds 1348 + support for Fn-Fx key combinations, keyboard backlight, and airplane mode 1349 + LEDs. 1350 + 1351 + If you have a System76 laptop running open firmware, say Y or M here. 1341 1352 1342 1353 endif # X86_PLATFORM_DEVICES 1343 1354
+5
drivers/platform/x86/Makefile
··· 61 61 obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o 62 62 obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o 63 63 obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o 64 + intel_cht_int33fe-objs := intel_cht_int33fe_common.o \ 65 + intel_cht_int33fe_typec.o \ 66 + intel_cht_int33fe_microb.o 67 + 64 68 obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o 65 69 obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o 66 70 obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o ··· 104 100 obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o 105 101 obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o 106 102 obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += intel_speed_select_if/ 103 + obj-$(CONFIG_SYSTEM76_ACPI) += system76_acpi.o
+5 -2
drivers/platform/x86/acerhdf.c
··· 4 4 * of the aspire one netbook, turns on/off the fan 5 5 * as soon as the upper/lower threshold is reached. 6 6 * 7 - * (C) 2009 - Peter Feuerer peter (a) piie.net 7 + * (C) 2009 - Peter Kaestle peter (a) piie.net 8 8 * http://piie.net 9 9 * 2009 Borislav Petkov bp (a) alien8.de 10 10 * ··· 224 224 {"Acer", "Aspire 5739G", "V1.3311", 0x55, 0x58, {0x20, 0x00}, 0}, 225 225 /* Acer TravelMate 7730 */ 226 226 {"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00}, 0}, 227 + /* Acer Aspire 7551 */ 228 + {"Acer", "Aspire 7551", "V1.18", 0x93, 0xa8, {0x14, 0x04}, 1}, 227 229 /* Acer TravelMate TM8573T */ 228 230 {"Acer", "TM8573T", "V1.13", 0x93, 0xa8, {0x14, 0x04}, 1}, 229 231 /* Gateway */ ··· 803 801 } 804 802 805 803 MODULE_LICENSE("GPL"); 806 - MODULE_AUTHOR("Peter Feuerer"); 804 + MODULE_AUTHOR("Peter Kaestle"); 807 805 MODULE_DESCRIPTION("Aspire One temperature and fan driver"); 808 806 MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); 809 807 MODULE_ALIAS("dmi:*:*Acer*:pnAO751h*:"); ··· 817 815 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*One*753:"); 818 816 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5315:"); 819 817 MODULE_ALIAS("dmi:*:*Acer*:TravelMate*7730G:"); 818 + MODULE_ALIAS("dmi:*:*Acer*:pnAspire*7551:"); 820 819 MODULE_ALIAS("dmi:*:*Acer*:TM8573T:"); 821 820 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); 822 821 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
+35 -36
drivers/platform/x86/asus-laptop.c
··· 34 34 #include <linux/uaccess.h> 35 35 #include <linux/input.h> 36 36 #include <linux/input/sparse-keymap.h> 37 - #include <linux/input-polldev.h> 38 37 #include <linux/rfkill.h> 39 38 #include <linux/slab.h> 40 39 #include <linux/dmi.h> ··· 243 244 244 245 struct input_dev *inputdev; 245 246 struct key_entry *keymap; 246 - struct input_polled_dev *pega_accel_poll; 247 + struct input_dev *pega_accel_poll; 247 248 248 249 struct asus_led wled; 249 250 struct asus_led bled; ··· 445 446 return clamp_val((short)val, -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP); 446 447 } 447 448 448 - static void pega_accel_poll(struct input_polled_dev *ipd) 449 + static void pega_accel_poll(struct input_dev *input) 449 450 { 450 - struct device *parent = ipd->input->dev.parent; 451 + struct device *parent = input->dev.parent; 451 452 struct asus_laptop *asus = dev_get_drvdata(parent); 452 453 453 454 /* In some cases, the very first call to poll causes a ··· 456 457 * device, and perhaps a firmware bug. Fake the first report. */ 457 458 if (!asus->pega_acc_live) { 458 459 asus->pega_acc_live = true; 459 - input_report_abs(ipd->input, ABS_X, 0); 460 - input_report_abs(ipd->input, ABS_Y, 0); 461 - input_report_abs(ipd->input, ABS_Z, 0); 462 - input_sync(ipd->input); 460 + input_report_abs(input, ABS_X, 0); 461 + input_report_abs(input, ABS_Y, 0); 462 + input_report_abs(input, ABS_Z, 0); 463 + input_sync(input); 463 464 return; 464 465 } 465 466 ··· 470 471 /* Note transform, convert to "right/up/out" in the native 471 472 * landscape orientation (i.e. the vector is the direction of 472 473 * "real up" in the device's cartiesian coordinates). */ 473 - input_report_abs(ipd->input, ABS_X, -asus->pega_acc_x); 474 - input_report_abs(ipd->input, ABS_Y, -asus->pega_acc_y); 475 - input_report_abs(ipd->input, ABS_Z, asus->pega_acc_z); 476 - input_sync(ipd->input); 474 + input_report_abs(input, ABS_X, -asus->pega_acc_x); 475 + input_report_abs(input, ABS_Y, -asus->pega_acc_y); 476 + input_report_abs(input, ABS_Z, asus->pega_acc_z); 477 + input_sync(input); 477 478 } 478 479 479 480 static void pega_accel_exit(struct asus_laptop *asus) 480 481 { 481 482 if (asus->pega_accel_poll) { 482 - input_unregister_polled_device(asus->pega_accel_poll); 483 - input_free_polled_device(asus->pega_accel_poll); 483 + input_unregister_device(asus->pega_accel_poll); 484 + asus->pega_accel_poll = NULL; 484 485 } 485 - asus->pega_accel_poll = NULL; 486 486 } 487 487 488 488 static int pega_accel_init(struct asus_laptop *asus) 489 489 { 490 490 int err; 491 - struct input_polled_dev *ipd; 491 + struct input_dev *input; 492 492 493 493 if (!asus->is_pega_lucid) 494 494 return -ENODEV; ··· 497 499 acpi_check_handle(asus->handle, METHOD_XLRZ, NULL)) 498 500 return -ENODEV; 499 501 500 - ipd = input_allocate_polled_device(); 501 - if (!ipd) 502 + input = input_allocate_device(); 503 + if (!input) 502 504 return -ENOMEM; 503 505 504 - ipd->poll = pega_accel_poll; 505 - ipd->poll_interval = 125; 506 - ipd->poll_interval_min = 50; 507 - ipd->poll_interval_max = 2000; 506 + input->name = PEGA_ACCEL_DESC; 507 + input->phys = PEGA_ACCEL_NAME "/input0"; 508 + input->dev.parent = &asus->platform_device->dev; 509 + input->id.bustype = BUS_HOST; 508 510 509 - ipd->input->name = PEGA_ACCEL_DESC; 510 - ipd->input->phys = PEGA_ACCEL_NAME "/input0"; 511 - ipd->input->dev.parent = &asus->platform_device->dev; 512 - ipd->input->id.bustype = BUS_HOST; 513 - 514 - set_bit(EV_ABS, ipd->input->evbit); 515 - input_set_abs_params(ipd->input, ABS_X, 511 + input_set_abs_params(input, ABS_X, 516 512 -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0); 517 - input_set_abs_params(ipd->input, ABS_Y, 513 + input_set_abs_params(input, ABS_Y, 518 514 -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0); 519 - input_set_abs_params(ipd->input, ABS_Z, 515 + input_set_abs_params(input, ABS_Z, 520 516 -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0); 521 517 522 - err = input_register_polled_device(ipd); 518 + err = input_setup_polling(input, pega_accel_poll); 523 519 if (err) 524 520 goto exit; 525 521 526 - asus->pega_accel_poll = ipd; 522 + input_set_poll_interval(input, 125); 523 + input_set_min_poll_interval(input, 50); 524 + input_set_max_poll_interval(input, 2000); 525 + 526 + err = input_register_device(input); 527 + if (err) 528 + goto exit; 529 + 530 + asus->pega_accel_poll = input; 527 531 return 0; 528 532 529 533 exit: 530 - input_free_polled_device(ipd); 534 + input_free_device(input); 531 535 return err; 532 536 } 533 537 ··· 1550 1550 1551 1551 /* Accelerometer "coarse orientation change" event */ 1552 1552 if (asus->pega_accel_poll && event == 0xEA) { 1553 - kobject_uevent(&asus->pega_accel_poll->input->dev.kobj, 1554 - KOBJ_CHANGE); 1553 + kobject_uevent(&asus->pega_accel_poll->dev.kobj, KOBJ_CHANGE); 1555 1554 return ; 1556 1555 } 1557 1556
+26
drivers/platform/x86/dell-laptop.c
··· 33 33 34 34 struct quirk_entry { 35 35 bool touchpad_led; 36 + bool kbd_led_not_present; 36 37 bool kbd_led_levels_off_1; 37 38 bool kbd_missing_ac_tag; 38 39 ··· 72 71 73 72 static struct quirk_entry quirk_dell_latitude_e6410 = { 74 73 .kbd_led_levels_off_1 = true, 74 + }; 75 + 76 + static struct quirk_entry quirk_dell_inspiron_1012 = { 77 + .kbd_led_not_present = true, 75 78 }; 76 79 77 80 static struct platform_driver platform_driver = { ··· 314 309 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6410"), 315 310 }, 316 311 .driver_data = &quirk_dell_latitude_e6410, 312 + }, 313 + { 314 + .callback = dmi_matched, 315 + .ident = "Dell Inspiron 1012", 316 + .matches = { 317 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 318 + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), 319 + }, 320 + .driver_data = &quirk_dell_inspiron_1012, 321 + }, 322 + { 323 + .callback = dmi_matched, 324 + .ident = "Dell Inspiron 1018", 325 + .matches = { 326 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 327 + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1018"), 328 + }, 329 + .driver_data = &quirk_dell_inspiron_1012, 317 330 }, 318 331 { } 319 332 }; ··· 1515 1492 static void kbd_init(void) 1516 1493 { 1517 1494 int ret; 1495 + 1496 + if (quirks && quirks->kbd_led_not_present) 1497 + return; 1518 1498 1519 1499 ret = kbd_init_info(); 1520 1500 kbd_init_tokens();
+19 -21
drivers/platform/x86/hdaps.c
··· 18 18 19 19 #include <linux/delay.h> 20 20 #include <linux/platform_device.h> 21 - #include <linux/input-polldev.h> 21 + #include <linux/input.h> 22 22 #include <linux/kernel.h> 23 23 #include <linux/mutex.h> 24 24 #include <linux/module.h> ··· 59 59 #define HDAPS_BOTH_AXES (HDAPS_X_AXIS | HDAPS_Y_AXIS) 60 60 61 61 static struct platform_device *pdev; 62 - static struct input_polled_dev *hdaps_idev; 62 + static struct input_dev *hdaps_idev; 63 63 static unsigned int hdaps_invert; 64 64 static u8 km_activity; 65 65 static int rest_x; ··· 318 318 __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y); 319 319 } 320 320 321 - static void hdaps_mousedev_poll(struct input_polled_dev *dev) 321 + static void hdaps_mousedev_poll(struct input_dev *input_dev) 322 322 { 323 - struct input_dev *input_dev = dev->input; 324 323 int x, y; 325 324 326 325 mutex_lock(&hdaps_mtx); ··· 530 531 531 532 static int __init hdaps_init(void) 532 533 { 533 - struct input_dev *idev; 534 534 int ret; 535 535 536 536 if (!dmi_check_system(hdaps_whitelist)) { ··· 557 559 if (ret) 558 560 goto out_device; 559 561 560 - hdaps_idev = input_allocate_polled_device(); 562 + hdaps_idev = input_allocate_device(); 561 563 if (!hdaps_idev) { 562 564 ret = -ENOMEM; 563 565 goto out_group; 564 566 } 565 567 566 - hdaps_idev->poll = hdaps_mousedev_poll; 567 - hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL; 568 - 569 568 /* initial calibrate for the input device */ 570 569 hdaps_calibrate(); 571 570 572 571 /* initialize the input class */ 573 - idev = hdaps_idev->input; 574 - idev->name = "hdaps"; 575 - idev->phys = "isa1600/input0"; 576 - idev->id.bustype = BUS_ISA; 577 - idev->dev.parent = &pdev->dev; 578 - idev->evbit[0] = BIT_MASK(EV_ABS); 579 - input_set_abs_params(idev, ABS_X, 572 + hdaps_idev->name = "hdaps"; 573 + hdaps_idev->phys = "isa1600/input0"; 574 + hdaps_idev->id.bustype = BUS_ISA; 575 + hdaps_idev->dev.parent = &pdev->dev; 576 + input_set_abs_params(hdaps_idev, ABS_X, 580 577 -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); 581 - input_set_abs_params(idev, ABS_Y, 578 + input_set_abs_params(hdaps_idev, ABS_Y, 582 579 -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); 583 580 584 - ret = input_register_polled_device(hdaps_idev); 581 + ret = input_setup_polling(hdaps_idev, hdaps_mousedev_poll); 582 + if (ret) 583 + goto out_idev; 584 + 585 + input_set_poll_interval(hdaps_idev, HDAPS_POLL_INTERVAL); 586 + 587 + ret = input_register_device(hdaps_idev); 585 588 if (ret) 586 589 goto out_idev; 587 590 ··· 590 591 return 0; 591 592 592 593 out_idev: 593 - input_free_polled_device(hdaps_idev); 594 + input_free_device(hdaps_idev); 594 595 out_group: 595 596 sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); 596 597 out_device: ··· 606 607 607 608 static void __exit hdaps_exit(void) 608 609 { 609 - input_unregister_polled_device(hdaps_idev); 610 - input_free_polled_device(hdaps_idev); 610 + input_unregister_device(hdaps_idev); 611 611 sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); 612 612 platform_device_unregister(pdev); 613 613 platform_driver_unregister(&hdaps_driver);
+5 -5
drivers/platform/x86/hp-wmi.c
··· 65 65 u32 command; 66 66 u32 commandtype; 67 67 u32 datasize; 68 - u32 data; 68 + u8 data[128]; 69 69 }; 70 70 71 71 enum hp_wmi_commandtype { ··· 216 216 .command = command, 217 217 .commandtype = query, 218 218 .datasize = insize, 219 - .data = 0, 219 + .data = { 0 }, 220 220 }; 221 221 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 222 222 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; ··· 228 228 229 229 if (WARN_ON(insize > sizeof(args.data))) 230 230 return -EINVAL; 231 - memcpy(&args.data, buffer, insize); 231 + memcpy(&args.data[0], buffer, insize); 232 232 233 233 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output); 234 234 ··· 380 380 int err, i; 381 381 382 382 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 383 - 0, sizeof(state)); 383 + sizeof(state), sizeof(state)); 384 384 if (err) 385 385 return err; 386 386 ··· 778 778 int err, i; 779 779 780 780 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 781 - 0, sizeof(state)); 781 + sizeof(state), sizeof(state)); 782 782 if (err) 783 783 return err < 0 ? err : -EINVAL; 784 784
+791 -99
drivers/platform/x86/huawei-wmi.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 - * Huawei WMI hotkeys 3 + * Huawei WMI laptop extras driver 4 4 * 5 5 * Copyright (C) 2018 Ayman Bagabas <ayman.bagabas@gmail.com> 6 6 */ 7 7 8 8 #include <linux/acpi.h> 9 + #include <linux/debugfs.h> 10 + #include <linux/delay.h> 11 + #include <linux/dmi.h> 9 12 #include <linux/input.h> 10 13 #include <linux/input/sparse-keymap.h> 11 14 #include <linux/leds.h> 12 15 #include <linux/module.h> 16 + #include <linux/mutex.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/power_supply.h> 19 + #include <linux/sysfs.h> 13 20 #include <linux/wmi.h> 21 + #include <acpi/battery.h> 14 22 15 23 /* 16 24 * Huawei WMI GUIDs 17 25 */ 18 - #define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100" 19 - #define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000" 26 + #define HWMI_METHOD_GUID "ABBC0F5B-8EA1-11D1-A000-C90629100000" 27 + #define HWMI_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000" 20 28 29 + /* Legacy GUIDs */ 21 30 #define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100" 31 + #define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100" 22 32 23 - struct huawei_wmi_priv { 24 - struct input_dev *idev; 25 - struct led_classdev cdev; 26 - acpi_handle handle; 27 - char *acpi_method; 33 + /* HWMI commands */ 34 + 35 + enum { 36 + BATTERY_THRESH_GET = 0x00001103, /* \GBTT */ 37 + BATTERY_THRESH_SET = 0x00001003, /* \SBTT */ 38 + FN_LOCK_GET = 0x00000604, /* \GFRS */ 39 + FN_LOCK_SET = 0x00000704, /* \SFRS */ 40 + MICMUTE_LED_SET = 0x00000b04, /* \SMLS */ 28 41 }; 42 + 43 + union hwmi_arg { 44 + u64 cmd; 45 + u8 args[8]; 46 + }; 47 + 48 + struct quirk_entry { 49 + bool battery_reset; 50 + bool ec_micmute; 51 + bool report_brightness; 52 + }; 53 + 54 + static struct quirk_entry *quirks; 55 + 56 + struct huawei_wmi_debug { 57 + struct dentry *root; 58 + u64 arg; 59 + }; 60 + 61 + struct huawei_wmi { 62 + bool battery_available; 63 + bool fn_lock_available; 64 + 65 + struct huawei_wmi_debug debug; 66 + struct input_dev *idev[2]; 67 + struct led_classdev cdev; 68 + struct device *dev; 69 + 70 + struct mutex wmi_lock; 71 + }; 72 + 73 + static struct huawei_wmi *huawei_wmi; 29 74 30 75 static const struct key_entry huawei_wmi_keymap[] = { 31 76 { KE_KEY, 0x281, { KEY_BRIGHTNESSDOWN } }, ··· 82 37 { KE_KEY, 0x289, { KEY_WLAN } }, 83 38 // Huawei |M| key 84 39 { KE_KEY, 0x28a, { KEY_CONFIG } }, 85 - // Keyboard backlight 40 + // Keyboard backlit 86 41 { KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } }, 87 42 { KE_IGNORE, 0x294, { KEY_KBDILLUMUP } }, 88 43 { KE_IGNORE, 0x295, { KEY_KBDILLUMUP } }, 89 44 { KE_END, 0 } 90 45 }; 91 46 92 - static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev, 93 - enum led_brightness brightness) 47 + static int battery_reset = -1; 48 + static int report_brightness = -1; 49 + 50 + module_param(battery_reset, bint, 0444); 51 + MODULE_PARM_DESC(battery_reset, 52 + "Reset battery charge values to (0-0) before disabling it using (0-100)"); 53 + module_param(report_brightness, bint, 0444); 54 + MODULE_PARM_DESC(report_brightness, 55 + "Report brightness keys."); 56 + 57 + /* Quirks */ 58 + 59 + static int __init dmi_matched(const struct dmi_system_id *dmi) 94 60 { 95 - struct huawei_wmi_priv *priv = dev_get_drvdata(led_cdev->dev->parent); 61 + quirks = dmi->driver_data; 62 + return 1; 63 + } 64 + 65 + static struct quirk_entry quirk_unknown = { 66 + }; 67 + 68 + static struct quirk_entry quirk_battery_reset = { 69 + .battery_reset = true, 70 + }; 71 + 72 + static struct quirk_entry quirk_matebook_x = { 73 + .ec_micmute = true, 74 + .report_brightness = true, 75 + }; 76 + 77 + static const struct dmi_system_id huawei_quirks[] = { 78 + { 79 + .callback = dmi_matched, 80 + .ident = "Huawei MACH-WX9", 81 + .matches = { 82 + DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), 83 + DMI_MATCH(DMI_PRODUCT_NAME, "MACH-WX9"), 84 + }, 85 + .driver_data = &quirk_battery_reset 86 + }, 87 + { 88 + .callback = dmi_matched, 89 + .ident = "Huawei MateBook X", 90 + .matches = { 91 + DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), 92 + DMI_MATCH(DMI_PRODUCT_NAME, "HUAWEI MateBook X") 93 + }, 94 + .driver_data = &quirk_matebook_x 95 + }, 96 + { } 97 + }; 98 + 99 + /* Utils */ 100 + 101 + static int huawei_wmi_call(struct huawei_wmi *huawei, 102 + struct acpi_buffer *in, struct acpi_buffer *out) 103 + { 96 104 acpi_status status; 97 - union acpi_object args[3]; 98 - struct acpi_object_list arg_list = { 99 - .pointer = args, 100 - .count = ARRAY_SIZE(args), 101 - }; 102 105 103 - args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER; 104 - args[1].integer.value = 0x04; 105 - 106 - if (strcmp(priv->acpi_method, "SPIN") == 0) { 107 - args[0].integer.value = 0; 108 - args[2].integer.value = brightness ? 1 : 0; 109 - } else if (strcmp(priv->acpi_method, "WPIN") == 0) { 110 - args[0].integer.value = 1; 111 - args[2].integer.value = brightness ? 0 : 1; 112 - } else { 113 - return -EINVAL; 106 + mutex_lock(&huawei->wmi_lock); 107 + status = wmi_evaluate_method(HWMI_METHOD_GUID, 0, 1, in, out); 108 + mutex_unlock(&huawei->wmi_lock); 109 + if (ACPI_FAILURE(status)) { 110 + dev_err(huawei->dev, "Failed to evaluate wmi method\n"); 111 + return -ENODEV; 114 112 } 115 - 116 - status = acpi_evaluate_object(priv->handle, priv->acpi_method, &arg_list, NULL); 117 - if (ACPI_FAILURE(status)) 118 - return -ENXIO; 119 113 120 114 return 0; 121 115 } 122 116 123 - static int huawei_wmi_leds_setup(struct wmi_device *wdev) 117 + /* HWMI takes a 64 bit input and returns either a package with 2 buffers, one of 118 + * 4 bytes and the other of 256 bytes, or one buffer of size 0x104 (260) bytes. 119 + * The first 4 bytes are ignored, we ignore the first 4 bytes buffer if we got a 120 + * package, or skip the first 4 if a buffer of 0x104 is used. The first byte of 121 + * the remaining 0x100 sized buffer has the return status of every call. In case 122 + * the return status is non-zero, we return -ENODEV but still copy the returned 123 + * buffer to the given buffer parameter (buf). 124 + */ 125 + static int huawei_wmi_cmd(u64 arg, u8 *buf, size_t buflen) 124 126 { 125 - struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev); 127 + struct huawei_wmi *huawei = huawei_wmi; 128 + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 129 + struct acpi_buffer in; 130 + union acpi_object *obj; 131 + size_t len; 132 + int err, i; 126 133 127 - priv->handle = ec_get_handle(); 128 - if (!priv->handle) 129 - return 0; 134 + in.length = sizeof(arg); 135 + in.pointer = &arg; 130 136 131 - if (acpi_has_method(priv->handle, "SPIN")) 132 - priv->acpi_method = "SPIN"; 133 - else if (acpi_has_method(priv->handle, "WPIN")) 134 - priv->acpi_method = "WPIN"; 135 - else 136 - return 0; 137 + /* Some models require calling HWMI twice to execute a command. We evaluate 138 + * HWMI and if we get a non-zero return status we evaluate it again. 139 + */ 140 + for (i = 0; i < 2; i++) { 141 + err = huawei_wmi_call(huawei, &in, &out); 142 + if (err) 143 + goto fail_cmd; 137 144 138 - priv->cdev.name = "platform::micmute"; 139 - priv->cdev.max_brightness = 1; 140 - priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set; 141 - priv->cdev.default_trigger = "audio-micmute"; 142 - priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); 143 - priv->cdev.dev = &wdev->dev; 144 - priv->cdev.flags = LED_CORE_SUSPENDRESUME; 145 + obj = out.pointer; 146 + if (!obj) { 147 + err = -EIO; 148 + goto fail_cmd; 149 + } 145 150 146 - return devm_led_classdev_register(&wdev->dev, &priv->cdev); 151 + switch (obj->type) { 152 + /* Models that implement both "legacy" and HWMI tend to return a 0x104 153 + * sized buffer instead of a package of 0x4 and 0x100 buffers. 154 + */ 155 + case ACPI_TYPE_BUFFER: 156 + if (obj->buffer.length == 0x104) { 157 + // Skip the first 4 bytes. 158 + obj->buffer.pointer += 4; 159 + len = 0x100; 160 + } else { 161 + dev_err(huawei->dev, "Bad buffer length, got %d\n", obj->buffer.length); 162 + err = -EIO; 163 + goto fail_cmd; 164 + } 165 + 166 + break; 167 + /* HWMI returns a package with 2 buffer elements, one of 4 bytes and the 168 + * other is 256 bytes. 169 + */ 170 + case ACPI_TYPE_PACKAGE: 171 + if (obj->package.count != 2) { 172 + dev_err(huawei->dev, "Bad package count, got %d\n", obj->package.count); 173 + err = -EIO; 174 + goto fail_cmd; 175 + } 176 + 177 + obj = &obj->package.elements[1]; 178 + if (obj->type != ACPI_TYPE_BUFFER) { 179 + dev_err(huawei->dev, "Bad package element type, got %d\n", obj->type); 180 + err = -EIO; 181 + goto fail_cmd; 182 + } 183 + len = obj->buffer.length; 184 + 185 + break; 186 + /* Shouldn't get here! */ 187 + default: 188 + dev_err(huawei->dev, "Unexpected obj type, got: %d\n", obj->type); 189 + err = -EIO; 190 + goto fail_cmd; 191 + } 192 + 193 + if (!*obj->buffer.pointer) 194 + break; 195 + } 196 + 197 + err = (*obj->buffer.pointer) ? -ENODEV : 0; 198 + 199 + if (buf) { 200 + len = min(buflen, len); 201 + memcpy(buf, obj->buffer.pointer, len); 202 + } 203 + 204 + fail_cmd: 205 + kfree(out.pointer); 206 + return err; 147 207 } 148 208 149 - static void huawei_wmi_process_key(struct wmi_device *wdev, int code) 209 + /* LEDs */ 210 + 211 + static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev, 212 + enum led_brightness brightness) 150 213 { 151 - struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev); 214 + /* This is a workaround until the "legacy" interface is implemented. */ 215 + if (quirks && quirks->ec_micmute) { 216 + char *acpi_method; 217 + acpi_handle handle; 218 + acpi_status status; 219 + union acpi_object args[3]; 220 + struct acpi_object_list arg_list = { 221 + .pointer = args, 222 + .count = ARRAY_SIZE(args), 223 + }; 224 + 225 + handle = ec_get_handle(); 226 + if (!handle) 227 + return -ENODEV; 228 + 229 + args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER; 230 + args[1].integer.value = 0x04; 231 + 232 + if (acpi_has_method(handle, "SPIN")) { 233 + acpi_method = "SPIN"; 234 + args[0].integer.value = 0; 235 + args[2].integer.value = brightness ? 1 : 0; 236 + } else if (acpi_has_method(handle, "WPIN")) { 237 + acpi_method = "WPIN"; 238 + args[0].integer.value = 1; 239 + args[2].integer.value = brightness ? 0 : 1; 240 + } else { 241 + return -ENODEV; 242 + } 243 + 244 + status = acpi_evaluate_object(handle, acpi_method, &arg_list, NULL); 245 + if (ACPI_FAILURE(status)) 246 + return -ENODEV; 247 + 248 + return 0; 249 + } else { 250 + union hwmi_arg arg; 251 + 252 + arg.cmd = MICMUTE_LED_SET; 253 + arg.args[2] = brightness; 254 + 255 + return huawei_wmi_cmd(arg.cmd, NULL, 0); 256 + } 257 + } 258 + 259 + static void huawei_wmi_leds_setup(struct device *dev) 260 + { 261 + struct huawei_wmi *huawei = dev_get_drvdata(dev); 262 + 263 + huawei->cdev.name = "platform::micmute"; 264 + huawei->cdev.max_brightness = 1; 265 + huawei->cdev.brightness_set_blocking = &huawei_wmi_micmute_led_set; 266 + huawei->cdev.default_trigger = "audio-micmute"; 267 + huawei->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); 268 + huawei->cdev.dev = dev; 269 + huawei->cdev.flags = LED_CORE_SUSPENDRESUME; 270 + 271 + devm_led_classdev_register(dev, &huawei->cdev); 272 + } 273 + 274 + /* Battery protection */ 275 + 276 + static int huawei_wmi_battery_get(int *start, int *end) 277 + { 278 + u8 ret[0x100]; 279 + int err, i; 280 + 281 + err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, 0x100); 282 + if (err) 283 + return err; 284 + 285 + /* Find the last two non-zero values. Return status is ignored. */ 286 + i = 0xff; 287 + do { 288 + if (start) 289 + *start = ret[i-1]; 290 + if (end) 291 + *end = ret[i]; 292 + } while (i > 2 && !ret[i--]); 293 + 294 + return 0; 295 + } 296 + 297 + static int huawei_wmi_battery_set(int start, int end) 298 + { 299 + union hwmi_arg arg; 300 + int err; 301 + 302 + if (start < 0 || end < 0 || start > 100 || end > 100) 303 + return -EINVAL; 304 + 305 + arg.cmd = BATTERY_THRESH_SET; 306 + arg.args[2] = start; 307 + arg.args[3] = end; 308 + 309 + /* This is an edge case were some models turn battery protection 310 + * off without changing their thresholds values. We clear the 311 + * values before turning off protection. Sometimes we need a sleep delay to 312 + * make sure these values make their way to EC memory. 313 + */ 314 + if (quirks && quirks->battery_reset && start == 0 && end == 100) { 315 + err = huawei_wmi_battery_set(0, 0); 316 + if (err) 317 + return err; 318 + 319 + msleep(1000); 320 + } 321 + 322 + err = huawei_wmi_cmd(arg.cmd, NULL, 0); 323 + 324 + return err; 325 + } 326 + 327 + static ssize_t charge_control_start_threshold_show(struct device *dev, 328 + struct device_attribute *attr, 329 + char *buf) 330 + { 331 + int err, start; 332 + 333 + err = huawei_wmi_battery_get(&start, NULL); 334 + if (err) 335 + return err; 336 + 337 + return sprintf(buf, "%d\n", start); 338 + } 339 + 340 + static ssize_t charge_control_end_threshold_show(struct device *dev, 341 + struct device_attribute *attr, 342 + char *buf) 343 + { 344 + int err, end; 345 + 346 + err = huawei_wmi_battery_get(NULL, &end); 347 + if (err) 348 + return err; 349 + 350 + return sprintf(buf, "%d\n", end); 351 + } 352 + 353 + static ssize_t charge_control_thresholds_show(struct device *dev, 354 + struct device_attribute *attr, 355 + char *buf) 356 + { 357 + int err, start, end; 358 + 359 + err = huawei_wmi_battery_get(&start, &end); 360 + if (err) 361 + return err; 362 + 363 + return sprintf(buf, "%d %d\n", start, end); 364 + } 365 + 366 + static ssize_t charge_control_start_threshold_store(struct device *dev, 367 + struct device_attribute *attr, 368 + const char *buf, size_t size) 369 + { 370 + int err, start, end; 371 + 372 + err = huawei_wmi_battery_get(NULL, &end); 373 + if (err) 374 + return err; 375 + 376 + if (sscanf(buf, "%d", &start) != 1) 377 + return -EINVAL; 378 + 379 + err = huawei_wmi_battery_set(start, end); 380 + if (err) 381 + return err; 382 + 383 + return size; 384 + } 385 + 386 + static ssize_t charge_control_end_threshold_store(struct device *dev, 387 + struct device_attribute *attr, 388 + const char *buf, size_t size) 389 + { 390 + int err, start, end; 391 + 392 + err = huawei_wmi_battery_get(&start, NULL); 393 + if (err) 394 + return err; 395 + 396 + if (sscanf(buf, "%d", &end) != 1) 397 + return -EINVAL; 398 + 399 + err = huawei_wmi_battery_set(start, end); 400 + if (err) 401 + return err; 402 + 403 + return size; 404 + } 405 + 406 + static ssize_t charge_control_thresholds_store(struct device *dev, 407 + struct device_attribute *attr, 408 + const char *buf, size_t size) 409 + { 410 + int err, start, end; 411 + 412 + if (sscanf(buf, "%d %d", &start, &end) != 2) 413 + return -EINVAL; 414 + 415 + err = huawei_wmi_battery_set(start, end); 416 + if (err) 417 + return err; 418 + 419 + return size; 420 + } 421 + 422 + static DEVICE_ATTR_RW(charge_control_start_threshold); 423 + static DEVICE_ATTR_RW(charge_control_end_threshold); 424 + static DEVICE_ATTR_RW(charge_control_thresholds); 425 + 426 + static int huawei_wmi_battery_add(struct power_supply *battery) 427 + { 428 + device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold); 429 + device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); 430 + 431 + return 0; 432 + } 433 + 434 + static int huawei_wmi_battery_remove(struct power_supply *battery) 435 + { 436 + device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold); 437 + device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold); 438 + 439 + return 0; 440 + } 441 + 442 + static struct acpi_battery_hook huawei_wmi_battery_hook = { 443 + .add_battery = huawei_wmi_battery_add, 444 + .remove_battery = huawei_wmi_battery_remove, 445 + .name = "Huawei Battery Extension" 446 + }; 447 + 448 + static void huawei_wmi_battery_setup(struct device *dev) 449 + { 450 + struct huawei_wmi *huawei = dev_get_drvdata(dev); 451 + 452 + huawei->battery_available = true; 453 + if (huawei_wmi_battery_get(NULL, NULL)) { 454 + huawei->battery_available = false; 455 + return; 456 + } 457 + 458 + battery_hook_register(&huawei_wmi_battery_hook); 459 + device_create_file(dev, &dev_attr_charge_control_thresholds); 460 + } 461 + 462 + static void huawei_wmi_battery_exit(struct device *dev) 463 + { 464 + struct huawei_wmi *huawei = dev_get_drvdata(dev); 465 + 466 + if (huawei->battery_available) { 467 + battery_hook_unregister(&huawei_wmi_battery_hook); 468 + device_remove_file(dev, &dev_attr_charge_control_thresholds); 469 + } 470 + } 471 + 472 + /* Fn lock */ 473 + 474 + static int huawei_wmi_fn_lock_get(int *on) 475 + { 476 + u8 ret[0x100] = { 0 }; 477 + int err, i; 478 + 479 + err = huawei_wmi_cmd(FN_LOCK_GET, ret, 0x100); 480 + if (err) 481 + return err; 482 + 483 + /* Find the first non-zero value. Return status is ignored. */ 484 + i = 1; 485 + do { 486 + if (on) 487 + *on = ret[i] - 1; // -1 undefined, 0 off, 1 on. 488 + } while (i < 0xff && !ret[i++]); 489 + 490 + return 0; 491 + } 492 + 493 + static int huawei_wmi_fn_lock_set(int on) 494 + { 495 + union hwmi_arg arg; 496 + 497 + arg.cmd = FN_LOCK_SET; 498 + arg.args[2] = on + 1; // 0 undefined, 1 off, 2 on. 499 + 500 + return huawei_wmi_cmd(arg.cmd, NULL, 0); 501 + } 502 + 503 + static ssize_t fn_lock_state_show(struct device *dev, 504 + struct device_attribute *attr, 505 + char *buf) 506 + { 507 + int err, on; 508 + 509 + err = huawei_wmi_fn_lock_get(&on); 510 + if (err) 511 + return err; 512 + 513 + return sprintf(buf, "%d\n", on); 514 + } 515 + 516 + static ssize_t fn_lock_state_store(struct device *dev, 517 + struct device_attribute *attr, 518 + const char *buf, size_t size) 519 + { 520 + int on, err; 521 + 522 + if (kstrtoint(buf, 10, &on) || 523 + on < 0 || on > 1) 524 + return -EINVAL; 525 + 526 + err = huawei_wmi_fn_lock_set(on); 527 + if (err) 528 + return err; 529 + 530 + return size; 531 + } 532 + 533 + static DEVICE_ATTR_RW(fn_lock_state); 534 + 535 + static void huawei_wmi_fn_lock_setup(struct device *dev) 536 + { 537 + struct huawei_wmi *huawei = dev_get_drvdata(dev); 538 + 539 + huawei->fn_lock_available = true; 540 + if (huawei_wmi_fn_lock_get(NULL)) { 541 + huawei->fn_lock_available = false; 542 + return; 543 + } 544 + 545 + device_create_file(dev, &dev_attr_fn_lock_state); 546 + } 547 + 548 + static void huawei_wmi_fn_lock_exit(struct device *dev) 549 + { 550 + struct huawei_wmi *huawei = dev_get_drvdata(dev); 551 + 552 + if (huawei->fn_lock_available) 553 + device_remove_file(dev, &dev_attr_fn_lock_state); 554 + } 555 + 556 + /* debugfs */ 557 + 558 + static void huawei_wmi_debugfs_call_dump(struct seq_file *m, void *data, 559 + union acpi_object *obj) 560 + { 561 + struct huawei_wmi *huawei = m->private; 562 + int i; 563 + 564 + switch (obj->type) { 565 + case ACPI_TYPE_INTEGER: 566 + seq_printf(m, "0x%llx", obj->integer.value); 567 + break; 568 + case ACPI_TYPE_STRING: 569 + seq_printf(m, "\"%.*s\"", obj->string.length, obj->string.pointer); 570 + break; 571 + case ACPI_TYPE_BUFFER: 572 + seq_puts(m, "{"); 573 + for (i = 0; i < obj->buffer.length; i++) { 574 + seq_printf(m, "0x%02x", obj->buffer.pointer[i]); 575 + if (i < obj->buffer.length - 1) 576 + seq_puts(m, ","); 577 + } 578 + seq_puts(m, "}"); 579 + break; 580 + case ACPI_TYPE_PACKAGE: 581 + seq_puts(m, "["); 582 + for (i = 0; i < obj->package.count; i++) { 583 + huawei_wmi_debugfs_call_dump(m, huawei, &obj->package.elements[i]); 584 + if (i < obj->package.count - 1) 585 + seq_puts(m, ","); 586 + } 587 + seq_puts(m, "]"); 588 + break; 589 + default: 590 + dev_err(huawei->dev, "Unexpected obj type, got %d\n", obj->type); 591 + return; 592 + } 593 + } 594 + 595 + static int huawei_wmi_debugfs_call_show(struct seq_file *m, void *data) 596 + { 597 + struct huawei_wmi *huawei = m->private; 598 + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 599 + struct acpi_buffer in; 600 + union acpi_object *obj; 601 + int err; 602 + 603 + in.length = sizeof(u64); 604 + in.pointer = &huawei->debug.arg; 605 + 606 + err = huawei_wmi_call(huawei, &in, &out); 607 + if (err) 608 + return err; 609 + 610 + obj = out.pointer; 611 + if (!obj) { 612 + err = -EIO; 613 + goto fail_debugfs_call; 614 + } 615 + 616 + huawei_wmi_debugfs_call_dump(m, huawei, obj); 617 + 618 + fail_debugfs_call: 619 + kfree(out.pointer); 620 + return err; 621 + } 622 + 623 + DEFINE_SHOW_ATTRIBUTE(huawei_wmi_debugfs_call); 624 + 625 + static void huawei_wmi_debugfs_setup(struct device *dev) 626 + { 627 + struct huawei_wmi *huawei = dev_get_drvdata(dev); 628 + 629 + huawei->debug.root = debugfs_create_dir("huawei-wmi", NULL); 630 + 631 + debugfs_create_x64("arg", 0644, huawei->debug.root, 632 + &huawei->debug.arg); 633 + debugfs_create_file("call", 0400, 634 + huawei->debug.root, huawei, &huawei_wmi_debugfs_call_fops); 635 + } 636 + 637 + static void huawei_wmi_debugfs_exit(struct device *dev) 638 + { 639 + struct huawei_wmi *huawei = dev_get_drvdata(dev); 640 + 641 + debugfs_remove_recursive(huawei->debug.root); 642 + } 643 + 644 + /* Input */ 645 + 646 + static void huawei_wmi_process_key(struct input_dev *idev, int code) 647 + { 152 648 const struct key_entry *key; 153 649 154 650 /* ··· 713 127 kfree(response.pointer); 714 128 } 715 129 716 - key = sparse_keymap_entry_from_scancode(priv->idev, code); 130 + key = sparse_keymap_entry_from_scancode(idev, code); 717 131 if (!key) { 718 - dev_info(&wdev->dev, "Unknown key pressed, code: 0x%04x\n", code); 132 + dev_info(&idev->dev, "Unknown key pressed, code: 0x%04x\n", code); 719 133 return; 720 134 } 721 135 722 - sparse_keymap_report_entry(priv->idev, key, 1, true); 136 + if (quirks && !quirks->report_brightness && 137 + (key->sw.code == KEY_BRIGHTNESSDOWN || 138 + key->sw.code == KEY_BRIGHTNESSUP)) 139 + return; 140 + 141 + sparse_keymap_report_entry(idev, key, 1, true); 723 142 } 724 143 725 - static void huawei_wmi_notify(struct wmi_device *wdev, 726 - union acpi_object *obj) 144 + static void huawei_wmi_input_notify(u32 value, void *context) 727 145 { 728 - if (obj->type == ACPI_TYPE_INTEGER) 729 - huawei_wmi_process_key(wdev, obj->integer.value); 146 + struct input_dev *idev = (struct input_dev *)context; 147 + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 148 + union acpi_object *obj; 149 + acpi_status status; 150 + 151 + status = wmi_get_event_data(value, &response); 152 + if (ACPI_FAILURE(status)) { 153 + dev_err(&idev->dev, "Unable to get event data\n"); 154 + return; 155 + } 156 + 157 + obj = (union acpi_object *)response.pointer; 158 + if (obj && obj->type == ACPI_TYPE_INTEGER) 159 + huawei_wmi_process_key(idev, obj->integer.value); 730 160 else 731 - dev_info(&wdev->dev, "Bad response type %d\n", obj->type); 161 + dev_err(&idev->dev, "Bad response type\n"); 162 + 163 + kfree(response.pointer); 732 164 } 733 165 734 - static int huawei_wmi_input_setup(struct wmi_device *wdev) 166 + static int huawei_wmi_input_setup(struct device *dev, 167 + const char *guid, 168 + struct input_dev **idev) 735 169 { 736 - struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev); 737 - int err; 738 - 739 - priv->idev = devm_input_allocate_device(&wdev->dev); 740 - if (!priv->idev) 170 + *idev = devm_input_allocate_device(dev); 171 + if (!*idev) 741 172 return -ENOMEM; 742 173 743 - priv->idev->name = "Huawei WMI hotkeys"; 744 - priv->idev->phys = "wmi/input0"; 745 - priv->idev->id.bustype = BUS_HOST; 746 - priv->idev->dev.parent = &wdev->dev; 174 + (*idev)->name = "Huawei WMI hotkeys"; 175 + (*idev)->phys = "wmi/input0"; 176 + (*idev)->id.bustype = BUS_HOST; 177 + (*idev)->dev.parent = dev; 747 178 748 - err = sparse_keymap_setup(priv->idev, huawei_wmi_keymap, NULL); 749 - if (err) 750 - return err; 751 - 752 - return input_register_device(priv->idev); 179 + return sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL) || 180 + input_register_device(*idev) || 181 + wmi_install_notify_handler(guid, huawei_wmi_input_notify, 182 + *idev); 753 183 } 754 184 755 - static int huawei_wmi_probe(struct wmi_device *wdev, const void *context) 185 + static void huawei_wmi_input_exit(struct device *dev, const char *guid) 756 186 { 757 - struct huawei_wmi_priv *priv; 758 - int err; 759 - 760 - priv = devm_kzalloc(&wdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL); 761 - if (!priv) 762 - return -ENOMEM; 763 - 764 - dev_set_drvdata(&wdev->dev, priv); 765 - 766 - err = huawei_wmi_input_setup(wdev); 767 - if (err) 768 - return err; 769 - 770 - return huawei_wmi_leds_setup(wdev); 187 + wmi_remove_notify_handler(guid); 771 188 } 772 189 773 - static const struct wmi_device_id huawei_wmi_id_table[] = { 190 + /* Huawei driver */ 191 + 192 + static const struct wmi_device_id huawei_wmi_events_id_table[] = { 774 193 { .guid_string = WMI0_EVENT_GUID }, 775 - { .guid_string = AMW0_EVENT_GUID }, 194 + { .guid_string = HWMI_EVENT_GUID }, 776 195 { } 777 196 }; 778 197 779 - static struct wmi_driver huawei_wmi_driver = { 198 + static int huawei_wmi_probe(struct platform_device *pdev) 199 + { 200 + const struct wmi_device_id *guid = huawei_wmi_events_id_table; 201 + int err; 202 + 203 + platform_set_drvdata(pdev, huawei_wmi); 204 + huawei_wmi->dev = &pdev->dev; 205 + 206 + while (*guid->guid_string) { 207 + struct input_dev *idev = *huawei_wmi->idev; 208 + 209 + if (wmi_has_guid(guid->guid_string)) { 210 + err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string, &idev); 211 + if (err) { 212 + dev_err(&pdev->dev, "Failed to setup input on %s\n", guid->guid_string); 213 + return err; 214 + } 215 + } 216 + 217 + idev++; 218 + guid++; 219 + } 220 + 221 + if (wmi_has_guid(HWMI_METHOD_GUID)) { 222 + mutex_init(&huawei_wmi->wmi_lock); 223 + 224 + huawei_wmi_leds_setup(&pdev->dev); 225 + huawei_wmi_fn_lock_setup(&pdev->dev); 226 + huawei_wmi_battery_setup(&pdev->dev); 227 + huawei_wmi_debugfs_setup(&pdev->dev); 228 + } 229 + 230 + return 0; 231 + } 232 + 233 + static int huawei_wmi_remove(struct platform_device *pdev) 234 + { 235 + const struct wmi_device_id *guid = huawei_wmi_events_id_table; 236 + 237 + while (*guid->guid_string) { 238 + if (wmi_has_guid(guid->guid_string)) 239 + huawei_wmi_input_exit(&pdev->dev, guid->guid_string); 240 + 241 + guid++; 242 + } 243 + 244 + if (wmi_has_guid(HWMI_METHOD_GUID)) { 245 + huawei_wmi_debugfs_exit(&pdev->dev); 246 + huawei_wmi_battery_exit(&pdev->dev); 247 + huawei_wmi_fn_lock_exit(&pdev->dev); 248 + } 249 + 250 + return 0; 251 + } 252 + 253 + static struct platform_driver huawei_wmi_driver = { 780 254 .driver = { 781 255 .name = "huawei-wmi", 782 256 }, 783 - .id_table = huawei_wmi_id_table, 784 257 .probe = huawei_wmi_probe, 785 - .notify = huawei_wmi_notify, 258 + .remove = huawei_wmi_remove, 786 259 }; 787 260 788 - module_wmi_driver(huawei_wmi_driver); 261 + static __init int huawei_wmi_init(void) 262 + { 263 + struct platform_device *pdev; 264 + int err; 789 265 790 - MODULE_DEVICE_TABLE(wmi, huawei_wmi_id_table); 266 + huawei_wmi = kzalloc(sizeof(struct huawei_wmi), GFP_KERNEL); 267 + if (!huawei_wmi) 268 + return -ENOMEM; 269 + 270 + quirks = &quirk_unknown; 271 + dmi_check_system(huawei_quirks); 272 + if (battery_reset != -1) 273 + quirks->battery_reset = battery_reset; 274 + if (report_brightness != -1) 275 + quirks->report_brightness = report_brightness; 276 + 277 + err = platform_driver_register(&huawei_wmi_driver); 278 + if (err) 279 + goto pdrv_err; 280 + 281 + pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0); 282 + if (IS_ERR(pdev)) { 283 + err = PTR_ERR(pdev); 284 + goto pdev_err; 285 + } 286 + 287 + return 0; 288 + 289 + pdev_err: 290 + platform_driver_unregister(&huawei_wmi_driver); 291 + pdrv_err: 292 + kfree(huawei_wmi); 293 + return err; 294 + } 295 + 296 + static __exit void huawei_wmi_exit(void) 297 + { 298 + struct platform_device *pdev = to_platform_device(huawei_wmi->dev); 299 + 300 + platform_device_unregister(pdev); 301 + platform_driver_unregister(&huawei_wmi_driver); 302 + 303 + kfree(huawei_wmi); 304 + } 305 + 306 + module_init(huawei_wmi_init); 307 + module_exit(huawei_wmi_exit); 308 + 309 + MODULE_ALIAS("wmi:"HWMI_METHOD_GUID); 310 + MODULE_DEVICE_TABLE(wmi, huawei_wmi_events_id_table); 791 311 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>"); 792 - MODULE_DESCRIPTION("Huawei WMI hotkeys"); 312 + MODULE_DESCRIPTION("Huawei WMI laptop extras driver"); 793 313 MODULE_LICENSE("GPL v2");
+8 -70
drivers/platform/x86/intel_cht_int33fe.c drivers/platform/x86/intel_cht_int33fe_typec.c
··· 17 17 * for these chips can bind to the them. 18 18 */ 19 19 20 - #include <linux/acpi.h> 21 20 #include <linux/i2c.h> 22 21 #include <linux/interrupt.h> 23 - #include <linux/module.h> 24 22 #include <linux/pci.h> 25 23 #include <linux/platform_device.h> 26 24 #include <linux/regulator/consumer.h> 27 25 #include <linux/slab.h> 28 26 #include <linux/usb/pd.h> 29 27 30 - #define EXPECTED_PTYPE 4 28 + #include "intel_cht_int33fe_common.h" 31 29 32 30 enum { 33 31 INT33FE_NODE_FUSB302, ··· 34 36 INT33FE_NODE_DISPLAYPORT, 35 37 INT33FE_NODE_USB_CONNECTOR, 36 38 INT33FE_NODE_MAX, 37 - }; 38 - 39 - struct cht_int33fe_data { 40 - struct i2c_client *max17047; 41 - struct i2c_client *fusb302; 42 - struct i2c_client *pi3usb30532; 43 - 44 - struct fwnode_handle *dp; 45 39 }; 46 40 47 41 static const struct software_node nodes[]; ··· 241 251 strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); 242 252 board_info.dev_name = "max17047"; 243 253 board_info.fwnode = fwnode; 244 - data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); 254 + data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); 245 255 246 - return PTR_ERR_OR_ZERO(data->max17047); 256 + return PTR_ERR_OR_ZERO(data->battery_fg); 247 257 } 248 258 249 - static int cht_int33fe_probe(struct platform_device *pdev) 259 + int cht_int33fe_typec_probe(struct cht_int33fe_data *data) 250 260 { 251 - struct device *dev = &pdev->dev; 261 + struct device *dev = data->dev; 252 262 struct i2c_board_info board_info; 253 - struct cht_int33fe_data *data; 254 263 struct fwnode_handle *fwnode; 255 264 struct regulator *regulator; 256 - unsigned long long ptyp; 257 - acpi_status status; 258 265 int fusb302_irq; 259 266 int ret; 260 - 261 - status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp); 262 - if (ACPI_FAILURE(status)) { 263 - dev_err(dev, "Error getting PTYPE\n"); 264 - return -ENODEV; 265 - } 266 - 267 - /* 268 - * The same ACPI HID is used for different configurations check PTYP 269 - * to ensure that we are dealing with the expected config. 270 - */ 271 - if (ptyp != EXPECTED_PTYPE) 272 - return -ENODEV; 273 - 274 - /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */ 275 - if (!acpi_dev_present("INT34D3", "1", 3)) { 276 - dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n", 277 - EXPECTED_PTYPE); 278 - return -ENODEV; 279 - } 280 267 281 268 /* 282 269 * We expect the WC PMIC to be paired with a TI bq24292i charger-IC. ··· 283 316 dev_err(dev, "Error getting FUSB302 irq\n"); 284 317 return fusb302_irq; 285 318 } 286 - 287 - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 288 - if (!data) 289 - return -ENOMEM; 290 319 291 320 ret = cht_int33fe_add_nodes(data); 292 321 if (ret) ··· 328 365 goto out_unregister_fusb302; 329 366 } 330 367 331 - platform_set_drvdata(pdev, data); 332 - 333 368 return 0; 334 369 335 370 out_unregister_fusb302: 336 371 i2c_unregister_device(data->fusb302); 337 372 338 373 out_unregister_max17047: 339 - i2c_unregister_device(data->max17047); 374 + i2c_unregister_device(data->battery_fg); 340 375 341 376 out_remove_nodes: 342 377 cht_int33fe_remove_nodes(data); ··· 342 381 return ret; 343 382 } 344 383 345 - static int cht_int33fe_remove(struct platform_device *pdev) 384 + int cht_int33fe_typec_remove(struct cht_int33fe_data *data) 346 385 { 347 - struct cht_int33fe_data *data = platform_get_drvdata(pdev); 348 - 349 386 i2c_unregister_device(data->pi3usb30532); 350 387 i2c_unregister_device(data->fusb302); 351 - i2c_unregister_device(data->max17047); 388 + i2c_unregister_device(data->battery_fg); 352 389 353 390 cht_int33fe_remove_nodes(data); 354 391 355 392 return 0; 356 393 } 357 - 358 - static const struct acpi_device_id cht_int33fe_acpi_ids[] = { 359 - { "INT33FE", }, 360 - { } 361 - }; 362 - MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids); 363 - 364 - static struct platform_driver cht_int33fe_driver = { 365 - .driver = { 366 - .name = "Intel Cherry Trail ACPI INT33FE driver", 367 - .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), 368 - }, 369 - .probe = cht_int33fe_probe, 370 - .remove = cht_int33fe_remove, 371 - }; 372 - 373 - module_platform_driver(cht_int33fe_driver); 374 - 375 - MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver"); 376 - MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 377 - MODULE_LICENSE("GPL v2");
+147
drivers/platform/x86/intel_cht_int33fe_common.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Common code for Intel Cherry Trail ACPI INT33FE pseudo device drivers 4 + * (USB Micro-B and Type-C connector variants). 5 + * 6 + * Copyright (c) 2019 Yauhen Kharuzhy <jekhor@gmail.com> 7 + */ 8 + 9 + #include <linux/acpi.h> 10 + #include <linux/i2c.h> 11 + #include <linux/module.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/slab.h> 14 + 15 + #include "intel_cht_int33fe_common.h" 16 + 17 + #define EXPECTED_PTYPE 4 18 + 19 + static int cht_int33fe_i2c_res_filter(struct acpi_resource *ares, void *data) 20 + { 21 + struct acpi_resource_i2c_serialbus *sb; 22 + int *count = data; 23 + 24 + if (i2c_acpi_get_i2c_resource(ares, &sb)) 25 + (*count)++; 26 + 27 + return 1; 28 + } 29 + 30 + static int cht_int33fe_count_i2c_clients(struct device *dev) 31 + { 32 + struct acpi_device *adev; 33 + LIST_HEAD(resource_list); 34 + int count = 0; 35 + 36 + adev = ACPI_COMPANION(dev); 37 + if (!adev) 38 + return -EINVAL; 39 + 40 + acpi_dev_get_resources(adev, &resource_list, 41 + cht_int33fe_i2c_res_filter, &count); 42 + 43 + acpi_dev_free_resource_list(&resource_list); 44 + 45 + return count; 46 + } 47 + 48 + static int cht_int33fe_check_hw_type(struct device *dev) 49 + { 50 + unsigned long long ptyp; 51 + acpi_status status; 52 + int ret; 53 + 54 + status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp); 55 + if (ACPI_FAILURE(status)) { 56 + dev_err(dev, "Error getting PTYPE\n"); 57 + return -ENODEV; 58 + } 59 + 60 + /* 61 + * The same ACPI HID is used for different configurations check PTYP 62 + * to ensure that we are dealing with the expected config. 63 + */ 64 + if (ptyp != EXPECTED_PTYPE) 65 + return -ENODEV; 66 + 67 + /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */ 68 + if (!acpi_dev_present("INT34D3", "1", 3)) { 69 + dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n", 70 + EXPECTED_PTYPE); 71 + return -ENODEV; 72 + } 73 + 74 + ret = cht_int33fe_count_i2c_clients(dev); 75 + if (ret < 0) 76 + return ret; 77 + 78 + switch (ret) { 79 + case 2: 80 + return INT33FE_HW_MICROB; 81 + case 4: 82 + return INT33FE_HW_TYPEC; 83 + default: 84 + return -ENODEV; 85 + } 86 + } 87 + 88 + static int cht_int33fe_probe(struct platform_device *pdev) 89 + { 90 + struct cht_int33fe_data *data; 91 + struct device *dev = &pdev->dev; 92 + int ret; 93 + 94 + ret = cht_int33fe_check_hw_type(dev); 95 + if (ret < 0) 96 + return ret; 97 + 98 + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 99 + if (!data) 100 + return -ENOMEM; 101 + 102 + data->dev = dev; 103 + 104 + switch (ret) { 105 + case INT33FE_HW_MICROB: 106 + data->probe = cht_int33fe_microb_probe; 107 + data->remove = cht_int33fe_microb_remove; 108 + break; 109 + 110 + case INT33FE_HW_TYPEC: 111 + data->probe = cht_int33fe_typec_probe; 112 + data->remove = cht_int33fe_typec_remove; 113 + break; 114 + } 115 + 116 + platform_set_drvdata(pdev, data); 117 + 118 + return data->probe(data); 119 + } 120 + 121 + static int cht_int33fe_remove(struct platform_device *pdev) 122 + { 123 + struct cht_int33fe_data *data = platform_get_drvdata(pdev); 124 + 125 + return data->remove(data); 126 + } 127 + 128 + static const struct acpi_device_id cht_int33fe_acpi_ids[] = { 129 + { "INT33FE", }, 130 + { } 131 + }; 132 + MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids); 133 + 134 + static struct platform_driver cht_int33fe_driver = { 135 + .driver = { 136 + .name = "Intel Cherry Trail ACPI INT33FE driver", 137 + .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), 138 + }, 139 + .probe = cht_int33fe_probe, 140 + .remove = cht_int33fe_remove, 141 + }; 142 + 143 + module_platform_driver(cht_int33fe_driver); 144 + 145 + MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver"); 146 + MODULE_AUTHOR("Yauhen Kharuzhy <jekhor@gmail.com>"); 147 + MODULE_LICENSE("GPL v2");
+41
drivers/platform/x86/intel_cht_int33fe_common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Common code for Intel Cherry Trail ACPI INT33FE pseudo device drivers 4 + * (USB Micro-B and Type-C connector variants), header file 5 + * 6 + * Copyright (c) 2019 Yauhen Kharuzhy <jekhor@gmail.com> 7 + */ 8 + 9 + #ifndef _INTEL_CHT_INT33FE_COMMON_H 10 + #define _INTEL_CHT_INT33FE_COMMON_H 11 + 12 + #include <linux/device.h> 13 + #include <linux/fwnode.h> 14 + #include <linux/i2c.h> 15 + 16 + enum int33fe_hw_type { 17 + INT33FE_HW_MICROB, 18 + INT33FE_HW_TYPEC, 19 + }; 20 + 21 + struct cht_int33fe_data { 22 + struct device *dev; 23 + 24 + int (*probe)(struct cht_int33fe_data *data); 25 + int (*remove)(struct cht_int33fe_data *data); 26 + 27 + struct i2c_client *battery_fg; 28 + 29 + /* Type-C only */ 30 + struct i2c_client *fusb302; 31 + struct i2c_client *pi3usb30532; 32 + 33 + struct fwnode_handle *dp; 34 + }; 35 + 36 + int cht_int33fe_microb_probe(struct cht_int33fe_data *data); 37 + int cht_int33fe_microb_remove(struct cht_int33fe_data *data); 38 + int cht_int33fe_typec_probe(struct cht_int33fe_data *data); 39 + int cht_int33fe_typec_remove(struct cht_int33fe_data *data); 40 + 41 + #endif /* _INTEL_CHT_INT33FE_COMMON_H */
+57
drivers/platform/x86/intel_cht_int33fe_microb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Cherry Trail ACPI INT33FE pseudo device driver for devices with 4 + * USB Micro-B connector (e.g. without of FUSB302 USB Type-C controller) 5 + * 6 + * Copyright (C) 2019 Yauhen Kharuzhy <jekhor@gmail.com> 7 + * 8 + * At least one Intel Cherry Trail based device which ship with Windows 10 9 + * (Lenovo YogaBook YB1-X91L/F tablet), have this weird INT33FE ACPI device 10 + * with a CRS table with 2 I2cSerialBusV2 resources, for 2 different chips 11 + * attached to various i2c busses: 12 + * 1. The Whiskey Cove PMIC, which is also described by the INT34D3 ACPI device 13 + * 2. TI BQ27542 Fuel Gauge Controller 14 + * 15 + * So this driver is a stub / pseudo driver whose only purpose is to 16 + * instantiate i2c-client for battery fuel gauge, so that standard i2c driver 17 + * for these chip can bind to the it. 18 + */ 19 + 20 + #include <linux/acpi.h> 21 + #include <linux/i2c.h> 22 + #include <linux/module.h> 23 + #include <linux/pci.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/regulator/consumer.h> 26 + #include <linux/slab.h> 27 + #include <linux/usb/pd.h> 28 + 29 + #include "intel_cht_int33fe_common.h" 30 + 31 + static const char * const bq27xxx_suppliers[] = { "bq25890-charger" }; 32 + 33 + static const struct property_entry bq27xxx_props[] = { 34 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq27xxx_suppliers), 35 + { } 36 + }; 37 + 38 + int cht_int33fe_microb_probe(struct cht_int33fe_data *data) 39 + { 40 + struct device *dev = data->dev; 41 + struct i2c_board_info board_info; 42 + 43 + memset(&board_info, 0, sizeof(board_info)); 44 + strscpy(board_info.type, "bq27542", ARRAY_SIZE(board_info.type)); 45 + board_info.dev_name = "bq27542"; 46 + board_info.properties = bq27xxx_props; 47 + data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); 48 + 49 + return PTR_ERR_OR_ZERO(data->battery_fg); 50 + } 51 + 52 + int cht_int33fe_microb_remove(struct cht_int33fe_data *data) 53 + { 54 + i2c_unregister_device(data->battery_fg); 55 + 56 + return 0; 57 + }
+14 -14
drivers/platform/x86/intel_int0002_vgpio.c
··· 164 164 { 165 165 struct device *dev = &pdev->dev; 166 166 const struct x86_cpu_id *cpu_id; 167 - struct irq_chip *irq_chip; 168 167 struct gpio_chip *chip; 168 + struct gpio_irq_chip *girq; 169 169 int irq, ret; 170 170 171 171 /* Menlow has a different INT0002 device? <sigh> */ ··· 192 192 chip->ngpio = GPE0A_PME_B0_VIRT_GPIO_PIN + 1; 193 193 chip->irq.init_valid_mask = int0002_init_irq_valid_mask; 194 194 195 - ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL); 196 - if (ret) { 197 - dev_err(dev, "Error adding gpio chip: %d\n", ret); 198 - return ret; 199 - } 200 - 201 195 /* 202 - * We manually request the irq here instead of passing a flow-handler 196 + * We directly request the irq here instead of passing a flow-handler 203 197 * to gpiochip_set_chained_irqchip, because the irq is shared. 198 + * FIXME: augment this if we managed to pull handling of shared 199 + * IRQs into gpiolib. 204 200 */ 205 201 ret = devm_request_irq(dev, irq, int0002_irq, 206 202 IRQF_SHARED, "INT0002", chip); ··· 205 209 return ret; 206 210 } 207 211 208 - irq_chip = (struct irq_chip *)cpu_id->driver_data; 212 + girq = &chip->irq; 213 + girq->chip = (struct irq_chip *)cpu_id->driver_data; 214 + /* This let us handle the parent IRQ in the driver */ 215 + girq->parent_handler = NULL; 216 + girq->num_parents = 0; 217 + girq->parents = NULL; 218 + girq->default_type = IRQ_TYPE_NONE; 219 + girq->handler = handle_edge_irq; 209 220 210 - ret = gpiochip_irqchip_add(chip, irq_chip, 0, handle_edge_irq, 211 - IRQ_TYPE_NONE); 221 + ret = devm_gpiochip_add_data(dev, chip, NULL); 212 222 if (ret) { 213 - dev_err(dev, "Error adding irqchip: %d\n", ret); 223 + dev_err(dev, "Error adding gpio chip: %d\n", ret); 214 224 return ret; 215 225 } 216 - 217 - gpiochip_set_chained_irqchip(chip, irq_chip, irq, NULL); 218 226 219 227 device_init_wakeup(dev, true); 220 228 return 0;
+10 -7
drivers/platform/x86/intel_pmc_core.c
··· 158 158 .pm_vric1_offset = SPT_PMC_VRIC1_OFFSET, 159 159 }; 160 160 161 - /* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */ 161 + /* Cannon Lake: PGD PFET Enable Ack Status Register(s) bitmap */ 162 162 static const struct pmc_bit_map cnp_pfear_map[] = { 163 + /* Reserved for Cannon Lake but valid for Comet Lake */ 163 164 {"PMC", BIT(0)}, 164 165 {"OPI-DMI", BIT(1)}, 165 166 {"SPI/eSPI", BIT(2)}, ··· 186 185 {"SDX", BIT(4)}, 187 186 {"SPE", BIT(5)}, 188 187 {"Fuse", BIT(6)}, 189 - /* Reserved for Cannonlake but valid for Icelake */ 188 + /* Reserved for Cannon Lake but valid for Ice Lake and Comet Lake */ 190 189 {"SBR8", BIT(7)}, 191 190 192 191 {"CSME_FSC", BIT(0)}, ··· 230 229 {"HDA_PGD4", BIT(2)}, 231 230 {"HDA_PGD5", BIT(3)}, 232 231 {"HDA_PGD6", BIT(4)}, 233 - /* Reserved for Cannonlake but valid for Icelake */ 232 + /* Reserved for Cannon Lake but valid for Ice Lake and Comet Lake */ 234 233 {"PSF6", BIT(5)}, 235 234 {"PSF7", BIT(6)}, 236 235 {"PSF8", BIT(7)}, 237 236 238 - /* Icelake generation onwards only */ 237 + /* Ice Lake generation onwards only */ 239 238 {"RES_65", BIT(0)}, 240 239 {"RES_66", BIT(1)}, 241 240 {"RES_67", BIT(2)}, ··· 325 324 {"ISH", CNP_PMC_LTR_ISH}, 326 325 {"UFSX2", CNP_PMC_LTR_UFSX2}, 327 326 {"EMMC", CNP_PMC_LTR_EMMC}, 328 - /* Reserved for Cannonlake but valid for Icelake */ 327 + /* Reserved for Cannon Lake but valid for Ice Lake */ 329 328 {"WIGIG", ICL_PMC_LTR_WIGIG}, 330 329 /* Below two cannot be used for LTR_IGNORE */ 331 330 {"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT}, ··· 814 813 INTEL_CPU_FAM6(CANNONLAKE_L, cnp_reg_map), 815 814 INTEL_CPU_FAM6(ICELAKE_L, icl_reg_map), 816 815 INTEL_CPU_FAM6(ICELAKE_NNPI, icl_reg_map), 816 + INTEL_CPU_FAM6(COMETLAKE, cnp_reg_map), 817 + INTEL_CPU_FAM6(COMETLAKE_L, cnp_reg_map), 817 818 {} 818 819 }; 819 820 ··· 874 871 pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data; 875 872 876 873 /* 877 - * Coffeelake has CPU ID of Kabylake and Cannonlake PCH. So here 878 - * Sunrisepoint PCH regmap can't be used. Use Cannonlake PCH regmap 874 + * Coffee Lake has CPU ID of Kaby Lake and Cannon Lake PCH. So here 875 + * Sunrisepoint PCH regmap can't be used. Use Cannon Lake PCH regmap 879 876 * in this case. 880 877 */ 881 878 if (pmcdev->map == &spt_reg_map && !pci_dev_present(pmc_pci_ids))
+16 -32
drivers/platform/x86/intel_punit_ipc.c
··· 224 224 225 225 static int intel_punit_get_bars(struct platform_device *pdev) 226 226 { 227 - struct resource *res; 228 227 void __iomem *addr; 229 228 230 229 /* ··· 231 232 * - BIOS_IPC BASE_DATA 232 233 * - BIOS_IPC BASE_IFACE 233 234 */ 234 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 235 - addr = devm_ioremap_resource(&pdev->dev, res); 235 + addr = devm_platform_ioremap_resource(pdev, 0); 236 236 if (IS_ERR(addr)) 237 237 return PTR_ERR(addr); 238 238 punit_ipcdev->base[BIOS_IPC][BASE_DATA] = addr; 239 239 240 - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 241 - addr = devm_ioremap_resource(&pdev->dev, res); 240 + addr = devm_platform_ioremap_resource(pdev, 1); 242 241 if (IS_ERR(addr)) 243 242 return PTR_ERR(addr); 244 243 punit_ipcdev->base[BIOS_IPC][BASE_IFACE] = addr; ··· 248 251 * - GTDRIVER_IPC BASE_DATA 249 252 * - GTDRIVER_IPC BASE_IFACE 250 253 */ 251 - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 252 - if (res) { 253 - addr = devm_ioremap_resource(&pdev->dev, res); 254 - if (!IS_ERR(addr)) 255 - punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr; 256 - } 254 + addr = devm_platform_ioremap_resource(pdev, 2); 255 + if (!IS_ERR(addr)) 256 + punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr; 257 257 258 - res = platform_get_resource(pdev, IORESOURCE_MEM, 3); 259 - if (res) { 260 - addr = devm_ioremap_resource(&pdev->dev, res); 261 - if (!IS_ERR(addr)) 262 - punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr; 263 - } 258 + addr = devm_platform_ioremap_resource(pdev, 3); 259 + if (!IS_ERR(addr)) 260 + punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr; 264 261 265 - res = platform_get_resource(pdev, IORESOURCE_MEM, 4); 266 - if (res) { 267 - addr = devm_ioremap_resource(&pdev->dev, res); 268 - if (!IS_ERR(addr)) 269 - punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr; 270 - } 262 + addr = devm_platform_ioremap_resource(pdev, 4); 263 + if (!IS_ERR(addr)) 264 + punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr; 271 265 272 - res = platform_get_resource(pdev, IORESOURCE_MEM, 5); 273 - if (res) { 274 - addr = devm_ioremap_resource(&pdev->dev, res); 275 - if (!IS_ERR(addr)) 276 - punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr; 277 - } 266 + addr = devm_platform_ioremap_resource(pdev, 5); 267 + if (!IS_ERR(addr)) 268 + punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr; 278 269 279 270 return 0; 280 271 } ··· 294 309 295 310 ret = intel_punit_get_bars(pdev); 296 311 if (ret) 297 - goto out; 312 + return ret; 298 313 299 314 punit_ipcdev->dev = &pdev->dev; 300 315 mutex_init(&punit_ipcdev->lock); 301 316 init_completion(&punit_ipcdev->cmd_complete); 302 317 303 - out: 304 - return ret; 318 + return 0; 305 319 } 306 320 307 321 static int intel_punit_ipc_remove(struct platform_device *pdev)
+42 -24
drivers/platform/x86/peaq-wmi.c
··· 6 6 7 7 #include <linux/acpi.h> 8 8 #include <linux/dmi.h> 9 - #include <linux/input-polldev.h> 9 + #include <linux/input.h> 10 10 #include <linux/kernel.h> 11 11 #include <linux/module.h> 12 12 ··· 18 18 19 19 MODULE_ALIAS("wmi:"PEAQ_DOLBY_BUTTON_GUID); 20 20 21 - static unsigned int peaq_ignore_events_counter; 22 - static struct input_polled_dev *peaq_poll_dev; 21 + static struct input_dev *peaq_poll_dev; 23 22 24 23 /* 25 24 * The Dolby button (yes really a Dolby button) causes an ACPI variable to get ··· 27 28 * (if polling after the release) or twice (polling between press and release). 28 29 * We ignore events for 0.5s after the first event to avoid reporting 2 presses. 29 30 */ 30 - static void peaq_wmi_poll(struct input_polled_dev *dev) 31 + static void peaq_wmi_poll(struct input_dev *input_dev) 31 32 { 33 + static unsigned long last_event_time; 34 + static bool had_events; 32 35 union acpi_object obj; 33 36 acpi_status status; 34 37 u32 dummy = 0; ··· 45 44 return; 46 45 47 46 if (obj.type != ACPI_TYPE_INTEGER) { 48 - dev_err(&peaq_poll_dev->input->dev, 47 + dev_err(&input_dev->dev, 49 48 "Error WMBC did not return an integer\n"); 50 49 return; 51 50 } 52 51 53 - if (peaq_ignore_events_counter && peaq_ignore_events_counter--) 52 + if (!obj.integer.value) 54 53 return; 55 54 56 - if (obj.integer.value) { 57 - input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 1); 58 - input_sync(peaq_poll_dev->input); 59 - input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 0); 60 - input_sync(peaq_poll_dev->input); 61 - peaq_ignore_events_counter = max(1u, 62 - PEAQ_POLL_IGNORE_MS / peaq_poll_dev->poll_interval); 63 - } 55 + if (had_events && time_before(jiffies, last_event_time + 56 + msecs_to_jiffies(PEAQ_POLL_IGNORE_MS))) 57 + return; 58 + 59 + input_event(input_dev, EV_KEY, KEY_SOUND, 1); 60 + input_sync(input_dev); 61 + input_event(input_dev, EV_KEY, KEY_SOUND, 0); 62 + input_sync(input_dev); 63 + 64 + last_event_time = jiffies; 65 + had_events = true; 64 66 } 65 67 66 68 /* Some other devices (Shuttle XS35) use the same WMI GUID for other purposes */ ··· 79 75 80 76 static int __init peaq_wmi_init(void) 81 77 { 78 + int err; 79 + 82 80 /* WMI GUID is not unique, also check for a DMI match */ 83 81 if (!dmi_check_system(peaq_dmi_table)) 84 82 return -ENODEV; ··· 88 82 if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) 89 83 return -ENODEV; 90 84 91 - peaq_poll_dev = input_allocate_polled_device(); 85 + peaq_poll_dev = input_allocate_device(); 92 86 if (!peaq_poll_dev) 93 87 return -ENOMEM; 94 88 95 - peaq_poll_dev->poll = peaq_wmi_poll; 96 - peaq_poll_dev->poll_interval = PEAQ_POLL_INTERVAL_MS; 97 - peaq_poll_dev->poll_interval_max = PEAQ_POLL_MAX_MS; 98 - peaq_poll_dev->input->name = "PEAQ WMI hotkeys"; 99 - peaq_poll_dev->input->phys = "wmi/input0"; 100 - peaq_poll_dev->input->id.bustype = BUS_HOST; 101 - input_set_capability(peaq_poll_dev->input, EV_KEY, KEY_SOUND); 89 + peaq_poll_dev->name = "PEAQ WMI hotkeys"; 90 + peaq_poll_dev->phys = "wmi/input0"; 91 + peaq_poll_dev->id.bustype = BUS_HOST; 92 + input_set_capability(peaq_poll_dev, EV_KEY, KEY_SOUND); 102 93 103 - return input_register_polled_device(peaq_poll_dev); 94 + err = input_setup_polling(peaq_poll_dev, peaq_wmi_poll); 95 + if (err) 96 + goto err_out; 97 + 98 + input_set_poll_interval(peaq_poll_dev, PEAQ_POLL_INTERVAL_MS); 99 + input_set_max_poll_interval(peaq_poll_dev, PEAQ_POLL_MAX_MS); 100 + 101 + err = input_register_device(peaq_poll_dev); 102 + if (err) 103 + goto err_out; 104 + 105 + return 0; 106 + 107 + err_out: 108 + input_free_device(peaq_poll_dev); 109 + return err; 104 110 } 105 111 106 112 static void __exit peaq_wmi_exit(void) 107 113 { 108 - input_unregister_polled_device(peaq_poll_dev); 114 + input_unregister_device(peaq_poll_dev); 109 115 } 110 116 111 117 module_init(peaq_wmi_init);
+384
drivers/platform/x86/system76_acpi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * System76 ACPI Driver 4 + * 5 + * Copyright (C) 2019 System76 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/acpi.h> 13 + #include <linux/init.h> 14 + #include <linux/kernel.h> 15 + #include <linux/leds.h> 16 + #include <linux/module.h> 17 + #include <linux/pci_ids.h> 18 + #include <linux/types.h> 19 + 20 + struct system76_data { 21 + struct acpi_device *acpi_dev; 22 + struct led_classdev ap_led; 23 + struct led_classdev kb_led; 24 + enum led_brightness kb_brightness; 25 + enum led_brightness kb_toggle_brightness; 26 + int kb_color; 27 + }; 28 + 29 + static const struct acpi_device_id device_ids[] = { 30 + {"17761776", 0}, 31 + {"", 0}, 32 + }; 33 + MODULE_DEVICE_TABLE(acpi, device_ids); 34 + 35 + // Array of keyboard LED brightness levels 36 + static const enum led_brightness kb_levels[] = { 37 + 48, 38 + 72, 39 + 96, 40 + 144, 41 + 192, 42 + 255 43 + }; 44 + 45 + // Array of keyboard LED colors in 24-bit RGB format 46 + static const int kb_colors[] = { 47 + 0xFFFFFF, 48 + 0x0000FF, 49 + 0xFF0000, 50 + 0xFF00FF, 51 + 0x00FF00, 52 + 0x00FFFF, 53 + 0xFFFF00 54 + }; 55 + 56 + // Get a System76 ACPI device value by name 57 + static int system76_get(struct system76_data *data, char *method) 58 + { 59 + acpi_handle handle; 60 + acpi_status status; 61 + unsigned long long ret = 0; 62 + 63 + handle = acpi_device_handle(data->acpi_dev); 64 + status = acpi_evaluate_integer(handle, method, NULL, &ret); 65 + if (ACPI_SUCCESS(status)) 66 + return (int)ret; 67 + else 68 + return -1; 69 + } 70 + 71 + // Set a System76 ACPI device value by name 72 + static int system76_set(struct system76_data *data, char *method, int value) 73 + { 74 + union acpi_object obj; 75 + struct acpi_object_list obj_list; 76 + acpi_handle handle; 77 + acpi_status status; 78 + 79 + obj.type = ACPI_TYPE_INTEGER; 80 + obj.integer.value = value; 81 + obj_list.count = 1; 82 + obj_list.pointer = &obj; 83 + handle = acpi_device_handle(data->acpi_dev); 84 + status = acpi_evaluate_object(handle, method, &obj_list, NULL); 85 + if (ACPI_SUCCESS(status)) 86 + return 0; 87 + else 88 + return -1; 89 + } 90 + 91 + // Get the airplane mode LED brightness 92 + static enum led_brightness ap_led_get(struct led_classdev *led) 93 + { 94 + struct system76_data *data; 95 + int value; 96 + 97 + data = container_of(led, struct system76_data, ap_led); 98 + value = system76_get(data, "GAPL"); 99 + if (value > 0) 100 + return (enum led_brightness)value; 101 + else 102 + return LED_OFF; 103 + } 104 + 105 + // Set the airplane mode LED brightness 106 + static void ap_led_set(struct led_classdev *led, enum led_brightness value) 107 + { 108 + struct system76_data *data; 109 + 110 + data = container_of(led, struct system76_data, ap_led); 111 + system76_set(data, "SAPL", value == LED_OFF ? 0 : 1); 112 + } 113 + 114 + // Get the last set keyboard LED brightness 115 + static enum led_brightness kb_led_get(struct led_classdev *led) 116 + { 117 + struct system76_data *data; 118 + 119 + data = container_of(led, struct system76_data, kb_led); 120 + return data->kb_brightness; 121 + } 122 + 123 + // Set the keyboard LED brightness 124 + static void kb_led_set(struct led_classdev *led, enum led_brightness value) 125 + { 126 + struct system76_data *data; 127 + 128 + data = container_of(led, struct system76_data, kb_led); 129 + data->kb_brightness = value; 130 + system76_set(data, "SKBL", (int)data->kb_brightness); 131 + } 132 + 133 + // Get the last set keyboard LED color 134 + static ssize_t kb_led_color_show( 135 + struct device *dev, 136 + struct device_attribute *dev_attr, 137 + char *buf) 138 + { 139 + struct led_classdev *led; 140 + struct system76_data *data; 141 + 142 + led = (struct led_classdev *)dev->driver_data; 143 + data = container_of(led, struct system76_data, kb_led); 144 + return sprintf(buf, "%06X\n", data->kb_color); 145 + } 146 + 147 + // Set the keyboard LED color 148 + static ssize_t kb_led_color_store( 149 + struct device *dev, 150 + struct device_attribute *dev_attr, 151 + const char *buf, 152 + size_t size) 153 + { 154 + struct led_classdev *led; 155 + struct system76_data *data; 156 + unsigned int val; 157 + int ret; 158 + 159 + led = (struct led_classdev *)dev->driver_data; 160 + data = container_of(led, struct system76_data, kb_led); 161 + ret = kstrtouint(buf, 16, &val); 162 + if (ret) 163 + return ret; 164 + if (val > 0xFFFFFF) 165 + return -EINVAL; 166 + data->kb_color = (int)val; 167 + system76_set(data, "SKBC", data->kb_color); 168 + 169 + return size; 170 + } 171 + 172 + static const struct device_attribute kb_led_color_dev_attr = { 173 + .attr = { 174 + .name = "color", 175 + .mode = 0644, 176 + }, 177 + .show = kb_led_color_show, 178 + .store = kb_led_color_store, 179 + }; 180 + 181 + // Notify that the keyboard LED was changed by hardware 182 + static void kb_led_notify(struct system76_data *data) 183 + { 184 + led_classdev_notify_brightness_hw_changed( 185 + &data->kb_led, 186 + data->kb_brightness 187 + ); 188 + } 189 + 190 + // Read keyboard LED brightness as set by hardware 191 + static void kb_led_hotkey_hardware(struct system76_data *data) 192 + { 193 + int value; 194 + 195 + value = system76_get(data, "GKBL"); 196 + if (value < 0) 197 + return; 198 + data->kb_brightness = value; 199 + kb_led_notify(data); 200 + } 201 + 202 + // Toggle the keyboard LED 203 + static void kb_led_hotkey_toggle(struct system76_data *data) 204 + { 205 + if (data->kb_brightness > 0) { 206 + data->kb_toggle_brightness = data->kb_brightness; 207 + kb_led_set(&data->kb_led, 0); 208 + } else { 209 + kb_led_set(&data->kb_led, data->kb_toggle_brightness); 210 + } 211 + kb_led_notify(data); 212 + } 213 + 214 + // Decrease the keyboard LED brightness 215 + static void kb_led_hotkey_down(struct system76_data *data) 216 + { 217 + int i; 218 + 219 + if (data->kb_brightness > 0) { 220 + for (i = ARRAY_SIZE(kb_levels); i > 0; i--) { 221 + if (kb_levels[i - 1] < data->kb_brightness) { 222 + kb_led_set(&data->kb_led, kb_levels[i - 1]); 223 + break; 224 + } 225 + } 226 + } else { 227 + kb_led_set(&data->kb_led, data->kb_toggle_brightness); 228 + } 229 + kb_led_notify(data); 230 + } 231 + 232 + // Increase the keyboard LED brightness 233 + static void kb_led_hotkey_up(struct system76_data *data) 234 + { 235 + int i; 236 + 237 + if (data->kb_brightness > 0) { 238 + for (i = 0; i < ARRAY_SIZE(kb_levels); i++) { 239 + if (kb_levels[i] > data->kb_brightness) { 240 + kb_led_set(&data->kb_led, kb_levels[i]); 241 + break; 242 + } 243 + } 244 + } else { 245 + kb_led_set(&data->kb_led, data->kb_toggle_brightness); 246 + } 247 + kb_led_notify(data); 248 + } 249 + 250 + // Cycle the keyboard LED color 251 + static void kb_led_hotkey_color(struct system76_data *data) 252 + { 253 + int i; 254 + 255 + if (data->kb_color < 0) 256 + return; 257 + if (data->kb_brightness > 0) { 258 + for (i = 0; i < ARRAY_SIZE(kb_colors); i++) { 259 + if (kb_colors[i] == data->kb_color) 260 + break; 261 + } 262 + i += 1; 263 + if (i >= ARRAY_SIZE(kb_colors)) 264 + i = 0; 265 + data->kb_color = kb_colors[i]; 266 + system76_set(data, "SKBC", data->kb_color); 267 + } else { 268 + kb_led_set(&data->kb_led, data->kb_toggle_brightness); 269 + } 270 + kb_led_notify(data); 271 + } 272 + 273 + // Handle ACPI notification 274 + static void system76_notify(struct acpi_device *acpi_dev, u32 event) 275 + { 276 + struct system76_data *data; 277 + 278 + data = acpi_driver_data(acpi_dev); 279 + switch (event) { 280 + case 0x80: 281 + kb_led_hotkey_hardware(data); 282 + break; 283 + case 0x81: 284 + kb_led_hotkey_toggle(data); 285 + break; 286 + case 0x82: 287 + kb_led_hotkey_down(data); 288 + break; 289 + case 0x83: 290 + kb_led_hotkey_up(data); 291 + break; 292 + case 0x84: 293 + kb_led_hotkey_color(data); 294 + break; 295 + } 296 + } 297 + 298 + // Add a System76 ACPI device 299 + static int system76_add(struct acpi_device *acpi_dev) 300 + { 301 + struct system76_data *data; 302 + int err; 303 + 304 + data = devm_kzalloc(&acpi_dev->dev, sizeof(*data), GFP_KERNEL); 305 + if (!data) 306 + return -ENOMEM; 307 + acpi_dev->driver_data = data; 308 + data->acpi_dev = acpi_dev; 309 + 310 + err = system76_get(data, "INIT"); 311 + if (err) 312 + return err; 313 + data->ap_led.name = "system76_acpi::airplane"; 314 + data->ap_led.flags = LED_CORE_SUSPENDRESUME; 315 + data->ap_led.brightness_get = ap_led_get; 316 + data->ap_led.brightness_set = ap_led_set; 317 + data->ap_led.max_brightness = 1; 318 + data->ap_led.default_trigger = "rfkill-none"; 319 + err = devm_led_classdev_register(&acpi_dev->dev, &data->ap_led); 320 + if (err) 321 + return err; 322 + 323 + data->kb_led.name = "system76_acpi::kbd_backlight"; 324 + data->kb_led.flags = LED_BRIGHT_HW_CHANGED | LED_CORE_SUSPENDRESUME; 325 + data->kb_led.brightness_get = kb_led_get; 326 + data->kb_led.brightness_set = kb_led_set; 327 + if (acpi_has_method(acpi_device_handle(data->acpi_dev), "SKBC")) { 328 + data->kb_led.max_brightness = 255; 329 + data->kb_toggle_brightness = 72; 330 + data->kb_color = 0xffffff; 331 + system76_set(data, "SKBC", data->kb_color); 332 + } else { 333 + data->kb_led.max_brightness = 5; 334 + data->kb_color = -1; 335 + } 336 + err = devm_led_classdev_register(&acpi_dev->dev, &data->kb_led); 337 + if (err) 338 + return err; 339 + 340 + if (data->kb_color >= 0) { 341 + err = device_create_file( 342 + data->kb_led.dev, 343 + &kb_led_color_dev_attr 344 + ); 345 + if (err) 346 + return err; 347 + } 348 + 349 + return 0; 350 + } 351 + 352 + // Remove a System76 ACPI device 353 + static int system76_remove(struct acpi_device *acpi_dev) 354 + { 355 + struct system76_data *data; 356 + 357 + data = acpi_driver_data(acpi_dev); 358 + if (data->kb_color >= 0) 359 + device_remove_file(data->kb_led.dev, &kb_led_color_dev_attr); 360 + 361 + devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led); 362 + 363 + devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led); 364 + 365 + system76_get(data, "FINI"); 366 + 367 + return 0; 368 + } 369 + 370 + static struct acpi_driver system76_driver = { 371 + .name = "System76 ACPI Driver", 372 + .class = "hotkey", 373 + .ids = device_ids, 374 + .ops = { 375 + .add = system76_add, 376 + .remove = system76_remove, 377 + .notify = system76_notify, 378 + }, 379 + }; 380 + module_acpi_driver(system76_driver); 381 + 382 + MODULE_DESCRIPTION("System76 ACPI Driver"); 383 + MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>"); 384 + MODULE_LICENSE("GPL");
+52
drivers/platform/x86/touchscreen_dmi.c
··· 310 310 .properties = jumper_ezpad_6_pro_b_props, 311 311 }; 312 312 313 + static const struct property_entry jumper_ezpad_6_m4_props[] = { 314 + PROPERTY_ENTRY_U32("touchscreen-min-x", 35), 315 + PROPERTY_ENTRY_U32("touchscreen-min-y", 15), 316 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1950), 317 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1525), 318 + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-m4.fw"), 319 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 320 + PROPERTY_ENTRY_BOOL("silead,home-button"), 321 + { } 322 + }; 323 + 324 + static const struct ts_dmi_data jumper_ezpad_6_m4_data = { 325 + .acpi_name = "MSSL1680:00", 326 + .properties = jumper_ezpad_6_m4_props, 327 + }; 328 + 313 329 static const struct property_entry jumper_ezpad_mini3_props[] = { 314 330 PROPERTY_ENTRY_U32("touchscreen-min-x", 23), 315 331 PROPERTY_ENTRY_U32("touchscreen-min-y", 16), ··· 512 496 static const struct ts_dmi_data pov_mobii_wintab_p1006w_v10_data = { 513 497 .acpi_name = "MSSL1680:00", 514 498 .properties = pov_mobii_wintab_p1006w_v10_props, 499 + }; 500 + 501 + static const struct property_entry schneider_sct101ctm_props[] = { 502 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1715), 503 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), 504 + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), 505 + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), 506 + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 507 + PROPERTY_ENTRY_STRING("firmware-name", 508 + "gsl1680-schneider-sct101ctm.fw"), 509 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 510 + PROPERTY_ENTRY_BOOL("silead,home-button"), 511 + { } 512 + }; 513 + 514 + static const struct ts_dmi_data schneider_sct101ctm_data = { 515 + .acpi_name = "MSSL1680:00", 516 + .properties = schneider_sct101ctm_props, 515 517 }; 516 518 517 519 static const struct property_entry teclast_x3_plus_props[] = { ··· 823 789 }, 824 790 }, 825 791 { 792 + /* Jumper EZpad 6 m4 */ 793 + .driver_data = (void *)&jumper_ezpad_6_m4_data, 794 + .matches = { 795 + DMI_MATCH(DMI_SYS_VENDOR, "jumper"), 796 + DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"), 797 + /* Jumper8.S106x.A00C.1066 with the version dropped */ 798 + DMI_MATCH(DMI_BIOS_VERSION, "Jumper8.S106x"), 799 + }, 800 + }, 801 + { 826 802 /* Jumper EZpad mini3 */ 827 803 .driver_data = (void *)&jumper_ezpad_mini3_data, 828 804 .matches = { ··· 950 906 /* Note 105b is Foxcon's USB/PCI vendor id */ 951 907 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), 952 908 DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), 909 + }, 910 + }, 911 + { 912 + /* Schneider SCT101CTM */ 913 + .driver_data = (void *)&schneider_sct101ctm_data, 914 + .matches = { 915 + DMI_MATCH(DMI_SYS_VENDOR, "Default string"), 916 + DMI_MATCH(DMI_PRODUCT_NAME, "SCT101CTM"), 953 917 }, 954 918 }, 955 919 {
+1 -1
drivers/thermal/gov_bang_bang.c
··· 2 2 /* 3 3 * gov_bang_bang.c - A simple thermal throttling governor using hysteresis 4 4 * 5 - * Copyright (C) 2014 Peter Feuerer <peter@piie.net> 5 + * Copyright (C) 2014 Peter Kaestle <peter@piie.net> 6 6 * 7 7 * Based on step_wise.c with following Copyrights: 8 8 * Copyright (C) 2012 Intel Corp
+831 -193
tools/power/x86/intel-speed-select/isst-config.c
··· 11 11 struct process_cmd_struct { 12 12 char *feature; 13 13 char *command; 14 - void (*process_fn)(void); 14 + void (*process_fn)(int arg); 15 + int arg; 15 16 }; 16 17 17 - static const char *version_str = "v1.0"; 18 + static const char *version_str = "v1.1"; 18 19 static const int supported_api_ver = 1; 19 20 static struct isst_if_platform_info isst_platform_info; 20 21 static char *progname; ··· 23 22 static FILE *outf; 24 23 25 24 static int cpu_model; 25 + static int cpu_stepping; 26 26 27 27 #define MAX_CPUS_IN_ONE_REQ 64 28 28 static short max_target_cpus; ··· 41 39 static int out_format_json; 42 40 static int cmd_help; 43 41 static int force_online_offline; 42 + static int auto_mode; 44 43 45 44 /* clos related */ 46 45 static int current_clos = -1; ··· 73 70 va_end(args); 74 71 } 75 72 76 - static void update_cpu_model(void) 73 + 74 + int is_clx_n_platform(void) 75 + { 76 + if (cpu_model == 0x55) 77 + if (cpu_stepping == 0x6 || cpu_stepping == 0x7) 78 + return 1; 79 + return 0; 80 + } 81 + 82 + static int update_cpu_model(void) 77 83 { 78 84 unsigned int ebx, ecx, edx; 79 85 unsigned int fms, family; ··· 92 80 cpu_model = (fms >> 4) & 0xf; 93 81 if (family == 6 || family == 0xf) 94 82 cpu_model += ((fms >> 16) & 0xf) << 4; 83 + 84 + cpu_stepping = fms & 0xf; 85 + /* only three CascadeLake-N models are supported */ 86 + if (is_clx_n_platform()) { 87 + FILE *fp; 88 + size_t n = 0; 89 + char *line = NULL; 90 + int ret = 1; 91 + 92 + fp = fopen("/proc/cpuinfo", "r"); 93 + if (!fp) 94 + err(-1, "cannot open /proc/cpuinfo\n"); 95 + 96 + while (getline(&line, &n, fp) > 0) { 97 + if (strstr(line, "model name")) { 98 + if (strstr(line, "6252N") || 99 + strstr(line, "6230N") || 100 + strstr(line, "5218N")) 101 + ret = 0; 102 + break; 103 + } 104 + } 105 + free(line); 106 + fclose(fp); 107 + return ret; 108 + } 109 + return 0; 95 110 } 96 111 97 112 /* Open a file, and exit on failure */ ··· 200 161 return ret; 201 162 } 202 163 164 + int get_cpufreq_base_freq(int cpu) 165 + { 166 + return parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", cpu); 167 + } 168 + 203 169 int get_topo_max_cpus(void) 204 170 { 205 171 return topo_max_cpus; ··· 213 169 static void set_cpu_online_offline(int cpu, int state) 214 170 { 215 171 char buffer[128]; 216 - int fd; 172 + int fd, ret; 217 173 218 174 snprintf(buffer, sizeof(buffer), 219 175 "/sys/devices/system/cpu/cpu%d/online", cpu); ··· 223 179 err(-1, "%s open failed", buffer); 224 180 225 181 if (state) 226 - write(fd, "1\n", 2); 182 + ret = write(fd, "1\n", 2); 227 183 else 228 - write(fd, "0\n", 2); 184 + ret = write(fd, "0\n", 2); 185 + 186 + if (ret == -1) 187 + perror("Online/Offline: Operation failed\n"); 229 188 230 189 close(fd); 231 190 } ··· 338 291 } 339 292 340 293 static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE]; 294 + static long long core_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE]; 341 295 static void set_cpu_present_cpu_mask(void) 342 296 { 343 297 size_t size; ··· 363 315 364 316 pkg_id = get_physical_package_id(i); 365 317 if (pkg_id < MAX_PACKAGE_COUNT && 366 - die_id < MAX_DIE_PER_PACKAGE) 318 + die_id < MAX_DIE_PER_PACKAGE) { 319 + int core_id = get_physical_core_id(i); 320 + 367 321 cpu_cnt[pkg_id][die_id]++; 322 + core_mask[pkg_id][die_id] |= (1ULL << core_id); 323 + } 368 324 } 369 325 closedir(dir); 370 326 } 327 + } 328 + 329 + int get_core_count(int pkg_id, int die_id) 330 + { 331 + int cnt = 0; 332 + 333 + if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE) { 334 + int i; 335 + 336 + for (i = 0; i < sizeof(long long) * 8; ++i) { 337 + if (core_mask[pkg_id][die_id] & (1ULL << i)) 338 + cnt++; 339 + } 340 + } 341 + 342 + return cnt; 371 343 } 372 344 373 345 int get_cpu_count(int pkg_id, int die_id) ··· 600 532 if (!ret && !write) 601 533 *resp = value; 602 534 break; 603 - case CLOS_PM_QOS_CONFIG: 604 - ret = isst_send_mmio_command(cpu, PM_QOS_CONFIG_OFFSET, 605 - write, &value); 606 - if (!ret && !write) 607 - *resp = value; 608 - break; 609 535 case CLOS_STATUS: 610 536 break; 611 537 default: ··· 624 562 fprintf(outf, 625 563 "Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n", 626 564 cpu, command, sub_command, parameter, req_data); 565 + return -1; 627 566 } else { 628 567 *resp = mbox_cmds.mbox_cmd[0].resp_data; 629 568 debug_printf( ··· 741 678 } 742 679 743 680 #define _get_tdp_level(desc, suffix, object, help) \ 744 - static void get_tdp_##object(void) \ 681 + static void get_tdp_##object(int arg) \ 745 682 { \ 746 683 struct isst_pkg_ctdp ctdp; \ 747 684 \ ··· 771 708 "Current TDP Level"); 772 709 _get_tdp_level("get-lock-status", levels, locked, "TDP lock status"); 773 710 711 + struct isst_pkg_ctdp clx_n_pkg_dev; 712 + 713 + static int clx_n_get_base_ratio(void) 714 + { 715 + FILE *fp; 716 + char *begin, *end, *line = NULL; 717 + char number[5]; 718 + float value = 0; 719 + size_t n = 0; 720 + 721 + fp = fopen("/proc/cpuinfo", "r"); 722 + if (!fp) 723 + err(-1, "cannot open /proc/cpuinfo\n"); 724 + 725 + while (getline(&line, &n, fp) > 0) { 726 + if (strstr(line, "model name")) { 727 + /* this is true for CascadeLake-N */ 728 + begin = strstr(line, "@ ") + 2; 729 + end = strstr(line, "GHz"); 730 + strncpy(number, begin, end - begin); 731 + value = atof(number) * 10; 732 + break; 733 + } 734 + } 735 + free(line); 736 + fclose(fp); 737 + 738 + return (int)(value); 739 + } 740 + 741 + static int clx_n_config(int cpu) 742 + { 743 + int i, ret, pkg_id, die_id; 744 + unsigned long cpu_bf; 745 + struct isst_pkg_ctdp_level_info *ctdp_level; 746 + struct isst_pbf_info *pbf_info; 747 + 748 + ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 749 + pbf_info = &ctdp_level->pbf_info; 750 + ctdp_level->core_cpumask_size = 751 + alloc_cpu_set(&ctdp_level->core_cpumask); 752 + 753 + /* find the frequency base ratio */ 754 + ctdp_level->tdp_ratio = clx_n_get_base_ratio(); 755 + if (ctdp_level->tdp_ratio == 0) { 756 + debug_printf("CLX: cn base ratio is zero\n"); 757 + ret = -1; 758 + goto error_ret; 759 + } 760 + 761 + /* find the high and low priority frequencies */ 762 + pbf_info->p1_high = 0; 763 + pbf_info->p1_low = ~0; 764 + 765 + pkg_id = get_physical_package_id(cpu); 766 + die_id = get_physical_die_id(cpu); 767 + 768 + for (i = 0; i < topo_max_cpus; i++) { 769 + if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) 770 + continue; 771 + 772 + if (pkg_id != get_physical_package_id(i) || 773 + die_id != get_physical_die_id(i)) 774 + continue; 775 + 776 + CPU_SET_S(i, ctdp_level->core_cpumask_size, 777 + ctdp_level->core_cpumask); 778 + 779 + cpu_bf = parse_int_file(1, 780 + "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", 781 + i); 782 + if (cpu_bf > pbf_info->p1_high) 783 + pbf_info->p1_high = cpu_bf; 784 + if (cpu_bf < pbf_info->p1_low) 785 + pbf_info->p1_low = cpu_bf; 786 + } 787 + 788 + if (pbf_info->p1_high == ~0UL) { 789 + debug_printf("CLX: maximum base frequency not set\n"); 790 + ret = -1; 791 + goto error_ret; 792 + } 793 + 794 + if (pbf_info->p1_low == 0) { 795 + debug_printf("CLX: minimum base frequency not set\n"); 796 + ret = -1; 797 + goto error_ret; 798 + } 799 + 800 + /* convert frequencies back to ratios */ 801 + pbf_info->p1_high = pbf_info->p1_high / 100000; 802 + pbf_info->p1_low = pbf_info->p1_low / 100000; 803 + 804 + /* create high priority cpu mask */ 805 + pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask); 806 + for (i = 0; i < topo_max_cpus; i++) { 807 + if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) 808 + continue; 809 + 810 + if (pkg_id != get_physical_package_id(i) || 811 + die_id != get_physical_die_id(i)) 812 + continue; 813 + 814 + cpu_bf = parse_int_file(1, 815 + "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", 816 + i); 817 + cpu_bf = cpu_bf / 100000; 818 + if (cpu_bf == pbf_info->p1_high) 819 + CPU_SET_S(i, pbf_info->core_cpumask_size, 820 + pbf_info->core_cpumask); 821 + } 822 + 823 + /* extra ctdp & pbf struct parameters */ 824 + ctdp_level->processed = 1; 825 + ctdp_level->pbf_support = 1; /* PBF is always supported and enabled */ 826 + ctdp_level->pbf_enabled = 1; 827 + ctdp_level->fact_support = 0; /* FACT is never supported */ 828 + ctdp_level->fact_enabled = 0; 829 + 830 + return 0; 831 + 832 + error_ret: 833 + free_cpu_set(ctdp_level->core_cpumask); 834 + return ret; 835 + } 836 + 837 + static void dump_clx_n_config_for_cpu(int cpu, void *arg1, void *arg2, 838 + void *arg3, void *arg4) 839 + { 840 + int ret; 841 + 842 + ret = clx_n_config(cpu); 843 + if (ret) { 844 + perror("isst_get_process_ctdp"); 845 + } else { 846 + struct isst_pkg_ctdp_level_info *ctdp_level; 847 + struct isst_pbf_info *pbf_info; 848 + 849 + ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 850 + pbf_info = &ctdp_level->pbf_info; 851 + isst_ctdp_display_information(cpu, outf, tdp_level, &clx_n_pkg_dev); 852 + free_cpu_set(ctdp_level->core_cpumask); 853 + free_cpu_set(pbf_info->core_cpumask); 854 + } 855 + } 856 + 774 857 static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2, 775 858 void *arg3, void *arg4) 776 859 { ··· 933 724 } 934 725 } 935 726 936 - static void dump_isst_config(void) 727 + static void dump_isst_config(int arg) 937 728 { 729 + void *fn; 730 + 938 731 if (cmd_help) { 939 732 fprintf(stderr, 940 733 "Print Intel(R) Speed Select Technology Performance profile configuration\n"); ··· 948 737 exit(0); 949 738 } 950 739 740 + if (!is_clx_n_platform()) 741 + fn = dump_isst_config_for_cpu; 742 + else 743 + fn = dump_clx_n_config_for_cpu; 744 + 951 745 isst_ctdp_display_information_start(outf); 952 746 953 747 if (max_target_cpus) 954 - for_each_online_target_cpu_in_set(dump_isst_config_for_cpu, 955 - NULL, NULL, NULL, NULL); 748 + for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL); 956 749 else 957 - for_each_online_package_in_set(dump_isst_config_for_cpu, NULL, 958 - NULL, NULL, NULL); 750 + for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL); 959 751 960 752 isst_ctdp_display_information_end(outf); 961 753 } ··· 1001 787 } 1002 788 } 1003 789 1004 - static void set_tdp_level(void) 790 + static void set_tdp_level(int arg) 1005 791 { 1006 792 if (cmd_help) { 1007 793 fprintf(stderr, "Set Config TDP level\n"); ··· 1026 812 isst_ctdp_display_information_end(outf); 1027 813 } 1028 814 815 + static void clx_n_dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, 816 + void *arg3, void *arg4) 817 + { 818 + int ret; 819 + 820 + ret = clx_n_config(cpu); 821 + if (ret) { 822 + perror("isst_get_process_ctdp"); 823 + } else { 824 + struct isst_pkg_ctdp_level_info *ctdp_level; 825 + struct isst_pbf_info *pbf_info; 826 + 827 + ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 828 + pbf_info = &ctdp_level->pbf_info; 829 + isst_pbf_display_information(cpu, outf, tdp_level, pbf_info); 830 + free_cpu_set(ctdp_level->core_cpumask); 831 + free_cpu_set(pbf_info->core_cpumask); 832 + } 833 + } 834 + 1029 835 static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 1030 836 void *arg4) 1031 837 { ··· 1061 827 } 1062 828 } 1063 829 1064 - static void dump_pbf_config(void) 830 + static void dump_pbf_config(int arg) 1065 831 { 832 + void *fn; 833 + 1066 834 if (cmd_help) { 1067 835 fprintf(stderr, 1068 836 "Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n"); ··· 1078 842 exit(1); 1079 843 } 1080 844 1081 - isst_ctdp_display_information_start(outf); 1082 - if (max_target_cpus) 1083 - for_each_online_target_cpu_in_set(dump_pbf_config_for_cpu, NULL, 1084 - NULL, NULL, NULL); 845 + if (!is_clx_n_platform()) 846 + fn = dump_pbf_config_for_cpu; 1085 847 else 1086 - for_each_online_package_in_set(dump_pbf_config_for_cpu, NULL, 1087 - NULL, NULL, NULL); 848 + fn = clx_n_dump_pbf_config_for_cpu; 849 + 850 + isst_ctdp_display_information_start(outf); 851 + 852 + if (max_target_cpus) 853 + for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL); 854 + else 855 + for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL); 856 + 1088 857 isst_ctdp_display_information_end(outf); 858 + } 859 + 860 + static int set_clos_param(int cpu, int clos, int epp, int wt, int min, int max) 861 + { 862 + struct isst_clos_config clos_config; 863 + int ret; 864 + 865 + ret = isst_pm_get_clos(cpu, clos, &clos_config); 866 + if (ret) { 867 + perror("isst_pm_get_clos"); 868 + return ret; 869 + } 870 + clos_config.clos_min = min; 871 + clos_config.clos_max = max; 872 + clos_config.epp = epp; 873 + clos_config.clos_prop_prio = wt; 874 + ret = isst_set_clos(cpu, clos, &clos_config); 875 + if (ret) { 876 + perror("isst_pm_set_clos"); 877 + return ret; 878 + } 879 + 880 + return 0; 881 + } 882 + 883 + static int set_cpufreq_scaling_min_max(int cpu, int max, int freq) 884 + { 885 + char buffer[128], freq_str[16]; 886 + int fd, ret, len; 887 + 888 + if (max) 889 + snprintf(buffer, sizeof(buffer), 890 + "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); 891 + else 892 + snprintf(buffer, sizeof(buffer), 893 + "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); 894 + 895 + fd = open(buffer, O_WRONLY); 896 + if (fd < 0) 897 + return fd; 898 + 899 + snprintf(freq_str, sizeof(freq_str), "%d", freq); 900 + len = strlen(freq_str); 901 + ret = write(fd, freq_str, len); 902 + if (ret == -1) { 903 + close(fd); 904 + return ret; 905 + } 906 + close(fd); 907 + 908 + return 0; 909 + } 910 + 911 + static int set_clx_pbf_cpufreq_scaling_min_max(int cpu) 912 + { 913 + struct isst_pkg_ctdp_level_info *ctdp_level; 914 + struct isst_pbf_info *pbf_info; 915 + int i, pkg_id, die_id, freq, freq_high, freq_low; 916 + int ret; 917 + 918 + ret = clx_n_config(cpu); 919 + if (ret) { 920 + perror("set_clx_pbf_cpufreq_scaling_min_max"); 921 + return ret; 922 + } 923 + 924 + ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 925 + pbf_info = &ctdp_level->pbf_info; 926 + freq_high = pbf_info->p1_high * 100000; 927 + freq_low = pbf_info->p1_low * 100000; 928 + 929 + pkg_id = get_physical_package_id(cpu); 930 + die_id = get_physical_die_id(cpu); 931 + for (i = 0; i < get_topo_max_cpus(); ++i) { 932 + if (pkg_id != get_physical_package_id(i) || 933 + die_id != get_physical_die_id(i)) 934 + continue; 935 + 936 + if (CPU_ISSET_S(i, pbf_info->core_cpumask_size, 937 + pbf_info->core_cpumask)) 938 + freq = freq_high; 939 + else 940 + freq = freq_low; 941 + 942 + set_cpufreq_scaling_min_max(i, 1, freq); 943 + set_cpufreq_scaling_min_max(i, 0, freq); 944 + } 945 + 946 + return 0; 947 + } 948 + 949 + static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, int scaling_max) 950 + { 951 + char buffer[128], min_freq[16]; 952 + int fd, ret, len; 953 + 954 + if (!CPU_ISSET_S(cpu, present_cpumask_size, present_cpumask)) 955 + return -1; 956 + 957 + if (cpuinfo_max) 958 + snprintf(buffer, sizeof(buffer), 959 + "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu); 960 + else 961 + snprintf(buffer, sizeof(buffer), 962 + "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpu); 963 + 964 + fd = open(buffer, O_RDONLY); 965 + if (fd < 0) 966 + return fd; 967 + 968 + len = read(fd, min_freq, sizeof(min_freq)); 969 + close(fd); 970 + 971 + if (len < 0) 972 + return len; 973 + 974 + if (scaling_max) 975 + snprintf(buffer, sizeof(buffer), 976 + "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); 977 + else 978 + snprintf(buffer, sizeof(buffer), 979 + "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); 980 + 981 + fd = open(buffer, O_WRONLY); 982 + if (fd < 0) 983 + return fd; 984 + 985 + len = strlen(min_freq); 986 + ret = write(fd, min_freq, len); 987 + if (ret == -1) { 988 + close(fd); 989 + return ret; 990 + } 991 + close(fd); 992 + 993 + return 0; 994 + } 995 + 996 + static void set_scaling_min_to_cpuinfo_max(int cpu) 997 + { 998 + int i, pkg_id, die_id; 999 + 1000 + pkg_id = get_physical_package_id(cpu); 1001 + die_id = get_physical_die_id(cpu); 1002 + for (i = 0; i < get_topo_max_cpus(); ++i) { 1003 + if (pkg_id != get_physical_package_id(i) || 1004 + die_id != get_physical_die_id(i)) 1005 + continue; 1006 + 1007 + set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0); 1008 + } 1009 + } 1010 + 1011 + static void set_scaling_min_to_cpuinfo_min(int cpu) 1012 + { 1013 + int i, pkg_id, die_id; 1014 + 1015 + pkg_id = get_physical_package_id(cpu); 1016 + die_id = get_physical_die_id(cpu); 1017 + for (i = 0; i < get_topo_max_cpus(); ++i) { 1018 + if (pkg_id != get_physical_package_id(i) || 1019 + die_id != get_physical_die_id(i)) 1020 + continue; 1021 + 1022 + set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0); 1023 + } 1024 + } 1025 + 1026 + static void set_scaling_max_to_cpuinfo_max(int cpu) 1027 + { 1028 + int i, pkg_id, die_id; 1029 + 1030 + pkg_id = get_physical_package_id(cpu); 1031 + die_id = get_physical_die_id(cpu); 1032 + for (i = 0; i < get_topo_max_cpus(); ++i) { 1033 + if (pkg_id != get_physical_package_id(i) || 1034 + die_id != get_physical_die_id(i)) 1035 + continue; 1036 + 1037 + set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1); 1038 + } 1039 + } 1040 + 1041 + static int set_core_priority_and_min(int cpu, int mask_size, 1042 + cpu_set_t *cpu_mask, int min_high, 1043 + int min_low) 1044 + { 1045 + int pkg_id, die_id, ret, i; 1046 + 1047 + if (!CPU_COUNT_S(mask_size, cpu_mask)) 1048 + return -1; 1049 + 1050 + ret = set_clos_param(cpu, 0, 0, 0, min_high, 0xff); 1051 + if (ret) 1052 + return ret; 1053 + 1054 + ret = set_clos_param(cpu, 1, 15, 15, min_low, 0xff); 1055 + if (ret) 1056 + return ret; 1057 + 1058 + ret = set_clos_param(cpu, 2, 15, 15, min_low, 0xff); 1059 + if (ret) 1060 + return ret; 1061 + 1062 + ret = set_clos_param(cpu, 3, 15, 15, min_low, 0xff); 1063 + if (ret) 1064 + return ret; 1065 + 1066 + pkg_id = get_physical_package_id(cpu); 1067 + die_id = get_physical_die_id(cpu); 1068 + for (i = 0; i < get_topo_max_cpus(); ++i) { 1069 + int clos; 1070 + 1071 + if (pkg_id != get_physical_package_id(i) || 1072 + die_id != get_physical_die_id(i)) 1073 + continue; 1074 + 1075 + if (CPU_ISSET_S(i, mask_size, cpu_mask)) 1076 + clos = 0; 1077 + else 1078 + clos = 3; 1079 + 1080 + debug_printf("Associate cpu: %d clos: %d\n", i, clos); 1081 + ret = isst_clos_associate(i, clos); 1082 + if (ret) { 1083 + perror("isst_clos_associate"); 1084 + return ret; 1085 + } 1086 + } 1087 + 1088 + return 0; 1089 + } 1090 + 1091 + static int set_pbf_core_power(int cpu) 1092 + { 1093 + struct isst_pbf_info pbf_info; 1094 + struct isst_pkg_ctdp pkg_dev; 1095 + int ret; 1096 + 1097 + ret = isst_get_ctdp_levels(cpu, &pkg_dev); 1098 + if (ret) { 1099 + perror("isst_get_ctdp_levels"); 1100 + return ret; 1101 + } 1102 + debug_printf("Current_level: %d\n", pkg_dev.current_level); 1103 + 1104 + ret = isst_get_pbf_info(cpu, pkg_dev.current_level, &pbf_info); 1105 + if (ret) { 1106 + perror("isst_get_pbf_info"); 1107 + return ret; 1108 + } 1109 + debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high, 1110 + pbf_info.p1_low); 1111 + 1112 + ret = set_core_priority_and_min(cpu, pbf_info.core_cpumask_size, 1113 + pbf_info.core_cpumask, 1114 + pbf_info.p1_high, pbf_info.p1_low); 1115 + if (ret) { 1116 + perror("set_core_priority_and_min"); 1117 + return ret; 1118 + } 1119 + 1120 + ret = isst_pm_qos_config(cpu, 1, 1); 1121 + if (ret) { 1122 + perror("isst_pm_qos_config"); 1123 + return ret; 1124 + } 1125 + 1126 + return 0; 1089 1127 } 1090 1128 1091 1129 static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, ··· 1368 858 int ret; 1369 859 int status = *(int *)arg4; 1370 860 861 + if (is_clx_n_platform()) { 862 + if (status) { 863 + ret = 0; 864 + if (auto_mode) 865 + set_clx_pbf_cpufreq_scaling_min_max(cpu); 866 + 867 + } else { 868 + ret = -1; 869 + if (auto_mode) { 870 + set_scaling_max_to_cpuinfo_max(cpu); 871 + set_scaling_min_to_cpuinfo_min(cpu); 872 + } 873 + } 874 + goto disp_result; 875 + } 876 + 877 + if (auto_mode) { 878 + if (status) { 879 + ret = set_pbf_core_power(cpu); 880 + if (ret) 881 + goto disp_result; 882 + } else { 883 + isst_pm_qos_config(cpu, 0, 0); 884 + } 885 + } 886 + 1371 887 ret = isst_set_pbf_fact_status(cpu, 1, status); 1372 888 if (ret) { 1373 889 perror("isst_set_pbf"); 890 + if (auto_mode) 891 + isst_pm_qos_config(cpu, 0, 0); 1374 892 } else { 1375 - if (status) 1376 - isst_display_result(cpu, outf, "base-freq", "enable", 1377 - ret); 1378 - else 1379 - isst_display_result(cpu, outf, "base-freq", "disable", 1380 - ret); 893 + if (auto_mode) { 894 + if (status) 895 + set_scaling_min_to_cpuinfo_max(cpu); 896 + else 897 + set_scaling_min_to_cpuinfo_min(cpu); 898 + } 1381 899 } 900 + 901 + disp_result: 902 + if (status) 903 + isst_display_result(cpu, outf, "base-freq", "enable", 904 + ret); 905 + else 906 + isst_display_result(cpu, outf, "base-freq", "disable", 907 + ret); 1382 908 } 1383 909 1384 - static void set_pbf_enable(void) 910 + static void set_pbf_enable(int arg) 1385 911 { 1386 - int status = 1; 912 + int enable = arg; 1387 913 1388 914 if (cmd_help) { 1389 - fprintf(stderr, 1390 - "Enable Intel Speed Select Technology base frequency feature [No command arguments are required]\n"); 915 + if (enable) { 916 + fprintf(stderr, 917 + "Enable Intel Speed Select Technology base frequency feature\n"); 918 + fprintf(stderr, 919 + "\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n"); 920 + } else { 921 + 922 + fprintf(stderr, 923 + "Disable Intel Speed Select Technology base frequency feature\n"); 924 + fprintf(stderr, 925 + "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); 926 + } 1391 927 exit(0); 1392 928 } 1393 929 1394 930 isst_ctdp_display_information_start(outf); 1395 931 if (max_target_cpus) 1396 932 for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL, 1397 - NULL, &status); 933 + NULL, &enable); 1398 934 else 1399 935 for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL, 1400 - NULL, &status); 1401 - isst_ctdp_display_information_end(outf); 1402 - } 1403 - 1404 - static void set_pbf_disable(void) 1405 - { 1406 - int status = 0; 1407 - 1408 - if (cmd_help) { 1409 - fprintf(stderr, 1410 - "Disable Intel Speed Select Technology base frequency feature [No command arguments are required]\n"); 1411 - exit(0); 1412 - } 1413 - 1414 - isst_ctdp_display_information_start(outf); 1415 - if (max_target_cpus) 1416 - for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL, 1417 - NULL, &status); 1418 - else 1419 - for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL, 1420 - NULL, &status); 936 + NULL, &enable); 1421 937 isst_ctdp_display_information_end(outf); 1422 938 } 1423 939 ··· 1461 925 fact_avx, &fact_info); 1462 926 } 1463 927 1464 - static void dump_fact_config(void) 928 + static void dump_fact_config(int arg) 1465 929 { 1466 930 if (cmd_help) { 1467 931 fprintf(stderr, ··· 1496 960 int ret; 1497 961 int status = *(int *)arg4; 1498 962 1499 - ret = isst_set_pbf_fact_status(cpu, 0, status); 1500 - if (ret) 1501 - perror("isst_set_fact"); 1502 - else { 963 + if (auto_mode) { 1503 964 if (status) { 1504 - struct isst_pkg_ctdp pkg_dev; 1505 - 1506 - ret = isst_get_ctdp_levels(cpu, &pkg_dev); 1507 - if (ret) { 1508 - isst_display_result(cpu, outf, "turbo-freq", 1509 - "enable", ret); 1510 - return; 1511 - } 1512 - ret = isst_set_trl(cpu, fact_trl); 1513 - isst_display_result(cpu, outf, "turbo-freq", "enable", 1514 - ret); 965 + ret = isst_pm_qos_config(cpu, 1, 1); 966 + if (ret) 967 + goto disp_results; 1515 968 } else { 1516 - /* Since we modified TRL during Fact enable, restore it */ 1517 - isst_set_trl_from_current_tdp(cpu, fact_trl); 1518 - isst_display_result(cpu, outf, "turbo-freq", "disable", 1519 - ret); 969 + isst_pm_qos_config(cpu, 0, 0); 1520 970 } 1521 971 } 972 + 973 + ret = isst_set_pbf_fact_status(cpu, 0, status); 974 + if (ret) { 975 + perror("isst_set_fact"); 976 + if (auto_mode) 977 + isst_pm_qos_config(cpu, 0, 0); 978 + 979 + goto disp_results; 980 + } 981 + 982 + /* Set TRL */ 983 + if (status) { 984 + struct isst_pkg_ctdp pkg_dev; 985 + 986 + ret = isst_get_ctdp_levels(cpu, &pkg_dev); 987 + if (!ret) 988 + ret = isst_set_trl(cpu, fact_trl); 989 + if (ret && auto_mode) 990 + isst_pm_qos_config(cpu, 0, 0); 991 + } 992 + 993 + disp_results: 994 + if (status) { 995 + isst_display_result(cpu, outf, "turbo-freq", "enable", ret); 996 + } else { 997 + /* Since we modified TRL during Fact enable, restore it */ 998 + isst_set_trl_from_current_tdp(cpu, fact_trl); 999 + isst_display_result(cpu, outf, "turbo-freq", "disable", ret); 1000 + } 1522 1001 } 1523 1002 1524 - static void set_fact_enable(void) 1003 + static void set_fact_enable(int arg) 1525 1004 { 1526 - int status = 1; 1005 + int i, ret, enable = arg; 1527 1006 1528 1007 if (cmd_help) { 1529 - fprintf(stderr, 1530 - "Enable Intel Speed Select Technology Turbo frequency feature\n"); 1531 - fprintf(stderr, 1532 - "Optional: -t|--trl : Specify turbo ratio limit\n"); 1008 + if (enable) { 1009 + fprintf(stderr, 1010 + "Enable Intel Speed Select Technology Turbo frequency feature\n"); 1011 + fprintf(stderr, 1012 + "Optional: -t|--trl : Specify turbo ratio limit\n"); 1013 + fprintf(stderr, 1014 + "\tOptional Arguments: -a|--auto : Designate specified target CPUs with"); 1015 + fprintf(stderr, 1016 + "-C|--cpu option as as high priority using core-power feature\n"); 1017 + } else { 1018 + fprintf(stderr, 1019 + "Disable Intel Speed Select Technology turbo frequency feature\n"); 1020 + fprintf(stderr, 1021 + "Optional: -t|--trl : Specify turbo ratio limit\n"); 1022 + fprintf(stderr, 1023 + "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); 1024 + } 1533 1025 exit(0); 1534 1026 } 1535 1027 1536 1028 isst_ctdp_display_information_start(outf); 1537 1029 if (max_target_cpus) 1538 1030 for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL, 1539 - NULL, &status); 1031 + NULL, &enable); 1540 1032 else 1541 1033 for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL, 1542 - NULL, &status); 1034 + NULL, &enable); 1543 1035 isst_ctdp_display_information_end(outf); 1544 - } 1545 1036 1546 - static void set_fact_disable(void) 1547 - { 1548 - int status = 0; 1037 + if (enable && auto_mode) { 1038 + /* 1039 + * When we adjust CLOS param, we have to set for siblings also. 1040 + * So for the each user specified CPU, also add the sibling 1041 + * in the present_cpu_mask. 1042 + */ 1043 + for (i = 0; i < get_topo_max_cpus(); ++i) { 1044 + char buffer[128], sibling_list[128], *cpu_str; 1045 + int fd, len; 1549 1046 1550 - if (cmd_help) { 1551 - fprintf(stderr, 1552 - "Disable Intel Speed Select Technology turbo frequency feature\n"); 1553 - fprintf(stderr, 1554 - "Optional: -t|--trl : Specify turbo ratio limit\n"); 1555 - exit(0); 1047 + if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask)) 1048 + continue; 1049 + 1050 + snprintf(buffer, sizeof(buffer), 1051 + "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i); 1052 + 1053 + fd = open(buffer, O_RDONLY); 1054 + if (fd < 0) 1055 + continue; 1056 + 1057 + len = read(fd, sibling_list, sizeof(sibling_list)); 1058 + close(fd); 1059 + 1060 + if (len < 0) 1061 + continue; 1062 + 1063 + cpu_str = strtok(sibling_list, ","); 1064 + while (cpu_str != NULL) { 1065 + int cpu; 1066 + 1067 + sscanf(cpu_str, "%d", &cpu); 1068 + CPU_SET_S(cpu, target_cpumask_size, target_cpumask); 1069 + cpu_str = strtok(NULL, ","); 1070 + } 1071 + } 1072 + 1073 + for (i = 0; i < get_topo_max_cpus(); ++i) { 1074 + int clos; 1075 + 1076 + if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) 1077 + continue; 1078 + 1079 + ret = set_clos_param(i, 0, 0, 0, 0, 0xff); 1080 + if (ret) 1081 + goto error_disp; 1082 + 1083 + ret = set_clos_param(i, 1, 15, 15, 0, 0xff); 1084 + if (ret) 1085 + goto error_disp; 1086 + 1087 + ret = set_clos_param(i, 2, 15, 15, 0, 0xff); 1088 + if (ret) 1089 + goto error_disp; 1090 + 1091 + ret = set_clos_param(i, 3, 15, 15, 0, 0xff); 1092 + if (ret) 1093 + goto error_disp; 1094 + 1095 + if (CPU_ISSET_S(i, target_cpumask_size, target_cpumask)) 1096 + clos = 0; 1097 + else 1098 + clos = 3; 1099 + 1100 + debug_printf("Associate cpu: %d clos: %d\n", i, clos); 1101 + ret = isst_clos_associate(i, clos); 1102 + if (ret) 1103 + goto error_disp; 1104 + } 1105 + isst_display_result(i, outf, "turbo-freq --auto", "enable", 0); 1556 1106 } 1557 1107 1558 - isst_ctdp_display_information_start(outf); 1559 - if (max_target_cpus) 1560 - for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL, 1561 - NULL, &status); 1562 - else 1563 - for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL, 1564 - NULL, &status); 1565 - isst_ctdp_display_information_end(outf); 1108 + return; 1109 + 1110 + error_disp: 1111 + isst_display_result(i, outf, "turbo-freq --auto", "enable", ret); 1112 + 1566 1113 } 1567 1114 1568 1115 static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3, ··· 1655 1036 int status = *(int *)arg4; 1656 1037 1657 1038 ret = isst_pm_qos_config(cpu, status, clos_priority_type); 1658 - if (ret) { 1039 + if (ret) 1659 1040 perror("isst_pm_qos_config"); 1660 - } else { 1661 - if (status) 1662 - isst_display_result(cpu, outf, "core-power", "enable", 1663 - ret); 1664 - else 1665 - isst_display_result(cpu, outf, "core-power", "disable", 1666 - ret); 1667 - } 1041 + 1042 + if (status) 1043 + isst_display_result(cpu, outf, "core-power", "enable", 1044 + ret); 1045 + else 1046 + isst_display_result(cpu, outf, "core-power", "disable", 1047 + ret); 1668 1048 } 1669 1049 1670 - static void set_clos_enable(void) 1050 + static void set_clos_enable(int arg) 1671 1051 { 1672 - int status = 1; 1052 + int enable = arg; 1673 1053 1674 1054 if (cmd_help) { 1675 - fprintf(stderr, "Enable core-power for a package/die\n"); 1676 - fprintf(stderr, 1677 - "\tClos Enable: Specify priority type with [--priority|-p]\n"); 1678 - fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n"); 1055 + if (enable) { 1056 + fprintf(stderr, 1057 + "Enable core-power for a package/die\n"); 1058 + fprintf(stderr, 1059 + "\tClos Enable: Specify priority type with [--priority|-p]\n"); 1060 + fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n"); 1061 + } else { 1062 + fprintf(stderr, 1063 + "Disable core-power: [No command arguments are required]\n"); 1064 + } 1679 1065 exit(0); 1680 1066 } 1681 1067 1682 - if (cpufreq_sysfs_present()) { 1068 + if (enable && cpufreq_sysfs_present()) { 1683 1069 fprintf(stderr, 1684 1070 "cpufreq subsystem and core-power enable will interfere with each other!\n"); 1685 1071 } ··· 1692 1068 isst_ctdp_display_information_start(outf); 1693 1069 if (max_target_cpus) 1694 1070 for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL, 1695 - NULL, NULL, &status); 1071 + NULL, NULL, &enable); 1696 1072 else 1697 1073 for_each_online_package_in_set(enable_clos_qos_config, NULL, 1698 - NULL, NULL, &status); 1699 - isst_ctdp_display_information_end(outf); 1700 - } 1701 - 1702 - static void set_clos_disable(void) 1703 - { 1704 - int status = 0; 1705 - 1706 - if (cmd_help) { 1707 - fprintf(stderr, 1708 - "Disable core-power: [No command arguments are required]\n"); 1709 - exit(0); 1710 - } 1711 - 1712 - isst_ctdp_display_information_start(outf); 1713 - if (max_target_cpus) 1714 - for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL, 1715 - NULL, NULL, &status); 1716 - else 1717 - for_each_online_package_in_set(enable_clos_qos_config, NULL, 1718 - NULL, NULL, &status); 1074 + NULL, NULL, &enable); 1719 1075 isst_ctdp_display_information_end(outf); 1720 1076 } 1721 1077 ··· 1713 1109 &clos_config); 1714 1110 } 1715 1111 1716 - static void dump_clos_config(void) 1112 + static void dump_clos_config(int arg) 1717 1113 { 1718 1114 if (cmd_help) { 1719 1115 fprintf(stderr, ··· 1749 1145 isst_clos_display_clos_information(cpu, outf, enable, prio_type); 1750 1146 } 1751 1147 1752 - static void dump_clos_info(void) 1148 + static void dump_clos_info(int arg) 1753 1149 { 1754 1150 if (cmd_help) { 1755 1151 fprintf(stderr, ··· 1792 1188 isst_display_result(cpu, outf, "core-power", "config", ret); 1793 1189 } 1794 1190 1795 - static void set_clos_config(void) 1191 + static void set_clos_config(int arg) 1796 1192 { 1797 1193 if (cmd_help) { 1798 1194 fprintf(stderr, ··· 1802 1198 fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n"); 1803 1199 fprintf(stderr, 1804 1200 "\tSpecify clos Proportional Priority [--weight|-w]\n"); 1805 - fprintf(stderr, "\tSpecify clos min with [--min|-n]\n"); 1806 - fprintf(stderr, "\tSpecify clos max with [--max|-m]\n"); 1807 - fprintf(stderr, "\tSpecify clos desired with [--desired|-d]\n"); 1201 + fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n"); 1202 + fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n"); 1203 + fprintf(stderr, "\tSpecify clos desired in MHz with [--desired|-d]\n"); 1808 1204 exit(0); 1809 1205 } 1810 1206 ··· 1826 1222 clos_min = 0; 1827 1223 } 1828 1224 if (clos_max < 0) { 1829 - fprintf(stderr, "clos max is not specified, default: 0xff\n"); 1225 + fprintf(stderr, "clos max is not specified, default: 25500 MHz\n"); 1830 1226 clos_max = 0xff; 1831 1227 } 1832 1228 if (clos_desired < 0) { ··· 1856 1252 isst_display_result(cpu, outf, "core-power", "assoc", ret); 1857 1253 } 1858 1254 1859 - static void set_clos_assoc(void) 1255 + static void set_clos_assoc(int arg) 1860 1256 { 1861 1257 if (cmd_help) { 1862 1258 fprintf(stderr, "Associate a clos id to a CPU\n"); ··· 1890 1286 isst_clos_display_assoc_information(cpu, outf, clos); 1891 1287 } 1892 1288 1893 - static void get_clos_assoc(void) 1289 + static void get_clos_assoc(int arg) 1894 1290 { 1895 1291 if (cmd_help) { 1896 1292 fprintf(stderr, "Get associate clos id to a CPU\n"); ··· 1910 1306 isst_ctdp_display_information_end(outf); 1911 1307 } 1912 1308 1309 + static struct process_cmd_struct clx_n_cmds[] = { 1310 + { "perf-profile", "info", dump_isst_config, 0 }, 1311 + { "base-freq", "info", dump_pbf_config, 0 }, 1312 + { "base-freq", "enable", set_pbf_enable, 1 }, 1313 + { "base-freq", "disable", set_pbf_enable, 0 }, 1314 + { NULL, NULL, NULL, 0 } 1315 + }; 1316 + 1913 1317 static struct process_cmd_struct isst_cmds[] = { 1914 - { "perf-profile", "get-lock-status", get_tdp_locked }, 1915 - { "perf-profile", "get-config-levels", get_tdp_levels }, 1916 - { "perf-profile", "get-config-version", get_tdp_version }, 1917 - { "perf-profile", "get-config-enabled", get_tdp_enabled }, 1918 - { "perf-profile", "get-config-current-level", get_tdp_current_level }, 1919 - { "perf-profile", "set-config-level", set_tdp_level }, 1920 - { "perf-profile", "info", dump_isst_config }, 1921 - { "base-freq", "info", dump_pbf_config }, 1922 - { "base-freq", "enable", set_pbf_enable }, 1923 - { "base-freq", "disable", set_pbf_disable }, 1924 - { "turbo-freq", "info", dump_fact_config }, 1925 - { "turbo-freq", "enable", set_fact_enable }, 1926 - { "turbo-freq", "disable", set_fact_disable }, 1927 - { "core-power", "info", dump_clos_info }, 1928 - { "core-power", "enable", set_clos_enable }, 1929 - { "core-power", "disable", set_clos_disable }, 1930 - { "core-power", "config", set_clos_config }, 1931 - { "core-power", "get-config", dump_clos_config }, 1932 - { "core-power", "assoc", set_clos_assoc }, 1933 - { "core-power", "get-assoc", get_clos_assoc }, 1318 + { "perf-profile", "get-lock-status", get_tdp_locked, 0 }, 1319 + { "perf-profile", "get-config-levels", get_tdp_levels, 0 }, 1320 + { "perf-profile", "get-config-version", get_tdp_version, 0 }, 1321 + { "perf-profile", "get-config-enabled", get_tdp_enabled, 0 }, 1322 + { "perf-profile", "get-config-current-level", get_tdp_current_level, 1323 + 0 }, 1324 + { "perf-profile", "set-config-level", set_tdp_level, 0 }, 1325 + { "perf-profile", "info", dump_isst_config, 0 }, 1326 + { "base-freq", "info", dump_pbf_config, 0 }, 1327 + { "base-freq", "enable", set_pbf_enable, 1 }, 1328 + { "base-freq", "disable", set_pbf_enable, 0 }, 1329 + { "turbo-freq", "info", dump_fact_config, 0 }, 1330 + { "turbo-freq", "enable", set_fact_enable, 1 }, 1331 + { "turbo-freq", "disable", set_fact_enable, 0 }, 1332 + { "core-power", "info", dump_clos_info, 0 }, 1333 + { "core-power", "enable", set_clos_enable, 1 }, 1334 + { "core-power", "disable", set_clos_enable, 0 }, 1335 + { "core-power", "config", set_clos_config, 0 }, 1336 + { "core-power", "get-config", dump_clos_config, 0 }, 1337 + { "core-power", "assoc", set_clos_assoc, 0 }, 1338 + { "core-power", "get-assoc", get_clos_assoc, 0 }, 1934 1339 { NULL, NULL, NULL } 1935 1340 }; 1936 1341 ··· 2030 1417 { "max", required_argument, 0, 'm' }, 2031 1418 { "priority", required_argument, 0, 'p' }, 2032 1419 { "weight", required_argument, 0, 'w' }, 1420 + { "auto", no_argument, 0, 'a' }, 2033 1421 { 0, 0, 0, 0 } 2034 1422 }; 2035 1423 2036 1424 option_index = start; 2037 1425 2038 1426 optind = start + 1; 2039 - while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:ho", 1427 + while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:hoa", 2040 1428 long_options, &option_index)) != -1) { 2041 1429 switch (opt) { 1430 + case 'a': 1431 + auto_mode = 1; 1432 + break; 2042 1433 case 'b': 2043 1434 fact_bucket = atoi(optarg); 2044 1435 break; ··· 2076 1459 break; 2077 1460 case 'd': 2078 1461 clos_desired = atoi(optarg); 1462 + clos_desired /= DISP_FREQ_MULTIPLIER; 2079 1463 break; 2080 1464 case 'e': 2081 1465 clos_epp = atoi(optarg); 2082 1466 break; 2083 1467 case 'n': 2084 1468 clos_min = atoi(optarg); 1469 + clos_min /= DISP_FREQ_MULTIPLIER; 2085 1470 break; 2086 1471 case 'm': 2087 1472 clos_max = atoi(optarg); 1473 + clos_max /= DISP_FREQ_MULTIPLIER; 2088 1474 break; 2089 1475 case 'p': 2090 1476 clos_priority_type = atoi(optarg); ··· 2109 1489 TDP, etc.\n"); 2110 1490 printf("\nCommands : For feature=perf-profile\n"); 2111 1491 printf("\tinfo\n"); 2112 - printf("\tget-lock-status\n"); 2113 - printf("\tget-config-levels\n"); 2114 - printf("\tget-config-version\n"); 2115 - printf("\tget-config-enabled\n"); 2116 - printf("\tget-config-current-level\n"); 2117 - printf("\tset-config-level\n"); 1492 + 1493 + if (!is_clx_n_platform()) { 1494 + printf("\tget-lock-status\n"); 1495 + printf("\tget-config-levels\n"); 1496 + printf("\tget-config-version\n"); 1497 + printf("\tget-config-enabled\n"); 1498 + printf("\tget-config-current-level\n"); 1499 + printf("\tset-config-level\n"); 1500 + } 2118 1501 } 2119 1502 2120 1503 static void pbf_help(void) ··· 2167 1544 { NULL, NULL } 2168 1545 }; 2169 1546 2170 - void process_command(int argc, char **argv) 1547 + static struct process_cmd_help_struct clx_n_help_cmds[] = { 1548 + { "perf-profile", isst_help }, 1549 + { "base-freq", pbf_help }, 1550 + { NULL, NULL } 1551 + }; 1552 + 1553 + void process_command(int argc, char **argv, 1554 + struct process_cmd_help_struct *help_cmds, 1555 + struct process_cmd_struct *cmds) 2171 1556 { 2172 1557 int i = 0, matched = 0; 2173 1558 char *feature = argv[optind]; ··· 2186 1555 2187 1556 debug_printf("feature name [%s] command [%s]\n", feature, cmd); 2188 1557 if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) { 2189 - while (isst_help_cmds[i].feature) { 2190 - if (!strcmp(isst_help_cmds[i].feature, feature)) { 2191 - isst_help_cmds[i].process_fn(); 1558 + while (help_cmds[i].feature) { 1559 + if (!strcmp(help_cmds[i].feature, feature)) { 1560 + help_cmds[i].process_fn(); 2192 1561 exit(0); 2193 1562 } 2194 1563 ++i; 2195 1564 } 2196 1565 } 2197 1566 2198 - create_cpu_map(); 1567 + if (!is_clx_n_platform()) 1568 + create_cpu_map(); 2199 1569 2200 1570 i = 0; 2201 - while (isst_cmds[i].feature) { 2202 - if (!strcmp(isst_cmds[i].feature, feature) && 2203 - !strcmp(isst_cmds[i].command, cmd)) { 1571 + while (cmds[i].feature) { 1572 + if (!strcmp(cmds[i].feature, feature) && 1573 + !strcmp(cmds[i].command, cmd)) { 2204 1574 parse_cmd_args(argc, optind + 1, argv); 2205 - isst_cmds[i].process_fn(); 1575 + cmds[i].process_fn(cmds[i].arg); 2206 1576 matched = 1; 2207 1577 break; 2208 1578 } ··· 2314 1682 fprintf(stderr, "Feature name and|or command not specified\n"); 2315 1683 exit(0); 2316 1684 } 2317 - update_cpu_model(); 1685 + ret = update_cpu_model(); 1686 + if (ret) 1687 + err(-1, "Invalid CPU model (%d)\n", cpu_model); 2318 1688 printf("Intel(R) Speed Select Technology\n"); 2319 1689 printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model); 2320 1690 set_max_cpu_num(); 2321 1691 set_cpu_present_cpu_mask(); 2322 1692 set_cpu_target_cpu_mask(); 2323 - ret = isst_fill_platform_info(); 2324 - if (ret) 2325 - goto out; 2326 1693 2327 - process_command(argc, argv); 1694 + if (!is_clx_n_platform()) { 1695 + ret = isst_fill_platform_info(); 1696 + if (ret) 1697 + goto out; 1698 + process_command(argc, argv, isst_help_cmds, isst_cmds); 1699 + } else { 1700 + process_command(argc, argv, clx_n_help_cmds, clx_n_cmds); 1701 + } 2328 1702 out: 2329 1703 free_cpu_set(present_cpumask); 2330 1704 free_cpu_set(target_cpumask);
+154 -22
tools/power/x86/intel-speed-select/isst-core.c
··· 13 13 14 14 ret = isst_send_mbox_command(cpu, CONFIG_TDP, 15 15 CONFIG_TDP_GET_LEVELS_INFO, 0, 0, &resp); 16 - if (ret) 17 - return ret; 16 + if (ret) { 17 + pkg_dev->levels = 0; 18 + pkg_dev->locked = 1; 19 + pkg_dev->current_level = 0; 20 + pkg_dev->version = 0; 21 + pkg_dev->enabled = 0; 22 + return 0; 23 + } 18 24 19 25 debug_printf("cpu:%d CONFIG_TDP_GET_LEVELS_INFO resp:%x\n", cpu, resp); 20 26 ··· 101 95 return 0; 102 96 } 103 97 98 + void isst_get_uncore_p0_p1_info(int cpu, int config_index, 99 + struct isst_pkg_ctdp_level_info *ctdp_level) 100 + { 101 + unsigned int resp; 102 + int ret; 103 + ret = isst_send_mbox_command(cpu, CONFIG_TDP, 104 + CONFIG_TDP_GET_UNCORE_P0_P1_INFO, 0, 105 + config_index, &resp); 106 + if (ret) { 107 + ctdp_level->uncore_p0 = 0; 108 + ctdp_level->uncore_p1 = 0; 109 + return; 110 + } 111 + 112 + ctdp_level->uncore_p0 = resp & GENMASK(7, 0); 113 + ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8; 114 + debug_printf( 115 + "cpu:%d ctdp:%d CONFIG_TDP_GET_UNCORE_P0_P1_INFO resp:%x uncore p0:%d uncore p1:%d\n", 116 + cpu, config_index, resp, ctdp_level->uncore_p0, 117 + ctdp_level->uncore_p1); 118 + } 119 + 120 + void isst_get_p1_info(int cpu, int config_index, 121 + struct isst_pkg_ctdp_level_info *ctdp_level) 122 + { 123 + unsigned int resp; 124 + int ret; 125 + ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_P1_INFO, 0, 126 + config_index, &resp); 127 + if (ret) { 128 + ctdp_level->sse_p1 = 0; 129 + ctdp_level->avx2_p1 = 0; 130 + ctdp_level->avx512_p1 = 0; 131 + return; 132 + } 133 + 134 + ctdp_level->sse_p1 = resp & GENMASK(7, 0); 135 + ctdp_level->avx2_p1 = (resp & GENMASK(15, 8)) >> 8; 136 + ctdp_level->avx512_p1 = (resp & GENMASK(23, 16)) >> 16; 137 + debug_printf( 138 + "cpu:%d ctdp:%d CONFIG_TDP_GET_P1_INFO resp:%x sse_p1:%d avx2_p1:%d avx512_p1:%d\n", 139 + cpu, config_index, resp, ctdp_level->sse_p1, 140 + ctdp_level->avx2_p1, ctdp_level->avx512_p1); 141 + } 142 + 143 + void isst_get_uncore_mem_freq(int cpu, int config_index, 144 + struct isst_pkg_ctdp_level_info *ctdp_level) 145 + { 146 + unsigned int resp; 147 + int ret; 148 + ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_MEM_FREQ, 149 + 0, config_index, &resp); 150 + if (ret) { 151 + ctdp_level->mem_freq = 0; 152 + return; 153 + } 154 + 155 + ctdp_level->mem_freq = resp & GENMASK(7, 0); 156 + debug_printf( 157 + "cpu:%d ctdp:%d CONFIG_TDP_GET_MEM_FREQ resp:%x uncore mem_freq:%d\n", 158 + cpu, config_index, resp, ctdp_level->mem_freq); 159 + } 160 + 104 161 int isst_get_tjmax_info(int cpu, int config_index, 105 162 struct isst_pkg_ctdp_level_info *ctdp_level) 106 163 { ··· 214 145 debug_printf("cpu:%d ctdp:%d mask:%d cpu count:%d\n", cpu, 215 146 config_index, i, ctdp_level->cpu_count); 216 147 } 148 + 149 + return 0; 150 + } 151 + 152 + int isst_get_get_trl_from_msr(int cpu, int *trl) 153 + { 154 + unsigned long long msr_trl; 155 + int ret; 156 + 157 + ret = isst_send_msr_command(cpu, 0x1AD, 0, &msr_trl); 158 + if (ret) 159 + return ret; 160 + 161 + trl[0] = msr_trl & GENMASK(7, 0); 162 + trl[1] = (msr_trl & GENMASK(15, 8)) >> 8; 163 + trl[2] = (msr_trl & GENMASK(23, 16)) >> 16; 164 + trl[3] = (msr_trl & GENMASK(31, 24)) >> 24; 165 + trl[4] = (msr_trl & GENMASK(39, 32)) >> 32; 166 + trl[5] = (msr_trl & GENMASK(47, 40)) >> 40; 167 + trl[6] = (msr_trl & GENMASK(55, 48)) >> 48; 168 + trl[7] = (msr_trl & GENMASK(63, 56)) >> 56; 217 169 218 170 return 0; 219 171 } ··· 335 245 336 246 int isst_get_pbf_info(int cpu, int level, struct isst_pbf_info *pbf_info) 337 247 { 248 + int i, ret, core_cnt, max; 338 249 unsigned int req, resp; 339 - int i, ret; 340 250 341 251 pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask); 342 252 343 - for (i = 0; i < 2; ++i) { 253 + core_cnt = get_core_count(get_physical_package_id(cpu), get_physical_die_id(cpu)); 254 + max = core_cnt > 32 ? 2 : 1; 255 + 256 + for (i = 0; i < max; ++i) { 344 257 unsigned long long mask; 345 258 int count; 346 259 ··· 351 258 CONFIG_TDP_PBF_GET_CORE_MASK_INFO, 352 259 0, (i << 8) | level, &resp); 353 260 if (ret) 354 - return ret; 261 + break; 355 262 356 263 debug_printf( 357 264 "cpu:%d CONFIG_TDP_PBF_GET_CORE_MASK_INFO resp:%x\n", ··· 416 323 417 324 ret = isst_get_ctdp_levels(cpu, &pkg_dev); 418 325 if (ret) 419 - return ret; 326 + debug_printf("cpu:%d No support for dynamic ISST\n", cpu); 420 327 421 328 current_level = pkg_dev.current_level; 422 329 ··· 646 553 i); 647 554 ctdp_level = &pkg_dev->ctdp_level[i]; 648 555 649 - ctdp_level->processed = 1; 650 556 ctdp_level->level = i; 651 557 ctdp_level->control_cpu = cpu; 652 558 ctdp_level->pkg_id = get_physical_package_id(cpu); ··· 653 561 654 562 ret = isst_get_ctdp_control(cpu, i, ctdp_level); 655 563 if (ret) 656 - return ret; 564 + continue; 565 + 566 + pkg_dev->processed = 1; 567 + ctdp_level->processed = 1; 568 + 569 + if (ctdp_level->pbf_support) { 570 + ret = isst_get_pbf_info(cpu, i, &ctdp_level->pbf_info); 571 + if (!ret) 572 + ctdp_level->pbf_found = 1; 573 + } 574 + 575 + if (ctdp_level->fact_support) { 576 + ret = isst_get_fact_info(cpu, i, 577 + &ctdp_level->fact_info); 578 + if (ret) 579 + return ret; 580 + } 581 + 582 + if (!pkg_dev->enabled) { 583 + int freq; 584 + 585 + freq = get_cpufreq_base_freq(cpu); 586 + if (freq > 0) { 587 + ctdp_level->sse_p1 = freq / 100000; 588 + ctdp_level->tdp_ratio = ctdp_level->sse_p1; 589 + } 590 + 591 + isst_get_get_trl_from_msr(cpu, ctdp_level->trl_sse_active_cores); 592 + isst_get_trl_bucket_info(cpu, &ctdp_level->buckets_info); 593 + continue; 594 + } 657 595 658 596 ret = isst_get_tdp_info(cpu, i, ctdp_level); 659 597 if (ret) ··· 722 600 if (ret) 723 601 return ret; 724 602 725 - if (ctdp_level->pbf_support) { 726 - ret = isst_get_pbf_info(cpu, i, &ctdp_level->pbf_info); 727 - if (!ret) 728 - ctdp_level->pbf_found = 1; 729 - } 730 - 731 - if (ctdp_level->fact_support) { 732 - ret = isst_get_fact_info(cpu, i, 733 - &ctdp_level->fact_info); 734 - if (ret) 735 - return ret; 736 - } 603 + isst_get_uncore_p0_p1_info(cpu, i, ctdp_level); 604 + isst_get_p1_info(cpu, i, ctdp_level); 605 + isst_get_uncore_mem_freq(cpu, i, ctdp_level); 737 606 } 738 - 739 - pkg_dev->processed = 1; 740 607 741 608 return 0; 742 609 } ··· 759 648 { 760 649 unsigned int req, resp; 761 650 int ret; 651 + 652 + if (!enable_clos) { 653 + struct isst_pkg_ctdp pkg_dev; 654 + struct isst_pkg_ctdp_level_info ctdp_level; 655 + 656 + ret = isst_get_ctdp_levels(cpu, &pkg_dev); 657 + if (ret) { 658 + debug_printf("isst_get_ctdp_levels\n"); 659 + return ret; 660 + } 661 + 662 + ret = isst_get_ctdp_control(cpu, pkg_dev.current_level, 663 + &ctdp_level); 664 + if (ret) 665 + return ret; 666 + 667 + if (ctdp_level.fact_enabled) { 668 + debug_printf("Turbo-freq feature must be disabled first\n"); 669 + return -EINVAL; 670 + } 671 + } 762 672 763 673 ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0, 764 674 &resp);
+104 -50
tools/power/x86/intel-speed-select/isst-display.c
··· 6 6 7 7 #include "isst.h" 8 8 9 - #define DISP_FREQ_MULTIPLIER 100 10 - 11 9 static void printcpulist(int str_len, char *str, int mask_size, 12 10 cpu_set_t *cpu_mask) 13 11 { ··· 202 204 pbf_info->p1_low * DISP_FREQ_MULTIPLIER); 203 205 format_and_print(outf, disp_level + 1, header, value); 204 206 207 + if (is_clx_n_platform()) 208 + return; 209 + 205 210 snprintf(header, sizeof(header), "tjunction-temperature(C)"); 206 211 snprintf(value, sizeof(value), "%d", pbf_info->t_prochot); 207 212 format_and_print(outf, disp_level + 1, header, value); ··· 315 314 char value[256]; 316 315 int i, base_level = 1; 317 316 318 - print_package_info(cpu, outf); 317 + if (pkg_dev->processed) 318 + print_package_info(cpu, outf); 319 319 320 320 for (i = 0; i <= pkg_dev->levels; ++i) { 321 321 struct isst_pkg_ctdp_level_info *ctdp_level; ··· 336 334 snprintf(value, sizeof(value), "%d", j); 337 335 format_and_print(outf, base_level + 4, header, value); 338 336 339 - snprintf(header, sizeof(header), "enable-cpu-mask"); 340 - printcpumask(sizeof(value), value, 341 - ctdp_level->core_cpumask_size, 342 - ctdp_level->core_cpumask); 343 - format_and_print(outf, base_level + 4, header, value); 337 + if (ctdp_level->core_cpumask_size) { 338 + snprintf(header, sizeof(header), "enable-cpu-mask"); 339 + printcpumask(sizeof(value), value, 340 + ctdp_level->core_cpumask_size, 341 + ctdp_level->core_cpumask); 342 + format_and_print(outf, base_level + 4, header, value); 344 343 345 - snprintf(header, sizeof(header), "enable-cpu-list"); 346 - printcpulist(sizeof(value), value, 347 - ctdp_level->core_cpumask_size, 348 - ctdp_level->core_cpumask); 349 - format_and_print(outf, base_level + 4, header, value); 344 + snprintf(header, sizeof(header), "enable-cpu-list"); 345 + printcpulist(sizeof(value), value, 346 + ctdp_level->core_cpumask_size, 347 + ctdp_level->core_cpumask); 348 + format_and_print(outf, base_level + 4, header, value); 349 + } 350 350 351 351 snprintf(header, sizeof(header), "thermal-design-power-ratio"); 352 352 snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio); 353 353 format_and_print(outf, base_level + 4, header, value); 354 354 355 355 snprintf(header, sizeof(header), "base-frequency(MHz)"); 356 + if (!ctdp_level->sse_p1) 357 + ctdp_level->sse_p1 = ctdp_level->tdp_ratio; 356 358 snprintf(value, sizeof(value), "%d", 357 - ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER); 359 + ctdp_level->sse_p1 * DISP_FREQ_MULTIPLIER); 358 360 format_and_print(outf, base_level + 4, header, value); 361 + 362 + if (ctdp_level->avx2_p1) { 363 + snprintf(header, sizeof(header), "base-frequency-avx2(MHz)"); 364 + snprintf(value, sizeof(value), "%d", 365 + ctdp_level->avx2_p1 * DISP_FREQ_MULTIPLIER); 366 + format_and_print(outf, base_level + 4, header, value); 367 + } 368 + 369 + if (ctdp_level->avx512_p1) { 370 + snprintf(header, sizeof(header), "base-frequency-avx512(MHz)"); 371 + snprintf(value, sizeof(value), "%d", 372 + ctdp_level->avx512_p1 * DISP_FREQ_MULTIPLIER); 373 + format_and_print(outf, base_level + 4, header, value); 374 + } 375 + 376 + if (ctdp_level->uncore_p1) { 377 + snprintf(header, sizeof(header), "uncore-frequency-min(MHz)"); 378 + snprintf(value, sizeof(value), "%d", 379 + ctdp_level->uncore_p1 * DISP_FREQ_MULTIPLIER); 380 + format_and_print(outf, base_level + 4, header, value); 381 + } 382 + 383 + if (ctdp_level->uncore_p0) { 384 + snprintf(header, sizeof(header), "uncore-frequency-max(MHz)"); 385 + snprintf(value, sizeof(value), "%d", 386 + ctdp_level->uncore_p0 * DISP_FREQ_MULTIPLIER); 387 + format_and_print(outf, base_level + 4, header, value); 388 + } 389 + 390 + if (ctdp_level->mem_freq) { 391 + snprintf(header, sizeof(header), "mem-frequency(MHz)"); 392 + snprintf(value, sizeof(value), "%d", 393 + ctdp_level->mem_freq * DISP_FREQ_MULTIPLIER); 394 + format_and_print(outf, base_level + 4, header, value); 395 + } 359 396 360 397 snprintf(header, sizeof(header), 361 398 "speed-select-turbo-freq"); ··· 418 377 snprintf(value, sizeof(value), "unsupported"); 419 378 format_and_print(outf, base_level + 4, header, value); 420 379 421 - snprintf(header, sizeof(header), "thermal-design-power(W)"); 422 - snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp); 423 - format_and_print(outf, base_level + 4, header, value); 380 + if (is_clx_n_platform()) { 381 + if (ctdp_level->pbf_support) 382 + _isst_pbf_display_information(cpu, outf, 383 + tdp_level, 384 + &ctdp_level->pbf_info, 385 + base_level + 4); 386 + continue; 387 + } 424 388 425 - snprintf(header, sizeof(header), "tjunction-max(C)"); 426 - snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot); 427 - format_and_print(outf, base_level + 4, header, value); 389 + if (ctdp_level->pkg_tdp) { 390 + snprintf(header, sizeof(header), "thermal-design-power(W)"); 391 + snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp); 392 + format_and_print(outf, base_level + 4, header, value); 393 + } 394 + 395 + if (ctdp_level->t_proc_hot) { 396 + snprintf(header, sizeof(header), "tjunction-max(C)"); 397 + snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot); 398 + format_and_print(outf, base_level + 4, header, value); 399 + } 428 400 429 401 snprintf(header, sizeof(header), "turbo-ratio-limits-sse"); 430 402 format_and_print(outf, base_level + 4, header, NULL); ··· 456 402 DISP_FREQ_MULTIPLIER); 457 403 format_and_print(outf, base_level + 6, header, value); 458 404 } 459 - snprintf(header, sizeof(header), "turbo-ratio-limits-avx"); 460 - format_and_print(outf, base_level + 4, header, NULL); 461 - for (j = 0; j < 8; ++j) { 462 - snprintf(header, sizeof(header), "bucket-%d", j); 463 - format_and_print(outf, base_level + 5, header, NULL); 464 405 465 - snprintf(header, sizeof(header), "core-count"); 466 - snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff); 467 - format_and_print(outf, base_level + 6, header, value); 406 + if (ctdp_level->trl_avx_active_cores[0]) { 407 + snprintf(header, sizeof(header), "turbo-ratio-limits-avx2"); 408 + format_and_print(outf, base_level + 4, header, NULL); 409 + for (j = 0; j < 8; ++j) { 410 + snprintf(header, sizeof(header), "bucket-%d", j); 411 + format_and_print(outf, base_level + 5, header, NULL); 468 412 469 - snprintf(header, sizeof(header), 470 - "max-turbo-frequency(MHz)"); 471 - snprintf(value, sizeof(value), "%d", 472 - ctdp_level->trl_avx_active_cores[j] * 473 - DISP_FREQ_MULTIPLIER); 474 - format_and_print(outf, base_level + 6, header, value); 413 + snprintf(header, sizeof(header), "core-count"); 414 + snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff); 415 + format_and_print(outf, base_level + 6, header, value); 416 + 417 + snprintf(header, sizeof(header), "max-turbo-frequency(MHz)"); 418 + snprintf(value, sizeof(value), "%d", ctdp_level->trl_avx_active_cores[j] * DISP_FREQ_MULTIPLIER); 419 + format_and_print(outf, base_level + 6, header, value); 420 + } 475 421 } 476 422 477 - snprintf(header, sizeof(header), "turbo-ratio-limits-avx512"); 478 - format_and_print(outf, base_level + 4, header, NULL); 479 - for (j = 0; j < 8; ++j) { 480 - snprintf(header, sizeof(header), "bucket-%d", j); 481 - format_and_print(outf, base_level + 5, header, NULL); 423 + if (ctdp_level->trl_avx_512_active_cores[0]) { 424 + snprintf(header, sizeof(header), "turbo-ratio-limits-avx512"); 425 + format_and_print(outf, base_level + 4, header, NULL); 426 + for (j = 0; j < 8; ++j) { 427 + snprintf(header, sizeof(header), "bucket-%d", j); 428 + format_and_print(outf, base_level + 5, header, NULL); 482 429 483 - snprintf(header, sizeof(header), "core-count"); 484 - snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff); 485 - format_and_print(outf, base_level + 6, header, value); 430 + snprintf(header, sizeof(header), "core-count"); 431 + snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff); 432 + format_and_print(outf, base_level + 6, header, value); 486 433 487 - snprintf(header, sizeof(header), 488 - "max-turbo-frequency(MHz)"); 489 - snprintf(value, sizeof(value), "%d", 490 - ctdp_level->trl_avx_512_active_cores[j] * 491 - DISP_FREQ_MULTIPLIER); 434 + snprintf(header, sizeof(header), "max-turbo-frequency(MHz)"); 435 + snprintf(value, sizeof(value), "%d", ctdp_level->trl_avx_512_active_cores[j] * DISP_FREQ_MULTIPLIER); 492 436 format_and_print(outf, base_level + 6, header, value); 437 + } 493 438 } 439 + 494 440 if (ctdp_level->pbf_support) 495 441 _isst_pbf_display_information(cpu, outf, i, 496 442 &ctdp_level->pbf_info, ··· 563 509 format_and_print(outf, 5, header, value); 564 510 565 511 snprintf(header, sizeof(header), "clos-min"); 566 - snprintf(value, sizeof(value), "%d", clos_config->clos_min); 512 + snprintf(value, sizeof(value), "%d MHz", clos_config->clos_min * DISP_FREQ_MULTIPLIER); 567 513 format_and_print(outf, 5, header, value); 568 514 569 515 snprintf(header, sizeof(header), "clos-max"); 570 - snprintf(value, sizeof(value), "%d", clos_config->clos_max); 516 + snprintf(value, sizeof(value), "%d MHz", clos_config->clos_max * DISP_FREQ_MULTIPLIER); 571 517 format_and_print(outf, 5, header, value); 572 518 573 519 snprintf(header, sizeof(header), "clos-desired"); 574 - snprintf(value, sizeof(value), "%d", clos_config->clos_desired); 520 + snprintf(value, sizeof(value), "%d MHz", clos_config->clos_desired * DISP_FREQ_MULTIPLIER); 575 521 format_and_print(outf, 5, header, value); 576 522 577 523 format_and_print(outf, 1, NULL, NULL);
+5
tools/power/x86/intel-speed-select/isst.h
··· 69 69 #define PM_CLOS_OFFSET 0x08 70 70 #define PQR_ASSOC_OFFSET 0x20 71 71 72 + #define DISP_FREQ_MULTIPLIER 100 73 + 72 74 struct isst_clos_config { 73 75 int pkg_id; 74 76 int die_id; ··· 163 161 164 162 extern int get_topo_max_cpus(void); 165 163 extern int get_cpu_count(int pkg_id, int die_id); 164 + extern int get_core_count(int pkg_id, int die_id); 166 165 167 166 /* Common interfaces */ 168 167 extern void debug_printf(const char *format, ...); ··· 240 237 extern int isst_clos_get_clos_information(int cpu, int *enable, int *type); 241 238 extern void isst_clos_display_clos_information(int cpu, FILE *outf, 242 239 int clos_enable, int type); 240 + extern int is_clx_n_platform(void); 241 + extern int get_cpufreq_base_freq(int cpu); 243 242 #endif