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

Pull x86 platform driver updates from Hans de Goede:
"This includes some small changes to kernel/stop_machine.c and arch/x86
which are deps of the new Intel IFS support.

Highlights:

- New drivers:
- Intel "In Field Scan" (IFS) support
- Winmate FM07/FM07P buttons
- Mellanox SN2201 support

- AMD PMC driver enhancements

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

* tag 'platform-drivers-x86-v5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (54 commits)
platform/x86/intel/ifs: Add CPU_SUP_INTEL dependency
platform/x86: intel_cht_int33fe: Set driver data
platform/x86: intel-hid: fix _DSM function index handling
platform/x86: toshiba_acpi: use kobj_to_dev()
platform/x86: samsung-laptop: use kobj_to_dev()
platform/x86: gigabyte-wmi: Add support for Z490 AORUS ELITE AC and X570 AORUS ELITE WIFI
tools/power/x86/intel-speed-select: Fix warning for perf_cap.cpu
tools/power/x86/intel-speed-select: Display error on turbo mode disabled
Documentation: In-Field Scan
platform/x86/intel/ifs: add ABI documentation for IFS
trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations
platform/x86/intel/ifs: Add IFS sysfs interface
platform/x86/intel/ifs: Add scan test support
platform/x86/intel/ifs: Authenticate and copy to secured memory
platform/x86/intel/ifs: Check IFS Image sanity
platform/x86/intel/ifs: Read IFS firmware image
platform/x86/intel/ifs: Add stub driver for In-Field Scan
stop_machine: Add stop_core_cpuslocked() for per-core operations
x86/msr-index: Define INTEGRITY_CAPABILITIES MSR
x86/microcode/intel: Expose collect_cpu_info_early() for IFS
...

