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.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform driver updates from Hans de Goede:
"New drivers:
- AMD Host System Management Port (HSMP)
- Intel Software Defined Silicon

Removed drivers (functionality folded into other drivers):
- intel_cht_int33fe_microb
- surface3_button

amd-pmc:
- s2idle bug-fixes
- Support for AMD Spill to DRAM STB feature

hp-wmi:
- Fix SW_TABLET_MODE detection method (and other fixes)
- Support omen thermal profile policy v1

serial-multi-instantiate:
- Add SPI device support
- Add support for CS35L41 amplifiers used in new laptops

think-lmi:
- syfs-class-firmware-attributes Certificate authentication support

thinkpad_acpi:
- Fixes + quirks
- Add platform_profile support on AMD based ThinkPads

x86-android-tablets:
- Improve Asus ME176C / TF103C support
- Support Nextbook Ares 8, Lenovo Tab 2 830 and 1050 tablets

Lots of various other small fixes and hardware-id additions"

* tag 'platform-drivers-x86-v5.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (60 commits)
platform/x86: think-lmi: Certificate authentication support
Documentation: syfs-class-firmware-attributes: Lenovo Certificate support
platform/x86: amd-pmc: Only report STB errors when STB enabled
platform/x86: amd-pmc: Drop CPU QoS workaround
platform/x86: amd-pmc: Output error codes in messages
platform/x86: amd-pmc: Move to later in the suspend process
ACPI / x86: Add support for LPS0 callback handler
platform/x86: thinkpad_acpi: consistently check fan_get_status return.
platform/x86: hp-wmi: support omen thermal profile policy v1
platform/x86: hp-wmi: Changing bios_args.data to be dynamically allocated
platform/x86: hp-wmi: Fix 0x05 error code reported by several WMI calls
platform/x86: hp-wmi: Fix SW_TABLET_MODE detection method
platform/x86: hp-wmi: Fix hp_wmi_read_int() reporting error (0x05)
platform/x86: amd-pmc: Validate entry into the deepest state on resume
platform/x86: thinkpad_acpi: Don't use test_bit on an integer
platform/x86: thinkpad_acpi: Fix compiler warning about uninitialized err variable
platform/x86: thinkpad_acpi: clean up dytc profile convert
platform/x86: x86-android-tablets: Depend on EFI and SPI
platform/x86: amd-pmc: uninitialized variable in amd_pmc_s2d_init()
platform/x86: intel-uncore-freq: fix uncore_freq_common_init() error codes
...