+3013 -213
+36
Documentation/ABI/stable/sysfs-driver-mlxreg-io
··· 467 467 feeding and line card configuration Id. 468 468 469 469 The files are read only. 470 + 471 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/phy_reset 472 + Date: May 2022 473 + KernelVersion: 5.19 474 + Contact: Vadim Pasternak <vadimpmellanox.com> 475 + Description: This file allows to reset PHY 88E1548 when attribute is set 0 476 + due to some abnormal PHY behavior. 477 + Expected behavior: 478 + When phy_reset is written 1, all PHY 88E1548 are released 479 + from the reset state, when 0 - are hold in reset state. 480 + 481 + The files are read/write. 482 + 483 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/mac_reset 484 + Date: May 2022 485 + KernelVersion: 5.19 486 + Contact: Vadim Pasternak <vadimpmellanox.com> 487 + Description: This file allows to reset ASIC MT52132 when attribute is set 0 488 + due to some abnormal ASIC behavior. 489 + Expected behavior: 490 + When mac_reset is written 1, the ASIC MT52132 is released 491 + from the reset state, when 0 - is hold in reset state. 492 + 493 + The files are read/write. 494 + 495 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/qsfp_pwr_good 496 + Date: May 2022 497 + KernelVersion: 5.19 498 + Contact: Vadim Pasternak <vadimpmellanox.com> 499 + Description: This file shows QSFP ports power status. The value is set to 0 500 + when one of any QSFP ports is plugged. The value is set to 1 when 501 + there are no any QSFP ports are plugged. 502 + The possible values are: 503 + 0 - Power good, 1 - Not power good. 504 + 505 + The files are read only.
+39
Documentation/ABI/testing/sysfs-platform-intel-ifs
··· 1 + What: /sys/devices/virtual/misc/intel_ifs_<N>/run_test 2 + Date: April 21 2022 3 + KernelVersion: 5.19 4 + Contact: "Jithu Joseph" <jithu.joseph@intel.com> 5 + Description: Write <cpu#> to trigger IFS test for one online core. 6 + Note that the test is per core. The cpu# can be 7 + for any thread on the core. Running on one thread 8 + completes the test for the core containing that thread. 9 + Example: to test the core containing cpu5: echo 5 > 10 + /sys/devices/platform/intel_ifs.<N>/run_test 11 + 12 + What: /sys/devices/virtual/misc/intel_ifs_<N>/status 13 + Date: April 21 2022 14 + KernelVersion: 5.19 15 + Contact: "Jithu Joseph" <jithu.joseph@intel.com> 16 + Description: The status of the last test. It can be one of "pass", "fail" 17 + or "untested". 18 + 19 + What: /sys/devices/virtual/misc/intel_ifs_<N>/details 20 + Date: April 21 2022 21 + KernelVersion: 5.19 22 + Contact: "Jithu Joseph" <jithu.joseph@intel.com> 23 + Description: Additional information regarding the last test. The details file reports 24 + the hex value of the SCAN_STATUS MSR. Note that the error_code field 25 + may contain driver defined software code not defined in the Intel SDM. 26 + 27 + What: /sys/devices/virtual/misc/intel_ifs_<N>/image_version 28 + Date: April 21 2022 29 + KernelVersion: 5.19 30 + Contact: "Jithu Joseph" <jithu.joseph@intel.com> 31 + Description: Version (hexadecimal) of loaded IFS binary image. If no scan image 32 + is loaded reports "none". 33 + 34 + What: /sys/devices/virtual/misc/intel_ifs_<N>/reload 35 + Date: April 21 2022 36 + KernelVersion: 5.19 37 + Contact: "Jithu Joseph" <jithu.joseph@intel.com> 38 + Description: Write "1" (or "y" or "Y") to reload the IFS image from 39 + /lib/firmware/intel/ifs/ff-mm-ss.scan.
+2
Documentation/x86/ifs.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + .. kernel-doc:: drivers/platform/x86/intel/ifs/ifs.h
+1
Documentation/x86/index.rst
··· 36 36 usb-legacy-support 37 37 i386/index 38 38 x86_64/index 39 + ifs 39 40 sva 40 41 sgx 41 42 features
+8
MAINTAINERS
··· 9863 9863 T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git 9864 9864 F: drivers/idle/intel_idle.c 9865 9865 9866 + INTEL IN FIELD SCAN (IFS) DEVICE 9867 + M: Jithu Joseph <jithu.joseph@intel.com> 9868 + R: Ashok Raj <ashok.raj@intel.com> 9869 + R: Tony Luck <tony.luck@intel.com> 9870 + S: Maintained 9871 + F: drivers/platform/x86/intel/ifs 9872 + F: include/trace/events/intel_ifs.h 9873 + 9866 9874 INTEL INTEGRATED SENSOR HUB DRIVER 9867 9875 M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 9868 9876 M: Jiri Kosina <jikos@kernel.org>
+18
arch/x86/include/asm/cpu.h
··· 76 76 77 77 extern __noendbr void cet_disable(void); 78 78 79 + struct ucode_cpu_info; 80 + 81 + int intel_cpu_collect_info(struct ucode_cpu_info *uci); 82 + 83 + static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1, 84 + unsigned int s2, unsigned int p2) 85 + { 86 + if (s1 != s2) 87 + return false; 88 + 89 + /* Processor flags are either both 0 ... */ 90 + if (!p1 && !p2) 91 + return true; 92 + 93 + /* ... or they intersect. */ 94 + return p1 & p2; 95 + } 96 + 79 97 #endif /* _ASM_X86_CPU_H */
+7
arch/x86/include/asm/msr-index.h
··· 76 76 77 77 /* Abbreviated from Intel SDM name IA32_CORE_CAPABILITIES */ 78 78 #define MSR_IA32_CORE_CAPS 0x000000cf 79 + #define MSR_IA32_CORE_CAPS_INTEGRITY_CAPS_BIT 2 80 + #define MSR_IA32_CORE_CAPS_INTEGRITY_CAPS BIT(MSR_IA32_CORE_CAPS_INTEGRITY_CAPS_BIT) 79 81 #define MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT_BIT 5 80 82 #define MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT BIT(MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT_BIT) 81 83 ··· 155 153 156 154 #define MSR_IA32_POWER_CTL 0x000001fc 157 155 #define MSR_IA32_POWER_CTL_BIT_EE 19 156 + 157 + /* Abbreviated from Intel SDM name IA32_INTEGRITY_CAPABILITIES */ 158 + #define MSR_INTEGRITY_CAPS 0x000002d9 159 + #define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4 160 + #define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT) 158 161 159 162 #define MSR_LBR_NHM_FROM 0x00000680 160 163 #define MSR_LBR_NHM_TO 0x000006c0
+109 -5
arch/x86/include/uapi/asm/amd_hsmp.h
··· 31 31 HSMP_GET_CCLK_THROTTLE_LIMIT, /* 10h Get CCLK frequency limit in socket */ 32 32 HSMP_GET_C0_PERCENT, /* 11h Get average C0 residency in socket */ 33 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 */ 34 + HSMP_GET_NBIO_DPM_LEVEL, /* 13h Get LCLK DPM level min and max for a given NBIO */ 35 + HSMP_GET_DDR_BANDWIDTH, /* 14h Get theoretical maximum and current DDR Bandwidth */ 36 + HSMP_GET_TEMP_MONITOR, /* 15h Get socket temperature */ 37 + HSMP_GET_DIMM_TEMP_RANGE, /* 16h Get per-DIMM temperature range and refresh rate */ 38 + HSMP_GET_DIMM_POWER, /* 17h Get per-DIMM power consumption */ 39 + HSMP_GET_DIMM_THERMAL, /* 18h Get per-DIMM thermal sensors */ 40 + HSMP_GET_SOCKET_FREQ_LIMIT, /* 19h Get current active frequency per socket */ 41 + HSMP_GET_CCLK_CORE_LIMIT, /* 1Ah Get CCLK frequency limit per core */ 42 + HSMP_GET_RAILS_SVI, /* 1Bh Get SVI-based Telemetry for all rails */ 43 + HSMP_GET_SOCKET_FMAX_FMIN, /* 1Ch Get Fmax and Fmin per socket */ 44 + HSMP_GET_IOLINK_BANDWITH, /* 1Dh Get current bandwidth on IO Link */ 45 + HSMP_GET_XGMI_BANDWITH, /* 1Eh Get current bandwidth on xGMI Link */ 46 + HSMP_SET_GMI3_WIDTH, /* 1Fh Set max and min GMI3 Link width */ 47 + HSMP_SET_PCI_RATE, /* 20h Control link rate on PCIe devices */ 48 + HSMP_SET_POWER_MODE, /* 21h Select power efficiency profile policy */ 49 + HSMP_SET_PSTATE_MAX_MIN, /* 22h Set the max and min DF P-State */ 37 50 HSMP_MSG_ID_MAX, 38 51 }; 39 52 ··· 188 175 */ 189 176 {1, 0, HSMP_SET}, 190 177 191 - /* RESERVED message */ 192 - {0, 0, HSMP_RSVD}, 178 + /* 179 + * HSMP_GET_NBIO_DPM_LEVEL, num_args = 1, response_sz = 1 180 + * input: args[0] = nbioid[23:16] 181 + * output: args[0] = max dpm level[15:8] + min dpm level[7:0] 182 + */ 183 + {1, 1, HSMP_GET}, 193 184 194 185 /* 195 186 * HSMP_GET_DDR_BANDWIDTH, num_args = 0, response_sz = 1 ··· 208 191 * [7:5] fractional part 209 192 */ 210 193 {0, 1, HSMP_GET}, 194 + 195 + /* 196 + * HSMP_GET_DIMM_TEMP_RANGE, num_args = 1, response_sz = 1 197 + * input: args[0] = DIMM address[7:0] 198 + * output: args[0] = refresh rate[3] + temperature range[2:0] 199 + */ 200 + {1, 1, HSMP_GET}, 201 + 202 + /* 203 + * HSMP_GET_DIMM_POWER, num_args = 1, response_sz = 1 204 + * input: args[0] = DIMM address[7:0] 205 + * output: args[0] = DIMM power in mW[31:17] + update rate in ms[16:8] + 206 + * DIMM address[7:0] 207 + */ 208 + {1, 1, HSMP_GET}, 209 + 210 + /* 211 + * HSMP_GET_DIMM_THERMAL, num_args = 1, response_sz = 1 212 + * input: args[0] = DIMM address[7:0] 213 + * output: args[0] = temperature in degree celcius[31:21] + update rate in ms[16:8] + 214 + * DIMM address[7:0] 215 + */ 216 + {1, 1, HSMP_GET}, 217 + 218 + /* 219 + * HSMP_GET_SOCKET_FREQ_LIMIT, num_args = 0, response_sz = 1 220 + * output: args[0] = frequency in MHz[31:16] + frequency source[15:0] 221 + */ 222 + {0, 1, HSMP_GET}, 223 + 224 + /* 225 + * HSMP_GET_CCLK_CORE_LIMIT, num_args = 1, response_sz = 1 226 + * input: args[0] = apic id [31:0] 227 + * output: args[0] = frequency in MHz[31:0] 228 + */ 229 + {1, 1, HSMP_GET}, 230 + 231 + /* 232 + * HSMP_GET_RAILS_SVI, num_args = 0, response_sz = 1 233 + * output: args[0] = power in mW[31:0] 234 + */ 235 + {0, 1, HSMP_GET}, 236 + 237 + /* 238 + * HSMP_GET_SOCKET_FMAX_FMIN, num_args = 0, response_sz = 1 239 + * output: args[0] = fmax in MHz[31:16] + fmin in MHz[15:0] 240 + */ 241 + {0, 1, HSMP_GET}, 242 + 243 + /* 244 + * HSMP_GET_IOLINK_BANDWITH, num_args = 1, response_sz = 1 245 + * input: args[0] = link id[15:8] + bw type[2:0] 246 + * output: args[0] = io bandwidth in Mbps[31:0] 247 + */ 248 + {1, 1, HSMP_GET}, 249 + 250 + /* 251 + * HSMP_GET_XGMI_BANDWITH, num_args = 1, response_sz = 1 252 + * input: args[0] = link id[15:8] + bw type[2:0] 253 + * output: args[0] = xgmi bandwidth in Mbps[31:0] 254 + */ 255 + {1, 1, HSMP_GET}, 256 + 257 + /* 258 + * HSMP_SET_GMI3_WIDTH, num_args = 1, response_sz = 0 259 + * input: args[0] = min link width[15:8] + max link width[7:0] 260 + */ 261 + {1, 0, HSMP_SET}, 262 + 263 + /* 264 + * HSMP_SET_PCI_RATE, num_args = 1, response_sz = 1 265 + * input: args[0] = link rate control value 266 + * output: args[0] = previous link rate control value 267 + */ 268 + {1, 1, HSMP_SET}, 269 + 270 + /* 271 + * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0 272 + * input: args[0] = power efficiency mode[2:0] 273 + */ 274 + {1, 0, HSMP_SET}, 275 + 276 + /* 277 + * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0 278 + * input: args[0] = min df pstate[15:8] + max df pstate[7:0] 279 + */ 280 + {1, 0, HSMP_SET}, 211 281 }; 212 282 213 283 /* Reset to default packing */
+32
arch/x86/kernel/cpu/intel.c
··· 184 184 return false; 185 185 } 186 186 187 + int intel_cpu_collect_info(struct ucode_cpu_info *uci) 188 + { 189 + unsigned int val[2]; 190 + unsigned int family, model; 191 + struct cpu_signature csig = { 0 }; 192 + unsigned int eax, ebx, ecx, edx; 193 + 194 + memset(uci, 0, sizeof(*uci)); 195 + 196 + eax = 0x00000001; 197 + ecx = 0; 198 + native_cpuid(&eax, &ebx, &ecx, &edx); 199 + csig.sig = eax; 200 + 201 + family = x86_family(eax); 202 + model = x86_model(eax); 203 + 204 + if (model >= 5 || family > 6) { 205 + /* get processor flags from MSR 0x17 */ 206 + native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); 207 + csig.pf = 1 << ((val[1] >> 18) & 7); 208 + } 209 + 210 + csig.rev = intel_get_microcode_revision(); 211 + 212 + uci->cpu_sig = csig; 213 + uci->valid = 1; 214 + 215 + return 0; 216 + } 217 + EXPORT_SYMBOL_GPL(intel_cpu_collect_info); 218 + 187 219 static void early_init_intel(struct cpuinfo_x86 *c) 188 220 { 189 221 u64 misc_enable;
+7 -52
arch/x86/kernel/cpu/microcode/intel.c
··· 45 45 /* last level cache size per core */ 46 46 static int llc_size_per_core; 47 47 48 - static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1, 49 - unsigned int s2, unsigned int p2) 50 - { 51 - if (s1 != s2) 52 - return false; 53 - 54 - /* Processor flags are either both 0 ... */ 55 - if (!p1 && !p2) 56 - return true; 57 - 58 - /* ... or they intersect. */ 59 - return p1 & p2; 60 - } 61 - 62 48 /* 63 49 * Returns 1 if update has been found, 0 otherwise. 64 50 */ ··· 55 69 struct extended_signature *ext_sig; 56 70 int i; 57 71 58 - if (cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf)) 72 + if (intel_cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf)) 59 73 return 1; 60 74 61 75 /* Look for ext. headers: */ ··· 66 80 ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE; 67 81 68 82 for (i = 0; i < ext_hdr->count; i++) { 69 - if (cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf)) 83 + if (intel_cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf)) 70 84 return 1; 71 85 ext_sig++; 72 86 } ··· 328 342 return patch; 329 343 } 330 344 331 - static int collect_cpu_info_early(struct ucode_cpu_info *uci) 332 - { 333 - unsigned int val[2]; 334 - unsigned int family, model; 335 - struct cpu_signature csig = { 0 }; 336 - unsigned int eax, ebx, ecx, edx; 337 - 338 - memset(uci, 0, sizeof(*uci)); 339 - 340 - eax = 0x00000001; 341 - ecx = 0; 342 - native_cpuid(&eax, &ebx, &ecx, &edx); 343 - csig.sig = eax; 344 - 345 - family = x86_family(eax); 346 - model = x86_model(eax); 347 - 348 - if ((model >= 5) || (family > 6)) { 349 - /* get processor flags from MSR 0x17 */ 350 - native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); 351 - csig.pf = 1 << ((val[1] >> 18) & 7); 352 - } 353 - 354 - csig.rev = intel_get_microcode_revision(); 355 - 356 - uci->cpu_sig = csig; 357 - uci->valid = 1; 358 - 359 - return 0; 360 - } 361 - 362 345 static void show_saved_mc(void) 363 346 { 364 347 #ifdef DEBUG ··· 341 386 return; 342 387 } 343 388 344 - collect_cpu_info_early(&uci); 389 + intel_cpu_collect_info(&uci); 345 390 346 391 sig = uci.cpu_sig.sig; 347 392 pf = uci.cpu_sig.pf; ··· 457 502 struct ucode_cpu_info uci; 458 503 459 504 if (delay_ucode_info) { 460 - collect_cpu_info_early(&uci); 505 + intel_cpu_collect_info(&uci); 461 506 print_ucode_info(&uci, current_mc_date); 462 507 delay_ucode_info = 0; 463 508 } ··· 559 604 if (!(cp.data && cp.size)) 560 605 return 0; 561 606 562 - collect_cpu_info_early(&uci); 607 + intel_cpu_collect_info(&uci); 563 608 564 609 scan_microcode(cp.data, cp.size, &uci, true); 565 610 ··· 592 637 if (!(cp.data && cp.size)) 593 638 return NULL; 594 639 595 - collect_cpu_info_early(uci); 640 + intel_cpu_collect_info(uci); 596 641 597 642 return scan_microcode(cp.data, cp.size, uci, false); 598 643 } ··· 667 712 struct microcode_intel *p; 668 713 struct ucode_cpu_info uci; 669 714 670 - collect_cpu_info_early(&uci); 715 + intel_cpu_collect_info(&uci); 671 716 672 717 p = find_patch(&uci); 673 718 if (!p)
+17
drivers/platform/mellanox/Kconfig
··· 78 78 to performance monitoring counters within various blocks in the 79 79 Mellanox BlueField SoC via a sysfs interface. 80 80 81 + config NVSW_SN2201 82 + tristate "Nvidia SN2201 platform driver support" 83 + depends on REGMAP 84 + depends on HWMON 85 + depends on I2C 86 + depends on REGMAP_I2C 87 + help 88 + This driver provides support for the Nvidia SN2201 platfom. 89 + The SN2201 is a highly integrated for one rack unit system with 90 + L3 management switches. It has 48 x 1Gbps RJ45 + 4 x 100G QSFP28 91 + ports in a compact 1RU form factor. The system also including a 92 + serial port (RS-232 interface), an OOB port (1G/100M MDI interface) 93 + and USB ports for management functions. 94 + The processor used on SN2201 is Intel Atom®Processor C Series, 95 + C3338R which is one of the Denverton product families. 96 + System equipped with Nvidia®Spectrum-1 32x100GbE Ethernet switch. 97 + 81 98 endif # MELLANOX_PLATFORM
+1
drivers/platform/mellanox/Makefile
··· 9 9 obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o 10 10 obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o 11 11 obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o 12 + obj-$(CONFIG_NVSW_SN2201) += nvsw-sn2201.o
+1261
drivers/platform/mellanox/nvsw-sn2201.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Nvidia sn2201 driver 4 + * 5 + * Copyright (C) 2022 Nvidia Technologies Ltd. 6 + */ 7 + 8 + #include <linux/device.h> 9 + #include <linux/i2c.h> 10 + #include <linux/interrupt.h> 11 + #include <linux/irq.h> 12 + #include <linux/gpio.h> 13 + #include <linux/module.h> 14 + #include <linux/platform_data/mlxcpld.h> 15 + #include <linux/platform_data/mlxreg.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/regmap.h> 18 + 19 + /* SN2201 CPLD register offset. */ 20 + #define NVSW_SN2201_CPLD_LPC_I2C_BASE_ADRR 0x2000 21 + #define NVSW_SN2201_CPLD_LPC_IO_RANGE 0x100 22 + #define NVSW_SN2201_HW_VER_ID_OFFSET 0x00 23 + #define NVSW_SN2201_BOARD_ID_OFFSET 0x01 24 + #define NVSW_SN2201_CPLD_VER_OFFSET 0x02 25 + #define NVSW_SN2201_CPLD_MVER_OFFSET 0x03 26 + #define NVSW_SN2201_CPLD_ID_OFFSET 0x04 27 + #define NVSW_SN2201_CPLD_PN_OFFSET 0x05 28 + #define NVSW_SN2201_CPLD_PN1_OFFSET 0x06 29 + #define NVSW_SN2201_PSU_CTRL_OFFSET 0x0a 30 + #define NVSW_SN2201_QSFP28_STATUS_OFFSET 0x0b 31 + #define NVSW_SN2201_QSFP28_INT_STATUS_OFFSET 0x0c 32 + #define NVSW_SN2201_QSFP28_LP_STATUS_OFFSET 0x0d 33 + #define NVSW_SN2201_QSFP28_RST_STATUS_OFFSET 0x0e 34 + #define NVSW_SN2201_SYS_STATUS_OFFSET 0x0f 35 + #define NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET 0x10 36 + #define NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET 0x12 37 + #define NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET 0x13 38 + #define NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET 0x14 39 + #define NVSW_SN2201_SYS_RST_STATUS_OFFSET 0x15 40 + #define NVSW_SN2201_SYS_INT_STATUS_OFFSET 0x21 41 + #define NVSW_SN2201_SYS_INT_MASK_OFFSET 0x22 42 + #define NVSW_SN2201_ASIC_STATUS_OFFSET 0x24 43 + #define NVSW_SN2201_ASIC_EVENT_OFFSET 0x25 44 + #define NVSW_SN2201_ASIC_MAKS_OFFSET 0x26 45 + #define NVSW_SN2201_THML_STATUS_OFFSET 0x27 46 + #define NVSW_SN2201_THML_EVENT_OFFSET 0x28 47 + #define NVSW_SN2201_THML_MASK_OFFSET 0x29 48 + #define NVSW_SN2201_PS_ALT_STATUS_OFFSET 0x2a 49 + #define NVSW_SN2201_PS_ALT_EVENT_OFFSET 0x2b 50 + #define NVSW_SN2201_PS_ALT_MASK_OFFSET 0x2c 51 + #define NVSW_SN2201_PS_PRSNT_STATUS_OFFSET 0x30 52 + #define NVSW_SN2201_PS_PRSNT_EVENT_OFFSET 0x31 53 + #define NVSW_SN2201_PS_PRSNT_MASK_OFFSET 0x32 54 + #define NVSW_SN2201_PS_DC_OK_STATUS_OFFSET 0x33 55 + #define NVSW_SN2201_PS_DC_OK_EVENT_OFFSET 0x34 56 + #define NVSW_SN2201_PS_DC_OK_MASK_OFFSET 0x35 57 + #define NVSW_SN2201_RST_CAUSE1_OFFSET 0x36 58 + #define NVSW_SN2201_RST_CAUSE2_OFFSET 0x37 59 + #define NVSW_SN2201_RST_SW_CTRL_OFFSET 0x38 60 + #define NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET 0x3a 61 + #define NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET 0x3b 62 + #define NVSW_SN2201_FAN_PRSNT_MASK_OFFSET 0x3c 63 + #define NVSW_SN2201_WD_TMR_OFFSET_LSB 0x40 64 + #define NVSW_SN2201_WD_TMR_OFFSET_MSB 0x41 65 + #define NVSW_SN2201_WD_ACT_OFFSET 0x42 66 + #define NVSW_SN2201_FAN_LED1_CTRL_OFFSET 0x50 67 + #define NVSW_SN2201_FAN_LED2_CTRL_OFFSET 0x51 68 + #define NVSW_SN2201_REG_MAX 0x52 69 + 70 + /* Number of physical I2C busses. */ 71 + #define NVSW_SN2201_PHY_I2C_BUS_NUM 2 72 + /* Number of main mux channels. */ 73 + #define NVSW_SN2201_MAIN_MUX_CHNL_NUM 8 74 + 75 + #define NVSW_SN2201_MAIN_NR 0 76 + #define NVSW_SN2201_MAIN_MUX_NR 1 77 + #define NVSW_SN2201_MAIN_MUX_DEFER_NR (NVSW_SN2201_PHY_I2C_BUS_NUM + \ 78 + NVSW_SN2201_MAIN_MUX_CHNL_NUM - 1) 79 + 80 + #define NVSW_SN2201_MAIN_MUX_CH0_NR NVSW_SN2201_PHY_I2C_BUS_NUM 81 + #define NVSW_SN2201_MAIN_MUX_CH1_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 1) 82 + #define NVSW_SN2201_MAIN_MUX_CH2_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 2) 83 + #define NVSW_SN2201_MAIN_MUX_CH3_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 3) 84 + #define NVSW_SN2201_MAIN_MUX_CH5_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 5) 85 + #define NVSW_SN2201_MAIN_MUX_CH6_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 6) 86 + #define NVSW_SN2201_MAIN_MUX_CH7_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 7) 87 + 88 + #define NVSW_SN2201_CPLD_NR NVSW_SN2201_MAIN_MUX_CH0_NR 89 + #define NVSW_SN2201_NR_NONE -1 90 + 91 + /* Masks for aggregation, PSU presence and power, ASIC events 92 + * in CPLD related registers. 93 + */ 94 + #define NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF 0xe0 95 + #define NVSW_SN2201_CPLD_AGGR_PSU_MASK_DEF 0x04 96 + #define NVSW_SN2201_CPLD_AGGR_PWR_MASK_DEF 0x02 97 + #define NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF 0x10 98 + #define NVSW_SN2201_CPLD_AGGR_MASK_DEF \ 99 + (NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF \ 100 + | NVSW_SN2201_CPLD_AGGR_PSU_MASK_DEF \ 101 + | NVSW_SN2201_CPLD_AGGR_PWR_MASK_DEF \ 102 + | NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF) 103 + 104 + #define NVSW_SN2201_CPLD_ASIC_MASK GENMASK(3, 1) 105 + #define NVSW_SN2201_CPLD_PSU_MASK GENMASK(1, 0) 106 + #define NVSW_SN2201_CPLD_PWR_MASK GENMASK(1, 0) 107 + #define NVSW_SN2201_CPLD_FAN_MASK GENMASK(3, 0) 108 + 109 + #define NVSW_SN2201_CPLD_SYSIRQ 26 110 + #define NVSW_SN2201_LPC_SYSIRQ 28 111 + #define NVSW_SN2201_CPLD_I2CADDR 0x41 112 + 113 + #define NVSW_SN2201_WD_DFLT_TIMEOUT 600 114 + 115 + /* nvsw_sn2201 - device private data 116 + * @dev: platform device; 117 + * @io_data: register access platform data; 118 + * @led_data: LED platform data; 119 + * @hotplug_data: hotplug platform data; 120 + * @i2c_data: I2C controller platform data; 121 + * @led: LED device; 122 + * @io_regs: register access device; 123 + * @pdev_hotplug: hotplug device; 124 + * @sn2201_devs: I2C devices for sn2201 devices; 125 + * @sn2201_devs_num: number of I2C devices for sn2201 device; 126 + * @main_mux_devs: I2C devices for main mux; 127 + * @main_mux_devs_num: number of I2C devices for main mux; 128 + * @cpld_devs: I2C devices for cpld; 129 + * @cpld_devs_num: number of I2C devices for cpld; 130 + * @main_mux_deferred_nr: I2C adapter number must be exist prior creating devices execution; 131 + */ 132 + struct nvsw_sn2201 { 133 + struct device *dev; 134 + struct mlxreg_core_platform_data *io_data; 135 + struct mlxreg_core_platform_data *led_data; 136 + struct mlxreg_core_platform_data *wd_data; 137 + struct mlxreg_core_hotplug_platform_data *hotplug_data; 138 + struct mlxreg_core_hotplug_platform_data *i2c_data; 139 + struct platform_device *led; 140 + struct platform_device *wd; 141 + struct platform_device *io_regs; 142 + struct platform_device *pdev_hotplug; 143 + struct platform_device *pdev_i2c; 144 + struct mlxreg_hotplug_device *sn2201_devs; 145 + int sn2201_devs_num; 146 + struct mlxreg_hotplug_device *main_mux_devs; 147 + int main_mux_devs_num; 148 + struct mlxreg_hotplug_device *cpld_devs; 149 + int cpld_devs_num; 150 + int main_mux_deferred_nr; 151 + }; 152 + 153 + static bool nvsw_sn2201_writeable_reg(struct device *dev, unsigned int reg) 154 + { 155 + switch (reg) { 156 + case NVSW_SN2201_PSU_CTRL_OFFSET: 157 + case NVSW_SN2201_QSFP28_LP_STATUS_OFFSET: 158 + case NVSW_SN2201_QSFP28_RST_STATUS_OFFSET: 159 + case NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET: 160 + case NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET: 161 + case NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET: 162 + case NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET: 163 + case NVSW_SN2201_SYS_RST_STATUS_OFFSET: 164 + case NVSW_SN2201_SYS_INT_MASK_OFFSET: 165 + case NVSW_SN2201_ASIC_EVENT_OFFSET: 166 + case NVSW_SN2201_ASIC_MAKS_OFFSET: 167 + case NVSW_SN2201_THML_EVENT_OFFSET: 168 + case NVSW_SN2201_THML_MASK_OFFSET: 169 + case NVSW_SN2201_PS_ALT_EVENT_OFFSET: 170 + case NVSW_SN2201_PS_ALT_MASK_OFFSET: 171 + case NVSW_SN2201_PS_PRSNT_EVENT_OFFSET: 172 + case NVSW_SN2201_PS_PRSNT_MASK_OFFSET: 173 + case NVSW_SN2201_PS_DC_OK_EVENT_OFFSET: 174 + case NVSW_SN2201_PS_DC_OK_MASK_OFFSET: 175 + case NVSW_SN2201_RST_SW_CTRL_OFFSET: 176 + case NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET: 177 + case NVSW_SN2201_FAN_PRSNT_MASK_OFFSET: 178 + case NVSW_SN2201_WD_TMR_OFFSET_LSB: 179 + case NVSW_SN2201_WD_TMR_OFFSET_MSB: 180 + case NVSW_SN2201_WD_ACT_OFFSET: 181 + case NVSW_SN2201_FAN_LED1_CTRL_OFFSET: 182 + case NVSW_SN2201_FAN_LED2_CTRL_OFFSET: 183 + return true; 184 + } 185 + return false; 186 + } 187 + 188 + static bool nvsw_sn2201_readable_reg(struct device *dev, unsigned int reg) 189 + { 190 + switch (reg) { 191 + case NVSW_SN2201_HW_VER_ID_OFFSET: 192 + case NVSW_SN2201_BOARD_ID_OFFSET: 193 + case NVSW_SN2201_CPLD_VER_OFFSET: 194 + case NVSW_SN2201_CPLD_MVER_OFFSET: 195 + case NVSW_SN2201_CPLD_ID_OFFSET: 196 + case NVSW_SN2201_CPLD_PN_OFFSET: 197 + case NVSW_SN2201_CPLD_PN1_OFFSET: 198 + case NVSW_SN2201_PSU_CTRL_OFFSET: 199 + case NVSW_SN2201_QSFP28_STATUS_OFFSET: 200 + case NVSW_SN2201_QSFP28_INT_STATUS_OFFSET: 201 + case NVSW_SN2201_QSFP28_LP_STATUS_OFFSET: 202 + case NVSW_SN2201_QSFP28_RST_STATUS_OFFSET: 203 + case NVSW_SN2201_SYS_STATUS_OFFSET: 204 + case NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET: 205 + case NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET: 206 + case NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET: 207 + case NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET: 208 + case NVSW_SN2201_SYS_RST_STATUS_OFFSET: 209 + case NVSW_SN2201_RST_CAUSE1_OFFSET: 210 + case NVSW_SN2201_RST_CAUSE2_OFFSET: 211 + case NVSW_SN2201_SYS_INT_STATUS_OFFSET: 212 + case NVSW_SN2201_SYS_INT_MASK_OFFSET: 213 + case NVSW_SN2201_ASIC_STATUS_OFFSET: 214 + case NVSW_SN2201_ASIC_EVENT_OFFSET: 215 + case NVSW_SN2201_ASIC_MAKS_OFFSET: 216 + case NVSW_SN2201_THML_STATUS_OFFSET: 217 + case NVSW_SN2201_THML_EVENT_OFFSET: 218 + case NVSW_SN2201_THML_MASK_OFFSET: 219 + case NVSW_SN2201_PS_ALT_STATUS_OFFSET: 220 + case NVSW_SN2201_PS_ALT_EVENT_OFFSET: 221 + case NVSW_SN2201_PS_ALT_MASK_OFFSET: 222 + case NVSW_SN2201_PS_PRSNT_STATUS_OFFSET: 223 + case NVSW_SN2201_PS_PRSNT_EVENT_OFFSET: 224 + case NVSW_SN2201_PS_PRSNT_MASK_OFFSET: 225 + case NVSW_SN2201_PS_DC_OK_STATUS_OFFSET: 226 + case NVSW_SN2201_PS_DC_OK_EVENT_OFFSET: 227 + case NVSW_SN2201_PS_DC_OK_MASK_OFFSET: 228 + case NVSW_SN2201_RST_SW_CTRL_OFFSET: 229 + case NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET: 230 + case NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET: 231 + case NVSW_SN2201_FAN_PRSNT_MASK_OFFSET: 232 + case NVSW_SN2201_WD_TMR_OFFSET_LSB: 233 + case NVSW_SN2201_WD_TMR_OFFSET_MSB: 234 + case NVSW_SN2201_WD_ACT_OFFSET: 235 + case NVSW_SN2201_FAN_LED1_CTRL_OFFSET: 236 + case NVSW_SN2201_FAN_LED2_CTRL_OFFSET: 237 + return true; 238 + } 239 + return false; 240 + } 241 + 242 + static bool nvsw_sn2201_volatile_reg(struct device *dev, unsigned int reg) 243 + { 244 + switch (reg) { 245 + case NVSW_SN2201_HW_VER_ID_OFFSET: 246 + case NVSW_SN2201_BOARD_ID_OFFSET: 247 + case NVSW_SN2201_CPLD_VER_OFFSET: 248 + case NVSW_SN2201_CPLD_MVER_OFFSET: 249 + case NVSW_SN2201_CPLD_ID_OFFSET: 250 + case NVSW_SN2201_CPLD_PN_OFFSET: 251 + case NVSW_SN2201_CPLD_PN1_OFFSET: 252 + case NVSW_SN2201_PSU_CTRL_OFFSET: 253 + case NVSW_SN2201_QSFP28_STATUS_OFFSET: 254 + case NVSW_SN2201_QSFP28_INT_STATUS_OFFSET: 255 + case NVSW_SN2201_QSFP28_LP_STATUS_OFFSET: 256 + case NVSW_SN2201_QSFP28_RST_STATUS_OFFSET: 257 + case NVSW_SN2201_SYS_STATUS_OFFSET: 258 + case NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET: 259 + case NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET: 260 + case NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET: 261 + case NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET: 262 + case NVSW_SN2201_SYS_RST_STATUS_OFFSET: 263 + case NVSW_SN2201_RST_CAUSE1_OFFSET: 264 + case NVSW_SN2201_RST_CAUSE2_OFFSET: 265 + case NVSW_SN2201_SYS_INT_STATUS_OFFSET: 266 + case NVSW_SN2201_SYS_INT_MASK_OFFSET: 267 + case NVSW_SN2201_ASIC_STATUS_OFFSET: 268 + case NVSW_SN2201_ASIC_EVENT_OFFSET: 269 + case NVSW_SN2201_ASIC_MAKS_OFFSET: 270 + case NVSW_SN2201_THML_STATUS_OFFSET: 271 + case NVSW_SN2201_THML_EVENT_OFFSET: 272 + case NVSW_SN2201_THML_MASK_OFFSET: 273 + case NVSW_SN2201_PS_ALT_STATUS_OFFSET: 274 + case NVSW_SN2201_PS_ALT_EVENT_OFFSET: 275 + case NVSW_SN2201_PS_ALT_MASK_OFFSET: 276 + case NVSW_SN2201_PS_PRSNT_STATUS_OFFSET: 277 + case NVSW_SN2201_PS_PRSNT_EVENT_OFFSET: 278 + case NVSW_SN2201_PS_PRSNT_MASK_OFFSET: 279 + case NVSW_SN2201_PS_DC_OK_STATUS_OFFSET: 280 + case NVSW_SN2201_PS_DC_OK_EVENT_OFFSET: 281 + case NVSW_SN2201_PS_DC_OK_MASK_OFFSET: 282 + case NVSW_SN2201_RST_SW_CTRL_OFFSET: 283 + case NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET: 284 + case NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET: 285 + case NVSW_SN2201_FAN_PRSNT_MASK_OFFSET: 286 + case NVSW_SN2201_WD_TMR_OFFSET_LSB: 287 + case NVSW_SN2201_WD_TMR_OFFSET_MSB: 288 + case NVSW_SN2201_FAN_LED1_CTRL_OFFSET: 289 + case NVSW_SN2201_FAN_LED2_CTRL_OFFSET: 290 + return true; 291 + } 292 + return false; 293 + } 294 + 295 + static const struct reg_default nvsw_sn2201_regmap_default[] = { 296 + { NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET, 0x00 }, 297 + { NVSW_SN2201_WD_ACT_OFFSET, 0x00 }, 298 + }; 299 + 300 + /* Configuration for the register map of a device with 1 bytes address space. */ 301 + static const struct regmap_config nvsw_sn2201_regmap_conf = { 302 + .reg_bits = 8, 303 + .val_bits = 8, 304 + .max_register = NVSW_SN2201_REG_MAX, 305 + .cache_type = REGCACHE_FLAT, 306 + .writeable_reg = nvsw_sn2201_writeable_reg, 307 + .readable_reg = nvsw_sn2201_readable_reg, 308 + .volatile_reg = nvsw_sn2201_volatile_reg, 309 + .reg_defaults = nvsw_sn2201_regmap_default, 310 + .num_reg_defaults = ARRAY_SIZE(nvsw_sn2201_regmap_default), 311 + }; 312 + 313 + /* Regions for LPC I2C controller and LPC base register space. */ 314 + static const struct resource nvsw_sn2201_lpc_io_resources[] = { 315 + [0] = DEFINE_RES_NAMED(NVSW_SN2201_CPLD_LPC_I2C_BASE_ADRR, 316 + NVSW_SN2201_CPLD_LPC_IO_RANGE, 317 + "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), 318 + }; 319 + 320 + static struct resource nvsw_sn2201_cpld_res[] = { 321 + [0] = DEFINE_RES_IRQ_NAMED(NVSW_SN2201_CPLD_SYSIRQ, "mlxreg-hotplug"), 322 + }; 323 + 324 + static struct resource nvsw_sn2201_lpc_res[] = { 325 + [0] = DEFINE_RES_IRQ_NAMED(NVSW_SN2201_LPC_SYSIRQ, "i2c-mlxcpld"), 326 + }; 327 + 328 + /* SN2201 I2C platform data. */ 329 + struct mlxreg_core_hotplug_platform_data nvsw_sn2201_i2c_data = { 330 + .irq = NVSW_SN2201_CPLD_SYSIRQ, 331 + }; 332 + 333 + /* SN2201 CPLD device. */ 334 + static struct i2c_board_info nvsw_sn2201_cpld_devices[] = { 335 + { 336 + I2C_BOARD_INFO("nvsw-sn2201", 0x41), 337 + }, 338 + }; 339 + 340 + /* SN2201 CPLD board info. */ 341 + static struct mlxreg_hotplug_device nvsw_sn2201_cpld_brdinfo[] = { 342 + { 343 + .brdinfo = &nvsw_sn2201_cpld_devices[0], 344 + .nr = NVSW_SN2201_CPLD_NR, 345 + }, 346 + }; 347 + 348 + /* SN2201 main mux device. */ 349 + static struct i2c_board_info nvsw_sn2201_main_mux_devices[] = { 350 + { 351 + I2C_BOARD_INFO("pca9548", 0x70), 352 + }, 353 + }; 354 + 355 + /* SN2201 main mux board info. */ 356 + static struct mlxreg_hotplug_device nvsw_sn2201_main_mux_brdinfo[] = { 357 + { 358 + .brdinfo = &nvsw_sn2201_main_mux_devices[0], 359 + .nr = NVSW_SN2201_MAIN_MUX_NR, 360 + }, 361 + }; 362 + 363 + /* SN2201 power devices. */ 364 + static struct i2c_board_info nvsw_sn2201_pwr_devices[] = { 365 + { 366 + I2C_BOARD_INFO("pmbus", 0x58), 367 + }, 368 + { 369 + I2C_BOARD_INFO("pmbus", 0x58), 370 + }, 371 + }; 372 + 373 + /* SN2201 fan devices. */ 374 + static struct i2c_board_info nvsw_sn2201_fan_devices[] = { 375 + { 376 + I2C_BOARD_INFO("24c02", 0x50), 377 + }, 378 + { 379 + I2C_BOARD_INFO("24c02", 0x51), 380 + }, 381 + { 382 + I2C_BOARD_INFO("24c02", 0x52), 383 + }, 384 + { 385 + I2C_BOARD_INFO("24c02", 0x53), 386 + }, 387 + }; 388 + 389 + /* SN2201 hotplug default data. */ 390 + static struct mlxreg_core_data nvsw_sn2201_psu_items_data[] = { 391 + { 392 + .label = "psu1", 393 + .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, 394 + .mask = BIT(0), 395 + .hpdev.nr = NVSW_SN2201_NR_NONE, 396 + }, 397 + { 398 + .label = "psu2", 399 + .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, 400 + .mask = BIT(1), 401 + .hpdev.nr = NVSW_SN2201_NR_NONE, 402 + }, 403 + }; 404 + 405 + static struct mlxreg_core_data nvsw_sn2201_pwr_items_data[] = { 406 + { 407 + .label = "pwr1", 408 + .reg = NVSW_SN2201_PS_DC_OK_STATUS_OFFSET, 409 + .mask = BIT(0), 410 + .hpdev.brdinfo = &nvsw_sn2201_pwr_devices[0], 411 + .hpdev.nr = NVSW_SN2201_MAIN_MUX_CH1_NR, 412 + }, 413 + { 414 + .label = "pwr2", 415 + .reg = NVSW_SN2201_PS_DC_OK_STATUS_OFFSET, 416 + .mask = BIT(1), 417 + .hpdev.brdinfo = &nvsw_sn2201_pwr_devices[1], 418 + .hpdev.nr = NVSW_SN2201_MAIN_MUX_CH2_NR, 419 + }, 420 + }; 421 + 422 + static struct mlxreg_core_data nvsw_sn2201_fan_items_data[] = { 423 + { 424 + .label = "fan1", 425 + .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, 426 + .mask = BIT(0), 427 + .hpdev.brdinfo = &nvsw_sn2201_fan_devices[0], 428 + .hpdev.nr = NVSW_SN2201_NR_NONE, 429 + }, 430 + { 431 + .label = "fan2", 432 + .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, 433 + .mask = BIT(1), 434 + .hpdev.brdinfo = &nvsw_sn2201_fan_devices[1], 435 + .hpdev.nr = NVSW_SN2201_NR_NONE, 436 + }, 437 + { 438 + .label = "fan3", 439 + .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, 440 + .mask = BIT(2), 441 + .hpdev.brdinfo = &nvsw_sn2201_fan_devices[2], 442 + .hpdev.nr = NVSW_SN2201_NR_NONE, 443 + }, 444 + { 445 + .label = "fan4", 446 + .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, 447 + .mask = BIT(3), 448 + .hpdev.brdinfo = &nvsw_sn2201_fan_devices[3], 449 + .hpdev.nr = NVSW_SN2201_NR_NONE, 450 + }, 451 + }; 452 + 453 + static struct mlxreg_core_data nvsw_sn2201_sys_items_data[] = { 454 + { 455 + .label = "nic_smb_alert", 456 + .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, 457 + .mask = BIT(1), 458 + .hpdev.nr = NVSW_SN2201_NR_NONE, 459 + }, 460 + { 461 + .label = "cpu_sd", 462 + .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, 463 + .mask = BIT(2), 464 + .hpdev.nr = NVSW_SN2201_NR_NONE, 465 + }, 466 + { 467 + .label = "mac_health", 468 + .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, 469 + .mask = BIT(3), 470 + .hpdev.nr = NVSW_SN2201_NR_NONE, 471 + }, 472 + }; 473 + 474 + static struct mlxreg_core_item nvsw_sn2201_items[] = { 475 + { 476 + .data = nvsw_sn2201_psu_items_data, 477 + .aggr_mask = NVSW_SN2201_CPLD_AGGR_PSU_MASK_DEF, 478 + .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, 479 + .mask = NVSW_SN2201_CPLD_PSU_MASK, 480 + .count = ARRAY_SIZE(nvsw_sn2201_psu_items_data), 481 + .inversed = 1, 482 + .health = false, 483 + }, 484 + { 485 + .data = nvsw_sn2201_pwr_items_data, 486 + .aggr_mask = NVSW_SN2201_CPLD_AGGR_PWR_MASK_DEF, 487 + .reg = NVSW_SN2201_PS_DC_OK_STATUS_OFFSET, 488 + .mask = NVSW_SN2201_CPLD_PWR_MASK, 489 + .count = ARRAY_SIZE(nvsw_sn2201_pwr_items_data), 490 + .inversed = 0, 491 + .health = false, 492 + }, 493 + { 494 + .data = nvsw_sn2201_fan_items_data, 495 + .aggr_mask = NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF, 496 + .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, 497 + .mask = NVSW_SN2201_CPLD_FAN_MASK, 498 + .count = ARRAY_SIZE(nvsw_sn2201_fan_items_data), 499 + .inversed = 1, 500 + .health = false, 501 + }, 502 + { 503 + .data = nvsw_sn2201_sys_items_data, 504 + .aggr_mask = NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF, 505 + .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, 506 + .mask = NVSW_SN2201_CPLD_ASIC_MASK, 507 + .count = ARRAY_SIZE(nvsw_sn2201_sys_items_data), 508 + .inversed = 1, 509 + .health = false, 510 + }, 511 + }; 512 + 513 + static 514 + struct mlxreg_core_hotplug_platform_data nvsw_sn2201_hotplug = { 515 + .items = nvsw_sn2201_items, 516 + .counter = ARRAY_SIZE(nvsw_sn2201_items), 517 + .cell = NVSW_SN2201_SYS_INT_STATUS_OFFSET, 518 + .mask = NVSW_SN2201_CPLD_AGGR_MASK_DEF, 519 + }; 520 + 521 + /* SN2201 static devices. */ 522 + static struct i2c_board_info nvsw_sn2201_static_devices[] = { 523 + { 524 + I2C_BOARD_INFO("24c02", 0x57), 525 + }, 526 + { 527 + I2C_BOARD_INFO("lm75", 0x4b), 528 + }, 529 + { 530 + I2C_BOARD_INFO("24c64", 0x56), 531 + }, 532 + { 533 + I2C_BOARD_INFO("ads1015", 0x49), 534 + }, 535 + { 536 + I2C_BOARD_INFO("pca9546", 0x71), 537 + }, 538 + { 539 + I2C_BOARD_INFO("emc2305", 0x4d), 540 + }, 541 + { 542 + I2C_BOARD_INFO("lm75", 0x49), 543 + }, 544 + { 545 + I2C_BOARD_INFO("pca9555", 0x27), 546 + }, 547 + { 548 + I2C_BOARD_INFO("powr1014", 0x37), 549 + }, 550 + { 551 + I2C_BOARD_INFO("lm75", 0x4f), 552 + }, 553 + { 554 + I2C_BOARD_INFO("pmbus", 0x40), 555 + }, 556 + }; 557 + 558 + /* SN2201 default static board info. */ 559 + static struct mlxreg_hotplug_device nvsw_sn2201_static_brdinfo[] = { 560 + { 561 + .brdinfo = &nvsw_sn2201_static_devices[0], 562 + .nr = NVSW_SN2201_MAIN_NR, 563 + }, 564 + { 565 + .brdinfo = &nvsw_sn2201_static_devices[1], 566 + .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, 567 + }, 568 + { 569 + .brdinfo = &nvsw_sn2201_static_devices[2], 570 + .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, 571 + }, 572 + { 573 + .brdinfo = &nvsw_sn2201_static_devices[3], 574 + .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, 575 + }, 576 + { 577 + .brdinfo = &nvsw_sn2201_static_devices[4], 578 + .nr = NVSW_SN2201_MAIN_MUX_CH3_NR, 579 + }, 580 + { 581 + .brdinfo = &nvsw_sn2201_static_devices[5], 582 + .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, 583 + }, 584 + { 585 + .brdinfo = &nvsw_sn2201_static_devices[6], 586 + .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, 587 + }, 588 + { 589 + .brdinfo = &nvsw_sn2201_static_devices[7], 590 + .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, 591 + }, 592 + { 593 + .brdinfo = &nvsw_sn2201_static_devices[8], 594 + .nr = NVSW_SN2201_MAIN_MUX_CH6_NR, 595 + }, 596 + { 597 + .brdinfo = &nvsw_sn2201_static_devices[9], 598 + .nr = NVSW_SN2201_MAIN_MUX_CH6_NR, 599 + }, 600 + { 601 + .brdinfo = &nvsw_sn2201_static_devices[10], 602 + .nr = NVSW_SN2201_MAIN_MUX_CH7_NR, 603 + }, 604 + }; 605 + 606 + /* LED default data. */ 607 + static struct mlxreg_core_data nvsw_sn2201_led_data[] = { 608 + { 609 + .label = "status:green", 610 + .reg = NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET, 611 + .mask = GENMASK(7, 4), 612 + }, 613 + { 614 + .label = "status:orange", 615 + .reg = NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET, 616 + .mask = GENMASK(7, 4), 617 + }, 618 + { 619 + .label = "psu:green", 620 + .reg = NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET, 621 + .mask = GENMASK(7, 4), 622 + }, 623 + { 624 + .label = "psu:orange", 625 + .reg = NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET, 626 + .mask = GENMASK(7, 4), 627 + }, 628 + { 629 + .label = "uid:blue", 630 + .reg = NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET, 631 + .mask = GENMASK(7, 4), 632 + }, 633 + { 634 + .label = "fan1:green", 635 + .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, 636 + .mask = GENMASK(7, 4), 637 + }, 638 + { 639 + .label = "fan1:orange", 640 + .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, 641 + .mask = GENMASK(7, 4), 642 + }, 643 + { 644 + .label = "fan2:green", 645 + .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, 646 + .mask = GENMASK(3, 0), 647 + }, 648 + { 649 + .label = "fan2:orange", 650 + .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, 651 + .mask = GENMASK(3, 0), 652 + }, 653 + { 654 + .label = "fan3:green", 655 + .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, 656 + .mask = GENMASK(7, 4), 657 + }, 658 + { 659 + .label = "fan3:orange", 660 + .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, 661 + .mask = GENMASK(7, 4), 662 + }, 663 + { 664 + .label = "fan4:green", 665 + .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, 666 + .mask = GENMASK(3, 0), 667 + }, 668 + { 669 + .label = "fan4:orange", 670 + .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, 671 + .mask = GENMASK(3, 0), 672 + }, 673 + }; 674 + 675 + static struct mlxreg_core_platform_data nvsw_sn2201_led = { 676 + .data = nvsw_sn2201_led_data, 677 + .counter = ARRAY_SIZE(nvsw_sn2201_led_data), 678 + }; 679 + 680 + /* Default register access data. */ 681 + static struct mlxreg_core_data nvsw_sn2201_io_data[] = { 682 + { 683 + .label = "cpld1_version", 684 + .reg = NVSW_SN2201_CPLD_VER_OFFSET, 685 + .bit = GENMASK(7, 0), 686 + .mode = 0444, 687 + }, 688 + { 689 + .label = "cpld1_version_min", 690 + .reg = NVSW_SN2201_CPLD_MVER_OFFSET, 691 + .bit = GENMASK(7, 0), 692 + .mode = 0444, 693 + }, 694 + { 695 + .label = "cpld1_pn", 696 + .reg = NVSW_SN2201_CPLD_PN_OFFSET, 697 + .bit = GENMASK(15, 0), 698 + .mode = 0444, 699 + .regnum = 2, 700 + }, 701 + { 702 + .label = "psu1_on", 703 + .reg = NVSW_SN2201_PSU_CTRL_OFFSET, 704 + .mask = GENMASK(7, 0) & ~BIT(0), 705 + .mode = 0644, 706 + }, 707 + { 708 + .label = "psu2_on", 709 + .reg = NVSW_SN2201_PSU_CTRL_OFFSET, 710 + .mask = GENMASK(7, 0) & ~BIT(1), 711 + .mode = 0644, 712 + }, 713 + { 714 + .label = "pwr_cycle", 715 + .reg = NVSW_SN2201_PSU_CTRL_OFFSET, 716 + .mask = GENMASK(7, 0) & ~BIT(2), 717 + .mode = 0644, 718 + }, 719 + { 720 + .label = "asic_health", 721 + .reg = NVSW_SN2201_SYS_STATUS_OFFSET, 722 + .mask = GENMASK(4, 3), 723 + .bit = 4, 724 + .mode = 0444, 725 + }, 726 + { 727 + .label = "qsfp_pwr_good", 728 + .reg = NVSW_SN2201_SYS_STATUS_OFFSET, 729 + .mask = GENMASK(7, 0) & ~BIT(0), 730 + .mode = 0444, 731 + }, 732 + { 733 + .label = "phy_reset", 734 + .reg = NVSW_SN2201_SYS_RST_STATUS_OFFSET, 735 + .mask = GENMASK(7, 0) & ~BIT(3), 736 + .mode = 0644, 737 + }, 738 + { 739 + .label = "mac_reset", 740 + .reg = NVSW_SN2201_SYS_RST_STATUS_OFFSET, 741 + .mask = GENMASK(7, 0) & ~BIT(2), 742 + .mode = 0644, 743 + }, 744 + { 745 + .label = "pwr_down", 746 + .reg = NVSW_SN2201_RST_SW_CTRL_OFFSET, 747 + .mask = GENMASK(7, 0) & ~BIT(0), 748 + .mode = 0644, 749 + }, 750 + { 751 + .label = "reset_long_pb", 752 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 753 + .mask = GENMASK(7, 0) & ~BIT(0), 754 + .mode = 0444, 755 + }, 756 + { 757 + .label = "reset_short_pb", 758 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 759 + .mask = GENMASK(7, 0) & ~BIT(1), 760 + .mode = 0444, 761 + }, 762 + { 763 + .label = "reset_aux_pwr_or_fu", 764 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 765 + .mask = GENMASK(7, 0) & ~BIT(2), 766 + .mode = 0444, 767 + }, 768 + { 769 + .label = "reset_swb_dc_dc_pwr_fail", 770 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 771 + .mask = GENMASK(7, 0) & ~BIT(3), 772 + .mode = 0444, 773 + }, 774 + { 775 + .label = "reset_sw_reset", 776 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 777 + .mask = GENMASK(7, 0) & ~BIT(4), 778 + .mode = 0444, 779 + }, 780 + { 781 + .label = "reset_fw_reset", 782 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 783 + .mask = GENMASK(7, 0) & ~BIT(5), 784 + .mode = 0444, 785 + }, 786 + { 787 + .label = "reset_swb_wd", 788 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 789 + .mask = GENMASK(7, 0) & ~BIT(6), 790 + .mode = 0444, 791 + }, 792 + { 793 + .label = "reset_asic_thermal", 794 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 795 + .mask = GENMASK(7, 0) & ~BIT(7), 796 + .mode = 0444, 797 + }, 798 + { 799 + .label = "reset_system", 800 + .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, 801 + .mask = GENMASK(7, 0) & ~BIT(1), 802 + .mode = 0444, 803 + }, 804 + { 805 + .label = "reset_sw_pwr_off", 806 + .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, 807 + .mask = GENMASK(7, 0) & ~BIT(2), 808 + .mode = 0444, 809 + }, 810 + { 811 + .label = "reset_cpu_pwr_fail_thermal", 812 + .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, 813 + .mask = GENMASK(7, 0) & ~BIT(4), 814 + .mode = 0444, 815 + }, 816 + { 817 + .label = "reset_reload_bios", 818 + .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, 819 + .mask = GENMASK(7, 0) & ~BIT(5), 820 + .mode = 0444, 821 + }, 822 + { 823 + .label = "reset_ac_pwr_fail", 824 + .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, 825 + .mask = GENMASK(7, 0) & ~BIT(6), 826 + .mode = 0444, 827 + }, 828 + { 829 + .label = "psu1", 830 + .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, 831 + .mask = GENMASK(7, 0) & ~BIT(0), 832 + .mode = 0444, 833 + }, 834 + { 835 + .label = "psu2", 836 + .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, 837 + .mask = GENMASK(7, 0) & ~BIT(1), 838 + .mode = 0444, 839 + }, 840 + }; 841 + 842 + static struct mlxreg_core_platform_data nvsw_sn2201_regs_io = { 843 + .data = nvsw_sn2201_io_data, 844 + .counter = ARRAY_SIZE(nvsw_sn2201_io_data), 845 + }; 846 + 847 + /* Default watchdog data. */ 848 + static struct mlxreg_core_data nvsw_sn2201_wd_data[] = { 849 + { 850 + .label = "action", 851 + .reg = NVSW_SN2201_WD_ACT_OFFSET, 852 + .mask = GENMASK(7, 1), 853 + .bit = 0, 854 + }, 855 + { 856 + .label = "timeout", 857 + .reg = NVSW_SN2201_WD_TMR_OFFSET_LSB, 858 + .mask = 0, 859 + .health_cntr = NVSW_SN2201_WD_DFLT_TIMEOUT, 860 + }, 861 + { 862 + .label = "timeleft", 863 + .reg = NVSW_SN2201_WD_TMR_OFFSET_LSB, 864 + .mask = 0, 865 + }, 866 + { 867 + .label = "ping", 868 + .reg = NVSW_SN2201_WD_ACT_OFFSET, 869 + .mask = GENMASK(7, 1), 870 + .bit = 0, 871 + }, 872 + { 873 + .label = "reset", 874 + .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, 875 + .mask = GENMASK(7, 0) & ~BIT(6), 876 + .bit = 6, 877 + }, 878 + }; 879 + 880 + static struct mlxreg_core_platform_data nvsw_sn2201_wd = { 881 + .data = nvsw_sn2201_wd_data, 882 + .counter = ARRAY_SIZE(nvsw_sn2201_wd_data), 883 + .version = MLX_WDT_TYPE3, 884 + .identity = "mlx-wdt-main", 885 + }; 886 + 887 + static int 888 + nvsw_sn2201_create_static_devices(struct nvsw_sn2201 *nvsw_sn2201, 889 + struct mlxreg_hotplug_device *devs, 890 + int size) 891 + { 892 + struct mlxreg_hotplug_device *dev = devs; 893 + int i; 894 + 895 + /* Create I2C static devices. */ 896 + for (i = 0; i < size; i++, dev++) { 897 + dev->client = i2c_new_client_device(dev->adapter, dev->brdinfo); 898 + if (IS_ERR(dev->client)) { 899 + dev_err(nvsw_sn2201->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", 900 + dev->brdinfo->type, 901 + dev->nr, dev->brdinfo->addr); 902 + 903 + dev->adapter = NULL; 904 + goto fail_create_static_devices; 905 + } 906 + } 907 + 908 + return 0; 909 + 910 + fail_create_static_devices: 911 + while (--i >= 0) { 912 + dev = devs + i; 913 + i2c_unregister_device(dev->client); 914 + dev->client = NULL; 915 + dev->adapter = NULL; 916 + } 917 + return IS_ERR(dev->client); 918 + } 919 + 920 + static void nvsw_sn2201_destroy_static_devices(struct nvsw_sn2201 *nvsw_sn2201, 921 + struct mlxreg_hotplug_device *devs, int size) 922 + { 923 + struct mlxreg_hotplug_device *dev = devs; 924 + int i; 925 + 926 + /* Destroy static I2C device for SN2201 static devices. */ 927 + for (i = 0; i < size; i++, dev++) { 928 + if (dev->client) { 929 + i2c_unregister_device(dev->client); 930 + dev->client = NULL; 931 + i2c_put_adapter(dev->adapter); 932 + dev->adapter = NULL; 933 + } 934 + } 935 + } 936 + 937 + static int nvsw_sn2201_config_post_init(struct nvsw_sn2201 *nvsw_sn2201) 938 + { 939 + struct mlxreg_hotplug_device *sn2201_dev; 940 + struct i2c_adapter *adap; 941 + struct device *dev; 942 + int i, err; 943 + 944 + dev = nvsw_sn2201->dev; 945 + adap = i2c_get_adapter(nvsw_sn2201->main_mux_deferred_nr); 946 + if (!adap) { 947 + dev_err(dev, "Failed to get adapter for bus %d\n", 948 + nvsw_sn2201->main_mux_deferred_nr); 949 + return -ENODEV; 950 + } 951 + i2c_put_adapter(adap); 952 + 953 + /* Update board info. */ 954 + sn2201_dev = nvsw_sn2201->sn2201_devs; 955 + for (i = 0; i < nvsw_sn2201->sn2201_devs_num; i++, sn2201_dev++) { 956 + sn2201_dev->adapter = i2c_get_adapter(sn2201_dev->nr); 957 + if (!sn2201_dev->adapter) 958 + return -ENODEV; 959 + i2c_put_adapter(sn2201_dev->adapter); 960 + } 961 + 962 + err = nvsw_sn2201_create_static_devices(nvsw_sn2201, nvsw_sn2201->sn2201_devs, 963 + nvsw_sn2201->sn2201_devs_num); 964 + if (err) 965 + dev_err(dev, "Failed to create static devices\n"); 966 + 967 + return err; 968 + } 969 + 970 + static int nvsw_sn2201_config_init(struct nvsw_sn2201 *nvsw_sn2201, void *regmap) 971 + { 972 + struct device *dev = nvsw_sn2201->dev; 973 + int err; 974 + 975 + nvsw_sn2201->io_data = &nvsw_sn2201_regs_io; 976 + nvsw_sn2201->led_data = &nvsw_sn2201_led; 977 + nvsw_sn2201->wd_data = &nvsw_sn2201_wd; 978 + nvsw_sn2201->hotplug_data = &nvsw_sn2201_hotplug; 979 + 980 + /* Register IO access driver. */ 981 + if (nvsw_sn2201->io_data) { 982 + nvsw_sn2201->io_data->regmap = regmap; 983 + nvsw_sn2201->io_regs = 984 + platform_device_register_resndata(dev, "mlxreg-io", PLATFORM_DEVID_NONE, NULL, 0, 985 + nvsw_sn2201->io_data, 986 + sizeof(*nvsw_sn2201->io_data)); 987 + if (IS_ERR(nvsw_sn2201->io_regs)) { 988 + err = PTR_ERR(nvsw_sn2201->io_regs); 989 + goto fail_register_io; 990 + } 991 + } 992 + 993 + /* Register LED driver. */ 994 + if (nvsw_sn2201->led_data) { 995 + nvsw_sn2201->led_data->regmap = regmap; 996 + nvsw_sn2201->led = 997 + platform_device_register_resndata(dev, "leds-mlxreg", PLATFORM_DEVID_NONE, NULL, 0, 998 + nvsw_sn2201->led_data, 999 + sizeof(*nvsw_sn2201->led_data)); 1000 + if (IS_ERR(nvsw_sn2201->led)) { 1001 + err = PTR_ERR(nvsw_sn2201->led); 1002 + goto fail_register_led; 1003 + } 1004 + } 1005 + 1006 + /* Register WD driver. */ 1007 + if (nvsw_sn2201->wd_data) { 1008 + nvsw_sn2201->wd_data->regmap = regmap; 1009 + nvsw_sn2201->wd = 1010 + platform_device_register_resndata(dev, "mlx-wdt", PLATFORM_DEVID_NONE, NULL, 0, 1011 + nvsw_sn2201->wd_data, 1012 + sizeof(*nvsw_sn2201->wd_data)); 1013 + if (IS_ERR(nvsw_sn2201->wd)) { 1014 + err = PTR_ERR(nvsw_sn2201->wd); 1015 + goto fail_register_wd; 1016 + } 1017 + } 1018 + 1019 + /* Register hotplug driver. */ 1020 + if (nvsw_sn2201->hotplug_data) { 1021 + nvsw_sn2201->hotplug_data->regmap = regmap; 1022 + nvsw_sn2201->pdev_hotplug = 1023 + platform_device_register_resndata(dev, "mlxreg-hotplug", PLATFORM_DEVID_NONE, 1024 + nvsw_sn2201_cpld_res, 1025 + ARRAY_SIZE(nvsw_sn2201_cpld_res), 1026 + nvsw_sn2201->hotplug_data, 1027 + sizeof(*nvsw_sn2201->hotplug_data)); 1028 + if (IS_ERR(nvsw_sn2201->pdev_hotplug)) { 1029 + err = PTR_ERR(nvsw_sn2201->pdev_hotplug); 1030 + goto fail_register_hotplug; 1031 + } 1032 + } 1033 + 1034 + return nvsw_sn2201_config_post_init(nvsw_sn2201); 1035 + 1036 + fail_register_hotplug: 1037 + if (nvsw_sn2201->wd) 1038 + platform_device_unregister(nvsw_sn2201->wd); 1039 + fail_register_wd: 1040 + if (nvsw_sn2201->led) 1041 + platform_device_unregister(nvsw_sn2201->led); 1042 + fail_register_led: 1043 + if (nvsw_sn2201->io_regs) 1044 + platform_device_unregister(nvsw_sn2201->io_regs); 1045 + fail_register_io: 1046 + 1047 + return err; 1048 + } 1049 + 1050 + static void nvsw_sn2201_config_exit(struct nvsw_sn2201 *nvsw_sn2201) 1051 + { 1052 + /* Unregister hotplug driver. */ 1053 + if (nvsw_sn2201->pdev_hotplug) 1054 + platform_device_unregister(nvsw_sn2201->pdev_hotplug); 1055 + /* Unregister WD driver. */ 1056 + if (nvsw_sn2201->wd) 1057 + platform_device_unregister(nvsw_sn2201->wd); 1058 + /* Unregister LED driver. */ 1059 + if (nvsw_sn2201->led) 1060 + platform_device_unregister(nvsw_sn2201->led); 1061 + /* Unregister IO access driver. */ 1062 + if (nvsw_sn2201->io_regs) 1063 + platform_device_unregister(nvsw_sn2201->io_regs); 1064 + } 1065 + 1066 + /* 1067 + * Initialization is divided into two parts: 1068 + * - I2C main bus init. 1069 + * - Mux creation and attaching devices to the mux, 1070 + * which assumes that the main bus is already created. 1071 + * This separation is required for synchronization between these two parts. 1072 + * Completion notify callback is used to make this flow synchronized. 1073 + */ 1074 + static int nvsw_sn2201_i2c_completion_notify(void *handle, int id) 1075 + { 1076 + struct nvsw_sn2201 *nvsw_sn2201 = handle; 1077 + void *regmap; 1078 + int i, err; 1079 + 1080 + /* Create main mux. */ 1081 + nvsw_sn2201->main_mux_devs->adapter = i2c_get_adapter(nvsw_sn2201->main_mux_devs->nr); 1082 + if (!nvsw_sn2201->main_mux_devs->adapter) { 1083 + err = -ENODEV; 1084 + dev_err(nvsw_sn2201->dev, "Failed to get adapter for bus %d\n", 1085 + nvsw_sn2201->cpld_devs->nr); 1086 + goto i2c_get_adapter_main_fail; 1087 + } 1088 + 1089 + nvsw_sn2201->main_mux_devs_num = ARRAY_SIZE(nvsw_sn2201_main_mux_brdinfo); 1090 + err = nvsw_sn2201_create_static_devices(nvsw_sn2201, nvsw_sn2201->main_mux_devs, 1091 + nvsw_sn2201->main_mux_devs_num); 1092 + if (err) { 1093 + dev_err(nvsw_sn2201->dev, "Failed to create main mux devices\n"); 1094 + goto nvsw_sn2201_create_static_devices_fail; 1095 + } 1096 + 1097 + nvsw_sn2201->cpld_devs->adapter = i2c_get_adapter(nvsw_sn2201->cpld_devs->nr); 1098 + if (!nvsw_sn2201->cpld_devs->adapter) { 1099 + err = -ENODEV; 1100 + dev_err(nvsw_sn2201->dev, "Failed to get adapter for bus %d\n", 1101 + nvsw_sn2201->cpld_devs->nr); 1102 + goto i2c_get_adapter_fail; 1103 + } 1104 + 1105 + /* Create CPLD device. */ 1106 + nvsw_sn2201->cpld_devs->client = i2c_new_dummy_device(nvsw_sn2201->cpld_devs->adapter, 1107 + NVSW_SN2201_CPLD_I2CADDR); 1108 + if (IS_ERR(nvsw_sn2201->cpld_devs->client)) { 1109 + err = PTR_ERR(nvsw_sn2201->cpld_devs->client); 1110 + dev_err(nvsw_sn2201->dev, "Failed to create %s cpld device at bus %d at addr 0x%02x\n", 1111 + nvsw_sn2201->cpld_devs->brdinfo->type, nvsw_sn2201->cpld_devs->nr, 1112 + nvsw_sn2201->cpld_devs->brdinfo->addr); 1113 + goto i2c_new_dummy_fail; 1114 + } 1115 + 1116 + regmap = devm_regmap_init_i2c(nvsw_sn2201->cpld_devs->client, &nvsw_sn2201_regmap_conf); 1117 + if (IS_ERR(regmap)) { 1118 + err = PTR_ERR(regmap); 1119 + dev_err(nvsw_sn2201->dev, "Failed to initialise managed register map\n"); 1120 + goto devm_regmap_init_i2c_fail; 1121 + } 1122 + 1123 + /* Set default registers. */ 1124 + for (i = 0; i < nvsw_sn2201_regmap_conf.num_reg_defaults; i++) { 1125 + err = regmap_write(regmap, nvsw_sn2201_regmap_default[i].reg, 1126 + nvsw_sn2201_regmap_default[i].def); 1127 + if (err) { 1128 + dev_err(nvsw_sn2201->dev, "Failed to set register at offset 0x%02x to default value: 0x%02x\n", 1129 + nvsw_sn2201_regmap_default[i].reg, 1130 + nvsw_sn2201_regmap_default[i].def); 1131 + goto regmap_write_fail; 1132 + } 1133 + } 1134 + 1135 + /* Sync registers with hardware. */ 1136 + regcache_mark_dirty(regmap); 1137 + err = regcache_sync(regmap); 1138 + if (err) { 1139 + dev_err(nvsw_sn2201->dev, "Failed to Sync registers with hardware\n"); 1140 + goto regcache_sync_fail; 1141 + } 1142 + 1143 + /* Configure SN2201 board. */ 1144 + err = nvsw_sn2201_config_init(nvsw_sn2201, regmap); 1145 + if (err) { 1146 + dev_err(nvsw_sn2201->dev, "Failed to configure board\n"); 1147 + goto nvsw_sn2201_config_init_fail; 1148 + } 1149 + 1150 + return 0; 1151 + 1152 + nvsw_sn2201_config_init_fail: 1153 + nvsw_sn2201_config_exit(nvsw_sn2201); 1154 + regcache_sync_fail: 1155 + regmap_write_fail: 1156 + devm_regmap_init_i2c_fail: 1157 + i2c_new_dummy_fail: 1158 + i2c_put_adapter(nvsw_sn2201->cpld_devs->adapter); 1159 + nvsw_sn2201->cpld_devs->adapter = NULL; 1160 + i2c_get_adapter_fail: 1161 + /* Destroy SN2201 static I2C devices. */ 1162 + nvsw_sn2201_destroy_static_devices(nvsw_sn2201, nvsw_sn2201->sn2201_devs, 1163 + nvsw_sn2201->sn2201_devs_num); 1164 + /* Destroy main mux device. */ 1165 + nvsw_sn2201_destroy_static_devices(nvsw_sn2201, nvsw_sn2201->main_mux_devs, 1166 + nvsw_sn2201->main_mux_devs_num); 1167 + nvsw_sn2201_create_static_devices_fail: 1168 + i2c_put_adapter(nvsw_sn2201->main_mux_devs->adapter); 1169 + i2c_get_adapter_main_fail: 1170 + return err; 1171 + } 1172 + 1173 + static int nvsw_sn2201_config_pre_init(struct nvsw_sn2201 *nvsw_sn2201) 1174 + { 1175 + nvsw_sn2201->i2c_data = &nvsw_sn2201_i2c_data; 1176 + 1177 + /* Register I2C controller. */ 1178 + nvsw_sn2201->i2c_data->handle = nvsw_sn2201; 1179 + nvsw_sn2201->i2c_data->completion_notify = nvsw_sn2201_i2c_completion_notify; 1180 + nvsw_sn2201->pdev_i2c = platform_device_register_resndata(nvsw_sn2201->dev, "i2c_mlxcpld", 1181 + NVSW_SN2201_MAIN_MUX_NR, 1182 + nvsw_sn2201_lpc_res, 1183 + ARRAY_SIZE(nvsw_sn2201_lpc_res), 1184 + nvsw_sn2201->i2c_data, 1185 + sizeof(*nvsw_sn2201->i2c_data)); 1186 + if (IS_ERR(nvsw_sn2201->pdev_i2c)) 1187 + return PTR_ERR(nvsw_sn2201->pdev_i2c); 1188 + 1189 + return 0; 1190 + } 1191 + 1192 + static int nvsw_sn2201_probe(struct platform_device *pdev) 1193 + { 1194 + struct nvsw_sn2201 *nvsw_sn2201; 1195 + 1196 + nvsw_sn2201 = devm_kzalloc(&pdev->dev, sizeof(*nvsw_sn2201), GFP_KERNEL); 1197 + if (!nvsw_sn2201) 1198 + return -ENOMEM; 1199 + 1200 + nvsw_sn2201->dev = &pdev->dev; 1201 + platform_set_drvdata(pdev, nvsw_sn2201); 1202 + platform_device_add_resources(pdev, nvsw_sn2201_lpc_io_resources, 1203 + ARRAY_SIZE(nvsw_sn2201_lpc_io_resources)); 1204 + 1205 + nvsw_sn2201->main_mux_deferred_nr = NVSW_SN2201_MAIN_MUX_DEFER_NR; 1206 + nvsw_sn2201->main_mux_devs = nvsw_sn2201_main_mux_brdinfo; 1207 + nvsw_sn2201->cpld_devs = nvsw_sn2201_cpld_brdinfo; 1208 + nvsw_sn2201->sn2201_devs = nvsw_sn2201_static_brdinfo; 1209 + nvsw_sn2201->sn2201_devs_num = ARRAY_SIZE(nvsw_sn2201_static_brdinfo); 1210 + 1211 + return nvsw_sn2201_config_pre_init(nvsw_sn2201); 1212 + } 1213 + 1214 + static int nvsw_sn2201_remove(struct platform_device *pdev) 1215 + { 1216 + struct nvsw_sn2201 *nvsw_sn2201 = platform_get_drvdata(pdev); 1217 + 1218 + /* Unregister underlying drivers. */ 1219 + nvsw_sn2201_config_exit(nvsw_sn2201); 1220 + 1221 + /* Destroy SN2201 static I2C devices. */ 1222 + nvsw_sn2201_destroy_static_devices(nvsw_sn2201, 1223 + nvsw_sn2201->sn2201_devs, 1224 + nvsw_sn2201->sn2201_devs_num); 1225 + 1226 + i2c_put_adapter(nvsw_sn2201->cpld_devs->adapter); 1227 + nvsw_sn2201->cpld_devs->adapter = NULL; 1228 + /* Destroy main mux device. */ 1229 + nvsw_sn2201_destroy_static_devices(nvsw_sn2201, 1230 + nvsw_sn2201->main_mux_devs, 1231 + nvsw_sn2201->main_mux_devs_num); 1232 + 1233 + /* Unregister I2C controller. */ 1234 + if (nvsw_sn2201->pdev_i2c) 1235 + platform_device_unregister(nvsw_sn2201->pdev_i2c); 1236 + 1237 + return 0; 1238 + } 1239 + 1240 + static const struct acpi_device_id nvsw_sn2201_acpi_ids[] = { 1241 + {"NVSN2201", 0}, 1242 + {} 1243 + }; 1244 + 1245 + MODULE_DEVICE_TABLE(acpi, nvsw_sn2201_acpi_ids); 1246 + 1247 + static struct platform_driver nvsw_sn2201_driver = { 1248 + .probe = nvsw_sn2201_probe, 1249 + .remove = nvsw_sn2201_remove, 1250 + .driver = { 1251 + .name = "nvsw-sn2201", 1252 + .acpi_match_table = nvsw_sn2201_acpi_ids, 1253 + }, 1254 + }; 1255 + 1256 + module_platform_driver(nvsw_sn2201_driver); 1257 + 1258 + MODULE_AUTHOR("Nvidia"); 1259 + MODULE_DESCRIPTION("Nvidia sn2201 platform driver"); 1260 + MODULE_LICENSE("Dual BSD/GPL"); 1261 + MODULE_ALIAS("platform:nvsw-sn2201");
+8
drivers/platform/x86/Kconfig
··· 1152 1152 To compile this driver as a module, choose M here: the module 1153 1153 will be called simatic-ipc. 1154 1154 1155 + config WINMATE_FM07_KEYS 1156 + tristate "Winmate FM07/FM07P front-panel keys driver" 1157 + depends on INPUT 1158 + help 1159 + Winmate FM07 and FM07P in-vehicle computers have a row of five 1160 + buttons below the display. This module adds an input device 1161 + that delivers key events when these buttons are pressed. 1162 + 1155 1163 endif # X86_PLATFORM_DEVICES 1156 1164 1157 1165 config PMC_ATOM
+3
drivers/platform/x86/Makefile
··· 130 130 131 131 # Siemens Simatic Industrial PCs 132 132 obj-$(CONFIG_SIEMENS_SIMATIC_IPC) += simatic-ipc.o 133 + 134 + # Winmate 135 + obj-$(CONFIG_WINMATE_FM07_KEYS) += winmate-fm07-keys.o
+82 -65
drivers/platform/x86/amd-pmc.c
··· 192 192 u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX]; 193 193 } __packed; 194 194 195 - static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) 196 - { 197 - int rc; 198 - u32 val; 199 - 200 - rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1); 201 - if (rc) 202 - return rc; 203 - 204 - dev->smu_program = (val >> 24) & GENMASK(7, 0); 205 - dev->major = (val >> 16) & GENMASK(7, 0); 206 - dev->minor = (val >> 8) & GENMASK(7, 0); 207 - dev->rev = (val >> 0) & GENMASK(7, 0); 208 - 209 - dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n", 210 - dev->smu_program, dev->major, dev->minor, dev->rev); 211 - 212 - return 0; 213 - } 214 - 215 195 static int amd_pmc_stb_debugfs_open(struct inode *inode, struct file *filp) 216 196 { 217 197 struct amd_pmc_dev *dev = filp->f_inode->i_private; ··· 274 294 .release = amd_pmc_stb_debugfs_release_v2, 275 295 }; 276 296 297 + #if defined(CONFIG_SUSPEND) || defined(CONFIG_DEBUG_FS) 298 + static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev) 299 + { 300 + if (dev->cpu_id == AMD_CPU_ID_PCO) { 301 + dev_warn_once(dev->dev, "SMU debugging info not supported on this platform\n"); 302 + return -EINVAL; 303 + } 304 + 305 + /* Get Active devices list from SMU */ 306 + if (!dev->active_ips) 307 + amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, 1); 308 + 309 + /* Get dram address */ 310 + if (!dev->smu_virt_addr) { 311 + u32 phys_addr_low, phys_addr_hi; 312 + u64 smu_phys_addr; 313 + 314 + amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, 1); 315 + amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, 1); 316 + smu_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); 317 + 318 + dev->smu_virt_addr = devm_ioremap(dev->dev, smu_phys_addr, 319 + sizeof(struct smu_metrics)); 320 + if (!dev->smu_virt_addr) 321 + return -ENOMEM; 322 + } 323 + 324 + /* Start the logging */ 325 + amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_RESET, 0); 326 + amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, 0); 327 + 328 + return 0; 329 + } 330 + 277 331 static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, 278 332 struct seq_file *s) 279 333 { ··· 335 321 336 322 static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table) 337 323 { 324 + if (!pdev->smu_virt_addr) { 325 + int ret = amd_pmc_setup_smu_logging(pdev); 326 + 327 + if (ret) 328 + return ret; 329 + } 330 + 338 331 if (pdev->cpu_id == AMD_CPU_ID_PCO) 339 332 return -ENODEV; 340 333 memcpy_fromio(table, pdev->smu_virt_addr, sizeof(struct smu_metrics)); 341 334 return 0; 342 335 } 336 + #endif /* CONFIG_SUSPEND || CONFIG_DEBUG_FS */ 343 337 344 338 #ifdef CONFIG_SUSPEND 345 339 static void amd_pmc_validate_deepest(struct amd_pmc_dev *pdev) ··· 401 379 struct amd_pmc_dev *dev = s->private; 402 380 u64 entry_time, exit_time, residency; 403 381 382 + /* Use FCH registers to get the S0ix stats */ 383 + if (!dev->fch_virt_addr) { 384 + u32 base_addr_lo = FCH_BASE_PHY_ADDR_LOW; 385 + u32 base_addr_hi = FCH_BASE_PHY_ADDR_HIGH; 386 + u64 fch_phys_addr = ((u64)base_addr_hi << 32 | base_addr_lo); 387 + 388 + dev->fch_virt_addr = devm_ioremap(dev->dev, fch_phys_addr, FCH_SSC_MAPPING_SIZE); 389 + if (!dev->fch_virt_addr) 390 + return -ENOMEM; 391 + } 392 + 404 393 entry_time = ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_H_OFFSET); 405 394 entry_time = entry_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_L_OFFSET); 406 395 ··· 431 398 } 432 399 DEFINE_SHOW_ATTRIBUTE(s0ix_stats); 433 400 401 + static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) 402 + { 403 + int rc; 404 + u32 val; 405 + 406 + rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1); 407 + if (rc) 408 + return rc; 409 + 410 + dev->smu_program = (val >> 24) & GENMASK(7, 0); 411 + dev->major = (val >> 16) & GENMASK(7, 0); 412 + dev->minor = (val >> 8) & GENMASK(7, 0); 413 + dev->rev = (val >> 0) & GENMASK(7, 0); 414 + 415 + dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n", 416 + dev->smu_program, dev->major, dev->minor, dev->rev); 417 + 418 + return 0; 419 + } 420 + 434 421 static int amd_pmc_idlemask_show(struct seq_file *s, void *unused) 435 422 { 436 423 struct amd_pmc_dev *dev = s->private; 437 424 int rc; 425 + 426 + /* we haven't yet read SMU version */ 427 + if (!dev->major) { 428 + rc = amd_pmc_get_smu_version(dev); 429 + if (rc) 430 + return rc; 431 + } 438 432 439 433 if (dev->major > 56 || (dev->major >= 55 && dev->minor >= 37)) { 440 434 rc = amd_pmc_idlemask_read(dev, NULL, s); ··· 508 448 { 509 449 } 510 450 #endif /* CONFIG_DEBUG_FS */ 511 - 512 - static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev) 513 - { 514 - u32 phys_addr_low, phys_addr_hi; 515 - u64 smu_phys_addr; 516 - 517 - if (dev->cpu_id == AMD_CPU_ID_PCO) 518 - return -EINVAL; 519 - 520 - /* Get Active devices list from SMU */ 521 - amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, 1); 522 - 523 - /* Get dram address */ 524 - amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, 1); 525 - amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, 1); 526 - smu_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); 527 - 528 - dev->smu_virt_addr = devm_ioremap(dev->dev, smu_phys_addr, sizeof(struct smu_metrics)); 529 - if (!dev->smu_virt_addr) 530 - return -ENOMEM; 531 - 532 - /* Start the logging */ 533 - amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, 0); 534 - 535 - return 0; 536 - } 537 451 538 452 static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) 539 453 { ··· 673 639 u32 arg = 1; 674 640 675 641 /* Reset and Start SMU logging - to monitor the s0i3 stats */ 676 - amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0); 677 - amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0); 642 + amd_pmc_setup_smu_logging(pdev); 678 643 679 644 /* Activate CZN specific RTC functionality */ 680 645 if (pdev->cpu_id == AMD_CPU_ID_CZN) { ··· 823 790 struct amd_pmc_dev *dev = &pmc; 824 791 struct pci_dev *rdev; 825 792 u32 base_addr_lo, base_addr_hi; 826 - u64 base_addr, fch_phys_addr; 793 + u64 base_addr; 827 794 int err; 828 795 u32 val; 829 796 ··· 877 844 878 845 mutex_init(&dev->lock); 879 846 880 - /* Use FCH registers to get the S0ix stats */ 881 - base_addr_lo = FCH_BASE_PHY_ADDR_LOW; 882 - base_addr_hi = FCH_BASE_PHY_ADDR_HIGH; 883 - fch_phys_addr = ((u64)base_addr_hi << 32 | base_addr_lo); 884 - dev->fch_virt_addr = devm_ioremap(dev->dev, fch_phys_addr, FCH_SSC_MAPPING_SIZE); 885 - if (!dev->fch_virt_addr) { 886 - err = -ENOMEM; 887 - goto err_pci_dev_put; 888 - } 889 - 890 - /* Use SMU to get the s0i3 debug stats */ 891 - err = amd_pmc_setup_smu_logging(dev); 892 - if (err) 893 - dev_err(dev->dev, "SMU debugging info not supported on this platform\n"); 894 - 895 847 if (enable_stb && dev->cpu_id == AMD_CPU_ID_YC) { 896 848 err = amd_pmc_s2d_init(dev); 897 849 if (err) 898 850 return err; 899 851 } 900 852 901 - amd_pmc_get_smu_version(dev); 902 853 platform_set_drvdata(pdev, dev); 903 854 #ifdef CONFIG_SUSPEND 904 855 err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops);
+1
drivers/platform/x86/asus-nb-wmi.c
··· 553 553 { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ 554 554 { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ 555 555 { KE_KEY, 0x82, { KEY_CAMERA } }, 556 + { KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */ 556 557 { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ 557 558 { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ 558 559 { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
+2 -2
drivers/platform/x86/asus-wmi.c
··· 2534 2534 static umode_t asus_fan_curve_is_visible(struct kobject *kobj, 2535 2535 struct attribute *attr, int idx) 2536 2536 { 2537 - struct device *dev = container_of(kobj, struct device, kobj); 2537 + struct device *dev = kobj_to_dev(kobj); 2538 2538 struct asus_wmi *asus = dev_get_drvdata(dev->parent); 2539 2539 2540 2540 /* ··· 3114 3114 3115 3115 if (!sparse_keymap_report_event(asus->inputdev, code, 3116 3116 key_value, autorelease)) 3117 - pr_info("Unknown key %x pressed\n", code); 3117 + pr_info("Unknown key code 0x%x\n", code); 3118 3118 } 3119 3119 3120 3120 static void asus_wmi_notify(u32 value, void *context)
+70 -57
drivers/platform/x86/dell/dcdbas.c
··· 40 40 41 41 static struct platform_device *dcdbas_pdev; 42 42 43 - static u8 *smi_data_buf; 44 - static dma_addr_t smi_data_buf_handle; 45 - static unsigned long smi_data_buf_size; 46 43 static unsigned long max_smi_data_buf_size = MAX_SMI_DATA_BUF_SIZE; 47 - static u32 smi_data_buf_phys_addr; 48 44 static DEFINE_MUTEX(smi_data_lock); 49 45 static u8 *bios_buffer; 46 + static struct smi_buffer smi_buf; 50 47 51 48 static unsigned int host_control_action; 52 49 static unsigned int host_control_smi_type; ··· 51 54 52 55 static bool wsmt_enabled; 53 56 57 + int dcdbas_smi_alloc(struct smi_buffer *smi_buffer, unsigned long size) 58 + { 59 + smi_buffer->virt = dma_alloc_coherent(&dcdbas_pdev->dev, size, 60 + &smi_buffer->dma, GFP_KERNEL); 61 + if (!smi_buffer->virt) { 62 + dev_dbg(&dcdbas_pdev->dev, 63 + "%s: failed to allocate memory size %lu\n", 64 + __func__, size); 65 + return -ENOMEM; 66 + } 67 + smi_buffer->size = size; 68 + 69 + dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", 70 + __func__, (u32)smi_buffer->dma, smi_buffer->size); 71 + 72 + return 0; 73 + } 74 + EXPORT_SYMBOL_GPL(dcdbas_smi_alloc); 75 + 76 + void dcdbas_smi_free(struct smi_buffer *smi_buffer) 77 + { 78 + if (!smi_buffer->virt) 79 + return; 80 + 81 + dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", 82 + __func__, (u32)smi_buffer->dma, smi_buffer->size); 83 + dma_free_coherent(&dcdbas_pdev->dev, smi_buffer->size, 84 + smi_buffer->virt, smi_buffer->dma); 85 + smi_buffer->virt = NULL; 86 + smi_buffer->dma = 0; 87 + smi_buffer->size = 0; 88 + } 89 + EXPORT_SYMBOL_GPL(dcdbas_smi_free); 90 + 54 91 /** 55 92 * smi_data_buf_free: free SMI data buffer 56 93 */ 57 94 static void smi_data_buf_free(void) 58 95 { 59 - if (!smi_data_buf || wsmt_enabled) 96 + if (!smi_buf.virt || wsmt_enabled) 60 97 return; 61 98 62 - dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", 63 - __func__, smi_data_buf_phys_addr, smi_data_buf_size); 64 - 65 - dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf, 66 - smi_data_buf_handle); 67 - smi_data_buf = NULL; 68 - smi_data_buf_handle = 0; 69 - smi_data_buf_phys_addr = 0; 70 - smi_data_buf_size = 0; 99 + dcdbas_smi_free(&smi_buf); 71 100 } 72 101 73 102 /** ··· 101 78 */ 102 79 static int smi_data_buf_realloc(unsigned long size) 103 80 { 104 - void *buf; 105 - dma_addr_t handle; 81 + struct smi_buffer tmp; 82 + int ret; 106 83 107 - if (smi_data_buf_size >= size) 84 + if (smi_buf.size >= size) 108 85 return 0; 109 86 110 87 if (size > max_smi_data_buf_size) 111 88 return -EINVAL; 112 89 113 90 /* new buffer is needed */ 114 - buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL); 115 - if (!buf) { 116 - dev_dbg(&dcdbas_pdev->dev, 117 - "%s: failed to allocate memory size %lu\n", 118 - __func__, size); 119 - return -ENOMEM; 120 - } 121 - /* memory zeroed by dma_alloc_coherent */ 91 + ret = dcdbas_smi_alloc(&tmp, size); 92 + if (ret) 93 + return ret; 122 94 123 - if (smi_data_buf) 124 - memcpy(buf, smi_data_buf, smi_data_buf_size); 95 + /* memory zeroed by dma_alloc_coherent */ 96 + if (smi_buf.virt) 97 + memcpy(tmp.virt, smi_buf.virt, smi_buf.size); 125 98 126 99 /* free any existing buffer */ 127 100 smi_data_buf_free(); 128 101 129 102 /* set up new buffer for use */ 130 - smi_data_buf = buf; 131 - smi_data_buf_handle = handle; 132 - smi_data_buf_phys_addr = (u32) virt_to_phys(buf); 133 - smi_data_buf_size = size; 134 - 135 - dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", 136 - __func__, smi_data_buf_phys_addr, smi_data_buf_size); 103 + smi_buf = tmp; 137 104 138 105 return 0; 139 106 } ··· 132 119 struct device_attribute *attr, 133 120 char *buf) 134 121 { 135 - return sprintf(buf, "%x\n", smi_data_buf_phys_addr); 122 + return sprintf(buf, "%x\n", (u32)smi_buf.dma); 136 123 } 137 124 138 125 static ssize_t smi_data_buf_size_show(struct device *dev, 139 126 struct device_attribute *attr, 140 127 char *buf) 141 128 { 142 - return sprintf(buf, "%lu\n", smi_data_buf_size); 129 + return sprintf(buf, "%lu\n", smi_buf.size); 143 130 } 144 131 145 132 static ssize_t smi_data_buf_size_store(struct device *dev, ··· 168 155 ssize_t ret; 169 156 170 157 mutex_lock(&smi_data_lock); 171 - ret = memory_read_from_buffer(buf, count, &pos, smi_data_buf, 172 - smi_data_buf_size); 158 + ret = memory_read_from_buffer(buf, count, &pos, smi_buf.virt, 159 + smi_buf.size); 173 160 mutex_unlock(&smi_data_lock); 174 161 return ret; 175 162 } ··· 189 176 if (ret) 190 177 goto out; 191 178 192 - memcpy(smi_data_buf + pos, buf, count); 179 + memcpy(smi_buf.virt + pos, buf, count); 193 180 ret = count; 194 181 out: 195 182 mutex_unlock(&smi_data_lock); ··· 320 307 321 308 mutex_lock(&smi_data_lock); 322 309 323 - if (smi_data_buf_size < sizeof(struct smi_cmd)) { 310 + if (smi_buf.size < sizeof(struct smi_cmd)) { 324 311 ret = -ENODEV; 325 312 goto out; 326 313 } 327 - smi_cmd = (struct smi_cmd *)smi_data_buf; 314 + smi_cmd = (struct smi_cmd *)smi_buf.virt; 328 315 329 316 switch (val) { 330 317 case 2: ··· 340 327 * Provide physical address of command buffer field within 341 328 * the struct smi_cmd to BIOS. 342 329 * 343 - * Because the address that smi_cmd (smi_data_buf) points to 330 + * Because the address that smi_cmd (smi_buf.virt) points to 344 331 * will be from memremap() of a non-memory address if WSMT 345 332 * is present, we can't use virt_to_phys() on smi_cmd, so 346 333 * we have to use the physical address that was saved when 347 334 * the virtual address for smi_cmd was received. 348 335 */ 349 - smi_cmd->ebx = smi_data_buf_phys_addr + 336 + smi_cmd->ebx = (u32)smi_buf.dma + 350 337 offsetof(struct smi_cmd, command_buffer); 351 338 ret = dcdbas_smi_request(smi_cmd); 352 339 if (!ret) 353 340 ret = count; 354 341 break; 355 342 case 0: 356 - memset(smi_data_buf, 0, smi_data_buf_size); 343 + memset(smi_buf.virt, 0, smi_buf.size); 357 344 ret = count; 358 345 break; 359 346 default: ··· 369 356 /** 370 357 * host_control_smi: generate host control SMI 371 358 * 372 - * Caller must set up the host control command in smi_data_buf. 359 + * Caller must set up the host control command in smi_buf.virt. 373 360 */ 374 361 static int host_control_smi(void) 375 362 { ··· 380 367 s8 cmd_status; 381 368 u8 index; 382 369 383 - apm_cmd = (struct apm_cmd *)smi_data_buf; 370 + apm_cmd = (struct apm_cmd *)smi_buf.virt; 384 371 apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL; 385 372 386 373 switch (host_control_smi_type) { 387 374 case HC_SMITYPE_TYPE1: 388 375 spin_lock_irqsave(&rtc_lock, flags); 389 376 /* write SMI data buffer physical address */ 390 - data = (u8 *)&smi_data_buf_phys_addr; 377 + data = (u8 *)&smi_buf.dma; 391 378 for (index = PE1300_CMOS_CMD_STRUCT_PTR; 392 379 index < (PE1300_CMOS_CMD_STRUCT_PTR + 4); 393 380 index++, data++) { ··· 418 405 case HC_SMITYPE_TYPE3: 419 406 spin_lock_irqsave(&rtc_lock, flags); 420 407 /* write SMI data buffer physical address */ 421 - data = (u8 *)&smi_data_buf_phys_addr; 408 + data = (u8 *)&smi_buf.dma; 422 409 for (index = PE1400_CMOS_CMD_STRUCT_PTR; 423 410 index < (PE1400_CMOS_CMD_STRUCT_PTR + 4); 424 411 index++, data++) { ··· 463 450 * This function is called by the driver after the system has 464 451 * finished shutting down if the user application specified a 465 452 * host control action to perform on shutdown. It is safe to 466 - * use smi_data_buf at this point because the system has finished 453 + * use smi_buf.virt at this point because the system has finished 467 454 * shutting down and no userspace apps are running. 468 455 */ 469 456 static void dcdbas_host_control(void) ··· 477 464 action = host_control_action; 478 465 host_control_action = HC_ACTION_NONE; 479 466 480 - if (!smi_data_buf) { 467 + if (!smi_buf.virt) { 481 468 dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__); 482 469 return; 483 470 } 484 471 485 - if (smi_data_buf_size < sizeof(struct apm_cmd)) { 472 + if (smi_buf.size < sizeof(struct apm_cmd)) { 486 473 dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n", 487 474 __func__); 488 475 return; 489 476 } 490 477 491 - apm_cmd = (struct apm_cmd *)smi_data_buf; 478 + apm_cmd = (struct apm_cmd *)smi_buf.virt; 492 479 493 480 /* power off takes precedence */ 494 481 if (action & HC_ACTION_HOST_CONTROL_POWEROFF) { ··· 596 583 return -ENOMEM; 597 584 } 598 585 599 - /* First 8 bytes is for a semaphore, not part of the smi_data_buf */ 600 - smi_data_buf_phys_addr = bios_buf_paddr + 8; 601 - smi_data_buf = bios_buffer + 8; 602 - smi_data_buf_size = remap_size - 8; 603 - max_smi_data_buf_size = smi_data_buf_size; 586 + /* First 8 bytes is for a semaphore, not part of the smi_buf.virt */ 587 + smi_buf.dma = bios_buf_paddr + 8; 588 + smi_buf.virt = bios_buffer + 8; 589 + smi_buf.size = remap_size - 8; 590 + max_smi_data_buf_size = smi_buf.size; 604 591 wsmt_enabled = true; 605 592 dev_info(&dcdbas_pdev->dev, 606 593 "WSMT found, using firmware-provided SMI buffer.\n");
+9
drivers/platform/x86/dell/dcdbas.h
··· 105 105 u64 num_of_4k_pages; 106 106 } __packed; 107 107 108 + struct smi_buffer { 109 + u8 *virt; 110 + unsigned long size; 111 + dma_addr_t dma; 112 + }; 113 + 114 + int dcdbas_smi_alloc(struct smi_buffer *smi_buffer, unsigned long size); 115 + void dcdbas_smi_free(struct smi_buffer *smi_buffer); 116 + 108 117 #endif /* _DCDBAS_H_ */ 109 118
+8 -6
drivers/platform/x86/dell/dell-smbios-smm.c
··· 20 20 21 21 static int da_command_address; 22 22 static int da_command_code; 23 + static struct smi_buffer smi_buf; 23 24 static struct calling_interface_buffer *buffer; 24 25 static struct platform_device *platform_device; 25 26 static DEFINE_MUTEX(smm_mutex); ··· 58 57 command.magic = SMI_CMD_MAGIC; 59 58 command.command_address = da_command_address; 60 59 command.command_code = da_command_code; 61 - command.ebx = virt_to_phys(buffer); 60 + command.ebx = smi_buf.dma; 62 61 command.ecx = 0x42534931; 63 62 64 63 mutex_lock(&smm_mutex); ··· 102 101 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr 103 102 * is passed to SMI handler. 104 103 */ 105 - buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); 106 - if (!buffer) 107 - return -ENOMEM; 104 + ret = dcdbas_smi_alloc(&smi_buf, PAGE_SIZE); 105 + if (ret) 106 + return ret; 107 + buffer = (void *)smi_buf.virt; 108 108 109 109 dmi_walk(find_cmd_address, NULL); 110 110 ··· 140 138 141 139 fail_wsmt: 142 140 fail_platform_device_alloc: 143 - free_page((unsigned long)buffer); 141 + dcdbas_smi_free(&smi_buf); 144 142 return ret; 145 143 } 146 144 ··· 149 147 if (platform_device) { 150 148 dell_smbios_unregister_device(&platform_device->dev); 151 149 platform_device_unregister(platform_device); 152 - free_page((unsigned long)buffer); 150 + dcdbas_smi_free(&smi_buf); 153 151 } 154 152 }
+2
drivers/platform/x86/gigabyte-wmi.c
··· 150 150 DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"), 151 151 DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660 GAMING X DDR4"), 152 152 DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"), 153 + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z490 AORUS ELITE AC"), 153 154 DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE"), 155 + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE WIFI"), 154 156 DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 GAMING X"), 155 157 DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 I AORUS PRO WIFI"), 156 158 DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 UD"),
+8
drivers/platform/x86/hp-wmi.c
··· 605 605 for (i = 0; i < rfkill2_count; i++) { 606 606 int num = rfkill2[i].num; 607 607 struct bios_rfkill2_device_state *devstate; 608 + 608 609 devstate = &state.device[num]; 609 610 610 611 if (num >= state.count || ··· 626 625 char *buf) 627 626 { 628 627 int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY); 628 + 629 629 if (value < 0) 630 630 return value; 631 631 return sprintf(buf, "%d\n", value); ··· 636 634 char *buf) 637 635 { 638 636 int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY); 637 + 639 638 if (value < 0) 640 639 return value; 641 640 return sprintf(buf, "%d\n", value); ··· 646 643 char *buf) 647 644 { 648 645 int value = hp_wmi_read_int(HPWMI_ALS_QUERY); 646 + 649 647 if (value < 0) 650 648 return value; 651 649 return sprintf(buf, "%d\n", value); ··· 656 652 char *buf) 657 653 { 658 654 int value = hp_wmi_get_dock_state(); 655 + 659 656 if (value < 0) 660 657 return value; 661 658 return sprintf(buf, "%d\n", value); ··· 666 661 char *buf) 667 662 { 668 663 int value = hp_wmi_get_tablet_mode(); 664 + 669 665 if (value < 0) 670 666 return value; 671 667 return sprintf(buf, "%d\n", value); ··· 677 671 { 678 672 /* Get the POST error code of previous boot failure. */ 679 673 int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY); 674 + 680 675 if (value < 0) 681 676 return value; 682 677 return sprintf(buf, "0x%x\n", value); ··· 1020 1013 struct rfkill *rfkill; 1021 1014 enum rfkill_type type; 1022 1015 char *name; 1016 + 1023 1017 switch (state.device[i].radio_type) { 1024 1018 case HPWMI_WIFI: 1025 1019 type = RFKILL_TYPE_WLAN;
+1
drivers/platform/x86/intel/Kconfig
··· 4 4 # 5 5 6 6 source "drivers/platform/x86/intel/atomisp2/Kconfig" 7 + source "drivers/platform/x86/intel/ifs/Kconfig" 7 8 source "drivers/platform/x86/intel/int1092/Kconfig" 8 9 source "drivers/platform/x86/intel/int3472/Kconfig" 9 10 source "drivers/platform/x86/intel/pmc/Kconfig"
+1
drivers/platform/x86/intel/Makefile
··· 5 5 # 6 6 7 7 obj-$(CONFIG_INTEL_ATOMISP2_PDX86) += atomisp2/ 8 + obj-$(CONFIG_INTEL_IFS) += ifs/ 8 9 obj-$(CONFIG_INTEL_SAR_INT1092) += int1092/ 9 10 obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/ 10 11 obj-$(CONFIG_INTEL_PMC_CORE) += pmc/
+2
drivers/platform/x86/intel/chtwc_int33fe.c
··· 389 389 goto out_unregister_fusb302; 390 390 } 391 391 392 + platform_set_drvdata(pdev, data); 393 + 392 394 return 0; 393 395 394 396 out_unregister_fusb302:
+1 -1
drivers/platform/x86/intel/hid.c
··· 238 238 239 239 method_name = (char *)intel_hid_dsm_fn_to_method[fn_index]; 240 240 241 - if (!(intel_hid_dsm_fn_mask & fn_index)) 241 + if (!(intel_hid_dsm_fn_mask & BIT(fn_index))) 242 242 goto skip_dsm_eval; 243 243 244 244 obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid,
+13
drivers/platform/x86/intel/ifs/Kconfig
··· 1 + config INTEL_IFS 2 + tristate "Intel In Field Scan" 3 + depends on X86 && CPU_SUP_INTEL && 64BIT && SMP 4 + select INTEL_IFS_DEVICE 5 + help 6 + Enable support for the In Field Scan capability in select 7 + CPUs. The capability allows for running low level tests via 8 + a scan image distributed by Intel via Github to validate CPU 9 + operation beyond baseline RAS capabilities. To compile this 10 + support as a module, choose M here. The module will be called 11 + intel_ifs. 12 + 13 + If unsure, say N.
+3
drivers/platform/x86/intel/ifs/Makefile
··· 1 + obj-$(CONFIG_INTEL_IFS) += intel_ifs.o 2 + 3 + intel_ifs-objs := core.o load.o runtest.o sysfs.o
+73
drivers/platform/x86/intel/ifs/core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright(c) 2022 Intel Corporation. */ 3 + 4 + #include <linux/module.h> 5 + #include <linux/kdev_t.h> 6 + #include <linux/semaphore.h> 7 + 8 + #include <asm/cpu_device_id.h> 9 + 10 + #include "ifs.h" 11 + 12 + #define X86_MATCH(model) \ 13 + X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \ 14 + INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL) 15 + 16 + static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { 17 + X86_MATCH(SAPPHIRERAPIDS_X), 18 + {} 19 + }; 20 + MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); 21 + 22 + static struct ifs_device ifs_device = { 23 + .data = { 24 + .integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT, 25 + }, 26 + .misc = { 27 + .name = "intel_ifs_0", 28 + .nodename = "intel_ifs/0", 29 + .minor = MISC_DYNAMIC_MINOR, 30 + }, 31 + }; 32 + 33 + static int __init ifs_init(void) 34 + { 35 + const struct x86_cpu_id *m; 36 + u64 msrval; 37 + 38 + m = x86_match_cpu(ifs_cpu_ids); 39 + if (!m) 40 + return -ENODEV; 41 + 42 + if (rdmsrl_safe(MSR_IA32_CORE_CAPS, &msrval)) 43 + return -ENODEV; 44 + 45 + if (!(msrval & MSR_IA32_CORE_CAPS_INTEGRITY_CAPS)) 46 + return -ENODEV; 47 + 48 + if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval)) 49 + return -ENODEV; 50 + 51 + ifs_device.misc.groups = ifs_get_groups(); 52 + 53 + if ((msrval & BIT(ifs_device.data.integrity_cap_bit)) && 54 + !misc_register(&ifs_device.misc)) { 55 + down(&ifs_sem); 56 + ifs_load_firmware(ifs_device.misc.this_device); 57 + up(&ifs_sem); 58 + return 0; 59 + } 60 + 61 + return -ENODEV; 62 + } 63 + 64 + static void __exit ifs_exit(void) 65 + { 66 + misc_deregister(&ifs_device.misc); 67 + } 68 + 69 + module_init(ifs_init); 70 + module_exit(ifs_exit); 71 + 72 + MODULE_LICENSE("GPL"); 73 + MODULE_DESCRIPTION("Intel In Field Scan (IFS) device");
+234
drivers/platform/x86/intel/ifs/ifs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* Copyright(c) 2022 Intel Corporation. */ 3 + 4 + #ifndef _IFS_H_ 5 + #define _IFS_H_ 6 + 7 + /** 8 + * DOC: In-Field Scan 9 + * 10 + * ============= 11 + * In-Field Scan 12 + * ============= 13 + * 14 + * Introduction 15 + * ------------ 16 + * 17 + * In Field Scan (IFS) is a hardware feature to run circuit level tests on 18 + * a CPU core to detect problems that are not caught by parity or ECC checks. 19 + * Future CPUs will support more than one type of test which will show up 20 + * with a new platform-device instance-id, for now only .0 is exposed. 21 + * 22 + * 23 + * IFS Image 24 + * --------- 25 + * 26 + * Intel provides a firmware file containing the scan tests via 27 + * github [#f1]_. Similar to microcode there is a separate file for each 28 + * family-model-stepping. 29 + * 30 + * IFS Image Loading 31 + * ----------------- 32 + * 33 + * The driver loads the tests into memory reserved BIOS local to each CPU 34 + * socket in a two step process using writes to MSRs to first load the 35 + * SHA hashes for the test. Then the tests themselves. Status MSRs provide 36 + * feedback on the success/failure of these steps. When a new test file 37 + * is installed it can be loaded by writing to the driver reload file:: 38 + * 39 + * # echo 1 > /sys/devices/virtual/misc/intel_ifs_0/reload 40 + * 41 + * Similar to microcode, the current version of the scan tests is stored 42 + * in a fixed location: /lib/firmware/intel/ifs.0/family-model-stepping.scan 43 + * 44 + * Running tests 45 + * ------------- 46 + * 47 + * Tests are run by the driver synchronizing execution of all threads on a 48 + * core and then writing to the ACTIVATE_SCAN MSR on all threads. Instruction 49 + * execution continues when: 50 + * 51 + * 1) All tests have completed. 52 + * 2) Execution was interrupted. 53 + * 3) A test detected a problem. 54 + * 55 + * Note that ALL THREADS ON THE CORE ARE EFFECTIVELY OFFLINE FOR THE 56 + * DURATION OF THE TEST. This can be up to 200 milliseconds. If the system 57 + * is running latency sensitive applications that cannot tolerate an 58 + * interruption of this magnitude, the system administrator must arrange 59 + * to migrate those applications to other cores before running a core test. 60 + * It may also be necessary to redirect interrupts to other CPUs. 61 + * 62 + * In all cases reading the SCAN_STATUS MSR provides details on what 63 + * happened. The driver makes the value of this MSR visible to applications 64 + * via the "details" file (see below). Interrupted tests may be restarted. 65 + * 66 + * The IFS driver provides sysfs interfaces via /sys/devices/virtual/misc/intel_ifs_0/ 67 + * to control execution: 68 + * 69 + * Test a specific core:: 70 + * 71 + * # echo <cpu#> > /sys/devices/virtual/misc/intel_ifs_0/run_test 72 + * 73 + * when HT is enabled any of the sibling cpu# can be specified to test 74 + * its corresponding physical core. Since the tests are per physical core, 75 + * the result of testing any thread is same. All siblings must be online 76 + * to run a core test. It is only necessary to test one thread. 77 + * 78 + * For e.g. to test core corresponding to cpu5 79 + * 80 + * # echo 5 > /sys/devices/virtual/misc/intel_ifs_0/run_test 81 + * 82 + * Results of the last test is provided in /sys:: 83 + * 84 + * $ cat /sys/devices/virtual/misc/intel_ifs_0/status 85 + * pass 86 + * 87 + * Status can be one of pass, fail, untested 88 + * 89 + * Additional details of the last test is provided by the details file:: 90 + * 91 + * $ cat /sys/devices/virtual/misc/intel_ifs_0/details 92 + * 0x8081 93 + * 94 + * The details file reports the hex value of the SCAN_STATUS MSR. 95 + * Hardware defined error codes are documented in volume 4 of the Intel 96 + * Software Developer's Manual but the error_code field may contain one of 97 + * the following driver defined software codes: 98 + * 99 + * +------+--------------------+ 100 + * | 0xFD | Software timeout | 101 + * +------+--------------------+ 102 + * | 0xFE | Partial completion | 103 + * +------+--------------------+ 104 + * 105 + * Driver design choices 106 + * --------------------- 107 + * 108 + * 1) The ACTIVATE_SCAN MSR allows for running any consecutive subrange of 109 + * available tests. But the driver always tries to run all tests and only 110 + * uses the subrange feature to restart an interrupted test. 111 + * 112 + * 2) Hardware allows for some number of cores to be tested in parallel. 113 + * The driver does not make use of this, it only tests one core at a time. 114 + * 115 + * .. [#f1] https://github.com/intel/TBD 116 + */ 117 + #include <linux/device.h> 118 + #include <linux/miscdevice.h> 119 + 120 + #define MSR_COPY_SCAN_HASHES 0x000002c2 121 + #define MSR_SCAN_HASHES_STATUS 0x000002c3 122 + #define MSR_AUTHENTICATE_AND_COPY_CHUNK 0x000002c4 123 + #define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5 124 + #define MSR_ACTIVATE_SCAN 0x000002c6 125 + #define MSR_SCAN_STATUS 0x000002c7 126 + #define SCAN_NOT_TESTED 0 127 + #define SCAN_TEST_PASS 1 128 + #define SCAN_TEST_FAIL 2 129 + 130 + /* MSR_SCAN_HASHES_STATUS bit fields */ 131 + union ifs_scan_hashes_status { 132 + u64 data; 133 + struct { 134 + u32 chunk_size :16; 135 + u32 num_chunks :8; 136 + u32 rsvd1 :8; 137 + u32 error_code :8; 138 + u32 rsvd2 :11; 139 + u32 max_core_limit :12; 140 + u32 valid :1; 141 + }; 142 + }; 143 + 144 + /* MSR_CHUNKS_AUTH_STATUS bit fields */ 145 + union ifs_chunks_auth_status { 146 + u64 data; 147 + struct { 148 + u32 valid_chunks :8; 149 + u32 total_chunks :8; 150 + u32 rsvd1 :16; 151 + u32 error_code :8; 152 + u32 rsvd2 :24; 153 + }; 154 + }; 155 + 156 + /* MSR_ACTIVATE_SCAN bit fields */ 157 + union ifs_scan { 158 + u64 data; 159 + struct { 160 + u32 start :8; 161 + u32 stop :8; 162 + u32 rsvd :16; 163 + u32 delay :31; 164 + u32 sigmce :1; 165 + }; 166 + }; 167 + 168 + /* MSR_SCAN_STATUS bit fields */ 169 + union ifs_status { 170 + u64 data; 171 + struct { 172 + u32 chunk_num :8; 173 + u32 chunk_stop_index :8; 174 + u32 rsvd1 :16; 175 + u32 error_code :8; 176 + u32 rsvd2 :22; 177 + u32 control_error :1; 178 + u32 signature_error :1; 179 + }; 180 + }; 181 + 182 + /* 183 + * Driver populated error-codes 184 + * 0xFD: Test timed out before completing all the chunks. 185 + * 0xFE: not all scan chunks were executed. Maximum forward progress retries exceeded. 186 + */ 187 + #define IFS_SW_TIMEOUT 0xFD 188 + #define IFS_SW_PARTIAL_COMPLETION 0xFE 189 + 190 + /** 191 + * struct ifs_data - attributes related to intel IFS driver 192 + * @integrity_cap_bit: MSR_INTEGRITY_CAPS bit enumerating this test 193 + * @loaded_version: stores the currently loaded ifs image version. 194 + * @loaded: If a valid test binary has been loaded into the memory 195 + * @loading_error: Error occurred on another CPU while loading image 196 + * @valid_chunks: number of chunks which could be validated. 197 + * @status: it holds simple status pass/fail/untested 198 + * @scan_details: opaque scan status code from h/w 199 + */ 200 + struct ifs_data { 201 + int integrity_cap_bit; 202 + int loaded_version; 203 + bool loaded; 204 + bool loading_error; 205 + int valid_chunks; 206 + int status; 207 + u64 scan_details; 208 + }; 209 + 210 + struct ifs_work { 211 + struct work_struct w; 212 + struct device *dev; 213 + }; 214 + 215 + struct ifs_device { 216 + struct ifs_data data; 217 + struct miscdevice misc; 218 + }; 219 + 220 + static inline struct ifs_data *ifs_get_data(struct device *dev) 221 + { 222 + struct miscdevice *m = dev_get_drvdata(dev); 223 + struct ifs_device *d = container_of(m, struct ifs_device, misc); 224 + 225 + return &d->data; 226 + } 227 + 228 + void ifs_load_firmware(struct device *dev); 229 + int do_core_test(int cpu, struct device *dev); 230 + const struct attribute_group **ifs_get_groups(void); 231 + 232 + extern struct semaphore ifs_sem; 233 + 234 + #endif
+266
drivers/platform/x86/intel/ifs/load.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright(c) 2022 Intel Corporation. */ 3 + 4 + #include <linux/firmware.h> 5 + #include <asm/cpu.h> 6 + #include <linux/slab.h> 7 + #include <asm/microcode_intel.h> 8 + 9 + #include "ifs.h" 10 + 11 + struct ifs_header { 12 + u32 header_ver; 13 + u32 blob_revision; 14 + u32 date; 15 + u32 processor_sig; 16 + u32 check_sum; 17 + u32 loader_rev; 18 + u32 processor_flags; 19 + u32 metadata_size; 20 + u32 total_size; 21 + u32 fusa_info; 22 + u64 reserved; 23 + }; 24 + 25 + #define IFS_HEADER_SIZE (sizeof(struct ifs_header)) 26 + static struct ifs_header *ifs_header_ptr; /* pointer to the ifs image header */ 27 + static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */ 28 + static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */ 29 + static DECLARE_COMPLETION(ifs_done); 30 + 31 + static const char * const scan_hash_status[] = { 32 + [0] = "No error reported", 33 + [1] = "Attempt to copy scan hashes when copy already in progress", 34 + [2] = "Secure Memory not set up correctly", 35 + [3] = "FuSaInfo.ProgramID does not match or ff-mm-ss does not match", 36 + [4] = "Reserved", 37 + [5] = "Integrity check failed", 38 + [6] = "Scan reload or test is in progress" 39 + }; 40 + 41 + static const char * const scan_authentication_status[] = { 42 + [0] = "No error reported", 43 + [1] = "Attempt to authenticate a chunk which is already marked as authentic", 44 + [2] = "Chunk authentication error. The hash of chunk did not match expected value" 45 + }; 46 + 47 + /* 48 + * To copy scan hashes and authenticate test chunks, the initiating cpu must point 49 + * to the EDX:EAX to the test image in linear address. 50 + * Run wrmsr(MSR_COPY_SCAN_HASHES) for scan hash copy and run wrmsr(MSR_AUTHENTICATE_AND_COPY_CHUNK) 51 + * for scan hash copy and test chunk authentication. 52 + */ 53 + static void copy_hashes_authenticate_chunks(struct work_struct *work) 54 + { 55 + struct ifs_work *local_work = container_of(work, struct ifs_work, w); 56 + union ifs_scan_hashes_status hashes_status; 57 + union ifs_chunks_auth_status chunk_status; 58 + struct device *dev = local_work->dev; 59 + int i, num_chunks, chunk_size; 60 + struct ifs_data *ifsd; 61 + u64 linear_addr, base; 62 + u32 err_code; 63 + 64 + ifsd = ifs_get_data(dev); 65 + /* run scan hash copy */ 66 + wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr); 67 + rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data); 68 + 69 + /* enumerate the scan image information */ 70 + num_chunks = hashes_status.num_chunks; 71 + chunk_size = hashes_status.chunk_size * 1024; 72 + err_code = hashes_status.error_code; 73 + 74 + if (!hashes_status.valid) { 75 + ifsd->loading_error = true; 76 + if (err_code >= ARRAY_SIZE(scan_hash_status)) { 77 + dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code); 78 + goto done; 79 + } 80 + dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]); 81 + goto done; 82 + } 83 + 84 + /* base linear address to the scan data */ 85 + base = ifs_test_image_ptr; 86 + 87 + /* scan data authentication and copy chunks to secured memory */ 88 + for (i = 0; i < num_chunks; i++) { 89 + linear_addr = base + i * chunk_size; 90 + linear_addr |= i; 91 + 92 + wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, linear_addr); 93 + rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); 94 + 95 + ifsd->valid_chunks = chunk_status.valid_chunks; 96 + err_code = chunk_status.error_code; 97 + 98 + if (err_code) { 99 + ifsd->loading_error = true; 100 + if (err_code >= ARRAY_SIZE(scan_authentication_status)) { 101 + dev_err(dev, 102 + "invalid error code 0x%x for authentication\n", err_code); 103 + goto done; 104 + } 105 + dev_err(dev, "Chunk authentication error %s\n", 106 + scan_authentication_status[err_code]); 107 + goto done; 108 + } 109 + } 110 + done: 111 + complete(&ifs_done); 112 + } 113 + 114 + /* 115 + * IFS requires scan chunks authenticated per each socket in the platform. 116 + * Once the test chunk is authenticated, it is automatically copied to secured memory 117 + * and proceed the authentication for the next chunk. 118 + */ 119 + static int scan_chunks_sanity_check(struct device *dev) 120 + { 121 + int metadata_size, curr_pkg, cpu, ret = -ENOMEM; 122 + struct ifs_data *ifsd = ifs_get_data(dev); 123 + bool *package_authenticated; 124 + struct ifs_work local_work; 125 + char *test_ptr; 126 + 127 + package_authenticated = kcalloc(topology_max_packages(), sizeof(bool), GFP_KERNEL); 128 + if (!package_authenticated) 129 + return ret; 130 + 131 + metadata_size = ifs_header_ptr->metadata_size; 132 + 133 + /* Spec says that if the Meta Data Size = 0 then it should be treated as 2000 */ 134 + if (metadata_size == 0) 135 + metadata_size = 2000; 136 + 137 + /* Scan chunk start must be 256 byte aligned */ 138 + if ((metadata_size + IFS_HEADER_SIZE) % 256) { 139 + dev_err(dev, "Scan pattern offset within the binary is not 256 byte aligned\n"); 140 + return -EINVAL; 141 + } 142 + 143 + test_ptr = (char *)ifs_header_ptr + IFS_HEADER_SIZE + metadata_size; 144 + ifsd->loading_error = false; 145 + 146 + ifs_test_image_ptr = (u64)test_ptr; 147 + ifsd->loaded_version = ifs_header_ptr->blob_revision; 148 + 149 + /* copy the scan hash and authenticate per package */ 150 + cpus_read_lock(); 151 + for_each_online_cpu(cpu) { 152 + curr_pkg = topology_physical_package_id(cpu); 153 + if (package_authenticated[curr_pkg]) 154 + continue; 155 + reinit_completion(&ifs_done); 156 + local_work.dev = dev; 157 + INIT_WORK(&local_work.w, copy_hashes_authenticate_chunks); 158 + schedule_work_on(cpu, &local_work.w); 159 + wait_for_completion(&ifs_done); 160 + if (ifsd->loading_error) 161 + goto out; 162 + package_authenticated[curr_pkg] = 1; 163 + } 164 + ret = 0; 165 + out: 166 + cpus_read_unlock(); 167 + kfree(package_authenticated); 168 + 169 + return ret; 170 + } 171 + 172 + static int ifs_sanity_check(struct device *dev, 173 + const struct microcode_header_intel *mc_header) 174 + { 175 + unsigned long total_size, data_size; 176 + u32 sum, *mc; 177 + 178 + total_size = get_totalsize(mc_header); 179 + data_size = get_datasize(mc_header); 180 + 181 + if ((data_size + MC_HEADER_SIZE > total_size) || (total_size % sizeof(u32))) { 182 + dev_err(dev, "bad ifs data file size.\n"); 183 + return -EINVAL; 184 + } 185 + 186 + if (mc_header->ldrver != 1 || mc_header->hdrver != 1) { 187 + dev_err(dev, "invalid/unknown ifs update format.\n"); 188 + return -EINVAL; 189 + } 190 + 191 + mc = (u32 *)mc_header; 192 + sum = 0; 193 + for (int i = 0; i < total_size / sizeof(u32); i++) 194 + sum += mc[i]; 195 + 196 + if (sum) { 197 + dev_err(dev, "bad ifs data checksum, aborting.\n"); 198 + return -EINVAL; 199 + } 200 + 201 + return 0; 202 + } 203 + 204 + static bool find_ifs_matching_signature(struct device *dev, struct ucode_cpu_info *uci, 205 + const struct microcode_header_intel *shdr) 206 + { 207 + unsigned int mc_size; 208 + 209 + mc_size = get_totalsize(shdr); 210 + 211 + if (!mc_size || ifs_sanity_check(dev, shdr) < 0) { 212 + dev_err(dev, "ifs sanity check failure\n"); 213 + return false; 214 + } 215 + 216 + if (!intel_cpu_signatures_match(uci->cpu_sig.sig, uci->cpu_sig.pf, shdr->sig, shdr->pf)) { 217 + dev_err(dev, "ifs signature, pf not matching\n"); 218 + return false; 219 + } 220 + 221 + return true; 222 + } 223 + 224 + static bool ifs_image_sanity_check(struct device *dev, const struct microcode_header_intel *data) 225 + { 226 + struct ucode_cpu_info uci; 227 + 228 + intel_cpu_collect_info(&uci); 229 + 230 + return find_ifs_matching_signature(dev, &uci, data); 231 + } 232 + 233 + /* 234 + * Load ifs image. Before loading ifs module, the ifs image must be located 235 + * in /lib/firmware/intel/ifs and named as {family/model/stepping}.{testname}. 236 + */ 237 + void ifs_load_firmware(struct device *dev) 238 + { 239 + struct ifs_data *ifsd = ifs_get_data(dev); 240 + const struct firmware *fw; 241 + char scan_path[32]; 242 + int ret; 243 + 244 + snprintf(scan_path, sizeof(scan_path), "intel/ifs/%02x-%02x-%02x.scan", 245 + boot_cpu_data.x86, boot_cpu_data.x86_model, boot_cpu_data.x86_stepping); 246 + 247 + ret = request_firmware_direct(&fw, scan_path, dev); 248 + if (ret) { 249 + dev_err(dev, "ifs file %s load failed\n", scan_path); 250 + goto done; 251 + } 252 + 253 + if (!ifs_image_sanity_check(dev, (struct microcode_header_intel *)fw->data)) { 254 + dev_err(dev, "ifs header sanity check failed\n"); 255 + goto release; 256 + } 257 + 258 + ifs_header_ptr = (struct ifs_header *)fw->data; 259 + ifs_hash_ptr = (u64)(ifs_header_ptr + 1); 260 + 261 + ret = scan_chunks_sanity_check(dev); 262 + release: 263 + release_firmware(fw); 264 + done: 265 + ifsd->loaded = (ret == 0); 266 + }
+252
drivers/platform/x86/intel/ifs/runtest.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright(c) 2022 Intel Corporation. */ 3 + 4 + #include <linux/cpu.h> 5 + #include <linux/delay.h> 6 + #include <linux/fs.h> 7 + #include <linux/nmi.h> 8 + #include <linux/slab.h> 9 + #include <linux/stop_machine.h> 10 + 11 + #include "ifs.h" 12 + 13 + /* 14 + * Note all code and data in this file is protected by 15 + * ifs_sem. On HT systems all threads on a core will 16 + * execute together, but only the first thread on the 17 + * core will update results of the test. 18 + */ 19 + 20 + #define CREATE_TRACE_POINTS 21 + #include <trace/events/intel_ifs.h> 22 + 23 + /* Max retries on the same chunk */ 24 + #define MAX_IFS_RETRIES 5 25 + 26 + /* 27 + * Number of TSC cycles that a logical CPU will wait for the other 28 + * logical CPU on the core in the WRMSR(ACTIVATE_SCAN). 29 + */ 30 + #define IFS_THREAD_WAIT 100000 31 + 32 + enum ifs_status_err_code { 33 + IFS_NO_ERROR = 0, 34 + IFS_OTHER_THREAD_COULD_NOT_JOIN = 1, 35 + IFS_INTERRUPTED_BEFORE_RENDEZVOUS = 2, 36 + IFS_POWER_MGMT_INADEQUATE_FOR_SCAN = 3, 37 + IFS_INVALID_CHUNK_RANGE = 4, 38 + IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS = 5, 39 + IFS_CORE_NOT_CAPABLE_CURRENTLY = 6, 40 + IFS_UNASSIGNED_ERROR_CODE = 7, 41 + IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8, 42 + IFS_INTERRUPTED_DURING_EXECUTION = 9, 43 + }; 44 + 45 + static const char * const scan_test_status[] = { 46 + [IFS_NO_ERROR] = "SCAN no error", 47 + [IFS_OTHER_THREAD_COULD_NOT_JOIN] = "Other thread could not join.", 48 + [IFS_INTERRUPTED_BEFORE_RENDEZVOUS] = "Interrupt occurred prior to SCAN coordination.", 49 + [IFS_POWER_MGMT_INADEQUATE_FOR_SCAN] = 50 + "Core Abort SCAN Response due to power management condition.", 51 + [IFS_INVALID_CHUNK_RANGE] = "Non valid chunks in the range", 52 + [IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS] = "Mismatch in arguments between threads T0/T1.", 53 + [IFS_CORE_NOT_CAPABLE_CURRENTLY] = "Core not capable of performing SCAN currently", 54 + [IFS_UNASSIGNED_ERROR_CODE] = "Unassigned error code 0x7", 55 + [IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT] = 56 + "Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently", 57 + [IFS_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SCAN start", 58 + }; 59 + 60 + static void message_not_tested(struct device *dev, int cpu, union ifs_status status) 61 + { 62 + if (status.error_code < ARRAY_SIZE(scan_test_status)) { 63 + dev_info(dev, "CPU(s) %*pbl: SCAN operation did not start. %s\n", 64 + cpumask_pr_args(cpu_smt_mask(cpu)), 65 + scan_test_status[status.error_code]); 66 + } else if (status.error_code == IFS_SW_TIMEOUT) { 67 + dev_info(dev, "CPU(s) %*pbl: software timeout during scan\n", 68 + cpumask_pr_args(cpu_smt_mask(cpu))); 69 + } else if (status.error_code == IFS_SW_PARTIAL_COMPLETION) { 70 + dev_info(dev, "CPU(s) %*pbl: %s\n", 71 + cpumask_pr_args(cpu_smt_mask(cpu)), 72 + "Not all scan chunks were executed. Maximum forward progress retries exceeded"); 73 + } else { 74 + dev_info(dev, "CPU(s) %*pbl: SCAN unknown status %llx\n", 75 + cpumask_pr_args(cpu_smt_mask(cpu)), status.data); 76 + } 77 + } 78 + 79 + static void message_fail(struct device *dev, int cpu, union ifs_status status) 80 + { 81 + /* 82 + * control_error is set when the microcode runs into a problem 83 + * loading the image from the reserved BIOS memory, or it has 84 + * been corrupted. Reloading the image may fix this issue. 85 + */ 86 + if (status.control_error) { 87 + dev_err(dev, "CPU(s) %*pbl: could not execute from loaded scan image\n", 88 + cpumask_pr_args(cpu_smt_mask(cpu))); 89 + } 90 + 91 + /* 92 + * signature_error is set when the output from the scan chains does not 93 + * match the expected signature. This might be a transient problem (e.g. 94 + * due to a bit flip from an alpha particle or neutron). If the problem 95 + * repeats on a subsequent test, then it indicates an actual problem in 96 + * the core being tested. 97 + */ 98 + if (status.signature_error) { 99 + dev_err(dev, "CPU(s) %*pbl: test signature incorrect.\n", 100 + cpumask_pr_args(cpu_smt_mask(cpu))); 101 + } 102 + } 103 + 104 + static bool can_restart(union ifs_status status) 105 + { 106 + enum ifs_status_err_code err_code = status.error_code; 107 + 108 + /* Signature for chunk is bad, or scan test failed */ 109 + if (status.signature_error || status.control_error) 110 + return false; 111 + 112 + switch (err_code) { 113 + case IFS_NO_ERROR: 114 + case IFS_OTHER_THREAD_COULD_NOT_JOIN: 115 + case IFS_INTERRUPTED_BEFORE_RENDEZVOUS: 116 + case IFS_POWER_MGMT_INADEQUATE_FOR_SCAN: 117 + case IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT: 118 + case IFS_INTERRUPTED_DURING_EXECUTION: 119 + return true; 120 + case IFS_INVALID_CHUNK_RANGE: 121 + case IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS: 122 + case IFS_CORE_NOT_CAPABLE_CURRENTLY: 123 + case IFS_UNASSIGNED_ERROR_CODE: 124 + break; 125 + } 126 + return false; 127 + } 128 + 129 + /* 130 + * Execute the scan. Called "simultaneously" on all threads of a core 131 + * at high priority using the stop_cpus mechanism. 132 + */ 133 + static int doscan(void *data) 134 + { 135 + int cpu = smp_processor_id(); 136 + u64 *msrs = data; 137 + int first; 138 + 139 + /* Only the first logical CPU on a core reports result */ 140 + first = cpumask_first(cpu_smt_mask(cpu)); 141 + 142 + /* 143 + * This WRMSR will wait for other HT threads to also write 144 + * to this MSR (at most for activate.delay cycles). Then it 145 + * starts scan of each requested chunk. The core scan happens 146 + * during the "execution" of the WRMSR. This instruction can 147 + * take up to 200 milliseconds (in the case where all chunks 148 + * are processed in a single pass) before it retires. 149 + */ 150 + wrmsrl(MSR_ACTIVATE_SCAN, msrs[0]); 151 + 152 + if (cpu == first) { 153 + /* Pass back the result of the scan */ 154 + rdmsrl(MSR_SCAN_STATUS, msrs[1]); 155 + } 156 + 157 + return 0; 158 + } 159 + 160 + /* 161 + * Use stop_core_cpuslocked() to synchronize writing to MSR_ACTIVATE_SCAN 162 + * on all threads of the core to be tested. Loop if necessary to complete 163 + * run of all chunks. Include some defensive tests to make sure forward 164 + * progress is made, and that the whole test completes in a reasonable time. 165 + */ 166 + static void ifs_test_core(int cpu, struct device *dev) 167 + { 168 + union ifs_scan activate; 169 + union ifs_status status; 170 + unsigned long timeout; 171 + struct ifs_data *ifsd; 172 + u64 msrvals[2]; 173 + int retries; 174 + 175 + ifsd = ifs_get_data(dev); 176 + 177 + activate.rsvd = 0; 178 + activate.delay = IFS_THREAD_WAIT; 179 + activate.sigmce = 0; 180 + activate.start = 0; 181 + activate.stop = ifsd->valid_chunks - 1; 182 + 183 + timeout = jiffies + HZ / 2; 184 + retries = MAX_IFS_RETRIES; 185 + 186 + while (activate.start <= activate.stop) { 187 + if (time_after(jiffies, timeout)) { 188 + status.error_code = IFS_SW_TIMEOUT; 189 + break; 190 + } 191 + 192 + msrvals[0] = activate.data; 193 + stop_core_cpuslocked(cpu, doscan, msrvals); 194 + 195 + status.data = msrvals[1]; 196 + 197 + trace_ifs_status(cpu, activate, status); 198 + 199 + /* Some cases can be retried, give up for others */ 200 + if (!can_restart(status)) 201 + break; 202 + 203 + if (status.chunk_num == activate.start) { 204 + /* Check for forward progress */ 205 + if (--retries == 0) { 206 + if (status.error_code == IFS_NO_ERROR) 207 + status.error_code = IFS_SW_PARTIAL_COMPLETION; 208 + break; 209 + } 210 + } else { 211 + retries = MAX_IFS_RETRIES; 212 + activate.start = status.chunk_num; 213 + } 214 + } 215 + 216 + /* Update status for this core */ 217 + ifsd->scan_details = status.data; 218 + 219 + if (status.control_error || status.signature_error) { 220 + ifsd->status = SCAN_TEST_FAIL; 221 + message_fail(dev, cpu, status); 222 + } else if (status.error_code) { 223 + ifsd->status = SCAN_NOT_TESTED; 224 + message_not_tested(dev, cpu, status); 225 + } else { 226 + ifsd->status = SCAN_TEST_PASS; 227 + } 228 + } 229 + 230 + /* 231 + * Initiate per core test. It wakes up work queue threads on the target cpu and 232 + * its sibling cpu. Once all sibling threads wake up, the scan test gets executed and 233 + * wait for all sibling threads to finish the scan test. 234 + */ 235 + int do_core_test(int cpu, struct device *dev) 236 + { 237 + int ret = 0; 238 + 239 + /* Prevent CPUs from being taken offline during the scan test */ 240 + cpus_read_lock(); 241 + 242 + if (!cpu_online(cpu)) { 243 + dev_info(dev, "cannot test on the offline cpu %d\n", cpu); 244 + ret = -EINVAL; 245 + goto out; 246 + } 247 + 248 + ifs_test_core(cpu, dev); 249 + out: 250 + cpus_read_unlock(); 251 + return ret; 252 + }
+149
drivers/platform/x86/intel/ifs/sysfs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright(c) 2022 Intel Corporation. */ 3 + 4 + #include <linux/cpu.h> 5 + #include <linux/delay.h> 6 + #include <linux/fs.h> 7 + #include <linux/semaphore.h> 8 + #include <linux/slab.h> 9 + 10 + #include "ifs.h" 11 + 12 + /* 13 + * Protects against simultaneous tests on multiple cores, or 14 + * reloading can file while a test is in progress 15 + */ 16 + DEFINE_SEMAPHORE(ifs_sem); 17 + 18 + /* 19 + * The sysfs interface to check additional details of last test 20 + * cat /sys/devices/system/platform/ifs/details 21 + */ 22 + static ssize_t details_show(struct device *dev, 23 + struct device_attribute *attr, 24 + char *buf) 25 + { 26 + struct ifs_data *ifsd = ifs_get_data(dev); 27 + 28 + return sysfs_emit(buf, "%#llx\n", ifsd->scan_details); 29 + } 30 + 31 + static DEVICE_ATTR_RO(details); 32 + 33 + static const char * const status_msg[] = { 34 + [SCAN_NOT_TESTED] = "untested", 35 + [SCAN_TEST_PASS] = "pass", 36 + [SCAN_TEST_FAIL] = "fail" 37 + }; 38 + 39 + /* 40 + * The sysfs interface to check the test status: 41 + * To check the status of last test 42 + * cat /sys/devices/platform/ifs/status 43 + */ 44 + static ssize_t status_show(struct device *dev, 45 + struct device_attribute *attr, 46 + char *buf) 47 + { 48 + struct ifs_data *ifsd = ifs_get_data(dev); 49 + 50 + return sysfs_emit(buf, "%s\n", status_msg[ifsd->status]); 51 + } 52 + 53 + static DEVICE_ATTR_RO(status); 54 + 55 + /* 56 + * The sysfs interface for single core testing 57 + * To start test, for example, cpu5 58 + * echo 5 > /sys/devices/platform/ifs/run_test 59 + * To check the result: 60 + * cat /sys/devices/platform/ifs/result 61 + * The sibling core gets tested at the same time. 62 + */ 63 + static ssize_t run_test_store(struct device *dev, 64 + struct device_attribute *attr, 65 + const char *buf, size_t count) 66 + { 67 + struct ifs_data *ifsd = ifs_get_data(dev); 68 + unsigned int cpu; 69 + int rc; 70 + 71 + rc = kstrtouint(buf, 0, &cpu); 72 + if (rc < 0 || cpu >= nr_cpu_ids) 73 + return -EINVAL; 74 + 75 + if (down_interruptible(&ifs_sem)) 76 + return -EINTR; 77 + 78 + if (!ifsd->loaded) 79 + rc = -EPERM; 80 + else 81 + rc = do_core_test(cpu, dev); 82 + 83 + up(&ifs_sem); 84 + 85 + return rc ? rc : count; 86 + } 87 + 88 + static DEVICE_ATTR_WO(run_test); 89 + 90 + /* 91 + * Reload the IFS image. When user wants to install new IFS image 92 + */ 93 + static ssize_t reload_store(struct device *dev, 94 + struct device_attribute *attr, 95 + const char *buf, size_t count) 96 + { 97 + struct ifs_data *ifsd = ifs_get_data(dev); 98 + bool res; 99 + 100 + 101 + if (kstrtobool(buf, &res)) 102 + return -EINVAL; 103 + if (!res) 104 + return count; 105 + 106 + if (down_interruptible(&ifs_sem)) 107 + return -EINTR; 108 + 109 + ifs_load_firmware(dev); 110 + 111 + up(&ifs_sem); 112 + 113 + return ifsd->loaded ? count : -ENODEV; 114 + } 115 + 116 + static DEVICE_ATTR_WO(reload); 117 + 118 + /* 119 + * Display currently loaded IFS image version. 120 + */ 121 + static ssize_t image_version_show(struct device *dev, 122 + struct device_attribute *attr, char *buf) 123 + { 124 + struct ifs_data *ifsd = ifs_get_data(dev); 125 + 126 + if (!ifsd->loaded) 127 + return sysfs_emit(buf, "%s\n", "none"); 128 + else 129 + return sysfs_emit(buf, "%#x\n", ifsd->loaded_version); 130 + } 131 + 132 + static DEVICE_ATTR_RO(image_version); 133 + 134 + /* global scan sysfs attributes */ 135 + static struct attribute *plat_ifs_attrs[] = { 136 + &dev_attr_details.attr, 137 + &dev_attr_status.attr, 138 + &dev_attr_run_test.attr, 139 + &dev_attr_reload.attr, 140 + &dev_attr_image_version.attr, 141 + NULL 142 + }; 143 + 144 + ATTRIBUTE_GROUPS(plat_ifs); 145 + 146 + const struct attribute_group **ifs_get_groups(void) 147 + { 148 + return plat_ifs_groups; 149 + }
+1 -1
drivers/platform/x86/intel/pmc/core.c
··· 999 999 struct attribute *attr, 1000 1000 int idx) 1001 1001 { 1002 - struct device *dev = container_of(kobj, struct device, kobj); 1002 + struct device *dev = kobj_to_dev(kobj); 1003 1003 struct pmc_dev *pmcdev = dev_get_drvdata(dev); 1004 1004 const struct pmc_reg_map *map = pmcdev->map; 1005 1005 u32 reg;
-13
drivers/platform/x86/pmc_atom.c
··· 221 221 *value = pmc_reg_read(pmc, offset); 222 222 return 0; 223 223 } 224 - EXPORT_SYMBOL_GPL(pmc_atom_read); 225 - 226 - int pmc_atom_write(int offset, u32 value) 227 - { 228 - struct pmc_dev *pmc = &pmc_device; 229 - 230 - if (!pmc->init) 231 - return -ENODEV; 232 - 233 - pmc_reg_write(pmc, offset, value); 234 - return 0; 235 - } 236 - EXPORT_SYMBOL_GPL(pmc_atom_write); 237 224 238 225 static void pmc_power_off(void) 239 226 {
+1 -1
drivers/platform/x86/samsung-laptop.c
··· 1208 1208 static umode_t samsung_sysfs_is_visible(struct kobject *kobj, 1209 1209 struct attribute *attr, int idx) 1210 1210 { 1211 - struct device *dev = container_of(kobj, struct device, kobj); 1211 + struct device *dev = kobj_to_dev(kobj); 1212 1212 struct samsung_laptop *samsung = dev_get_drvdata(dev); 1213 1213 bool ok = true; 1214 1214
+1 -1
drivers/platform/x86/toshiba_acpi.c
··· 2353 2353 static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2354 2354 struct attribute *attr, int idx) 2355 2355 { 2356 - struct device *dev = container_of(kobj, struct device, kobj); 2356 + struct device *dev = kobj_to_dev(kobj); 2357 2357 struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2358 2358 bool exists = true; 2359 2359
+189
drivers/platform/x86/winmate-fm07-keys.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // Driver for the Winmate FM07 front-panel keys 4 + // 5 + // Author: Daniel Beer <daniel.beer@tirotech.co.nz> 6 + 7 + #include <linux/init.h> 8 + #include <linux/module.h> 9 + #include <linux/input.h> 10 + #include <linux/ioport.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/dmi.h> 13 + #include <linux/io.h> 14 + 15 + #define DRV_NAME "winmate-fm07keys" 16 + 17 + #define PORT_CMD 0x6c 18 + #define PORT_DATA 0x68 19 + 20 + #define EC_ADDR_KEYS 0x3b 21 + #define EC_CMD_READ 0x80 22 + 23 + #define BASE_KEY KEY_F13 24 + #define NUM_KEYS 5 25 + 26 + /* Typically we're done in fewer than 10 iterations */ 27 + #define LOOP_TIMEOUT 1000 28 + 29 + static void fm07keys_poll(struct input_dev *input) 30 + { 31 + uint8_t k; 32 + int i; 33 + 34 + /* Flush output buffer */ 35 + i = 0; 36 + while (inb(PORT_CMD) & 0x01) { 37 + if (++i >= LOOP_TIMEOUT) 38 + goto timeout; 39 + inb(PORT_DATA); 40 + } 41 + 42 + /* Send request and wait for write completion */ 43 + outb(EC_CMD_READ, PORT_CMD); 44 + i = 0; 45 + while (inb(PORT_CMD) & 0x02) 46 + if (++i >= LOOP_TIMEOUT) 47 + goto timeout; 48 + 49 + outb(EC_ADDR_KEYS, PORT_DATA); 50 + i = 0; 51 + while (inb(PORT_CMD) & 0x02) 52 + if (++i >= LOOP_TIMEOUT) 53 + goto timeout; 54 + 55 + /* Wait for data ready */ 56 + i = 0; 57 + while (!(inb(PORT_CMD) & 0x01)) 58 + if (++i >= LOOP_TIMEOUT) 59 + goto timeout; 60 + k = inb(PORT_DATA); 61 + 62 + /* Notify of new key states */ 63 + for (i = 0; i < NUM_KEYS; i++) { 64 + input_report_key(input, BASE_KEY + i, (~k) & 1); 65 + k >>= 1; 66 + } 67 + 68 + input_sync(input); 69 + return; 70 + 71 + timeout: 72 + dev_warn_ratelimited(&input->dev, "timeout polling IO memory\n"); 73 + } 74 + 75 + static int fm07keys_probe(struct platform_device *pdev) 76 + { 77 + struct device *dev = &pdev->dev; 78 + struct input_dev *input; 79 + int ret; 80 + int i; 81 + 82 + input = devm_input_allocate_device(dev); 83 + if (!input) { 84 + dev_err(dev, "no memory for input device\n"); 85 + return -ENOMEM; 86 + } 87 + 88 + if (!devm_request_region(dev, PORT_CMD, 1, "Winmate FM07 EC")) 89 + return -EBUSY; 90 + if (!devm_request_region(dev, PORT_DATA, 1, "Winmate FM07 EC")) 91 + return -EBUSY; 92 + 93 + input->name = "Winmate FM07 front-panel keys"; 94 + input->phys = DRV_NAME "/input0"; 95 + 96 + input->id.bustype = BUS_HOST; 97 + input->id.vendor = 0x0001; 98 + input->id.product = 0x0001; 99 + input->id.version = 0x0100; 100 + 101 + __set_bit(EV_KEY, input->evbit); 102 + 103 + for (i = 0; i < NUM_KEYS; i++) 104 + __set_bit(BASE_KEY + i, input->keybit); 105 + 106 + ret = input_setup_polling(input, fm07keys_poll); 107 + if (ret) { 108 + dev_err(dev, "unable to set up polling, err=%d\n", ret); 109 + return ret; 110 + } 111 + 112 + /* These are silicone buttons. They can't be pressed in rapid 113 + * succession too quickly, and 50 Hz seems to be an adequate 114 + * sampling rate without missing any events when tested. 115 + */ 116 + input_set_poll_interval(input, 20); 117 + 118 + ret = input_register_device(input); 119 + if (ret) { 120 + dev_err(dev, "unable to register polled device, err=%d\n", 121 + ret); 122 + return ret; 123 + } 124 + 125 + input_sync(input); 126 + return 0; 127 + } 128 + 129 + static struct platform_driver fm07keys_driver = { 130 + .probe = fm07keys_probe, 131 + .driver = { 132 + .name = DRV_NAME 133 + }, 134 + }; 135 + 136 + static struct platform_device *dev; 137 + 138 + static const struct dmi_system_id fm07keys_dmi_table[] __initconst = { 139 + { 140 + /* FM07 and FM07P */ 141 + .matches = { 142 + DMI_MATCH(DMI_SYS_VENDOR, "Winmate Inc."), 143 + DMI_MATCH(DMI_PRODUCT_NAME, "IP30"), 144 + }, 145 + }, 146 + { } 147 + }; 148 + 149 + MODULE_DEVICE_TABLE(dmi, fm07keys_dmi_table); 150 + 151 + static int __init fm07keys_init(void) 152 + { 153 + int ret; 154 + 155 + if (!dmi_check_system(fm07keys_dmi_table)) 156 + return -ENODEV; 157 + 158 + ret = platform_driver_register(&fm07keys_driver); 159 + if (ret) { 160 + pr_err("fm07keys: failed to register driver, err=%d\n", ret); 161 + return ret; 162 + } 163 + 164 + dev = platform_device_register_simple(DRV_NAME, -1, NULL, 0); 165 + if (IS_ERR(dev)) { 166 + ret = PTR_ERR(dev); 167 + pr_err("fm07keys: failed to allocate device, err = %d\n", ret); 168 + goto fail_register; 169 + } 170 + 171 + return 0; 172 + 173 + fail_register: 174 + platform_driver_unregister(&fm07keys_driver); 175 + return ret; 176 + } 177 + 178 + static void __exit fm07keys_exit(void) 179 + { 180 + platform_driver_unregister(&fm07keys_driver); 181 + platform_device_unregister(dev); 182 + } 183 + 184 + module_init(fm07keys_init); 185 + module_exit(fm07keys_exit); 186 + 187 + MODULE_AUTHOR("Daniel Beer <daniel.beer@tirotech.co.nz>"); 188 + MODULE_DESCRIPTION("Winmate FM07 front-panel keys driver"); 189 + MODULE_LICENSE("GPL");
+6 -7
drivers/platform/x86/wmi.c
··· 1308 1308 static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, 1309 1309 void *context) 1310 1310 { 1311 - struct wmi_block *wblock; 1312 - bool found_it = false; 1311 + struct wmi_block *wblock = NULL, *iter; 1313 1312 1314 - list_for_each_entry(wblock, &wmi_block_list, list) { 1315 - struct guid_block *block = &wblock->gblock; 1313 + list_for_each_entry(iter, &wmi_block_list, list) { 1314 + struct guid_block *block = &iter->gblock; 1316 1315 1317 - if (wblock->acpi_device->handle == handle && 1316 + if (iter->acpi_device->handle == handle && 1318 1317 (block->flags & ACPI_WMI_EVENT) && 1319 1318 (block->notify_id == event)) { 1320 - found_it = true; 1319 + wblock = iter; 1321 1320 break; 1322 1321 } 1323 1322 } 1324 1323 1325 - if (!found_it) 1324 + if (!wblock) 1326 1325 return; 1327 1326 1328 1327 /* If a driver is bound, then notify the driver. */
+4
include/linux/platform_data/mlxreg.h
··· 216 216 * @mask_low: low aggregation interrupt common mask; 217 217 * @deferred_nr: I2C adapter number must be exist prior probing execution; 218 218 * @shift_nr: I2C adapter numbers must be incremented by this value; 219 + * @handle: handle to be passed by callback; 220 + * @completion_notify: callback to notify when platform driver probing is done; 219 221 */ 220 222 struct mlxreg_core_hotplug_platform_data { 221 223 struct mlxreg_core_item *items; ··· 230 228 u32 mask_low; 231 229 int deferred_nr; 232 230 int shift_nr; 231 + void *handle; 232 + int (*completion_notify)(void *handle, int id); 233 233 }; 234 234 235 235 #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
-1
include/linux/platform_data/x86/pmc_atom.h
··· 144 144 #define SLEEP_ENABLE 0x2000 145 145 146 146 extern int pmc_atom_read(int offset, u32 *value); 147 - extern int pmc_atom_write(int offset, u32 value); 148 147 149 148 #endif /* PMC_ATOM_H */
+16
include/linux/stop_machine.h
··· 124 124 */ 125 125 int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); 126 126 127 + /** 128 + * stop_core_cpuslocked: - stop all threads on just one core 129 + * @cpu: any cpu in the targeted core 130 + * @fn: the function to run 131 + * @data: the data ptr for @fn() 132 + * 133 + * Same as above, but instead of every CPU, only the logical CPUs of a 134 + * single core are affected. 135 + * 136 + * Context: Must be called from within a cpus_read_lock() protected region. 137 + * 138 + * Return: 0 if all executions of @fn returned 0, any non zero return 139 + * value if any returned non zero. 140 + */ 141 + int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data); 142 + 127 143 int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, 128 144 const struct cpumask *cpus); 129 145 #else /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
+41
include/trace/events/intel_ifs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #undef TRACE_SYSTEM 3 + #define TRACE_SYSTEM intel_ifs 4 + 5 + #if !defined(_TRACE_IFS_H) || defined(TRACE_HEADER_MULTI_READ) 6 + #define _TRACE_IFS_H 7 + 8 + #include <linux/ktime.h> 9 + #include <linux/tracepoint.h> 10 + 11 + TRACE_EVENT(ifs_status, 12 + 13 + TP_PROTO(int cpu, union ifs_scan activate, union ifs_status status), 14 + 15 + TP_ARGS(cpu, activate, status), 16 + 17 + TP_STRUCT__entry( 18 + __field( u64, status ) 19 + __field( int, cpu ) 20 + __field( u8, start ) 21 + __field( u8, stop ) 22 + ), 23 + 24 + TP_fast_assign( 25 + __entry->cpu = cpu; 26 + __entry->start = activate.start; 27 + __entry->stop = activate.stop; 28 + __entry->status = status.data; 29 + ), 30 + 31 + TP_printk("cpu: %d, start: %.2x, stop: %.2x, status: %llx", 32 + __entry->cpu, 33 + __entry->start, 34 + __entry->stop, 35 + __entry->status) 36 + ); 37 + 38 + #endif /* _TRACE_IFS_H */ 39 + 40 + /* This part must be outside protection */ 41 + #include <trace/define_trace.h>
+21
kernel/stop_machine.c
··· 633 633 } 634 634 EXPORT_SYMBOL_GPL(stop_machine); 635 635 636 + #ifdef CONFIG_SCHED_SMT 637 + int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data) 638 + { 639 + const struct cpumask *smt_mask = cpu_smt_mask(cpu); 640 + 641 + struct multi_stop_data msdata = { 642 + .fn = fn, 643 + .data = data, 644 + .num_threads = cpumask_weight(smt_mask), 645 + .active_cpus = smt_mask, 646 + }; 647 + 648 + lockdep_assert_cpus_held(); 649 + 650 + /* Set the initial state and stop all online cpus. */ 651 + set_state(&msdata, MULTI_STOP_PREPARE); 652 + return stop_cpus(smt_mask, multi_cpu_stop, &msdata); 653 + } 654 + EXPORT_SYMBOL_GPL(stop_core_cpuslocked); 655 + #endif 656 + 636 657 /** 637 658 * stop_machine_from_inactive_cpu - stop_machine() from inactive CPU 638 659 * @fn: the function to run
+1 -1
tools/power/x86/intel-speed-select/hfi-events.c
··· 190 190 struct genlmsghdr *genlhdr = genlmsg_hdr(nlh); 191 191 struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1]; 192 192 int ret; 193 - struct perf_cap perf_cap; 193 + struct perf_cap perf_cap = {0}; 194 194 195 195 ret = genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL); 196 196
+6
tools/power/x86/intel-speed-select/isst-config.c
··· 1892 1892 int ret; 1893 1893 int status = *(int *)arg4; 1894 1894 1895 + if (status && no_turbo()) { 1896 + isst_display_error_info_message(1, "Turbo mode is disabled", 0, 0); 1897 + ret = -1; 1898 + goto disp_results; 1899 + } 1900 + 1895 1901 ret = isst_get_ctdp_levels(cpu, &pkg_dev); 1896 1902 if (ret) { 1897 1903 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);