+4686 -1381
+45
Documentation/ABI/testing/sysfs-class-firmware-attributes
··· 246 246 that is being referenced (e.g hdd0, hdd1 etc) 247 247 This attribute defaults to device 0. 248 248 249 + certificate: 250 + signature: 251 + save_signature: 252 + These attributes are used for certificate based authentication. This is 253 + used in conjunction with a signing server as an alternative to password 254 + based authentication. 255 + The user writes to the attribute(s) with a BASE64 encoded string obtained 256 + from the signing server. 257 + The attributes can be displayed to check the stored value. 258 + 259 + Some usage examples: 260 + Installing a certificate to enable feature: 261 + echo <supervisor password > authentication/Admin/current_password 262 + echo <signed certificate> > authentication/Admin/certificate 263 + 264 + Updating the installed certificate: 265 + echo <signature> > authentication/Admin/signature 266 + echo <signed certificate> > authentication/Admin/certificate 267 + 268 + Removing the installed certificate: 269 + echo <signature> > authentication/Admin/signature 270 + echo '' > authentication/Admin/certificate 271 + 272 + Changing a BIOS setting: 273 + echo <signature> > authentication/Admin/signature 274 + echo <save signature> > authentication/Admin/save_signature 275 + echo Enable > attribute/PasswordBeep/current_value 276 + 277 + You cannot enable certificate authentication if a supervisor password 278 + has not been set. 279 + Clearing the certificate results in no bios-admin authentication method 280 + being configured allowing anyone to make changes. 281 + After any of these operations the system must reboot for the changes to 282 + take effect. 283 + 284 + certificate_thumbprint: 285 + Read only attribute used to display the MD5, SHA1 and SHA256 thumbprints 286 + for the certificate installed in the BIOS. 287 + 288 + certificate_to_password: 289 + Write only attribute used to switch from certificate based authentication 290 + back to password based. 291 + Usage: 292 + echo <signature> > authentication/Admin/signature 293 + echo <password> > authentication/Admin/certificate_to_password 249 294 250 295 251 296 What: /sys/class/firmware-attributes/*/attributes/pending_reboot
+77
Documentation/ABI/testing/sysfs-driver-intel_sdsi
··· 1 + What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X 2 + Date: Feb 2022 3 + KernelVersion: 5.18 4 + Contact: "David E. Box" <david.e.box@linux.intel.com> 5 + Description: 6 + This directory contains interface files for accessing Intel 7 + Software Defined Silicon (SDSi) features on a CPU. X 8 + represents the socket instance (though not the socket ID). 9 + The socket ID is determined by reading the registers file 10 + and decoding it per the specification. 11 + 12 + Some files communicate with SDSi hardware through a mailbox. 13 + Should the operation fail, one of the following error codes 14 + may be returned: 15 + 16 + Error Code Cause 17 + ---------- ----- 18 + EIO General mailbox failure. Log may indicate cause. 19 + EBUSY Mailbox is owned by another agent. 20 + EPERM SDSI capability is not enabled in hardware. 21 + EPROTO Failure in mailbox protocol detected by driver. 22 + See log for details. 23 + EOVERFLOW For provision commands, the size of the data 24 + exceeds what may be written. 25 + ESPIPE Seeking is not allowed. 26 + ETIMEDOUT Failure to complete mailbox transaction in time. 27 + 28 + What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/guid 29 + Date: Feb 2022 30 + KernelVersion: 5.18 31 + Contact: "David E. Box" <david.e.box@linux.intel.com> 32 + Description: 33 + (RO) The GUID for the registers file. The GUID identifies 34 + the layout of the registers file in this directory. 35 + Information about the register layouts for a particular GUID 36 + is available at http://github.com/intel/intel-sdsi 37 + 38 + What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/registers 39 + Date: Feb 2022 40 + KernelVersion: 5.18 41 + Contact: "David E. Box" <david.e.box@linux.intel.com> 42 + Description: 43 + (RO) Contains information needed by applications to provision 44 + a CPU and monitor status information. The layout of this file 45 + is determined by the GUID in this directory. Information about 46 + the layout for a particular GUID is available at 47 + http://github.com/intel/intel-sdsi 48 + 49 + What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/provision_akc 50 + Date: Feb 2022 51 + KernelVersion: 5.18 52 + Contact: "David E. Box" <david.e.box@linux.intel.com> 53 + Description: 54 + (WO) Used to write an Authentication Key Certificate (AKC) to 55 + the SDSi NVRAM for the CPU. The AKC is used to authenticate a 56 + Capability Activation Payload. Mailbox command. 57 + 58 + What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/provision_cap 59 + Date: Feb 2022 60 + KernelVersion: 5.18 61 + Contact: "David E. Box" <david.e.box@linux.intel.com> 62 + Description: 63 + (WO) Used to write a Capability Activation Payload (CAP) to the 64 + SDSi NVRAM for the CPU. CAPs are used to activate a given CPU 65 + feature. A CAP is validated by SDSi hardware using a previously 66 + provisioned AKC file. Upon successful authentication, the CPU 67 + configuration is updated. A cold reboot is required to fully 68 + activate the feature. Mailbox command. 69 + 70 + What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/state_certificate 71 + Date: Feb 2022 72 + KernelVersion: 5.18 73 + Contact: "David E. Box" <david.e.box@linux.intel.com> 74 + Description: 75 + (RO) Used to read back the current State Certificate for the CPU 76 + from SDSi hardware. The State Certificate contains information 77 + about the current licenses on the CPU. Mailbox command.
+1
Documentation/ABI/testing/sysfs-platform-lg-laptop
··· 17 17 KernelVersion: 4.20 18 18 Contact: "Matan Ziv-Av <matan@svgalib.org> 19 19 Description: 20 + Deprecated use /sys/class/power_supply/CMB0/charge_control_end_threshold 20 21 Maximal battery charge level. Accepted values are 80 or 100. 21 22 22 23 What: /sys/devices/platform/lg-laptop/fan_mode
+1 -1
Documentation/admin-guide/laptops/lg-laptop.rst
··· 38 38 Battery care limit 39 39 ------------------ 40 40 41 - Writing 80/100 to /sys/devices/platform/lg-laptop/battery_care_limit 41 + Writing 80/100 to /sys/class/power_supply/CMB0/charge_control_end_threshold 42 42 sets the maximum capacity to charge the battery. Limiting the charge 43 43 reduces battery capacity loss over time. 44 44
+2
Documentation/userspace-api/ioctl/ioctl-number.rst
··· 375 375 <mailto:thomas@winischhofer.net> 376 376 0xF6 all LTTng Linux Trace Toolkit Next Generation 377 377 <mailto:mathieu.desnoyers@efficios.com> 378 + 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver 379 + <mailto:nchatrad@amd.com> 378 380 0xFD all linux/dm-ioctl.h 379 381 0xFE all linux/isst_if.h 380 382 ==== ===== ======================================================= ================================================================
+86
Documentation/x86/amd_hsmp.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ============================================ 4 + AMD HSMP interface 5 + ============================================ 6 + 7 + Newer Fam19h EPYC server line of processors from AMD support system 8 + management functionality via HSMP (Host System Management Port). 9 + 10 + The Host System Management Port (HSMP) is an interface to provide 11 + OS-level software with access to system management functions via a 12 + set of mailbox registers. 13 + 14 + More details on the interface can be found in chapter 15 + "7 Host System Management Port (HSMP)" of the family/model PPR 16 + Eg: https://www.amd.com/system/files/TechDocs/55898_B1_pub_0.50.zip 17 + 18 + HSMP interface is supported on EPYC server CPU models only. 19 + 20 + 21 + HSMP device 22 + ============================================ 23 + 24 + amd_hsmp driver under the drivers/platforms/x86/ creates miscdevice 25 + /dev/hsmp to let user space programs run hsmp mailbox commands. 26 + 27 + $ ls -al /dev/hsmp 28 + crw-r--r-- 1 root root 10, 123 Jan 21 21:41 /dev/hsmp 29 + 30 + Characteristics of the dev node: 31 + * Write mode is used for running set/configure commands 32 + * Read mode is used for running get/status monitor commands 33 + 34 + Access restrictions: 35 + * Only root user is allowed to open the file in write mode. 36 + * The file can be opened in read mode by all the users. 37 + 38 + In-kernel integration: 39 + * Other subsystems in the kernel can use the exported transport 40 + function hsmp_send_message(). 41 + * Locking across callers is taken care by the driver. 42 + 43 + 44 + An example 45 + ========== 46 + 47 + To access hsmp device from a C program. 48 + First, you need to include the headers:: 49 + 50 + #include <linux/amd_hsmp.h> 51 + 52 + Which defines the supported messages/message IDs. 53 + 54 + Next thing, open the device file, as follows:: 55 + 56 + int file; 57 + 58 + file = open("/dev/hsmp", O_RDWR); 59 + if (file < 0) { 60 + /* ERROR HANDLING; you can check errno to see what went wrong */ 61 + exit(1); 62 + } 63 + 64 + The following IOCTL is defined: 65 + 66 + ``ioctl(file, HSMP_IOCTL_CMD, struct hsmp_message *msg)`` 67 + The argument is a pointer to a:: 68 + 69 + struct hsmp_message { 70 + __u32 msg_id; /* Message ID */ 71 + __u16 num_args; /* Number of input argument words in message */ 72 + __u16 response_sz; /* Number of expected output/response words */ 73 + __u32 args[HSMP_MAX_MSG_LEN]; /* argument/response buffer */ 74 + __u16 sock_ind; /* socket number */ 75 + }; 76 + 77 + The ioctl would return a non-zero on failure; you can read errno to see 78 + what happened. The transaction returns 0 on success. 79 + 80 + More details on the interface and message definitions can be found in chapter 81 + "7 Host System Management Port (HSMP)" of the respective family/model PPR 82 + eg: https://www.amd.com/system/files/TechDocs/55898_B1_pub_0.50.zip 83 + 84 + User space C-APIs are made available by linking against the esmi library, 85 + which is provided by the E-SMS project https://developer.amd.com/e-sms/. 86 + See: https://github.com/amd/esmi_ib_library
+1
Documentation/x86/index.rst
··· 25 25 intel-iommu 26 26 intel_txt 27 27 amd-memory-encryption 28 + amd_hsmp 28 29 pti 29 30 mds 30 31 microcode
+18 -1
MAINTAINERS
··· 989 989 S: Maintained 990 990 F: drivers/platform/x86/amd-pmc.* 991 991 992 + AMD HSMP DRIVER 993 + M: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com> 994 + R: Carlos Bilbao <carlos.bilbao@amd.com> 995 + L: platform-driver-x86@vger.kernel.org 996 + S: Maintained 997 + F: Documentation/x86/amd_hsmp.rst 998 + F: arch/x86/include/asm/amd_hsmp.h 999 + F: arch/x86/include/uapi/asm/amd_hsmp.h 1000 + F: drivers/platform/x86/amd_hsmp.c 1001 + 992 1002 AMD POWERPLAY AND SWSMU 993 1003 M: Evan Quan <evan.quan@amd.com> 994 1004 L: amd-gfx@lists.freedesktop.org ··· 9944 9934 F: arch/x86/include/asm/intel_scu_ipc.h 9945 9935 F: drivers/platform/x86/intel_scu_* 9946 9936 9937 + INTEL SDSI DRIVER 9938 + M: David E. Box <david.e.box@linux.intel.com> 9939 + S: Supported 9940 + F: drivers/platform/x86/intel/sdsi.c 9941 + F: tools/arch/x86/intel_sdsi/ 9942 + F: tools/testing/selftests/drivers/sdsi/ 9943 + 9947 9944 INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER 9948 9945 M: Daniel Scally <djrscally@gmail.com> 9949 9946 S: Maintained ··· 9987 9970 M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 9988 9971 L: platform-driver-x86@vger.kernel.org 9989 9972 S: Maintained 9990 - F: drivers/platform/x86/intel/uncore-frequency.c 9973 + F: drivers/platform/x86/intel/uncore-frequency/ 9991 9974 9992 9975 INTEL VENDOR SPECIFIC EXTENDED CAPABILITIES DRIVER 9993 9976 M: David E. Box <david.e.box@linux.intel.com>
+16
arch/x86/include/asm/amd_hsmp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + 3 + #ifndef _ASM_X86_AMD_HSMP_H_ 4 + #define _ASM_X86_AMD_HSMP_H_ 5 + 6 + #include <uapi/asm/amd_hsmp.h> 7 + 8 + #if IS_ENABLED(CONFIG_AMD_HSMP) 9 + int hsmp_send_message(struct hsmp_message *msg); 10 + #else 11 + static inline int hsmp_send_message(struct hsmp_message *msg) 12 + { 13 + return -ENODEV; 14 + } 15 + #endif 16 + #endif /*_ASM_X86_AMD_HSMP_H_*/
+203
arch/x86/include/uapi/asm/amd_hsmp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + 3 + #ifndef _UAPI_ASM_X86_AMD_HSMP_H_ 4 + #define _UAPI_ASM_X86_AMD_HSMP_H_ 5 + 6 + #include <linux/types.h> 7 + 8 + #pragma pack(4) 9 + 10 + #define HSMP_MAX_MSG_LEN 8 11 + 12 + /* 13 + * HSMP Messages supported 14 + */ 15 + enum hsmp_message_ids { 16 + HSMP_TEST = 1, /* 01h Increments input value by 1 */ 17 + HSMP_GET_SMU_VER, /* 02h SMU FW version */ 18 + HSMP_GET_PROTO_VER, /* 03h HSMP interface version */ 19 + HSMP_GET_SOCKET_POWER, /* 04h average package power consumption */ 20 + HSMP_SET_SOCKET_POWER_LIMIT, /* 05h Set the socket power limit */ 21 + HSMP_GET_SOCKET_POWER_LIMIT, /* 06h Get current socket power limit */ 22 + HSMP_GET_SOCKET_POWER_LIMIT_MAX,/* 07h Get maximum socket power value */ 23 + HSMP_SET_BOOST_LIMIT, /* 08h Set a core maximum frequency limit */ 24 + HSMP_SET_BOOST_LIMIT_SOCKET, /* 09h Set socket maximum frequency level */ 25 + HSMP_GET_BOOST_LIMIT, /* 0Ah Get current frequency limit */ 26 + HSMP_GET_PROC_HOT, /* 0Bh Get PROCHOT status */ 27 + HSMP_SET_XGMI_LINK_WIDTH, /* 0Ch Set max and min width of xGMI Link */ 28 + HSMP_SET_DF_PSTATE, /* 0Dh Alter APEnable/Disable messages behavior */ 29 + HSMP_SET_AUTO_DF_PSTATE, /* 0Eh Enable DF P-State Performance Boost algorithm */ 30 + HSMP_GET_FCLK_MCLK, /* 0Fh Get FCLK and MEMCLK for current socket */ 31 + HSMP_GET_CCLK_THROTTLE_LIMIT, /* 10h Get CCLK frequency limit in socket */ 32 + HSMP_GET_C0_PERCENT, /* 11h Get average C0 residency in socket */ 33 + HSMP_SET_NBIO_DPM_LEVEL, /* 12h Set max/min LCLK DPM Level for a given NBIO */ 34 + /* 13h Reserved */ 35 + HSMP_GET_DDR_BANDWIDTH = 0x14, /* 14h Get theoretical maximum and current DDR Bandwidth */ 36 + HSMP_GET_TEMP_MONITOR, /* 15h Get per-DIMM temperature and refresh rates */ 37 + HSMP_MSG_ID_MAX, 38 + }; 39 + 40 + struct hsmp_message { 41 + __u32 msg_id; /* Message ID */ 42 + __u16 num_args; /* Number of input argument words in message */ 43 + __u16 response_sz; /* Number of expected output/response words */ 44 + __u32 args[HSMP_MAX_MSG_LEN]; /* argument/response buffer */ 45 + __u16 sock_ind; /* socket number */ 46 + }; 47 + 48 + enum hsmp_msg_type { 49 + HSMP_RSVD = -1, 50 + HSMP_SET = 0, 51 + HSMP_GET = 1, 52 + }; 53 + 54 + struct hsmp_msg_desc { 55 + int num_args; 56 + int response_sz; 57 + enum hsmp_msg_type type; 58 + }; 59 + 60 + /* 61 + * User may use these comments as reference, please find the 62 + * supported list of messages and message definition in the 63 + * HSMP chapter of respective family/model PPR. 64 + * 65 + * Not supported messages would return -ENOMSG. 66 + */ 67 + static const struct hsmp_msg_desc hsmp_msg_desc_table[] = { 68 + /* RESERVED */ 69 + {0, 0, HSMP_RSVD}, 70 + 71 + /* 72 + * HSMP_TEST, num_args = 1, response_sz = 1 73 + * input: args[0] = xx 74 + * output: args[0] = xx + 1 75 + */ 76 + {1, 1, HSMP_GET}, 77 + 78 + /* 79 + * HSMP_GET_SMU_VER, num_args = 0, response_sz = 1 80 + * output: args[0] = smu fw ver 81 + */ 82 + {0, 1, HSMP_GET}, 83 + 84 + /* 85 + * HSMP_GET_PROTO_VER, num_args = 0, response_sz = 1 86 + * output: args[0] = proto version 87 + */ 88 + {0, 1, HSMP_GET}, 89 + 90 + /* 91 + * HSMP_GET_SOCKET_POWER, num_args = 0, response_sz = 1 92 + * output: args[0] = socket power in mWatts 93 + */ 94 + {0, 1, HSMP_GET}, 95 + 96 + /* 97 + * HSMP_SET_SOCKET_POWER_LIMIT, num_args = 1, response_sz = 0 98 + * input: args[0] = power limit value in mWatts 99 + */ 100 + {1, 0, HSMP_SET}, 101 + 102 + /* 103 + * HSMP_GET_SOCKET_POWER_LIMIT, num_args = 0, response_sz = 1 104 + * output: args[0] = socket power limit value in mWatts 105 + */ 106 + {0, 1, HSMP_GET}, 107 + 108 + /* 109 + * HSMP_GET_SOCKET_POWER_LIMIT_MAX, num_args = 0, response_sz = 1 110 + * output: args[0] = maximuam socket power limit in mWatts 111 + */ 112 + {0, 1, HSMP_GET}, 113 + 114 + /* 115 + * HSMP_SET_BOOST_LIMIT, num_args = 1, response_sz = 0 116 + * input: args[0] = apic id[31:16] + boost limit value in MHz[15:0] 117 + */ 118 + {1, 0, HSMP_SET}, 119 + 120 + /* 121 + * HSMP_SET_BOOST_LIMIT_SOCKET, num_args = 1, response_sz = 0 122 + * input: args[0] = boost limit value in MHz 123 + */ 124 + {1, 0, HSMP_SET}, 125 + 126 + /* 127 + * HSMP_GET_BOOST_LIMIT, num_args = 1, response_sz = 1 128 + * input: args[0] = apic id 129 + * output: args[0] = boost limit value in MHz 130 + */ 131 + {1, 1, HSMP_GET}, 132 + 133 + /* 134 + * HSMP_GET_PROC_HOT, num_args = 0, response_sz = 1 135 + * output: args[0] = proc hot status 136 + */ 137 + {0, 1, HSMP_GET}, 138 + 139 + /* 140 + * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0 141 + * input: args[0] = min link width[15:8] + max link width[7:0] 142 + */ 143 + {1, 0, HSMP_SET}, 144 + 145 + /* 146 + * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0 147 + * input: args[0] = df pstate[7:0] 148 + */ 149 + {1, 0, HSMP_SET}, 150 + 151 + /* HSMP_SET_AUTO_DF_PSTATE, num_args = 0, response_sz = 0 */ 152 + {0, 0, HSMP_SET}, 153 + 154 + /* 155 + * HSMP_GET_FCLK_MCLK, num_args = 0, response_sz = 2 156 + * output: args[0] = fclk in MHz, args[1] = mclk in MHz 157 + */ 158 + {0, 2, HSMP_GET}, 159 + 160 + /* 161 + * HSMP_GET_CCLK_THROTTLE_LIMIT, num_args = 0, response_sz = 1 162 + * output: args[0] = core clock in MHz 163 + */ 164 + {0, 1, HSMP_GET}, 165 + 166 + /* 167 + * HSMP_GET_C0_PERCENT, num_args = 0, response_sz = 1 168 + * output: args[0] = average c0 residency 169 + */ 170 + {0, 1, HSMP_GET}, 171 + 172 + /* 173 + * HSMP_SET_NBIO_DPM_LEVEL, num_args = 1, response_sz = 0 174 + * input: args[0] = nbioid[23:16] + max dpm level[15:8] + min dpm level[7:0] 175 + */ 176 + {1, 0, HSMP_SET}, 177 + 178 + /* RESERVED message */ 179 + {0, 0, HSMP_RSVD}, 180 + 181 + /* 182 + * HSMP_GET_DDR_BANDWIDTH, num_args = 0, response_sz = 1 183 + * output: args[0] = max bw in Gbps[31:20] + utilised bw in Gbps[19:8] + 184 + * bw in percentage[7:0] 185 + */ 186 + {0, 1, HSMP_GET}, 187 + 188 + /* 189 + * HSMP_GET_TEMP_MONITOR, num_args = 0, response_sz = 1 190 + * output: args[0] = temperature in degree celsius. [15:8] integer part + 191 + * [7:5] fractional part 192 + */ 193 + {0, 1, HSMP_GET}, 194 + }; 195 + 196 + /* Reset to default packing */ 197 + #pragma pack() 198 + 199 + /* Define unique ioctl command for hsmp msgs using generic _IOWR */ 200 + #define HSMP_BASE_IOCTL_NR 0xF8 201 + #define HSMP_IOCTL_CMD _IOWR(HSMP_BASE_IOCTL_NR, 0, struct hsmp_message) 202 + 203 + #endif /*_ASM_X86_AMD_HSMP_H_*/
+5
drivers/acpi/scan.c
··· 1751 1751 /* Non-conforming _HID for Cirrus Logic already released */ 1752 1752 {"CLSA0100", }, 1753 1753 /* 1754 + * Some ACPI devs contain SerialBus resources even though they are not 1755 + * attached to a serial bus at all. 1756 + */ 1757 + {"MSHW0028", }, 1758 + /* 1754 1759 * HIDs of device with an UartSerialBusV2 resource for which userspace 1755 1760 * expects a regular tty cdev to be created (instead of the in kernel 1756 1761 * serdev) and which have a kernel driver which expects a platform_dev
+40
drivers/acpi/x86/s2idle.c
··· 86 86 int min_dstate; 87 87 }; 88 88 89 + static LIST_HEAD(lps0_s2idle_devops_head); 90 + 89 91 static struct lpi_constraints *lpi_constraints_table; 90 92 static int lpi_constraints_table_size; 91 93 static int rev_id; ··· 442 440 443 441 int acpi_s2idle_prepare_late(void) 444 442 { 443 + struct acpi_s2idle_dev_ops *handler; 444 + 445 445 if (!lps0_device_handle || sleep_no_lps0) 446 446 return 0; 447 447 ··· 474 470 acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY, 475 471 lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); 476 472 } 473 + 474 + list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) { 475 + if (handler->prepare) 476 + handler->prepare(); 477 + } 478 + 477 479 return 0; 478 480 } 479 481 480 482 void acpi_s2idle_restore_early(void) 481 483 { 484 + struct acpi_s2idle_dev_ops *handler; 485 + 482 486 if (!lps0_device_handle || sleep_no_lps0) 483 487 return; 488 + 489 + list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) 490 + if (handler->restore) 491 + handler->restore(); 484 492 485 493 /* Modern standby exit */ 486 494 if (lps0_dsm_func_mask_microsoft > 0) ··· 535 519 acpi_scan_add_handler(&lps0_handler); 536 520 s2idle_set_ops(&acpi_s2idle_ops_lps0); 537 521 } 522 + 523 + int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg) 524 + { 525 + if (!lps0_device_handle || sleep_no_lps0) 526 + return -ENODEV; 527 + 528 + lock_system_sleep(); 529 + list_add(&arg->list_node, &lps0_s2idle_devops_head); 530 + unlock_system_sleep(); 531 + 532 + return 0; 533 + } 534 + EXPORT_SYMBOL_GPL(acpi_register_lps0_dev); 535 + 536 + void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg) 537 + { 538 + if (!lps0_device_handle || sleep_no_lps0) 539 + return; 540 + 541 + lock_system_sleep(); 542 + list_del(&arg->list_node); 543 + unlock_system_sleep(); 544 + } 545 + EXPORT_SYMBOL_GPL(acpi_unregister_lps0_dev); 538 546 539 547 #endif /* CONFIG_SUSPEND */
+23 -1
drivers/input/misc/soc_button_array.c
··· 470 470 }; 471 471 472 472 /* 473 + * Button info for Microsoft Surface 3 (non pro), this is indentical to 474 + * the PNP0C40 info except that the home button is active-high. 475 + * 476 + * The Surface 3 Pro also has a MSHW0028 ACPI device, but that uses a custom 477 + * version of the drivers/platform/x86/intel/hid.c 5 button array ACPI API 478 + * instead. A check() callback is not necessary though as the Surface 3 Pro 479 + * MSHW0028 ACPI device's resource table does not contain any GPIOs. 480 + */ 481 + static const struct soc_button_info soc_button_MSHW0028[] = { 482 + { "power", 0, EV_KEY, KEY_POWER, false, true, true }, 483 + { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false }, 484 + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true }, 485 + { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true }, 486 + { } 487 + }; 488 + 489 + static const struct soc_device_data soc_device_MSHW0028 = { 490 + .button_info = soc_button_MSHW0028, 491 + }; 492 + 493 + /* 473 494 * Special device check for Surface Book 2 and Surface Pro (2017). 474 495 * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned 475 496 * devices use MSHW0040 for power and volume buttons, however the way they ··· 556 535 { "ID9001", (unsigned long)&soc_device_INT33D3 }, 557 536 { "ACPI0011", 0 }, 558 537 559 - /* Microsoft Surface Devices (5th and 6th generation) */ 538 + /* Microsoft Surface Devices (3th, 5th and 6th generation) */ 539 + { "MSHW0028", (unsigned long)&soc_device_MSHW0028 }, 560 540 { "MSHW0040", (unsigned long)&soc_device_MSHW0040 }, 561 541 562 542 { }
+10
drivers/pinctrl/intel/pinctrl-baytrail.c
··· 443 443 static const unsigned int byt_sus_pcu_spi_mode_values[] = { 0 }; 444 444 static const unsigned int byt_sus_pcu_spi_gpio_mode_values[] = { 1 }; 445 445 446 + static const unsigned int byt_sus_pmu_clk1_pins[] = { 5 }; 447 + static const unsigned int byt_sus_pmu_clk2_pins[] = { 6 }; 448 + 446 449 static const struct intel_pingroup byt_sus_groups[] = { 447 450 PIN_GROUP("usb_oc_grp", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_mode_values), 448 451 PIN_GROUP("usb_ulpi_grp", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_mode_values), ··· 453 450 PIN_GROUP("usb_oc_grp_gpio", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_gpio_mode_values), 454 451 PIN_GROUP("usb_ulpi_grp_gpio", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_gpio_mode_values), 455 452 PIN_GROUP("pcu_spi_grp_gpio", byt_sus_pcu_spi_pins, byt_sus_pcu_spi_gpio_mode_values), 453 + PIN_GROUP("pmu_clk1_grp", byt_sus_pmu_clk1_pins, 1), 454 + PIN_GROUP("pmu_clk2_grp", byt_sus_pmu_clk2_pins, 1), 456 455 }; 457 456 458 457 static const char * const byt_sus_usb_groups[] = { 459 458 "usb_oc_grp", "usb_ulpi_grp", 460 459 }; 461 460 static const char * const byt_sus_spi_groups[] = { "pcu_spi_grp" }; 461 + static const char * const byt_sus_pmu_clk_groups[] = { 462 + "pmu_clk1_grp", "pmu_clk2_grp", 463 + }; 462 464 static const char * const byt_sus_gpio_groups[] = { 463 465 "usb_oc_grp_gpio", "usb_ulpi_grp_gpio", "pcu_spi_grp_gpio", 466 + "pmu_clk1_grp", "pmu_clk2_grp", 464 467 }; 465 468 466 469 static const struct intel_function byt_sus_functions[] = { 467 470 FUNCTION("usb", byt_sus_usb_groups), 468 471 FUNCTION("spi", byt_sus_spi_groups), 469 472 FUNCTION("gpio", byt_sus_gpio_groups), 473 + FUNCTION("pmu_clk", byt_sus_pmu_clk_groups), 470 474 }; 471 475 472 476 static const struct intel_community byt_sus_communities[] = {
-7
drivers/platform/surface/Kconfig
··· 28 28 To compile this driver as a module, choose M here: the module will 29 29 be called surface3-wmi. 30 30 31 - config SURFACE_3_BUTTON 32 - tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet" 33 - depends on ACPI 34 - depends on KEYBOARD_GPIO && I2C 35 - help 36 - This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet. 37 - 38 31 config SURFACE_3_POWER_OPREGION 39 32 tristate "Surface 3 battery platform operation region support" 40 33 depends on ACPI
-1
drivers/platform/surface/Makefile
··· 5 5 # 6 6 7 7 obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o 8 - obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o 9 8 obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o 10 9 obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o 11 10 obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
+5 -12
drivers/platform/surface/surface3-wmi.c
··· 116 116 void *data, 117 117 void **return_value) 118 118 { 119 - struct acpi_device *adev, **ts_adev; 119 + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 120 + struct acpi_device **ts_adev = data; 120 121 121 - if (acpi_bus_get_device(handle, &adev)) 122 - return AE_OK; 123 - 124 - ts_adev = data; 125 - 126 - if (strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME, 127 - strlen(SPI_TS_OBJ_NAME))) 122 + if (!adev || strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME, 123 + strlen(SPI_TS_OBJ_NAME))) 128 124 return AE_OK; 129 125 130 126 if (*ts_adev) { ··· 186 190 187 191 error = input_register_device(input); 188 192 if (error) 189 - goto out_err; 193 + return error; 190 194 191 195 s3_wmi.input = input; 192 196 193 197 return 0; 194 - out_err: 195 - input_free_device(s3_wmi.input); 196 - return error; 197 198 } 198 199 199 200 static int __init s3_wmi_probe(struct platform_device *pdev)
-247
drivers/platform/surface/surface3_button.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* 3 - * Supports for the button array on the Surface tablets. 4 - * 5 - * (C) Copyright 2016 Red Hat, Inc 6 - * 7 - * Based on soc_button_array.c: 8 - * 9 - * {C} Copyright 2014 Intel Corporation 10 - */ 11 - 12 - #include <linux/module.h> 13 - #include <linux/input.h> 14 - #include <linux/init.h> 15 - #include <linux/kernel.h> 16 - #include <linux/i2c.h> 17 - #include <linux/slab.h> 18 - #include <linux/acpi.h> 19 - #include <linux/gpio/consumer.h> 20 - #include <linux/gpio_keys.h> 21 - #include <linux/gpio.h> 22 - #include <linux/platform_device.h> 23 - 24 - 25 - #define SURFACE_BUTTON_OBJ_NAME "TEV2" 26 - #define MAX_NBUTTONS 4 27 - 28 - /* 29 - * Some of the buttons like volume up/down are auto repeat, while others 30 - * are not. To support both, we register two platform devices, and put 31 - * buttons into them based on whether the key should be auto repeat. 32 - */ 33 - #define BUTTON_TYPES 2 34 - 35 - /* 36 - * Power button, Home button, Volume buttons support is supposed to 37 - * be covered by drivers/input/misc/soc_button_array.c, which is implemented 38 - * according to "Windows ACPI Design Guide for SoC Platforms". 39 - * However surface 3 seems not to obey the specs, instead it uses 40 - * device TEV2(MSHW0028) for declaring the GPIOs. The gpios are also slightly 41 - * different in which the Home button is active high. 42 - * Compared to surfacepro3_button.c which also handles MSHW0028, the Surface 3 43 - * is a reduce platform and thus uses GPIOs, not ACPI events. 44 - * We choose an I2C driver here because we need to access the resources 45 - * declared under the device node, while surfacepro3_button.c only needs 46 - * the ACPI companion node. 47 - */ 48 - static const struct acpi_device_id surface3_acpi_match[] = { 49 - { "MSHW0028", 0 }, 50 - { } 51 - }; 52 - MODULE_DEVICE_TABLE(acpi, surface3_acpi_match); 53 - 54 - struct surface3_button_info { 55 - const char *name; 56 - int acpi_index; 57 - unsigned int event_type; 58 - unsigned int event_code; 59 - bool autorepeat; 60 - bool wakeup; 61 - bool active_low; 62 - }; 63 - 64 - struct surface3_button_data { 65 - struct platform_device *children[BUTTON_TYPES]; 66 - }; 67 - 68 - /* 69 - * Get the Nth GPIO number from the ACPI object. 70 - */ 71 - static int surface3_button_lookup_gpio(struct device *dev, int acpi_index) 72 - { 73 - struct gpio_desc *desc; 74 - int gpio; 75 - 76 - desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS); 77 - if (IS_ERR(desc)) 78 - return PTR_ERR(desc); 79 - 80 - gpio = desc_to_gpio(desc); 81 - 82 - gpiod_put(desc); 83 - 84 - return gpio; 85 - } 86 - 87 - static struct platform_device * 88 - surface3_button_device_create(struct i2c_client *client, 89 - const struct surface3_button_info *button_info, 90 - bool autorepeat) 91 - { 92 - const struct surface3_button_info *info; 93 - struct platform_device *pd; 94 - struct gpio_keys_button *gpio_keys; 95 - struct gpio_keys_platform_data *gpio_keys_pdata; 96 - int n_buttons = 0; 97 - int gpio; 98 - int error; 99 - 100 - gpio_keys_pdata = devm_kzalloc(&client->dev, 101 - sizeof(*gpio_keys_pdata) + 102 - sizeof(*gpio_keys) * MAX_NBUTTONS, 103 - GFP_KERNEL); 104 - if (!gpio_keys_pdata) 105 - return ERR_PTR(-ENOMEM); 106 - 107 - gpio_keys = (void *)(gpio_keys_pdata + 1); 108 - 109 - for (info = button_info; info->name; info++) { 110 - if (info->autorepeat != autorepeat) 111 - continue; 112 - 113 - gpio = surface3_button_lookup_gpio(&client->dev, 114 - info->acpi_index); 115 - if (!gpio_is_valid(gpio)) 116 - continue; 117 - 118 - gpio_keys[n_buttons].type = info->event_type; 119 - gpio_keys[n_buttons].code = info->event_code; 120 - gpio_keys[n_buttons].gpio = gpio; 121 - gpio_keys[n_buttons].active_low = info->active_low; 122 - gpio_keys[n_buttons].desc = info->name; 123 - gpio_keys[n_buttons].wakeup = info->wakeup; 124 - n_buttons++; 125 - } 126 - 127 - if (n_buttons == 0) { 128 - error = -ENODEV; 129 - goto err_free_mem; 130 - } 131 - 132 - gpio_keys_pdata->buttons = gpio_keys; 133 - gpio_keys_pdata->nbuttons = n_buttons; 134 - gpio_keys_pdata->rep = autorepeat; 135 - 136 - pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO); 137 - if (!pd) { 138 - error = -ENOMEM; 139 - goto err_free_mem; 140 - } 141 - 142 - error = platform_device_add_data(pd, gpio_keys_pdata, 143 - sizeof(*gpio_keys_pdata)); 144 - if (error) 145 - goto err_free_pdev; 146 - 147 - error = platform_device_add(pd); 148 - if (error) 149 - goto err_free_pdev; 150 - 151 - return pd; 152 - 153 - err_free_pdev: 154 - platform_device_put(pd); 155 - err_free_mem: 156 - devm_kfree(&client->dev, gpio_keys_pdata); 157 - return ERR_PTR(error); 158 - } 159 - 160 - static int surface3_button_remove(struct i2c_client *client) 161 - { 162 - struct surface3_button_data *priv = i2c_get_clientdata(client); 163 - 164 - int i; 165 - 166 - for (i = 0; i < BUTTON_TYPES; i++) 167 - if (priv->children[i]) 168 - platform_device_unregister(priv->children[i]); 169 - 170 - return 0; 171 - } 172 - 173 - static struct surface3_button_info surface3_button_surface3[] = { 174 - { "power", 0, EV_KEY, KEY_POWER, false, true, true }, 175 - { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false }, 176 - { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true }, 177 - { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true }, 178 - { } 179 - }; 180 - 181 - static int surface3_button_probe(struct i2c_client *client, 182 - const struct i2c_device_id *id) 183 - { 184 - struct device *dev = &client->dev; 185 - struct surface3_button_data *priv; 186 - struct platform_device *pd; 187 - int i; 188 - int error; 189 - 190 - if (strncmp(acpi_device_bid(ACPI_COMPANION(&client->dev)), 191 - SURFACE_BUTTON_OBJ_NAME, 192 - strlen(SURFACE_BUTTON_OBJ_NAME))) 193 - return -ENODEV; 194 - 195 - error = gpiod_count(dev, NULL); 196 - if (error < 0) { 197 - dev_dbg(dev, "no GPIO attached, ignoring...\n"); 198 - return error; 199 - } 200 - 201 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 202 - if (!priv) 203 - return -ENOMEM; 204 - 205 - i2c_set_clientdata(client, priv); 206 - 207 - for (i = 0; i < BUTTON_TYPES; i++) { 208 - pd = surface3_button_device_create(client, 209 - surface3_button_surface3, 210 - i == 0); 211 - if (IS_ERR(pd)) { 212 - error = PTR_ERR(pd); 213 - if (error != -ENODEV) { 214 - surface3_button_remove(client); 215 - return error; 216 - } 217 - continue; 218 - } 219 - 220 - priv->children[i] = pd; 221 - } 222 - 223 - if (!priv->children[0] && !priv->children[1]) 224 - return -ENODEV; 225 - 226 - return 0; 227 - } 228 - 229 - static const struct i2c_device_id surface3_id[] = { 230 - { } 231 - }; 232 - MODULE_DEVICE_TABLE(i2c, surface3_id); 233 - 234 - static struct i2c_driver surface3_driver = { 235 - .probe = surface3_button_probe, 236 - .remove = surface3_button_remove, 237 - .id_table = surface3_id, 238 - .driver = { 239 - .name = "surface3", 240 - .acpi_match_table = ACPI_PTR(surface3_acpi_match), 241 - }, 242 - }; 243 - module_i2c_driver(surface3_driver); 244 - 245 - MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 246 - MODULE_DESCRIPTION("surface3 button array driver"); 247 - MODULE_LICENSE("GPL v2");
+2 -1
drivers/platform/surface/surface_acpi_notify.c
··· 770 770 return AE_OK; 771 771 772 772 /* Ignore ACPI devices that are not present. */ 773 - if (acpi_bus_get_device(handle, &adev) != 0) 773 + adev = acpi_fetch_acpi_dev(handle); 774 + if (!adev) 774 775 return AE_OK; 775 776 776 777 san_consumer_dbg(&pdev->dev, handle, "creating device link\n");
+15 -1
drivers/platform/x86/Kconfig
··· 210 210 If you choose to compile this driver as a module the module will be 211 211 called amd-pmc. 212 212 213 + config AMD_HSMP 214 + tristate "AMD HSMP Driver" 215 + depends on AMD_NB && X86_64 216 + help 217 + The driver provides a way for user space tools to monitor and manage 218 + system management functionality on EPYC server CPUs from AMD. 219 + 220 + Host System Management Port (HSMP) interface is a mailbox interface 221 + between the x86 core and the System Management Unit (SMU) firmware. 222 + 223 + If you choose to compile this driver as a module the module will be 224 + called amd_hsmp. 225 + 213 226 config ADV_SWBUTTON 214 227 tristate "Advantech ACPI Software Button Driver" 215 228 depends on ACPI && INPUT ··· 928 915 config LG_LAPTOP 929 916 tristate "LG Laptop Extras" 930 917 depends on ACPI 918 + depends on ACPI_BATTERY 931 919 depends on ACPI_WMI 932 920 depends on INPUT 933 921 select INPUT_SPARSEKMAP ··· 1041 1027 1042 1028 config X86_ANDROID_TABLETS 1043 1029 tristate "X86 Android tablet support" 1044 - depends on I2C && SERIAL_DEV_BUS && ACPI && GPIOLIB 1030 + depends on I2C && SPI && SERIAL_DEV_BUS && ACPI && EFI && GPIOLIB 1045 1031 help 1046 1032 X86 tablets which ship with Android as (part of) the factory image 1047 1033 typically have various problems with their DSDTs. The factory kernels
+1
drivers/platform/x86/Makefile
··· 24 24 25 25 # AMD 26 26 obj-$(CONFIG_AMD_PMC) += amd-pmc.o 27 + obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o 27 28 28 29 # Advantech 29 30 obj-$(CONFIG_ADV_SWBUTTON) += adv_swbutton.o
+184 -66
drivers/platform/x86/amd-pmc.c
··· 21 21 #include <linux/module.h> 22 22 #include <linux/pci.h> 23 23 #include <linux/platform_device.h> 24 - #include <linux/pm_qos.h> 25 24 #include <linux/rtc.h> 26 25 #include <linux/suspend.h> 27 26 #include <linux/seq_file.h> ··· 40 41 #define AMD_PMC_STB_INDEX_DATA 0xFC 41 42 #define AMD_PMC_STB_PMI_0 0x03E30600 42 43 #define AMD_PMC_STB_PREDEF 0xC6000001 44 + 45 + /* STB S2D(Spill to DRAM) has different message port offset */ 46 + #define STB_SPILL_TO_DRAM 0xBE 47 + #define AMD_S2D_REGISTER_MESSAGE 0xA20 48 + #define AMD_S2D_REGISTER_RESPONSE 0xA80 49 + #define AMD_S2D_REGISTER_ARGUMENT 0xA88 50 + 51 + /* STB Spill to DRAM Parameters */ 52 + #define S2D_TELEMETRY_BYTES_MAX 0x100000 53 + #define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 43 54 44 55 /* Base address of SMU for mapping physical address to virtual address */ 45 56 #define AMD_PMC_SMU_INDEX_ADDRESS 0xB8 ··· 95 86 #define PMC_MSG_DELAY_MIN_US 50 96 87 #define RESPONSE_REGISTER_LOOP_MAX 20000 97 88 98 - /* QoS request for letting CPUs in idle states, but not the deepest */ 99 - #define AMD_PMC_MAX_IDLE_STATE_LATENCY 3 100 - 101 89 #define SOC_SUBSYSTEM_IP_MAX 12 102 90 #define DELAY_MIN_US 2000 103 91 #define DELAY_MAX_US 3000 ··· 103 97 MSG_TEST = 0x01, 104 98 MSG_OS_HINT_PCO, 105 99 MSG_OS_HINT_RN, 100 + }; 101 + 102 + enum s2d_arg { 103 + S2D_TELEMETRY_SIZE = 0x01, 104 + S2D_PHYS_ADDR_LOW, 105 + S2D_PHYS_ADDR_HIGH, 106 106 }; 107 107 108 108 struct amd_pmc_bit_map { ··· 135 123 struct amd_pmc_dev { 136 124 void __iomem *regbase; 137 125 void __iomem *smu_virt_addr; 126 + void __iomem *stb_virt_addr; 138 127 void __iomem *fch_virt_addr; 128 + bool msg_port; 139 129 u32 base_addr; 140 130 u32 cpu_id; 141 131 u32 active_ips; ··· 149 135 struct device *dev; 150 136 struct pci_dev *rdev; 151 137 struct mutex lock; /* generic mutex lock */ 152 - struct pm_qos_request amd_pmc_pm_qos_req; 153 138 #if IS_ENABLED(CONFIG_DEBUG_FS) 154 139 struct dentry *dbgfs_dir; 155 140 #endif /* CONFIG_DEBUG_FS */ ··· 254 241 .release = amd_pmc_stb_debugfs_release, 255 242 }; 256 243 244 + static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) 245 + { 246 + struct amd_pmc_dev *dev = filp->f_inode->i_private; 247 + u32 *buf; 248 + 249 + buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL); 250 + if (!buf) 251 + return -ENOMEM; 252 + 253 + memcpy_fromio(buf, dev->stb_virt_addr, S2D_TELEMETRY_BYTES_MAX); 254 + filp->private_data = buf; 255 + 256 + return 0; 257 + } 258 + 259 + static ssize_t amd_pmc_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size, 260 + loff_t *pos) 261 + { 262 + if (!filp->private_data) 263 + return -EINVAL; 264 + 265 + return simple_read_from_buffer(buf, size, pos, filp->private_data, 266 + S2D_TELEMETRY_BYTES_MAX); 267 + } 268 + 269 + static int amd_pmc_stb_debugfs_release_v2(struct inode *inode, struct file *filp) 270 + { 271 + kfree(filp->private_data); 272 + return 0; 273 + } 274 + 275 + static const struct file_operations amd_pmc_stb_debugfs_fops_v2 = { 276 + .owner = THIS_MODULE, 277 + .open = amd_pmc_stb_debugfs_open_v2, 278 + .read = amd_pmc_stb_debugfs_read_v2, 279 + .release = amd_pmc_stb_debugfs_release_v2, 280 + }; 281 + 257 282 static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, 258 283 struct seq_file *s) 259 284 { ··· 317 266 return 0; 318 267 } 319 268 269 + static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table) 270 + { 271 + if (pdev->cpu_id == AMD_CPU_ID_PCO) 272 + return -ENODEV; 273 + memcpy_fromio(table, pdev->smu_virt_addr, sizeof(struct smu_metrics)); 274 + return 0; 275 + } 276 + 277 + static void amd_pmc_validate_deepest(struct amd_pmc_dev *pdev) 278 + { 279 + struct smu_metrics table; 280 + 281 + if (get_metrics_table(pdev, &table)) 282 + return; 283 + 284 + if (!table.s0i3_last_entry_status) 285 + dev_warn(pdev->dev, "Last suspend didn't reach deepest state\n"); 286 + else 287 + dev_dbg(pdev->dev, "Last suspend in deepest state for %lluus\n", 288 + table.timein_s0i3_lastcapture); 289 + } 290 + 320 291 #ifdef CONFIG_DEBUG_FS 321 292 static int smu_fw_info_show(struct seq_file *s, void *unused) 322 293 { ··· 346 273 struct smu_metrics table; 347 274 int idx; 348 275 349 - if (dev->cpu_id == AMD_CPU_ID_PCO) 276 + if (get_metrics_table(dev, &table)) 350 277 return -EINVAL; 351 - 352 - memcpy_fromio(&table, dev->smu_virt_addr, sizeof(struct smu_metrics)); 353 278 354 279 seq_puts(s, "\n=== SMU Statistics ===\n"); 355 280 seq_printf(s, "Table Version: %d\n", table.table_version); ··· 426 355 debugfs_create_file("amd_pmc_idlemask", 0644, dev->dbgfs_dir, dev, 427 356 &amd_pmc_idlemask_fops); 428 357 /* Enable STB only when the module_param is set */ 429 - if (enable_stb) 430 - debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, 431 - &amd_pmc_stb_debugfs_fops); 358 + if (enable_stb) { 359 + if (dev->cpu_id == AMD_CPU_ID_YC) 360 + debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, 361 + &amd_pmc_stb_debugfs_fops_v2); 362 + else 363 + debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, 364 + &amd_pmc_stb_debugfs_fops); 365 + } 432 366 } 433 367 #else 434 368 static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) ··· 473 397 474 398 static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) 475 399 { 476 - u32 value; 400 + u32 value, message, argument, response; 477 401 478 - value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_RESPONSE); 402 + if (dev->msg_port) { 403 + message = AMD_S2D_REGISTER_MESSAGE; 404 + argument = AMD_S2D_REGISTER_ARGUMENT; 405 + response = AMD_S2D_REGISTER_RESPONSE; 406 + } else { 407 + message = AMD_PMC_REGISTER_MESSAGE; 408 + argument = AMD_PMC_REGISTER_ARGUMENT; 409 + response = AMD_PMC_REGISTER_RESPONSE; 410 + } 411 + 412 + value = amd_pmc_reg_read(dev, response); 479 413 dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value); 480 414 481 - value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT); 415 + value = amd_pmc_reg_read(dev, argument); 482 416 dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value); 483 417 484 - value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_MESSAGE); 418 + value = amd_pmc_reg_read(dev, message); 485 419 dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value); 486 420 } 487 421 488 422 static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret) 489 423 { 490 424 int rc; 491 - u32 val; 425 + u32 val, message, argument, response; 492 426 493 427 mutex_lock(&dev->lock); 428 + 429 + if (dev->msg_port) { 430 + message = AMD_S2D_REGISTER_MESSAGE; 431 + argument = AMD_S2D_REGISTER_ARGUMENT; 432 + response = AMD_S2D_REGISTER_RESPONSE; 433 + } else { 434 + message = AMD_PMC_REGISTER_MESSAGE; 435 + argument = AMD_PMC_REGISTER_ARGUMENT; 436 + response = AMD_PMC_REGISTER_RESPONSE; 437 + } 438 + 494 439 /* Wait until we get a valid response */ 495 - rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE, 440 + rc = readx_poll_timeout(ioread32, dev->regbase + response, 496 441 val, val != 0, PMC_MSG_DELAY_MIN_US, 497 442 PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); 498 443 if (rc) { ··· 522 425 } 523 426 524 427 /* Write zero to response register */ 525 - amd_pmc_reg_write(dev, AMD_PMC_REGISTER_RESPONSE, 0); 428 + amd_pmc_reg_write(dev, response, 0); 526 429 527 430 /* Write argument into response register */ 528 - amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, arg); 431 + amd_pmc_reg_write(dev, argument, arg); 529 432 530 433 /* Write message ID to message ID register */ 531 - amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg); 434 + amd_pmc_reg_write(dev, message, msg); 532 435 533 436 /* Wait until we get a valid response */ 534 - rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE, 437 + rc = readx_poll_timeout(ioread32, dev->regbase + response, 535 438 val, val != 0, PMC_MSG_DELAY_MIN_US, 536 439 PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); 537 440 if (rc) { ··· 544 447 if (ret) { 545 448 /* PMFW may take longer time to return back the data */ 546 449 usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US); 547 - *data = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT); 450 + *data = amd_pmc_reg_read(dev, argument); 548 451 } 549 452 break; 550 453 case AMD_PMC_RESULT_CMD_REJECT_BUSY: ··· 623 526 rc = rtc_alarm_irq_enable(rtc_device, 0); 624 527 dev_dbg(pdev->dev, "wakeup timer programmed for %lld seconds\n", duration); 625 528 626 - /* 627 - * Prevent CPUs from getting into deep idle states while sending OS_HINT 628 - * which is otherwise generally safe to send when at least one of the CPUs 629 - * is not in deep idle states. 630 - */ 631 - cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req, AMD_PMC_MAX_IDLE_STATE_LATENCY); 632 - wake_up_all_idle_cpus(); 633 - 634 529 return rc; 635 530 } 636 531 637 - static int __maybe_unused amd_pmc_suspend(struct device *dev) 532 + static void amd_pmc_s2idle_prepare(void) 638 533 { 639 - struct amd_pmc_dev *pdev = dev_get_drvdata(dev); 534 + struct amd_pmc_dev *pdev = &pmc; 640 535 int rc; 641 536 u8 msg; 642 537 u32 arg = 1; ··· 640 551 /* Activate CZN specific RTC functionality */ 641 552 if (pdev->cpu_id == AMD_CPU_ID_CZN) { 642 553 rc = amd_pmc_verify_czn_rtc(pdev, &arg); 643 - if (rc) 644 - goto fail; 554 + if (rc) { 555 + dev_err(pdev->dev, "failed to set RTC: %d\n", rc); 556 + return; 557 + } 645 558 } 646 559 647 560 /* Dump the IdleMask before we send hint to SMU */ 648 - amd_pmc_idlemask_read(pdev, dev, NULL); 561 + amd_pmc_idlemask_read(pdev, pdev->dev, NULL); 649 562 msg = amd_pmc_get_os_hint(pdev); 650 563 rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0); 651 564 if (rc) { 652 - dev_err(pdev->dev, "suspend failed\n"); 653 - goto fail; 565 + dev_err(pdev->dev, "suspend failed: %d\n", rc); 566 + return; 654 567 } 655 568 656 - if (enable_stb) 569 + if (enable_stb) { 657 570 rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF); 658 - if (rc) { 659 - dev_err(pdev->dev, "error writing to STB\n"); 660 - goto fail; 571 + if (rc) 572 + dev_err(pdev->dev, "error writing to STB: %d\n", rc); 661 573 } 662 - 663 - return 0; 664 - fail: 665 - if (pdev->cpu_id == AMD_CPU_ID_CZN) 666 - cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req, 667 - PM_QOS_DEFAULT_VALUE); 668 - return rc; 669 574 } 670 575 671 - static int __maybe_unused amd_pmc_resume(struct device *dev) 576 + static void amd_pmc_s2idle_restore(void) 672 577 { 673 - struct amd_pmc_dev *pdev = dev_get_drvdata(dev); 578 + struct amd_pmc_dev *pdev = &pmc; 674 579 int rc; 675 580 u8 msg; 676 581 677 582 msg = amd_pmc_get_os_hint(pdev); 678 583 rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, 0); 679 584 if (rc) 680 - dev_err(pdev->dev, "resume failed\n"); 585 + dev_err(pdev->dev, "resume failed: %d\n", rc); 681 586 682 587 /* Let SMU know that we are looking for stats */ 683 588 amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0); 684 589 685 590 /* Dump the IdleMask to see the blockers */ 686 - amd_pmc_idlemask_read(pdev, dev, NULL); 591 + amd_pmc_idlemask_read(pdev, pdev->dev, NULL); 687 592 688 593 /* Write data incremented by 1 to distinguish in stb_read */ 689 - if (enable_stb) 594 + if (enable_stb) { 690 595 rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF + 1); 691 - if (rc) 692 - dev_err(pdev->dev, "error writing to STB\n"); 596 + if (rc) 597 + dev_err(pdev->dev, "error writing to STB: %d\n", rc); 598 + } 693 599 694 - /* Restore the QoS request back to defaults if it was set */ 695 - if (pdev->cpu_id == AMD_CPU_ID_CZN) 696 - cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req, 697 - PM_QOS_DEFAULT_VALUE); 698 - 699 - return rc; 600 + /* Notify on failed entry */ 601 + amd_pmc_validate_deepest(pdev); 700 602 } 701 603 702 - static const struct dev_pm_ops amd_pmc_pm_ops = { 703 - .suspend_noirq = amd_pmc_suspend, 704 - .resume_noirq = amd_pmc_resume, 604 + static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = { 605 + .prepare = amd_pmc_s2idle_prepare, 606 + .restore = amd_pmc_s2idle_restore, 705 607 }; 706 608 707 609 static const struct pci_device_id pmc_pci_ids[] = { ··· 703 623 { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) }, 704 624 { } 705 625 }; 626 + 627 + static int amd_pmc_s2d_init(struct amd_pmc_dev *dev) 628 + { 629 + u32 phys_addr_low, phys_addr_hi; 630 + u64 stb_phys_addr; 631 + u32 size = 0; 632 + 633 + /* Spill to DRAM feature uses separate SMU message port */ 634 + dev->msg_port = 1; 635 + 636 + amd_pmc_send_cmd(dev, S2D_TELEMETRY_SIZE, &size, STB_SPILL_TO_DRAM, 1); 637 + if (size != S2D_TELEMETRY_BYTES_MAX) 638 + return -EIO; 639 + 640 + /* Get STB DRAM address */ 641 + amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, STB_SPILL_TO_DRAM, 1); 642 + amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, STB_SPILL_TO_DRAM, 1); 643 + 644 + stb_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); 645 + 646 + /* Clear msg_port for other SMU operation */ 647 + dev->msg_port = 0; 648 + 649 + dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, S2D_TELEMETRY_DRAMBYTES_MAX); 650 + if (!dev->stb_virt_addr) 651 + return -ENOMEM; 652 + 653 + return 0; 654 + } 706 655 707 656 static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data) 708 657 { ··· 851 742 if (err) 852 743 dev_err(dev->dev, "SMU debugging info not supported on this platform\n"); 853 744 745 + if (enable_stb && dev->cpu_id == AMD_CPU_ID_YC) { 746 + err = amd_pmc_s2d_init(dev); 747 + if (err) 748 + return err; 749 + } 750 + 854 751 amd_pmc_get_smu_version(dev); 855 752 platform_set_drvdata(pdev, dev); 753 + err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops); 754 + if (err) 755 + dev_warn(dev->dev, "failed to register LPS0 sleep handler, expect increased power consumption\n"); 756 + 856 757 amd_pmc_dbgfs_register(dev); 857 - cpu_latency_qos_add_request(&dev->amd_pmc_pm_qos_req, PM_QOS_DEFAULT_VALUE); 858 758 return 0; 859 759 860 760 err_pci_dev_put: ··· 875 757 { 876 758 struct amd_pmc_dev *dev = platform_get_drvdata(pdev); 877 759 760 + acpi_unregister_lps0_dev(&amd_pmc_s2idle_dev_ops); 878 761 amd_pmc_dbgfs_unregister(dev); 879 762 pci_dev_put(dev->rdev); 880 763 mutex_destroy(&dev->lock); ··· 896 777 .driver = { 897 778 .name = "amd_pmc", 898 779 .acpi_match_table = amd_pmc_acpi_ids, 899 - .pm = &amd_pmc_pm_ops, 900 780 }, 901 781 .probe = amd_pmc_probe, 902 782 .remove = amd_pmc_remove,
+425
drivers/platform/x86/amd_hsmp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * AMD HSMP Platform Driver 4 + * Copyright (c) 2022, AMD. 5 + * All Rights Reserved. 6 + * 7 + * This file provides a device implementation for HSMP interface 8 + */ 9 + 10 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 + 12 + #include <asm/amd_hsmp.h> 13 + #include <asm/amd_nb.h> 14 + #include <linux/delay.h> 15 + #include <linux/io.h> 16 + #include <linux/miscdevice.h> 17 + #include <linux/module.h> 18 + #include <linux/pci.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/semaphore.h> 21 + 22 + #define DRIVER_NAME "amd_hsmp" 23 + #define DRIVER_VERSION "1.0" 24 + 25 + /* HSMP Status / Error codes */ 26 + #define HSMP_STATUS_NOT_READY 0x00 27 + #define HSMP_STATUS_OK 0x01 28 + #define HSMP_ERR_INVALID_MSG 0xFE 29 + #define HSMP_ERR_INVALID_INPUT 0xFF 30 + 31 + /* Timeout in millsec */ 32 + #define HSMP_MSG_TIMEOUT 100 33 + #define HSMP_SHORT_SLEEP 1 34 + 35 + #define HSMP_WR true 36 + #define HSMP_RD false 37 + 38 + /* 39 + * To access specific HSMP mailbox register, s/w writes the SMN address of HSMP mailbox 40 + * register into the SMN_INDEX register, and reads/writes the SMN_DATA reg. 41 + * Below are required SMN address for HSMP Mailbox register offsets in SMU address space 42 + */ 43 + #define SMN_HSMP_MSG_ID 0x3B10534 44 + #define SMN_HSMP_MSG_RESP 0x3B10980 45 + #define SMN_HSMP_MSG_DATA 0x3B109E0 46 + 47 + #define HSMP_INDEX_REG 0xc4 48 + #define HSMP_DATA_REG 0xc8 49 + 50 + static struct semaphore *hsmp_sem; 51 + 52 + static struct miscdevice hsmp_device; 53 + 54 + static int amd_hsmp_rdwr(struct pci_dev *root, u32 address, 55 + u32 *value, bool write) 56 + { 57 + int ret; 58 + 59 + ret = pci_write_config_dword(root, HSMP_INDEX_REG, address); 60 + if (ret) 61 + return ret; 62 + 63 + ret = (write ? pci_write_config_dword(root, HSMP_DATA_REG, *value) 64 + : pci_read_config_dword(root, HSMP_DATA_REG, value)); 65 + 66 + return ret; 67 + } 68 + 69 + /* 70 + * Send a message to the HSMP port via PCI-e config space registers. 71 + * 72 + * The caller is expected to zero out any unused arguments. 73 + * If a response is expected, the number of response words should be greater than 0. 74 + * 75 + * Returns 0 for success and populates the requested number of arguments. 76 + * Returns a negative error code for failure. 77 + */ 78 + static int __hsmp_send_message(struct pci_dev *root, struct hsmp_message *msg) 79 + { 80 + unsigned long timeout, short_sleep; 81 + u32 mbox_status; 82 + u32 index; 83 + int ret; 84 + 85 + /* Clear the status register */ 86 + mbox_status = HSMP_STATUS_NOT_READY; 87 + ret = amd_hsmp_rdwr(root, SMN_HSMP_MSG_RESP, &mbox_status, HSMP_WR); 88 + if (ret) { 89 + pr_err("Error %d clearing mailbox status register\n", ret); 90 + return ret; 91 + } 92 + 93 + index = 0; 94 + /* Write any message arguments */ 95 + while (index < msg->num_args) { 96 + ret = amd_hsmp_rdwr(root, SMN_HSMP_MSG_DATA + (index << 2), 97 + &msg->args[index], HSMP_WR); 98 + if (ret) { 99 + pr_err("Error %d writing message argument %d\n", ret, index); 100 + return ret; 101 + } 102 + index++; 103 + } 104 + 105 + /* Write the message ID which starts the operation */ 106 + ret = amd_hsmp_rdwr(root, SMN_HSMP_MSG_ID, &msg->msg_id, HSMP_WR); 107 + if (ret) { 108 + pr_err("Error %d writing message ID %u\n", ret, msg->msg_id); 109 + return ret; 110 + } 111 + 112 + /* 113 + * Depending on when the trigger write completes relative to the SMU 114 + * firmware 1 ms cycle, the operation may take from tens of us to 1 ms 115 + * to complete. Some operations may take more. Therefore we will try 116 + * a few short duration sleeps and switch to long sleeps if we don't 117 + * succeed quickly. 118 + */ 119 + short_sleep = jiffies + msecs_to_jiffies(HSMP_SHORT_SLEEP); 120 + timeout = jiffies + msecs_to_jiffies(HSMP_MSG_TIMEOUT); 121 + 122 + while (time_before(jiffies, timeout)) { 123 + ret = amd_hsmp_rdwr(root, SMN_HSMP_MSG_RESP, &mbox_status, HSMP_RD); 124 + if (ret) { 125 + pr_err("Error %d reading mailbox status\n", ret); 126 + return ret; 127 + } 128 + 129 + if (mbox_status != HSMP_STATUS_NOT_READY) 130 + break; 131 + if (time_before(jiffies, short_sleep)) 132 + usleep_range(50, 100); 133 + else 134 + usleep_range(1000, 2000); 135 + } 136 + 137 + if (unlikely(mbox_status == HSMP_STATUS_NOT_READY)) { 138 + return -ETIMEDOUT; 139 + } else if (unlikely(mbox_status == HSMP_ERR_INVALID_MSG)) { 140 + return -ENOMSG; 141 + } else if (unlikely(mbox_status == HSMP_ERR_INVALID_INPUT)) { 142 + return -EINVAL; 143 + } else if (unlikely(mbox_status != HSMP_STATUS_OK)) { 144 + pr_err("Message ID %u unknown failure (status = 0x%X)\n", 145 + msg->msg_id, mbox_status); 146 + return -EIO; 147 + } 148 + 149 + /* 150 + * SMU has responded OK. Read response data. 151 + * SMU reads the input arguments from eight 32 bit registers starting 152 + * from SMN_HSMP_MSG_DATA and writes the response data to the same 153 + * SMN_HSMP_MSG_DATA address. 154 + * We copy the response data if any, back to the args[]. 155 + */ 156 + index = 0; 157 + while (index < msg->response_sz) { 158 + ret = amd_hsmp_rdwr(root, SMN_HSMP_MSG_DATA + (index << 2), 159 + &msg->args[index], HSMP_RD); 160 + if (ret) { 161 + pr_err("Error %d reading response %u for message ID:%u\n", 162 + ret, index, msg->msg_id); 163 + break; 164 + } 165 + index++; 166 + } 167 + 168 + return ret; 169 + } 170 + 171 + static int validate_message(struct hsmp_message *msg) 172 + { 173 + /* msg_id against valid range of message IDs */ 174 + if (msg->msg_id < HSMP_TEST || msg->msg_id >= HSMP_MSG_ID_MAX) 175 + return -ENOMSG; 176 + 177 + /* msg_id is a reserved message ID */ 178 + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) 179 + return -ENOMSG; 180 + 181 + /* num_args and response_sz against the HSMP spec */ 182 + if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args || 183 + msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) 184 + return -EINVAL; 185 + 186 + return 0; 187 + } 188 + 189 + int hsmp_send_message(struct hsmp_message *msg) 190 + { 191 + struct amd_northbridge *nb; 192 + int ret; 193 + 194 + if (!msg) 195 + return -EINVAL; 196 + 197 + nb = node_to_amd_nb(msg->sock_ind); 198 + if (!nb || !nb->root) 199 + return -ENODEV; 200 + 201 + ret = validate_message(msg); 202 + if (ret) 203 + return ret; 204 + 205 + /* 206 + * The time taken by smu operation to complete is between 207 + * 10us to 1ms. Sometime it may take more time. 208 + * In SMP system timeout of 100 millisecs should 209 + * be enough for the previous thread to finish the operation 210 + */ 211 + ret = down_timeout(&hsmp_sem[msg->sock_ind], 212 + msecs_to_jiffies(HSMP_MSG_TIMEOUT)); 213 + if (ret < 0) 214 + return ret; 215 + 216 + ret = __hsmp_send_message(nb->root, msg); 217 + 218 + up(&hsmp_sem[msg->sock_ind]); 219 + 220 + return ret; 221 + } 222 + EXPORT_SYMBOL_GPL(hsmp_send_message); 223 + 224 + static int hsmp_test(u16 sock_ind, u32 value) 225 + { 226 + struct hsmp_message msg = { 0 }; 227 + struct amd_northbridge *nb; 228 + int ret = -ENODEV; 229 + 230 + nb = node_to_amd_nb(sock_ind); 231 + if (!nb || !nb->root) 232 + return ret; 233 + 234 + /* 235 + * Test the hsmp port by performing TEST command. The test message 236 + * takes one argument and returns the value of that argument + 1. 237 + */ 238 + msg.msg_id = HSMP_TEST; 239 + msg.num_args = 1; 240 + msg.response_sz = 1; 241 + msg.args[0] = value; 242 + msg.sock_ind = sock_ind; 243 + 244 + ret = __hsmp_send_message(nb->root, &msg); 245 + if (ret) 246 + return ret; 247 + 248 + /* Check the response value */ 249 + if (msg.args[0] != (value + 1)) { 250 + pr_err("Socket %d test message failed, Expected 0x%08X, received 0x%08X\n", 251 + sock_ind, (value + 1), msg.args[0]); 252 + return -EBADE; 253 + } 254 + 255 + return ret; 256 + } 257 + 258 + static long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) 259 + { 260 + int __user *arguser = (int __user *)arg; 261 + struct hsmp_message msg = { 0 }; 262 + int ret; 263 + 264 + if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) 265 + return -EFAULT; 266 + 267 + /* 268 + * Check msg_id is within the range of supported msg ids 269 + * i.e within the array bounds of hsmp_msg_desc_table 270 + */ 271 + if (msg.msg_id < HSMP_TEST || msg.msg_id >= HSMP_MSG_ID_MAX) 272 + return -ENOMSG; 273 + 274 + switch (fp->f_mode & (FMODE_WRITE | FMODE_READ)) { 275 + case FMODE_WRITE: 276 + /* 277 + * Device is opened in O_WRONLY mode 278 + * Execute only set/configure commands 279 + */ 280 + if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_SET) 281 + return -EINVAL; 282 + break; 283 + case FMODE_READ: 284 + /* 285 + * Device is opened in O_RDONLY mode 286 + * Execute only get/monitor commands 287 + */ 288 + if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_GET) 289 + return -EINVAL; 290 + break; 291 + case FMODE_READ | FMODE_WRITE: 292 + /* 293 + * Device is opened in O_RDWR mode 294 + * Execute both get/monitor and set/configure commands 295 + */ 296 + break; 297 + default: 298 + return -EINVAL; 299 + } 300 + 301 + ret = hsmp_send_message(&msg); 302 + if (ret) 303 + return ret; 304 + 305 + if (hsmp_msg_desc_table[msg.msg_id].response_sz > 0) { 306 + /* Copy results back to user for get/monitor commands */ 307 + if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) 308 + return -EFAULT; 309 + } 310 + 311 + return 0; 312 + } 313 + 314 + static const struct file_operations hsmp_fops = { 315 + .owner = THIS_MODULE, 316 + .unlocked_ioctl = hsmp_ioctl, 317 + .compat_ioctl = hsmp_ioctl, 318 + }; 319 + 320 + static int hsmp_pltdrv_probe(struct platform_device *pdev) 321 + { 322 + int i; 323 + 324 + hsmp_sem = devm_kzalloc(&pdev->dev, 325 + (amd_nb_num() * sizeof(struct semaphore)), 326 + GFP_KERNEL); 327 + if (!hsmp_sem) 328 + return -ENOMEM; 329 + 330 + for (i = 0; i < amd_nb_num(); i++) 331 + sema_init(&hsmp_sem[i], 1); 332 + 333 + hsmp_device.name = "hsmp_cdev"; 334 + hsmp_device.minor = MISC_DYNAMIC_MINOR; 335 + hsmp_device.fops = &hsmp_fops; 336 + hsmp_device.parent = &pdev->dev; 337 + hsmp_device.nodename = "hsmp"; 338 + hsmp_device.mode = 0644; 339 + 340 + return misc_register(&hsmp_device); 341 + } 342 + 343 + static int hsmp_pltdrv_remove(struct platform_device *pdev) 344 + { 345 + misc_deregister(&hsmp_device); 346 + 347 + return 0; 348 + } 349 + 350 + static struct platform_driver amd_hsmp_driver = { 351 + .probe = hsmp_pltdrv_probe, 352 + .remove = hsmp_pltdrv_remove, 353 + .driver = { 354 + .name = DRIVER_NAME, 355 + }, 356 + }; 357 + 358 + static struct platform_device *amd_hsmp_platdev; 359 + 360 + static int __init hsmp_plt_init(void) 361 + { 362 + int ret = -ENODEV; 363 + u16 num_sockets; 364 + int i; 365 + 366 + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD || boot_cpu_data.x86 < 0x19) { 367 + pr_err("HSMP is not supported on Family:%x model:%x\n", 368 + boot_cpu_data.x86, boot_cpu_data.x86_model); 369 + return ret; 370 + } 371 + 372 + /* 373 + * amd_nb_num() returns number of SMN/DF interfaces present in the system 374 + * if we have N SMN/DF interfaces that ideally means N sockets 375 + */ 376 + num_sockets = amd_nb_num(); 377 + if (num_sockets == 0) 378 + return ret; 379 + 380 + /* Test the hsmp interface on each socket */ 381 + for (i = 0; i < num_sockets; i++) { 382 + ret = hsmp_test(i, 0xDEADBEEF); 383 + if (ret) { 384 + pr_err("HSMP is not supported on Fam:%x model:%x\n", 385 + boot_cpu_data.x86, boot_cpu_data.x86_model); 386 + pr_err("Or Is HSMP disabled in BIOS ?\n"); 387 + return -EOPNOTSUPP; 388 + } 389 + } 390 + 391 + ret = platform_driver_register(&amd_hsmp_driver); 392 + if (ret) 393 + return ret; 394 + 395 + amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, -1); 396 + if (!amd_hsmp_platdev) { 397 + ret = -ENOMEM; 398 + goto drv_unregister; 399 + } 400 + 401 + ret = platform_device_add(amd_hsmp_platdev); 402 + if (ret) { 403 + platform_device_put(amd_hsmp_platdev); 404 + goto drv_unregister; 405 + } 406 + 407 + return 0; 408 + 409 + drv_unregister: 410 + platform_driver_unregister(&amd_hsmp_driver); 411 + return ret; 412 + } 413 + 414 + static void __exit hsmp_plt_exit(void) 415 + { 416 + platform_device_unregister(amd_hsmp_platdev); 417 + platform_driver_unregister(&amd_hsmp_driver); 418 + } 419 + 420 + device_initcall(hsmp_plt_init); 421 + module_exit(hsmp_plt_exit); 422 + 423 + MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver"); 424 + MODULE_VERSION(DRIVER_VERSION); 425 + MODULE_LICENSE("GPL v2");
+1 -1
drivers/platform/x86/dell/dcdbas.c
··· 284 284 285 285 return ret; 286 286 } 287 + EXPORT_SYMBOL(dcdbas_smi_request); 287 288 288 289 /** 289 290 * smi_request_store: ··· 352 351 mutex_unlock(&smi_data_lock); 353 352 return ret; 354 353 } 355 - EXPORT_SYMBOL(dcdbas_smi_request); 356 354 357 355 /** 358 356 * host_control_smi: generate host control SMI
+164 -66
drivers/platform/x86/hp-wmi.c
··· 35 35 MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C"); 36 36 MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); 37 37 38 - static int enable_tablet_mode_sw = -1; 39 - module_param(enable_tablet_mode_sw, int, 0444); 40 - MODULE_PARM_DESC(enable_tablet_mode_sw, "Enable SW_TABLET_MODE reporting (-1=auto, 0=no, 1=yes)"); 41 - 42 38 #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" 43 39 #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4" 44 40 #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95 ··· 55 59 "88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD", 56 60 "88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912", 57 61 "8917", "8918", "8949", "894A", "89EB" 62 + }; 63 + 64 + /* DMI Board names of Omen laptops that are specifically set to be thermal 65 + * profile version 0 by the Omen Command Center app, regardless of what 66 + * the get system design information WMI call returns 67 + */ 68 + static const char *const omen_thermal_profile_force_v0_boards[] = { 69 + "8607", "8746", "8747", "8749", "874A", "8748" 58 70 }; 59 71 60 72 enum hp_wmi_radio { ··· 90 86 HPWMI_BATTERY_CHARGE_PERIOD = 0x10, 91 87 }; 92 88 89 + /* 90 + * struct bios_args buffer is dynamically allocated. New WMI command types 91 + * were introduced that exceeds 128-byte data size. Changes to handle 92 + * the data size allocation scheme were kept in hp_wmi_perform_qurey function. 93 + */ 93 94 struct bios_args { 94 95 u32 signature; 95 96 u32 command; 96 97 u32 commandtype; 97 98 u32 datasize; 98 - u8 data[128]; 99 + u8 data[]; 99 100 }; 100 101 101 102 enum hp_wmi_commandtype { ··· 116 107 HPWMI_FEATURE2_QUERY = 0x0d, 117 108 HPWMI_WIRELESS2_QUERY = 0x1b, 118 109 HPWMI_POSTCODEERROR_QUERY = 0x2a, 110 + HPWMI_SYSTEM_DEVICE_MODE = 0x40, 119 111 HPWMI_THERMAL_PROFILE_QUERY = 0x4c, 120 112 }; 121 113 ··· 125 115 HPWMI_SET_PERFORMANCE_MODE = 0x1A, 126 116 HPWMI_FAN_SPEED_MAX_GET_QUERY = 0x26, 127 117 HPWMI_FAN_SPEED_MAX_SET_QUERY = 0x27, 118 + HPWMI_GET_SYSTEM_DESIGN_DATA = 0x28, 128 119 }; 129 120 130 121 enum hp_wmi_command { ··· 160 149 HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, 161 150 }; 162 151 163 - enum hp_thermal_profile_omen { 164 - HP_OMEN_THERMAL_PROFILE_DEFAULT = 0x00, 165 - HP_OMEN_THERMAL_PROFILE_PERFORMANCE = 0x01, 166 - HP_OMEN_THERMAL_PROFILE_COOL = 0x02, 152 + enum hp_thermal_profile_omen_v0 { 153 + HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00, 154 + HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01, 155 + HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02, 156 + }; 157 + 158 + enum hp_thermal_profile_omen_v1 { 159 + HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30, 160 + HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31, 161 + HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50, 167 162 }; 168 163 169 164 enum hp_thermal_profile { ··· 234 217 static int rfkill2_count; 235 218 static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 236 219 220 + /* 221 + * Chassis Types values were obtained from SMBIOS reference 222 + * specification version 3.00. A complete list of system enclosures 223 + * and chassis types is available on Table 17. 224 + */ 225 + static const char * const tablet_chassis_types[] = { 226 + "30", /* Tablet*/ 227 + "31", /* Convertible */ 228 + "32" /* Detachable */ 229 + }; 230 + 231 + #define DEVICE_MODE_TABLET 0x06 232 + 237 233 /* map output size to the corresponding WMI method id */ 238 234 static inline int encode_outsize_for_pvsz(int outsize) 239 235 { ··· 286 256 static int hp_wmi_perform_query(int query, enum hp_wmi_command command, 287 257 void *buffer, int insize, int outsize) 288 258 { 289 - int mid; 259 + struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL }; 290 260 struct bios_return *bios_return; 291 - int actual_outsize; 292 - union acpi_object *obj; 293 - struct bios_args args = { 294 - .signature = 0x55434553, 295 - .command = command, 296 - .commandtype = query, 297 - .datasize = insize, 298 - .data = { 0 }, 299 - }; 300 - struct acpi_buffer input = { sizeof(struct bios_args), &args }; 301 - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 302 - int ret = 0; 261 + union acpi_object *obj = NULL; 262 + struct bios_args *args = NULL; 263 + int mid, actual_outsize, ret; 264 + size_t bios_args_size; 303 265 304 266 mid = encode_outsize_for_pvsz(outsize); 305 267 if (WARN_ON(mid < 0)) 306 268 return mid; 307 269 308 - if (WARN_ON(insize > sizeof(args.data))) 309 - return -EINVAL; 310 - memcpy(&args.data[0], buffer, insize); 270 + bios_args_size = struct_size(args, data, insize); 271 + args = kmalloc(bios_args_size, GFP_KERNEL); 272 + if (!args) 273 + return -ENOMEM; 311 274 312 - wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output); 275 + input.length = bios_args_size; 276 + input.pointer = args; 277 + 278 + args->signature = 0x55434553; 279 + args->command = command; 280 + args->commandtype = query; 281 + args->datasize = insize; 282 + memcpy(args->data, buffer, flex_array_size(args, data, insize)); 283 + 284 + ret = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output); 285 + if (ret) 286 + goto out_free; 313 287 314 288 obj = output.pointer; 315 - 316 - if (!obj) 317 - return -EINVAL; 289 + if (!obj) { 290 + ret = -EINVAL; 291 + goto out_free; 292 + } 318 293 319 294 if (obj->type != ACPI_TYPE_BUFFER) { 295 + pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret); 320 296 ret = -EINVAL; 321 297 goto out_free; 322 298 } ··· 347 311 348 312 out_free: 349 313 kfree(obj); 314 + kfree(args); 350 315 return ret; 351 316 } 352 317 ··· 357 320 char fan_data[4] = { fan, 0, 0, 0 }; 358 321 359 322 int ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_GET_QUERY, HPWMI_GM, 360 - &fan_data, sizeof(fan_data), 323 + &fan_data, sizeof(char), 361 324 sizeof(fan_data)); 362 325 363 326 if (ret != 0) ··· 374 337 int val = 0, ret; 375 338 376 339 ret = hp_wmi_perform_query(query, HPWMI_READ, &val, 377 - sizeof(val), sizeof(val)); 340 + 0, sizeof(val)); 378 341 379 342 if (ret) 380 343 return ret < 0 ? ret : -EINVAL; ··· 382 345 return val; 383 346 } 384 347 385 - static int hp_wmi_hw_state(int mask) 348 + static int hp_wmi_get_dock_state(void) 386 349 { 387 350 int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY); 388 351 389 352 if (state < 0) 390 353 return state; 391 354 392 - return !!(state & mask); 355 + return !!(state & HPWMI_DOCK_MASK); 356 + } 357 + 358 + static int hp_wmi_get_tablet_mode(void) 359 + { 360 + char system_device_mode[4] = { 0 }; 361 + const char *chassis_type; 362 + bool tablet_found; 363 + int ret; 364 + 365 + chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); 366 + if (!chassis_type) 367 + return -ENODEV; 368 + 369 + tablet_found = match_string(tablet_chassis_types, 370 + ARRAY_SIZE(tablet_chassis_types), 371 + chassis_type) >= 0; 372 + if (!tablet_found) 373 + return -ENODEV; 374 + 375 + ret = hp_wmi_perform_query(HPWMI_SYSTEM_DEVICE_MODE, HPWMI_READ, 376 + system_device_mode, 0, sizeof(system_device_mode)); 377 + if (ret < 0) 378 + return ret; 379 + 380 + return system_device_mode[0] == DEVICE_MODE_TABLET; 393 381 } 394 382 395 383 static int omen_thermal_profile_set(int mode) ··· 422 360 char buffer[2] = {0, mode}; 423 361 int ret; 424 362 425 - if (mode < 0 || mode > 2) 426 - return -EINVAL; 427 - 428 363 ret = hp_wmi_perform_query(HPWMI_SET_PERFORMANCE_MODE, HPWMI_GM, 429 - &buffer, sizeof(buffer), sizeof(buffer)); 364 + &buffer, sizeof(buffer), 0); 430 365 431 366 if (ret) 432 367 return ret < 0 ? ret : -EINVAL; ··· 443 384 board_name) >= 0; 444 385 } 445 386 387 + static int omen_get_thermal_policy_version(void) 388 + { 389 + unsigned char buffer[8] = { 0 }; 390 + int ret; 391 + 392 + const char *board_name = dmi_get_system_info(DMI_BOARD_NAME); 393 + 394 + if (board_name) { 395 + int matches = match_string(omen_thermal_profile_force_v0_boards, 396 + ARRAY_SIZE(omen_thermal_profile_force_v0_boards), 397 + board_name); 398 + if (matches >= 0) 399 + return 0; 400 + } 401 + 402 + ret = hp_wmi_perform_query(HPWMI_GET_SYSTEM_DESIGN_DATA, HPWMI_GM, 403 + &buffer, sizeof(buffer), sizeof(buffer)); 404 + 405 + if (ret) 406 + return ret < 0 ? ret : -EINVAL; 407 + 408 + return buffer[3]; 409 + } 410 + 446 411 static int omen_thermal_profile_get(void) 447 412 { 448 413 u8 data; ··· 484 401 int ret; 485 402 486 403 ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_SET_QUERY, HPWMI_GM, 487 - &enabled, sizeof(enabled), sizeof(enabled)); 404 + &enabled, sizeof(enabled), 0); 488 405 489 406 if (ret) 490 407 return ret < 0 ? ret : -EINVAL; ··· 497 414 int val = 0, ret; 498 415 499 416 ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_GET_QUERY, HPWMI_GM, 500 - &val, sizeof(val), sizeof(val)); 417 + &val, 0, sizeof(val)); 501 418 502 419 if (ret) 503 420 return ret < 0 ? ret : -EINVAL; ··· 509 426 { 510 427 int state = 0; 511 428 int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state, 512 - sizeof(state), sizeof(state)); 429 + 0, sizeof(state)); 513 430 if (!ret) 514 431 return 1; 515 432 ··· 520 437 { 521 438 u8 state[128]; 522 439 int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state, 523 - sizeof(state), sizeof(state)); 440 + 0, sizeof(state)); 524 441 if (!ret) 525 442 return 1; 526 443 ··· 598 515 int err, i; 599 516 600 517 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 601 - sizeof(state), sizeof(state)); 518 + 0, sizeof(state)); 602 519 if (err) 603 520 return err; 604 521 ··· 651 568 static ssize_t dock_show(struct device *dev, struct device_attribute *attr, 652 569 char *buf) 653 570 { 654 - int value = hp_wmi_hw_state(HPWMI_DOCK_MASK); 571 + int value = hp_wmi_get_dock_state(); 655 572 if (value < 0) 656 573 return value; 657 574 return sprintf(buf, "%d\n", value); ··· 660 577 static ssize_t tablet_show(struct device *dev, struct device_attribute *attr, 661 578 char *buf) 662 579 { 663 - int value = hp_wmi_hw_state(HPWMI_TABLET_MASK); 580 + int value = hp_wmi_get_tablet_mode(); 664 581 if (value < 0) 665 582 return value; 666 583 return sprintf(buf, "%d\n", value); ··· 687 604 return ret; 688 605 689 606 ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp, 690 - sizeof(tmp), sizeof(tmp)); 607 + sizeof(tmp), 0); 691 608 if (ret) 692 609 return ret < 0 ? ret : -EINVAL; 693 610 ··· 708 625 if (clear == false) 709 626 return -EINVAL; 710 627 711 - /* Clear the POST error code. It is kept until until cleared. */ 628 + /* Clear the POST error code. It is kept until cleared. */ 712 629 ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp, 713 - sizeof(tmp), sizeof(tmp)); 630 + sizeof(tmp), 0); 714 631 if (ret) 715 632 return ret < 0 ? ret : -EINVAL; 716 633 ··· 782 699 case HPWMI_DOCK_EVENT: 783 700 if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) 784 701 input_report_switch(hp_wmi_input_dev, SW_DOCK, 785 - hp_wmi_hw_state(HPWMI_DOCK_MASK)); 702 + hp_wmi_get_dock_state()); 786 703 if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) 787 704 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 788 - hp_wmi_hw_state(HPWMI_TABLET_MASK)); 705 + hp_wmi_get_tablet_mode()); 789 706 input_sync(hp_wmi_input_dev); 790 707 break; 791 708 case HPWMI_PARK_HDD: ··· 863 780 __set_bit(EV_SW, hp_wmi_input_dev->evbit); 864 781 865 782 /* Dock */ 866 - val = hp_wmi_hw_state(HPWMI_DOCK_MASK); 783 + val = hp_wmi_get_dock_state(); 867 784 if (!(val < 0)) { 868 785 __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); 869 786 input_report_switch(hp_wmi_input_dev, SW_DOCK, val); 870 787 } 871 788 872 789 /* Tablet mode */ 873 - if (enable_tablet_mode_sw > 0) { 874 - val = hp_wmi_hw_state(HPWMI_TABLET_MASK); 875 - if (val >= 0) { 876 - __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); 877 - input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val); 878 - } 790 + val = hp_wmi_get_tablet_mode(); 791 + if (!(val < 0)) { 792 + __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); 793 + input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val); 879 794 } 880 795 881 796 err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL); ··· 1000 919 int err, i; 1001 920 1002 921 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 1003 - sizeof(state), sizeof(state)); 922 + 0, sizeof(state)); 1004 923 if (err) 1005 924 return err < 0 ? err : -EINVAL; 1006 925 ··· 1089 1008 return tp; 1090 1009 1091 1010 switch (tp) { 1092 - case HP_OMEN_THERMAL_PROFILE_PERFORMANCE: 1011 + case HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE: 1012 + case HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE: 1093 1013 *profile = PLATFORM_PROFILE_PERFORMANCE; 1094 1014 break; 1095 - case HP_OMEN_THERMAL_PROFILE_DEFAULT: 1015 + case HP_OMEN_V0_THERMAL_PROFILE_DEFAULT: 1016 + case HP_OMEN_V1_THERMAL_PROFILE_DEFAULT: 1096 1017 *profile = PLATFORM_PROFILE_BALANCED; 1097 1018 break; 1098 - case HP_OMEN_THERMAL_PROFILE_COOL: 1019 + case HP_OMEN_V0_THERMAL_PROFILE_COOL: 1020 + case HP_OMEN_V1_THERMAL_PROFILE_COOL: 1099 1021 *profile = PLATFORM_PROFILE_COOL; 1100 1022 break; 1101 1023 default: ··· 1111 1027 static int platform_profile_omen_set(struct platform_profile_handler *pprof, 1112 1028 enum platform_profile_option profile) 1113 1029 { 1114 - int err, tp; 1030 + int err, tp, tp_version; 1031 + 1032 + tp_version = omen_get_thermal_policy_version(); 1033 + 1034 + if (tp_version < 0 || tp_version > 1) 1035 + return -EOPNOTSUPP; 1115 1036 1116 1037 switch (profile) { 1117 1038 case PLATFORM_PROFILE_PERFORMANCE: 1118 - tp = HP_OMEN_THERMAL_PROFILE_PERFORMANCE; 1039 + if (tp_version == 0) 1040 + tp = HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE; 1041 + else 1042 + tp = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE; 1119 1043 break; 1120 1044 case PLATFORM_PROFILE_BALANCED: 1121 - tp = HP_OMEN_THERMAL_PROFILE_DEFAULT; 1045 + if (tp_version == 0) 1046 + tp = HP_OMEN_V0_THERMAL_PROFILE_DEFAULT; 1047 + else 1048 + tp = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT; 1122 1049 break; 1123 1050 case PLATFORM_PROFILE_COOL: 1124 - tp = HP_OMEN_THERMAL_PROFILE_COOL; 1051 + if (tp_version == 0) 1052 + tp = HP_OMEN_V0_THERMAL_PROFILE_COOL; 1053 + else 1054 + tp = HP_OMEN_V1_THERMAL_PROFILE_COOL; 1125 1055 break; 1126 1056 default: 1127 1057 return -EOPNOTSUPP; ··· 1325 1227 if (hp_wmi_input_dev) { 1326 1228 if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) 1327 1229 input_report_switch(hp_wmi_input_dev, SW_DOCK, 1328 - hp_wmi_hw_state(HPWMI_DOCK_MASK)); 1230 + hp_wmi_get_dock_state()); 1329 1231 if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) 1330 1232 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 1331 - hp_wmi_hw_state(HPWMI_TABLET_MASK)); 1233 + hp_wmi_get_tablet_mode()); 1332 1234 input_sync(hp_wmi_input_dev); 1333 1235 } 1334 1236
+10 -3
drivers/platform/x86/huawei-wmi.c
··· 470 470 471 471 static int huawei_wmi_battery_add(struct power_supply *battery) 472 472 { 473 - device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold); 474 - device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); 473 + int err = 0; 475 474 476 - return 0; 475 + err = device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold); 476 + if (err) 477 + return err; 478 + 479 + err = device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); 480 + if (err) 481 + device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold); 482 + 483 + return err; 477 484 } 478 485 479 486 static int huawei_wmi_battery_remove(struct power_supply *battery)
+34 -13
drivers/platform/x86/intel/Kconfig
··· 5 5 6 6 source "drivers/platform/x86/intel/atomisp2/Kconfig" 7 7 source "drivers/platform/x86/intel/int1092/Kconfig" 8 - source "drivers/platform/x86/intel/int33fe/Kconfig" 9 8 source "drivers/platform/x86/intel/int3472/Kconfig" 10 9 source "drivers/platform/x86/intel/pmc/Kconfig" 11 10 source "drivers/platform/x86/intel/pmt/Kconfig" 12 11 source "drivers/platform/x86/intel/speed_select_if/Kconfig" 13 12 source "drivers/platform/x86/intel/telemetry/Kconfig" 14 13 source "drivers/platform/x86/intel/wmi/Kconfig" 14 + source "drivers/platform/x86/intel/uncore-frequency/Kconfig" 15 + 15 16 16 17 config INTEL_HID_EVENT 17 18 tristate "Intel HID Event" ··· 90 89 To compile this driver as a module, choose M here: the module 91 90 will be called intel_chtdc_ti_pwrbtn. 92 91 92 + config INTEL_CHTWC_INT33FE 93 + tristate "Intel Cherry Trail Whiskey Cove ACPI INT33FE Driver" 94 + depends on X86 && ACPI && I2C && REGULATOR 95 + depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) 96 + depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m) 97 + depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m) 98 + help 99 + This driver add support for the Intel Cherry Trail Whiskey Cove 100 + INT33FE ACPI device found on the GPD win and the GPD pocket. 101 + 102 + The INT33FE ACPI device on these mini laptops contains I2cSerialBusV2 103 + resources for a MAX17042 Fuel Gauge, FUSB302 USB Type-C Controller 104 + and PI3USB30532 USB switch. 105 + This driver instantiates i2c-clients for these, so that standard 106 + i2c drivers for these chips can bind to the them. 107 + 108 + If you enable this driver it is advised to also select 109 + CONFIG_TYPEC_FUSB302=m, CONFIG_TYPEC_MUX_PI3USB30532=m and 110 + CONFIG_BATTERY_MAX17042=m. 111 + 93 112 config INTEL_ISHTP_ECLITE 94 113 tristate "Intel ISHTP eclite controller Driver" 95 114 depends on INTEL_ISH_HID ··· 155 134 firmware will copy the memory contents back to RAM and resume the OS 156 135 as usual. 157 136 137 + config INTEL_SDSI 138 + tristate "Intel Software Defined Silicon Driver" 139 + depends on INTEL_VSEC 140 + depends on X86_64 141 + help 142 + This driver enables access to the Intel Software Defined Silicon 143 + interface used to provision silicon features with an authentication 144 + certificate and capability license. 145 + 146 + To compile this driver as a module, choose M here: the module will 147 + be called intel_sdsi. 148 + 158 149 config INTEL_SMARTCONNECT 159 150 tristate "Intel Smart Connect disabling driver" 160 151 depends on ACPI ··· 191 158 192 159 This driver is only required when the system is not using Hardware 193 160 P-States (HWP). In HWP mode, priority can be read from ACPI tables. 194 - 195 - config INTEL_UNCORE_FREQ_CONTROL 196 - tristate "Intel Uncore frequency control driver" 197 - depends on X86_64 198 - help 199 - This driver allows control of Uncore frequency limits on 200 - supported server platforms. 201 - 202 - Uncore frequency controls RING/LLC (last-level cache) clocks. 203 - 204 - To compile this driver as a module, choose M here: the module 205 - will be called intel-uncore-frequency. 206 161 207 162 config INTEL_VSEC 208 163 tristate "Intel Vendor Specific Extended Capabilities Driver"
+6 -3
drivers/platform/x86/intel/Makefile
··· 6 6 7 7 obj-$(CONFIG_INTEL_ATOMISP2_PDX86) += atomisp2/ 8 8 obj-$(CONFIG_INTEL_SAR_INT1092) += int1092/ 9 - obj-$(CONFIG_INTEL_CHT_INT33FE) += int33fe/ 10 9 obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/ 11 10 obj-$(CONFIG_INTEL_PMC_CORE) += pmc/ 12 11 obj-$(CONFIG_INTEL_PMT_CLASS) += pmt/ 13 12 obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += speed_select_if/ 14 13 obj-$(CONFIG_INTEL_TELEMETRY) += telemetry/ 15 14 obj-$(CONFIG_INTEL_WMI) += wmi/ 15 + obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += uncore-frequency/ 16 + 16 17 17 18 # Intel input drivers 18 19 intel-hid-y := hid.o ··· 27 26 obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o 28 27 intel_oaktrail-y := oaktrail.o 29 28 obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o 29 + intel_sdsi-y := sdsi.o 30 + obj-$(CONFIG_INTEL_SDSI) += intel_sdsi.o 30 31 intel_vsec-y := vsec.o 31 32 obj-$(CONFIG_INTEL_VSEC) += intel_vsec.o 32 33 ··· 39 36 obj-$(CONFIG_X86_ANDROID_TABLETS) += intel_crystal_cove_charger.o 40 37 intel_chtdc_ti_pwrbtn-y := chtdc_ti_pwrbtn.o 41 38 obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o 39 + intel_chtwc_int33fe-y := chtwc_int33fe.o 40 + obj-$(CONFIG_INTEL_CHTWC_INT33FE) += intel_chtwc_int33fe.o 42 41 intel_mrfld_pwrbtn-y := mrfld_pwrbtn.o 43 42 obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o 44 43 intel_punit_ipc-y := punit_ipc.o ··· 53 48 obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o 54 49 intel_turbo_max_3-y := turbo_max_3.o 55 50 obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o 56 - intel-uncore-frequency-y := uncore-frequency.o 57 - obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency.o
+2 -5
drivers/platform/x86/intel/hid.c
··· 726 726 check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv) 727 727 { 728 728 const struct acpi_device_id *ids = context; 729 - struct acpi_device *dev; 729 + struct acpi_device *dev = acpi_fetch_acpi_dev(handle); 730 730 731 - if (acpi_bus_get_device(handle, &dev) != 0) 732 - return AE_OK; 733 - 734 - if (acpi_match_device_ids(dev, ids) == 0) 731 + if (dev && acpi_match_device_ids(dev, ids) == 0) 735 732 if (!IS_ERR_OR_NULL(acpi_create_platform_device(dev, NULL))) 736 733 dev_info(&dev->dev, 737 734 "intel-hid: created platform device\n");
-24
drivers/platform/x86/intel/int33fe/Kconfig
··· 1 - # SPDX-License-Identifier: GPL-2.0-only 2 - config INTEL_CHT_INT33FE 3 - tristate "Intel Cherry Trail ACPI INT33FE Driver" 4 - depends on X86 && ACPI && I2C && REGULATOR 5 - depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) 6 - depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m) 7 - depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m) 8 - help 9 - This driver add support for the INT33FE ACPI device found on 10 - some Intel Cherry Trail devices. 11 - 12 - There are two kinds of INT33FE ACPI device possible: for hardware 13 - with USB Type-C and Micro-B connectors. This driver supports both. 14 - 15 - The INT33FE ACPI device has a CRS table with I2cSerialBusV2 16 - resources for Fuel Gauge Controller and (in the Type-C variant) 17 - FUSB302 USB Type-C Controller and PI3USB30532 USB switch. 18 - This driver instantiates i2c-clients for these, so that standard 19 - i2c drivers for these chips can bind to the them. 20 - 21 - If you enable this driver it is advised to also select 22 - CONFIG_BATTERY_BQ27XXX=m or CONFIG_BATTERY_BQ27XXX_I2C=m for Micro-B 23 - device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m 24 - for Type-C device.
-5
drivers/platform/x86/intel/int33fe/Makefile
··· 1 - # SPDX-License-Identifier: GPL-2.0-only 2 - obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o 3 - intel_cht_int33fe-y := intel_cht_int33fe_common.o \ 4 - intel_cht_int33fe_typec.o \ 5 - intel_cht_int33fe_microb.o
-118
drivers/platform/x86/intel/int33fe/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_check_hw_type(struct device *dev) 20 - { 21 - unsigned long long ptyp; 22 - acpi_status status; 23 - int ret; 24 - 25 - status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp); 26 - if (ACPI_FAILURE(status)) { 27 - dev_err(dev, "Error getting PTYPE\n"); 28 - return -ENODEV; 29 - } 30 - 31 - /* 32 - * The same ACPI HID is used for different configurations check PTYP 33 - * to ensure that we are dealing with the expected config. 34 - */ 35 - if (ptyp != EXPECTED_PTYPE) 36 - return -ENODEV; 37 - 38 - /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */ 39 - if (!acpi_dev_present("INT34D3", "1", 3)) { 40 - dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n", 41 - EXPECTED_PTYPE); 42 - return -ENODEV; 43 - } 44 - 45 - ret = i2c_acpi_client_count(ACPI_COMPANION(dev)); 46 - if (ret < 0) 47 - return ret; 48 - 49 - switch (ret) { 50 - case 2: 51 - return INT33FE_HW_MICROB; 52 - case 4: 53 - return INT33FE_HW_TYPEC; 54 - default: 55 - return -ENODEV; 56 - } 57 - } 58 - 59 - static int cht_int33fe_probe(struct platform_device *pdev) 60 - { 61 - struct cht_int33fe_data *data; 62 - struct device *dev = &pdev->dev; 63 - int ret; 64 - 65 - ret = cht_int33fe_check_hw_type(dev); 66 - if (ret < 0) 67 - return ret; 68 - 69 - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 70 - if (!data) 71 - return -ENOMEM; 72 - 73 - data->dev = dev; 74 - 75 - switch (ret) { 76 - case INT33FE_HW_MICROB: 77 - data->probe = cht_int33fe_microb_probe; 78 - data->remove = cht_int33fe_microb_remove; 79 - break; 80 - 81 - case INT33FE_HW_TYPEC: 82 - data->probe = cht_int33fe_typec_probe; 83 - data->remove = cht_int33fe_typec_remove; 84 - break; 85 - } 86 - 87 - platform_set_drvdata(pdev, data); 88 - 89 - return data->probe(data); 90 - } 91 - 92 - static int cht_int33fe_remove(struct platform_device *pdev) 93 - { 94 - struct cht_int33fe_data *data = platform_get_drvdata(pdev); 95 - 96 - return data->remove(data); 97 - } 98 - 99 - static const struct acpi_device_id cht_int33fe_acpi_ids[] = { 100 - { "INT33FE", }, 101 - { } 102 - }; 103 - MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids); 104 - 105 - static struct platform_driver cht_int33fe_driver = { 106 - .driver = { 107 - .name = "Intel Cherry Trail ACPI INT33FE driver", 108 - .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), 109 - }, 110 - .probe = cht_int33fe_probe, 111 - .remove = cht_int33fe_remove, 112 - }; 113 - 114 - module_platform_driver(cht_int33fe_driver); 115 - 116 - MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver"); 117 - MODULE_AUTHOR("Yauhen Kharuzhy <jekhor@gmail.com>"); 118 - MODULE_LICENSE("GPL v2");
-41
drivers/platform/x86/intel/int33fe/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 */
-61
drivers/platform/x86/intel/int33fe/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 - static const struct software_node bq27xxx_node = { 39 - .properties = bq27xxx_props, 40 - }; 41 - 42 - int cht_int33fe_microb_probe(struct cht_int33fe_data *data) 43 - { 44 - struct device *dev = data->dev; 45 - struct i2c_board_info board_info; 46 - 47 - memset(&board_info, 0, sizeof(board_info)); 48 - strscpy(board_info.type, "bq27542", ARRAY_SIZE(board_info.type)); 49 - board_info.dev_name = "bq27542"; 50 - board_info.swnode = &bq27xxx_node; 51 - data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); 52 - 53 - return PTR_ERR_OR_ZERO(data->battery_fg); 54 - } 55 - 56 - int cht_int33fe_microb_remove(struct cht_int33fe_data *data) 57 - { 58 - i2c_unregister_device(data->battery_fg); 59 - 60 - return 0; 61 - }
+61 -4
drivers/platform/x86/intel/int33fe/intel_cht_int33fe_typec.c drivers/platform/x86/intel/chtwc_int33fe.c
··· 17 17 * for these chips can bind to the them. 18 18 */ 19 19 20 + #include <linux/dmi.h> 20 21 #include <linux/i2c.h> 21 22 #include <linux/interrupt.h> 22 23 #include <linux/pci.h> ··· 27 26 #include <linux/slab.h> 28 27 #include <linux/usb/pd.h> 29 28 30 - #include "intel_cht_int33fe_common.h" 29 + struct cht_int33fe_data { 30 + struct i2c_client *battery_fg; 31 + struct i2c_client *fusb302; 32 + struct i2c_client *pi3usb30532; 33 + struct fwnode_handle *dp; 34 + }; 31 35 32 36 /* 33 37 * Grrr, I severely dislike buggy BIOS-es. At least one BIOS enumerates ··· 278 272 return PTR_ERR_OR_ZERO(data->battery_fg); 279 273 } 280 274 281 - int cht_int33fe_typec_probe(struct cht_int33fe_data *data) 275 + static const struct dmi_system_id cht_int33fe_typec_ids[] = { 276 + { 277 + /* 278 + * GPD win / GPD pocket mini laptops 279 + * 280 + * This DMI match may not seem unique, but it is. In the 67000+ 281 + * DMI decode dumps from linux-hardware.org only 116 have 282 + * board_vendor set to "AMI Corporation" and of those 116 only 283 + * the GPD win's and pocket's board_name is "Default string". 284 + */ 285 + .matches = { 286 + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 287 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"), 288 + DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), 289 + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), 290 + }, 291 + }, 292 + { } 293 + }; 294 + MODULE_DEVICE_TABLE(dmi, cht_int33fe_typec_ids); 295 + 296 + static int cht_int33fe_typec_probe(struct platform_device *pdev) 282 297 { 283 - struct device *dev = data->dev; 284 298 struct i2c_board_info board_info; 299 + struct device *dev = &pdev->dev; 300 + struct cht_int33fe_data *data; 285 301 struct fwnode_handle *fwnode; 286 302 struct regulator *regulator; 287 303 int fusb302_irq; 288 304 int ret; 305 + 306 + if (!dmi_check_system(cht_int33fe_typec_ids)) 307 + return -ENODEV; 308 + 309 + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 310 + if (!data) 311 + return -ENOMEM; 289 312 290 313 /* 291 314 * We expect the WC PMIC to be paired with a TI bq24292i charger-IC. ··· 403 368 return ret; 404 369 } 405 370 406 - int cht_int33fe_typec_remove(struct cht_int33fe_data *data) 371 + static int cht_int33fe_typec_remove(struct platform_device *pdev) 407 372 { 373 + struct cht_int33fe_data *data = platform_get_drvdata(pdev); 374 + 408 375 i2c_unregister_device(data->pi3usb30532); 409 376 i2c_unregister_device(data->fusb302); 410 377 i2c_unregister_device(data->battery_fg); ··· 415 378 416 379 return 0; 417 380 } 381 + 382 + static const struct acpi_device_id cht_int33fe_acpi_ids[] = { 383 + { "INT33FE", }, 384 + { } 385 + }; 386 + 387 + static struct platform_driver cht_int33fe_typec_driver = { 388 + .driver = { 389 + .name = "Intel Cherry Trail ACPI INT33FE Type-C driver", 390 + .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), 391 + }, 392 + .probe = cht_int33fe_typec_probe, 393 + .remove = cht_int33fe_typec_remove, 394 + }; 395 + 396 + module_platform_driver(cht_int33fe_typec_driver); 397 + 398 + MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE Type-C pseudo device driver"); 399 + MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 400 + MODULE_LICENSE("GPL v2");
+2 -3
drivers/platform/x86/intel/int3472/discrete.c
··· 112 112 struct acpi_device *adev; 113 113 acpi_handle handle; 114 114 acpi_status status; 115 - int ret; 116 115 117 116 if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { 118 117 dev_warn(int3472->dev, "Too many GPIOs mapped\n"); ··· 138 139 if (ACPI_FAILURE(status)) 139 140 return -EINVAL; 140 141 141 - ret = acpi_bus_get_device(handle, &adev); 142 - if (ret) 142 + adev = acpi_fetch_acpi_dev(handle); 143 + if (!adev) 143 144 return -ENODEV; 144 145 145 146 table_entry = &int3472->gpios.table[int3472->n_sensor_gpios];
+574
drivers/platform/x86/intel/sdsi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Software Defined Silicon driver 4 + * 5 + * Copyright (c) 2022, Intel Corporation. 6 + * All Rights Reserved. 7 + * 8 + * Author: "David E. Box" <david.e.box@linux.intel.com> 9 + */ 10 + 11 + #include <linux/auxiliary_bus.h> 12 + #include <linux/bits.h> 13 + #include <linux/bitfield.h> 14 + #include <linux/device.h> 15 + #include <linux/iopoll.h> 16 + #include <linux/kernel.h> 17 + #include <linux/module.h> 18 + #include <linux/pci.h> 19 + #include <linux/slab.h> 20 + #include <linux/sysfs.h> 21 + #include <linux/types.h> 22 + #include <linux/uaccess.h> 23 + 24 + #include "vsec.h" 25 + 26 + #define ACCESS_TYPE_BARID 2 27 + #define ACCESS_TYPE_LOCAL 3 28 + 29 + #define SDSI_MIN_SIZE_DWORDS 276 30 + #define SDSI_SIZE_CONTROL 8 31 + #define SDSI_SIZE_MAILBOX 1024 32 + #define SDSI_SIZE_REGS 72 33 + #define SDSI_SIZE_CMD sizeof(u64) 34 + 35 + /* 36 + * Write messages are currently up to the size of the mailbox 37 + * while read messages are up to 4 times the size of the 38 + * mailbox, sent in packets 39 + */ 40 + #define SDSI_SIZE_WRITE_MSG SDSI_SIZE_MAILBOX 41 + #define SDSI_SIZE_READ_MSG (SDSI_SIZE_MAILBOX * 4) 42 + 43 + #define SDSI_ENABLED_FEATURES_OFFSET 16 44 + #define SDSI_ENABLED BIT(3) 45 + #define SDSI_SOCKET_ID_OFFSET 64 46 + #define SDSI_SOCKET_ID GENMASK(3, 0) 47 + 48 + #define SDSI_MBOX_CMD_SUCCESS 0x40 49 + #define SDSI_MBOX_CMD_TIMEOUT 0x80 50 + 51 + #define MBOX_TIMEOUT_US 2000 52 + #define MBOX_TIMEOUT_ACQUIRE_US 1000 53 + #define MBOX_POLLING_PERIOD_US 100 54 + #define MBOX_MAX_PACKETS 4 55 + 56 + #define MBOX_OWNER_NONE 0x00 57 + #define MBOX_OWNER_INBAND 0x01 58 + 59 + #define CTRL_RUN_BUSY BIT(0) 60 + #define CTRL_READ_WRITE BIT(1) 61 + #define CTRL_SOM BIT(2) 62 + #define CTRL_EOM BIT(3) 63 + #define CTRL_OWNER GENMASK(5, 4) 64 + #define CTRL_COMPLETE BIT(6) 65 + #define CTRL_READY BIT(7) 66 + #define CTRL_STATUS GENMASK(15, 8) 67 + #define CTRL_PACKET_SIZE GENMASK(31, 16) 68 + #define CTRL_MSG_SIZE GENMASK(63, 48) 69 + 70 + #define DISC_TABLE_SIZE 12 71 + #define DT_ACCESS_TYPE GENMASK(3, 0) 72 + #define DT_SIZE GENMASK(27, 12) 73 + #define DT_TBIR GENMASK(2, 0) 74 + #define DT_OFFSET(v) ((v) & GENMASK(31, 3)) 75 + 76 + enum sdsi_command { 77 + SDSI_CMD_PROVISION_AKC = 0x04, 78 + SDSI_CMD_PROVISION_CAP = 0x08, 79 + SDSI_CMD_READ_STATE = 0x10, 80 + }; 81 + 82 + struct sdsi_mbox_info { 83 + u64 *payload; 84 + u64 *buffer; 85 + int size; 86 + }; 87 + 88 + struct disc_table { 89 + u32 access_info; 90 + u32 guid; 91 + u32 offset; 92 + }; 93 + 94 + struct sdsi_priv { 95 + struct mutex mb_lock; /* Mailbox access lock */ 96 + struct device *dev; 97 + void __iomem *control_addr; 98 + void __iomem *mbox_addr; 99 + void __iomem *regs_addr; 100 + u32 guid; 101 + bool sdsi_enabled; 102 + }; 103 + 104 + /* SDSi mailbox operations must be performed using 64bit mov instructions */ 105 + static __always_inline void 106 + sdsi_memcpy64_toio(u64 __iomem *to, const u64 *from, size_t count_bytes) 107 + { 108 + size_t count = count_bytes / sizeof(*to); 109 + int i; 110 + 111 + for (i = 0; i < count; i++) 112 + writeq(from[i], &to[i]); 113 + } 114 + 115 + static __always_inline void 116 + sdsi_memcpy64_fromio(u64 *to, const u64 __iomem *from, size_t count_bytes) 117 + { 118 + size_t count = count_bytes / sizeof(*to); 119 + int i; 120 + 121 + for (i = 0; i < count; i++) 122 + to[i] = readq(&from[i]); 123 + } 124 + 125 + static inline void sdsi_complete_transaction(struct sdsi_priv *priv) 126 + { 127 + u64 control = FIELD_PREP(CTRL_COMPLETE, 1); 128 + 129 + lockdep_assert_held(&priv->mb_lock); 130 + writeq(control, priv->control_addr); 131 + } 132 + 133 + static int sdsi_status_to_errno(u32 status) 134 + { 135 + switch (status) { 136 + case SDSI_MBOX_CMD_SUCCESS: 137 + return 0; 138 + case SDSI_MBOX_CMD_TIMEOUT: 139 + return -ETIMEDOUT; 140 + default: 141 + return -EIO; 142 + } 143 + } 144 + 145 + static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, 146 + size_t *data_size) 147 + { 148 + struct device *dev = priv->dev; 149 + u32 total, loop, eom, status, message_size; 150 + u64 control; 151 + int ret; 152 + 153 + lockdep_assert_held(&priv->mb_lock); 154 + 155 + /* Format and send the read command */ 156 + control = FIELD_PREP(CTRL_EOM, 1) | 157 + FIELD_PREP(CTRL_SOM, 1) | 158 + FIELD_PREP(CTRL_RUN_BUSY, 1) | 159 + FIELD_PREP(CTRL_PACKET_SIZE, info->size); 160 + writeq(control, priv->control_addr); 161 + 162 + /* For reads, data sizes that are larger than the mailbox size are read in packets. */ 163 + total = 0; 164 + loop = 0; 165 + do { 166 + int offset = SDSI_SIZE_MAILBOX * loop; 167 + void __iomem *addr = priv->mbox_addr + offset; 168 + u64 *buf = info->buffer + offset / SDSI_SIZE_CMD; 169 + u32 packet_size; 170 + 171 + /* Poll on ready bit */ 172 + ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY, 173 + MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US); 174 + if (ret) 175 + break; 176 + 177 + eom = FIELD_GET(CTRL_EOM, control); 178 + status = FIELD_GET(CTRL_STATUS, control); 179 + packet_size = FIELD_GET(CTRL_PACKET_SIZE, control); 180 + message_size = FIELD_GET(CTRL_MSG_SIZE, control); 181 + 182 + ret = sdsi_status_to_errno(status); 183 + if (ret) 184 + break; 185 + 186 + /* Only the last packet can be less than the mailbox size. */ 187 + if (!eom && packet_size != SDSI_SIZE_MAILBOX) { 188 + dev_err(dev, "Invalid packet size\n"); 189 + ret = -EPROTO; 190 + break; 191 + } 192 + 193 + if (packet_size > SDSI_SIZE_MAILBOX) { 194 + dev_err(dev, "Packet size too large\n"); 195 + ret = -EPROTO; 196 + break; 197 + } 198 + 199 + sdsi_memcpy64_fromio(buf, addr, round_up(packet_size, SDSI_SIZE_CMD)); 200 + 201 + total += packet_size; 202 + 203 + sdsi_complete_transaction(priv); 204 + } while (!eom && ++loop < MBOX_MAX_PACKETS); 205 + 206 + if (ret) { 207 + sdsi_complete_transaction(priv); 208 + return ret; 209 + } 210 + 211 + if (!eom) { 212 + dev_err(dev, "Exceeded read attempts\n"); 213 + return -EPROTO; 214 + } 215 + 216 + /* Message size check is only valid for multi-packet transfers */ 217 + if (loop && total != message_size) 218 + dev_warn(dev, "Read count %u differs from expected count %u\n", 219 + total, message_size); 220 + 221 + *data_size = total; 222 + 223 + return 0; 224 + } 225 + 226 + static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info) 227 + { 228 + u64 control; 229 + u32 status; 230 + int ret; 231 + 232 + lockdep_assert_held(&priv->mb_lock); 233 + 234 + /* Write rest of the payload */ 235 + sdsi_memcpy64_toio(priv->mbox_addr + SDSI_SIZE_CMD, info->payload + 1, 236 + info->size - SDSI_SIZE_CMD); 237 + 238 + /* Format and send the write command */ 239 + control = FIELD_PREP(CTRL_EOM, 1) | 240 + FIELD_PREP(CTRL_SOM, 1) | 241 + FIELD_PREP(CTRL_RUN_BUSY, 1) | 242 + FIELD_PREP(CTRL_READ_WRITE, 1) | 243 + FIELD_PREP(CTRL_PACKET_SIZE, info->size); 244 + writeq(control, priv->control_addr); 245 + 246 + /* Poll on run_busy bit */ 247 + ret = readq_poll_timeout(priv->control_addr, control, !(control & CTRL_RUN_BUSY), 248 + MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US); 249 + 250 + if (ret) 251 + goto release_mbox; 252 + 253 + status = FIELD_GET(CTRL_STATUS, control); 254 + ret = sdsi_status_to_errno(status); 255 + 256 + release_mbox: 257 + sdsi_complete_transaction(priv); 258 + 259 + return ret; 260 + } 261 + 262 + static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info) 263 + { 264 + u64 control; 265 + u32 owner; 266 + int ret; 267 + 268 + lockdep_assert_held(&priv->mb_lock); 269 + 270 + /* Check mailbox is available */ 271 + control = readq(priv->control_addr); 272 + owner = FIELD_GET(CTRL_OWNER, control); 273 + if (owner != MBOX_OWNER_NONE) 274 + return -EBUSY; 275 + 276 + /* Write first qword of payload */ 277 + writeq(info->payload[0], priv->mbox_addr); 278 + 279 + /* Check for ownership */ 280 + ret = readq_poll_timeout(priv->control_addr, control, 281 + FIELD_GET(CTRL_OWNER, control) & MBOX_OWNER_INBAND, 282 + MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_ACQUIRE_US); 283 + 284 + return ret; 285 + } 286 + 287 + static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info) 288 + { 289 + int ret; 290 + 291 + lockdep_assert_held(&priv->mb_lock); 292 + 293 + ret = sdsi_mbox_acquire(priv, info); 294 + if (ret) 295 + return ret; 296 + 297 + return sdsi_mbox_cmd_write(priv, info); 298 + } 299 + 300 + static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size) 301 + { 302 + int ret; 303 + 304 + lockdep_assert_held(&priv->mb_lock); 305 + 306 + ret = sdsi_mbox_acquire(priv, info); 307 + if (ret) 308 + return ret; 309 + 310 + return sdsi_mbox_cmd_read(priv, info, data_size); 311 + } 312 + 313 + static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count, 314 + enum sdsi_command command) 315 + { 316 + struct sdsi_mbox_info info; 317 + int ret; 318 + 319 + if (!priv->sdsi_enabled) 320 + return -EPERM; 321 + 322 + if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD)) 323 + return -EOVERFLOW; 324 + 325 + /* Qword aligned message + command qword */ 326 + info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD; 327 + 328 + info.payload = kzalloc(info.size, GFP_KERNEL); 329 + if (!info.payload) 330 + return -ENOMEM; 331 + 332 + /* Copy message to payload buffer */ 333 + memcpy(info.payload, buf, count); 334 + 335 + /* Command is last qword of payload buffer */ 336 + info.payload[(info.size - SDSI_SIZE_CMD) / SDSI_SIZE_CMD] = command; 337 + 338 + ret = mutex_lock_interruptible(&priv->mb_lock); 339 + if (ret) 340 + goto free_payload; 341 + ret = sdsi_mbox_write(priv, &info); 342 + mutex_unlock(&priv->mb_lock); 343 + 344 + free_payload: 345 + kfree(info.payload); 346 + 347 + if (ret) 348 + return ret; 349 + 350 + return count; 351 + } 352 + 353 + static ssize_t provision_akc_write(struct file *filp, struct kobject *kobj, 354 + struct bin_attribute *attr, char *buf, loff_t off, 355 + size_t count) 356 + { 357 + struct device *dev = kobj_to_dev(kobj); 358 + struct sdsi_priv *priv = dev_get_drvdata(dev); 359 + 360 + if (off) 361 + return -ESPIPE; 362 + 363 + return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_AKC); 364 + } 365 + static BIN_ATTR_WO(provision_akc, SDSI_SIZE_WRITE_MSG); 366 + 367 + static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj, 368 + struct bin_attribute *attr, char *buf, loff_t off, 369 + size_t count) 370 + { 371 + struct device *dev = kobj_to_dev(kobj); 372 + struct sdsi_priv *priv = dev_get_drvdata(dev); 373 + 374 + if (off) 375 + return -ESPIPE; 376 + 377 + return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_CAP); 378 + } 379 + static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG); 380 + 381 + static long state_certificate_read(struct file *filp, struct kobject *kobj, 382 + struct bin_attribute *attr, char *buf, loff_t off, 383 + size_t count) 384 + { 385 + struct device *dev = kobj_to_dev(kobj); 386 + struct sdsi_priv *priv = dev_get_drvdata(dev); 387 + u64 command = SDSI_CMD_READ_STATE; 388 + struct sdsi_mbox_info info; 389 + size_t size; 390 + int ret; 391 + 392 + if (!priv->sdsi_enabled) 393 + return -EPERM; 394 + 395 + if (off) 396 + return 0; 397 + 398 + /* Buffer for return data */ 399 + info.buffer = kmalloc(SDSI_SIZE_READ_MSG, GFP_KERNEL); 400 + if (!info.buffer) 401 + return -ENOMEM; 402 + 403 + info.payload = &command; 404 + info.size = sizeof(command); 405 + 406 + ret = mutex_lock_interruptible(&priv->mb_lock); 407 + if (ret) 408 + goto free_buffer; 409 + ret = sdsi_mbox_read(priv, &info, &size); 410 + mutex_unlock(&priv->mb_lock); 411 + if (ret < 0) 412 + goto free_buffer; 413 + 414 + if (size > count) 415 + size = count; 416 + 417 + memcpy(buf, info.buffer, size); 418 + 419 + free_buffer: 420 + kfree(info.buffer); 421 + 422 + if (ret) 423 + return ret; 424 + 425 + return size; 426 + } 427 + static BIN_ATTR(state_certificate, 0400, state_certificate_read, NULL, SDSI_SIZE_READ_MSG); 428 + 429 + static ssize_t registers_read(struct file *filp, struct kobject *kobj, 430 + struct bin_attribute *attr, char *buf, loff_t off, 431 + size_t count) 432 + { 433 + struct device *dev = kobj_to_dev(kobj); 434 + struct sdsi_priv *priv = dev_get_drvdata(dev); 435 + void __iomem *addr = priv->regs_addr; 436 + 437 + memcpy_fromio(buf, addr + off, count); 438 + 439 + return count; 440 + } 441 + static BIN_ATTR(registers, 0400, registers_read, NULL, SDSI_SIZE_REGS); 442 + 443 + static struct bin_attribute *sdsi_bin_attrs[] = { 444 + &bin_attr_registers, 445 + &bin_attr_state_certificate, 446 + &bin_attr_provision_akc, 447 + &bin_attr_provision_cap, 448 + NULL 449 + }; 450 + 451 + static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf) 452 + { 453 + struct sdsi_priv *priv = dev_get_drvdata(dev); 454 + 455 + return sysfs_emit(buf, "0x%x\n", priv->guid); 456 + } 457 + static DEVICE_ATTR_RO(guid); 458 + 459 + static struct attribute *sdsi_attrs[] = { 460 + &dev_attr_guid.attr, 461 + NULL 462 + }; 463 + 464 + static const struct attribute_group sdsi_group = { 465 + .attrs = sdsi_attrs, 466 + .bin_attrs = sdsi_bin_attrs, 467 + }; 468 + __ATTRIBUTE_GROUPS(sdsi); 469 + 470 + static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent, 471 + struct disc_table *disc_table, struct resource *disc_res) 472 + { 473 + u32 access_type = FIELD_GET(DT_ACCESS_TYPE, disc_table->access_info); 474 + u32 size = FIELD_GET(DT_SIZE, disc_table->access_info); 475 + u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset); 476 + u32 offset = DT_OFFSET(disc_table->offset); 477 + u32 features_offset; 478 + struct resource res = {}; 479 + 480 + /* Starting location of SDSi MMIO region based on access type */ 481 + switch (access_type) { 482 + case ACCESS_TYPE_LOCAL: 483 + if (tbir) { 484 + dev_err(priv->dev, "Unsupported BAR index %u for access type %u\n", 485 + tbir, access_type); 486 + return -EINVAL; 487 + } 488 + 489 + /* 490 + * For access_type LOCAL, the base address is as follows: 491 + * base address = end of discovery region + base offset + 1 492 + */ 493 + res.start = disc_res->end + offset + 1; 494 + break; 495 + 496 + case ACCESS_TYPE_BARID: 497 + res.start = pci_resource_start(parent, tbir) + offset; 498 + break; 499 + 500 + default: 501 + dev_err(priv->dev, "Unrecognized access_type %u\n", access_type); 502 + return -EINVAL; 503 + } 504 + 505 + res.end = res.start + size * sizeof(u32) - 1; 506 + res.flags = IORESOURCE_MEM; 507 + 508 + priv->control_addr = devm_ioremap_resource(priv->dev, &res); 509 + if (IS_ERR(priv->control_addr)) 510 + return PTR_ERR(priv->control_addr); 511 + 512 + priv->mbox_addr = priv->control_addr + SDSI_SIZE_CONTROL; 513 + priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX; 514 + 515 + features_offset = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET); 516 + priv->sdsi_enabled = !!(features_offset & SDSI_ENABLED); 517 + 518 + return 0; 519 + } 520 + 521 + static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) 522 + { 523 + struct intel_vsec_device *intel_cap_dev = auxdev_to_ivdev(auxdev); 524 + struct disc_table disc_table; 525 + struct resource *disc_res; 526 + void __iomem *disc_addr; 527 + struct sdsi_priv *priv; 528 + int ret; 529 + 530 + priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL); 531 + if (!priv) 532 + return -ENOMEM; 533 + 534 + priv->dev = &auxdev->dev; 535 + mutex_init(&priv->mb_lock); 536 + auxiliary_set_drvdata(auxdev, priv); 537 + 538 + /* Get the SDSi discovery table */ 539 + disc_res = &intel_cap_dev->resource[0]; 540 + disc_addr = devm_ioremap_resource(&auxdev->dev, disc_res); 541 + if (IS_ERR(disc_addr)) 542 + return PTR_ERR(disc_addr); 543 + 544 + memcpy_fromio(&disc_table, disc_addr, DISC_TABLE_SIZE); 545 + 546 + priv->guid = disc_table.guid; 547 + 548 + /* Map the SDSi mailbox registers */ 549 + ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res); 550 + if (ret) 551 + return ret; 552 + 553 + return 0; 554 + } 555 + 556 + static const struct auxiliary_device_id sdsi_aux_id_table[] = { 557 + { .name = "intel_vsec.sdsi" }, 558 + {} 559 + }; 560 + MODULE_DEVICE_TABLE(auxiliary, sdsi_aux_id_table); 561 + 562 + static struct auxiliary_driver sdsi_aux_driver = { 563 + .driver = { 564 + .dev_groups = sdsi_groups, 565 + }, 566 + .id_table = sdsi_aux_id_table, 567 + .probe = sdsi_probe, 568 + /* No remove. All resources are handled under devm */ 569 + }; 570 + module_auxiliary_driver(sdsi_aux_driver); 571 + 572 + MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 573 + MODULE_DESCRIPTION("Intel Software Defined Silicon driver"); 574 + MODULE_LICENSE("GPL");
-452
drivers/platform/x86/intel/uncore-frequency.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Intel Uncore Frequency Setting 4 - * Copyright (c) 2019, Intel Corporation. 5 - * All rights reserved. 6 - * 7 - * Provide interface to set MSR 620 at a granularity of per die. On CPU online, 8 - * one control CPU is identified per die to read/write limit. This control CPU 9 - * is changed, if the CPU state is changed to offline. When the last CPU is 10 - * offline in a die then remove the sysfs object for that die. 11 - * The majority of actual code is related to sysfs create and read/write 12 - * attributes. 13 - * 14 - * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 15 - */ 16 - 17 - #include <linux/cpu.h> 18 - #include <linux/module.h> 19 - #include <linux/slab.h> 20 - #include <linux/suspend.h> 21 - #include <asm/cpu_device_id.h> 22 - #include <asm/intel-family.h> 23 - 24 - #define MSR_UNCORE_RATIO_LIMIT 0x620 25 - #define UNCORE_FREQ_KHZ_MULTIPLIER 100000 26 - 27 - /** 28 - * struct uncore_data - Encapsulate all uncore data 29 - * @stored_uncore_data: Last user changed MSR 620 value, which will be restored 30 - * on system resume. 31 - * @initial_min_freq_khz: Sampled minimum uncore frequency at driver init 32 - * @initial_max_freq_khz: Sampled maximum uncore frequency at driver init 33 - * @control_cpu: Designated CPU for a die to read/write 34 - * @valid: Mark the data valid/invalid 35 - * 36 - * This structure is used to encapsulate all data related to uncore sysfs 37 - * settings for a die/package. 38 - */ 39 - struct uncore_data { 40 - struct kobject kobj; 41 - struct completion kobj_unregister; 42 - u64 stored_uncore_data; 43 - u32 initial_min_freq_khz; 44 - u32 initial_max_freq_khz; 45 - int control_cpu; 46 - bool valid; 47 - }; 48 - 49 - #define to_uncore_data(a) container_of(a, struct uncore_data, kobj) 50 - 51 - /* Max instances for uncore data, one for each die */ 52 - static int uncore_max_entries __read_mostly; 53 - /* Storage for uncore data for all instances */ 54 - static struct uncore_data *uncore_instances; 55 - /* Root of the all uncore sysfs kobjs */ 56 - static struct kobject *uncore_root_kobj; 57 - /* Stores the CPU mask of the target CPUs to use during uncore read/write */ 58 - static cpumask_t uncore_cpu_mask; 59 - /* CPU online callback register instance */ 60 - static enum cpuhp_state uncore_hp_state __read_mostly; 61 - /* Mutex to control all mutual exclusions */ 62 - static DEFINE_MUTEX(uncore_lock); 63 - 64 - struct uncore_attr { 65 - struct attribute attr; 66 - ssize_t (*show)(struct kobject *kobj, 67 - struct attribute *attr, char *buf); 68 - ssize_t (*store)(struct kobject *kobj, 69 - struct attribute *attr, const char *c, ssize_t count); 70 - }; 71 - 72 - #define define_one_uncore_ro(_name) \ 73 - static struct uncore_attr _name = \ 74 - __ATTR(_name, 0444, show_##_name, NULL) 75 - 76 - #define define_one_uncore_rw(_name) \ 77 - static struct uncore_attr _name = \ 78 - __ATTR(_name, 0644, show_##_name, store_##_name) 79 - 80 - #define show_uncore_data(member_name) \ 81 - static ssize_t show_##member_name(struct kobject *kobj, \ 82 - struct attribute *attr, \ 83 - char *buf) \ 84 - { \ 85 - struct uncore_data *data = to_uncore_data(kobj); \ 86 - return scnprintf(buf, PAGE_SIZE, "%u\n", \ 87 - data->member_name); \ 88 - } \ 89 - define_one_uncore_ro(member_name) 90 - 91 - show_uncore_data(initial_min_freq_khz); 92 - show_uncore_data(initial_max_freq_khz); 93 - 94 - /* Common function to read MSR 0x620 and read min/max */ 95 - static int uncore_read_ratio(struct uncore_data *data, unsigned int *min, 96 - unsigned int *max) 97 - { 98 - u64 cap; 99 - int ret; 100 - 101 - if (data->control_cpu < 0) 102 - return -ENXIO; 103 - 104 - ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); 105 - if (ret) 106 - return ret; 107 - 108 - *max = (cap & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; 109 - *min = ((cap & GENMASK(14, 8)) >> 8) * UNCORE_FREQ_KHZ_MULTIPLIER; 110 - 111 - return 0; 112 - } 113 - 114 - /* Common function to set min/max ratios to be used by sysfs callbacks */ 115 - static int uncore_write_ratio(struct uncore_data *data, unsigned int input, 116 - int set_max) 117 - { 118 - int ret; 119 - u64 cap; 120 - 121 - mutex_lock(&uncore_lock); 122 - 123 - if (data->control_cpu < 0) { 124 - ret = -ENXIO; 125 - goto finish_write; 126 - } 127 - 128 - input /= UNCORE_FREQ_KHZ_MULTIPLIER; 129 - if (!input || input > 0x7F) { 130 - ret = -EINVAL; 131 - goto finish_write; 132 - } 133 - 134 - ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); 135 - if (ret) 136 - goto finish_write; 137 - 138 - if (set_max) { 139 - cap &= ~0x7F; 140 - cap |= input; 141 - } else { 142 - cap &= ~GENMASK(14, 8); 143 - cap |= (input << 8); 144 - } 145 - 146 - ret = wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, cap); 147 - if (ret) 148 - goto finish_write; 149 - 150 - data->stored_uncore_data = cap; 151 - 152 - finish_write: 153 - mutex_unlock(&uncore_lock); 154 - 155 - return ret; 156 - } 157 - 158 - static ssize_t store_min_max_freq_khz(struct kobject *kobj, 159 - struct attribute *attr, 160 - const char *buf, ssize_t count, 161 - int min_max) 162 - { 163 - struct uncore_data *data = to_uncore_data(kobj); 164 - unsigned int input; 165 - 166 - if (kstrtouint(buf, 10, &input)) 167 - return -EINVAL; 168 - 169 - uncore_write_ratio(data, input, min_max); 170 - 171 - return count; 172 - } 173 - 174 - static ssize_t show_min_max_freq_khz(struct kobject *kobj, 175 - struct attribute *attr, 176 - char *buf, int min_max) 177 - { 178 - struct uncore_data *data = to_uncore_data(kobj); 179 - unsigned int min, max; 180 - int ret; 181 - 182 - mutex_lock(&uncore_lock); 183 - ret = uncore_read_ratio(data, &min, &max); 184 - mutex_unlock(&uncore_lock); 185 - if (ret) 186 - return ret; 187 - 188 - if (min_max) 189 - return sprintf(buf, "%u\n", max); 190 - 191 - return sprintf(buf, "%u\n", min); 192 - } 193 - 194 - #define store_uncore_min_max(name, min_max) \ 195 - static ssize_t store_##name(struct kobject *kobj, \ 196 - struct attribute *attr, \ 197 - const char *buf, ssize_t count) \ 198 - { \ 199 - \ 200 - return store_min_max_freq_khz(kobj, attr, buf, count, \ 201 - min_max); \ 202 - } 203 - 204 - #define show_uncore_min_max(name, min_max) \ 205 - static ssize_t show_##name(struct kobject *kobj, \ 206 - struct attribute *attr, char *buf) \ 207 - { \ 208 - \ 209 - return show_min_max_freq_khz(kobj, attr, buf, min_max); \ 210 - } 211 - 212 - store_uncore_min_max(min_freq_khz, 0); 213 - store_uncore_min_max(max_freq_khz, 1); 214 - 215 - show_uncore_min_max(min_freq_khz, 0); 216 - show_uncore_min_max(max_freq_khz, 1); 217 - 218 - define_one_uncore_rw(min_freq_khz); 219 - define_one_uncore_rw(max_freq_khz); 220 - 221 - static struct attribute *uncore_attrs[] = { 222 - &initial_min_freq_khz.attr, 223 - &initial_max_freq_khz.attr, 224 - &max_freq_khz.attr, 225 - &min_freq_khz.attr, 226 - NULL 227 - }; 228 - ATTRIBUTE_GROUPS(uncore); 229 - 230 - static void uncore_sysfs_entry_release(struct kobject *kobj) 231 - { 232 - struct uncore_data *data = to_uncore_data(kobj); 233 - 234 - complete(&data->kobj_unregister); 235 - } 236 - 237 - static struct kobj_type uncore_ktype = { 238 - .release = uncore_sysfs_entry_release, 239 - .sysfs_ops = &kobj_sysfs_ops, 240 - .default_groups = uncore_groups, 241 - }; 242 - 243 - /* Caller provides protection */ 244 - static struct uncore_data *uncore_get_instance(unsigned int cpu) 245 - { 246 - int id = topology_logical_die_id(cpu); 247 - 248 - if (id >= 0 && id < uncore_max_entries) 249 - return &uncore_instances[id]; 250 - 251 - return NULL; 252 - } 253 - 254 - static void uncore_add_die_entry(int cpu) 255 - { 256 - struct uncore_data *data; 257 - 258 - mutex_lock(&uncore_lock); 259 - data = uncore_get_instance(cpu); 260 - if (!data) { 261 - mutex_unlock(&uncore_lock); 262 - return; 263 - } 264 - 265 - if (data->valid) { 266 - /* control cpu changed */ 267 - data->control_cpu = cpu; 268 - } else { 269 - char str[64]; 270 - int ret; 271 - 272 - memset(data, 0, sizeof(*data)); 273 - sprintf(str, "package_%02d_die_%02d", 274 - topology_physical_package_id(cpu), 275 - topology_die_id(cpu)); 276 - 277 - uncore_read_ratio(data, &data->initial_min_freq_khz, 278 - &data->initial_max_freq_khz); 279 - 280 - init_completion(&data->kobj_unregister); 281 - 282 - ret = kobject_init_and_add(&data->kobj, &uncore_ktype, 283 - uncore_root_kobj, str); 284 - if (!ret) { 285 - data->control_cpu = cpu; 286 - data->valid = true; 287 - } 288 - } 289 - mutex_unlock(&uncore_lock); 290 - } 291 - 292 - /* Last CPU in this die is offline, make control cpu invalid */ 293 - static void uncore_remove_die_entry(int cpu) 294 - { 295 - struct uncore_data *data; 296 - 297 - mutex_lock(&uncore_lock); 298 - data = uncore_get_instance(cpu); 299 - if (data) 300 - data->control_cpu = -1; 301 - mutex_unlock(&uncore_lock); 302 - } 303 - 304 - static int uncore_event_cpu_online(unsigned int cpu) 305 - { 306 - int target; 307 - 308 - /* Check if there is an online cpu in the package for uncore MSR */ 309 - target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu)); 310 - if (target < nr_cpu_ids) 311 - return 0; 312 - 313 - /* Use this CPU on this die as a control CPU */ 314 - cpumask_set_cpu(cpu, &uncore_cpu_mask); 315 - uncore_add_die_entry(cpu); 316 - 317 - return 0; 318 - } 319 - 320 - static int uncore_event_cpu_offline(unsigned int cpu) 321 - { 322 - int target; 323 - 324 - /* Check if existing cpu is used for uncore MSRs */ 325 - if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) 326 - return 0; 327 - 328 - /* Find a new cpu to set uncore MSR */ 329 - target = cpumask_any_but(topology_die_cpumask(cpu), cpu); 330 - 331 - if (target < nr_cpu_ids) { 332 - cpumask_set_cpu(target, &uncore_cpu_mask); 333 - uncore_add_die_entry(target); 334 - } else { 335 - uncore_remove_die_entry(cpu); 336 - } 337 - 338 - return 0; 339 - } 340 - 341 - static int uncore_pm_notify(struct notifier_block *nb, unsigned long mode, 342 - void *_unused) 343 - { 344 - int cpu; 345 - 346 - switch (mode) { 347 - case PM_POST_HIBERNATION: 348 - case PM_POST_RESTORE: 349 - case PM_POST_SUSPEND: 350 - for_each_cpu(cpu, &uncore_cpu_mask) { 351 - struct uncore_data *data; 352 - int ret; 353 - 354 - data = uncore_get_instance(cpu); 355 - if (!data || !data->valid || !data->stored_uncore_data) 356 - continue; 357 - 358 - ret = wrmsrl_on_cpu(cpu, MSR_UNCORE_RATIO_LIMIT, 359 - data->stored_uncore_data); 360 - if (ret) 361 - return ret; 362 - } 363 - break; 364 - default: 365 - break; 366 - } 367 - return 0; 368 - } 369 - 370 - static struct notifier_block uncore_pm_nb = { 371 - .notifier_call = uncore_pm_notify, 372 - }; 373 - 374 - static const struct x86_cpu_id intel_uncore_cpu_ids[] = { 375 - X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, NULL), 376 - X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, NULL), 377 - X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, NULL), 378 - X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL), 379 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), 380 - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), 381 - X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL), 382 - {} 383 - }; 384 - 385 - static int __init intel_uncore_init(void) 386 - { 387 - const struct x86_cpu_id *id; 388 - int ret; 389 - 390 - id = x86_match_cpu(intel_uncore_cpu_ids); 391 - if (!id) 392 - return -ENODEV; 393 - 394 - uncore_max_entries = topology_max_packages() * 395 - topology_max_die_per_package(); 396 - uncore_instances = kcalloc(uncore_max_entries, 397 - sizeof(*uncore_instances), GFP_KERNEL); 398 - if (!uncore_instances) 399 - return -ENOMEM; 400 - 401 - uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency", 402 - &cpu_subsys.dev_root->kobj); 403 - if (!uncore_root_kobj) { 404 - ret = -ENOMEM; 405 - goto err_free; 406 - } 407 - 408 - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 409 - "platform/x86/uncore-freq:online", 410 - uncore_event_cpu_online, 411 - uncore_event_cpu_offline); 412 - if (ret < 0) 413 - goto err_rem_kobj; 414 - 415 - uncore_hp_state = ret; 416 - 417 - ret = register_pm_notifier(&uncore_pm_nb); 418 - if (ret) 419 - goto err_rem_state; 420 - 421 - return 0; 422 - 423 - err_rem_state: 424 - cpuhp_remove_state(uncore_hp_state); 425 - err_rem_kobj: 426 - kobject_put(uncore_root_kobj); 427 - err_free: 428 - kfree(uncore_instances); 429 - 430 - return ret; 431 - } 432 - module_init(intel_uncore_init) 433 - 434 - static void __exit intel_uncore_exit(void) 435 - { 436 - int i; 437 - 438 - unregister_pm_notifier(&uncore_pm_nb); 439 - cpuhp_remove_state(uncore_hp_state); 440 - for (i = 0; i < uncore_max_entries; ++i) { 441 - if (uncore_instances[i].valid) { 442 - kobject_put(&uncore_instances[i].kobj); 443 - wait_for_completion(&uncore_instances[i].kobj_unregister); 444 - } 445 - } 446 - kobject_put(uncore_root_kobj); 447 - kfree(uncore_instances); 448 - } 449 - module_exit(intel_uncore_exit) 450 - 451 - MODULE_LICENSE("GPL v2"); 452 - MODULE_DESCRIPTION("Intel Uncore Frequency Limits Driver");
+21
drivers/platform/x86/intel/uncore-frequency/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # Uncore Frquency control drivers 4 + # 5 + 6 + menu "Intel Uncore Frequency Control" 7 + depends on X86_64 || COMPILE_TEST 8 + 9 + config INTEL_UNCORE_FREQ_CONTROL 10 + tristate "Intel Uncore frequency control driver" 11 + depends on X86_64 12 + help 13 + This driver allows control of Uncore frequency limits on 14 + supported server platforms. 15 + 16 + Uncore frequency controls RING/LLC (last-level cache) clocks. 17 + 18 + To compile this driver as a module, choose M here: the module 19 + will be called intel-uncore-frequency. 20 + 21 + endmenu
+9
drivers/platform/x86/intel/uncore-frequency/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for linux/drivers/platform/x86/intel/uncore-frequency 4 + # 5 + 6 + obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency.o 7 + intel-uncore-frequency-y := uncore-frequency.o 8 + obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency-common.o 9 + intel-uncore-frequency-common-y := uncore-frequency-common.o
+252
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Uncore Frequency Control: Common code implementation 4 + * Copyright (c) 2022, Intel Corporation. 5 + * All rights reserved. 6 + * 7 + */ 8 + #include <linux/cpu.h> 9 + #include <linux/module.h> 10 + #include "uncore-frequency-common.h" 11 + 12 + /* Mutex to control all mutual exclusions */ 13 + static DEFINE_MUTEX(uncore_lock); 14 + /* Root of the all uncore sysfs kobjs */ 15 + static struct kobject *uncore_root_kobj; 16 + /* uncore instance count */ 17 + static int uncore_instance_count; 18 + 19 + /* callbacks for actual HW read/write */ 20 + static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned int *max); 21 + static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max); 22 + static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq); 23 + 24 + static ssize_t show_min_max_freq_khz(struct uncore_data *data, 25 + char *buf, int min_max) 26 + { 27 + unsigned int min, max; 28 + int ret; 29 + 30 + mutex_lock(&uncore_lock); 31 + ret = uncore_read(data, &min, &max); 32 + mutex_unlock(&uncore_lock); 33 + if (ret) 34 + return ret; 35 + 36 + if (min_max) 37 + return sprintf(buf, "%u\n", max); 38 + 39 + return sprintf(buf, "%u\n", min); 40 + } 41 + 42 + static ssize_t store_min_max_freq_khz(struct uncore_data *data, 43 + const char *buf, ssize_t count, 44 + int min_max) 45 + { 46 + unsigned int input; 47 + 48 + if (kstrtouint(buf, 10, &input)) 49 + return -EINVAL; 50 + 51 + mutex_lock(&uncore_lock); 52 + uncore_write(data, input, min_max); 53 + mutex_unlock(&uncore_lock); 54 + 55 + return count; 56 + } 57 + 58 + static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf) 59 + { 60 + unsigned int freq; 61 + int ret; 62 + 63 + mutex_lock(&uncore_lock); 64 + ret = uncore_read_freq(data, &freq); 65 + mutex_unlock(&uncore_lock); 66 + if (ret) 67 + return ret; 68 + 69 + return sprintf(buf, "%u\n", freq); 70 + } 71 + 72 + #define store_uncore_min_max(name, min_max) \ 73 + static ssize_t store_##name(struct device *dev, \ 74 + struct device_attribute *attr, \ 75 + const char *buf, size_t count) \ 76 + { \ 77 + struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ 78 + \ 79 + return store_min_max_freq_khz(data, buf, count, \ 80 + min_max); \ 81 + } 82 + 83 + #define show_uncore_min_max(name, min_max) \ 84 + static ssize_t show_##name(struct device *dev, \ 85 + struct device_attribute *attr, char *buf)\ 86 + { \ 87 + struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ 88 + \ 89 + return show_min_max_freq_khz(data, buf, min_max); \ 90 + } 91 + 92 + #define show_uncore_perf_status(name) \ 93 + static ssize_t show_##name(struct device *dev, \ 94 + struct device_attribute *attr, char *buf)\ 95 + { \ 96 + struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ 97 + \ 98 + return show_perf_status_freq_khz(data, buf); \ 99 + } 100 + 101 + store_uncore_min_max(min_freq_khz, 0); 102 + store_uncore_min_max(max_freq_khz, 1); 103 + 104 + show_uncore_min_max(min_freq_khz, 0); 105 + show_uncore_min_max(max_freq_khz, 1); 106 + 107 + show_uncore_perf_status(current_freq_khz); 108 + 109 + #define show_uncore_data(member_name) \ 110 + static ssize_t show_##member_name(struct device *dev, \ 111 + struct device_attribute *attr, char *buf)\ 112 + { \ 113 + struct uncore_data *data = container_of(attr, struct uncore_data,\ 114 + member_name##_dev_attr);\ 115 + \ 116 + return scnprintf(buf, PAGE_SIZE, "%u\n", \ 117 + data->member_name); \ 118 + } \ 119 + 120 + show_uncore_data(initial_min_freq_khz); 121 + show_uncore_data(initial_max_freq_khz); 122 + 123 + #define init_attribute_rw(_name) \ 124 + do { \ 125 + sysfs_attr_init(&data->_name##_dev_attr.attr); \ 126 + data->_name##_dev_attr.show = show_##_name; \ 127 + data->_name##_dev_attr.store = store_##_name; \ 128 + data->_name##_dev_attr.attr.name = #_name; \ 129 + data->_name##_dev_attr.attr.mode = 0644; \ 130 + } while (0) 131 + 132 + #define init_attribute_ro(_name) \ 133 + do { \ 134 + sysfs_attr_init(&data->_name##_dev_attr.attr); \ 135 + data->_name##_dev_attr.show = show_##_name; \ 136 + data->_name##_dev_attr.store = NULL; \ 137 + data->_name##_dev_attr.attr.name = #_name; \ 138 + data->_name##_dev_attr.attr.mode = 0444; \ 139 + } while (0) 140 + 141 + #define init_attribute_root_ro(_name) \ 142 + do { \ 143 + sysfs_attr_init(&data->_name##_dev_attr.attr); \ 144 + data->_name##_dev_attr.show = show_##_name; \ 145 + data->_name##_dev_attr.store = NULL; \ 146 + data->_name##_dev_attr.attr.name = #_name; \ 147 + data->_name##_dev_attr.attr.mode = 0400; \ 148 + } while (0) 149 + 150 + static int create_attr_group(struct uncore_data *data, char *name) 151 + { 152 + int ret, index = 0; 153 + 154 + init_attribute_rw(max_freq_khz); 155 + init_attribute_rw(min_freq_khz); 156 + init_attribute_ro(initial_min_freq_khz); 157 + init_attribute_ro(initial_max_freq_khz); 158 + init_attribute_root_ro(current_freq_khz); 159 + 160 + data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr; 161 + data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr; 162 + data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr; 163 + data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr; 164 + data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr; 165 + data->uncore_attrs[index] = NULL; 166 + 167 + data->uncore_attr_group.name = name; 168 + data->uncore_attr_group.attrs = data->uncore_attrs; 169 + ret = sysfs_create_group(uncore_root_kobj, &data->uncore_attr_group); 170 + 171 + return ret; 172 + } 173 + 174 + static void delete_attr_group(struct uncore_data *data, char *name) 175 + { 176 + sysfs_remove_group(uncore_root_kobj, &data->uncore_attr_group); 177 + } 178 + 179 + int uncore_freq_add_entry(struct uncore_data *data, int cpu) 180 + { 181 + int ret = 0; 182 + 183 + mutex_lock(&uncore_lock); 184 + if (data->valid) { 185 + /* control cpu changed */ 186 + data->control_cpu = cpu; 187 + goto uncore_unlock; 188 + } 189 + 190 + sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id); 191 + 192 + uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz); 193 + 194 + ret = create_attr_group(data, data->name); 195 + if (!ret) { 196 + data->control_cpu = cpu; 197 + data->valid = true; 198 + } 199 + 200 + uncore_unlock: 201 + mutex_unlock(&uncore_lock); 202 + 203 + return ret; 204 + } 205 + EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY); 206 + 207 + void uncore_freq_remove_die_entry(struct uncore_data *data) 208 + { 209 + mutex_lock(&uncore_lock); 210 + delete_attr_group(data, data->name); 211 + data->control_cpu = -1; 212 + data->valid = false; 213 + mutex_unlock(&uncore_lock); 214 + } 215 + EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY); 216 + 217 + int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max), 218 + int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int set_max), 219 + int (*read_freq)(struct uncore_data *data, unsigned int *freq)) 220 + { 221 + mutex_lock(&uncore_lock); 222 + 223 + uncore_read = read_control_freq; 224 + uncore_write = write_control_freq; 225 + uncore_read_freq = read_freq; 226 + 227 + if (!uncore_root_kobj) 228 + uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency", 229 + &cpu_subsys.dev_root->kobj); 230 + if (uncore_root_kobj) 231 + ++uncore_instance_count; 232 + mutex_unlock(&uncore_lock); 233 + 234 + return uncore_root_kobj ? 0 : -ENOMEM; 235 + } 236 + EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY); 237 + 238 + void uncore_freq_common_exit(void) 239 + { 240 + mutex_lock(&uncore_lock); 241 + --uncore_instance_count; 242 + if (!uncore_instance_count) { 243 + kobject_put(uncore_root_kobj); 244 + uncore_root_kobj = NULL; 245 + } 246 + mutex_unlock(&uncore_lock); 247 + } 248 + EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY); 249 + 250 + 251 + MODULE_LICENSE("GPL v2"); 252 + MODULE_DESCRIPTION("Intel Uncore Frequency Common Module");
+62
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Intel Uncore Frequency Control: Common defines and prototypes 4 + * Copyright (c) 2022, Intel Corporation. 5 + * All rights reserved. 6 + * 7 + */ 8 + 9 + #ifndef __INTEL_UNCORE_FREQ_COMMON_H 10 + #define __INTEL_UNCORE_FREQ_COMMON_H 11 + 12 + #include <linux/device.h> 13 + 14 + /** 15 + * struct uncore_data - Encapsulate all uncore data 16 + * @stored_uncore_data: Last user changed MSR 620 value, which will be restored 17 + * on system resume. 18 + * @initial_min_freq_khz: Sampled minimum uncore frequency at driver init 19 + * @initial_max_freq_khz: Sampled maximum uncore frequency at driver init 20 + * @control_cpu: Designated CPU for a die to read/write 21 + * @valid: Mark the data valid/invalid 22 + * @package_id: Package id for this instance 23 + * @die_id: Die id for this instance 24 + * @name: Sysfs entry name for this instance 25 + * @uncore_attr_group: Attribute group storage 26 + * @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz 27 + * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz 28 + * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_max_freq_khz 29 + * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_min_freq_khz 30 + * @current_freq_khz_dev_attr: Storage for device attribute current_freq_khz 31 + * @uncore_attrs: Attribute storage for group creation 32 + * 33 + * This structure is used to encapsulate all data related to uncore sysfs 34 + * settings for a die/package. 35 + */ 36 + struct uncore_data { 37 + u64 stored_uncore_data; 38 + u32 initial_min_freq_khz; 39 + u32 initial_max_freq_khz; 40 + int control_cpu; 41 + bool valid; 42 + int package_id; 43 + int die_id; 44 + char name[32]; 45 + 46 + struct attribute_group uncore_attr_group; 47 + struct device_attribute max_freq_khz_dev_attr; 48 + struct device_attribute min_freq_khz_dev_attr; 49 + struct device_attribute initial_max_freq_khz_dev_attr; 50 + struct device_attribute initial_min_freq_khz_dev_attr; 51 + struct device_attribute current_freq_khz_dev_attr; 52 + struct attribute *uncore_attrs[6]; 53 + }; 54 + 55 + int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, unsigned int *min, unsigned int *max), 56 + int (*write_control_freq)(struct uncore_data *data, unsigned int input, unsigned int min_max), 57 + int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq)); 58 + void uncore_freq_common_exit(void); 59 + int uncore_freq_add_entry(struct uncore_data *data, int cpu); 60 + void uncore_freq_remove_die_entry(struct uncore_data *data); 61 + 62 + #endif
+272
drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Uncore Frequency Setting 4 + * Copyright (c) 2022, Intel Corporation. 5 + * All rights reserved. 6 + * 7 + * Provide interface to set MSR 620 at a granularity of per die. On CPU online, 8 + * one control CPU is identified per die to read/write limit. This control CPU 9 + * is changed, if the CPU state is changed to offline. When the last CPU is 10 + * offline in a die then remove the sysfs object for that die. 11 + * The majority of actual code is related to sysfs create and read/write 12 + * attributes. 13 + * 14 + * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 15 + */ 16 + 17 + #include <linux/cpu.h> 18 + #include <linux/module.h> 19 + #include <linux/slab.h> 20 + #include <linux/suspend.h> 21 + #include <asm/cpu_device_id.h> 22 + #include <asm/intel-family.h> 23 + 24 + #include "uncore-frequency-common.h" 25 + 26 + /* Max instances for uncore data, one for each die */ 27 + static int uncore_max_entries __read_mostly; 28 + /* Storage for uncore data for all instances */ 29 + static struct uncore_data *uncore_instances; 30 + /* Stores the CPU mask of the target CPUs to use during uncore read/write */ 31 + static cpumask_t uncore_cpu_mask; 32 + /* CPU online callback register instance */ 33 + static enum cpuhp_state uncore_hp_state __read_mostly; 34 + 35 + #define MSR_UNCORE_RATIO_LIMIT 0x620 36 + #define MSR_UNCORE_PERF_STATUS 0x621 37 + #define UNCORE_FREQ_KHZ_MULTIPLIER 100000 38 + 39 + static int uncore_read_control_freq(struct uncore_data *data, unsigned int *min, 40 + unsigned int *max) 41 + { 42 + u64 cap; 43 + int ret; 44 + 45 + if (data->control_cpu < 0) 46 + return -ENXIO; 47 + 48 + ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); 49 + if (ret) 50 + return ret; 51 + 52 + *max = (cap & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; 53 + *min = ((cap & GENMASK(14, 8)) >> 8) * UNCORE_FREQ_KHZ_MULTIPLIER; 54 + 55 + return 0; 56 + } 57 + 58 + static int uncore_write_control_freq(struct uncore_data *data, unsigned int input, 59 + unsigned int min_max) 60 + { 61 + int ret; 62 + u64 cap; 63 + 64 + input /= UNCORE_FREQ_KHZ_MULTIPLIER; 65 + if (!input || input > 0x7F) 66 + return -EINVAL; 67 + 68 + if (data->control_cpu < 0) 69 + return -ENXIO; 70 + 71 + ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap); 72 + if (ret) 73 + return ret; 74 + 75 + if (min_max) { 76 + cap &= ~0x7F; 77 + cap |= input; 78 + } else { 79 + cap &= ~GENMASK(14, 8); 80 + cap |= (input << 8); 81 + } 82 + 83 + ret = wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, cap); 84 + if (ret) 85 + return ret; 86 + 87 + data->stored_uncore_data = cap; 88 + 89 + return 0; 90 + } 91 + 92 + static int uncore_read_freq(struct uncore_data *data, unsigned int *freq) 93 + { 94 + u64 ratio; 95 + int ret; 96 + 97 + if (data->control_cpu < 0) 98 + return -ENXIO; 99 + 100 + ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_PERF_STATUS, &ratio); 101 + if (ret) 102 + return ret; 103 + 104 + *freq = (ratio & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER; 105 + 106 + return 0; 107 + } 108 + 109 + /* Caller provides protection */ 110 + static struct uncore_data *uncore_get_instance(unsigned int cpu) 111 + { 112 + int id = topology_logical_die_id(cpu); 113 + 114 + if (id >= 0 && id < uncore_max_entries) 115 + return &uncore_instances[id]; 116 + 117 + return NULL; 118 + } 119 + 120 + static int uncore_event_cpu_online(unsigned int cpu) 121 + { 122 + struct uncore_data *data; 123 + int target; 124 + 125 + /* Check if there is an online cpu in the package for uncore MSR */ 126 + target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu)); 127 + if (target < nr_cpu_ids) 128 + return 0; 129 + 130 + /* Use this CPU on this die as a control CPU */ 131 + cpumask_set_cpu(cpu, &uncore_cpu_mask); 132 + 133 + data = uncore_get_instance(cpu); 134 + if (!data) 135 + return 0; 136 + 137 + data->package_id = topology_physical_package_id(cpu); 138 + data->die_id = topology_die_id(cpu); 139 + 140 + return uncore_freq_add_entry(data, cpu); 141 + } 142 + 143 + static int uncore_event_cpu_offline(unsigned int cpu) 144 + { 145 + struct uncore_data *data; 146 + int target; 147 + 148 + data = uncore_get_instance(cpu); 149 + if (!data) 150 + return 0; 151 + 152 + /* Check if existing cpu is used for uncore MSRs */ 153 + if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) 154 + return 0; 155 + 156 + /* Find a new cpu to set uncore MSR */ 157 + target = cpumask_any_but(topology_die_cpumask(cpu), cpu); 158 + 159 + if (target < nr_cpu_ids) { 160 + cpumask_set_cpu(target, &uncore_cpu_mask); 161 + uncore_freq_add_entry(data, target); 162 + } else { 163 + uncore_freq_remove_die_entry(data); 164 + } 165 + 166 + return 0; 167 + } 168 + 169 + static int uncore_pm_notify(struct notifier_block *nb, unsigned long mode, 170 + void *_unused) 171 + { 172 + int i; 173 + 174 + switch (mode) { 175 + case PM_POST_HIBERNATION: 176 + case PM_POST_RESTORE: 177 + case PM_POST_SUSPEND: 178 + for (i = 0; i < uncore_max_entries; ++i) { 179 + struct uncore_data *data = &uncore_instances[i]; 180 + 181 + if (!data || !data->valid || !data->stored_uncore_data) 182 + return 0; 183 + 184 + wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, 185 + data->stored_uncore_data); 186 + } 187 + break; 188 + default: 189 + break; 190 + } 191 + return 0; 192 + } 193 + 194 + static struct notifier_block uncore_pm_nb = { 195 + .notifier_call = uncore_pm_notify, 196 + }; 197 + 198 + static const struct x86_cpu_id intel_uncore_cpu_ids[] = { 199 + X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, NULL), 200 + X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, NULL), 201 + X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, NULL), 202 + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL), 203 + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), 204 + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), 205 + X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL), 206 + {} 207 + }; 208 + MODULE_DEVICE_TABLE(x86cpu, intel_uncore_cpu_ids); 209 + 210 + static int __init intel_uncore_init(void) 211 + { 212 + const struct x86_cpu_id *id; 213 + int ret; 214 + 215 + id = x86_match_cpu(intel_uncore_cpu_ids); 216 + if (!id) 217 + return -ENODEV; 218 + 219 + uncore_max_entries = topology_max_packages() * 220 + topology_max_die_per_package(); 221 + uncore_instances = kcalloc(uncore_max_entries, 222 + sizeof(*uncore_instances), GFP_KERNEL); 223 + if (!uncore_instances) 224 + return -ENOMEM; 225 + 226 + ret = uncore_freq_common_init(uncore_read_control_freq, uncore_write_control_freq, 227 + uncore_read_freq); 228 + if (ret) 229 + goto err_free; 230 + 231 + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 232 + "platform/x86/uncore-freq:online", 233 + uncore_event_cpu_online, 234 + uncore_event_cpu_offline); 235 + if (ret < 0) 236 + goto err_rem_kobj; 237 + 238 + uncore_hp_state = ret; 239 + 240 + ret = register_pm_notifier(&uncore_pm_nb); 241 + if (ret) 242 + goto err_rem_state; 243 + 244 + return 0; 245 + 246 + err_rem_state: 247 + cpuhp_remove_state(uncore_hp_state); 248 + err_rem_kobj: 249 + uncore_freq_common_exit(); 250 + err_free: 251 + kfree(uncore_instances); 252 + 253 + return ret; 254 + } 255 + module_init(intel_uncore_init) 256 + 257 + static void __exit intel_uncore_exit(void) 258 + { 259 + int i; 260 + 261 + unregister_pm_notifier(&uncore_pm_nb); 262 + cpuhp_remove_state(uncore_hp_state); 263 + for (i = 0; i < uncore_max_entries; ++i) 264 + uncore_freq_remove_die_entry(&uncore_instances[i]); 265 + uncore_freq_common_exit(); 266 + kfree(uncore_instances); 267 + } 268 + module_exit(intel_uncore_exit) 269 + 270 + MODULE_IMPORT_NS(INTEL_UNCORE_FREQUENCY); 271 + MODULE_LICENSE("GPL v2"); 272 + MODULE_DESCRIPTION("Intel Uncore Frequency Limits Driver");
+2 -5
drivers/platform/x86/intel/vbtn.c
··· 384 384 check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv) 385 385 { 386 386 const struct acpi_device_id *ids = context; 387 - struct acpi_device *dev; 387 + struct acpi_device *dev = acpi_fetch_acpi_dev(handle); 388 388 389 - if (acpi_bus_get_device(handle, &dev) != 0) 390 - return AE_OK; 391 - 392 - if (acpi_match_device_ids(dev, ids) == 0) 389 + if (dev && acpi_match_device_ids(dev, ids) == 0) 393 390 if (!IS_ERR_OR_NULL(acpi_create_platform_device(dev, NULL))) 394 391 dev_info(&dev->dev, 395 392 "intel-vbtn: created platform device\n");
+11 -1
drivers/platform/x86/intel/vsec.c
··· 32 32 #define TABLE_OFFSET_SHIFT 3 33 33 34 34 static DEFINE_IDA(intel_vsec_ida); 35 + static DEFINE_IDA(intel_vsec_sdsi_ida); 35 36 36 37 /** 37 38 * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers. ··· 64 63 VSEC_ID_TELEMETRY = 2, 65 64 VSEC_ID_WATCHER = 3, 66 65 VSEC_ID_CRASHLOG = 4, 66 + VSEC_ID_SDSI = 65, 67 67 }; 68 68 69 69 static enum intel_vsec_id intel_vsec_allow_list[] = { 70 70 VSEC_ID_TELEMETRY, 71 71 VSEC_ID_WATCHER, 72 72 VSEC_ID_CRASHLOG, 73 + VSEC_ID_SDSI, 73 74 }; 74 75 75 76 static const char *intel_vsec_name(enum intel_vsec_id id) ··· 85 82 86 83 case VSEC_ID_CRASHLOG: 87 84 return "crashlog"; 85 + 86 + case VSEC_ID_SDSI: 87 + return "sdsi"; 88 88 89 89 default: 90 90 return NULL; ··· 217 211 intel_vsec_dev->resource = res; 218 212 intel_vsec_dev->num_resources = header->num_entries; 219 213 intel_vsec_dev->quirks = quirks; 220 - intel_vsec_dev->ida = &intel_vsec_ida; 214 + 215 + if (header->id == VSEC_ID_SDSI) 216 + intel_vsec_dev->ida = &intel_vsec_sdsi_ida; 217 + else 218 + intel_vsec_dev->ida = &intel_vsec_ida; 221 219 222 220 return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id)); 223 221 }
+49 -8
drivers/platform/x86/lg-laptop.c
··· 17 17 #include <linux/platform_device.h> 18 18 #include <linux/types.h> 19 19 20 + #include <acpi/battery.h> 21 + 20 22 #define LED_DEVICE(_name, max, flag) struct led_classdev _name = { \ 21 23 .name = __stringify(_name), \ 22 24 .max_brightness = max, \ ··· 460 458 return sysfs_emit(buffer, "%d\n", status); 461 459 } 462 460 463 - static ssize_t battery_care_limit_store(struct device *dev, 464 - struct device_attribute *attr, 465 - const char *buffer, size_t count) 461 + static ssize_t charge_control_end_threshold_store(struct device *dev, 462 + struct device_attribute *attr, 463 + const char *buf, size_t count) 466 464 { 467 465 unsigned long value; 468 466 int ret; 469 467 470 - ret = kstrtoul(buffer, 10, &value); 468 + ret = kstrtoul(buf, 10, &value); 471 469 if (ret) 472 470 return ret; 473 471 ··· 488 486 return -EINVAL; 489 487 } 490 488 491 - static ssize_t battery_care_limit_show(struct device *dev, 492 - struct device_attribute *attr, 493 - char *buffer) 489 + static ssize_t charge_control_end_threshold_show(struct device *device, 490 + struct device_attribute *attr, 491 + char *buf) 494 492 { 495 493 unsigned int status; 496 494 union acpi_object *r; ··· 522 520 if (status != 80 && status != 100) 523 521 status = 0; 524 522 525 - return sysfs_emit(buffer, "%d\n", status); 523 + return sysfs_emit(buf, "%d\n", status); 524 + } 525 + 526 + static ssize_t battery_care_limit_show(struct device *dev, 527 + struct device_attribute *attr, 528 + char *buffer) 529 + { 530 + return charge_control_end_threshold_show(dev, attr, buffer); 531 + } 532 + 533 + static ssize_t battery_care_limit_store(struct device *dev, 534 + struct device_attribute *attr, 535 + const char *buffer, size_t count) 536 + { 537 + return charge_control_end_threshold_store(dev, attr, buffer, count); 526 538 } 527 539 528 540 static DEVICE_ATTR_RW(fan_mode); 529 541 static DEVICE_ATTR_RW(usb_charge); 530 542 static DEVICE_ATTR_RW(reader_mode); 531 543 static DEVICE_ATTR_RW(fn_lock); 544 + static DEVICE_ATTR_RW(charge_control_end_threshold); 532 545 static DEVICE_ATTR_RW(battery_care_limit); 546 + 547 + static int lg_battery_add(struct power_supply *battery) 548 + { 549 + if (device_create_file(&battery->dev, 550 + &dev_attr_charge_control_end_threshold)) 551 + return -ENODEV; 552 + 553 + return 0; 554 + } 555 + 556 + static int lg_battery_remove(struct power_supply *battery) 557 + { 558 + device_remove_file(&battery->dev, 559 + &dev_attr_charge_control_end_threshold); 560 + return 0; 561 + } 562 + 563 + static struct acpi_battery_hook battery_hook = { 564 + .add_battery = lg_battery_add, 565 + .remove_battery = lg_battery_remove, 566 + .name = "LG Battery Extension", 567 + }; 533 568 534 569 static struct attribute *dev_attributes[] = { 535 570 &dev_attr_fan_mode.attr, ··· 750 711 led_classdev_register(&pf_device->dev, &tpad_led); 751 712 752 713 wmi_input_setup(); 714 + battery_hook_register(&battery_hook); 753 715 754 716 return 0; 755 717 ··· 768 728 led_classdev_unregister(&tpad_led); 769 729 led_classdev_unregister(&kbd_backlight); 770 730 731 + battery_hook_unregister(&battery_hook); 771 732 wmi_input_destroy(); 772 733 platform_device_unregister(pf_device); 773 734 pf_device = NULL;
+419 -107
drivers/platform/x86/think-lmi.c
··· 16 16 #include <linux/fs.h> 17 17 #include <linux/string.h> 18 18 #include <linux/types.h> 19 + #include <linux/dmi.h> 19 20 #include <linux/wmi.h> 20 21 #include "firmware_attributes_class.h" 21 22 #include "think-lmi.h" ··· 26 25 MODULE_PARM_DESC(debug_support, "Enable debug command support"); 27 26 28 27 /* 29 - * Name: 30 - * Lenovo_BiosSetting 31 - * Description: 32 - * Get item name and settings for current LMI instance. 33 - * Type: 34 - * Query 35 - * Returns: 36 - * "Item,Value" 37 - * Example: 38 - * "WakeOnLAN,Enable" 28 + * Name: BiosSetting 29 + * Description: Get item name and settings for current LMI instance. 30 + * Type: Query 31 + * Returns: "Item,Value" 32 + * Example: "WakeOnLAN,Enable" 39 33 */ 40 34 #define LENOVO_BIOS_SETTING_GUID "51F5230E-9677-46CD-A1CF-C0B23EE34DB7" 41 35 42 36 /* 43 - * Name: 44 - * Lenovo_SetBiosSetting 45 - * Description: 46 - * Change the BIOS setting to the desired value using the Lenovo_SetBiosSetting 47 - * class. To save the settings, use the Lenovo_SaveBiosSetting class. 37 + * Name: SetBiosSetting 38 + * Description: Change the BIOS setting to the desired value using the SetBiosSetting 39 + * class. To save the settings, use the SaveBiosSetting class. 48 40 * BIOS settings and values are case sensitive. 49 41 * After making changes to the BIOS settings, you must reboot the computer 50 42 * before the changes will take effect. 51 - * Type: 52 - * Method 53 - * Arguments: 54 - * "Item,Value,Password,Encoding,KbdLang;" 55 - * Example: 56 - * "WakeOnLAN,Disable,pa55w0rd,ascii,us;" 43 + * Type: Method 44 + * Arguments: "Item,Value,Password,Encoding,KbdLang;" 45 + * Example: "WakeOnLAN,Disable,pa55w0rd,ascii,us;" 57 46 */ 58 47 #define LENOVO_SET_BIOS_SETTINGS_GUID "98479A64-33F5-4E33-A707-8E251EBBC3A1" 59 48 60 49 /* 61 - * Name: 62 - * Lenovo_SaveBiosSettings 63 - * Description: 64 - * Save any pending changes in settings. 65 - * Type: 66 - * Method 67 - * Arguments: 68 - * "Password,Encoding,KbdLang;" 69 - * Example: 70 - * "pa55w0rd,ascii,us;" 50 + * Name: SaveBiosSettings 51 + * Description: Save any pending changes in settings. 52 + * Type: Method 53 + * Arguments: "Password,Encoding,KbdLang;" 54 + * Example: "pa55w0rd,ascii,us;" 71 55 */ 72 56 #define LENOVO_SAVE_BIOS_SETTINGS_GUID "6A4B54EF-A5ED-4D33-9455-B0D9B48DF4B3" 73 57 74 58 /* 75 - * Name: 76 - * Lenovo_BiosPasswordSettings 77 - * Description: 78 - * Return BIOS Password settings 79 - * Type: 80 - * Query 81 - * Returns: 82 - * PasswordMode, PasswordState, MinLength, MaxLength, 59 + * Name: BiosPasswordSettings 60 + * Description: Return BIOS Password settings 61 + * Type: Query 62 + * Returns: PasswordMode, PasswordState, MinLength, MaxLength, 83 63 * SupportedEncoding, SupportedKeyboard 84 64 */ 85 65 #define LENOVO_BIOS_PASSWORD_SETTINGS_GUID "8ADB159E-1E32-455C-BC93-308A7ED98246" 86 66 87 67 /* 88 - * Name: 89 - * Lenovo_SetBiosPassword 90 - * Description: 91 - * Change a specific password. 68 + * Name: SetBiosPassword 69 + * Description: Change a specific password. 92 70 * - BIOS settings cannot be changed at the same boot as power-on 93 71 * passwords (POP) and hard disk passwords (HDP). If you want to change 94 72 * BIOS settings and POP or HDP, you must reboot the system after changing 95 73 * one of them. 96 74 * - A password cannot be set using this method when one does not already 97 75 * exist. Passwords can only be updated or cleared. 98 - * Type: 99 - * Method 100 - * Arguments: 101 - * "PasswordType,CurrentPassword,NewPassword,Encoding,KbdLang;" 102 - * Example: 103 - * "pop,pa55w0rd,newpa55w0rd,ascii,us;” 76 + * Type: Method 77 + * Arguments: "PasswordType,CurrentPassword,NewPassword,Encoding,KbdLang;" 78 + * Example: "pop,pa55w0rd,newpa55w0rd,ascii,us;” 104 79 */ 105 80 #define LENOVO_SET_BIOS_PASSWORD_GUID "2651D9FD-911C-4B69-B94E-D0DED5963BD7" 106 81 107 82 /* 108 - * Name: 109 - * Lenovo_GetBiosSelections 110 - * Description: 111 - * Return a list of valid settings for a given item. 112 - * Type: 113 - * Method 114 - * Arguments: 115 - * "Item" 116 - * Returns: 117 - * "Value1,Value2,Value3,..." 83 + * Name: GetBiosSelections 84 + * Description: Return a list of valid settings for a given item. 85 + * Type: Method 86 + * Arguments: "Item" 87 + * Returns: "Value1,Value2,Value3,..." 118 88 * Example: 119 89 * -> "FlashOverLAN" 120 90 * <- "Enabled,Disabled" ··· 93 121 #define LENOVO_GET_BIOS_SELECTIONS_GUID "7364651A-132F-4FE7-ADAA-40C6C7EE2E3B" 94 122 95 123 /* 96 - * Name: 97 - * Lenovo_DebugCmdGUID 98 - * Description 99 - * Debug entry GUID method for entering debug commands to the BIOS 124 + * Name: DebugCmd 125 + * Description: Debug entry method for entering debug commands to the BIOS 100 126 */ 101 127 #define LENOVO_DEBUG_CMD_GUID "7FF47003-3B6C-4E5E-A227-E979824A85D1" 102 128 103 129 /* 104 - * Name: 105 - * Lenovo_OpcodeIF 106 - * Description: 107 - * Opcode interface which provides the ability to set multiple 130 + * Name: OpcodeIF 131 + * Description: Opcode interface which provides the ability to set multiple 108 132 * parameters and then trigger an action with a final command. 109 133 * This is particularly useful for simplifying setting passwords. 110 134 * With this support comes the ability to set System, HDD and NVMe ··· 109 141 */ 110 142 #define LENOVO_OPCODE_IF_GUID "DFDDEF2C-57D4-48ce-B196-0FB787D90836" 111 143 144 + /* 145 + * Name: SetBiosCert 146 + * Description: Install BIOS certificate. 147 + * Type: Method 148 + * Arguments: "Certificate,Password" 149 + * You must reboot the computer before the changes will take effect. 150 + */ 151 + #define LENOVO_SET_BIOS_CERT_GUID "26861C9F-47E9-44C4-BD8B-DFE7FA2610FE" 152 + 153 + /* 154 + * Name: UpdateBiosCert 155 + * Description: Update BIOS certificate. 156 + * Type: Method 157 + * Format: "Certificate,Signature" 158 + * You must reboot the computer before the changes will take effect. 159 + */ 160 + #define LENOVO_UPDATE_BIOS_CERT_GUID "9AA3180A-9750-41F7-B9F7-D5D3B1BAC3CE" 161 + 162 + /* 163 + * Name: ClearBiosCert 164 + * Description: Uninstall BIOS certificate. 165 + * Type: Method 166 + * Format: "Serial,Signature" 167 + * You must reboot the computer before the changes will take effect. 168 + */ 169 + #define LENOVO_CLEAR_BIOS_CERT_GUID "B2BC39A7-78DD-4D71-B059-A510DEC44890" 170 + /* 171 + * Name: CertToPassword 172 + * Description: Switch from certificate to password authentication. 173 + * Type: Method 174 + * Format: "Password,Signature" 175 + * You must reboot the computer before the changes will take effect. 176 + */ 177 + #define LENOVO_CERT_TO_PASSWORD_GUID "0DE8590D-5510-4044-9621-77C227F5A70D" 178 + 179 + /* 180 + * Name: SetBiosSettingCert 181 + * Description: Set attribute using certificate authentication. 182 + * Type: Method 183 + * Format: "Item,Value,Signature" 184 + */ 185 + #define LENOVO_SET_BIOS_SETTING_CERT_GUID "34A008CC-D205-4B62-9E67-31DFA8B90003" 186 + 187 + /* 188 + * Name: SaveBiosSettingCert 189 + * Description: Save any pending changes in settings. 190 + * Type: Method 191 + * Format: "Signature" 192 + */ 193 + #define LENOVO_SAVE_BIOS_SETTING_CERT_GUID "C050FB9D-DF5F-4606-B066-9EFC401B2551" 194 + 195 + /* 196 + * Name: CertThumbprint 197 + * Description: Display Certificate thumbprints 198 + * Type: Query 199 + * Returns: MD5, SHA1 & SHA256 thumbprints 200 + */ 201 + #define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4" 202 + 112 203 #define TLMI_POP_PWD (1 << 0) 113 204 #define TLMI_PAP_PWD (1 << 1) 114 205 #define TLMI_HDD_PWD (1 << 2) 115 206 #define TLMI_SYS_PWD (1 << 3) 207 + #define TLMI_CERT (1 << 7) 208 + 116 209 #define to_tlmi_pwd_setting(kobj) container_of(kobj, struct tlmi_pwd_setting, kobj) 117 210 #define to_tlmi_attr_setting(kobj) container_of(kobj, struct tlmi_attr_setting, kobj) 118 211 ··· 197 168 static struct class *fw_attr_class; 198 169 199 170 /* ------ Utility functions ------------*/ 171 + /* Strip out CR if one is present */ 172 + static void strip_cr(char *str) 173 + { 174 + char *p = strchrnul(str, '\n'); 175 + *p = '\0'; 176 + } 177 + 200 178 /* Convert BIOS WMI error string to suitable error code */ 201 179 static int tlmi_errstr_to_err(const char *errstr) 202 180 { ··· 401 365 { 402 366 struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 403 367 size_t pwdlen; 404 - char *p; 405 368 406 369 pwdlen = strlen(buf); 407 370 /* pwdlen == 0 is allowed to clear the password */ ··· 409 374 410 375 strscpy(setting->password, buf, setting->maxlen); 411 376 /* Strip out CR if one is present, setting password won't work if it is present */ 412 - p = strchrnul(setting->password, '\n'); 413 - *p = '\0'; 377 + strip_cr(setting->password); 414 378 return count; 415 379 } 416 380 ··· 420 386 const char *buf, size_t count) 421 387 { 422 388 struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 423 - char *auth_str, *new_pwd, *p; 389 + char *auth_str, *new_pwd; 424 390 size_t pwdlen; 425 391 int ret; 426 392 ··· 435 401 return -ENOMEM; 436 402 437 403 /* Strip out CR if one is present, setting password won't work if it is present */ 438 - p = strchrnul(new_pwd, '\n'); 439 - *p = '\0'; 404 + strip_cr(new_pwd); 440 405 441 406 pwdlen = strlen(new_pwd); 442 407 /* pwdlen == 0 is allowed to clear the password */ ··· 641 608 642 609 static struct kobj_attribute auth_level = __ATTR_RW(level); 643 610 611 + static ssize_t cert_thumbprint(char *buf, const char *arg, int count) 612 + { 613 + const struct acpi_buffer input = { strlen(arg), (char *)arg }; 614 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 615 + const union acpi_object *obj; 616 + acpi_status status; 617 + 618 + status = wmi_evaluate_method(LENOVO_CERT_THUMBPRINT_GUID, 0, 0, &input, &output); 619 + if (ACPI_FAILURE(status)) { 620 + kfree(output.pointer); 621 + return -EIO; 622 + } 623 + obj = output.pointer; 624 + if (!obj) 625 + return -ENOMEM; 626 + if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer) { 627 + kfree(output.pointer); 628 + return -EIO; 629 + } 630 + count += sysfs_emit_at(buf, count, "%s : %s\n", arg, (char *)obj->string.pointer); 631 + kfree(output.pointer); 632 + 633 + return count; 634 + } 635 + 636 + static ssize_t certificate_thumbprint_show(struct kobject *kobj, struct kobj_attribute *attr, 637 + char *buf) 638 + { 639 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 640 + int count = 0; 641 + 642 + if (!tlmi_priv.certificate_support || !setting->cert_installed) 643 + return -EOPNOTSUPP; 644 + 645 + count += cert_thumbprint(buf, "Md5", count); 646 + count += cert_thumbprint(buf, "Sha1", count); 647 + count += cert_thumbprint(buf, "Sha256", count); 648 + return count; 649 + } 650 + 651 + static struct kobj_attribute auth_cert_thumb = __ATTR_RO(certificate_thumbprint); 652 + 653 + static ssize_t cert_to_password_store(struct kobject *kobj, 654 + struct kobj_attribute *attr, 655 + const char *buf, size_t count) 656 + { 657 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 658 + char *auth_str, *passwd; 659 + int ret; 660 + 661 + if (!capable(CAP_SYS_ADMIN)) 662 + return -EPERM; 663 + 664 + if (!tlmi_priv.certificate_support) 665 + return -EOPNOTSUPP; 666 + 667 + if (!setting->cert_installed) 668 + return -EINVAL; 669 + 670 + if (!setting->signature || !setting->signature[0]) 671 + return -EACCES; 672 + 673 + passwd = kstrdup(buf, GFP_KERNEL); 674 + if (!passwd) 675 + return -ENOMEM; 676 + 677 + /* Strip out CR if one is present */ 678 + strip_cr(passwd); 679 + 680 + /* Format: 'Password,Signature' */ 681 + auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature); 682 + if (!auth_str) { 683 + kfree(passwd); 684 + return -ENOMEM; 685 + } 686 + ret = tlmi_simple_call(LENOVO_CERT_TO_PASSWORD_GUID, auth_str); 687 + kfree(auth_str); 688 + kfree(passwd); 689 + 690 + return ret ?: count; 691 + } 692 + 693 + static struct kobj_attribute auth_cert_to_password = __ATTR_WO(cert_to_password); 694 + 695 + static ssize_t certificate_store(struct kobject *kobj, 696 + struct kobj_attribute *attr, 697 + const char *buf, size_t count) 698 + { 699 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 700 + char *auth_str, *new_cert; 701 + char *guid; 702 + int ret; 703 + 704 + if (!capable(CAP_SYS_ADMIN)) 705 + return -EPERM; 706 + 707 + if (!tlmi_priv.certificate_support) 708 + return -EOPNOTSUPP; 709 + 710 + new_cert = kstrdup(buf, GFP_KERNEL); 711 + if (!new_cert) 712 + return -ENOMEM; 713 + /* Strip out CR if one is present */ 714 + strip_cr(new_cert); 715 + 716 + /* If empty then clear installed certificate */ 717 + if (new_cert[0] == '\0') { /* Clear installed certificate */ 718 + kfree(new_cert); 719 + 720 + /* Check that signature is set */ 721 + if (!setting->signature || !setting->signature[0]) 722 + return -EACCES; 723 + 724 + /* Format: 'serial#, signature' */ 725 + auth_str = kasprintf(GFP_KERNEL, "%s,%s", 726 + dmi_get_system_info(DMI_PRODUCT_SERIAL), 727 + setting->signature); 728 + if (!auth_str) 729 + return -ENOMEM; 730 + 731 + ret = tlmi_simple_call(LENOVO_CLEAR_BIOS_CERT_GUID, auth_str); 732 + kfree(auth_str); 733 + if (ret) 734 + return ret; 735 + 736 + kfree(setting->certificate); 737 + setting->certificate = NULL; 738 + return count; 739 + } 740 + 741 + if (setting->cert_installed) { 742 + /* Certificate is installed so this is an update */ 743 + if (!setting->signature || !setting->signature[0]) { 744 + kfree(new_cert); 745 + return -EACCES; 746 + } 747 + guid = LENOVO_UPDATE_BIOS_CERT_GUID; 748 + /* Format: 'Certificate,Signature' */ 749 + auth_str = kasprintf(GFP_KERNEL, "%s,%s", 750 + new_cert, setting->signature); 751 + } else { 752 + /* This is a fresh install */ 753 + if (!setting->valid || !setting->password[0]) { 754 + kfree(new_cert); 755 + return -EACCES; 756 + } 757 + guid = LENOVO_SET_BIOS_CERT_GUID; 758 + /* Format: 'Certificate,Admin-password' */ 759 + auth_str = kasprintf(GFP_KERNEL, "%s,%s", 760 + new_cert, setting->password); 761 + } 762 + if (!auth_str) { 763 + kfree(new_cert); 764 + return -ENOMEM; 765 + } 766 + 767 + ret = tlmi_simple_call(guid, auth_str); 768 + kfree(auth_str); 769 + if (ret) { 770 + kfree(new_cert); 771 + return ret; 772 + } 773 + 774 + kfree(setting->certificate); 775 + setting->certificate = new_cert; 776 + return count; 777 + } 778 + 779 + static struct kobj_attribute auth_certificate = __ATTR_WO(certificate); 780 + 781 + static ssize_t signature_store(struct kobject *kobj, 782 + struct kobj_attribute *attr, 783 + const char *buf, size_t count) 784 + { 785 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 786 + char *new_signature; 787 + 788 + if (!capable(CAP_SYS_ADMIN)) 789 + return -EPERM; 790 + 791 + if (!tlmi_priv.certificate_support) 792 + return -EOPNOTSUPP; 793 + 794 + new_signature = kstrdup(buf, GFP_KERNEL); 795 + if (!new_signature) 796 + return -ENOMEM; 797 + 798 + /* Strip out CR if one is present */ 799 + strip_cr(new_signature); 800 + 801 + /* Free any previous signature */ 802 + kfree(setting->signature); 803 + setting->signature = new_signature; 804 + 805 + return count; 806 + } 807 + 808 + static struct kobj_attribute auth_signature = __ATTR_WO(signature); 809 + 810 + static ssize_t save_signature_store(struct kobject *kobj, 811 + struct kobj_attribute *attr, 812 + const char *buf, size_t count) 813 + { 814 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 815 + char *new_signature; 816 + 817 + if (!capable(CAP_SYS_ADMIN)) 818 + return -EPERM; 819 + 820 + if (!tlmi_priv.certificate_support) 821 + return -EOPNOTSUPP; 822 + 823 + new_signature = kstrdup(buf, GFP_KERNEL); 824 + if (!new_signature) 825 + return -ENOMEM; 826 + 827 + /* Strip out CR if one is present */ 828 + strip_cr(new_signature); 829 + 830 + /* Free any previous signature */ 831 + kfree(setting->save_signature); 832 + setting->save_signature = new_signature; 833 + 834 + return count; 835 + } 836 + 837 + static struct kobj_attribute auth_save_signature = __ATTR_WO(save_signature); 838 + 644 839 static umode_t auth_attr_is_visible(struct kobject *kobj, 645 840 struct attribute *attr, int n) 646 841 { 647 842 struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 648 843 649 - /*We only want to display level and index settings on HDD/NVMe */ 844 + /* We only want to display level and index settings on HDD/NVMe */ 650 845 if ((attr == (struct attribute *)&auth_index) || 651 846 (attr == (struct attribute *)&auth_level)) { 652 847 if ((setting == tlmi_priv.pwd_hdd) || (setting == tlmi_priv.pwd_nvme)) 653 848 return attr->mode; 654 849 return 0; 655 850 } 851 + 852 + /* We only display certificates on Admin account, if supported */ 853 + if ((attr == (struct attribute *)&auth_certificate) || 854 + (attr == (struct attribute *)&auth_signature) || 855 + (attr == (struct attribute *)&auth_save_signature) || 856 + (attr == (struct attribute *)&auth_cert_thumb) || 857 + (attr == (struct attribute *)&auth_cert_to_password)) { 858 + if ((setting == tlmi_priv.pwd_admin) && tlmi_priv.certificate_support) 859 + return attr->mode; 860 + return 0; 861 + } 862 + 656 863 return attr->mode; 657 864 } 658 865 ··· 908 635 &auth_kbdlang.attr, 909 636 &auth_index.attr, 910 637 &auth_level.attr, 638 + &auth_certificate.attr, 639 + &auth_signature.attr, 640 + &auth_save_signature.attr, 641 + &auth_cert_thumb.attr, 642 + &auth_cert_to_password.attr, 911 643 NULL 912 644 }; 913 645 ··· 967 689 struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj); 968 690 char *set_str = NULL, *new_setting = NULL; 969 691 char *auth_str = NULL; 970 - char *p; 971 692 int ret; 972 693 973 694 if (!tlmi_priv.can_set_bios_settings) ··· 977 700 return -ENOMEM; 978 701 979 702 /* Strip out CR if one is present */ 980 - p = strchrnul(new_setting, '\n'); 981 - *p = '\0'; 703 + strip_cr(new_setting); 982 704 983 - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { 984 - auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", 985 - tlmi_priv.pwd_admin->password, 986 - encoding_options[tlmi_priv.pwd_admin->encoding], 987 - tlmi_priv.pwd_admin->kbdlang); 988 - if (!auth_str) { 705 + /* Check if certificate authentication is enabled and active */ 706 + if (tlmi_priv.certificate_support && tlmi_priv.pwd_admin->cert_installed) { 707 + if (!tlmi_priv.pwd_admin->signature || !tlmi_priv.pwd_admin->save_signature) { 708 + ret = -EINVAL; 709 + goto out; 710 + } 711 + set_str = kasprintf(GFP_KERNEL, "%s,%s,%s", setting->display_name, 712 + new_setting, tlmi_priv.pwd_admin->signature); 713 + if (!set_str) { 989 714 ret = -ENOMEM; 990 715 goto out; 991 716 } 717 + 718 + ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTING_CERT_GUID, set_str); 719 + if (ret) 720 + goto out; 721 + ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID, 722 + tlmi_priv.pwd_admin->save_signature); 723 + if (ret) 724 + goto out; 725 + } else { /* Non certiifcate based authentication */ 726 + if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { 727 + auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", 728 + tlmi_priv.pwd_admin->password, 729 + encoding_options[tlmi_priv.pwd_admin->encoding], 730 + tlmi_priv.pwd_admin->kbdlang); 731 + if (!auth_str) { 732 + ret = -ENOMEM; 733 + goto out; 734 + } 735 + } 736 + 737 + if (auth_str) 738 + set_str = kasprintf(GFP_KERNEL, "%s,%s,%s", setting->display_name, 739 + new_setting, auth_str); 740 + else 741 + set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name, 742 + new_setting); 743 + if (!set_str) { 744 + ret = -ENOMEM; 745 + goto out; 746 + } 747 + 748 + ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTINGS_GUID, set_str); 749 + if (ret) 750 + goto out; 751 + 752 + if (auth_str) 753 + ret = tlmi_save_bios_settings(auth_str); 754 + else 755 + ret = tlmi_save_bios_settings(""); 992 756 } 993 - 994 - if (auth_str) 995 - set_str = kasprintf(GFP_KERNEL, "%s,%s,%s", setting->display_name, 996 - new_setting, auth_str); 997 - else 998 - set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name, 999 - new_setting); 1000 - if (!set_str) { 1001 - ret = -ENOMEM; 1002 - goto out; 1003 - } 1004 - 1005 - ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTINGS_GUID, set_str); 1006 - if (ret) 1007 - goto out; 1008 - 1009 - if (auth_str) 1010 - ret = tlmi_save_bios_settings(auth_str); 1011 - else 1012 - ret = tlmi_save_bios_settings(""); 1013 - 1014 757 if (!ret && !tlmi_priv.pending_changes) { 1015 758 tlmi_priv.pending_changes = true; 1016 759 /* let userland know it may need to check reboot pending again */ ··· 1126 829 { 1127 830 char *set_str = NULL, *new_setting = NULL; 1128 831 char *auth_str = NULL; 1129 - char *p; 1130 832 int ret; 1131 833 1132 834 if (!tlmi_priv.can_debug_cmd) ··· 1136 840 return -ENOMEM; 1137 841 1138 842 /* Strip out CR if one is present */ 1139 - p = strchrnul(new_setting, '\n'); 1140 - *p = '\0'; 843 + strip_cr(new_setting); 1141 844 1142 845 if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { 1143 846 auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", ··· 1191 896 sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr); 1192 897 if (tlmi_priv.can_debug_cmd && debug_support) 1193 898 sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr); 899 + 1194 900 kset_unregister(tlmi_priv.attribute_kset); 1195 901 1196 902 /* Authentication structures */ ··· 1210 914 } 1211 915 1212 916 kset_unregister(tlmi_priv.authentication_kset); 917 + 918 + /* Free up any saved certificates/signatures */ 919 + kfree(tlmi_priv.pwd_admin->certificate); 920 + kfree(tlmi_priv.pwd_admin->signature); 921 + kfree(tlmi_priv.pwd_admin->save_signature); 1213 922 } 1214 923 1215 924 static int tlmi_sysfs_init(void) ··· 1276 975 if (ret) 1277 976 goto fail_create_attr; 1278 977 } 978 + 1279 979 /* Create authentication entries */ 1280 980 tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL, 1281 981 &tlmi_priv.class_dev->kobj); ··· 1389 1087 if (wmi_has_guid(LENOVO_OPCODE_IF_GUID)) 1390 1088 tlmi_priv.opcode_support = true; 1391 1089 1090 + if (wmi_has_guid(LENOVO_SET_BIOS_CERT_GUID) && 1091 + wmi_has_guid(LENOVO_SET_BIOS_SETTING_CERT_GUID) && 1092 + wmi_has_guid(LENOVO_SAVE_BIOS_SETTING_CERT_GUID)) 1093 + tlmi_priv.certificate_support = true; 1094 + 1392 1095 /* 1393 1096 * Try to find the number of valid settings of this machine 1394 1097 * and use it to create sysfs attributes. ··· 1505 1198 } 1506 1199 } 1507 1200 } 1201 + 1202 + if (tlmi_priv.certificate_support && 1203 + (tlmi_priv.pwdcfg.core.password_state & TLMI_CERT)) 1204 + tlmi_priv.pwd_admin->cert_installed = true; 1205 + 1508 1206 return 0; 1509 1207 1510 1208 fail_clear_attr:
+5
drivers/platform/x86/think-lmi.h
··· 62 62 char kbdlang[TLMI_LANG_MAXLEN]; 63 63 int index; /*Used for HDD and NVME auth */ 64 64 enum level_option level; 65 + bool cert_installed; 66 + char *certificate; 67 + char *signature; 68 + char *save_signature; 65 69 }; 66 70 67 71 /* Attribute setting details */ ··· 86 82 bool pending_changes; 87 83 bool can_debug_cmd; 88 84 bool opcode_support; 85 + bool certificate_support; 89 86 90 87 struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT]; 91 88 struct device *class_dev;
+144 -77
drivers/platform/x86/thinkpad_acpi.c
··· 728 728 static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle, 729 729 u32 level, void *context, void **return_value) 730 730 { 731 - struct acpi_device *dev; 732 731 if (!strcmp(context, "video")) { 733 - if (acpi_bus_get_device(handle, &dev)) 734 - return AE_OK; 735 - if (strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev))) 732 + struct acpi_device *dev = acpi_fetch_acpi_dev(handle); 733 + 734 + if (!dev || strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev))) 736 735 return AE_OK; 737 736 } 738 737 ··· 785 786 static int __init setup_acpi_notify(struct ibm_struct *ibm) 786 787 { 787 788 acpi_status status; 788 - int rc; 789 789 790 790 BUG_ON(!ibm->acpi); 791 791 ··· 794 796 vdbg_printk(TPACPI_DBG_INIT, 795 797 "setting up ACPI notify for %s\n", ibm->name); 796 798 797 - rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); 798 - if (rc < 0) { 799 - pr_err("acpi_bus_get_device(%s) failed: %d\n", ibm->name, rc); 799 + ibm->acpi->device = acpi_fetch_acpi_dev(*ibm->acpi->handle); 800 + if (!ibm->acpi->device) { 801 + pr_err("acpi_fetch_acpi_dev(%s) failed\n", ibm->name); 800 802 return -ENODEV; 801 803 } 802 804 ··· 6721 6723 struct acpi_device *device, *child; 6722 6724 int rc; 6723 6725 6724 - if (acpi_bus_get_device(handle, &device)) 6726 + device = acpi_fetch_acpi_dev(handle); 6727 + if (!device) 6725 6728 return 0; 6726 6729 6727 6730 rc = 0; ··· 8285 8286 case TPACPI_FAN_WR_ACPI_FANS: 8286 8287 case TPACPI_FAN_WR_TPEC: 8287 8288 rc = fan_get_status(&s); 8288 - if (rc < 0) 8289 + if (rc) 8289 8290 break; 8290 8291 8291 8292 /* Don't go out of emergency fan mode */ ··· 8304 8305 8305 8306 case TPACPI_FAN_WR_ACPI_SFAN: 8306 8307 rc = fan_get_status(&s); 8307 - if (rc < 0) 8308 + if (rc) 8308 8309 break; 8309 8310 8310 8311 s &= 0x07; ··· 8698 8699 TPACPI_Q_LNV3('N', '2', 'N', TPACPI_FAN_2CTL), /* P53 / P73 */ 8699 8700 TPACPI_Q_LNV3('N', '2', 'E', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (1st gen) */ 8700 8701 TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (2nd gen) */ 8701 - TPACPI_Q_LNV3('N', '2', 'V', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (3nd gen) */ 8702 - TPACPI_Q_LNV3('N', '4', '0', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (4nd gen) */ 8703 8702 TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL), /* P15 (1st gen) / P15v (1st gen) */ 8704 - TPACPI_Q_LNV3('N', '3', '2', TPACPI_FAN_2CTL), /* X1 Carbon (9th gen) */ 8705 8703 TPACPI_Q_LNV3('N', '3', '7', TPACPI_FAN_2CTL), /* T15g (2nd gen) */ 8706 8704 TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */ 8707 8705 }; ··· 8742 8746 * ThinkPad ECs supports the fan control register */ 8743 8747 if (likely(acpi_ec_read(fan_status_offset, 8744 8748 &fan_control_initial_status))) { 8749 + int res; 8750 + unsigned int speed; 8751 + 8745 8752 fan_status_access_mode = TPACPI_FAN_RD_TPEC; 8746 8753 if (quirks & TPACPI_FAN_Q1) 8747 8754 fan_quirk1_setup(); ··· 8757 8758 tp_features.second_fan_ctl = 1; 8758 8759 pr_info("secondary fan control enabled\n"); 8759 8760 } 8761 + /* Try and probe the 2nd fan */ 8762 + res = fan2_get_speed(&speed); 8763 + if (res >= 0) { 8764 + /* It responded - so let's assume it's there */ 8765 + tp_features.second_fan = 1; 8766 + tp_features.second_fan_ctl = 1; 8767 + pr_info("secondary fan control detected & enabled\n"); 8768 + } 8769 + 8760 8770 } else { 8761 8771 pr_err("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n"); 8762 8772 return -ENODEV; ··· 8843 8835 /* Store fan status in cache */ 8844 8836 fan_control_resume_level = 0; 8845 8837 rc = fan_get_status_safe(&fan_control_resume_level); 8846 - if (rc < 0) 8838 + if (rc) 8847 8839 pr_notice("failed to read fan level for later restore during resume: %d\n", 8848 8840 rc); 8849 8841 ··· 8864 8856 8865 8857 if (!fan_control_allowed || 8866 8858 !fan_control_resume_level || 8867 - (fan_get_status_safe(&current_level) < 0)) 8859 + fan_get_status_safe(&current_level)) 8868 8860 return; 8869 8861 8870 8862 switch (fan_control_access_mode) { ··· 8918 8910 case TPACPI_FAN_RD_ACPI_GFAN: 8919 8911 /* 570, 600e/x, 770e, 770x */ 8920 8912 rc = fan_get_status_safe(&status); 8921 - if (rc < 0) 8913 + if (rc) 8922 8914 return rc; 8923 8915 8924 8916 seq_printf(m, "status:\t\t%s\n" ··· 8929 8921 case TPACPI_FAN_RD_TPEC: 8930 8922 /* all except 570, 600e/x, 770e, 770x */ 8931 8923 rc = fan_get_status_safe(&status); 8932 - if (rc < 0) 8924 + if (rc) 8933 8925 return rc; 8934 8926 8935 8927 seq_printf(m, "status:\t\t%s\n", ··· 10130 10122 10131 10123 #define DYTC_CMD_FUNC_CAP 3 /* To get DYTC capabilities */ 10132 10124 #define DYTC_FC_MMC 27 /* MMC Mode supported */ 10125 + #define DYTC_FC_PSC 29 /* PSC Mode supported */ 10133 10126 10134 10127 #define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */ 10135 10128 #define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */ ··· 10141 10132 10142 10133 #define DYTC_FUNCTION_STD 0 /* Function = 0, standard mode */ 10143 10134 #define DYTC_FUNCTION_CQL 1 /* Function = 1, lap mode */ 10144 - #define DYTC_FUNCTION_MMC 11 /* Function = 11, desk mode */ 10135 + #define DYTC_FUNCTION_MMC 11 /* Function = 11, MMC mode */ 10136 + #define DYTC_FUNCTION_PSC 13 /* Function = 13, PSC mode */ 10145 10137 10146 - #define DYTC_MODE_PERFORM 2 /* High power mode aka performance */ 10147 - #define DYTC_MODE_LOWPOWER 3 /* Low power mode */ 10148 - #define DYTC_MODE_BALANCE 0xF /* Default mode aka balanced */ 10149 - #define DYTC_MODE_MMC_BALANCE 0 /* Default mode from MMC_GET, aka balanced */ 10138 + #define DYTC_MODE_MMC_PERFORM 2 /* High power mode aka performance */ 10139 + #define DYTC_MODE_MMC_LOWPOWER 3 /* Low power mode */ 10140 + #define DYTC_MODE_MMC_BALANCE 0xF /* Default mode aka balanced */ 10141 + #define DYTC_MODE_MMC_DEFAULT 0 /* Default mode from MMC_GET, aka balanced */ 10142 + 10143 + #define DYTC_MODE_PSC_LOWPOWER 3 /* Low power mode */ 10144 + #define DYTC_MODE_PSC_BALANCE 5 /* Default mode aka balanced */ 10145 + #define DYTC_MODE_PSC_PERFORM 7 /* High power mode aka performance */ 10150 10146 10151 10147 #define DYTC_ERR_MASK 0xF /* Bits 0-3 in cmd result are the error result */ 10152 10148 #define DYTC_ERR_SUCCESS 1 /* CMD completed successful */ ··· 10161 10147 (mode) << DYTC_SET_MODE_BIT | \ 10162 10148 (on) << DYTC_SET_VALID_BIT) 10163 10149 10164 - #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0) 10150 + #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0) 10151 + #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1) 10165 10152 10166 - #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1) 10153 + enum dytc_profile_funcmode { 10154 + DYTC_FUNCMODE_NONE = 0, 10155 + DYTC_FUNCMODE_MMC, 10156 + DYTC_FUNCMODE_PSC, 10157 + }; 10167 10158 10159 + static enum dytc_profile_funcmode dytc_profile_available; 10168 10160 static enum platform_profile_option dytc_current_profile; 10169 10161 static atomic_t dytc_ignore_event = ATOMIC_INIT(0); 10170 10162 static DEFINE_MUTEX(dytc_mutex); ··· 10178 10158 10179 10159 static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile) 10180 10160 { 10181 - switch (dytcmode) { 10182 - case DYTC_MODE_LOWPOWER: 10183 - *profile = PLATFORM_PROFILE_LOW_POWER; 10184 - break; 10185 - case DYTC_MODE_BALANCE: 10186 - case DYTC_MODE_MMC_BALANCE: 10187 - *profile = PLATFORM_PROFILE_BALANCED; 10188 - break; 10189 - case DYTC_MODE_PERFORM: 10190 - *profile = PLATFORM_PROFILE_PERFORMANCE; 10191 - break; 10192 - default: /* Unknown mode */ 10193 - return -EINVAL; 10161 + if (dytc_profile_available == DYTC_FUNCMODE_MMC) { 10162 + switch (dytcmode) { 10163 + case DYTC_MODE_MMC_LOWPOWER: 10164 + *profile = PLATFORM_PROFILE_LOW_POWER; 10165 + break; 10166 + case DYTC_MODE_MMC_DEFAULT: 10167 + case DYTC_MODE_MMC_BALANCE: 10168 + *profile = PLATFORM_PROFILE_BALANCED; 10169 + break; 10170 + case DYTC_MODE_MMC_PERFORM: 10171 + *profile = PLATFORM_PROFILE_PERFORMANCE; 10172 + break; 10173 + default: /* Unknown mode */ 10174 + return -EINVAL; 10175 + } 10176 + return 0; 10177 + } 10178 + if (dytc_profile_available == DYTC_FUNCMODE_PSC) { 10179 + switch (dytcmode) { 10180 + case DYTC_MODE_PSC_LOWPOWER: 10181 + *profile = PLATFORM_PROFILE_LOW_POWER; 10182 + break; 10183 + case DYTC_MODE_PSC_BALANCE: 10184 + *profile = PLATFORM_PROFILE_BALANCED; 10185 + break; 10186 + case DYTC_MODE_PSC_PERFORM: 10187 + *profile = PLATFORM_PROFILE_PERFORMANCE; 10188 + break; 10189 + default: /* Unknown mode */ 10190 + return -EINVAL; 10191 + } 10194 10192 } 10195 10193 return 0; 10196 10194 } ··· 10217 10179 { 10218 10180 switch (profile) { 10219 10181 case PLATFORM_PROFILE_LOW_POWER: 10220 - *perfmode = DYTC_MODE_LOWPOWER; 10182 + if (dytc_profile_available == DYTC_FUNCMODE_MMC) 10183 + *perfmode = DYTC_MODE_MMC_LOWPOWER; 10184 + else if (dytc_profile_available == DYTC_FUNCMODE_PSC) 10185 + *perfmode = DYTC_MODE_PSC_LOWPOWER; 10221 10186 break; 10222 10187 case PLATFORM_PROFILE_BALANCED: 10223 - *perfmode = DYTC_MODE_BALANCE; 10188 + if (dytc_profile_available == DYTC_FUNCMODE_MMC) 10189 + *perfmode = DYTC_MODE_MMC_BALANCE; 10190 + else if (dytc_profile_available == DYTC_FUNCMODE_PSC) 10191 + *perfmode = DYTC_MODE_PSC_BALANCE; 10224 10192 break; 10225 10193 case PLATFORM_PROFILE_PERFORMANCE: 10226 - *perfmode = DYTC_MODE_PERFORM; 10194 + if (dytc_profile_available == DYTC_FUNCMODE_MMC) 10195 + *perfmode = DYTC_MODE_MMC_PERFORM; 10196 + else if (dytc_profile_available == DYTC_FUNCMODE_PSC) 10197 + *perfmode = DYTC_MODE_PSC_PERFORM; 10227 10198 break; 10228 10199 default: /* Unknown profile */ 10229 10200 return -EOPNOTSUPP; ··· 10298 10251 static int dytc_profile_set(struct platform_profile_handler *pprof, 10299 10252 enum platform_profile_option profile) 10300 10253 { 10254 + int perfmode; 10301 10255 int output; 10302 10256 int err; 10303 10257 ··· 10306 10258 if (err) 10307 10259 return err; 10308 10260 10309 - if (profile == PLATFORM_PROFILE_BALANCED) { 10310 - /* 10311 - * To get back to balanced mode we need to issue a reset command. 10312 - * Note we still need to disable CQL mode before hand and re-enable 10313 - * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays 10314 - * stuck at 0 for aprox. 30 minutes. 10315 - */ 10316 - err = dytc_cql_command(DYTC_CMD_RESET, &output); 10317 - if (err) 10318 - goto unlock; 10319 - } else { 10320 - int perfmode; 10261 + err = convert_profile_to_dytc(profile, &perfmode); 10262 + if (err) 10263 + goto unlock; 10321 10264 10322 - err = convert_profile_to_dytc(profile, &perfmode); 10323 - if (err) 10324 - goto unlock; 10325 - 10326 - /* Determine if we are in CQL mode. This alters the commands we do */ 10327 - err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), &output); 10265 + if (dytc_profile_available == DYTC_FUNCMODE_MMC) { 10266 + if (profile == PLATFORM_PROFILE_BALANCED) { 10267 + /* 10268 + * To get back to balanced mode we need to issue a reset command. 10269 + * Note we still need to disable CQL mode before hand and re-enable 10270 + * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays 10271 + * stuck at 0 for aprox. 30 minutes. 10272 + */ 10273 + err = dytc_cql_command(DYTC_CMD_RESET, &output); 10274 + if (err) 10275 + goto unlock; 10276 + } else { 10277 + /* Determine if we are in CQL mode. This alters the commands we do */ 10278 + err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), 10279 + &output); 10280 + if (err) 10281 + goto unlock; 10282 + } 10283 + } 10284 + if (dytc_profile_available == DYTC_FUNCMODE_PSC) { 10285 + err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output); 10328 10286 if (err) 10329 10287 goto unlock; 10330 10288 } ··· 10344 10290 static void dytc_profile_refresh(void) 10345 10291 { 10346 10292 enum platform_profile_option profile; 10347 - int output, err; 10293 + int output, err = 0; 10348 10294 int perfmode; 10349 10295 10350 10296 mutex_lock(&dytc_mutex); 10351 - if (dytc_mmc_get_available) 10352 - err = dytc_command(DYTC_CMD_MMC_GET, &output); 10353 - else 10354 - err = dytc_cql_command(DYTC_CMD_GET, &output); 10297 + if (dytc_profile_available == DYTC_FUNCMODE_MMC) { 10298 + if (dytc_mmc_get_available) 10299 + err = dytc_command(DYTC_CMD_MMC_GET, &output); 10300 + else 10301 + err = dytc_cql_command(DYTC_CMD_GET, &output); 10302 + } else if (dytc_profile_available == DYTC_FUNCMODE_PSC) 10303 + err = dytc_command(DYTC_CMD_GET, &output); 10304 + 10355 10305 mutex_unlock(&dytc_mutex); 10356 10306 if (err) 10357 10307 return; ··· 10382 10324 set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices); 10383 10325 set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices); 10384 10326 10327 + dytc_profile_available = DYTC_FUNCMODE_NONE; 10385 10328 err = dytc_command(DYTC_CMD_QUERY, &output); 10386 10329 if (err) 10387 10330 return err; ··· 10394 10335 if (dytc_version < 5) 10395 10336 return -ENODEV; 10396 10337 10397 - /* Check what capabilities are supported. Currently MMC is needed */ 10338 + /* Check what capabilities are supported */ 10398 10339 err = dytc_command(DYTC_CMD_FUNC_CAP, &output); 10399 10340 if (err) 10400 10341 return err; 10401 - if (!(output & BIT(DYTC_FC_MMC))) { 10402 - dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n"); 10342 + 10343 + if (output & BIT(DYTC_FC_MMC)) { /* MMC MODE */ 10344 + dytc_profile_available = DYTC_FUNCMODE_MMC; 10345 + 10346 + /* 10347 + * Check if MMC_GET functionality available 10348 + * Version > 6 and return success from MMC_GET command 10349 + */ 10350 + dytc_mmc_get_available = false; 10351 + if (dytc_version >= 6) { 10352 + err = dytc_command(DYTC_CMD_MMC_GET, &output); 10353 + if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) 10354 + dytc_mmc_get_available = true; 10355 + } 10356 + } else if (output & BIT(DYTC_FC_PSC)) { /* PSC MODE */ 10357 + dytc_profile_available = DYTC_FUNCMODE_PSC; 10358 + } else { 10359 + dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n"); 10403 10360 return -ENODEV; 10404 10361 } 10405 10362 10406 10363 dbg_printk(TPACPI_DBG_INIT, 10407 10364 "DYTC version %d: thermal mode available\n", dytc_version); 10408 - /* 10409 - * Check if MMC_GET functionality available 10410 - * Version > 6 and return success from MMC_GET command 10411 - */ 10412 - dytc_mmc_get_available = false; 10413 - if (dytc_version >= 6) { 10414 - err = dytc_command(DYTC_CMD_MMC_GET, &output); 10415 - if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) 10416 - dytc_mmc_get_available = true; 10417 - } 10365 + 10418 10366 /* Create platform_profile structure and register */ 10419 10367 err = platform_profile_register(&dytc_profile); 10420 10368 /* ··· 10439 10373 10440 10374 static void dytc_profile_exit(void) 10441 10375 { 10376 + dytc_profile_available = DYTC_FUNCMODE_NONE; 10442 10377 platform_profile_remove(); 10443 10378 } 10444 10379
+587 -45
drivers/platform/x86/x86-android-tablets.c
··· 12 12 13 13 #include <linux/acpi.h> 14 14 #include <linux/dmi.h> 15 + #include <linux/efi.h> 16 + #include <linux/gpio_keys.h> 15 17 #include <linux/gpio/consumer.h> 16 18 #include <linux/gpio/driver.h> 17 19 #include <linux/gpio/machine.h> 18 20 #include <linux/i2c.h> 21 + #include <linux/input.h> 19 22 #include <linux/irq.h> 20 23 #include <linux/irqdomain.h> 21 24 #include <linux/module.h> 22 25 #include <linux/mod_devicetable.h> 26 + #include <linux/pinctrl/consumer.h> 27 + #include <linux/pinctrl/machine.h> 28 + #include <linux/platform_data/lp855x.h> 23 29 #include <linux/platform_device.h> 30 + #include <linux/pm.h> 24 31 #include <linux/power/bq24190_charger.h> 32 + #include <linux/rmi.h> 25 33 #include <linux/serdev.h> 34 + #include <linux/spi/spi.h> 26 35 #include <linux/string.h> 27 36 /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */ 28 37 #include "../../gpio/gpiolib.h" ··· 62 53 return gc->label && !strcmp(gc->label, data); 63 54 } 64 55 56 + static int x86_android_tablet_get_gpiod(char *label, int pin, struct gpio_desc **desc) 57 + { 58 + struct gpio_desc *gpiod; 59 + struct gpio_chip *chip; 60 + 61 + chip = gpiochip_find(label, gpiochip_find_match_label); 62 + if (!chip) { 63 + pr_err("error cannot find GPIO chip %s\n", label); 64 + return -ENODEV; 65 + } 66 + 67 + gpiod = gpiochip_get_desc(chip, pin); 68 + if (IS_ERR(gpiod)) { 69 + pr_err("error %ld getting GPIO %s %d\n", PTR_ERR(gpiod), label, pin); 70 + return PTR_ERR(gpiod); 71 + } 72 + 73 + *desc = gpiod; 74 + return 0; 75 + } 76 + 65 77 static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data) 66 78 { 67 79 struct irq_fwspec fwspec = { }; 68 80 struct irq_domain *domain; 69 81 struct acpi_device *adev; 70 82 struct gpio_desc *gpiod; 71 - struct gpio_chip *chip; 72 83 unsigned int irq_type; 73 84 acpi_handle handle; 74 85 acpi_status status; ··· 96 67 97 68 switch (data->type) { 98 69 case X86_ACPI_IRQ_TYPE_APIC: 70 + /* 71 + * The DSDT may already reference the GSI in a device skipped by 72 + * acpi_quirk_skip_i2c_client_enumeration(). Unregister the GSI 73 + * to avoid EBUSY errors in this case. 74 + */ 75 + acpi_unregister_gsi(data->index); 99 76 irq = acpi_register_gsi(NULL, data->index, data->trigger, data->polarity); 100 77 if (irq < 0) 101 78 pr_err("error %d getting APIC IRQ %d\n", irq, data->index); ··· 109 74 return irq; 110 75 case X86_ACPI_IRQ_TYPE_GPIOINT: 111 76 /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */ 112 - chip = gpiochip_find(data->chip, gpiochip_find_match_label); 113 - if (!chip) { 114 - pr_err("error cannot find GPIO chip %s\n", data->chip); 115 - return -ENODEV; 116 - } 117 - 118 - gpiod = gpiochip_get_desc(chip, data->index); 119 - if (IS_ERR(gpiod)) { 120 - ret = PTR_ERR(gpiod); 121 - pr_err("error %d getting GPIO %s %d\n", ret, data->chip, data->index); 77 + ret = x86_android_tablet_get_gpiod(data->chip, data->index, &gpiod); 78 + if (ret) 122 79 return ret; 123 - } 124 80 125 81 irq = gpiod_to_irq(gpiod); 126 82 if (irq < 0) { ··· 131 105 return -ENODEV; 132 106 } 133 107 134 - acpi_bus_get_device(handle, &adev); 108 + adev = acpi_fetch_acpi_dev(handle); 135 109 if (!adev) { 136 110 pr_err("error could not get %s adev\n", data->chip); 137 111 return -ENODEV; ··· 172 146 struct x86_dev_info { 173 147 char *invalid_aei_gpiochip; 174 148 const char * const *modules; 149 + const struct software_node *bat_swnode; 175 150 struct gpiod_lookup_table * const *gpiod_lookup_tables; 176 151 const struct x86_i2c_client_info *i2c_client_info; 177 152 const struct platform_device_info *pdev_info; ··· 184 157 void (*exit)(void); 185 158 }; 186 159 187 - /* Generic / shared bq24190 settings */ 188 - static const char * const bq24190_suppliers[] = { "tusb1210-psy" }; 160 + /* Generic / shared charger / battery settings */ 161 + static const char * const tusb1211_chg_det_psy[] = { "tusb1211-charger-detect" }; 162 + static const char * const bq24190_psy[] = { "bq24190-charger" }; 163 + static const char * const bq25890_psy[] = { "bq25890-charger" }; 189 164 190 - static const struct property_entry bq24190_props[] = { 191 - PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers), 192 - PROPERTY_ENTRY_BOOL("omit-battery-class"), 193 - PROPERTY_ENTRY_BOOL("disable-reset"), 165 + static const struct property_entry fg_bq24190_supply_props[] = { 166 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy), 194 167 { } 195 168 }; 196 169 197 - static const struct software_node bq24190_node = { 198 - .properties = bq24190_props, 170 + static const struct software_node fg_bq24190_supply_node = { 171 + .properties = fg_bq24190_supply_props, 199 172 }; 200 173 201 - /* For enableing the bq24190 5V boost based on id-pin */ 174 + static const struct property_entry fg_bq25890_supply_props[] = { 175 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq25890_psy), 176 + { } 177 + }; 178 + 179 + static const struct software_node fg_bq25890_supply_node = { 180 + .properties = fg_bq25890_supply_props, 181 + }; 182 + 183 + /* LiPo HighVoltage (max 4.35V) settings used by most devs with a HV bat. */ 184 + static const struct property_entry generic_lipo_hv_4v35_battery_props[] = { 185 + PROPERTY_ENTRY_STRING("compatible", "simple-battery"), 186 + PROPERTY_ENTRY_STRING("device-chemistry", "lithium-ion"), 187 + PROPERTY_ENTRY_U32("precharge-current-microamp", 256000), 188 + PROPERTY_ENTRY_U32("charge-term-current-microamp", 128000), 189 + PROPERTY_ENTRY_U32("constant-charge-current-max-microamp", 1856000), 190 + PROPERTY_ENTRY_U32("constant-charge-voltage-max-microvolt", 4352000), 191 + PROPERTY_ENTRY_U32("factory-internal-resistance-micro-ohms", 150000), 192 + { } 193 + }; 194 + 195 + static const struct software_node generic_lipo_hv_4v35_battery_node = { 196 + .properties = generic_lipo_hv_4v35_battery_props, 197 + }; 198 + 199 + /* For enabling the bq24190 5V boost based on id-pin */ 202 200 static struct regulator_consumer_supply intel_int3496_consumer = { 203 201 .supply = "vbus", 204 202 .dev_name = "intel-int3496", ··· 265 213 }, 266 214 }; 267 215 216 + /* Asus ME176C and TF103C tablets shared data */ 217 + static struct gpio_keys_button asus_me176c_tf103c_lid = { 218 + .code = SW_LID, 219 + /* .gpio gets filled in by asus_me176c_tf103c_init() */ 220 + .active_low = true, 221 + .desc = "lid_sw", 222 + .type = EV_SW, 223 + .wakeup = true, 224 + .debounce_interval = 50, 225 + }; 226 + 227 + static const struct gpio_keys_platform_data asus_me176c_tf103c_lid_pdata __initconst = { 228 + .buttons = &asus_me176c_tf103c_lid, 229 + .nbuttons = 1, 230 + .name = "lid_sw", 231 + }; 232 + 233 + static const struct platform_device_info asus_me176c_tf103c_pdevs[] __initconst = { 234 + { 235 + .name = "gpio-keys", 236 + .id = PLATFORM_DEVID_AUTO, 237 + .data = &asus_me176c_tf103c_lid_pdata, 238 + .size_data = sizeof(asus_me176c_tf103c_lid_pdata), 239 + }, 240 + { 241 + /* For micro USB ID pin handling */ 242 + .name = "intel-int3496", 243 + .id = PLATFORM_DEVID_NONE, 244 + }, 245 + }; 246 + 247 + static int __init asus_me176c_tf103c_init(void) 248 + { 249 + struct gpio_desc *gpiod; 250 + int ret; 251 + 252 + ret = x86_android_tablet_get_gpiod("INT33FC:02", 12, &gpiod); 253 + if (ret < 0) 254 + return ret; 255 + asus_me176c_tf103c_lid.gpio = desc_to_gpio(gpiod); 256 + 257 + return 0; 258 + } 259 + 260 + 268 261 /* Asus ME176C tablets have an Android factory img with everything hardcoded */ 269 262 static const char * const asus_me176c_accel_mount_matrix[] = { 270 263 "-1", "0", "0", ··· 326 229 .properties = asus_me176c_accel_props, 327 230 }; 328 231 232 + static const struct property_entry asus_me176c_bq24190_props[] = { 233 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", tusb1211_chg_det_psy), 234 + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node), 235 + PROPERTY_ENTRY_U32("ti,system-minimum-microvolt", 3600000), 236 + PROPERTY_ENTRY_BOOL("omit-battery-class"), 237 + PROPERTY_ENTRY_BOOL("disable-reset"), 238 + { } 239 + }; 240 + 241 + static const struct software_node asus_me176c_bq24190_node = { 242 + .properties = asus_me176c_bq24190_props, 243 + }; 244 + 245 + static const struct property_entry asus_me176c_ug3105_props[] = { 246 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy), 247 + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node), 248 + PROPERTY_ENTRY_U32("upisemi,rsns-microohm", 10000), 249 + { } 250 + }; 251 + 252 + static const struct software_node asus_me176c_ug3105_node = { 253 + .properties = asus_me176c_ug3105_props, 254 + }; 255 + 329 256 static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst = { 330 257 { 331 - /* bq24190 battery charger */ 258 + /* bq24297 battery charger */ 332 259 .board_info = { 333 260 .type = "bq24190", 334 261 .addr = 0x6b, 335 - .dev_name = "bq24190", 336 - .swnode = &bq24190_node, 262 + .dev_name = "bq24297", 263 + .swnode = &asus_me176c_bq24190_node, 337 264 .platform_data = &bq24190_pdata, 338 265 }, 339 266 .adapter_path = "\\_SB_.I2C1", ··· 373 252 .type = "ug3105", 374 253 .addr = 0x70, 375 254 .dev_name = "ug3105", 255 + .swnode = &asus_me176c_ug3105_node, 376 256 }, 377 257 .adapter_path = "\\_SB_.I2C1", 378 258 }, { ··· 393 271 .swnode = &asus_me176c_accel_node, 394 272 }, 395 273 .adapter_path = "\\_SB_.I2C5", 274 + .irq_data = { 275 + .type = X86_ACPI_IRQ_TYPE_APIC, 276 + .index = 0x44, 277 + .trigger = ACPI_EDGE_SENSITIVE, 278 + .polarity = ACPI_ACTIVE_LOW, 279 + }, 396 280 }, { 397 281 /* goodix touchscreen */ 398 282 .board_info = { ··· 443 315 static const struct x86_dev_info asus_me176c_info __initconst = { 444 316 .i2c_client_info = asus_me176c_i2c_clients, 445 317 .i2c_client_count = ARRAY_SIZE(asus_me176c_i2c_clients), 446 - .pdev_info = int3496_pdevs, 447 - .pdev_count = ARRAY_SIZE(int3496_pdevs), 318 + .pdev_info = asus_me176c_tf103c_pdevs, 319 + .pdev_count = ARRAY_SIZE(asus_me176c_tf103c_pdevs), 448 320 .serdev_info = asus_me176c_serdevs, 449 321 .serdev_count = ARRAY_SIZE(asus_me176c_serdevs), 450 322 .gpiod_lookup_tables = asus_me176c_gpios, 323 + .bat_swnode = &generic_lipo_hv_4v35_battery_node, 451 324 .modules = bq24190_modules, 452 325 .invalid_aei_gpiochip = "INT33FC:02", 326 + .init = asus_me176c_tf103c_init, 453 327 }; 454 328 455 329 /* Asus TF103C tablets have an Android factory img with everything hardcoded */ ··· 479 349 .properties = asus_tf103c_touchscreen_props, 480 350 }; 481 351 352 + static const struct property_entry asus_tf103c_battery_props[] = { 353 + PROPERTY_ENTRY_STRING("compatible", "simple-battery"), 354 + PROPERTY_ENTRY_STRING("device-chemistry", "lithium-ion-polymer"), 355 + PROPERTY_ENTRY_U32("precharge-current-microamp", 256000), 356 + PROPERTY_ENTRY_U32("charge-term-current-microamp", 128000), 357 + PROPERTY_ENTRY_U32("constant-charge-current-max-microamp", 2048000), 358 + PROPERTY_ENTRY_U32("constant-charge-voltage-max-microvolt", 4208000), 359 + PROPERTY_ENTRY_U32("factory-internal-resistance-micro-ohms", 150000), 360 + { } 361 + }; 362 + 363 + static const struct software_node asus_tf103c_battery_node = { 364 + .properties = asus_tf103c_battery_props, 365 + }; 366 + 367 + static const struct property_entry asus_tf103c_bq24190_props[] = { 368 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", tusb1211_chg_det_psy), 369 + PROPERTY_ENTRY_REF("monitored-battery", &asus_tf103c_battery_node), 370 + PROPERTY_ENTRY_U32("ti,system-minimum-microvolt", 3600000), 371 + PROPERTY_ENTRY_BOOL("omit-battery-class"), 372 + PROPERTY_ENTRY_BOOL("disable-reset"), 373 + { } 374 + }; 375 + 376 + static const struct software_node asus_tf103c_bq24190_node = { 377 + .properties = asus_tf103c_bq24190_props, 378 + }; 379 + 380 + static const struct property_entry asus_tf103c_ug3105_props[] = { 381 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy), 382 + PROPERTY_ENTRY_REF("monitored-battery", &asus_tf103c_battery_node), 383 + PROPERTY_ENTRY_U32("upisemi,rsns-microohm", 5000), 384 + { } 385 + }; 386 + 387 + static const struct software_node asus_tf103c_ug3105_node = { 388 + .properties = asus_tf103c_ug3105_props, 389 + }; 390 + 482 391 static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst = { 483 392 { 484 - /* bq24190 battery charger */ 393 + /* bq24297 battery charger */ 485 394 .board_info = { 486 395 .type = "bq24190", 487 396 .addr = 0x6b, 488 - .dev_name = "bq24190", 489 - .swnode = &bq24190_node, 397 + .dev_name = "bq24297", 398 + .swnode = &asus_tf103c_bq24190_node, 490 399 .platform_data = &bq24190_pdata, 491 400 }, 492 401 .adapter_path = "\\_SB_.I2C1", ··· 541 372 .type = "ug3105", 542 373 .addr = 0x70, 543 374 .dev_name = "ug3105", 375 + .swnode = &asus_tf103c_ug3105_node, 544 376 }, 545 377 .adapter_path = "\\_SB_.I2C1", 546 378 }, { ··· 588 418 static const struct x86_dev_info asus_tf103c_info __initconst = { 589 419 .i2c_client_info = asus_tf103c_i2c_clients, 590 420 .i2c_client_count = ARRAY_SIZE(asus_tf103c_i2c_clients), 591 - .pdev_info = int3496_pdevs, 592 - .pdev_count = ARRAY_SIZE(int3496_pdevs), 421 + .pdev_info = asus_me176c_tf103c_pdevs, 422 + .pdev_count = ARRAY_SIZE(asus_me176c_tf103c_pdevs), 593 423 .gpiod_lookup_tables = asus_tf103c_gpios, 424 + .bat_swnode = &asus_tf103c_battery_node, 594 425 .modules = bq24190_modules, 595 426 .invalid_aei_gpiochip = "INT33FC:02", 427 + .init = asus_me176c_tf103c_init, 596 428 }; 597 429 598 430 /* ··· 701 529 .init = czc_p10t_init, 702 530 }; 703 531 532 + /* Lenovo Yoga Book X90F / X91F / X91L need manual instantiation of the fg client */ 533 + static const struct x86_i2c_client_info lenovo_yogabook_x9x_i2c_clients[] __initconst = { 534 + { 535 + /* BQ27542 fuel-gauge */ 536 + .board_info = { 537 + .type = "bq27542", 538 + .addr = 0x55, 539 + .dev_name = "bq27542", 540 + .swnode = &fg_bq25890_supply_node, 541 + }, 542 + .adapter_path = "\\_SB_.PCI0.I2C1", 543 + }, 544 + }; 545 + 546 + static const struct x86_dev_info lenovo_yogabook_x9x_info __initconst = { 547 + .i2c_client_info = lenovo_yogabook_x9x_i2c_clients, 548 + .i2c_client_count = ARRAY_SIZE(lenovo_yogabook_x9x_i2c_clients), 549 + }; 550 + 551 + /* Lenovo Yoga Tablet 2 1050F/L's Android factory img has everything hardcoded */ 552 + static const struct property_entry lenovo_yoga_tab2_830_1050_bq24190_props[] = { 553 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", tusb1211_chg_det_psy), 554 + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node), 555 + PROPERTY_ENTRY_BOOL("omit-battery-class"), 556 + PROPERTY_ENTRY_BOOL("disable-reset"), 557 + { } 558 + }; 559 + 560 + static const struct software_node lenovo_yoga_tab2_830_1050_bq24190_node = { 561 + .properties = lenovo_yoga_tab2_830_1050_bq24190_props, 562 + }; 563 + 564 + /* This gets filled by lenovo_yoga_tab2_830_1050_init() */ 565 + static struct rmi_device_platform_data lenovo_yoga_tab2_830_1050_rmi_pdata = { }; 566 + 567 + static struct lp855x_platform_data lenovo_yoga_tab2_830_1050_lp8557_pdata = { 568 + .device_control = 0x86, 569 + .initial_brightness = 128, 570 + }; 571 + 572 + static const struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __initconst = { 573 + { 574 + /* bq24292i battery charger */ 575 + .board_info = { 576 + .type = "bq24190", 577 + .addr = 0x6b, 578 + .dev_name = "bq24292i", 579 + .swnode = &lenovo_yoga_tab2_830_1050_bq24190_node, 580 + .platform_data = &bq24190_pdata, 581 + }, 582 + .adapter_path = "\\_SB_.I2C1", 583 + .irq_data = { 584 + .type = X86_ACPI_IRQ_TYPE_GPIOINT, 585 + .chip = "INT33FC:02", 586 + .index = 2, 587 + .trigger = ACPI_EDGE_SENSITIVE, 588 + .polarity = ACPI_ACTIVE_HIGH, 589 + }, 590 + }, { 591 + /* BQ27541 fuel-gauge */ 592 + .board_info = { 593 + .type = "bq27541", 594 + .addr = 0x55, 595 + .dev_name = "bq27541", 596 + .swnode = &fg_bq24190_supply_node, 597 + }, 598 + .adapter_path = "\\_SB_.I2C1", 599 + }, { 600 + /* Synaptics RMI touchscreen */ 601 + .board_info = { 602 + .type = "rmi4_i2c", 603 + .addr = 0x38, 604 + .dev_name = "rmi4_i2c", 605 + .platform_data = &lenovo_yoga_tab2_830_1050_rmi_pdata, 606 + }, 607 + .adapter_path = "\\_SB_.I2C6", 608 + .irq_data = { 609 + .type = X86_ACPI_IRQ_TYPE_APIC, 610 + .index = 0x45, 611 + .trigger = ACPI_EDGE_SENSITIVE, 612 + .polarity = ACPI_ACTIVE_HIGH, 613 + }, 614 + }, { 615 + /* LP8557 Backlight controller */ 616 + .board_info = { 617 + .type = "lp8557", 618 + .addr = 0x2c, 619 + .dev_name = "lp8557", 620 + .platform_data = &lenovo_yoga_tab2_830_1050_lp8557_pdata, 621 + }, 622 + .adapter_path = "\\_SB_.I2C3", 623 + }, 624 + }; 625 + 626 + static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_int3496_gpios = { 627 + .dev_id = "intel-int3496", 628 + .table = { 629 + GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_LOW), 630 + GPIO_LOOKUP("INT33FC:02", 24, "id", GPIO_ACTIVE_HIGH), 631 + { } 632 + }, 633 + }; 634 + 635 + #define LENOVO_YOGA_TAB2_830_1050_CODEC_NAME "spi-10WM5102:00" 636 + 637 + static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_codec_gpios = { 638 + .dev_id = LENOVO_YOGA_TAB2_830_1050_CODEC_NAME, 639 + .table = { 640 + GPIO_LOOKUP("gpio_crystalcove", 3, "reset", GPIO_ACTIVE_HIGH), 641 + GPIO_LOOKUP("INT33FC:01", 23, "wlf,ldoena", GPIO_ACTIVE_HIGH), 642 + GPIO_LOOKUP("arizona", 2, "wlf,spkvdd-ena", GPIO_ACTIVE_HIGH), 643 + GPIO_LOOKUP("arizona", 4, "wlf,micd-pol", GPIO_ACTIVE_LOW), 644 + { } 645 + }, 646 + }; 647 + 648 + static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] = { 649 + &lenovo_yoga_tab2_830_1050_int3496_gpios, 650 + &lenovo_yoga_tab2_830_1050_codec_gpios, 651 + NULL 652 + }; 653 + 654 + static int __init lenovo_yoga_tab2_830_1050_init(void); 655 + static void lenovo_yoga_tab2_830_1050_exit(void); 656 + 657 + static struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initdata = { 658 + .i2c_client_info = lenovo_yoga_tab2_830_1050_i2c_clients, 659 + /* i2c_client_count gets set by lenovo_yoga_tab2_830_1050_init() */ 660 + .pdev_info = int3496_pdevs, 661 + .pdev_count = ARRAY_SIZE(int3496_pdevs), 662 + .gpiod_lookup_tables = lenovo_yoga_tab2_830_1050_gpios, 663 + .bat_swnode = &generic_lipo_hv_4v35_battery_node, 664 + .modules = bq24190_modules, 665 + .invalid_aei_gpiochip = "INT33FC:02", 666 + .init = lenovo_yoga_tab2_830_1050_init, 667 + .exit = lenovo_yoga_tab2_830_1050_exit, 668 + }; 669 + 670 + /* 671 + * The Lenovo Yoga Tablet 2 830 and 1050 (8" vs 10") versions use the same 672 + * mainboard, but they need some different treatment related to the display: 673 + * 1. The 830 uses a portrait LCD panel with a landscape touchscreen, requiring 674 + * the touchscreen driver to adjust the touch-coords to match the LCD. 675 + * 2. Both use an TI LP8557 LED backlight controller. On the 1050 the LP8557's 676 + * PWM input is connected to the PMIC's PWM output and everything works fine 677 + * with the defaults programmed into the LP8557 by the BIOS. 678 + * But on the 830 the LP8557's PWM input is connected to a PWM output coming 679 + * from the LCD panel's controller. The Android code has a hack in the i915 680 + * driver to write the non-standard DSI reg 0x9f with the desired backlight 681 + * level to set the duty-cycle of the LCD's PWM output. 682 + * 683 + * To avoid having to have a similar hack in the mainline kernel the LP8557 684 + * entry in lenovo_yoga_tab2_830_1050_i2c_clients instead just programs the 685 + * LP8557 to directly set the level, ignoring the PWM input. This means that 686 + * the LP8557 i2c_client should only be instantiated on the 830. 687 + */ 688 + static int __init lenovo_yoga_tab2_830_1050_init_display(void) 689 + { 690 + struct gpio_desc *gpiod; 691 + int ret; 692 + 693 + /* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */ 694 + ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, &gpiod); 695 + if (ret) 696 + return ret; 697 + 698 + ret = gpiod_get_value_cansleep(gpiod); 699 + if (ret) { 700 + pr_info("detected Lenovo Yoga Tablet 2 1050F/L\n"); 701 + lenovo_yoga_tab2_830_1050_info.i2c_client_count = 702 + ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients) - 1; 703 + } else { 704 + pr_info("detected Lenovo Yoga Tablet 2 830F/L\n"); 705 + lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.swap_axes = true; 706 + lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.flip_y = true; 707 + lenovo_yoga_tab2_830_1050_info.i2c_client_count = 708 + ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients); 709 + } 710 + 711 + return 0; 712 + } 713 + 714 + /* SUS (INT33FC:02) pin 6 needs to be configured as pmu_clk for the audio codec */ 715 + static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map = 716 + PIN_MAP_MUX_GROUP(LENOVO_YOGA_TAB2_830_1050_CODEC_NAME, "codec_32khz_clk", 717 + "INT33FC:02", "pmu_clk2_grp", "pmu_clk"); 718 + 719 + static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl; 720 + 721 + static int __init lenovo_yoga_tab2_830_1050_init_codec(void) 722 + { 723 + struct device *codec_dev; 724 + struct pinctrl *pinctrl; 725 + int ret; 726 + 727 + codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, 728 + LENOVO_YOGA_TAB2_830_1050_CODEC_NAME); 729 + if (!codec_dev) { 730 + pr_err("error cannot find %s device\n", LENOVO_YOGA_TAB2_830_1050_CODEC_NAME); 731 + return -ENODEV; 732 + } 733 + 734 + ret = pinctrl_register_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map, 1); 735 + if (ret) 736 + goto err_put_device; 737 + 738 + pinctrl = pinctrl_get_select(codec_dev, "codec_32khz_clk"); 739 + if (IS_ERR(pinctrl)) { 740 + ret = dev_err_probe(codec_dev, PTR_ERR(pinctrl), "selecting codec_32khz_clk\n"); 741 + goto err_unregister_mappings; 742 + } 743 + 744 + /* We're done with the codec_dev now */ 745 + put_device(codec_dev); 746 + 747 + lenovo_yoga_tab2_830_1050_codec_pinctrl = pinctrl; 748 + return 0; 749 + 750 + err_unregister_mappings: 751 + pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map); 752 + err_put_device: 753 + put_device(codec_dev); 754 + return ret; 755 + } 756 + 757 + /* 758 + * These tablet's DSDT does not set acpi_gbl_reduced_hardware, so acpi_power_off 759 + * gets used as pm_power_off handler. This causes "poweroff" on these tablets 760 + * to hang hard. Requiring pressing the powerbutton for 30 seconds *twice* 761 + * followed by a normal 3 second press to recover. Avoid this by doing an EFI 762 + * poweroff instead. 763 + */ 764 + static void lenovo_yoga_tab2_830_1050_power_off(void) 765 + { 766 + efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); 767 + } 768 + 769 + static int __init lenovo_yoga_tab2_830_1050_init(void) 770 + { 771 + int ret; 772 + 773 + ret = lenovo_yoga_tab2_830_1050_init_display(); 774 + if (ret) 775 + return ret; 776 + 777 + ret = lenovo_yoga_tab2_830_1050_init_codec(); 778 + if (ret) 779 + return ret; 780 + 781 + pm_power_off = lenovo_yoga_tab2_830_1050_power_off; 782 + return 0; 783 + } 784 + 785 + static void lenovo_yoga_tab2_830_1050_exit(void) 786 + { 787 + pm_power_off = NULL; /* Just turn poweroff into halt on module unload */ 788 + 789 + if (lenovo_yoga_tab2_830_1050_codec_pinctrl) { 790 + pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); 791 + pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map); 792 + } 793 + } 794 + 795 + /* Nextbook Ares 8 tablets have an Android factory img with everything hardcoded */ 796 + static const char * const nextbook_ares8_accel_mount_matrix[] = { 797 + "0", "-1", "0", 798 + "-1", "0", "0", 799 + "0", "0", "1" 800 + }; 801 + 802 + static const struct property_entry nextbook_ares8_accel_props[] = { 803 + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix), 804 + { } 805 + }; 806 + 807 + static const struct software_node nextbook_ares8_accel_node = { 808 + .properties = nextbook_ares8_accel_props, 809 + }; 810 + 811 + static const struct property_entry nextbook_ares8_touchscreen_props[] = { 812 + PROPERTY_ENTRY_U32("touchscreen-size-x", 800), 813 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), 814 + { } 815 + }; 816 + 817 + static const struct software_node nextbook_ares8_touchscreen_node = { 818 + .properties = nextbook_ares8_touchscreen_props, 819 + }; 820 + 821 + static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = { 822 + { 823 + /* Freescale MMA8653FC accel */ 824 + .board_info = { 825 + .type = "mma8653", 826 + .addr = 0x1d, 827 + .dev_name = "mma8653", 828 + .swnode = &nextbook_ares8_accel_node, 829 + }, 830 + .adapter_path = "\\_SB_.I2C3", 831 + }, { 832 + /* FT5416DQ9 touchscreen controller */ 833 + .board_info = { 834 + .type = "edt-ft5x06", 835 + .addr = 0x38, 836 + .dev_name = "ft5416", 837 + .swnode = &nextbook_ares8_touchscreen_node, 838 + }, 839 + .adapter_path = "\\_SB_.I2C4", 840 + .irq_data = { 841 + .type = X86_ACPI_IRQ_TYPE_GPIOINT, 842 + .chip = "INT33FC:02", 843 + .index = 3, 844 + .trigger = ACPI_EDGE_SENSITIVE, 845 + .polarity = ACPI_ACTIVE_LOW, 846 + }, 847 + }, 848 + }; 849 + 850 + static struct gpiod_lookup_table nextbook_ares8_int3496_gpios = { 851 + .dev_id = "intel-int3496", 852 + .table = { 853 + GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_HIGH), 854 + GPIO_LOOKUP("INT33FC:02", 18, "id", GPIO_ACTIVE_HIGH), 855 + { } 856 + }, 857 + }; 858 + 859 + static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = { 860 + &nextbook_ares8_int3496_gpios, 861 + NULL 862 + }; 863 + 864 + static const struct x86_dev_info nextbook_ares8_info __initconst = { 865 + .i2c_client_info = nextbook_ares8_i2c_clients, 866 + .i2c_client_count = ARRAY_SIZE(nextbook_ares8_i2c_clients), 867 + .pdev_info = int3496_pdevs, 868 + .pdev_count = ARRAY_SIZE(int3496_pdevs), 869 + .gpiod_lookup_tables = nextbook_ares8_gpios, 870 + .invalid_aei_gpiochip = "INT33FC:02", 871 + }; 872 + 704 873 /* 705 874 * Whitelabel (sold as various brands) TM800A550L tablets. 706 875 * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices ··· 1129 616 * 1130 617 * This takes care of instantiating the hidden devices manually. 1131 618 */ 1132 - static const char * const bq27520_suppliers[] = { "bq25890-charger" }; 1133 - 1134 - static const struct property_entry bq27520_props[] = { 1135 - PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq27520_suppliers), 1136 - { } 1137 - }; 1138 - 1139 - static const struct software_node bq27520_node = { 1140 - .properties = bq27520_props, 1141 - }; 1142 - 1143 619 static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = { 1144 620 { 1145 621 /* BQ27520 fuel-gauge */ ··· 1136 634 .type = "bq27520", 1137 635 .addr = 0x55, 1138 636 .dev_name = "bq27520", 1139 - .swnode = &bq27520_node, 637 + .swnode = &fg_bq25890_supply_node, 1140 638 }, 1141 639 .adapter_path = "\\_SB_.PCI0.I2C1", 1142 640 }, { ··· 1192 690 .driver_data = (void *)&czc_p10t, 1193 691 }, 1194 692 { 1195 - /* A variant of CZC P10T */ 693 + /* CZC P10T variant */ 1196 694 .ident = "ViewSonic ViewPad 10", 1197 695 .matches = { 1198 696 DMI_MATCH(DMI_SYS_VENDOR, "ViewSonic"), 1199 697 DMI_MATCH(DMI_PRODUCT_NAME, "VPAD10"), 1200 698 }, 1201 699 .driver_data = (void *)&czc_p10t, 700 + }, 701 + { 702 + /* Lenovo Yoga Book X90F / X91F / X91L */ 703 + .matches = { 704 + /* Non exact match to match all versions */ 705 + DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"), 706 + }, 707 + .driver_data = (void *)&lenovo_yogabook_x9x_info, 708 + }, 709 + { 710 + /* 711 + * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10" 712 + * Lenovo Yoga Tablet 2 use the same mainboard) 713 + */ 714 + .matches = { 715 + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), 716 + DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"), 717 + DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"), 718 + /* Partial match on beginning of BIOS version */ 719 + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"), 720 + }, 721 + .driver_data = (void *)&lenovo_yoga_tab2_830_1050_info, 722 + }, 723 + { 724 + /* Nextbook Ares 8 */ 725 + .matches = { 726 + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), 727 + DMI_MATCH(DMI_PRODUCT_NAME, "M890BAP"), 728 + }, 729 + .driver_data = (void *)&nextbook_ares8_info, 1202 730 }, 1203 731 { 1204 732 /* Whitelabel (sold as various brands) TM800A550L */ ··· 1259 727 static struct platform_device **pdevs; 1260 728 static struct serdev_device **serdevs; 1261 729 static struct gpiod_lookup_table * const *gpiod_lookup_tables; 730 + static const struct software_node *bat_swnode; 1262 731 static void (*exit_handler)(void); 1263 732 1264 733 static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info, ··· 1383 850 1384 851 for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) 1385 852 gpiod_remove_lookup_table(gpiod_lookup_tables[i]); 853 + 854 + software_node_unregister(bat_swnode); 1386 855 } 1387 856 1388 857 static __init int x86_android_tablet_init(void) ··· 1420 885 */ 1421 886 for (i = 0; dev_info->modules && dev_info->modules[i]; i++) 1422 887 request_module(dev_info->modules[i]); 888 + 889 + bat_swnode = dev_info->bat_swnode; 890 + if (bat_swnode) { 891 + ret = software_node_register(bat_swnode); 892 + if (ret) 893 + return ret; 894 + } 1423 895 1424 896 gpiod_lookup_tables = dev_info->gpiod_lookup_tables; 1425 897 for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
+9 -1
include/linux/acpi.h
··· 1024 1024 1025 1025 acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, 1026 1026 u32 val_a, u32 val_b); 1027 - 1027 + #ifdef CONFIG_X86 1028 + struct acpi_s2idle_dev_ops { 1029 + struct list_head list_node; 1030 + void (*prepare)(void); 1031 + void (*restore)(void); 1032 + }; 1033 + int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg); 1034 + void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg); 1035 + #endif /* CONFIG_X86 */ 1028 1036 #ifndef CONFIG_IA64 1029 1037 void arch_reserve_mem_area(acpi_physical_address addr, size_t size); 1030 1038 #else
+21
tools/arch/x86/intel_sdsi/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Makefile for Intel Software Defined Silicon provisioning tool 3 + 4 + intel_sdsi: intel_sdsi.c 5 + 6 + CFLAGS = -Wextra 7 + 8 + BINDIR ?= /usr/sbin 9 + 10 + override CFLAGS += -O2 -Wall 11 + 12 + %: %.c 13 + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 14 + 15 + .PHONY : clean 16 + clean : 17 + @rm -f intel_sdsi 18 + 19 + install : intel_sdsi 20 + install -d $(DESTDIR)$(BINDIR) 21 + install -m 755 -p intel_sdsi $(DESTDIR)$(BINDIR)/intel_sdsi
+558
tools/arch/x86/intel_sdsi/intel_sdsi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * sdsi: Intel Software Defined Silicon tool for provisioning certificates 4 + * and activation payloads on supported cpus. 5 + * 6 + * See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst 7 + * for register descriptions. 8 + * 9 + * Copyright (C) 2022 Intel Corporation. All rights reserved. 10 + */ 11 + 12 + #include <dirent.h> 13 + #include <errno.h> 14 + #include <fcntl.h> 15 + #include <getopt.h> 16 + #include <stdbool.h> 17 + #include <stdio.h> 18 + #include <stdint.h> 19 + #include <stdlib.h> 20 + #include <string.h> 21 + #include <unistd.h> 22 + 23 + #include <sys/types.h> 24 + 25 + #define SDSI_DEV "intel_vsec.sdsi" 26 + #define AUX_DEV_PATH "/sys/bus/auxiliary/devices/" 27 + #define SDSI_PATH (AUX_DEV_DIR SDSI_DEV) 28 + #define GUID 0x6dd191 29 + #define REGISTERS_MIN_SIZE 72 30 + 31 + #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) 32 + #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) 33 + 34 + struct enabled_features { 35 + uint64_t reserved:3; 36 + uint64_t sdsi:1; 37 + uint64_t reserved1:60; 38 + }; 39 + 40 + struct auth_fail_count { 41 + uint64_t key_failure_count:3; 42 + uint64_t key_failure_threshold:3; 43 + uint64_t auth_failure_count:3; 44 + uint64_t auth_failure_threshold:3; 45 + uint64_t reserved:52; 46 + }; 47 + 48 + struct availability { 49 + uint64_t reserved:48; 50 + uint64_t available:3; 51 + uint64_t threshold:3; 52 + }; 53 + 54 + struct sdsi_regs { 55 + uint64_t ppin; 56 + uint64_t reserved; 57 + struct enabled_features en_features; 58 + uint64_t reserved1; 59 + struct auth_fail_count auth_fail_count; 60 + struct availability prov_avail; 61 + uint64_t reserved2; 62 + uint64_t reserved3; 63 + uint64_t socket_id; 64 + }; 65 + 66 + struct sdsi_dev { 67 + struct sdsi_regs regs; 68 + char *dev_name; 69 + char *dev_path; 70 + int guid; 71 + }; 72 + 73 + enum command { 74 + CMD_NONE, 75 + CMD_SOCKET_INFO, 76 + CMD_DUMP_CERT, 77 + CMD_PROV_AKC, 78 + CMD_PROV_CAP, 79 + }; 80 + 81 + static void sdsi_list_devices(void) 82 + { 83 + struct dirent *entry; 84 + DIR *aux_dir; 85 + bool found = false; 86 + 87 + aux_dir = opendir(AUX_DEV_PATH); 88 + if (!aux_dir) { 89 + fprintf(stderr, "Cannot open directory %s\n", AUX_DEV_PATH); 90 + return; 91 + } 92 + 93 + while ((entry = readdir(aux_dir))) { 94 + if (!strncmp(SDSI_DEV, entry->d_name, strlen(SDSI_DEV))) { 95 + found = true; 96 + printf("%s\n", entry->d_name); 97 + } 98 + } 99 + 100 + if (!found) 101 + fprintf(stderr, "No sdsi devices found.\n"); 102 + } 103 + 104 + static int sdsi_update_registers(struct sdsi_dev *s) 105 + { 106 + FILE *regs_ptr; 107 + int ret; 108 + 109 + memset(&s->regs, 0, sizeof(s->regs)); 110 + 111 + /* Open the registers file */ 112 + ret = chdir(s->dev_path); 113 + if (ret == -1) { 114 + perror("chdir"); 115 + return ret; 116 + } 117 + 118 + regs_ptr = fopen("registers", "r"); 119 + if (!regs_ptr) { 120 + perror("Could not open 'registers' file"); 121 + return -1; 122 + } 123 + 124 + if (s->guid != GUID) { 125 + fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid); 126 + fclose(regs_ptr); 127 + return -1; 128 + } 129 + 130 + /* Update register info for this guid */ 131 + ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr); 132 + if (ret != sizeof(s->regs)) { 133 + fprintf(stderr, "Could not read 'registers' file\n"); 134 + fclose(regs_ptr); 135 + return -1; 136 + } 137 + 138 + fclose(regs_ptr); 139 + 140 + return 0; 141 + } 142 + 143 + static int sdsi_read_reg(struct sdsi_dev *s) 144 + { 145 + int ret; 146 + 147 + ret = sdsi_update_registers(s); 148 + if (ret) 149 + return ret; 150 + 151 + /* Print register info for this guid */ 152 + printf("\n"); 153 + printf("Socket information for device %s\n", s->dev_name); 154 + printf("\n"); 155 + printf("PPIN: 0x%lx\n", s->regs.ppin); 156 + printf("Enabled Features\n"); 157 + printf(" SDSi: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled"); 158 + printf("Authorization Failure Count\n"); 159 + printf(" AKC Failure Count: %d\n", s->regs.auth_fail_count.key_failure_count); 160 + printf(" AKC Failure Threshold: %d\n", s->regs.auth_fail_count.key_failure_threshold); 161 + printf(" CAP Failure Count: %d\n", s->regs.auth_fail_count.auth_failure_count); 162 + printf(" CAP Failure Threshold: %d\n", s->regs.auth_fail_count.auth_failure_threshold); 163 + printf("Provisioning Availability\n"); 164 + printf(" Updates Available: %d\n", s->regs.prov_avail.available); 165 + printf(" Updates Threshold: %d\n", s->regs.prov_avail.threshold); 166 + printf("Socket ID: %ld\n", s->regs.socket_id & 0xF); 167 + 168 + return 0; 169 + } 170 + 171 + static int sdsi_certificate_dump(struct sdsi_dev *s) 172 + { 173 + uint64_t state_certificate[512] = {0}; 174 + bool first_instance; 175 + uint64_t previous; 176 + FILE *cert_ptr; 177 + int i, ret, size; 178 + 179 + ret = sdsi_update_registers(s); 180 + if (ret) 181 + return ret; 182 + 183 + if (!s->regs.en_features.sdsi) { 184 + fprintf(stderr, "SDSi feature is present but not enabled."); 185 + fprintf(stderr, " Unable to read state certificate"); 186 + return -1; 187 + } 188 + 189 + ret = chdir(s->dev_path); 190 + if (ret == -1) { 191 + perror("chdir"); 192 + return ret; 193 + } 194 + 195 + cert_ptr = fopen("state_certificate", "r"); 196 + if (!cert_ptr) { 197 + perror("Could not open 'state_certificate' file"); 198 + return -1; 199 + } 200 + 201 + size = fread(state_certificate, 1, sizeof(state_certificate), cert_ptr); 202 + if (!size) { 203 + fprintf(stderr, "Could not read 'state_certificate' file\n"); 204 + fclose(cert_ptr); 205 + return -1; 206 + } 207 + 208 + printf("%3d: 0x%lx\n", 0, state_certificate[0]); 209 + previous = state_certificate[0]; 210 + first_instance = true; 211 + 212 + for (i = 1; i < (int)(round_up(size, sizeof(uint64_t))/sizeof(uint64_t)); i++) { 213 + if (state_certificate[i] == previous) { 214 + if (first_instance) { 215 + puts("*"); 216 + first_instance = false; 217 + } 218 + continue; 219 + } 220 + printf("%3d: 0x%lx\n", i, state_certificate[i]); 221 + previous = state_certificate[i]; 222 + first_instance = true; 223 + } 224 + printf("%3d\n", i); 225 + 226 + fclose(cert_ptr); 227 + 228 + return 0; 229 + } 230 + 231 + static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command) 232 + { 233 + int bin_fd, prov_fd, size, ret; 234 + char buf[4096] = { 0 }; 235 + char cap[] = "provision_cap"; 236 + char akc[] = "provision_akc"; 237 + char *prov_file; 238 + 239 + if (!bin_file) { 240 + fprintf(stderr, "No binary file provided\n"); 241 + return -1; 242 + } 243 + 244 + /* Open the binary */ 245 + bin_fd = open(bin_file, O_RDONLY); 246 + if (bin_fd == -1) { 247 + fprintf(stderr, "Could not open file %s: %s\n", bin_file, strerror(errno)); 248 + return bin_fd; 249 + } 250 + 251 + prov_file = (command == CMD_PROV_AKC) ? akc : cap; 252 + 253 + ret = chdir(s->dev_path); 254 + if (ret == -1) { 255 + perror("chdir"); 256 + close(bin_fd); 257 + return ret; 258 + } 259 + 260 + /* Open the provision file */ 261 + prov_fd = open(prov_file, O_WRONLY); 262 + if (prov_fd == -1) { 263 + fprintf(stderr, "Could not open file %s: %s\n", prov_file, strerror(errno)); 264 + close(bin_fd); 265 + return prov_fd; 266 + } 267 + 268 + /* Read the binary file into the buffer */ 269 + size = read(bin_fd, buf, 4096); 270 + if (size == -1) { 271 + close(bin_fd); 272 + close(prov_fd); 273 + return -1; 274 + } 275 + 276 + ret = write(prov_fd, buf, size); 277 + if (ret == -1) { 278 + close(bin_fd); 279 + close(prov_fd); 280 + perror("Provisioning failed"); 281 + return ret; 282 + } 283 + 284 + printf("Provisioned %s file %s successfully\n", prov_file, bin_file); 285 + 286 + close(bin_fd); 287 + close(prov_fd); 288 + 289 + return 0; 290 + } 291 + 292 + static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file) 293 + { 294 + int ret; 295 + 296 + ret = sdsi_update_registers(s); 297 + if (ret) 298 + return ret; 299 + 300 + if (!s->regs.en_features.sdsi) { 301 + fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision"); 302 + return -1; 303 + } 304 + 305 + if (!s->regs.prov_avail.available) { 306 + fprintf(stderr, "Maximum number of updates (%d) has been reached.\n", 307 + s->regs.prov_avail.threshold); 308 + return -1; 309 + } 310 + 311 + if (s->regs.auth_fail_count.key_failure_count == 312 + s->regs.auth_fail_count.key_failure_threshold) { 313 + fprintf(stderr, "Maximum number of AKC provision failures (%d) has been reached.\n", 314 + s->regs.auth_fail_count.key_failure_threshold); 315 + fprintf(stderr, "Power cycle the system to reset the counter\n"); 316 + return -1; 317 + } 318 + 319 + return sdsi_provision(s, bin_file, CMD_PROV_AKC); 320 + } 321 + 322 + static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file) 323 + { 324 + int ret; 325 + 326 + ret = sdsi_update_registers(s); 327 + if (ret) 328 + return ret; 329 + 330 + if (!s->regs.en_features.sdsi) { 331 + fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision"); 332 + return -1; 333 + } 334 + 335 + if (!s->regs.prov_avail.available) { 336 + fprintf(stderr, "Maximum number of updates (%d) has been reached.\n", 337 + s->regs.prov_avail.threshold); 338 + return -1; 339 + } 340 + 341 + if (s->regs.auth_fail_count.auth_failure_count == 342 + s->regs.auth_fail_count.auth_failure_threshold) { 343 + fprintf(stderr, "Maximum number of CAP provision failures (%d) has been reached.\n", 344 + s->regs.auth_fail_count.auth_failure_threshold); 345 + fprintf(stderr, "Power cycle the system to reset the counter\n"); 346 + return -1; 347 + } 348 + 349 + return sdsi_provision(s, bin_file, CMD_PROV_CAP); 350 + } 351 + 352 + static int read_sysfs_data(const char *file, int *value) 353 + { 354 + char buff[16]; 355 + FILE *fp; 356 + 357 + fp = fopen(file, "r"); 358 + if (!fp) { 359 + perror(file); 360 + return -1; 361 + } 362 + 363 + if (!fgets(buff, 16, fp)) { 364 + fprintf(stderr, "Failed to read file '%s'", file); 365 + fclose(fp); 366 + return -1; 367 + } 368 + 369 + fclose(fp); 370 + *value = strtol(buff, NULL, 0); 371 + 372 + return 0; 373 + } 374 + 375 + static struct sdsi_dev *sdsi_create_dev(char *dev_no) 376 + { 377 + int dev_name_len = sizeof(SDSI_DEV) + strlen(dev_no) + 1; 378 + struct sdsi_dev *s; 379 + int guid; 380 + DIR *dir; 381 + 382 + s = (struct sdsi_dev *)malloc(sizeof(*s)); 383 + if (!s) { 384 + perror("malloc"); 385 + return NULL; 386 + } 387 + 388 + s->dev_name = (char *)malloc(sizeof(SDSI_DEV) + strlen(dev_no) + 1); 389 + if (!s->dev_name) { 390 + perror("malloc"); 391 + free(s); 392 + return NULL; 393 + } 394 + 395 + snprintf(s->dev_name, dev_name_len, "%s.%s", SDSI_DEV, dev_no); 396 + 397 + s->dev_path = (char *)malloc(sizeof(AUX_DEV_PATH) + dev_name_len); 398 + if (!s->dev_path) { 399 + perror("malloc"); 400 + free(s->dev_name); 401 + free(s); 402 + return NULL; 403 + } 404 + 405 + snprintf(s->dev_path, sizeof(AUX_DEV_PATH) + dev_name_len, "%s%s", AUX_DEV_PATH, 406 + s->dev_name); 407 + dir = opendir(s->dev_path); 408 + if (!dir) { 409 + fprintf(stderr, "Could not open directory '%s': %s\n", s->dev_path, 410 + strerror(errno)); 411 + free(s->dev_path); 412 + free(s->dev_name); 413 + free(s); 414 + return NULL; 415 + } 416 + 417 + if (chdir(s->dev_path) == -1) { 418 + perror("chdir"); 419 + free(s->dev_path); 420 + free(s->dev_name); 421 + free(s); 422 + return NULL; 423 + } 424 + 425 + if (read_sysfs_data("guid", &guid)) { 426 + free(s->dev_path); 427 + free(s->dev_name); 428 + free(s); 429 + return NULL; 430 + } 431 + 432 + s->guid = guid; 433 + 434 + return s; 435 + } 436 + 437 + static void sdsi_free_dev(struct sdsi_dev *s) 438 + { 439 + free(s->dev_path); 440 + free(s->dev_name); 441 + free(s); 442 + } 443 + 444 + static void usage(char *prog) 445 + { 446 + printf("Usage: %s [-l] [-d DEVNO [-iD] [-a FILE] [-c FILE]]\n", prog); 447 + } 448 + 449 + static void show_help(void) 450 + { 451 + printf("Commands:\n"); 452 + printf(" %-18s\t%s\n", "-l, --list", "list available sdsi devices"); 453 + printf(" %-18s\t%s\n", "-d, --devno DEVNO", "sdsi device number"); 454 + printf(" %-18s\t%s\n", "-i --info", "show socket information"); 455 + printf(" %-18s\t%s\n", "-D --dump", "dump state certificate data"); 456 + printf(" %-18s\t%s\n", "-a --akc FILE", "provision socket with AKC FILE"); 457 + printf(" %-18s\t%s\n", "-c --cap FILE>", "provision socket with CAP FILE"); 458 + } 459 + 460 + int main(int argc, char *argv[]) 461 + { 462 + char bin_file[PATH_MAX], *dev_no = NULL; 463 + char *progname; 464 + enum command command = CMD_NONE; 465 + struct sdsi_dev *s; 466 + int ret = 0, opt; 467 + int option_index = 0; 468 + 469 + static struct option long_options[] = { 470 + {"akc", required_argument, 0, 'a'}, 471 + {"cap", required_argument, 0, 'c'}, 472 + {"devno", required_argument, 0, 'd'}, 473 + {"dump", no_argument, 0, 'D'}, 474 + {"help", no_argument, 0, 'h'}, 475 + {"info", no_argument, 0, 'i'}, 476 + {"list", no_argument, 0, 'l'}, 477 + {0, 0, 0, 0 } 478 + }; 479 + 480 + 481 + progname = argv[0]; 482 + 483 + while ((opt = getopt_long_only(argc, argv, "+a:c:d:Da:c:h", long_options, 484 + &option_index)) != -1) { 485 + switch (opt) { 486 + case 'd': 487 + dev_no = optarg; 488 + break; 489 + case 'l': 490 + sdsi_list_devices(); 491 + return 0; 492 + case 'i': 493 + command = CMD_SOCKET_INFO; 494 + break; 495 + case 'D': 496 + command = CMD_DUMP_CERT; 497 + break; 498 + case 'a': 499 + case 'c': 500 + if (!access(optarg, F_OK) == 0) { 501 + fprintf(stderr, "Could not open file '%s': %s\n", optarg, 502 + strerror(errno)); 503 + return -1; 504 + } 505 + 506 + if (!realpath(optarg, bin_file)) { 507 + perror("realpath"); 508 + return -1; 509 + } 510 + 511 + command = (opt == 'a') ? CMD_PROV_AKC : CMD_PROV_CAP; 512 + break; 513 + case 'h': 514 + usage(progname); 515 + show_help(); 516 + return 0; 517 + default: 518 + usage(progname); 519 + return -1; 520 + } 521 + } 522 + 523 + if (!dev_no) { 524 + if (command != CMD_NONE) 525 + fprintf(stderr, "Missing device number, DEVNO, for this command\n"); 526 + usage(progname); 527 + return -1; 528 + } 529 + 530 + s = sdsi_create_dev(dev_no); 531 + if (!s) 532 + return -1; 533 + 534 + /* Run the command */ 535 + switch (command) { 536 + case CMD_NONE: 537 + fprintf(stderr, "Missing command for device %s\n", dev_no); 538 + usage(progname); 539 + break; 540 + case CMD_SOCKET_INFO: 541 + ret = sdsi_read_reg(s); 542 + break; 543 + case CMD_DUMP_CERT: 544 + ret = sdsi_certificate_dump(s); 545 + break; 546 + case CMD_PROV_AKC: 547 + ret = sdsi_provision_akc(s, bin_file); 548 + break; 549 + case CMD_PROV_CAP: 550 + ret = sdsi_provision_cap(s, bin_file); 551 + break; 552 + } 553 + 554 + 555 + sdsi_free_dev(s); 556 + 557 + return ret; 558 + }
+25
tools/testing/selftests/drivers/sdsi/sdsi.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Runs tests for the intel_sdsi driver 4 + 5 + if ! command -v python3 > /dev/null 2>&1; then 6 + echo "drivers/sdsi: [SKIP] python3 not installed" 7 + exit 77 8 + fi 9 + 10 + if ! python3 -c "import pytest" > /dev/null 2>&1; then 11 + echo "drivers/sdsi: [SKIP] pytest module not installed" 12 + exit 77 13 + fi 14 + 15 + if ! /sbin/modprobe -q -r intel_sdsi; then 16 + echo "drivers/sdsi: [SKIP]" 17 + exit 77 18 + fi 19 + 20 + if /sbin/modprobe -q intel_sdsi && python3 -m pytest sdsi_test.py; then 21 + echo "drivers/sdsi: [OK]" 22 + else 23 + echo "drivers/sdsi: [FAIL]" 24 + exit 1 25 + fi
+226
tools/testing/selftests/drivers/sdsi/sdsi_test.py
··· 1 + #!/usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + from struct import pack 5 + from time import sleep 6 + 7 + import errno 8 + import glob 9 + import os 10 + import subprocess 11 + 12 + try: 13 + import pytest 14 + except ImportError: 15 + print("Unable to import pytest python module.") 16 + print("\nIf not already installed, you may do so with:") 17 + print("\t\tpip3 install pytest") 18 + exit(1) 19 + 20 + SOCKETS = glob.glob('/sys/bus/auxiliary/devices/intel_vsec.sdsi.*') 21 + NUM_SOCKETS = len(SOCKETS) 22 + 23 + MODULE_NAME = 'intel_sdsi' 24 + DEV_PREFIX = 'intel_vsec.sdsi' 25 + CLASS_DIR = '/sys/bus/auxiliary/devices' 26 + GUID = "0x6dd191" 27 + 28 + def read_bin_file(file): 29 + with open(file, mode='rb') as f: 30 + content = f.read() 31 + return content 32 + 33 + def get_dev_file_path(socket, file): 34 + return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/' + file 35 + 36 + def kmemleak_enabled(): 37 + kmemleak = "/sys/kernel/debug/kmemleak" 38 + return os.path.isfile(kmemleak) 39 + 40 + class TestSDSiDriver: 41 + def test_driver_loaded(self): 42 + lsmod_p = subprocess.Popen(('lsmod'), stdout=subprocess.PIPE) 43 + result = subprocess.check_output(('grep', '-q', MODULE_NAME), stdin=lsmod_p.stdout) 44 + 45 + @pytest.mark.parametrize('socket', range(0, NUM_SOCKETS)) 46 + class TestSDSiFilesClass: 47 + 48 + def read_value(self, file): 49 + f = open(file, "r") 50 + value = f.read().strip("\n") 51 + return value 52 + 53 + def get_dev_folder(self, socket): 54 + return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/' 55 + 56 + def test_sysfs_files_exist(self, socket): 57 + folder = self.get_dev_folder(socket) 58 + print (folder) 59 + assert os.path.isfile(folder + "guid") == True 60 + assert os.path.isfile(folder + "provision_akc") == True 61 + assert os.path.isfile(folder + "provision_cap") == True 62 + assert os.path.isfile(folder + "state_certificate") == True 63 + assert os.path.isfile(folder + "registers") == True 64 + 65 + def test_sysfs_file_permissions(self, socket): 66 + folder = self.get_dev_folder(socket) 67 + mode = os.stat(folder + "guid").st_mode & 0o777 68 + assert mode == 0o444 # Read all 69 + mode = os.stat(folder + "registers").st_mode & 0o777 70 + assert mode == 0o400 # Read owner 71 + mode = os.stat(folder + "provision_akc").st_mode & 0o777 72 + assert mode == 0o200 # Read owner 73 + mode = os.stat(folder + "provision_cap").st_mode & 0o777 74 + assert mode == 0o200 # Read owner 75 + mode = os.stat(folder + "state_certificate").st_mode & 0o777 76 + assert mode == 0o400 # Read owner 77 + 78 + def test_sysfs_file_ownership(self, socket): 79 + folder = self.get_dev_folder(socket) 80 + 81 + st = os.stat(folder + "guid") 82 + assert st.st_uid == 0 83 + assert st.st_gid == 0 84 + 85 + st = os.stat(folder + "registers") 86 + assert st.st_uid == 0 87 + assert st.st_gid == 0 88 + 89 + st = os.stat(folder + "provision_akc") 90 + assert st.st_uid == 0 91 + assert st.st_gid == 0 92 + 93 + st = os.stat(folder + "provision_cap") 94 + assert st.st_uid == 0 95 + assert st.st_gid == 0 96 + 97 + st = os.stat(folder + "state_certificate") 98 + assert st.st_uid == 0 99 + assert st.st_gid == 0 100 + 101 + def test_sysfs_file_sizes(self, socket): 102 + folder = self.get_dev_folder(socket) 103 + 104 + if self.read_value(folder + "guid") == GUID: 105 + st = os.stat(folder + "registers") 106 + assert st.st_size == 72 107 + 108 + st = os.stat(folder + "provision_akc") 109 + assert st.st_size == 1024 110 + 111 + st = os.stat(folder + "provision_cap") 112 + assert st.st_size == 1024 113 + 114 + st = os.stat(folder + "state_certificate") 115 + assert st.st_size == 4096 116 + 117 + def test_no_seek_allowed(self, socket): 118 + folder = self.get_dev_folder(socket) 119 + rand_file = bytes(os.urandom(8)) 120 + 121 + f = open(folder + "provision_cap", "wb", 0) 122 + f.seek(1) 123 + with pytest.raises(OSError) as error: 124 + f.write(rand_file) 125 + assert error.value.errno == errno.ESPIPE 126 + f.close() 127 + 128 + f = open(folder + "provision_akc", "wb", 0) 129 + f.seek(1) 130 + with pytest.raises(OSError) as error: 131 + f.write(rand_file) 132 + assert error.value.errno == errno.ESPIPE 133 + f.close() 134 + 135 + def test_registers_seek(self, socket): 136 + folder = self.get_dev_folder(socket) 137 + 138 + # Check that the value read from an offset of the entire 139 + # file is none-zero and the same as the value read 140 + # from seeking to the same location 141 + f = open(folder + "registers", "rb") 142 + data = f.read() 143 + f.seek(64) 144 + id = f.read() 145 + assert id != bytes(0) 146 + assert data[64:] == id 147 + f.close() 148 + 149 + @pytest.mark.parametrize('socket', range(0, NUM_SOCKETS)) 150 + class TestSDSiMailboxCmdsClass: 151 + def test_provision_akc_eoverflow_1017_bytes(self, socket): 152 + 153 + # The buffer for writes is 1k, of with 8 bytes must be 154 + # reserved for the command, leaving 1016 bytes max. 155 + # Check that we get an overflow error for 1017 bytes. 156 + node = get_dev_file_path(socket, "provision_akc") 157 + rand_file = bytes(os.urandom(1017)) 158 + 159 + f = open(node, 'wb', 0) 160 + with pytest.raises(OSError) as error: 161 + f.write(rand_file) 162 + assert error.value.errno == errno.EOVERFLOW 163 + f.close() 164 + 165 + @pytest.mark.parametrize('socket', range(0, NUM_SOCKETS)) 166 + class TestSdsiDriverLocksClass: 167 + def test_enodev_when_pci_device_removed(self, socket): 168 + node = get_dev_file_path(socket, "provision_akc") 169 + dev_name = DEV_PREFIX + '.' + str(socket) 170 + driver_dir = CLASS_DIR + '/' + dev_name + "/driver/" 171 + rand_file = bytes(os.urandom(8)) 172 + 173 + f = open(node, 'wb', 0) 174 + g = open(node, 'wb', 0) 175 + 176 + with open(driver_dir + 'unbind', 'w') as k: 177 + print(dev_name, file = k) 178 + 179 + with pytest.raises(OSError) as error: 180 + f.write(rand_file) 181 + assert error.value.errno == errno.ENODEV 182 + 183 + with pytest.raises(OSError) as error: 184 + g.write(rand_file) 185 + assert error.value.errno == errno.ENODEV 186 + 187 + f.close() 188 + g.close() 189 + 190 + # Short wait needed to allow file to close before pulling driver 191 + sleep(1) 192 + 193 + p = subprocess.Popen(('modprobe', '-r', 'intel_sdsi')) 194 + p.wait() 195 + p = subprocess.Popen(('modprobe', '-r', 'intel_vsec')) 196 + p.wait() 197 + p = subprocess.Popen(('modprobe', 'intel_vsec')) 198 + p.wait() 199 + 200 + # Short wait needed to allow driver time to get inserted 201 + # before continuing tests 202 + sleep(1) 203 + 204 + def test_memory_leak(self, socket): 205 + if not kmemleak_enabled(): 206 + pytest.skip("kmemleak not enabled in kernel") 207 + 208 + dev_name = DEV_PREFIX + '.' + str(socket) 209 + driver_dir = CLASS_DIR + '/' + dev_name + "/driver/" 210 + 211 + with open(driver_dir + 'unbind', 'w') as k: 212 + print(dev_name, file = k) 213 + 214 + sleep(1) 215 + 216 + subprocess.check_output(('modprobe', '-r', 'intel_sdsi')) 217 + subprocess.check_output(('modprobe', '-r', 'intel_vsec')) 218 + 219 + with open('/sys/kernel/debug/kmemleak', 'w') as f: 220 + print('scan', file = f) 221 + sleep(5) 222 + 223 + assert os.stat('/sys/kernel/debug/kmemleak').st_size == 0 224 + 225 + subprocess.check_output(('modprobe', 'intel_vsec')) 226 + sleep(1)