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

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

Pull x86 platform driver updates from Hans de Goede:

- Microsoft Surface:
- SSAM hot unplug support
- Surface Pro 8 keyboard cover support
- Tablet mode switch support for Surface Pro 8 and Surface Laptop
Studio

- thinkpad_acpi:
- AMD Automatice Mode Transitions (AMT) support

- Mellanox:
- Vulcan chassis COMe NVSwitch management support
- XH3000 support

- New generic/shared Intel P2SB (Primary to Sideband) support

- Lots of small cleanups

- Various small bugfixes

- Various new hardware ids / quirks additions

* tag 'platform-drivers-x86-v6.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (105 commits)
platform/x86/intel/vsec: Fix wrong type for local status variables
platform/x86: p2sb: Move out of X86_PLATFORM_DEVICES dependency
platform/x86: pmc_atom: Fix comment typo
platform/surface: gpe: Add support for 13" Intel version of Surface Laptop 4
platform/olpc: Fix uninitialized data in debugfs write
platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity
platform/x86: pmc_atom: Match all Lex BayTrail boards with critclk_systems DMI table
platform/x86: sony-laptop: Remove useless comparisons in sony_pic_read_possible_resource()
tools/power/x86/intel-speed-select: Remove unneeded semicolon
tools/power/x86/intel-speed-select: Fix off by one check
platform/surface: tabletsw: Fix __le32 integer access
Documentation/ABI: Add new attributes for mlxreg-io sysfs interfaces
Documentation/ABI: mlxreg-io: Fix contact info
platform/mellanox: mlxreg-io: Add locking for io operations
platform/x86: mlx-platform: Add COME board revision register
platform/x86: mlx-platform: Add support for new system XH3000
platform/x86: mlx-platform: Introduce support for COMe NVSwitch management module for Vulcan chassis
platform/x86: mlx-platform: Add support for systems equipped with two ASICs
platform/x86: mlx-platform: Add cosmetic changes for alignment
platform/x86: mlx-platform: Make activation of some drivers conditional
...

+3267 -1032
+60 -21
Documentation/ABI/stable/sysfs-driver-mlxreg-io
··· 1 1 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_health 2 2 Date: June 2018 3 3 KernelVersion: 4.19 4 - Contact: Vadim Pasternak <vadimpmellanox.com> 4 + Contact: Vadim Pasternak <vadimp@nvidia.com> 5 5 Description: This file shows ASIC health status. The possible values are: 6 6 0 - health failed, 2 - health OK, 3 - ASIC in booting state. 7 7 ··· 11 11 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld2_version 12 12 Date: June 2018 13 13 KernelVersion: 4.19 14 - Contact: Vadim Pasternak <vadimpmellanox.com> 14 + Contact: Vadim Pasternak <vadimp@nvidia.com> 15 15 Description: These files show with which CPLD versions have been burned 16 16 on carrier and switch boards. 17 17 ··· 20 20 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/fan_dir 21 21 Date: December 2018 22 22 KernelVersion: 5.0 23 - Contact: Vadim Pasternak <vadimpmellanox.com> 23 + Contact: Vadim Pasternak <vadimp@nvidia.com> 24 24 Description: This file shows the system fans direction: 25 25 forward direction - relevant bit is set 0; 26 26 reversed direction - relevant bit is set 1. ··· 30 30 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld3_version 31 31 Date: November 2018 32 32 KernelVersion: 5.0 33 - Contact: Vadim Pasternak <vadimpmellanox.com> 33 + Contact: Vadim Pasternak <vadimp@nvidia.com> 34 34 Description: These files show with which CPLD versions have been burned 35 35 on LED or Gearbox board. 36 36 ··· 39 39 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable 40 40 Date: November 2018 41 41 KernelVersion: 5.0 42 - Contact: Vadim Pasternak <vadimpmellanox.com> 42 + Contact: Vadim Pasternak <vadimp@nvidia.com> 43 43 Description: These files enable and disable the access to the JTAG domain. 44 44 By default access to the JTAG domain is disabled. 45 45 ··· 48 48 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/select_iio 49 49 Date: June 2018 50 50 KernelVersion: 4.19 51 - Contact: Vadim Pasternak <vadimpmellanox.com> 51 + Contact: Vadim Pasternak <vadimp@nvidia.com> 52 52 Description: This file allows iio devices selection. 53 53 54 54 Attribute select_iio can be written with 0 or with 1. It ··· 62 62 /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pwr_down 63 63 Date: June 2018 64 64 KernelVersion: 4.19 65 - Contact: Vadim Pasternak <vadimpmellanox.com> 65 + Contact: Vadim Pasternak <vadimp@nvidia.com> 66 66 Description: These files allow asserting system power cycling, switching 67 67 power supply units on and off and system's main power domain 68 68 shutdown. ··· 89 89 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sw_reset 90 90 Date: June 2018 91 91 KernelVersion: 4.19 92 - Contact: Vadim Pasternak <vadimpmellanox.com> 92 + Contact: Vadim Pasternak <vadimp@nvidia.com> 93 93 Description: These files show the system reset cause, as following: power 94 94 auxiliary outage or power refresh, ASIC thermal shutdown, halt, 95 95 hotswap, watchdog, firmware reset, long press power button, ··· 106 106 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_voltmon_upgrade_fail 107 107 Date: November 2018 108 108 KernelVersion: 5.0 109 - Contact: Vadim Pasternak <vadimpmellanox.com> 109 + Contact: Vadim Pasternak <vadimp@nvidia.com> 110 110 Description: These files show the system reset cause, as following: ComEx 111 111 power fail, reset from ComEx, system platform reset, reset 112 112 due to voltage monitor devices upgrade failure, ··· 119 119 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld4_version 120 120 Date: November 2018 121 121 KernelVersion: 5.0 122 - Contact: Vadim Pasternak <vadimpmellanox.com> 122 + Contact: Vadim Pasternak <vadimp@nvidia.com> 123 123 Description: These files show with which CPLD versions have been burned 124 124 on LED board. 125 125 ··· 133 133 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_swb_wd 134 134 Date: June 2019 135 135 KernelVersion: 5.3 136 - Contact: Vadim Pasternak <vadimpmellanox.com> 136 + Contact: Vadim Pasternak <vadimp@nvidia.com> 137 137 Description: These files show the system reset cause, as following: 138 138 COMEX thermal shutdown; wathchdog power off or reset was derived 139 139 by one of the next components: COMEX, switch board or by Small Form ··· 148 148 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/config2 149 149 Date: January 2020 150 150 KernelVersion: 5.6 151 - Contact: Vadim Pasternak <vadimpmellanox.com> 151 + Contact: Vadim Pasternak <vadimp@nvidia.com> 152 152 Description: These files show system static topology identification 153 153 like system's static I2C topology, number and type of FPGA 154 154 devices within the system and so on. ··· 161 161 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sw_pwr_off 162 162 Date: January 2020 163 163 KernelVersion: 5.6 164 - Contact: Vadim Pasternak <vadimpmellanox.com> 164 + Contact: Vadim Pasternak <vadimp@nvidia.com> 165 165 Description: These files show the system reset causes, as following: reset 166 166 due to AC power failure, reset invoked from software by 167 167 assertion reset signal through CPLD. reset caused by signal ··· 173 173 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pcie_asic_reset_dis 174 174 Date: January 2020 175 175 KernelVersion: 5.6 176 - Contact: Vadim Pasternak <vadimpmellanox.com> 176 + Contact: Vadim Pasternak <vadimp@nvidia.com> 177 177 Description: This file allows to retain ASIC up during PCIe root complex 178 178 reset, when attribute is set 1. 179 179 ··· 182 182 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/vpd_wp 183 183 Date: January 2020 184 184 KernelVersion: 5.6 185 - Contact: Vadim Pasternak <vadimpmellanox.com> 185 + Contact: Vadim Pasternak <vadimp@nvidia.com> 186 186 Description: This file allows to overwrite system VPD hardware write 187 187 protection when attribute is set 1. 188 188 ··· 191 191 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/voltreg_update_status 192 192 Date: January 2020 193 193 KernelVersion: 5.6 194 - Contact: Vadim Pasternak <vadimpmellanox.com> 194 + Contact: Vadim Pasternak <vadimp@nvidia.com> 195 195 Description: This file exposes the configuration update status of burnable 196 196 voltage regulator devices. The status values are as following: 197 197 0 - OK; 1 - CRC failure; 2 = I2C failure; 3 - in progress. ··· 201 201 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/ufm_version 202 202 Date: January 2020 203 203 KernelVersion: 5.6 204 - Contact: Vadim Pasternak <vadimpmellanox.com> 204 + Contact: Vadim Pasternak <vadimp@nvidia.com> 205 205 Description: This file exposes the firmware version of burnable voltage 206 206 regulator devices. 207 207 ··· 217 217 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld4_version_min 218 218 Date: July 2020 219 219 KernelVersion: 5.9 220 - Contact: Vadim Pasternak <vadimpmellanox.com> 220 + Contact: Vadim Pasternak <vadimp@nvidia.com> 221 221 Description: These files show with which CPLD part numbers and minor 222 222 versions have been burned CPLD devices equipped on a 223 223 system. ··· 471 471 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/phy_reset 472 472 Date: May 2022 473 473 KernelVersion: 5.19 474 - Contact: Vadim Pasternak <vadimpmellanox.com> 474 + Contact: Vadim Pasternak <vadimp@nvidia.com> 475 475 Description: This file allows to reset PHY 88E1548 when attribute is set 0 476 476 due to some abnormal PHY behavior. 477 477 Expected behavior: ··· 483 483 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/mac_reset 484 484 Date: May 2022 485 485 KernelVersion: 5.19 486 - Contact: Vadim Pasternak <vadimpmellanox.com> 486 + Contact: Vadim Pasternak <vadimp@nvidia.com> 487 487 Description: This file allows to reset ASIC MT52132 when attribute is set 0 488 488 due to some abnormal ASIC behavior. 489 489 Expected behavior: ··· 495 495 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/qsfp_pwr_good 496 496 Date: May 2022 497 497 KernelVersion: 5.19 498 - Contact: Vadim Pasternak <vadimpmellanox.com> 498 + Contact: Vadim Pasternak <vadimp@nvidia.com> 499 499 Description: This file shows QSFP ports power status. The value is set to 0 500 500 when one of any QSFP ports is plugged. The value is set to 1 when 501 501 there are no any QSFP ports are plugged. ··· 503 503 0 - Power good, 1 - Not power good. 504 504 505 505 The files are read only. 506 + 507 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic2_health 508 + Date: July 2022 509 + KernelVersion: 5.20 510 + Contact: Vadim Pasternak <vadimp@nvidia.com> 511 + Description: This file shows 2-nd ASIC health status. The possible values are: 512 + 0 - health failed, 2 - health OK, 3 - ASIC in booting state. 513 + 514 + The file is read only. 515 + 516 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_reset 517 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic2_reset 518 + Date: July 2022 519 + KernelVersion: 5.20 520 + Contact: Vadim Pasternak <vadimp@nvidia.com> 521 + Description: These files allow to each of ASICs by writing 1. 522 + 523 + The files are write only. 524 + 525 + 526 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/comm_chnl_ready 527 + Date: July 2022 528 + KernelVersion: 5.20 529 + Contact: Vadim Pasternak <vadimp@nvidia.com> 530 + Description: This file is used to indicate remote end (for example BMC) that system 531 + host CPU is ready for sending telemetry data to remote end. 532 + For indication the file should be written 1. 533 + 534 + The file is write only. 535 + 536 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/config3 537 + Date: January 2020 538 + KernelVersion: 5.6 539 + Contact: Vadim Pasternak <vadimp@nvidia.com> 540 + Description: The file indicates COME module hardware configuration. 541 + The value is pushed by hardware through GPIO pins. 542 + The purpose is to expose some minor BOM changes for the same system SKU. 543 + 544 + The file is read only.
+57
Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw
··· 1 + What: /sys/bus/surface_aggregator/devices/01:0e:01:00:01/state 2 + Date: July 2022 3 + KernelVersion: 5.20 4 + Contact: Maximilian Luz <luzmaximilian@gmail.com> 5 + Description: 6 + This attribute returns a string with the current type-cover 7 + or device posture, as indicated by the embedded controller. 8 + Currently returned posture states are: 9 + 10 + - "disconnected": The type-cover has been disconnected. 11 + 12 + - "closed": The type-cover has been folded closed and lies on 13 + top of the display. 14 + 15 + - "laptop": The type-cover is open and in laptop-mode, i.e., 16 + ready for normal use. 17 + 18 + - "folded-canvas": The type-cover has been folded back 19 + part-ways, but does not lie flush with the back side of the 20 + device. In general, this means that the kick-stand is used 21 + and extended atop of the cover. 22 + 23 + - "folded-back": The type cover has been fully folded back and 24 + lies flush with the back side of the device. 25 + 26 + - "<unknown>": The current state is unknown to the driver, for 27 + example due to newer as-of-yet unsupported hardware. 28 + 29 + New states may be introduced with new hardware. Users therefore 30 + must not rely on this list of states being exhaustive and 31 + gracefully handle unknown states. 32 + 33 + What: /sys/bus/surface_aggregator/devices/01:26:01:00:01/state 34 + Date: July 2022 35 + KernelVersion: 5.20 36 + Contact: Maximilian Luz <luzmaximilian@gmail.com> 37 + Description: 38 + This attribute returns a string with the current device posture, as indicated by the embedded controller. Currently 39 + returned posture states are: 40 + 41 + - "closed": The lid of the device is closed. 42 + 43 + - "laptop": The lid of the device is opened and the device 44 + operates as a normal laptop. 45 + 46 + - "slate": The screen covers the keyboard or has been flipped 47 + back and the device operates mainly based on touch input. 48 + 49 + - "tablet": The device operates as tablet and exclusively 50 + relies on touch input (or external peripherals). 51 + 52 + - "<unknown>": The current state is unknown to the driver, for 53 + example due to newer as-of-yet unsupported hardware. 54 + 55 + New states may be introduced with new hardware. Users therefore 56 + must not rely on this list of states being exhaustive and 57 + gracefully handle unknown states.
+5 -1
Documentation/driver-api/surface_aggregator/client.rst
··· 17 17 .. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE` 18 18 .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register` 19 19 .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister` 20 + .. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register` 21 + .. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister` 20 22 .. |ssam_request_sync| replace:: :c:func:`ssam_request_sync` 21 23 .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>` 22 24 ··· 314 312 To receive events from the SAM EC, an event notifier must be registered for 315 313 the desired event via |ssam_notifier_register|. The notifier must be 316 314 unregistered via |ssam_notifier_unregister| once it is not required any 317 - more. 315 + more. For |ssam_device| type clients, the |ssam_device_notifier_register| and 316 + |ssam_device_notifier_unregister| wrappers should be preferred as they properly 317 + handle hot-removal of client devices. 318 318 319 319 Event notifiers are registered by providing (at minimum) a callback to call 320 320 in case an event has been received, the registry specifying how the event
+14 -2
MAINTAINERS
··· 1007 1007 M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 1008 1008 L: platform-driver-x86@vger.kernel.org 1009 1009 S: Maintained 1010 - F: drivers/platform/x86/amd-pmc.* 1010 + F: drivers/platform/x86/amd/pmc.c 1011 1011 1012 1012 AMD HSMP DRIVER 1013 1013 M: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com> ··· 1017 1017 F: Documentation/x86/amd_hsmp.rst 1018 1018 F: arch/x86/include/asm/amd_hsmp.h 1019 1019 F: arch/x86/include/uapi/asm/amd_hsmp.h 1020 - F: drivers/platform/x86/amd_hsmp.c 1020 + F: drivers/platform/x86/amd/hsmp.c 1021 1021 1022 1022 AMD POWERPLAY AND SWSMU 1023 1023 M: Evan Quan <evan.quan@amd.com> ··· 13467 13467 F: include/linux/cciss*.h 13468 13468 F: include/uapi/linux/cciss*.h 13469 13469 13470 + MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH 13471 + M: Maximilian Luz <luzmaximilian@gmail.com> 13472 + L: platform-driver-x86@vger.kernel.org 13473 + S: Maintained 13474 + F: drivers/platform/surface/surface_aggregator_tabletsw.c 13475 + 13470 13476 MICROSOFT SURFACE BATTERY AND AC DRIVERS 13471 13477 M: Maximilian Luz <luzmaximilian@gmail.com> 13472 13478 L: linux-pm@vger.kernel.org ··· 13543 13537 F: include/linux/surface_acpi_notify.h 13544 13538 F: include/linux/surface_aggregator/ 13545 13539 F: include/uapi/linux/surface_aggregator/ 13540 + 13541 + MICROSOFT SURFACE SYSTEM AGGREGATOR HUB DRIVER 13542 + M: Maximilian Luz <luzmaximilian@gmail.com> 13543 + L: platform-driver-x86@vger.kernel.org 13544 + S: Maintained 13545 + F: drivers/platform/surface/surface_aggregator_hub.c 13546 13546 13547 13547 MICROTEK X6 SCANNER 13548 13548 M: Oliver Neukum <oliver@neukum.org>
+1 -3
drivers/clk/x86/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 - obj-$(CONFIG_PMC_ATOM) += clk-pmc-atom.o 3 2 obj-$(CONFIG_X86_AMD_PLATFORM_DEVICE) += clk-fch.o 4 - clk-x86-lpss-y := clk-lpss-atom.o 5 - obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o 3 + obj-$(CONFIG_X86_INTEL_LPSS) += clk-lpss-atom.o clk-pmc-atom.o 6 4 obj-$(CONFIG_CLK_LGM_CGU) += clk-cgu.o clk-cgu-pll.o clk-lgm.o
+1
drivers/edac/Kconfig
··· 263 263 config EDAC_PND2 264 264 tristate "Intel Pondicherry2" 265 265 depends on PCI && X86_64 && X86_MCE_INTEL 266 + select P2SB if X86 266 267 help 267 268 Support for error detection and correction on the Intel 268 269 Pondicherry2 Integrated Memory Controller. This SoC IP is
+20 -42
drivers/edac/pnd2_edac.c
··· 28 28 #include <linux/bitmap.h> 29 29 #include <linux/math64.h> 30 30 #include <linux/mod_devicetable.h> 31 + #include <linux/platform_data/x86/p2sb.h> 32 + 31 33 #include <asm/cpu_device_id.h> 32 34 #include <asm/intel-family.h> 33 35 #include <asm/processor.h> ··· 234 232 return U64_LSHIFT(hi.base, 32) | U64_LSHIFT(lo.base, 15); 235 233 } 236 234 237 - static u64 get_sideband_reg_base_addr(void) 238 - { 239 - struct pci_dev *pdev; 240 - u32 hi, lo; 241 - u8 hidden; 242 - 243 - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x19dd, NULL); 244 - if (pdev) { 245 - /* Unhide the P2SB device, if it's hidden */ 246 - pci_read_config_byte(pdev, 0xe1, &hidden); 247 - if (hidden) 248 - pci_write_config_byte(pdev, 0xe1, 0); 249 - 250 - pci_read_config_dword(pdev, 0x10, &lo); 251 - pci_read_config_dword(pdev, 0x14, &hi); 252 - lo &= 0xfffffff0; 253 - 254 - /* Hide the P2SB device, if it was hidden before */ 255 - if (hidden) 256 - pci_write_config_byte(pdev, 0xe1, hidden); 257 - 258 - pci_dev_put(pdev); 259 - return (U64_LSHIFT(hi, 32) | U64_LSHIFT(lo, 0)); 260 - } else { 261 - return 0xfd000000; 262 - } 263 - } 264 - 265 235 #define DNV_MCHBAR_SIZE 0x8000 266 236 #define DNV_SB_PORT_SIZE 0x10000 267 237 static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name) 268 238 { 269 239 struct pci_dev *pdev; 270 - char *base; 271 - u64 addr; 272 - unsigned long size; 240 + void __iomem *base; 241 + struct resource r; 242 + int ret; 273 243 274 244 if (op == 4) { 275 245 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL); ··· 253 279 } else { 254 280 /* MMIO via memory controller hub base address */ 255 281 if (op == 0 && port == 0x4c) { 256 - addr = get_mem_ctrl_hub_base_addr(); 257 - if (!addr) 282 + memset(&r, 0, sizeof(r)); 283 + 284 + r.start = get_mem_ctrl_hub_base_addr(); 285 + if (!r.start) 258 286 return -ENODEV; 259 - size = DNV_MCHBAR_SIZE; 287 + r.end = r.start + DNV_MCHBAR_SIZE - 1; 260 288 } else { 261 289 /* MMIO via sideband register base address */ 262 - addr = get_sideband_reg_base_addr(); 263 - if (!addr) 264 - return -ENODEV; 265 - addr += (port << 16); 266 - size = DNV_SB_PORT_SIZE; 290 + ret = p2sb_bar(NULL, 0, &r); 291 + if (ret) 292 + return ret; 293 + 294 + r.start += (port << 16); 295 + r.end = r.start + DNV_SB_PORT_SIZE - 1; 267 296 } 268 297 269 - base = ioremap((resource_size_t)addr, size); 298 + base = ioremap(r.start, resource_size(&r)); 270 299 if (!base) 271 300 return -ENODEV; 272 301 273 302 if (sz == 8) 274 - *(u32 *)(data + 4) = *(u32 *)(base + off + 4); 275 - *(u32 *)data = *(u32 *)(base + off); 303 + *(u64 *)data = readq(base + off); 304 + else 305 + *(u32 *)data = readl(base + off); 276 306 277 307 iounmap(base); 278 308 }
+37 -1
drivers/hid/surface-hid/surface_hid_core.c
··· 19 19 #include "surface_hid_core.h" 20 20 21 21 22 + /* -- Utility functions. ---------------------------------------------------- */ 23 + 24 + static bool surface_hid_is_hot_removed(struct surface_hid_device *shid) 25 + { 26 + /* 27 + * Non-ssam client devices, i.e. platform client devices, cannot be 28 + * hot-removed. 29 + */ 30 + if (!is_ssam_device(shid->dev)) 31 + return false; 32 + 33 + return ssam_device_is_hot_removed(to_ssam_device(shid->dev)); 34 + } 35 + 36 + 22 37 /* -- Device descriptor access. --------------------------------------------- */ 23 38 24 39 static int surface_hid_load_hid_descriptor(struct surface_hid_device *shid) 25 40 { 26 41 int status; 42 + 43 + if (surface_hid_is_hot_removed(shid)) 44 + return -ENODEV; 27 45 28 46 status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_HID, 29 47 (u8 *)&shid->hid_desc, sizeof(shid->hid_desc)); ··· 79 61 { 80 62 int status; 81 63 64 + if (surface_hid_is_hot_removed(shid)) 65 + return -ENODEV; 66 + 82 67 status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_ATTRS, 83 68 (u8 *)&shid->attrs, sizeof(shid->attrs)); 84 69 if (status) ··· 109 88 static void surface_hid_stop(struct hid_device *hid) 110 89 { 111 90 struct surface_hid_device *shid = hid->driver_data; 91 + bool hot_removed; 92 + 93 + /* 94 + * Communication may fail for devices that have been hot-removed. This 95 + * also includes unregistration of HID events, so we need to check this 96 + * here. Only if the device has not been marked as hot-removed, we can 97 + * safely disable events. 98 + */ 99 + hot_removed = surface_hid_is_hot_removed(shid); 112 100 113 101 /* Note: This call will log errors for us, so ignore them here. */ 114 - ssam_notifier_unregister(shid->ctrl, &shid->notif); 102 + __ssam_notifier_unregister(shid->ctrl, &shid->notif, !hot_removed); 115 103 } 116 104 117 105 static int surface_hid_open(struct hid_device *hid) ··· 139 109 u8 *buf; 140 110 int status; 141 111 112 + if (surface_hid_is_hot_removed(shid)) 113 + return -ENODEV; 114 + 142 115 buf = kzalloc(len, GFP_KERNEL); 143 116 if (!buf) 144 117 return -ENOMEM; ··· 158 125 size_t len, unsigned char rtype, int reqtype) 159 126 { 160 127 struct surface_hid_device *shid = hid->driver_data; 128 + 129 + if (surface_hid_is_hot_removed(shid)) 130 + return -ENODEV; 161 131 162 132 if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) 163 133 return shid->ops.output_report(shid, reportnum, buf, len);
+1
drivers/i2c/busses/Kconfig
··· 108 108 config I2C_I801 109 109 tristate "Intel 82801 (ICH/PCH)" 110 110 depends on PCI 111 + select P2SB if X86 111 112 select CHECK_SIGNATURE if X86 && DMI 112 113 select I2C_SMBUS 113 114 help
+9 -30
drivers/i2c/busses/i2c-i801.c
··· 112 112 #include <linux/err.h> 113 113 #include <linux/platform_device.h> 114 114 #include <linux/platform_data/itco_wdt.h> 115 + #include <linux/platform_data/x86/p2sb.h> 115 116 #include <linux/pm_runtime.h> 116 117 #include <linux/mutex.h> 117 118 ··· 142 141 #define TCOBASE 0x050 143 142 #define TCOCTL 0x054 144 143 145 - #define SBREG_BAR 0x10 146 144 #define SBREG_SMBCTRL 0xc6000c 147 145 #define SBREG_SMBCTRL_DNV 0xcf000c 148 146 ··· 1485 1485 .version = 4, 1486 1486 }; 1487 1487 struct resource *res; 1488 - unsigned int devfn; 1489 - u64 base64_addr; 1490 - u32 base_addr; 1491 - u8 hidden; 1488 + int ret; 1492 1489 1493 1490 /* 1494 1491 * We must access the NO_REBOOT bit over the Primary to Sideband 1495 - * bridge (P2SB). The BIOS prevents the P2SB device from being 1496 - * enumerated by the PCI subsystem, so we need to unhide/hide it 1497 - * to lookup the P2SB BAR. 1492 + * (P2SB) bridge. 1498 1493 */ 1499 - pci_lock_rescan_remove(); 1500 - 1501 - devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); 1502 - 1503 - /* Unhide the P2SB device, if it is hidden */ 1504 - pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); 1505 - if (hidden) 1506 - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); 1507 - 1508 - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); 1509 - base64_addr = base_addr & 0xfffffff0; 1510 - 1511 - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); 1512 - base64_addr |= (u64)base_addr << 32; 1513 - 1514 - /* Hide the P2SB device, if it was hidden before */ 1515 - if (hidden) 1516 - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); 1517 - pci_unlock_rescan_remove(); 1518 1494 1519 1495 res = &tco_res[1]; 1496 + ret = p2sb_bar(pci_dev->bus, 0, res); 1497 + if (ret) 1498 + return ERR_PTR(ret); 1499 + 1520 1500 if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) 1521 - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; 1501 + res->start += SBREG_SMBCTRL_DNV; 1522 1502 else 1523 - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; 1503 + res->start += SBREG_SMBCTRL; 1524 1504 1525 1505 res->end = res->start + 3; 1526 - res->flags = IORESOURCE_MEM; 1527 1506 1528 1507 return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, 1529 1508 tco_res, 2, &pldata, sizeof(pldata));
+3 -3
drivers/leds/simple/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config LEDS_SIEMENS_SIMATIC_IPC 3 3 tristate "LED driver for Siemens Simatic IPCs" 4 - depends on LEDS_CLASS 4 + depends on LEDS_GPIO 5 5 depends on SIEMENS_SIMATIC_IPC 6 6 help 7 7 This option enables support for the LEDs of several Industrial PCs 8 8 from Siemens. 9 9 10 - To compile this driver as a module, choose M here: the module 11 - will be called simatic-ipc-leds. 10 + To compile this driver as a module, choose M here: the modules 11 + will be called simatic-ipc-leds and simatic-ipc-leds-gpio.
+1
drivers/leds/simple/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o 3 + obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds-gpio.o
+105
drivers/leds/simple/simatic-ipc-leds-gpio.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for GPIO based LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2022 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + 17 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { 18 + .dev_id = "leds-gpio", 19 + .table = { 20 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 0, GPIO_ACTIVE_LOW), 21 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 52, NULL, 1, GPIO_ACTIVE_LOW), 22 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 53, NULL, 2, GPIO_ACTIVE_LOW), 23 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 57, NULL, 3, GPIO_ACTIVE_LOW), 24 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 58, NULL, 4, GPIO_ACTIVE_LOW), 25 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 60, NULL, 5, GPIO_ACTIVE_LOW), 26 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 56, NULL, 6, GPIO_ACTIVE_LOW), 27 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 59, NULL, 7, GPIO_ACTIVE_HIGH), 28 + }, 29 + }; 30 + 31 + static const struct gpio_led simatic_ipc_gpio_leds[] = { 32 + { .name = "green:" LED_FUNCTION_STATUS "-3" }, 33 + { .name = "red:" LED_FUNCTION_STATUS "-1" }, 34 + { .name = "green:" LED_FUNCTION_STATUS "-1" }, 35 + { .name = "red:" LED_FUNCTION_STATUS "-2" }, 36 + { .name = "green:" LED_FUNCTION_STATUS "-2" }, 37 + { .name = "red:" LED_FUNCTION_STATUS "-3" }, 38 + }; 39 + 40 + static const struct gpio_led_platform_data simatic_ipc_gpio_leds_pdata = { 41 + .num_leds = ARRAY_SIZE(simatic_ipc_gpio_leds), 42 + .leds = simatic_ipc_gpio_leds, 43 + }; 44 + 45 + static struct platform_device *simatic_leds_pdev; 46 + 47 + static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev) 48 + { 49 + gpiod_remove_lookup_table(&simatic_ipc_led_gpio_table); 50 + platform_device_unregister(simatic_leds_pdev); 51 + 52 + return 0; 53 + } 54 + 55 + static int simatic_ipc_leds_gpio_probe(struct platform_device *pdev) 56 + { 57 + struct gpio_desc *gpiod; 58 + int err; 59 + 60 + gpiod_add_lookup_table(&simatic_ipc_led_gpio_table); 61 + simatic_leds_pdev = platform_device_register_resndata(NULL, 62 + "leds-gpio", PLATFORM_DEVID_NONE, NULL, 0, 63 + &simatic_ipc_gpio_leds_pdata, 64 + sizeof(simatic_ipc_gpio_leds_pdata)); 65 + if (IS_ERR(simatic_leds_pdev)) { 66 + err = PTR_ERR(simatic_leds_pdev); 67 + goto out; 68 + } 69 + 70 + /* PM_BIOS_BOOT_N */ 71 + gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 6, GPIOD_OUT_LOW); 72 + if (IS_ERR(gpiod)) { 73 + err = PTR_ERR(gpiod); 74 + goto out; 75 + } 76 + gpiod_put(gpiod); 77 + 78 + /* PM_WDT_OUT */ 79 + gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 7, GPIOD_OUT_LOW); 80 + if (IS_ERR(gpiod)) { 81 + err = PTR_ERR(gpiod); 82 + goto out; 83 + } 84 + gpiod_put(gpiod); 85 + 86 + return 0; 87 + out: 88 + simatic_ipc_leds_gpio_remove(pdev); 89 + 90 + return err; 91 + } 92 + 93 + static struct platform_driver simatic_ipc_led_gpio_driver = { 94 + .probe = simatic_ipc_leds_gpio_probe, 95 + .remove = simatic_ipc_leds_gpio_remove, 96 + .driver = { 97 + .name = KBUILD_MODNAME, 98 + } 99 + }; 100 + module_platform_driver(simatic_ipc_led_gpio_driver); 101 + 102 + MODULE_LICENSE("GPL v2"); 103 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 104 + MODULE_SOFTDEP("pre: platform:leds-gpio"); 105 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+4 -76
drivers/leds/simple/simatic-ipc-leds.c
··· 23 23 #define SIMATIC_IPC_LED_PORT_BASE 0x404E 24 24 25 25 struct simatic_ipc_led { 26 - unsigned int value; /* mask for io and offset for mem */ 26 + unsigned int value; /* mask for io */ 27 27 char *name; 28 28 struct led_classdev cdev; 29 29 }; ··· 35 35 {1 << 6, "yellow:" LED_FUNCTION_STATUS "-2" }, 36 36 {1 << 13, "red:" LED_FUNCTION_STATUS "-3" }, 37 37 {1 << 5, "yellow:" LED_FUNCTION_STATUS "-3" }, 38 - { } 39 - }; 40 - 41 - /* the actual start will be discovered with PCI, 0 is a placeholder */ 42 - static struct resource simatic_ipc_led_mem_res = DEFINE_RES_MEM_NAMED(0, SZ_4K, KBUILD_MODNAME); 43 - 44 - static void __iomem *simatic_ipc_led_memory; 45 - 46 - static struct simatic_ipc_led simatic_ipc_leds_mem[] = { 47 - {0x500 + 0x1A0, "red:" LED_FUNCTION_STATUS "-1"}, 48 - {0x500 + 0x1A8, "green:" LED_FUNCTION_STATUS "-1"}, 49 - {0x500 + 0x1C8, "red:" LED_FUNCTION_STATUS "-2"}, 50 - {0x500 + 0x1D0, "green:" LED_FUNCTION_STATUS "-2"}, 51 - {0x500 + 0x1E0, "red:" LED_FUNCTION_STATUS "-3"}, 52 - {0x500 + 0x198, "green:" LED_FUNCTION_STATUS "-3"}, 53 38 { } 54 39 }; 55 40 ··· 73 88 return inw(SIMATIC_IPC_LED_PORT_BASE) & led->value ? LED_OFF : led_cd->max_brightness; 74 89 } 75 90 76 - static void simatic_ipc_led_set_mem(struct led_classdev *led_cd, 77 - enum led_brightness brightness) 78 - { 79 - struct simatic_ipc_led *led = cdev_to_led(led_cd); 80 - void __iomem *reg = simatic_ipc_led_memory + led->value; 81 - u32 val; 82 - 83 - val = readl(reg); 84 - val = (val & ~1) | (brightness == LED_OFF); 85 - writel(val, reg); 86 - } 87 - 88 - static enum led_brightness simatic_ipc_led_get_mem(struct led_classdev *led_cd) 89 - { 90 - struct simatic_ipc_led *led = cdev_to_led(led_cd); 91 - void __iomem *reg = simatic_ipc_led_memory + led->value; 92 - u32 val; 93 - 94 - val = readl(reg); 95 - return (val & 1) ? LED_OFF : led_cd->max_brightness; 96 - } 97 - 98 91 static int simatic_ipc_leds_probe(struct platform_device *pdev) 99 92 { 100 93 const struct simatic_ipc_platform *plat = pdev->dev.platform_data; ··· 80 117 struct simatic_ipc_led *ipcled; 81 118 struct led_classdev *cdev; 82 119 struct resource *res; 83 - void __iomem *reg; 84 - int err, type; 85 - u32 val; 120 + int err; 86 121 87 122 switch (plat->devmode) { 88 123 case SIMATIC_IPC_DEVICE_227D: ··· 95 134 } 96 135 ipcled = simatic_ipc_leds_io; 97 136 } 98 - type = IORESOURCE_IO; 99 137 if (!devm_request_region(dev, res->start, resource_size(res), KBUILD_MODNAME)) { 100 138 dev_err(dev, "Unable to register IO resource at %pR\n", res); 101 139 return -EBUSY; 102 140 } 103 - break; 104 - case SIMATIC_IPC_DEVICE_127E: 105 - res = &simatic_ipc_led_mem_res; 106 - ipcled = simatic_ipc_leds_mem; 107 - type = IORESOURCE_MEM; 108 - 109 - /* get GPIO base from PCI */ 110 - res->start = simatic_ipc_get_membase0(PCI_DEVFN(13, 0)); 111 - if (res->start == 0) 112 - return -ENODEV; 113 - 114 - /* do the final address calculation */ 115 - res->start = res->start + (0xC5 << 16); 116 - res->end += res->start; 117 - 118 - simatic_ipc_led_memory = devm_ioremap_resource(dev, res); 119 - if (IS_ERR(simatic_ipc_led_memory)) 120 - return PTR_ERR(simatic_ipc_led_memory); 121 - 122 - /* initialize power/watchdog LED */ 123 - reg = simatic_ipc_led_memory + 0x500 + 0x1D8; /* PM_WDT_OUT */ 124 - val = readl(reg); 125 - writel(val & ~1, reg); 126 - 127 - reg = simatic_ipc_led_memory + 0x500 + 0x1C0; /* PM_BIOS_BOOT_N */ 128 - val = readl(reg); 129 - writel(val | 1, reg); 130 141 break; 131 142 default: 132 143 return -ENODEV; ··· 106 173 107 174 while (ipcled->value) { 108 175 cdev = &ipcled->cdev; 109 - if (type == IORESOURCE_MEM) { 110 - cdev->brightness_set = simatic_ipc_led_set_mem; 111 - cdev->brightness_get = simatic_ipc_led_get_mem; 112 - } else { 113 - cdev->brightness_set = simatic_ipc_led_set_io; 114 - cdev->brightness_get = simatic_ipc_led_get_io; 115 - } 176 + cdev->brightness_set = simatic_ipc_led_set_io; 177 + cdev->brightness_get = simatic_ipc_led_get_io; 116 178 cdev->max_brightness = LED_ON; 117 179 cdev->name = ipcled->name; 118 180
+1
drivers/mfd/Kconfig
··· 572 572 tristate "Intel ICH LPC" 573 573 depends on PCI 574 574 select MFD_CORE 575 + select P2SB if X86 575 576 help 576 577 The LPC bridge function of the Intel ICH provides support for 577 578 many functional units. This driver provides needed support for
+125 -36
drivers/mfd/lpc_ich.c
··· 8 8 * Configuration Registers. 9 9 * 10 10 * This driver is derived from lpc_sch. 11 - 11 + * 12 + * Copyright (c) 2017, 2021-2022 Intel Corporation 12 13 * Copyright (c) 2011 Extreme Engineering Solution, Inc. 13 14 * Author: Aaron Sierra <asierra@xes-inc.com> 14 15 * ··· 43 42 #include <linux/errno.h> 44 43 #include <linux/acpi.h> 45 44 #include <linux/pci.h> 45 + #include <linux/pinctrl/pinctrl.h> 46 46 #include <linux/mfd/core.h> 47 47 #include <linux/mfd/lpc_ich.h> 48 48 #include <linux/platform_data/itco_wdt.h> 49 + #include <linux/platform_data/x86/p2sb.h> 49 50 50 51 #define ACPIBASE 0x40 51 52 #define ACPIBASE_GPE_OFF 0x28 ··· 73 70 #define SPIBASE_LPT_SZ 512 74 71 #define BCR 0xdc 75 72 #define BCR_WPD BIT(0) 76 - 77 - #define SPIBASE_APL_SZ 4096 78 73 79 74 #define GPIOBASE_ICH0 0x58 80 75 #define GPIOCTRL_ICH0 0x5C ··· 144 143 .ignore_resource_conflicts = true, 145 144 }; 146 145 146 + #define APL_GPIO_NORTH 0 147 + #define APL_GPIO_NORTHWEST 1 148 + #define APL_GPIO_WEST 2 149 + #define APL_GPIO_SOUTHWEST 3 150 + #define APL_GPIO_NR_DEVICES 4 151 + 152 + /* Offset data for Apollo Lake GPIO controllers */ 153 + static resource_size_t apl_gpio_offsets[APL_GPIO_NR_DEVICES] = { 154 + [APL_GPIO_NORTH] = 0xc50000, 155 + [APL_GPIO_NORTHWEST] = 0xc40000, 156 + [APL_GPIO_WEST] = 0xc70000, 157 + [APL_GPIO_SOUTHWEST] = 0xc00000, 158 + }; 159 + 160 + #define APL_GPIO_RESOURCE_SIZE 0x1000 161 + 162 + #define APL_GPIO_IRQ 14 163 + 164 + static struct resource apl_gpio_resources[APL_GPIO_NR_DEVICES][2] = { 165 + [APL_GPIO_NORTH] = { 166 + DEFINE_RES_MEM(0, 0), 167 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 168 + }, 169 + [APL_GPIO_NORTHWEST] = { 170 + DEFINE_RES_MEM(0, 0), 171 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 172 + }, 173 + [APL_GPIO_WEST] = { 174 + DEFINE_RES_MEM(0, 0), 175 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 176 + }, 177 + [APL_GPIO_SOUTHWEST] = { 178 + DEFINE_RES_MEM(0, 0), 179 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 180 + }, 181 + }; 182 + 183 + static const struct mfd_cell apl_gpio_devices[APL_GPIO_NR_DEVICES] = { 184 + [APL_GPIO_NORTH] = { 185 + .name = "apollolake-pinctrl", 186 + .id = APL_GPIO_NORTH, 187 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTH]), 188 + .resources = apl_gpio_resources[APL_GPIO_NORTH], 189 + .ignore_resource_conflicts = true, 190 + }, 191 + [APL_GPIO_NORTHWEST] = { 192 + .name = "apollolake-pinctrl", 193 + .id = APL_GPIO_NORTHWEST, 194 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTHWEST]), 195 + .resources = apl_gpio_resources[APL_GPIO_NORTHWEST], 196 + .ignore_resource_conflicts = true, 197 + }, 198 + [APL_GPIO_WEST] = { 199 + .name = "apollolake-pinctrl", 200 + .id = APL_GPIO_WEST, 201 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_WEST]), 202 + .resources = apl_gpio_resources[APL_GPIO_WEST], 203 + .ignore_resource_conflicts = true, 204 + }, 205 + [APL_GPIO_SOUTHWEST] = { 206 + .name = "apollolake-pinctrl", 207 + .id = APL_GPIO_SOUTHWEST, 208 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_SOUTHWEST]), 209 + .resources = apl_gpio_resources[APL_GPIO_SOUTHWEST], 210 + .ignore_resource_conflicts = true, 211 + }, 212 + }; 147 213 148 214 static struct mfd_cell lpc_ich_spi_cell = { 149 215 .name = "intel-spi", ··· 1154 1086 return ret; 1155 1087 } 1156 1088 1089 + static int lpc_ich_init_pinctrl(struct pci_dev *dev) 1090 + { 1091 + struct resource base; 1092 + unsigned int i; 1093 + int ret; 1094 + 1095 + /* Check, if GPIO has been exported as an ACPI device */ 1096 + if (acpi_dev_present("INT3452", NULL, -1)) 1097 + return -EEXIST; 1098 + 1099 + ret = p2sb_bar(dev->bus, 0, &base); 1100 + if (ret) 1101 + return ret; 1102 + 1103 + for (i = 0; i < ARRAY_SIZE(apl_gpio_devices); i++) { 1104 + struct resource *mem = &apl_gpio_resources[i][0]; 1105 + resource_size_t offset = apl_gpio_offsets[i]; 1106 + 1107 + /* Fill MEM resource */ 1108 + mem->start = base.start + offset; 1109 + mem->end = base.start + offset + APL_GPIO_RESOURCE_SIZE - 1; 1110 + mem->flags = base.flags; 1111 + } 1112 + 1113 + return mfd_add_devices(&dev->dev, 0, apl_gpio_devices, 1114 + ARRAY_SIZE(apl_gpio_devices), NULL, 0, NULL); 1115 + } 1116 + 1157 1117 static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data) 1158 1118 { 1159 1119 u32 val; ··· 1196 1100 return val & BYT_BCR_WPD; 1197 1101 } 1198 1102 1199 - static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) 1103 + static bool lpc_ich_set_writeable(struct pci_bus *bus, unsigned int devfn) 1200 1104 { 1201 - struct pci_dev *pdev = data; 1202 1105 u32 bcr; 1203 1106 1204 - pci_read_config_dword(pdev, BCR, &bcr); 1107 + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); 1205 1108 if (!(bcr & BCR_WPD)) { 1206 1109 bcr |= BCR_WPD; 1207 - pci_write_config_dword(pdev, BCR, bcr); 1208 - pci_read_config_dword(pdev, BCR, &bcr); 1110 + pci_bus_write_config_dword(bus, devfn, BCR, bcr); 1111 + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); 1209 1112 } 1210 1113 1211 1114 return bcr & BCR_WPD; 1212 1115 } 1213 1116 1117 + static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) 1118 + { 1119 + struct pci_dev *pdev = data; 1120 + 1121 + return lpc_ich_set_writeable(pdev->bus, pdev->devfn); 1122 + } 1123 + 1214 1124 static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data) 1215 1125 { 1216 - unsigned int spi = PCI_DEVFN(13, 2); 1217 - struct pci_bus *bus = data; 1218 - u32 bcr; 1126 + struct pci_dev *pdev = data; 1219 1127 1220 - pci_bus_read_config_dword(bus, spi, BCR, &bcr); 1221 - if (!(bcr & BCR_WPD)) { 1222 - bcr |= BCR_WPD; 1223 - pci_bus_write_config_dword(bus, spi, BCR, bcr); 1224 - pci_bus_read_config_dword(bus, spi, BCR, &bcr); 1225 - } 1226 - 1227 - return bcr & BCR_WPD; 1128 + return lpc_ich_set_writeable(pdev->bus, PCI_DEVFN(13, 2)); 1228 1129 } 1229 1130 1230 1131 static int lpc_ich_init_spi(struct pci_dev *dev) ··· 1230 1137 struct resource *res = &intel_spi_res[0]; 1231 1138 struct intel_spi_boardinfo *info; 1232 1139 u32 spi_base, rcba; 1140 + int ret; 1233 1141 1234 1142 info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); 1235 1143 if (!info) ··· 1261 1167 } 1262 1168 break; 1263 1169 1264 - case INTEL_SPI_BXT: { 1265 - unsigned int p2sb = PCI_DEVFN(13, 0); 1266 - unsigned int spi = PCI_DEVFN(13, 2); 1267 - struct pci_bus *bus = dev->bus; 1268 - 1170 + case INTEL_SPI_BXT: 1269 1171 /* 1270 1172 * The P2SB is hidden by BIOS and we need to unhide it in 1271 1173 * order to read BAR of the SPI flash device. Once that is 1272 1174 * done we hide it again. 1273 1175 */ 1274 - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x0); 1275 - pci_bus_read_config_dword(bus, spi, PCI_BASE_ADDRESS_0, 1276 - &spi_base); 1277 - if (spi_base != ~0) { 1278 - res->start = spi_base & 0xfffffff0; 1279 - res->end = res->start + SPIBASE_APL_SZ - 1; 1176 + ret = p2sb_bar(dev->bus, PCI_DEVFN(13, 2), res); 1177 + if (ret) 1178 + return ret; 1280 1179 1281 - info->set_writeable = lpc_ich_bxt_set_writeable; 1282 - info->data = bus; 1283 - } 1284 - 1285 - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1); 1180 + info->set_writeable = lpc_ich_bxt_set_writeable; 1181 + info->data = dev; 1286 1182 break; 1287 - } 1288 1183 1289 1184 default: 1290 1185 return -EINVAL; ··· 1328 1245 1329 1246 if (lpc_chipset_info[priv->chipset].gpio_version) { 1330 1247 ret = lpc_ich_init_gpio(dev); 1248 + if (!ret) 1249 + cell_added = true; 1250 + } 1251 + 1252 + if (priv->chipset == LPC_APL) { 1253 + ret = lpc_ich_init_pinctrl(dev); 1331 1254 if (!ret) 1332 1255 cell_added = true; 1333 1256 }
+6 -8
drivers/pinctrl/intel/pinctrl-intel.c
··· 1641 1641 1642 1642 const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) 1643 1643 { 1644 + const struct intel_pinctrl_soc_data * const *table; 1644 1645 const struct intel_pinctrl_soc_data *data = NULL; 1645 - const struct intel_pinctrl_soc_data **table; 1646 - struct acpi_device *adev; 1647 - unsigned int i; 1648 1646 1649 - adev = ACPI_COMPANION(&pdev->dev); 1650 - if (adev) { 1651 - const void *match = device_get_match_data(&pdev->dev); 1647 + table = device_get_match_data(&pdev->dev); 1648 + if (table) { 1649 + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 1650 + unsigned int i; 1652 1651 1653 - table = (const struct intel_pinctrl_soc_data **)match; 1654 1652 for (i = 0; table[i]; i++) { 1655 1653 if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { 1656 1654 data = table[i]; ··· 1662 1664 if (!id) 1663 1665 return ERR_PTR(-ENODEV); 1664 1666 1665 - table = (const struct intel_pinctrl_soc_data **)id->driver_data; 1667 + table = (const struct intel_pinctrl_soc_data * const *)id->driver_data; 1666 1668 data = table[pdev->id]; 1667 1669 } 1668 1670
+2 -3
drivers/platform/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 - if X86 3 - source "drivers/platform/x86/Kconfig" 4 - endif 5 2 if MIPS 6 3 source "drivers/platform/mips/Kconfig" 7 4 endif ··· 12 15 source "drivers/platform/olpc/Kconfig" 13 16 14 17 source "drivers/platform/surface/Kconfig" 18 + 19 + source "drivers/platform/x86/Kconfig"
+23
drivers/platform/mellanox/mlxreg-io.c
··· 31 31 * @group: sysfs attribute group; 32 32 * @groups: list of sysfs attribute group for hwmon registration; 33 33 * @regsize: size of a register value; 34 + * @io_lock: user access locking; 34 35 */ 35 36 struct mlxreg_io_priv_data { 36 37 struct platform_device *pdev; ··· 42 41 struct attribute_group group; 43 42 const struct attribute_group *groups[2]; 44 43 int regsize; 44 + struct mutex io_lock; /* Protects user access. */ 45 45 }; 46 46 47 47 static int ··· 118 116 u32 regval = 0; 119 117 int ret; 120 118 119 + mutex_lock(&priv->io_lock); 120 + 121 121 ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, 122 122 priv->regsize, &regval); 123 123 if (ret) 124 124 goto access_error; 125 125 126 + mutex_unlock(&priv->io_lock); 127 + 126 128 return sprintf(buf, "%u\n", regval); 127 129 128 130 access_error: 131 + mutex_unlock(&priv->io_lock); 129 132 return ret; 130 133 } 131 134 ··· 152 145 if (ret) 153 146 return ret; 154 147 148 + mutex_lock(&priv->io_lock); 149 + 155 150 ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false, 156 151 priv->regsize, &regval); 157 152 if (ret) ··· 163 154 if (ret) 164 155 goto access_error; 165 156 157 + mutex_unlock(&priv->io_lock); 158 + 166 159 return len; 167 160 168 161 access_error: 162 + mutex_unlock(&priv->io_lock); 169 163 dev_err(&priv->pdev->dev, "Bus access error\n"); 170 164 return ret; 171 165 } ··· 258 246 return PTR_ERR(priv->hwmon); 259 247 } 260 248 249 + mutex_init(&priv->io_lock); 261 250 dev_set_drvdata(&pdev->dev, priv); 251 + 252 + return 0; 253 + } 254 + 255 + static int mlxreg_io_remove(struct platform_device *pdev) 256 + { 257 + struct mlxreg_io_priv_data *priv = dev_get_drvdata(&pdev->dev); 258 + 259 + mutex_destroy(&priv->io_lock); 262 260 263 261 return 0; 264 262 } ··· 278 256 .name = "mlxreg-io", 279 257 }, 280 258 .probe = mlxreg_io_probe, 259 + .remove = mlxreg_io_remove, 281 260 }; 282 261 283 262 module_platform_driver(mlxreg_io_driver);
+63 -19
drivers/platform/mellanox/mlxreg-lc.c
··· 716 716 switch (regval) { 717 717 case MLXREG_LC_SN4800_C16: 718 718 err = mlxreg_lc_sn4800_c16_config_init(mlxreg_lc, regmap, data); 719 - if (err) 719 + if (err) { 720 + dev_err(dev, "Failed to config client %s at bus %d at addr 0x%02x\n", 721 + data->hpdev.brdinfo->type, data->hpdev.nr, 722 + data->hpdev.brdinfo->addr); 720 723 return err; 724 + } 721 725 break; 722 726 default: 723 727 return -ENODEV; ··· 734 730 mlxreg_lc->mux = platform_device_register_resndata(dev, "i2c-mux-mlxcpld", data->hpdev.nr, 735 731 NULL, 0, mlxreg_lc->mux_data, 736 732 sizeof(*mlxreg_lc->mux_data)); 737 - if (IS_ERR(mlxreg_lc->mux)) 733 + if (IS_ERR(mlxreg_lc->mux)) { 734 + dev_err(dev, "Failed to create mux infra for client %s at bus %d at addr 0x%02x\n", 735 + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); 738 736 return PTR_ERR(mlxreg_lc->mux); 737 + } 739 738 740 739 /* Register IO access driver. */ 741 740 if (mlxreg_lc->io_data) { ··· 747 740 platform_device_register_resndata(dev, "mlxreg-io", data->hpdev.nr, NULL, 0, 748 741 mlxreg_lc->io_data, sizeof(*mlxreg_lc->io_data)); 749 742 if (IS_ERR(mlxreg_lc->io_regs)) { 743 + dev_err(dev, "Failed to create regio for client %s at bus %d at addr 0x%02x\n", 744 + data->hpdev.brdinfo->type, data->hpdev.nr, 745 + data->hpdev.brdinfo->addr); 750 746 err = PTR_ERR(mlxreg_lc->io_regs); 751 747 goto fail_register_io; 752 748 } ··· 763 753 mlxreg_lc->led_data, 764 754 sizeof(*mlxreg_lc->led_data)); 765 755 if (IS_ERR(mlxreg_lc->led)) { 756 + dev_err(dev, "Failed to create LED objects for client %s at bus %d at addr 0x%02x\n", 757 + data->hpdev.brdinfo->type, data->hpdev.nr, 758 + data->hpdev.brdinfo->addr); 766 759 err = PTR_ERR(mlxreg_lc->led); 767 760 goto fail_register_led; 768 761 } ··· 822 809 if (!data->hpdev.adapter) { 823 810 dev_err(&pdev->dev, "Failed to get adapter for bus %d\n", 824 811 data->hpdev.nr); 825 - return -EFAULT; 812 + err = -EFAULT; 813 + goto i2c_get_adapter_fail; 826 814 } 827 815 828 816 /* Create device at the top of line card I2C tree.*/ ··· 832 818 if (IS_ERR(data->hpdev.client)) { 833 819 dev_err(&pdev->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", 834 820 data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); 835 - 836 - i2c_put_adapter(data->hpdev.adapter); 837 - data->hpdev.adapter = NULL; 838 - return PTR_ERR(data->hpdev.client); 821 + err = PTR_ERR(data->hpdev.client); 822 + goto i2c_new_device_fail; 839 823 } 840 824 841 825 regmap = devm_regmap_init_i2c(data->hpdev.client, 842 826 &mlxreg_lc_regmap_conf); 843 827 if (IS_ERR(regmap)) { 828 + dev_err(&pdev->dev, "Failed to create regmap for client %s at bus %d at addr 0x%02x\n", 829 + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); 844 830 err = PTR_ERR(regmap); 845 - goto mlxreg_lc_probe_fail; 831 + goto devm_regmap_init_i2c_fail; 846 832 } 847 833 848 834 /* Set default registers. */ 849 835 for (i = 0; i < mlxreg_lc_regmap_conf.num_reg_defaults; i++) { 850 836 err = regmap_write(regmap, mlxreg_lc_regmap_default[i].reg, 851 837 mlxreg_lc_regmap_default[i].def); 852 - if (err) 853 - goto mlxreg_lc_probe_fail; 838 + if (err) { 839 + dev_err(&pdev->dev, "Failed to set default regmap %d for client %s at bus %d at addr 0x%02x\n", 840 + i, data->hpdev.brdinfo->type, data->hpdev.nr, 841 + data->hpdev.brdinfo->addr); 842 + goto regmap_write_fail; 843 + } 854 844 } 855 845 856 846 /* Sync registers with hardware. */ 857 847 regcache_mark_dirty(regmap); 858 848 err = regcache_sync(regmap); 859 - if (err) 860 - goto mlxreg_lc_probe_fail; 849 + if (err) { 850 + dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n", 851 + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); 852 + err = PTR_ERR(regmap); 853 + goto regcache_sync_fail; 854 + } 861 855 862 856 par_pdata = data->hpdev.brdinfo->platform_data; 863 857 mlxreg_lc->par_regmap = par_pdata->regmap; ··· 876 854 /* Configure line card. */ 877 855 err = mlxreg_lc_config_init(mlxreg_lc, regmap, data); 878 856 if (err) 879 - goto mlxreg_lc_probe_fail; 857 + goto mlxreg_lc_config_init_fail; 880 858 881 859 return err; 882 860 883 - mlxreg_lc_probe_fail: 861 + mlxreg_lc_config_init_fail: 862 + regcache_sync_fail: 863 + regmap_write_fail: 864 + devm_regmap_init_i2c_fail: 865 + if (data->hpdev.client) { 866 + i2c_unregister_device(data->hpdev.client); 867 + data->hpdev.client = NULL; 868 + } 869 + i2c_new_device_fail: 884 870 i2c_put_adapter(data->hpdev.adapter); 871 + data->hpdev.adapter = NULL; 872 + i2c_get_adapter_fail: 873 + /* Clear event notification callback and handle. */ 874 + if (data->notifier) { 875 + data->notifier->user_handler = NULL; 876 + data->notifier->handle = NULL; 877 + } 885 878 return err; 886 879 } 887 880 ··· 905 868 struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev); 906 869 struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev); 907 870 908 - /* Clear event notification callback. */ 909 - if (data->notifier) { 910 - data->notifier->user_handler = NULL; 911 - data->notifier->handle = NULL; 912 - } 871 + /* 872 + * Probing and removing are invoked by hotplug events raised upon line card insertion and 873 + * removing. If probing procedure fails all data is cleared. However, hotplug event still 874 + * will be raised on line card removing and activate removing procedure. In this case there 875 + * is nothing to remove. 876 + */ 877 + if (!data->notifier || !data->notifier->handle) 878 + return 0; 879 + 880 + /* Clear event notification callback and handle. */ 881 + data->notifier->user_handler = NULL; 882 + data->notifier->handle = NULL; 913 883 914 884 /* Destroy static I2C device feeding by main power. */ 915 885 mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
+1 -1
drivers/platform/olpc/olpc-ec.c
··· 264 264 int i, m; 265 265 unsigned char ec_cmd[EC_MAX_CMD_ARGS]; 266 266 unsigned int ec_cmd_int[EC_MAX_CMD_ARGS]; 267 - char cmdbuf[64]; 267 + char cmdbuf[64] = ""; 268 268 int ec_cmd_bytes; 269 269 270 270 mutex_lock(&ec_dbgfs_lock);
+54 -4
drivers/platform/surface/Kconfig
··· 72 72 The provided interface is intended for debugging and development only, 73 73 and should not be used otherwise. 74 74 75 + config SURFACE_AGGREGATOR_HUB 76 + tristate "Surface System Aggregator Module Subsystem Device Hubs" 77 + depends on SURFACE_AGGREGATOR 78 + depends on SURFACE_AGGREGATOR_BUS 79 + help 80 + Device-hub drivers for Surface System Aggregator Module (SSAM) subsystem 81 + devices. 82 + 83 + Provides subsystem hub drivers which manage client devices on various 84 + SSAM subsystems. In some subsystems, notably the BAS subsystem managing 85 + devices contained in the base of the Surface Book 3 and the KIP subsystem 86 + managing type-cover devices in the Surface Pro 8 and Surface Pro X, 87 + devices can be (hot-)removed. Hub devices and drivers are required to 88 + manage these subdevices. 89 + 90 + Devices managed via these hubs are: 91 + - Battery/AC devices (Surface Book 3). 92 + - HID input devices (7th-generation and later models with detachable 93 + input devices). 94 + 95 + Select M (recommended) or Y here if you want support for the above 96 + mentioned devices on the corresponding Surface models. Without this 97 + module, the respective devices mentioned above will not be instantiated 98 + and thus any functionality provided by them will be missing, even when 99 + drivers for these devices are present. This module only provides the 100 + respective subsystem hubs. Both drivers and device specification (e.g. 101 + via the Surface Aggregator Registry) for these devices still need to be 102 + selected via other options. 103 + 75 104 config SURFACE_AGGREGATOR_REGISTRY 76 105 tristate "Surface System Aggregator Module Device Registry" 77 106 depends on SURFACE_AGGREGATOR 78 107 depends on SURFACE_AGGREGATOR_BUS 79 108 help 80 - Device-registry and device-hubs for Surface System Aggregator Module 81 - (SSAM) devices. 109 + Device-registry for Surface System Aggregator Module (SSAM) devices. 82 110 83 111 Provides a module and driver which act as a device-registry for SSAM 84 112 client devices that cannot be detected automatically, e.g. via ACPI. 85 - Such devices are instead provided via this registry and attached via 86 - device hubs, also provided in this module. 113 + Such devices are instead provided and managed via this registry. 87 114 88 115 Devices provided via this registry are: 89 116 - Platform profile (performance-/cooling-mode) device (5th- and later ··· 125 98 these devices are present. In other words, this module only provides 126 99 the respective client devices. Drivers for these devices still need to 127 100 be selected via the other options. 101 + 102 + config SURFACE_AGGREGATOR_TABLET_SWITCH 103 + tristate "Surface Aggregator Generic Tablet-Mode Switch Driver" 104 + depends on SURFACE_AGGREGATOR 105 + depends on SURFACE_AGGREGATOR_BUS 106 + depends on INPUT 107 + help 108 + Provides a tablet-mode switch input device on Microsoft Surface models 109 + using the KIP subsystem for detachable keyboards (e.g. keyboard covers) 110 + or the POS subsystem for device/screen posture changes. 111 + 112 + The KIP subsystem is used on newer Surface generations to handle 113 + detachable input peripherals, specifically the keyboard cover (containing 114 + keyboard and touchpad) on the Surface Pro 8 and Surface Pro X. The POS 115 + subsystem is used for device posture change notifications on the Surface 116 + Laptop Studio. This module provides a driver to let user-space know when 117 + the device should be considered in tablet-mode due to the keyboard cover 118 + being detached or folded back (essentially signaling when the keyboard is 119 + not available for input). It does so by creating a tablet-mode switch 120 + input device, sending the standard SW_TABLET_MODE event on mode change. 121 + 122 + Select M or Y here, if you want to provide tablet-mode switch input 123 + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. 128 124 129 125 config SURFACE_DTX 130 126 tristate "Surface DTX (Detachment System) Driver"
+2
drivers/platform/surface/Makefile
··· 9 9 obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o 10 10 obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/ 11 11 obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o 12 + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o 12 13 obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o 14 + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o 13 15 obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o 14 16 obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o 15 17 obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o
+1 -1
drivers/platform/surface/aggregator/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0+ 2 - # Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 2 + # Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 3 3 4 4 menuconfig SURFACE_AGGREGATOR 5 5 tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers"
+1 -1
drivers/platform/surface/aggregator/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0+ 2 - # Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 2 + # Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 3 3 4 4 # For include/trace/define_trace.h to include trace.h 5 5 CFLAGS_core.o = -I$(src)
+134 -17
drivers/platform/surface/aggregator/bus.c
··· 2 2 /* 3 3 * Surface System Aggregator Module bus and device integration. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #include <linux/device.h> 9 + #include <linux/property.h> 9 10 #include <linux/slab.h> 10 11 11 12 #include <linux/surface_aggregator/controller.h> ··· 14 13 15 14 #include "bus.h" 16 15 #include "controller.h" 16 + 17 + 18 + /* -- Device and bus functions. --------------------------------------------- */ 17 19 18 20 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, 19 21 char *buf) ··· 50 46 struct ssam_device *sdev = to_ssam_device(dev); 51 47 52 48 ssam_controller_put(sdev->ctrl); 49 + fwnode_handle_put(sdev->dev.fwnode); 53 50 kfree(sdev); 54 51 } 55 52 ··· 368 363 } 369 364 EXPORT_SYMBOL_GPL(ssam_device_driver_unregister); 370 365 366 + 367 + /* -- Bus registration. ----------------------------------------------------- */ 368 + 369 + /** 370 + * ssam_bus_register() - Register and set-up the SSAM client device bus. 371 + */ 372 + int ssam_bus_register(void) 373 + { 374 + return bus_register(&ssam_bus_type); 375 + } 376 + 377 + /** 378 + * ssam_bus_unregister() - Unregister the SSAM client device bus. 379 + */ 380 + void ssam_bus_unregister(void) 381 + { 382 + return bus_unregister(&ssam_bus_type); 383 + } 384 + 385 + 386 + /* -- Helpers for controller and hub devices. ------------------------------- */ 387 + 388 + static int ssam_device_uid_from_string(const char *str, struct ssam_device_uid *uid) 389 + { 390 + u8 d, tc, tid, iid, fn; 391 + int n; 392 + 393 + n = sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn); 394 + if (n != 5) 395 + return -EINVAL; 396 + 397 + uid->domain = d; 398 + uid->category = tc; 399 + uid->target = tid; 400 + uid->instance = iid; 401 + uid->function = fn; 402 + 403 + return 0; 404 + } 405 + 406 + static int ssam_get_uid_for_node(struct fwnode_handle *node, struct ssam_device_uid *uid) 407 + { 408 + const char *str = fwnode_get_name(node); 409 + 410 + /* 411 + * To simplify definitions of firmware nodes, we set the device name 412 + * based on the UID of the device, prefixed with "ssam:". 413 + */ 414 + if (strncmp(str, "ssam:", strlen("ssam:")) != 0) 415 + return -ENODEV; 416 + 417 + str += strlen("ssam:"); 418 + return ssam_device_uid_from_string(str, uid); 419 + } 420 + 421 + static int ssam_add_client_device(struct device *parent, struct ssam_controller *ctrl, 422 + struct fwnode_handle *node) 423 + { 424 + struct ssam_device_uid uid; 425 + struct ssam_device *sdev; 426 + int status; 427 + 428 + status = ssam_get_uid_for_node(node, &uid); 429 + if (status) 430 + return status; 431 + 432 + sdev = ssam_device_alloc(ctrl, uid); 433 + if (!sdev) 434 + return -ENOMEM; 435 + 436 + sdev->dev.parent = parent; 437 + sdev->dev.fwnode = fwnode_handle_get(node); 438 + 439 + status = ssam_device_add(sdev); 440 + if (status) 441 + ssam_device_put(sdev); 442 + 443 + return status; 444 + } 445 + 446 + /** 447 + * __ssam_register_clients() - Register client devices defined under the 448 + * given firmware node as children of the given device. 449 + * @parent: The parent device under which clients should be registered. 450 + * @ctrl: The controller with which client should be registered. 451 + * @node: The firmware node holding definitions of the devices to be added. 452 + * 453 + * Register all clients that have been defined as children of the given root 454 + * firmware node as children of the given parent device. The respective child 455 + * firmware nodes will be associated with the correspondingly created child 456 + * devices. 457 + * 458 + * The given controller will be used to instantiate the new devices. See 459 + * ssam_device_add() for details. 460 + * 461 + * Note that, generally, the use of either ssam_device_register_clients() or 462 + * ssam_register_clients() should be preferred as they directly use the 463 + * firmware node and/or controller associated with the given device. This 464 + * function is only intended for use when different device specifications (e.g. 465 + * ACPI and firmware nodes) need to be combined (as is done in the platform hub 466 + * of the device registry). 467 + * 468 + * Return: Returns zero on success, nonzero on failure. 469 + */ 470 + int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, 471 + struct fwnode_handle *node) 472 + { 473 + struct fwnode_handle *child; 474 + int status; 475 + 476 + fwnode_for_each_child_node(node, child) { 477 + /* 478 + * Try to add the device specified in the firmware node. If 479 + * this fails with -ENODEV, the node does not specify any SSAM 480 + * device, so ignore it and continue with the next one. 481 + */ 482 + status = ssam_add_client_device(parent, ctrl, child); 483 + if (status && status != -ENODEV) 484 + goto err; 485 + } 486 + 487 + return 0; 488 + err: 489 + ssam_remove_clients(parent); 490 + return status; 491 + } 492 + EXPORT_SYMBOL_GPL(__ssam_register_clients); 493 + 371 494 static int ssam_remove_device(struct device *dev, void *_data) 372 495 { 373 496 struct ssam_device *sdev = to_ssam_device(dev); ··· 520 387 device_for_each_child_reverse(dev, NULL, ssam_remove_device); 521 388 } 522 389 EXPORT_SYMBOL_GPL(ssam_remove_clients); 523 - 524 - /** 525 - * ssam_bus_register() - Register and set-up the SSAM client device bus. 526 - */ 527 - int ssam_bus_register(void) 528 - { 529 - return bus_register(&ssam_bus_type); 530 - } 531 - 532 - /** 533 - * ssam_bus_unregister() - Unregister the SSAM client device bus. 534 - */ 535 - void ssam_bus_unregister(void) 536 - { 537 - return bus_unregister(&ssam_bus_type); 538 - }
+1 -1
drivers/platform/surface/aggregator/bus.h
··· 2 2 /* 3 3 * Surface System Aggregator Module bus and device integration. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #ifndef _SURFACE_AGGREGATOR_BUS_H
+36 -19
drivers/platform/surface/aggregator/controller.c
··· 2 2 /* 3 3 * Main SSAM/SSH controller structure and functionality. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #include <linux/acpi.h> ··· 2199 2199 } 2200 2200 2201 2201 /** 2202 - * ssam_nf_refcount_disable_free() - Disable event for reference count entry if it is 2203 - * no longer in use and free the corresponding entry. 2202 + * ssam_nf_refcount_disable_free() - Disable event for reference count entry if 2203 + * it is no longer in use and free the corresponding entry. 2204 2204 * @ctrl: The controller to disable the event on. 2205 2205 * @entry: The reference count entry for the event to be disabled. 2206 2206 * @flags: The flags used for enabling the event on the EC. 2207 + * @ec: Flag specifying if the event should actually be disabled on the EC. 2207 2208 * 2208 - * If the reference count equals zero, i.e. the event is no longer requested by 2209 - * any client, the event will be disabled and the corresponding reference count 2210 - * entry freed. The reference count entry must not be used any more after a 2211 - * call to this function. 2209 + * If ``ec`` equals ``true`` and the reference count equals zero (i.e. the 2210 + * event is no longer requested by any client), the specified event will be 2211 + * disabled on the EC via the corresponding request. 2212 + * 2213 + * If ``ec`` equals ``false``, no request will be sent to the EC and the event 2214 + * can be considered in a detached state (i.e. no longer used but still 2215 + * enabled). Disabling an event via this method may be required for 2216 + * hot-removable devices, where event disable requests may time out after the 2217 + * device has been physically removed. 2218 + * 2219 + * In both cases, if the reference count equals zero, the corresponding 2220 + * reference count entry will be freed. The reference count entry must not be 2221 + * used any more after a call to this function. 2212 2222 * 2213 2223 * Also checks if the flags used for disabling the event match the flags used 2214 2224 * for enabling the event and warns if they do not (regardless of reference ··· 2233 2223 * returns the status of the event-enable EC command. 2234 2224 */ 2235 2225 static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, 2236 - struct ssam_nf_refcount_entry *entry, u8 flags) 2226 + struct ssam_nf_refcount_entry *entry, u8 flags, bool ec) 2237 2227 { 2238 2228 const struct ssam_event_registry reg = entry->key.reg; 2239 2229 const struct ssam_event_id id = entry->key.id; ··· 2242 2232 2243 2233 lockdep_assert_held(&nf->lock); 2244 2234 2245 - ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", 2246 - reg.target_category, id.target_category, id.instance, entry->refcount); 2235 + ssam_dbg(ctrl, "%s event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", 2236 + ec ? "disabling" : "detaching", reg.target_category, id.target_category, 2237 + id.instance, entry->refcount); 2247 2238 2248 2239 if (entry->flags != flags) { 2249 2240 ssam_warn(ctrl, ··· 2253 2242 id.instance); 2254 2243 } 2255 2244 2256 - if (entry->refcount == 0) { 2245 + if (ec && entry->refcount == 0) { 2257 2246 status = ssam_ssh_event_disable(ctrl, reg, id, flags); 2258 2247 kfree(entry); 2259 2248 } ··· 2333 2322 EXPORT_SYMBOL_GPL(ssam_notifier_register); 2334 2323 2335 2324 /** 2336 - * ssam_notifier_unregister() - Unregister an event notifier. 2337 - * @ctrl: The controller the notifier has been registered on. 2338 - * @n: The event notifier to unregister. 2325 + * __ssam_notifier_unregister() - Unregister an event notifier. 2326 + * @ctrl: The controller the notifier has been registered on. 2327 + * @n: The event notifier to unregister. 2328 + * @disable: Whether to disable the corresponding event on the EC. 2339 2329 * 2340 2330 * Unregister an event notifier. Decrement the usage counter of the associated 2341 2331 * SAM event if the notifier is not marked as an observer. If the usage counter 2342 - * reaches zero, the event will be disabled. 2332 + * reaches zero and ``disable`` equals ``true``, the event will be disabled. 2333 + * 2334 + * Useful for hot-removable devices, where communication may fail once the 2335 + * device has been physically removed. In that case, specifying ``disable`` as 2336 + * ``false`` avoids communication with the EC. 2343 2337 * 2344 2338 * Return: Returns zero on success, %-ENOENT if the given notifier block has 2345 2339 * not been registered on the controller. If the given notifier block was the 2346 2340 * last one associated with its specific event, returns the status of the 2347 2341 * event-disable EC-command. 2348 2342 */ 2349 - int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n) 2343 + int __ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n, 2344 + bool disable) 2350 2345 { 2351 2346 u16 rqid = ssh_tc_to_rqid(n->event.id.target_category); 2352 2347 struct ssam_nf_refcount_entry *entry; ··· 2390 2373 goto remove; 2391 2374 } 2392 2375 2393 - status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags); 2376 + status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags, disable); 2394 2377 } 2395 2378 2396 2379 remove: ··· 2400 2383 2401 2384 return status; 2402 2385 } 2403 - EXPORT_SYMBOL_GPL(ssam_notifier_unregister); 2386 + EXPORT_SYMBOL_GPL(__ssam_notifier_unregister); 2404 2387 2405 2388 /** 2406 2389 * ssam_controller_event_enable() - Enable the specified event. ··· 2494 2477 return -ENOENT; 2495 2478 } 2496 2479 2497 - status = ssam_nf_refcount_disable_free(ctrl, entry, flags); 2480 + status = ssam_nf_refcount_disable_free(ctrl, entry, flags, true); 2498 2481 2499 2482 mutex_unlock(&nf->lock); 2500 2483 return status;
+1 -1
drivers/platform/surface/aggregator/controller.h
··· 2 2 /* 3 3 * Main SSAM/SSH controller structure and functionality. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #ifndef _SURFACE_AGGREGATOR_CONTROLLER_H
+1 -1
drivers/platform/surface/aggregator/core.c
··· 7 7 * Handles communication via requests as well as enabling, disabling, and 8 8 * relaying of events. 9 9 * 10 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 10 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 11 11 */ 12 12 13 13 #include <linux/acpi.h>
+1 -1
drivers/platform/surface/aggregator/ssh_msgb.h
··· 2 2 /* 3 3 * SSH message builder functions. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
+1 -1
drivers/platform/surface/aggregator/ssh_packet_layer.c
··· 2 2 /* 3 3 * SSH packet transport layer. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #include <asm/unaligned.h>
+1 -1
drivers/platform/surface/aggregator/ssh_packet_layer.h
··· 2 2 /* 3 3 * SSH packet transport layer. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H
+1 -1
drivers/platform/surface/aggregator/ssh_parser.c
··· 2 2 /* 3 3 * SSH message parser. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #include <asm/unaligned.h>
+1 -1
drivers/platform/surface/aggregator/ssh_parser.h
··· 2 2 /* 3 3 * SSH message parser. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #ifndef _SURFACE_AGGREGATOR_SSH_PARSER_H
+1 -1
drivers/platform/surface/aggregator/ssh_request_layer.c
··· 2 2 /* 3 3 * SSH request transport layer. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #include <asm/unaligned.h>
+1 -1
drivers/platform/surface/aggregator/ssh_request_layer.h
··· 2 2 /* 3 3 * SSH request transport layer. 4 4 * 5 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H
+46 -36
drivers/platform/surface/aggregator/trace.h
··· 2 2 /* 3 3 * Trace points for SSAM/SSH. 4 4 * 5 - * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com> 5 + * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 6 */ 7 7 8 8 #undef TRACE_SYSTEM ··· 76 76 TRACE_DEFINE_ENUM(SSAM_SSH_TC_TCH); 77 77 TRACE_DEFINE_ENUM(SSAM_SSH_TC_BKL); 78 78 TRACE_DEFINE_ENUM(SSAM_SSH_TC_TAM); 79 - TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC); 79 + TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC0); 80 80 TRACE_DEFINE_ENUM(SSAM_SSH_TC_UFI); 81 81 TRACE_DEFINE_ENUM(SSAM_SSH_TC_USC); 82 82 TRACE_DEFINE_ENUM(SSAM_SSH_TC_PEN); ··· 85 85 TRACE_DEFINE_ENUM(SSAM_SSH_TC_SMC); 86 86 TRACE_DEFINE_ENUM(SSAM_SSH_TC_KPD); 87 87 TRACE_DEFINE_ENUM(SSAM_SSH_TC_REG); 88 + TRACE_DEFINE_ENUM(SSAM_SSH_TC_SPT); 89 + TRACE_DEFINE_ENUM(SSAM_SSH_TC_SYS); 90 + TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC1); 91 + TRACE_DEFINE_ENUM(SSAM_SSH_TC_SHB); 92 + TRACE_DEFINE_ENUM(SSAM_SSH_TC_POS); 88 93 89 94 #define SSAM_PTR_UID_LEN 9 90 95 #define SSAM_U8_FIELD_NOT_APPLICABLE ((u16)-1) ··· 234 229 235 230 #define ssam_show_ssh_tc(rqid) \ 236 231 __print_symbolic(rqid, \ 237 - { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \ 238 - { SSAM_SSH_TC_SAM, "SAM" }, \ 239 - { SSAM_SSH_TC_BAT, "BAT" }, \ 240 - { SSAM_SSH_TC_TMP, "TMP" }, \ 241 - { SSAM_SSH_TC_PMC, "PMC" }, \ 242 - { SSAM_SSH_TC_FAN, "FAN" }, \ 243 - { SSAM_SSH_TC_PoM, "PoM" }, \ 244 - { SSAM_SSH_TC_DBG, "DBG" }, \ 245 - { SSAM_SSH_TC_KBD, "KBD" }, \ 246 - { SSAM_SSH_TC_FWU, "FWU" }, \ 247 - { SSAM_SSH_TC_UNI, "UNI" }, \ 248 - { SSAM_SSH_TC_LPC, "LPC" }, \ 249 - { SSAM_SSH_TC_TCL, "TCL" }, \ 250 - { SSAM_SSH_TC_SFL, "SFL" }, \ 251 - { SSAM_SSH_TC_KIP, "KIP" }, \ 252 - { SSAM_SSH_TC_EXT, "EXT" }, \ 253 - { SSAM_SSH_TC_BLD, "BLD" }, \ 254 - { SSAM_SSH_TC_BAS, "BAS" }, \ 255 - { SSAM_SSH_TC_SEN, "SEN" }, \ 256 - { SSAM_SSH_TC_SRQ, "SRQ" }, \ 257 - { SSAM_SSH_TC_MCU, "MCU" }, \ 258 - { SSAM_SSH_TC_HID, "HID" }, \ 259 - { SSAM_SSH_TC_TCH, "TCH" }, \ 260 - { SSAM_SSH_TC_BKL, "BKL" }, \ 261 - { SSAM_SSH_TC_TAM, "TAM" }, \ 262 - { SSAM_SSH_TC_ACC, "ACC" }, \ 263 - { SSAM_SSH_TC_UFI, "UFI" }, \ 264 - { SSAM_SSH_TC_USC, "USC" }, \ 265 - { SSAM_SSH_TC_PEN, "PEN" }, \ 266 - { SSAM_SSH_TC_VID, "VID" }, \ 267 - { SSAM_SSH_TC_AUD, "AUD" }, \ 268 - { SSAM_SSH_TC_SMC, "SMC" }, \ 269 - { SSAM_SSH_TC_KPD, "KPD" }, \ 270 - { SSAM_SSH_TC_REG, "REG" } \ 232 + { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \ 233 + { SSAM_SSH_TC_SAM, "SAM" }, \ 234 + { SSAM_SSH_TC_BAT, "BAT" }, \ 235 + { SSAM_SSH_TC_TMP, "TMP" }, \ 236 + { SSAM_SSH_TC_PMC, "PMC" }, \ 237 + { SSAM_SSH_TC_FAN, "FAN" }, \ 238 + { SSAM_SSH_TC_PoM, "PoM" }, \ 239 + { SSAM_SSH_TC_DBG, "DBG" }, \ 240 + { SSAM_SSH_TC_KBD, "KBD" }, \ 241 + { SSAM_SSH_TC_FWU, "FWU" }, \ 242 + { SSAM_SSH_TC_UNI, "UNI" }, \ 243 + { SSAM_SSH_TC_LPC, "LPC" }, \ 244 + { SSAM_SSH_TC_TCL, "TCL" }, \ 245 + { SSAM_SSH_TC_SFL, "SFL" }, \ 246 + { SSAM_SSH_TC_KIP, "KIP" }, \ 247 + { SSAM_SSH_TC_EXT, "EXT" }, \ 248 + { SSAM_SSH_TC_BLD, "BLD" }, \ 249 + { SSAM_SSH_TC_BAS, "BAS" }, \ 250 + { SSAM_SSH_TC_SEN, "SEN" }, \ 251 + { SSAM_SSH_TC_SRQ, "SRQ" }, \ 252 + { SSAM_SSH_TC_MCU, "MCU" }, \ 253 + { SSAM_SSH_TC_HID, "HID" }, \ 254 + { SSAM_SSH_TC_TCH, "TCH" }, \ 255 + { SSAM_SSH_TC_BKL, "BKL" }, \ 256 + { SSAM_SSH_TC_TAM, "TAM" }, \ 257 + { SSAM_SSH_TC_ACC0, "ACC0" }, \ 258 + { SSAM_SSH_TC_UFI, "UFI" }, \ 259 + { SSAM_SSH_TC_USC, "USC" }, \ 260 + { SSAM_SSH_TC_PEN, "PEN" }, \ 261 + { SSAM_SSH_TC_VID, "VID" }, \ 262 + { SSAM_SSH_TC_AUD, "AUD" }, \ 263 + { SSAM_SSH_TC_SMC, "SMC" }, \ 264 + { SSAM_SSH_TC_KPD, "KPD" }, \ 265 + { SSAM_SSH_TC_REG, "REG" }, \ 266 + { SSAM_SSH_TC_SPT, "SPT" }, \ 267 + { SSAM_SSH_TC_SYS, "SYS" }, \ 268 + { SSAM_SSH_TC_ACC1, "ACC1" }, \ 269 + { SSAM_SSH_TC_SHB, "SMB" }, \ 270 + { SSAM_SSH_TC_POS, "POS" } \ 271 271 ) 272 272 273 273 DECLARE_EVENT_CLASS(ssam_frame_class,
+25 -4
drivers/platform/surface/surface_acpi_notify.c
··· 8 8 * notifications sent from ACPI via the SAN interface by providing them to any 9 9 * registered external driver. 10 10 * 11 - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> 11 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 12 12 */ 13 13 14 14 #include <asm/unaligned.h> ··· 37 37 #define to_san_data(ptr, member) \ 38 38 container_of(ptr, struct san_data, member) 39 39 40 + static struct workqueue_struct *san_wq; 40 41 41 42 /* -- dGPU notifier interface. ---------------------------------------------- */ 42 43 ··· 357 356 358 357 memcpy(&work->event, event, sizeof(struct ssam_event) + event->length); 359 358 360 - schedule_delayed_work(&work->work, delay); 359 + queue_delayed_work(san_wq, &work->work, delay); 361 360 return SSAM_NOTIF_HANDLED; 362 361 } 363 362 ··· 862 861 * We have unregistered our event sources. Now we need to ensure that 863 862 * all delayed works they may have spawned are run to completion. 864 863 */ 865 - flush_scheduled_work(); 864 + flush_workqueue(san_wq); 866 865 867 866 return 0; 868 867 } ··· 882 881 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 883 882 }, 884 883 }; 885 - module_platform_driver(surface_acpi_notify); 884 + 885 + static int __init san_init(void) 886 + { 887 + int ret; 888 + 889 + san_wq = alloc_workqueue("san_wq", 0, 0); 890 + if (!san_wq) 891 + return -ENOMEM; 892 + ret = platform_driver_register(&surface_acpi_notify); 893 + if (ret) 894 + destroy_workqueue(san_wq); 895 + return ret; 896 + } 897 + module_init(san_init); 898 + 899 + static void __exit san_exit(void) 900 + { 901 + platform_driver_unregister(&surface_acpi_notify); 902 + destroy_workqueue(san_wq); 903 + } 904 + module_exit(san_exit); 886 905 887 906 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); 888 907 MODULE_DESCRIPTION("Surface ACPI Notify driver for Surface System Aggregator Module");
+1 -1
drivers/platform/surface/surface_aggregator_cdev.c
··· 3 3 * Provides user-space access to the SSAM EC via the /dev/surface/aggregator 4 4 * misc device. Intended for debugging and development. 5 5 * 6 - * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com> 6 + * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com> 7 7 */ 8 8 9 9 #include <linux/fs.h>
+371
drivers/platform/surface/surface_aggregator_hub.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Driver for Surface System Aggregator Module (SSAM) subsystem device hubs. 4 + * 5 + * Provides a driver for SSAM subsystems device hubs. This driver performs 6 + * instantiation of the devices managed by said hubs and takes care of 7 + * (hot-)removal. 8 + * 9 + * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com> 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/limits.h> 14 + #include <linux/module.h> 15 + #include <linux/types.h> 16 + #include <linux/workqueue.h> 17 + 18 + #include <linux/surface_aggregator/device.h> 19 + 20 + 21 + /* -- SSAM generic subsystem hub driver framework. -------------------------- */ 22 + 23 + enum ssam_hub_state { 24 + SSAM_HUB_UNINITIALIZED, /* Only set during initialization. */ 25 + SSAM_HUB_CONNECTED, 26 + SSAM_HUB_DISCONNECTED, 27 + }; 28 + 29 + enum ssam_hub_flags { 30 + SSAM_HUB_HOT_REMOVED, 31 + }; 32 + 33 + struct ssam_hub; 34 + 35 + struct ssam_hub_ops { 36 + int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state); 37 + }; 38 + 39 + struct ssam_hub { 40 + struct ssam_device *sdev; 41 + 42 + enum ssam_hub_state state; 43 + unsigned long flags; 44 + 45 + struct delayed_work update_work; 46 + unsigned long connect_delay; 47 + 48 + struct ssam_event_notifier notif; 49 + struct ssam_hub_ops ops; 50 + }; 51 + 52 + struct ssam_hub_desc { 53 + struct { 54 + struct ssam_event_registry reg; 55 + struct ssam_event_id id; 56 + enum ssam_event_mask mask; 57 + } event; 58 + 59 + struct { 60 + u32 (*notify)(struct ssam_event_notifier *nf, const struct ssam_event *event); 61 + int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state); 62 + } ops; 63 + 64 + unsigned long connect_delay_ms; 65 + }; 66 + 67 + static void ssam_hub_update_workfn(struct work_struct *work) 68 + { 69 + struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work); 70 + enum ssam_hub_state state; 71 + int status = 0; 72 + 73 + status = hub->ops.get_state(hub, &state); 74 + if (status) 75 + return; 76 + 77 + /* 78 + * There is a small possibility that hub devices were hot-removed and 79 + * re-added before we were able to remove them here. In that case, both 80 + * the state returned by get_state() and the state of the hub will 81 + * equal SSAM_HUB_CONNECTED and we would bail early below, which would 82 + * leave child devices without proper (re-)initialization and the 83 + * hot-remove flag set. 84 + * 85 + * Therefore, we check whether devices have been hot-removed via an 86 + * additional flag on the hub and, in this case, override the returned 87 + * hub state. In case of a missed disconnect (i.e. get_state returned 88 + * "connected"), we further need to re-schedule this work (with the 89 + * appropriate delay) as the actual connect work submission might have 90 + * been merged with this one. 91 + * 92 + * This then leads to one of two cases: Either we submit an unnecessary 93 + * work item (which will get ignored via either the queue or the state 94 + * checks) or, in the unlikely case that the work is actually required, 95 + * double the normal connect delay. 96 + */ 97 + if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) { 98 + if (state == SSAM_HUB_CONNECTED) 99 + schedule_delayed_work(&hub->update_work, hub->connect_delay); 100 + 101 + state = SSAM_HUB_DISCONNECTED; 102 + } 103 + 104 + if (hub->state == state) 105 + return; 106 + hub->state = state; 107 + 108 + if (hub->state == SSAM_HUB_CONNECTED) 109 + status = ssam_device_register_clients(hub->sdev); 110 + else 111 + ssam_remove_clients(&hub->sdev->dev); 112 + 113 + if (status) 114 + dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status); 115 + } 116 + 117 + static int ssam_hub_mark_hot_removed(struct device *dev, void *_data) 118 + { 119 + struct ssam_device *sdev = to_ssam_device(dev); 120 + 121 + if (is_ssam_device(dev)) 122 + ssam_device_mark_hot_removed(sdev); 123 + 124 + return 0; 125 + } 126 + 127 + static void ssam_hub_update(struct ssam_hub *hub, bool connected) 128 + { 129 + unsigned long delay; 130 + 131 + /* Mark devices as hot-removed before we remove any. */ 132 + if (!connected) { 133 + set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags); 134 + device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed); 135 + } 136 + 137 + /* 138 + * Delay update when the base/keyboard cover is being connected to give 139 + * devices/EC some time to set up. 140 + */ 141 + delay = connected ? hub->connect_delay : 0; 142 + 143 + schedule_delayed_work(&hub->update_work, delay); 144 + } 145 + 146 + static int __maybe_unused ssam_hub_resume(struct device *dev) 147 + { 148 + struct ssam_hub *hub = dev_get_drvdata(dev); 149 + 150 + schedule_delayed_work(&hub->update_work, 0); 151 + return 0; 152 + } 153 + static SIMPLE_DEV_PM_OPS(ssam_hub_pm_ops, NULL, ssam_hub_resume); 154 + 155 + static int ssam_hub_probe(struct ssam_device *sdev) 156 + { 157 + const struct ssam_hub_desc *desc; 158 + struct ssam_hub *hub; 159 + int status; 160 + 161 + desc = ssam_device_get_match_data(sdev); 162 + if (!desc) { 163 + WARN(1, "no driver match data specified"); 164 + return -EINVAL; 165 + } 166 + 167 + hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); 168 + if (!hub) 169 + return -ENOMEM; 170 + 171 + hub->sdev = sdev; 172 + hub->state = SSAM_HUB_UNINITIALIZED; 173 + 174 + hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ 175 + hub->notif.base.fn = desc->ops.notify; 176 + hub->notif.event.reg = desc->event.reg; 177 + hub->notif.event.id = desc->event.id; 178 + hub->notif.event.mask = desc->event.mask; 179 + hub->notif.event.flags = SSAM_EVENT_SEQUENCED; 180 + 181 + hub->connect_delay = msecs_to_jiffies(desc->connect_delay_ms); 182 + hub->ops.get_state = desc->ops.get_state; 183 + 184 + INIT_DELAYED_WORK(&hub->update_work, ssam_hub_update_workfn); 185 + 186 + ssam_device_set_drvdata(sdev, hub); 187 + 188 + status = ssam_device_notifier_register(sdev, &hub->notif); 189 + if (status) 190 + return status; 191 + 192 + schedule_delayed_work(&hub->update_work, 0); 193 + return 0; 194 + } 195 + 196 + static void ssam_hub_remove(struct ssam_device *sdev) 197 + { 198 + struct ssam_hub *hub = ssam_device_get_drvdata(sdev); 199 + 200 + ssam_device_notifier_unregister(sdev, &hub->notif); 201 + cancel_delayed_work_sync(&hub->update_work); 202 + ssam_remove_clients(&sdev->dev); 203 + } 204 + 205 + 206 + /* -- SSAM base-subsystem hub driver. --------------------------------------- */ 207 + 208 + /* 209 + * Some devices (especially battery) may need a bit of time to be fully usable 210 + * after being (re-)connected. This delay has been determined via 211 + * experimentation. 212 + */ 213 + #define SSAM_BASE_UPDATE_CONNECT_DELAY 2500 214 + 215 + SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { 216 + .target_category = SSAM_SSH_TC_BAS, 217 + .target_id = 0x01, 218 + .command_id = 0x0d, 219 + .instance_id = 0x00, 220 + }); 221 + 222 + #define SSAM_BAS_OPMODE_TABLET 0x00 223 + #define SSAM_EVENT_BAS_CID_CONNECTION 0x0c 224 + 225 + static int ssam_base_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state) 226 + { 227 + u8 opmode; 228 + int status; 229 + 230 + status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode); 231 + if (status < 0) { 232 + dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status); 233 + return status; 234 + } 235 + 236 + if (opmode != SSAM_BAS_OPMODE_TABLET) 237 + *state = SSAM_HUB_CONNECTED; 238 + else 239 + *state = SSAM_HUB_DISCONNECTED; 240 + 241 + return 0; 242 + } 243 + 244 + static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) 245 + { 246 + struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); 247 + 248 + if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION) 249 + return 0; 250 + 251 + if (event->length < 1) { 252 + dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); 253 + return 0; 254 + } 255 + 256 + ssam_hub_update(hub, event->data[0]); 257 + 258 + /* 259 + * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and 260 + * consumed by the detachment system driver. We're just a (more or less) 261 + * silent observer. 262 + */ 263 + return 0; 264 + } 265 + 266 + static const struct ssam_hub_desc base_hub = { 267 + .event = { 268 + .reg = SSAM_EVENT_REGISTRY_SAM, 269 + .id = { 270 + .target_category = SSAM_SSH_TC_BAS, 271 + .instance = 0, 272 + }, 273 + .mask = SSAM_EVENT_MASK_NONE, 274 + }, 275 + .ops = { 276 + .notify = ssam_base_hub_notif, 277 + .get_state = ssam_base_hub_query_state, 278 + }, 279 + .connect_delay_ms = SSAM_BASE_UPDATE_CONNECT_DELAY, 280 + }; 281 + 282 + 283 + /* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */ 284 + 285 + /* 286 + * Some devices may need a bit of time to be fully usable after being 287 + * (re-)connected. This delay has been determined via experimentation. 288 + */ 289 + #define SSAM_KIP_UPDATE_CONNECT_DELAY 250 290 + 291 + #define SSAM_EVENT_KIP_CID_CONNECTION 0x2c 292 + 293 + SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_query_state, u8, { 294 + .target_category = SSAM_SSH_TC_KIP, 295 + .target_id = 0x01, 296 + .command_id = 0x2c, 297 + .instance_id = 0x00, 298 + }); 299 + 300 + static int ssam_kip_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state) 301 + { 302 + int status; 303 + u8 connected; 304 + 305 + status = ssam_retry(__ssam_kip_query_state, hub->sdev->ctrl, &connected); 306 + if (status < 0) { 307 + dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status); 308 + return status; 309 + } 310 + 311 + *state = connected ? SSAM_HUB_CONNECTED : SSAM_HUB_DISCONNECTED; 312 + return 0; 313 + } 314 + 315 + static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) 316 + { 317 + struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); 318 + 319 + if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION) 320 + return 0; /* Return "unhandled". */ 321 + 322 + if (event->length < 1) { 323 + dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); 324 + return 0; 325 + } 326 + 327 + ssam_hub_update(hub, event->data[0]); 328 + return SSAM_NOTIF_HANDLED; 329 + } 330 + 331 + static const struct ssam_hub_desc kip_hub = { 332 + .event = { 333 + .reg = SSAM_EVENT_REGISTRY_SAM, 334 + .id = { 335 + .target_category = SSAM_SSH_TC_KIP, 336 + .instance = 0, 337 + }, 338 + .mask = SSAM_EVENT_MASK_TARGET, 339 + }, 340 + .ops = { 341 + .notify = ssam_kip_hub_notif, 342 + .get_state = ssam_kip_hub_query_state, 343 + }, 344 + .connect_delay_ms = SSAM_KIP_UPDATE_CONNECT_DELAY, 345 + }; 346 + 347 + 348 + /* -- Driver registration. -------------------------------------------------- */ 349 + 350 + static const struct ssam_device_id ssam_hub_match[] = { 351 + { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub }, 352 + { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub }, 353 + { } 354 + }; 355 + MODULE_DEVICE_TABLE(ssam, ssam_hub_match); 356 + 357 + static struct ssam_device_driver ssam_subsystem_hub_driver = { 358 + .probe = ssam_hub_probe, 359 + .remove = ssam_hub_remove, 360 + .match_table = ssam_hub_match, 361 + .driver = { 362 + .name = "surface_aggregator_subsystem_hub", 363 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 364 + .pm = &ssam_hub_pm_ops, 365 + }, 366 + }; 367 + module_ssam_device_driver(ssam_subsystem_hub_driver); 368 + 369 + MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); 370 + MODULE_DESCRIPTION("Subsystem device hub driver for Surface System Aggregator Module"); 371 + MODULE_LICENSE("GPL");
+53 -309
drivers/platform/surface/surface_aggregator_registry.c
··· 6 6 * cannot be auto-detected. Provides device-hubs and performs instantiation 7 7 * for these devices. 8 8 * 9 - * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com> 9 + * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com> 10 10 */ 11 11 12 12 #include <linux/acpi.h> 13 13 #include <linux/kernel.h> 14 - #include <linux/limits.h> 15 14 #include <linux/module.h> 16 15 #include <linux/platform_device.h> 17 16 #include <linux/property.h> 18 17 #include <linux/types.h> 19 - #include <linux/workqueue.h> 20 18 21 - #include <linux/surface_aggregator/controller.h> 22 19 #include <linux/surface_aggregator/device.h> 23 20 24 21 ··· 38 41 .name = "ssam_platform_hub", 39 42 }; 40 43 44 + /* KIP device hub (connects keyboard cover devices on Surface Pro 8). */ 45 + static const struct software_node ssam_node_hub_kip = { 46 + .name = "ssam:00:00:01:0e:00", 47 + .parent = &ssam_node_root, 48 + }; 49 + 41 50 /* Base device hub (devices attached to Surface Book 3 base). */ 42 51 static const struct software_node ssam_node_hub_base = { 43 - .name = "ssam:00:00:02:00:00", 52 + .name = "ssam:00:00:02:11:00", 44 53 .parent = &ssam_node_root, 45 54 }; 46 55 ··· 71 68 /* Platform profile / performance-mode device. */ 72 69 static const struct software_node ssam_node_tmp_pprof = { 73 70 .name = "ssam:01:03:01:00:01", 71 + .parent = &ssam_node_root, 72 + }; 73 + 74 + /* Tablet-mode switch via KIP subsystem. */ 75 + static const struct software_node ssam_node_kip_tablet_switch = { 76 + .name = "ssam:01:0e:01:00:01", 74 77 .parent = &ssam_node_root, 75 78 }; 76 79 ··· 164 155 .parent = &ssam_node_hub_base, 165 156 }; 166 157 158 + /* HID keyboard (KIP hub). */ 159 + static const struct software_node ssam_node_hid_kip_keyboard = { 160 + .name = "ssam:01:15:02:01:00", 161 + .parent = &ssam_node_hub_kip, 162 + }; 163 + 164 + /* HID pen stash (KIP hub; pen taken / stashed away evens). */ 165 + static const struct software_node ssam_node_hid_kip_penstash = { 166 + .name = "ssam:01:15:02:02:00", 167 + .parent = &ssam_node_hub_kip, 168 + }; 169 + 170 + /* HID touchpad (KIP hub). */ 171 + static const struct software_node ssam_node_hid_kip_touchpad = { 172 + .name = "ssam:01:15:02:03:00", 173 + .parent = &ssam_node_hub_kip, 174 + }; 175 + 176 + /* HID device instance 5 (KIP hub, unknown HID device). */ 177 + static const struct software_node ssam_node_hid_kip_iid5 = { 178 + .name = "ssam:01:15:02:05:00", 179 + .parent = &ssam_node_hub_kip, 180 + }; 181 + 182 + /* Tablet-mode switch via POS subsystem. */ 183 + static const struct software_node ssam_node_pos_tablet_switch = { 184 + .name = "ssam:01:26:01:00:01", 185 + .parent = &ssam_node_root, 186 + }; 187 + 167 188 /* 168 189 * Devices for 5th- and 6th-generations models: 169 190 * - Surface Book 2, ··· 240 201 &ssam_node_bat_ac, 241 202 &ssam_node_bat_main, 242 203 &ssam_node_tmp_pprof, 204 + &ssam_node_pos_tablet_switch, 243 205 &ssam_node_hid_tid1_keyboard, 244 206 &ssam_node_hid_tid1_penstash, 245 207 &ssam_node_hid_tid1_touchpad, ··· 270 230 271 231 static const struct software_node *ssam_node_group_sp8[] = { 272 232 &ssam_node_root, 233 + &ssam_node_hub_kip, 273 234 &ssam_node_bat_ac, 274 235 &ssam_node_bat_main, 275 236 &ssam_node_tmp_pprof, 276 - /* TODO: Add support for keyboard cover. */ 237 + &ssam_node_kip_tablet_switch, 238 + &ssam_node_hid_kip_keyboard, 239 + &ssam_node_hid_kip_penstash, 240 + &ssam_node_hid_kip_touchpad, 241 + &ssam_node_hid_kip_iid5, 277 242 NULL, 278 - }; 279 - 280 - 281 - /* -- Device registry helper functions. ------------------------------------- */ 282 - 283 - static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid) 284 - { 285 - u8 d, tc, tid, iid, fn; 286 - int n; 287 - 288 - n = sscanf(str, "ssam:%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn); 289 - if (n != 5) 290 - return -EINVAL; 291 - 292 - uid->domain = d; 293 - uid->category = tc; 294 - uid->target = tid; 295 - uid->instance = iid; 296 - uid->function = fn; 297 - 298 - return 0; 299 - } 300 - 301 - static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl, 302 - struct fwnode_handle *node) 303 - { 304 - struct ssam_device_uid uid; 305 - struct ssam_device *sdev; 306 - int status; 307 - 308 - status = ssam_uid_from_string(fwnode_get_name(node), &uid); 309 - if (status) 310 - return status; 311 - 312 - sdev = ssam_device_alloc(ctrl, uid); 313 - if (!sdev) 314 - return -ENOMEM; 315 - 316 - sdev->dev.parent = parent; 317 - sdev->dev.fwnode = node; 318 - 319 - status = ssam_device_add(sdev); 320 - if (status) 321 - ssam_device_put(sdev); 322 - 323 - return status; 324 - } 325 - 326 - static int ssam_hub_register_clients(struct device *parent, struct ssam_controller *ctrl, 327 - struct fwnode_handle *node) 328 - { 329 - struct fwnode_handle *child; 330 - int status; 331 - 332 - fwnode_for_each_child_node(node, child) { 333 - /* 334 - * Try to add the device specified in the firmware node. If 335 - * this fails with -EINVAL, the node does not specify any SSAM 336 - * device, so ignore it and continue with the next one. 337 - */ 338 - 339 - status = ssam_hub_add_device(parent, ctrl, child); 340 - if (status && status != -EINVAL) 341 - goto err; 342 - } 343 - 344 - return 0; 345 - err: 346 - ssam_remove_clients(parent); 347 - return status; 348 - } 349 - 350 - 351 - /* -- SSAM base-hub driver. ------------------------------------------------- */ 352 - 353 - /* 354 - * Some devices (especially battery) may need a bit of time to be fully usable 355 - * after being (re-)connected. This delay has been determined via 356 - * experimentation. 357 - */ 358 - #define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500) 359 - 360 - enum ssam_base_hub_state { 361 - SSAM_BASE_HUB_UNINITIALIZED, 362 - SSAM_BASE_HUB_CONNECTED, 363 - SSAM_BASE_HUB_DISCONNECTED, 364 - }; 365 - 366 - struct ssam_base_hub { 367 - struct ssam_device *sdev; 368 - 369 - enum ssam_base_hub_state state; 370 - struct delayed_work update_work; 371 - 372 - struct ssam_event_notifier notif; 373 - }; 374 - 375 - SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { 376 - .target_category = SSAM_SSH_TC_BAS, 377 - .target_id = 0x01, 378 - .command_id = 0x0d, 379 - .instance_id = 0x00, 380 - }); 381 - 382 - #define SSAM_BAS_OPMODE_TABLET 0x00 383 - #define SSAM_EVENT_BAS_CID_CONNECTION 0x0c 384 - 385 - static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_hub_state *state) 386 - { 387 - u8 opmode; 388 - int status; 389 - 390 - status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode); 391 - if (status < 0) { 392 - dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status); 393 - return status; 394 - } 395 - 396 - if (opmode != SSAM_BAS_OPMODE_TABLET) 397 - *state = SSAM_BASE_HUB_CONNECTED; 398 - else 399 - *state = SSAM_BASE_HUB_DISCONNECTED; 400 - 401 - return 0; 402 - } 403 - 404 - static ssize_t ssam_base_hub_state_show(struct device *dev, struct device_attribute *attr, 405 - char *buf) 406 - { 407 - struct ssam_base_hub *hub = dev_get_drvdata(dev); 408 - bool connected = hub->state == SSAM_BASE_HUB_CONNECTED; 409 - 410 - return sysfs_emit(buf, "%d\n", connected); 411 - } 412 - 413 - static struct device_attribute ssam_base_hub_attr_state = 414 - __ATTR(state, 0444, ssam_base_hub_state_show, NULL); 415 - 416 - static struct attribute *ssam_base_hub_attrs[] = { 417 - &ssam_base_hub_attr_state.attr, 418 - NULL, 419 - }; 420 - 421 - static const struct attribute_group ssam_base_hub_group = { 422 - .attrs = ssam_base_hub_attrs, 423 - }; 424 - 425 - static void ssam_base_hub_update_workfn(struct work_struct *work) 426 - { 427 - struct ssam_base_hub *hub = container_of(work, struct ssam_base_hub, update_work.work); 428 - struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev); 429 - enum ssam_base_hub_state state; 430 - int status = 0; 431 - 432 - status = ssam_base_hub_query_state(hub, &state); 433 - if (status) 434 - return; 435 - 436 - if (hub->state == state) 437 - return; 438 - hub->state = state; 439 - 440 - if (hub->state == SSAM_BASE_HUB_CONNECTED) 441 - status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node); 442 - else 443 - ssam_remove_clients(&hub->sdev->dev); 444 - 445 - if (status) 446 - dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status); 447 - } 448 - 449 - static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) 450 - { 451 - struct ssam_base_hub *hub = container_of(nf, struct ssam_base_hub, notif); 452 - unsigned long delay; 453 - 454 - if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION) 455 - return 0; 456 - 457 - if (event->length < 1) { 458 - dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); 459 - return 0; 460 - } 461 - 462 - /* 463 - * Delay update when the base is being connected to give devices/EC 464 - * some time to set up. 465 - */ 466 - delay = event->data[0] ? SSAM_BASE_UPDATE_CONNECT_DELAY : 0; 467 - 468 - schedule_delayed_work(&hub->update_work, delay); 469 - 470 - /* 471 - * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and 472 - * consumed by the detachment system driver. We're just a (more or less) 473 - * silent observer. 474 - */ 475 - return 0; 476 - } 477 - 478 - static int __maybe_unused ssam_base_hub_resume(struct device *dev) 479 - { 480 - struct ssam_base_hub *hub = dev_get_drvdata(dev); 481 - 482 - schedule_delayed_work(&hub->update_work, 0); 483 - return 0; 484 - } 485 - static SIMPLE_DEV_PM_OPS(ssam_base_hub_pm_ops, NULL, ssam_base_hub_resume); 486 - 487 - static int ssam_base_hub_probe(struct ssam_device *sdev) 488 - { 489 - struct ssam_base_hub *hub; 490 - int status; 491 - 492 - hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); 493 - if (!hub) 494 - return -ENOMEM; 495 - 496 - hub->sdev = sdev; 497 - hub->state = SSAM_BASE_HUB_UNINITIALIZED; 498 - 499 - hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ 500 - hub->notif.base.fn = ssam_base_hub_notif; 501 - hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; 502 - hub->notif.event.id.target_category = SSAM_SSH_TC_BAS, 503 - hub->notif.event.id.instance = 0, 504 - hub->notif.event.mask = SSAM_EVENT_MASK_NONE; 505 - hub->notif.event.flags = SSAM_EVENT_SEQUENCED; 506 - 507 - INIT_DELAYED_WORK(&hub->update_work, ssam_base_hub_update_workfn); 508 - 509 - ssam_device_set_drvdata(sdev, hub); 510 - 511 - status = ssam_notifier_register(sdev->ctrl, &hub->notif); 512 - if (status) 513 - return status; 514 - 515 - status = sysfs_create_group(&sdev->dev.kobj, &ssam_base_hub_group); 516 - if (status) 517 - goto err; 518 - 519 - schedule_delayed_work(&hub->update_work, 0); 520 - return 0; 521 - 522 - err: 523 - ssam_notifier_unregister(sdev->ctrl, &hub->notif); 524 - cancel_delayed_work_sync(&hub->update_work); 525 - ssam_remove_clients(&sdev->dev); 526 - return status; 527 - } 528 - 529 - static void ssam_base_hub_remove(struct ssam_device *sdev) 530 - { 531 - struct ssam_base_hub *hub = ssam_device_get_drvdata(sdev); 532 - 533 - sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group); 534 - 535 - ssam_notifier_unregister(sdev->ctrl, &hub->notif); 536 - cancel_delayed_work_sync(&hub->update_work); 537 - ssam_remove_clients(&sdev->dev); 538 - } 539 - 540 - static const struct ssam_device_id ssam_base_hub_match[] = { 541 - { SSAM_VDEV(HUB, 0x02, SSAM_ANY_IID, 0x00) }, 542 - { }, 543 - }; 544 - 545 - static struct ssam_device_driver ssam_base_hub_driver = { 546 - .probe = ssam_base_hub_probe, 547 - .remove = ssam_base_hub_remove, 548 - .match_table = ssam_base_hub_match, 549 - .driver = { 550 - .name = "surface_aggregator_base_hub", 551 - .probe_type = PROBE_PREFER_ASYNCHRONOUS, 552 - .pm = &ssam_base_hub_pm_ops, 553 - }, 554 243 }; 555 244 556 245 ··· 366 597 367 598 set_secondary_fwnode(&pdev->dev, root); 368 599 369 - status = ssam_hub_register_clients(&pdev->dev, ctrl, root); 600 + status = __ssam_register_clients(&pdev->dev, ctrl, root); 370 601 if (status) { 371 602 set_secondary_fwnode(&pdev->dev, NULL); 372 603 software_node_unregister_node_group(nodes); ··· 395 626 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 396 627 }, 397 628 }; 398 - 399 - 400 - /* -- Module initialization. ------------------------------------------------ */ 401 - 402 - static int __init ssam_device_hub_init(void) 403 - { 404 - int status; 405 - 406 - status = platform_driver_register(&ssam_platform_hub_driver); 407 - if (status) 408 - return status; 409 - 410 - status = ssam_device_driver_register(&ssam_base_hub_driver); 411 - if (status) 412 - platform_driver_unregister(&ssam_platform_hub_driver); 413 - 414 - return status; 415 - } 416 - module_init(ssam_device_hub_init); 417 - 418 - static void __exit ssam_device_hub_exit(void) 419 - { 420 - ssam_device_driver_unregister(&ssam_base_hub_driver); 421 - platform_driver_unregister(&ssam_platform_hub_driver); 422 - } 423 - module_exit(ssam_device_hub_exit); 629 + module_platform_driver(ssam_platform_hub_driver); 424 630 425 631 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); 426 632 MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module");
+533
drivers/platform/surface/surface_aggregator_tabletsw.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Surface System Aggregator Module (SSAM) tablet mode switch driver. 4 + * 5 + * Copyright (C) 2022 Maximilian Luz <luzmaximilian@gmail.com> 6 + */ 7 + 8 + #include <asm/unaligned.h> 9 + #include <linux/input.h> 10 + #include <linux/kernel.h> 11 + #include <linux/module.h> 12 + #include <linux/types.h> 13 + #include <linux/workqueue.h> 14 + 15 + #include <linux/surface_aggregator/controller.h> 16 + #include <linux/surface_aggregator/device.h> 17 + 18 + 19 + /* -- SSAM generic tablet switch driver framework. -------------------------- */ 20 + 21 + struct ssam_tablet_sw; 22 + 23 + struct ssam_tablet_sw_ops { 24 + int (*get_state)(struct ssam_tablet_sw *sw, u32 *state); 25 + const char *(*state_name)(struct ssam_tablet_sw *sw, u32 state); 26 + bool (*state_is_tablet_mode)(struct ssam_tablet_sw *sw, u32 state); 27 + }; 28 + 29 + struct ssam_tablet_sw { 30 + struct ssam_device *sdev; 31 + 32 + u32 state; 33 + struct work_struct update_work; 34 + struct input_dev *mode_switch; 35 + 36 + struct ssam_tablet_sw_ops ops; 37 + struct ssam_event_notifier notif; 38 + }; 39 + 40 + struct ssam_tablet_sw_desc { 41 + struct { 42 + const char *name; 43 + const char *phys; 44 + } dev; 45 + 46 + struct { 47 + u32 (*notify)(struct ssam_event_notifier *nf, const struct ssam_event *event); 48 + int (*get_state)(struct ssam_tablet_sw *sw, u32 *state); 49 + const char *(*state_name)(struct ssam_tablet_sw *sw, u32 state); 50 + bool (*state_is_tablet_mode)(struct ssam_tablet_sw *sw, u32 state); 51 + } ops; 52 + 53 + struct { 54 + struct ssam_event_registry reg; 55 + struct ssam_event_id id; 56 + enum ssam_event_mask mask; 57 + u8 flags; 58 + } event; 59 + }; 60 + 61 + static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) 62 + { 63 + struct ssam_tablet_sw *sw = dev_get_drvdata(dev); 64 + const char *state = sw->ops.state_name(sw, sw->state); 65 + 66 + return sysfs_emit(buf, "%s\n", state); 67 + } 68 + static DEVICE_ATTR_RO(state); 69 + 70 + static struct attribute *ssam_tablet_sw_attrs[] = { 71 + &dev_attr_state.attr, 72 + NULL, 73 + }; 74 + 75 + static const struct attribute_group ssam_tablet_sw_group = { 76 + .attrs = ssam_tablet_sw_attrs, 77 + }; 78 + 79 + static void ssam_tablet_sw_update_workfn(struct work_struct *work) 80 + { 81 + struct ssam_tablet_sw *sw = container_of(work, struct ssam_tablet_sw, update_work); 82 + int tablet, status; 83 + u32 state; 84 + 85 + status = sw->ops.get_state(sw, &state); 86 + if (status) 87 + return; 88 + 89 + if (sw->state == state) 90 + return; 91 + sw->state = state; 92 + 93 + /* Send SW_TABLET_MODE event. */ 94 + tablet = sw->ops.state_is_tablet_mode(sw, state); 95 + input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); 96 + input_sync(sw->mode_switch); 97 + } 98 + 99 + static int __maybe_unused ssam_tablet_sw_resume(struct device *dev) 100 + { 101 + struct ssam_tablet_sw *sw = dev_get_drvdata(dev); 102 + 103 + schedule_work(&sw->update_work); 104 + return 0; 105 + } 106 + static SIMPLE_DEV_PM_OPS(ssam_tablet_sw_pm_ops, NULL, ssam_tablet_sw_resume); 107 + 108 + static int ssam_tablet_sw_probe(struct ssam_device *sdev) 109 + { 110 + const struct ssam_tablet_sw_desc *desc; 111 + struct ssam_tablet_sw *sw; 112 + int tablet, status; 113 + 114 + desc = ssam_device_get_match_data(sdev); 115 + if (!desc) { 116 + WARN(1, "no driver match data specified"); 117 + return -EINVAL; 118 + } 119 + 120 + sw = devm_kzalloc(&sdev->dev, sizeof(*sw), GFP_KERNEL); 121 + if (!sw) 122 + return -ENOMEM; 123 + 124 + sw->sdev = sdev; 125 + 126 + sw->ops.get_state = desc->ops.get_state; 127 + sw->ops.state_name = desc->ops.state_name; 128 + sw->ops.state_is_tablet_mode = desc->ops.state_is_tablet_mode; 129 + 130 + INIT_WORK(&sw->update_work, ssam_tablet_sw_update_workfn); 131 + 132 + ssam_device_set_drvdata(sdev, sw); 133 + 134 + /* Get initial state. */ 135 + status = sw->ops.get_state(sw, &sw->state); 136 + if (status) 137 + return status; 138 + 139 + /* Set up tablet mode switch. */ 140 + sw->mode_switch = devm_input_allocate_device(&sdev->dev); 141 + if (!sw->mode_switch) 142 + return -ENOMEM; 143 + 144 + sw->mode_switch->name = desc->dev.name; 145 + sw->mode_switch->phys = desc->dev.phys; 146 + sw->mode_switch->id.bustype = BUS_HOST; 147 + sw->mode_switch->dev.parent = &sdev->dev; 148 + 149 + tablet = sw->ops.state_is_tablet_mode(sw, sw->state); 150 + input_set_capability(sw->mode_switch, EV_SW, SW_TABLET_MODE); 151 + input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); 152 + 153 + status = input_register_device(sw->mode_switch); 154 + if (status) 155 + return status; 156 + 157 + /* Set up notifier. */ 158 + sw->notif.base.priority = 0; 159 + sw->notif.base.fn = desc->ops.notify; 160 + sw->notif.event.reg = desc->event.reg; 161 + sw->notif.event.id = desc->event.id; 162 + sw->notif.event.mask = desc->event.mask; 163 + sw->notif.event.flags = SSAM_EVENT_SEQUENCED; 164 + 165 + status = ssam_device_notifier_register(sdev, &sw->notif); 166 + if (status) 167 + return status; 168 + 169 + status = sysfs_create_group(&sdev->dev.kobj, &ssam_tablet_sw_group); 170 + if (status) 171 + goto err; 172 + 173 + /* We might have missed events during setup, so check again. */ 174 + schedule_work(&sw->update_work); 175 + return 0; 176 + 177 + err: 178 + ssam_device_notifier_unregister(sdev, &sw->notif); 179 + cancel_work_sync(&sw->update_work); 180 + return status; 181 + } 182 + 183 + static void ssam_tablet_sw_remove(struct ssam_device *sdev) 184 + { 185 + struct ssam_tablet_sw *sw = ssam_device_get_drvdata(sdev); 186 + 187 + sysfs_remove_group(&sdev->dev.kobj, &ssam_tablet_sw_group); 188 + 189 + ssam_device_notifier_unregister(sdev, &sw->notif); 190 + cancel_work_sync(&sw->update_work); 191 + } 192 + 193 + 194 + /* -- SSAM KIP tablet switch implementation. -------------------------------- */ 195 + 196 + #define SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED 0x1d 197 + 198 + enum ssam_kip_cover_state { 199 + SSAM_KIP_COVER_STATE_DISCONNECTED = 0x01, 200 + SSAM_KIP_COVER_STATE_CLOSED = 0x02, 201 + SSAM_KIP_COVER_STATE_LAPTOP = 0x03, 202 + SSAM_KIP_COVER_STATE_FOLDED_CANVAS = 0x04, 203 + SSAM_KIP_COVER_STATE_FOLDED_BACK = 0x05, 204 + }; 205 + 206 + static const char *ssam_kip_cover_state_name(struct ssam_tablet_sw *sw, u32 state) 207 + { 208 + switch (state) { 209 + case SSAM_KIP_COVER_STATE_DISCONNECTED: 210 + return "disconnected"; 211 + 212 + case SSAM_KIP_COVER_STATE_CLOSED: 213 + return "closed"; 214 + 215 + case SSAM_KIP_COVER_STATE_LAPTOP: 216 + return "laptop"; 217 + 218 + case SSAM_KIP_COVER_STATE_FOLDED_CANVAS: 219 + return "folded-canvas"; 220 + 221 + case SSAM_KIP_COVER_STATE_FOLDED_BACK: 222 + return "folded-back"; 223 + 224 + default: 225 + dev_warn(&sw->sdev->dev, "unknown KIP cover state: %u\n", state); 226 + return "<unknown>"; 227 + } 228 + } 229 + 230 + static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 state) 231 + { 232 + switch (state) { 233 + case SSAM_KIP_COVER_STATE_DISCONNECTED: 234 + case SSAM_KIP_COVER_STATE_FOLDED_CANVAS: 235 + case SSAM_KIP_COVER_STATE_FOLDED_BACK: 236 + return true; 237 + 238 + case SSAM_KIP_COVER_STATE_CLOSED: 239 + case SSAM_KIP_COVER_STATE_LAPTOP: 240 + return false; 241 + 242 + default: 243 + dev_warn(&sw->sdev->dev, "unknown KIP cover state: %d\n", sw->state); 244 + return true; 245 + } 246 + } 247 + 248 + SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_cover_state, u8, { 249 + .target_category = SSAM_SSH_TC_KIP, 250 + .target_id = 0x01, 251 + .command_id = 0x1d, 252 + .instance_id = 0x00, 253 + }); 254 + 255 + static int ssam_kip_get_cover_state(struct ssam_tablet_sw *sw, u32 *state) 256 + { 257 + int status; 258 + u8 raw; 259 + 260 + status = ssam_retry(__ssam_kip_get_cover_state, sw->sdev->ctrl, &raw); 261 + if (status < 0) { 262 + dev_err(&sw->sdev->dev, "failed to query KIP lid state: %d\n", status); 263 + return status; 264 + } 265 + 266 + *state = raw; 267 + return 0; 268 + } 269 + 270 + static u32 ssam_kip_sw_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) 271 + { 272 + struct ssam_tablet_sw *sw = container_of(nf, struct ssam_tablet_sw, notif); 273 + 274 + if (event->command_id != SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED) 275 + return 0; /* Return "unhandled". */ 276 + 277 + if (event->length < 1) 278 + dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length); 279 + 280 + schedule_work(&sw->update_work); 281 + return SSAM_NOTIF_HANDLED; 282 + } 283 + 284 + static const struct ssam_tablet_sw_desc ssam_kip_sw_desc = { 285 + .dev = { 286 + .name = "Microsoft Surface KIP Tablet Mode Switch", 287 + .phys = "ssam/01:0e:01:00:01/input0", 288 + }, 289 + .ops = { 290 + .notify = ssam_kip_sw_notif, 291 + .get_state = ssam_kip_get_cover_state, 292 + .state_name = ssam_kip_cover_state_name, 293 + .state_is_tablet_mode = ssam_kip_cover_state_is_tablet_mode, 294 + }, 295 + .event = { 296 + .reg = SSAM_EVENT_REGISTRY_SAM, 297 + .id = { 298 + .target_category = SSAM_SSH_TC_KIP, 299 + .instance = 0, 300 + }, 301 + .mask = SSAM_EVENT_MASK_TARGET, 302 + }, 303 + }; 304 + 305 + 306 + /* -- SSAM POS tablet switch implementation. -------------------------------- */ 307 + 308 + static bool tablet_mode_in_slate_state = true; 309 + module_param(tablet_mode_in_slate_state, bool, 0644); 310 + MODULE_PARM_DESC(tablet_mode_in_slate_state, "Enable tablet mode in slate device posture, default is 'true'"); 311 + 312 + #define SSAM_EVENT_POS_CID_POSTURE_CHANGED 0x03 313 + #define SSAM_POS_MAX_SOURCES 4 314 + 315 + enum ssam_pos_state { 316 + SSAM_POS_POSTURE_LID_CLOSED = 0x00, 317 + SSAM_POS_POSTURE_LAPTOP = 0x01, 318 + SSAM_POS_POSTURE_SLATE = 0x02, 319 + SSAM_POS_POSTURE_TABLET = 0x03, 320 + }; 321 + 322 + struct ssam_sources_list { 323 + __le32 count; 324 + __le32 id[SSAM_POS_MAX_SOURCES]; 325 + } __packed; 326 + 327 + static const char *ssam_pos_state_name(struct ssam_tablet_sw *sw, u32 state) 328 + { 329 + switch (state) { 330 + case SSAM_POS_POSTURE_LID_CLOSED: 331 + return "closed"; 332 + 333 + case SSAM_POS_POSTURE_LAPTOP: 334 + return "laptop"; 335 + 336 + case SSAM_POS_POSTURE_SLATE: 337 + return "slate"; 338 + 339 + case SSAM_POS_POSTURE_TABLET: 340 + return "tablet"; 341 + 342 + default: 343 + dev_warn(&sw->sdev->dev, "unknown device posture: %u\n", state); 344 + return "<unknown>"; 345 + } 346 + } 347 + 348 + static bool ssam_pos_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 state) 349 + { 350 + switch (state) { 351 + case SSAM_POS_POSTURE_LAPTOP: 352 + case SSAM_POS_POSTURE_LID_CLOSED: 353 + return false; 354 + 355 + case SSAM_POS_POSTURE_SLATE: 356 + return tablet_mode_in_slate_state; 357 + 358 + case SSAM_POS_POSTURE_TABLET: 359 + return true; 360 + 361 + default: 362 + dev_warn(&sw->sdev->dev, "unknown device posture: %u\n", state); 363 + return true; 364 + } 365 + } 366 + 367 + static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sources_list *sources) 368 + { 369 + struct ssam_request rqst; 370 + struct ssam_response rsp; 371 + int status; 372 + 373 + rqst.target_category = SSAM_SSH_TC_POS; 374 + rqst.target_id = 0x01; 375 + rqst.command_id = 0x01; 376 + rqst.instance_id = 0x00; 377 + rqst.flags = SSAM_REQUEST_HAS_RESPONSE; 378 + rqst.length = 0; 379 + rqst.payload = NULL; 380 + 381 + rsp.capacity = sizeof(*sources); 382 + rsp.length = 0; 383 + rsp.pointer = (u8 *)sources; 384 + 385 + status = ssam_retry(ssam_request_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0); 386 + if (status) 387 + return status; 388 + 389 + /* We need at least the 'sources->count' field. */ 390 + if (rsp.length < sizeof(__le32)) { 391 + dev_err(&sw->sdev->dev, "received source list response is too small\n"); 392 + return -EPROTO; 393 + } 394 + 395 + /* Make sure 'sources->count' matches with the response length. */ 396 + if (get_unaligned_le32(&sources->count) * sizeof(__le32) + sizeof(__le32) != rsp.length) { 397 + dev_err(&sw->sdev->dev, "mismatch between number of sources and response size\n"); 398 + return -EPROTO; 399 + } 400 + 401 + return 0; 402 + } 403 + 404 + static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id) 405 + { 406 + struct ssam_sources_list sources = {}; 407 + int status; 408 + 409 + status = ssam_pos_get_sources_list(sw, &sources); 410 + if (status) 411 + return status; 412 + 413 + if (get_unaligned_le32(&sources.count) == 0) { 414 + dev_err(&sw->sdev->dev, "no posture sources found\n"); 415 + return -ENODEV; 416 + } 417 + 418 + /* 419 + * We currently don't know what to do with more than one posture 420 + * source. At the moment, only one source seems to be used/provided. 421 + * The WARN_ON() here should hopefully let us know quickly once there 422 + * is a device that provides multiple sources, at which point we can 423 + * then try to figure out how to handle them. 424 + */ 425 + WARN_ON(get_unaligned_le32(&sources.count) > 1); 426 + 427 + *source_id = get_unaligned_le32(&sources.id[0]); 428 + return 0; 429 + } 430 + 431 + SSAM_DEFINE_SYNC_REQUEST_WR(__ssam_pos_get_posture_for_source, __le32, __le32, { 432 + .target_category = SSAM_SSH_TC_POS, 433 + .target_id = 0x01, 434 + .command_id = 0x02, 435 + .instance_id = 0x00, 436 + }); 437 + 438 + static int ssam_pos_get_posture_for_source(struct ssam_tablet_sw *sw, u32 source_id, u32 *posture) 439 + { 440 + __le32 source_le = cpu_to_le32(source_id); 441 + __le32 rspval_le = 0; 442 + int status; 443 + 444 + status = ssam_retry(__ssam_pos_get_posture_for_source, sw->sdev->ctrl, 445 + &source_le, &rspval_le); 446 + if (status) 447 + return status; 448 + 449 + *posture = le32_to_cpu(rspval_le); 450 + return 0; 451 + } 452 + 453 + static int ssam_pos_get_posture(struct ssam_tablet_sw *sw, u32 *state) 454 + { 455 + u32 source_id; 456 + int status; 457 + 458 + status = ssam_pos_get_source(sw, &source_id); 459 + if (status) { 460 + dev_err(&sw->sdev->dev, "failed to get posture source ID: %d\n", status); 461 + return status; 462 + } 463 + 464 + status = ssam_pos_get_posture_for_source(sw, source_id, state); 465 + if (status) { 466 + dev_err(&sw->sdev->dev, "failed to get posture value for source %u: %d\n", 467 + source_id, status); 468 + return status; 469 + } 470 + 471 + return 0; 472 + } 473 + 474 + static u32 ssam_pos_sw_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) 475 + { 476 + struct ssam_tablet_sw *sw = container_of(nf, struct ssam_tablet_sw, notif); 477 + 478 + if (event->command_id != SSAM_EVENT_POS_CID_POSTURE_CHANGED) 479 + return 0; /* Return "unhandled". */ 480 + 481 + if (event->length != sizeof(__le32) * 3) 482 + dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length); 483 + 484 + schedule_work(&sw->update_work); 485 + return SSAM_NOTIF_HANDLED; 486 + } 487 + 488 + static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = { 489 + .dev = { 490 + .name = "Microsoft Surface POS Tablet Mode Switch", 491 + .phys = "ssam/01:26:01:00:01/input0", 492 + }, 493 + .ops = { 494 + .notify = ssam_pos_sw_notif, 495 + .get_state = ssam_pos_get_posture, 496 + .state_name = ssam_pos_state_name, 497 + .state_is_tablet_mode = ssam_pos_state_is_tablet_mode, 498 + }, 499 + .event = { 500 + .reg = SSAM_EVENT_REGISTRY_SAM, 501 + .id = { 502 + .target_category = SSAM_SSH_TC_POS, 503 + .instance = 0, 504 + }, 505 + .mask = SSAM_EVENT_MASK_TARGET, 506 + }, 507 + }; 508 + 509 + 510 + /* -- Driver registration. -------------------------------------------------- */ 511 + 512 + static const struct ssam_device_id ssam_tablet_sw_match[] = { 513 + { SSAM_SDEV(KIP, 0x01, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc }, 514 + { SSAM_SDEV(POS, 0x01, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc }, 515 + { }, 516 + }; 517 + MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match); 518 + 519 + static struct ssam_device_driver ssam_tablet_sw_driver = { 520 + .probe = ssam_tablet_sw_probe, 521 + .remove = ssam_tablet_sw_remove, 522 + .match_table = ssam_tablet_sw_match, 523 + .driver = { 524 + .name = "surface_aggregator_tablet_mode_switch", 525 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 526 + .pm = &ssam_tablet_sw_pm_ops, 527 + }, 528 + }; 529 + module_ssam_device_driver(ssam_tablet_sw_driver); 530 + 531 + MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); 532 + MODULE_DESCRIPTION("Tablet mode switch driver for Surface devices using the Surface Aggregator Module"); 533 + MODULE_LICENSE("GPL");
+1 -1
drivers/platform/surface/surface_dtx.c
··· 8 8 * acknowledge (to speed things up), abort (e.g. in case the dGPU is still in 9 9 * use), or request detachment via user-space. 10 10 * 11 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 11 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 12 12 */ 13 13 14 14 #include <linux/fs.h>
+13 -1
drivers/platform/surface/surface_gpe.c
··· 4 4 * properly configuring the respective GPEs. Required for wakeup via lid on 5 5 * newer Intel-based Microsoft Surface devices. 6 6 * 7 - * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com> 7 + * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com> 8 8 */ 9 9 10 10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ··· 170 170 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_3_1872"), 171 171 }, 172 172 .driver_data = (void *)lid_device_props_l4D, 173 + }, 174 + { 175 + .ident = "Surface Laptop 4 (Intel 13\")", 176 + .matches = { 177 + /* 178 + * We match for SKU here due to different variants: The 179 + * AMD (15") version does not rely on GPEs. 180 + */ 181 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 182 + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1950:1951"), 183 + }, 184 + .driver_data = (void *)lid_device_props_l4B, 173 185 }, 174 186 { 175 187 .ident = "Surface Laptop Studio",
+1 -1
drivers/platform/surface/surface_hotplug.c
··· 10 10 * Event signaling is handled via ACPI, which will generate the appropriate 11 11 * device-check notifications to be picked up by the PCIe hot-plug driver. 12 12 * 13 - * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> 13 + * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 14 14 */ 15 15 16 16 #include <linux/acpi.h>
+1 -1
drivers/platform/surface/surface_platform_profile.c
··· 3 3 * Surface Platform Profile / Performance Mode driver for Surface System 4 4 * Aggregator Module (thermal subsystem). 5 5 * 6 - * Copyright (C) 2021 Maximilian Luz <luzmaximilian@gmail.com> 6 + * Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com> 7 7 */ 8 8 9 9 #include <asm/unaligned.h>
+17 -35
drivers/platform/x86/Kconfig
··· 177 177 178 178 config ACER_WMI 179 179 tristate "Acer WMI Laptop Extras" 180 - depends on ACPI 181 - select LEDS_CLASS 182 - select NEW_LEDS 183 180 depends on BACKLIGHT_CLASS_DEVICE 184 181 depends on SERIO_I8042 185 182 depends on INPUT 186 183 depends on RFKILL || RFKILL = n 187 184 depends on ACPI_WMI 185 + select ACPI_VIDEO 188 186 select INPUT_SPARSEKMAP 189 - # Acer WMI depends on ACPI_VIDEO when ACPI is enabled 190 - select ACPI_VIDEO if ACPI 187 + select LEDS_CLASS 188 + select NEW_LEDS 191 189 help 192 190 This is a driver for newer Acer (and Wistron) laptops. It adds 193 191 wireless radio and bluetooth control, and on some laptops, ··· 194 196 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M 195 197 here. 196 198 197 - config AMD_PMC 198 - tristate "AMD SoC PMC driver" 199 - depends on ACPI && PCI && RTC_CLASS 200 - help 201 - The driver provides support for AMD Power Management Controller 202 - primarily responsible for S2Idle transactions that are driven from 203 - a platform firmware running on SMU. This driver also provides a debug 204 - mechanism to investigate the S2Idle transactions and failures. 205 - 206 - Say Y or M here if you have a notebook powered by AMD RYZEN CPU/APU. 207 - 208 - If you choose to compile this driver as a module the module will be 209 - called amd-pmc. 210 - 211 - config AMD_HSMP 212 - tristate "AMD HSMP Driver" 213 - depends on AMD_NB && X86_64 214 - help 215 - The driver provides a way for user space tools to monitor and manage 216 - system management functionality on EPYC server CPUs from AMD. 217 - 218 - Host System Management Port (HSMP) interface is a mailbox interface 219 - between the x86 core and the System Management Unit (SMU) firmware. 220 - 221 - If you choose to compile this driver as a module the module will be 222 - called amd_hsmp. 199 + source "drivers/platform/x86/amd/Kconfig" 223 200 224 201 config ADV_SWBUTTON 225 202 tristate "Advantech ACPI Software Button Driver" ··· 273 300 select INPUT_SPARSEKMAP 274 301 select LEDS_CLASS 275 302 select NEW_LEDS 303 + select LEDS_TRIGGERS 304 + select LEDS_TRIGGER_AUDIO 276 305 select ACPI_PLATFORM_PROFILE 277 306 help 278 307 Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new ··· 1139 1164 1140 1165 endif # X86_PLATFORM_DEVICES 1141 1166 1142 - config PMC_ATOM 1143 - def_bool y 1144 - depends on PCI 1145 - select COMMON_CLK 1167 + config P2SB 1168 + bool "Primary to Sideband (P2SB) bridge access support" 1169 + depends on PCI && X86 1170 + help 1171 + The Primary to Sideband (P2SB) bridge is an interface to some 1172 + PCI devices connected through it. In particular, SPI NOR controller 1173 + in Intel Apollo Lake SoC is one of such devices. 1174 + 1175 + The main purpose of this library is to unhide P2SB device in case 1176 + firmware kept it hidden on some platforms in order to access devices 1177 + behind it.
+6 -3
drivers/platform/x86/Makefile
··· 23 23 obj-$(CONFIG_ACER_WMI) += acer-wmi.o 24 24 25 25 # AMD 26 - obj-$(CONFIG_AMD_PMC) += amd-pmc.o 27 - obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o 26 + obj-y += amd/ 28 27 29 28 # Advantech 30 29 obj-$(CONFIG_ADV_SWBUTTON) += adv_swbutton.o ··· 119 120 # Intel uncore drivers 120 121 obj-$(CONFIG_INTEL_IPS) += intel_ips.o 121 122 123 + # Intel miscellaneous drivers 124 + intel_p2sb-y := p2sb.o 125 + obj-$(CONFIG_P2SB) += intel_p2sb.o 126 + 122 127 # Intel PMIC / PMC / P-Unit devices 123 128 obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 124 129 obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o 125 130 obj-$(CONFIG_INTEL_SCU_PLATFORM) += intel_scu_pltdrv.o 126 131 obj-$(CONFIG_INTEL_SCU_WDT) += intel_scu_wdt.o 127 132 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o 128 - obj-$(CONFIG_PMC_ATOM) += pmc_atom.o 133 + obj-$(CONFIG_X86_INTEL_LPSS) += pmc_atom.o 129 134 130 135 # Siemens Simatic Industrial PCs 131 136 obj-$(CONFIG_SIEMENS_SIMATIC_IPC) += simatic-ipc.o
+1 -6
drivers/platform/x86/acer-wmi.c
··· 1615 1615 1616 1616 static int update_bl_status(struct backlight_device *bd) 1617 1617 { 1618 - int intensity = bd->props.brightness; 1619 - 1620 - if (bd->props.power != FB_BLANK_UNBLANK) 1621 - intensity = 0; 1622 - if (bd->props.fb_blank != FB_BLANK_UNBLANK) 1623 - intensity = 0; 1618 + int intensity = backlight_get_brightness(bd); 1624 1619 1625 1620 set_u32(intensity, ACER_CAP_BRIGHTNESS); 1626 1621
drivers/platform/x86/amd-pmc.c drivers/platform/x86/amd/pmc.c
+31
drivers/platform/x86/amd/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # AMD x86 Platform Specific Drivers 4 + # 5 + 6 + config AMD_PMC 7 + tristate "AMD SoC PMC driver" 8 + depends on ACPI && PCI && RTC_CLASS 9 + help 10 + The driver provides support for AMD Power Management Controller 11 + primarily responsible for S2Idle transactions that are driven from 12 + a platform firmware running on SMU. This driver also provides a debug 13 + mechanism to investigate the S2Idle transactions and failures. 14 + 15 + Say Y or M here if you have a notebook powered by AMD RYZEN CPU/APU. 16 + 17 + If you choose to compile this driver as a module the module will be 18 + called amd-pmc. 19 + 20 + config AMD_HSMP 21 + tristate "AMD HSMP Driver" 22 + depends on AMD_NB && X86_64 23 + help 24 + The driver provides a way for user space tools to monitor and manage 25 + system management functionality on EPYC server CPUs from AMD. 26 + 27 + Host System Management Port (HSMP) interface is a mailbox interface 28 + between the x86 core and the System Management Unit (SMU) firmware. 29 + 30 + If you choose to compile this driver as a module the module will be 31 + called amd_hsmp.
+10
drivers/platform/x86/amd/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for drivers/platform/x86/amd 4 + # AMD x86 Platform-Specific Drivers 5 + # 6 + 7 + amd-pmc-y := pmc.o 8 + obj-$(CONFIG_AMD_PMC) += amd-pmc.o 9 + amd_hsmp-y := hsmp.o 10 + obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o
drivers/platform/x86/amd_hsmp.c drivers/platform/x86/amd/hsmp.c
+1 -4
drivers/platform/x86/apple-gmux.c
··· 291 291 static int gmux_update_status(struct backlight_device *bd) 292 292 { 293 293 struct apple_gmux_data *gmux_data = bl_get_data(bd); 294 - u32 brightness = bd->props.brightness; 295 - 296 - if (bd->props.state & BL_CORE_SUSPENDED) 297 - return 0; 294 + u32 brightness = backlight_get_brightness(bd); 298 295 299 296 gmux_write32(gmux_data, GMUX_PORT_BRIGHTNESS, brightness); 300 297
+25
drivers/platform/x86/asus-wmi.c
··· 208 208 int kbd_led_wk; 209 209 struct led_classdev lightbar_led; 210 210 int lightbar_led_wk; 211 + struct led_classdev micmute_led; 211 212 struct workqueue_struct *led_workqueue; 212 213 struct work_struct tpd_led_work; 213 214 struct work_struct wlan_led_work; ··· 1029 1028 return result & ASUS_WMI_DSTS_LIGHTBAR_MASK; 1030 1029 } 1031 1030 1031 + static int micmute_led_set(struct led_classdev *led_cdev, 1032 + enum led_brightness brightness) 1033 + { 1034 + int state = brightness != LED_OFF; 1035 + int err; 1036 + 1037 + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MICMUTE_LED, state, NULL); 1038 + return err < 0 ? err : 0; 1039 + } 1040 + 1032 1041 static void asus_wmi_led_exit(struct asus_wmi *asus) 1033 1042 { 1034 1043 led_classdev_unregister(&asus->kbd_led); 1035 1044 led_classdev_unregister(&asus->tpd_led); 1036 1045 led_classdev_unregister(&asus->wlan_led); 1037 1046 led_classdev_unregister(&asus->lightbar_led); 1047 + led_classdev_unregister(&asus->micmute_led); 1038 1048 1039 1049 if (asus->led_workqueue) 1040 1050 destroy_workqueue(asus->led_workqueue); ··· 1115 1103 1116 1104 rv = led_classdev_register(&asus->platform_device->dev, 1117 1105 &asus->lightbar_led); 1106 + } 1107 + 1108 + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MICMUTE_LED)) { 1109 + asus->micmute_led.name = "asus::micmute"; 1110 + asus->micmute_led.max_brightness = 1; 1111 + asus->micmute_led.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); 1112 + asus->micmute_led.brightness_set_blocking = micmute_led_set; 1113 + asus->micmute_led.default_trigger = "audio-micmute"; 1114 + 1115 + rv = led_classdev_register(&asus->platform_device->dev, 1116 + &asus->micmute_led); 1117 + if (rv) 1118 + goto error; 1118 1119 } 1119 1120 1120 1121 error:
+1 -3
drivers/platform/x86/compal-laptop.c
··· 324 324 if (ret) 325 325 return ret; 326 326 327 - set_backlight_state((b->props.power == FB_BLANK_UNBLANK) 328 - && !(b->props.state & BL_CORE_SUSPENDED) 329 - && !(b->props.state & BL_CORE_FBBLANK)); 327 + set_backlight_state(!backlight_is_blank(b)); 330 328 return 0; 331 329 } 332 330
-1
drivers/platform/x86/dell/Kconfig
··· 5 5 6 6 menuconfig X86_PLATFORM_DRIVERS_DELL 7 7 bool "Dell X86 Platform Specific Device Drivers" 8 - depends on X86_PLATFORM_DEVICES 9 8 help 10 9 Say Y here to get to see options for device drivers for various 11 10 Dell x86 platforms, including vendor-specific laptop extension drivers.
+7 -16
drivers/platform/x86/intel/pmt/class.c
··· 20 20 #define PMT_XA_MAX INT_MAX 21 21 #define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) 22 22 23 - /* 24 - * Early implementations of PMT on client platforms have some 25 - * differences from the server platforms (which use the Out Of Band 26 - * Management Services Module OOBMSM). This list tracks those 27 - * platforms as needed to handle those differences. Newer client 28 - * platforms are expected to be fully compatible with server. 29 - */ 30 - static const struct pci_device_id pmt_telem_early_client_pci_ids[] = { 31 - { PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */ 32 - { PCI_VDEVICE(INTEL, 0x490e) }, /* DG1 */ 33 - { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */ 34 - { } 35 - }; 36 - 37 23 bool intel_pmt_is_early_client_hw(struct device *dev) 38 24 { 39 - struct pci_dev *parent = to_pci_dev(dev->parent); 25 + struct intel_vsec_device *ivdev = dev_to_ivdev(dev); 40 26 41 - return !!pci_match_id(pmt_telem_early_client_pci_ids, parent); 27 + /* 28 + * Early implementations of PMT on client platforms have some 29 + * differences from the server platforms (which use the Out Of Band 30 + * Management Services Module OOBMSM). 31 + */ 32 + return !!(ivdev->info->quirks & VSEC_QUIRK_EARLY_HW); 42 33 } 43 34 EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw); 44 35
+15 -3
drivers/platform/x86/intel/pmt/telemetry.c
··· 23 23 #define TELEM_GUID_OFFSET 0x4 24 24 #define TELEM_BASE_OFFSET 0x8 25 25 #define TELEM_ACCESS(v) ((v) & GENMASK(3, 0)) 26 + #define TELEM_TYPE(v) (((v) & GENMASK(7, 4)) >> 4) 26 27 /* size is in bytes */ 27 28 #define TELEM_SIZE(v) (((v) & GENMASK(27, 12)) >> 10) 28 29 29 30 /* Used by client hardware to identify a fixed telemetry entry*/ 30 31 #define TELEM_CLIENT_FIXED_BLOCK_GUID 0x10000000 32 + 33 + enum telem_type { 34 + TELEM_TYPE_PUNIT = 0, 35 + TELEM_TYPE_CRASHLOG, 36 + TELEM_TYPE_PUNIT_FIXED, 37 + }; 31 38 32 39 struct pmt_telem_priv { 33 40 int num_entries; ··· 46 39 { 47 40 u32 guid = readl(entry->disc_table + TELEM_GUID_OFFSET); 48 41 49 - if (guid != TELEM_CLIENT_FIXED_BLOCK_GUID) 50 - return false; 42 + if (intel_pmt_is_early_client_hw(dev)) { 43 + u32 type = TELEM_TYPE(readl(entry->disc_table)); 51 44 52 - return intel_pmt_is_early_client_hw(dev); 45 + if ((type == TELEM_TYPE_PUNIT_FIXED) || 46 + (guid == TELEM_CLIENT_FIXED_BLOCK_GUID)) 47 + return true; 48 + } 49 + 50 + return false; 53 51 } 54 52 55 53 static int pmt_telem_header_decode(struct intel_pmt_entry *entry,
+32 -7
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
··· 277 277 return 0; 278 278 } 279 279 280 + #define ISST_MAX_BUS_NUMBER 2 280 281 281 282 struct isst_if_cpu_info { 282 283 /* For BUS 0 and BUS 1 only, which we need for PUNIT interface */ 283 - int bus_info[2]; 284 - struct pci_dev *pci_dev[2]; 284 + int bus_info[ISST_MAX_BUS_NUMBER]; 285 + struct pci_dev *pci_dev[ISST_MAX_BUS_NUMBER]; 285 286 int punit_cpu_id; 286 287 int numa_node; 287 288 }; 288 289 290 + struct isst_if_pkg_info { 291 + struct pci_dev *pci_dev[ISST_MAX_BUS_NUMBER]; 292 + }; 293 + 289 294 static struct isst_if_cpu_info *isst_cpu_info; 295 + static struct isst_if_pkg_info *isst_pkg_info; 296 + 290 297 #define ISST_MAX_PCI_DOMAINS 8 291 298 292 299 static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn) 293 300 { 294 301 struct pci_dev *matched_pci_dev = NULL; 295 302 struct pci_dev *pci_dev = NULL; 296 - int no_matches = 0; 303 + int no_matches = 0, pkg_id; 297 304 int i, bus_number; 298 305 299 - if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids || 300 - cpu >= num_possible_cpus()) 306 + if (bus_no < 0 || bus_no >= ISST_MAX_BUS_NUMBER || cpu < 0 || 307 + cpu >= nr_cpu_ids || cpu >= num_possible_cpus()) 301 308 return NULL; 309 + 310 + pkg_id = topology_physical_package_id(cpu); 302 311 303 312 bus_number = isst_cpu_info[cpu].bus_info[bus_no]; 304 313 if (bus_number < 0) ··· 333 324 } 334 325 335 326 if (node == isst_cpu_info[cpu].numa_node) { 327 + isst_pkg_info[pkg_id].pci_dev[bus_no] = _pci_dev; 328 + 336 329 pci_dev = _pci_dev; 337 330 break; 338 331 } ··· 352 341 */ 353 342 if (!pci_dev && no_matches == 1) 354 343 pci_dev = matched_pci_dev; 344 + 345 + /* Return pci_dev pointer for any matched CPU in the package */ 346 + if (!pci_dev) 347 + pci_dev = isst_pkg_info[pkg_id].pci_dev[bus_no]; 355 348 356 349 return pci_dev; 357 350 } ··· 376 361 { 377 362 struct pci_dev *pci_dev; 378 363 379 - if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids || 380 - cpu >= num_possible_cpus()) 364 + if (bus_no < 0 || bus_no >= ISST_MAX_BUS_NUMBER || cpu < 0 || 365 + cpu >= nr_cpu_ids || cpu >= num_possible_cpus()) 381 366 return NULL; 382 367 383 368 pci_dev = isst_cpu_info[cpu].pci_dev[bus_no]; ··· 432 417 if (!isst_cpu_info) 433 418 return -ENOMEM; 434 419 420 + isst_pkg_info = kcalloc(topology_max_packages(), 421 + sizeof(*isst_pkg_info), 422 + GFP_KERNEL); 423 + if (!isst_pkg_info) { 424 + kfree(isst_cpu_info); 425 + return -ENOMEM; 426 + } 427 + 435 428 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 436 429 "platform/x86/isst-if:online", 437 430 isst_if_cpu_online, NULL); 438 431 if (ret < 0) { 432 + kfree(isst_pkg_info); 439 433 kfree(isst_cpu_info); 440 434 return ret; 441 435 } ··· 457 433 static void isst_if_cpu_info_exit(void) 458 434 { 459 435 cpuhp_remove_state(isst_if_online_id); 436 + kfree(isst_pkg_info); 460 437 kfree(isst_cpu_info); 461 438 }; 462 439
+104 -26
drivers/platform/x86/intel/vsec.c
··· 15 15 16 16 #include <linux/auxiliary_bus.h> 17 17 #include <linux/bits.h> 18 + #include <linux/delay.h> 18 19 #include <linux/kernel.h> 19 20 #include <linux/idr.h> 20 21 #include <linux/module.h> ··· 31 30 #define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0)) 32 31 #define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3)) 33 32 #define TABLE_OFFSET_SHIFT 3 33 + #define PMT_XA_START 0 34 + #define PMT_XA_MAX INT_MAX 35 + #define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) 34 36 35 37 static DEFINE_IDA(intel_vsec_ida); 36 38 static DEFINE_IDA(intel_vsec_sdsi_ida); 39 + static DEFINE_XARRAY_ALLOC(auxdev_array); 37 40 38 41 /** 39 42 * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers. ··· 57 52 u8 entry_size; 58 53 u8 tbir; 59 54 u32 offset; 60 - }; 61 - 62 - /* Platform specific data */ 63 - struct intel_vsec_platform_info { 64 - struct intel_vsec_header **capabilities; 65 - unsigned long quirks; 66 55 }; 67 56 68 57 enum intel_vsec_id { ··· 137 138 const char *name) 138 139 { 139 140 struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev; 140 - int ret; 141 + int ret, id; 141 142 142 143 ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); 143 144 if (ret < 0) { ··· 164 165 return ret; 165 166 } 166 167 167 - return devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, auxdev); 168 + ret = devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, 169 + auxdev); 170 + if (ret < 0) 171 + return ret; 172 + 173 + /* Add auxdev to list */ 174 + ret = xa_alloc(&auxdev_array, &id, intel_vsec_dev, PMT_XA_LIMIT, 175 + GFP_KERNEL); 176 + if (ret) 177 + return ret; 178 + 179 + return 0; 168 180 } 169 181 170 182 static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, 171 - unsigned long quirks) 183 + struct intel_vsec_platform_info *info) 172 184 { 173 185 struct intel_vsec_device *intel_vsec_dev; 174 186 struct resource *res, *tmp; 187 + unsigned long quirks = info->quirks; 175 188 int i; 176 189 177 190 if (!intel_vsec_allowed(header->id) || intel_vsec_disabled(header->id, quirks)) ··· 227 216 intel_vsec_dev->pcidev = pdev; 228 217 intel_vsec_dev->resource = res; 229 218 intel_vsec_dev->num_resources = header->num_entries; 230 - intel_vsec_dev->quirks = quirks; 219 + intel_vsec_dev->info = info; 231 220 232 221 if (header->id == VSEC_ID_SDSI) 233 222 intel_vsec_dev->ida = &intel_vsec_sdsi_ida; ··· 237 226 return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id)); 238 227 } 239 228 240 - static bool intel_vsec_walk_header(struct pci_dev *pdev, unsigned long quirks, 241 - struct intel_vsec_header **header) 229 + static bool intel_vsec_walk_header(struct pci_dev *pdev, 230 + struct intel_vsec_platform_info *info) 242 231 { 232 + struct intel_vsec_header **header = info->capabilities; 243 233 bool have_devices = false; 244 234 int ret; 245 235 246 236 for ( ; *header; header++) { 247 - ret = intel_vsec_add_dev(pdev, *header, quirks); 237 + ret = intel_vsec_add_dev(pdev, *header, info); 248 238 if (ret) 249 239 dev_info(&pdev->dev, "Could not add device for DVSEC id %d\n", 250 240 (*header)->id); ··· 256 244 return have_devices; 257 245 } 258 246 259 - static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) 247 + static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, 248 + struct intel_vsec_platform_info *info) 260 249 { 261 250 bool have_devices = false; 262 251 int pos = 0; ··· 296 283 pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr); 297 284 header.id = PCI_DVSEC_HEADER2_ID(hdr); 298 285 299 - ret = intel_vsec_add_dev(pdev, &header, quirks); 286 + ret = intel_vsec_add_dev(pdev, &header, info); 300 287 if (ret) 301 288 continue; 302 289 ··· 306 293 return have_devices; 307 294 } 308 295 309 - static bool intel_vsec_walk_vsec(struct pci_dev *pdev, unsigned long quirks) 296 + static bool intel_vsec_walk_vsec(struct pci_dev *pdev, 297 + struct intel_vsec_platform_info *info) 310 298 { 311 299 bool have_devices = false; 312 300 int pos = 0; ··· 341 327 header.tbir = INTEL_DVSEC_TABLE_BAR(table); 342 328 header.offset = INTEL_DVSEC_TABLE_OFFSET(table); 343 329 344 - ret = intel_vsec_add_dev(pdev, &header, quirks); 330 + ret = intel_vsec_add_dev(pdev, &header, info); 345 331 if (ret) 346 332 continue; 347 333 ··· 355 341 { 356 342 struct intel_vsec_platform_info *info; 357 343 bool have_devices = false; 358 - unsigned long quirks = 0; 359 344 int ret; 360 345 361 346 ret = pcim_enable_device(pdev); 362 347 if (ret) 363 348 return ret; 364 349 350 + pci_save_state(pdev); 365 351 info = (struct intel_vsec_platform_info *)id->driver_data; 366 - if (info) 367 - quirks = info->quirks; 352 + if (!info) 353 + return -EINVAL; 368 354 369 - if (intel_vsec_walk_dvsec(pdev, quirks)) 355 + if (intel_vsec_walk_dvsec(pdev, info)) 370 356 have_devices = true; 371 357 372 - if (intel_vsec_walk_vsec(pdev, quirks)) 358 + if (intel_vsec_walk_vsec(pdev, info)) 373 359 have_devices = true; 374 360 375 361 if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && 376 - intel_vsec_walk_header(pdev, quirks, info->capabilities)) 362 + intel_vsec_walk_header(pdev, info)) 377 363 have_devices = true; 378 364 379 365 if (!have_devices) ··· 384 370 385 371 /* TGL info */ 386 372 static const struct intel_vsec_platform_info tgl_info = { 387 - .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | VSEC_QUIRK_TABLE_SHIFT, 373 + .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | 374 + VSEC_QUIRK_TABLE_SHIFT | VSEC_QUIRK_EARLY_HW, 388 375 }; 389 376 390 377 /* DG1 info */ ··· 405 390 406 391 static const struct intel_vsec_platform_info dg1_info = { 407 392 .capabilities = dg1_capabilities, 408 - .quirks = VSEC_QUIRK_NO_DVSEC, 393 + .quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW, 409 394 }; 410 395 411 396 #define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d 412 397 #define PCI_DEVICE_ID_INTEL_VSEC_DG1 0x490e 413 398 #define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM 0x09a7 399 + #define PCI_DEVICE_ID_INTEL_VSEC_RPL 0xa77d 414 400 #define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d 415 401 static const struct pci_device_id intel_vsec_pci_ids[] = { 416 402 { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, 417 403 { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, 418 - { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, NULL) }, 404 + { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &(struct intel_vsec_platform_info) {}) }, 405 + { PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) }, 419 406 { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, 420 407 { } 421 408 }; 422 409 MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); 423 410 411 + static pci_ers_result_t intel_vsec_pci_error_detected(struct pci_dev *pdev, 412 + pci_channel_state_t state) 413 + { 414 + pci_ers_result_t status = PCI_ERS_RESULT_NEED_RESET; 415 + 416 + dev_info(&pdev->dev, "PCI error detected, state %d", state); 417 + 418 + if (state == pci_channel_io_perm_failure) 419 + status = PCI_ERS_RESULT_DISCONNECT; 420 + else 421 + pci_disable_device(pdev); 422 + 423 + return status; 424 + } 425 + 426 + static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev) 427 + { 428 + struct intel_vsec_device *intel_vsec_dev; 429 + pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT; 430 + const struct pci_device_id *pci_dev_id; 431 + unsigned long index; 432 + 433 + dev_info(&pdev->dev, "Resetting PCI slot\n"); 434 + 435 + msleep(2000); 436 + if (pci_enable_device(pdev)) { 437 + dev_info(&pdev->dev, 438 + "Failed to re-enable PCI device after reset.\n"); 439 + goto out; 440 + } 441 + 442 + status = PCI_ERS_RESULT_RECOVERED; 443 + 444 + xa_for_each(&auxdev_array, index, intel_vsec_dev) { 445 + /* check if pdev doesn't match */ 446 + if (pdev != intel_vsec_dev->pcidev) 447 + continue; 448 + devm_release_action(&pdev->dev, intel_vsec_remove_aux, 449 + &intel_vsec_dev->auxdev); 450 + } 451 + pci_disable_device(pdev); 452 + pci_restore_state(pdev); 453 + pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev); 454 + intel_vsec_pci_probe(pdev, pci_dev_id); 455 + 456 + out: 457 + return status; 458 + } 459 + 460 + static void intel_vsec_pci_resume(struct pci_dev *pdev) 461 + { 462 + dev_info(&pdev->dev, "Done resuming PCI device\n"); 463 + } 464 + 465 + static const struct pci_error_handlers intel_vsec_pci_err_handlers = { 466 + .error_detected = intel_vsec_pci_error_detected, 467 + .slot_reset = intel_vsec_pci_slot_reset, 468 + .resume = intel_vsec_pci_resume, 469 + }; 470 + 424 471 static struct pci_driver intel_vsec_pci_driver = { 425 472 .name = "intel_vsec", 426 473 .id_table = intel_vsec_pci_ids, 427 474 .probe = intel_vsec_pci_probe, 475 + .err_handler = &intel_vsec_pci_err_handlers, 428 476 }; 429 477 module_pci_driver(intel_vsec_pci_driver); 430 478
+10 -1
drivers/platform/x86/intel/vsec.h
··· 20 20 21 21 /* DVSEC not present (provided in driver data) */ 22 22 VSEC_QUIRK_NO_DVSEC = BIT(3), 23 + 24 + /* Platforms requiring quirk in the auxiliary driver */ 25 + VSEC_QUIRK_EARLY_HW = BIT(4), 26 + }; 27 + 28 + /* Platform specific data */ 29 + struct intel_vsec_platform_info { 30 + struct intel_vsec_header **capabilities; 31 + unsigned long quirks; 23 32 }; 24 33 25 34 struct intel_vsec_device { ··· 36 27 struct pci_dev *pcidev; 37 28 struct resource *resource; 38 29 struct ida *ida; 39 - unsigned long quirks; 30 + struct intel_vsec_platform_info *info; 40 31 int num_resources; 41 32 }; 42 33
+443 -48
drivers/platform/x86/mlx-platform.c
··· 34 34 #define MLXPLAT_CPLD_LPC_REG_CPLD3_PN1_OFFSET 0x09 35 35 #define MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET 0x0a 36 36 #define MLXPLAT_CPLD_LPC_REG_CPLD4_PN1_OFFSET 0x0b 37 + #define MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET 0x19 37 38 #define MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET 0x1c 38 39 #define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d 39 40 #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e ··· 67 66 #define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43 68 67 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44 69 68 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45 69 + #define MLXPLAT_CPLD_LPC_REG_GWP_OFFSET 0x4a 70 + #define MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET 0x4b 71 + #define MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET 0x4c 70 72 #define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 71 73 #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 72 74 #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 75 + #define MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET 0x53 76 + #define MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET 0x54 77 + #define MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET 0x55 73 78 #define MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET 0x56 74 79 #define MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET 0x57 75 80 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 ··· 150 143 #define MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET 0xfa 151 144 #define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb 152 145 #define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc 146 + #define MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET 0xfd 153 147 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 154 148 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 155 149 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda ··· 201 193 MLXPLAT_CPLD_AGGR_MASK_LC_ACT | \ 202 194 MLXPLAT_CPLD_AGGR_MASK_LC_SDWN) 203 195 #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 196 + #define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2 BIT(2) 204 197 #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) 205 198 #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) 206 199 #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) ··· 213 204 #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) 214 205 #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) 215 206 #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) 207 + #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) 216 208 #define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 217 209 #define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) 218 210 ··· 593 583 { 594 584 .label = "asic1", 595 585 .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, 586 + .mask = MLXPLAT_CPLD_ASIC_MASK, 587 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 588 + }, 589 + }; 590 + 591 + static struct mlxreg_core_data mlxplat_mlxcpld_default_asic2_items_data[] = { 592 + { 593 + .label = "asic2", 594 + .reg = MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET, 596 595 .mask = MLXPLAT_CPLD_ASIC_MASK, 597 596 .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 598 597 }, ··· 1170 1151 .inversed = 0, 1171 1152 .health = true, 1172 1153 }, 1154 + { 1155 + .data = mlxplat_mlxcpld_default_asic2_items_data, 1156 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 1157 + .reg = MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET, 1158 + .mask = MLXPLAT_CPLD_ASIC_MASK, 1159 + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic2_items_data), 1160 + .inversed = 0, 1161 + .health = true, 1162 + } 1173 1163 }; 1174 1164 1175 1165 static ··· 1188 1160 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 1189 1161 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, 1190 1162 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 1191 - .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 1163 + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, 1192 1164 }; 1193 1165 1194 1166 static struct mlxreg_core_data mlxplat_mlxcpld_modular_pwr_items_data[] = { ··· 2032 2004 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 2033 2005 }; 2034 2006 2007 + /* Platform hotplug for NVLink blade systems family data */ 2008 + static struct mlxreg_core_data mlxplat_mlxcpld_global_wp_items_data[] = { 2009 + { 2010 + .label = "global_wp_grant", 2011 + .reg = MLXPLAT_CPLD_LPC_REG_GWP_OFFSET, 2012 + .mask = MLXPLAT_CPLD_GWP_MASK, 2013 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2014 + }, 2015 + }; 2016 + 2017 + static struct mlxreg_core_item mlxplat_mlxcpld_nvlink_blade_items[] = { 2018 + { 2019 + .data = mlxplat_mlxcpld_global_wp_items_data, 2020 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2021 + .reg = MLXPLAT_CPLD_LPC_REG_GWP_OFFSET, 2022 + .mask = MLXPLAT_CPLD_GWP_MASK, 2023 + .count = ARRAY_SIZE(mlxplat_mlxcpld_global_wp_items_data), 2024 + .inversed = 0, 2025 + .health = false, 2026 + }, 2027 + }; 2028 + 2029 + static 2030 + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_nvlink_blade_data = { 2031 + .items = mlxplat_mlxcpld_nvlink_blade_items, 2032 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_items), 2033 + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 2034 + .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, 2035 + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 2036 + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 2037 + }; 2038 + 2035 2039 /* Platform led default data */ 2036 2040 static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { 2037 2041 { ··· 2160 2100 static struct mlxreg_core_platform_data mlxplat_default_led_wc_data = { 2161 2101 .data = mlxplat_mlxcpld_default_led_wc_data, 2162 2102 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_wc_data), 2103 + }; 2104 + 2105 + /* Platform led default data for water cooling Ethernet switch blade */ 2106 + static struct mlxreg_core_data mlxplat_mlxcpld_default_led_eth_wc_blade_data[] = { 2107 + { 2108 + .label = "status:green", 2109 + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 2110 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 2111 + }, 2112 + { 2113 + .label = "status:red", 2114 + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 2115 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK 2116 + }, 2117 + }; 2118 + 2119 + static struct mlxreg_core_platform_data mlxplat_default_led_eth_wc_blade_data = { 2120 + .data = mlxplat_mlxcpld_default_led_eth_wc_blade_data, 2121 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_eth_wc_blade_data), 2163 2122 }; 2164 2123 2165 2124 /* Platform led MSN21xx system family data */ ··· 2936 2857 .mode = 0444, 2937 2858 }, 2938 2859 { 2860 + .label = "asic_reset", 2861 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, 2862 + .mask = GENMASK(7, 0) & ~BIT(3), 2863 + .mode = 0200, 2864 + }, 2865 + { 2866 + .label = "asic2_reset", 2867 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, 2868 + .mask = GENMASK(7, 0) & ~BIT(2), 2869 + .mode = 0200, 2870 + }, 2871 + { 2939 2872 .label = "reset_long_pb", 2940 2873 .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 2941 2874 .mask = GENMASK(7, 0) & ~BIT(0), ··· 3087 2996 .mode = 0444, 3088 2997 }, 3089 2998 { 2999 + .label = "asic2_health", 3000 + .reg = MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET, 3001 + .mask = MLXPLAT_CPLD_ASIC_MASK, 3002 + .bit = 1, 3003 + .mode = 0444, 3004 + }, 3005 + { 3090 3006 .label = "fan_dir", 3091 3007 .reg = MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION, 3092 3008 .bit = GENMASK(7, 0), ··· 3151 3053 { 3152 3054 .label = "config2", 3153 3055 .reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET, 3056 + .bit = GENMASK(7, 0), 3057 + .mode = 0444, 3058 + }, 3059 + { 3060 + .label = "config3", 3061 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET, 3154 3062 .bit = GENMASK(7, 0), 3155 3063 .mode = 0444, 3156 3064 }, ··· 3639 3535 .mode = 0444, 3640 3536 }, 3641 3537 { 3538 + .label = "config3", 3539 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET, 3540 + .bit = GENMASK(7, 0), 3541 + .mode = 0444, 3542 + }, 3543 + { 3642 3544 .label = "ufm_version", 3643 3545 .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, 3644 3546 .bit = GENMASK(7, 0), ··· 3655 3545 static struct mlxreg_core_platform_data mlxplat_modular_regs_io_data = { 3656 3546 .data = mlxplat_mlxcpld_modular_regs_io_data, 3657 3547 .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_regs_io_data), 3548 + }; 3549 + 3550 + /* Platform register access for NVLink blade systems family data */ 3551 + static struct mlxreg_core_data mlxplat_mlxcpld_nvlink_blade_regs_io_data[] = { 3552 + { 3553 + .label = "cpld1_version", 3554 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, 3555 + .bit = GENMASK(7, 0), 3556 + .mode = 0444, 3557 + }, 3558 + { 3559 + .label = "cpld1_pn", 3560 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET, 3561 + .bit = GENMASK(15, 0), 3562 + .mode = 0444, 3563 + .regnum = 2, 3564 + }, 3565 + { 3566 + .label = "cpld1_version_min", 3567 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET, 3568 + .bit = GENMASK(7, 0), 3569 + .mode = 0444, 3570 + }, 3571 + { 3572 + .label = "reset_aux_pwr_or_ref", 3573 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 3574 + .mask = GENMASK(7, 0) & ~BIT(2), 3575 + .mode = 0444, 3576 + }, 3577 + { 3578 + .label = "reset_from_comex", 3579 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 3580 + .mask = GENMASK(7, 0) & ~BIT(4), 3581 + .mode = 0444, 3582 + }, 3583 + { 3584 + .label = "reset_comex_pwr_fail", 3585 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 3586 + .mask = GENMASK(7, 0) & ~BIT(3), 3587 + .mode = 0444, 3588 + }, 3589 + { 3590 + .label = "reset_platform", 3591 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 3592 + .mask = GENMASK(7, 0) & ~BIT(4), 3593 + .mode = 0444, 3594 + }, 3595 + { 3596 + .label = "reset_soc", 3597 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 3598 + .mask = GENMASK(7, 0) & ~BIT(5), 3599 + .mode = 0444, 3600 + }, 3601 + { 3602 + .label = "reset_comex_wd", 3603 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 3604 + .mask = GENMASK(7, 0) & ~BIT(6), 3605 + .mode = 0444, 3606 + }, 3607 + { 3608 + .label = "reset_voltmon_upgrade_fail", 3609 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 3610 + .mask = GENMASK(7, 0) & ~BIT(0), 3611 + .mode = 0444, 3612 + }, 3613 + { 3614 + .label = "reset_system", 3615 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 3616 + .mask = GENMASK(7, 0) & ~BIT(1), 3617 + .mode = 0444, 3618 + }, 3619 + { 3620 + .label = "reset_sw_pwr_off", 3621 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 3622 + .mask = GENMASK(7, 0) & ~BIT(2), 3623 + .mode = 0444, 3624 + }, 3625 + { 3626 + .label = "reset_comex_thermal", 3627 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 3628 + .mask = GENMASK(7, 0) & ~BIT(3), 3629 + .mode = 0444, 3630 + }, 3631 + { 3632 + .label = "reset_reload_bios", 3633 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 3634 + .mask = GENMASK(7, 0) & ~BIT(5), 3635 + .mode = 0444, 3636 + }, 3637 + { 3638 + .label = "reset_ac_pwr_fail", 3639 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 3640 + .mask = GENMASK(7, 0) & ~BIT(6), 3641 + .mode = 0444, 3642 + }, 3643 + { 3644 + .label = "pwr_cycle", 3645 + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, 3646 + .mask = GENMASK(7, 0) & ~BIT(2), 3647 + .mode = 0200, 3648 + }, 3649 + { 3650 + .label = "pwr_down", 3651 + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, 3652 + .mask = GENMASK(7, 0) & ~BIT(3), 3653 + .mode = 0200, 3654 + }, 3655 + { 3656 + .label = "global_wp_request", 3657 + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 3658 + .mask = GENMASK(7, 0) & ~BIT(0), 3659 + .mode = 0644, 3660 + }, 3661 + { 3662 + .label = "jtag_enable", 3663 + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 3664 + .mask = GENMASK(7, 0) & ~BIT(4), 3665 + .mode = 0644, 3666 + }, 3667 + { 3668 + .label = "comm_chnl_ready", 3669 + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 3670 + .mask = GENMASK(7, 0) & ~BIT(6), 3671 + .mode = 0200, 3672 + }, 3673 + { 3674 + .label = "bios_safe_mode", 3675 + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, 3676 + .mask = GENMASK(7, 0) & ~BIT(4), 3677 + .mode = 0444, 3678 + }, 3679 + { 3680 + .label = "bios_active_image", 3681 + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, 3682 + .mask = GENMASK(7, 0) & ~BIT(5), 3683 + .mode = 0444, 3684 + }, 3685 + { 3686 + .label = "bios_auth_fail", 3687 + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, 3688 + .mask = GENMASK(7, 0) & ~BIT(6), 3689 + .mode = 0444, 3690 + }, 3691 + { 3692 + .label = "bios_upgrade_fail", 3693 + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, 3694 + .mask = GENMASK(7, 0) & ~BIT(7), 3695 + .mode = 0444, 3696 + }, 3697 + { 3698 + .label = "voltreg_update_status", 3699 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, 3700 + .mask = MLXPLAT_CPLD_VOLTREG_UPD_MASK, 3701 + .bit = 5, 3702 + .mode = 0444, 3703 + }, 3704 + { 3705 + .label = "vpd_wp", 3706 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, 3707 + .mask = GENMASK(7, 0) & ~BIT(3), 3708 + .mode = 0644, 3709 + }, 3710 + { 3711 + .label = "pcie_asic_reset_dis", 3712 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, 3713 + .mask = GENMASK(7, 0) & ~BIT(4), 3714 + .mode = 0644, 3715 + }, 3716 + { 3717 + .label = "global_wp_response", 3718 + .reg = MLXPLAT_CPLD_LPC_REG_GWP_OFFSET, 3719 + .mask = GENMASK(7, 0) & ~BIT(0), 3720 + .mode = 0444, 3721 + }, 3722 + { 3723 + .label = "config1", 3724 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, 3725 + .bit = GENMASK(7, 0), 3726 + .mode = 0444, 3727 + }, 3728 + { 3729 + .label = "config2", 3730 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET, 3731 + .bit = GENMASK(7, 0), 3732 + .mode = 0444, 3733 + }, 3734 + { 3735 + .label = "config3", 3736 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET, 3737 + .bit = GENMASK(7, 0), 3738 + .mode = 0444, 3739 + }, 3740 + { 3741 + .label = "ufm_version", 3742 + .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, 3743 + .bit = GENMASK(7, 0), 3744 + .mode = 0444, 3745 + }, 3746 + }; 3747 + 3748 + static struct mlxreg_core_platform_data mlxplat_nvlink_blade_regs_io_data = { 3749 + .data = mlxplat_mlxcpld_nvlink_blade_regs_io_data, 3750 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_regs_io_data), 3658 3751 }; 3659 3752 3660 3753 /* Platform FAN default */ ··· 4245 3932 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 4246 3933 case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: 4247 3934 case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: 3935 + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: 3936 + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: 4248 3937 case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: 4249 3938 case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: 3939 + case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: 3940 + case MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET: 4250 3941 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 4251 3942 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 4252 3943 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: ··· 4340 4023 case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: 4341 4024 case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: 4342 4025 case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: 4026 + case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: 4027 + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: 4028 + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: 4343 4029 case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: 4344 4030 case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: 4345 4031 case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: 4032 + case MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET: 4033 + case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: 4034 + case MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET: 4346 4035 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 4347 4036 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 4348 4037 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: ··· 4423 4100 case MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET: 4424 4101 case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: 4425 4102 case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: 4103 + case MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET: 4426 4104 case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: 4427 4105 return true; 4428 4106 } ··· 4474 4150 case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: 4475 4151 case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: 4476 4152 case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: 4153 + case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: 4154 + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: 4155 + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: 4477 4156 case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: 4478 4157 case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: 4479 4158 case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: 4159 + case MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET: 4160 + case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: 4161 + case MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET: 4480 4162 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 4481 4163 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 4482 4164 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: ··· 4551 4221 case MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET: 4552 4222 case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: 4553 4223 case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: 4224 + case MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET: 4554 4225 case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: 4555 4226 return true; 4556 4227 } ··· 4748 4417 return 1; 4749 4418 } 4750 4419 4420 + static int __init mlxplat_dmi_default_eth_wc_blade_matched(const struct dmi_system_id *dmi) 4421 + { 4422 + int i; 4423 + 4424 + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; 4425 + mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data); 4426 + mlxplat_mux_data = mlxplat_default_mux_data; 4427 + for (i = 0; i < mlxplat_mux_num; i++) { 4428 + mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 4429 + mlxplat_mux_data[i].n_values = 4430 + ARRAY_SIZE(mlxplat_msn21xx_channels); 4431 + } 4432 + mlxplat_hotplug = &mlxplat_mlxcpld_default_wc_data; 4433 + mlxplat_hotplug->deferred_nr = 4434 + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 4435 + mlxplat_led = &mlxplat_default_led_eth_wc_blade_data; 4436 + mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; 4437 + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) 4438 + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; 4439 + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; 4440 + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng; 4441 + 4442 + return 1; 4443 + } 4444 + 4751 4445 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) 4752 4446 { 4753 4447 int i; ··· 4935 4579 return 1; 4936 4580 } 4937 4581 4582 + static int __init mlxplat_dmi_nvlink_blade_matched(const struct dmi_system_id *dmi) 4583 + { 4584 + int i; 4585 + 4586 + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; 4587 + mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data); 4588 + mlxplat_mux_data = mlxplat_default_mux_data; 4589 + mlxplat_hotplug = &mlxplat_mlxcpld_nvlink_blade_data; 4590 + mlxplat_hotplug->deferred_nr = 4591 + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 4592 + for (i = 0; i < mlxplat_mux_num; i++) { 4593 + mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; 4594 + mlxplat_mux_data[i].n_values = 4595 + ARRAY_SIZE(mlxplat_msn21xx_channels); 4596 + } 4597 + mlxplat_regs_io = &mlxplat_nvlink_blade_regs_io_data; 4598 + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; 4599 + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400; 4600 + 4601 + return 1; 4602 + } 4603 + 4938 4604 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { 4939 4605 { 4940 4606 .callback = mlxplat_dmi_default_wc_matched, ··· 4990 4612 }, 4991 4613 }, 4992 4614 { 4615 + .callback = mlxplat_dmi_default_eth_wc_blade_matched, 4616 + .matches = { 4617 + DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), 4618 + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI139"), 4619 + }, 4620 + }, 4621 + { 4993 4622 .callback = mlxplat_dmi_qmb7xx_matched, 4994 4623 .matches = { 4995 4624 DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), ··· 5024 4639 .callback = mlxplat_dmi_modular_matched, 5025 4640 .matches = { 5026 4641 DMI_MATCH(DMI_BOARD_NAME, "VMOD0011"), 4642 + }, 4643 + }, 4644 + { 4645 + .callback = mlxplat_dmi_nvlink_blade_matched, 4646 + .matches = { 4647 + DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"), 5027 4648 }, 5028 4649 }, 5029 4650 { ··· 5221 4830 nr = (nr == mlxplat_max_adap_num) ? -1 : nr; 5222 4831 if (mlxplat_i2c) 5223 4832 mlxplat_i2c->regmap = priv->regmap; 5224 - priv->pdev_i2c = platform_device_register_resndata( 5225 - &mlxplat_dev->dev, "i2c_mlxcpld", 5226 - nr, mlxplat_mlxcpld_resources, 5227 - ARRAY_SIZE(mlxplat_mlxcpld_resources), 5228 - mlxplat_i2c, sizeof(*mlxplat_i2c)); 4833 + priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", 4834 + nr, mlxplat_mlxcpld_resources, 4835 + ARRAY_SIZE(mlxplat_mlxcpld_resources), 4836 + mlxplat_i2c, sizeof(*mlxplat_i2c)); 5229 4837 if (IS_ERR(priv->pdev_i2c)) { 5230 4838 err = PTR_ERR(priv->pdev_i2c); 5231 4839 goto fail_alloc; 5232 4840 } 5233 4841 5234 4842 for (i = 0; i < mlxplat_mux_num; i++) { 5235 - priv->pdev_mux[i] = platform_device_register_resndata( 5236 - &priv->pdev_i2c->dev, 5237 - "i2c-mux-reg", i, NULL, 5238 - 0, &mlxplat_mux_data[i], 5239 - sizeof(mlxplat_mux_data[i])); 4843 + priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, 4844 + "i2c-mux-reg", i, NULL, 0, 4845 + &mlxplat_mux_data[i], 4846 + sizeof(mlxplat_mux_data[i])); 5240 4847 if (IS_ERR(priv->pdev_mux[i])) { 5241 4848 err = PTR_ERR(priv->pdev_mux[i]); 5242 4849 goto fail_platform_mux_register; ··· 5242 4853 } 5243 4854 5244 4855 /* Add hotplug driver */ 5245 - mlxplat_hotplug->regmap = priv->regmap; 5246 - priv->pdev_hotplug = platform_device_register_resndata( 5247 - &mlxplat_dev->dev, "mlxreg-hotplug", 5248 - PLATFORM_DEVID_NONE, 5249 - mlxplat_mlxcpld_resources, 5250 - ARRAY_SIZE(mlxplat_mlxcpld_resources), 5251 - mlxplat_hotplug, sizeof(*mlxplat_hotplug)); 5252 - if (IS_ERR(priv->pdev_hotplug)) { 5253 - err = PTR_ERR(priv->pdev_hotplug); 5254 - goto fail_platform_mux_register; 4856 + if (mlxplat_hotplug) { 4857 + mlxplat_hotplug->regmap = priv->regmap; 4858 + priv->pdev_hotplug = 4859 + platform_device_register_resndata(&mlxplat_dev->dev, 4860 + "mlxreg-hotplug", PLATFORM_DEVID_NONE, 4861 + mlxplat_mlxcpld_resources, 4862 + ARRAY_SIZE(mlxplat_mlxcpld_resources), 4863 + mlxplat_hotplug, sizeof(*mlxplat_hotplug)); 4864 + if (IS_ERR(priv->pdev_hotplug)) { 4865 + err = PTR_ERR(priv->pdev_hotplug); 4866 + goto fail_platform_mux_register; 4867 + } 5255 4868 } 5256 4869 5257 4870 /* Set default registers. */ ··· 5266 4875 } 5267 4876 5268 4877 /* Add LED driver. */ 5269 - mlxplat_led->regmap = priv->regmap; 5270 - priv->pdev_led = platform_device_register_resndata( 5271 - &mlxplat_dev->dev, "leds-mlxreg", 5272 - PLATFORM_DEVID_NONE, NULL, 0, 5273 - mlxplat_led, sizeof(*mlxplat_led)); 5274 - if (IS_ERR(priv->pdev_led)) { 5275 - err = PTR_ERR(priv->pdev_led); 5276 - goto fail_platform_hotplug_register; 4878 + if (mlxplat_led) { 4879 + mlxplat_led->regmap = priv->regmap; 4880 + priv->pdev_led = 4881 + platform_device_register_resndata(&mlxplat_dev->dev, "leds-mlxreg", 4882 + PLATFORM_DEVID_NONE, NULL, 0, mlxplat_led, 4883 + sizeof(*mlxplat_led)); 4884 + if (IS_ERR(priv->pdev_led)) { 4885 + err = PTR_ERR(priv->pdev_led); 4886 + goto fail_platform_hotplug_register; 4887 + } 5277 4888 } 5278 4889 5279 4890 /* Add registers io access driver. */ 5280 4891 if (mlxplat_regs_io) { 5281 4892 mlxplat_regs_io->regmap = priv->regmap; 5282 - priv->pdev_io_regs = platform_device_register_resndata( 5283 - &mlxplat_dev->dev, "mlxreg-io", 5284 - PLATFORM_DEVID_NONE, NULL, 0, 5285 - mlxplat_regs_io, 5286 - sizeof(*mlxplat_regs_io)); 4893 + priv->pdev_io_regs = platform_device_register_resndata(&mlxplat_dev->dev, 4894 + "mlxreg-io", 4895 + PLATFORM_DEVID_NONE, NULL, 4896 + 0, mlxplat_regs_io, 4897 + sizeof(*mlxplat_regs_io)); 5287 4898 if (IS_ERR(priv->pdev_io_regs)) { 5288 4899 err = PTR_ERR(priv->pdev_io_regs); 5289 4900 goto fail_platform_led_register; ··· 5295 4902 /* Add FAN driver. */ 5296 4903 if (mlxplat_fan) { 5297 4904 mlxplat_fan->regmap = priv->regmap; 5298 - priv->pdev_fan = platform_device_register_resndata( 5299 - &mlxplat_dev->dev, "mlxreg-fan", 5300 - PLATFORM_DEVID_NONE, NULL, 0, 5301 - mlxplat_fan, 5302 - sizeof(*mlxplat_fan)); 4905 + priv->pdev_fan = platform_device_register_resndata(&mlxplat_dev->dev, "mlxreg-fan", 4906 + PLATFORM_DEVID_NONE, NULL, 0, 4907 + mlxplat_fan, 4908 + sizeof(*mlxplat_fan)); 5303 4909 if (IS_ERR(priv->pdev_fan)) { 5304 4910 err = PTR_ERR(priv->pdev_fan); 5305 4911 goto fail_platform_io_regs_register; ··· 5312 4920 for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { 5313 4921 if (mlxplat_wd_data[j]) { 5314 4922 mlxplat_wd_data[j]->regmap = priv->regmap; 5315 - priv->pdev_wd[j] = platform_device_register_resndata( 5316 - &mlxplat_dev->dev, "mlx-wdt", 5317 - j, NULL, 0, 5318 - mlxplat_wd_data[j], 5319 - sizeof(*mlxplat_wd_data[j])); 4923 + priv->pdev_wd[j] = 4924 + platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", j, 4925 + NULL, 0, mlxplat_wd_data[j], 4926 + sizeof(*mlxplat_wd_data[j])); 5320 4927 if (IS_ERR(priv->pdev_wd[j])) { 5321 4928 err = PTR_ERR(priv->pdev_wd[j]); 5322 4929 goto fail_platform_wd_register; ··· 5340 4949 if (mlxplat_regs_io) 5341 4950 platform_device_unregister(priv->pdev_io_regs); 5342 4951 fail_platform_led_register: 5343 - platform_device_unregister(priv->pdev_led); 4952 + if (mlxplat_led) 4953 + platform_device_unregister(priv->pdev_led); 5344 4954 fail_platform_hotplug_register: 5345 - platform_device_unregister(priv->pdev_hotplug); 4955 + if (mlxplat_hotplug) 4956 + platform_device_unregister(priv->pdev_hotplug); 5346 4957 fail_platform_mux_register: 5347 4958 while (--i >= 0) 5348 4959 platform_device_unregister(priv->pdev_mux[i]); ··· 5367 4974 platform_device_unregister(priv->pdev_fan); 5368 4975 if (priv->pdev_io_regs) 5369 4976 platform_device_unregister(priv->pdev_io_regs); 5370 - platform_device_unregister(priv->pdev_led); 5371 - platform_device_unregister(priv->pdev_hotplug); 4977 + if (priv->pdev_led) 4978 + platform_device_unregister(priv->pdev_led); 4979 + if (priv->pdev_hotplug) 4980 + platform_device_unregister(priv->pdev_hotplug); 5372 4981 5373 4982 for (i = mlxplat_mux_num - 1; i >= 0 ; i--) 5374 4983 platform_device_unregister(priv->pdev_mux[i]);
+133
drivers/platform/x86/p2sb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Primary to Sideband (P2SB) bridge access support 4 + * 5 + * Copyright (c) 2017, 2021-2022 Intel Corporation. 6 + * 7 + * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 8 + * Jonathan Yong <jonathan.yong@intel.com> 9 + */ 10 + 11 + #include <linux/bits.h> 12 + #include <linux/export.h> 13 + #include <linux/pci.h> 14 + #include <linux/platform_data/x86/p2sb.h> 15 + 16 + #include <asm/cpu_device_id.h> 17 + #include <asm/intel-family.h> 18 + 19 + #define P2SBC 0xe0 20 + #define P2SBC_HIDE BIT(8) 21 + 22 + static const struct x86_cpu_id p2sb_cpu_ids[] = { 23 + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, PCI_DEVFN(13, 0)), 24 + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, PCI_DEVFN(31, 1)), 25 + X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D, PCI_DEVFN(31, 1)), 26 + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, PCI_DEVFN(31, 1)), 27 + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, PCI_DEVFN(31, 1)), 28 + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, PCI_DEVFN(31, 1)), 29 + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, PCI_DEVFN(31, 1)), 30 + {} 31 + }; 32 + 33 + static int p2sb_get_devfn(unsigned int *devfn) 34 + { 35 + const struct x86_cpu_id *id; 36 + 37 + id = x86_match_cpu(p2sb_cpu_ids); 38 + if (!id) 39 + return -ENODEV; 40 + 41 + *devfn = (unsigned int)id->driver_data; 42 + return 0; 43 + } 44 + 45 + static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) 46 + { 47 + /* Copy resource from the first BAR of the device in question */ 48 + *mem = pdev->resource[0]; 49 + return 0; 50 + } 51 + 52 + static int p2sb_scan_and_read(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 53 + { 54 + struct pci_dev *pdev; 55 + int ret; 56 + 57 + pdev = pci_scan_single_device(bus, devfn); 58 + if (!pdev) 59 + return -ENODEV; 60 + 61 + ret = p2sb_read_bar0(pdev, mem); 62 + 63 + pci_stop_and_remove_bus_device(pdev); 64 + return ret; 65 + } 66 + 67 + /** 68 + * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR 69 + * @bus: PCI bus to communicate with 70 + * @devfn: PCI slot and function to communicate with 71 + * @mem: memory resource to be filled in 72 + * 73 + * The BIOS prevents the P2SB device from being enumerated by the PCI 74 + * subsystem, so we need to unhide and hide it back to lookup the BAR. 75 + * 76 + * if @bus is NULL, the bus 0 in domain 0 will be used. 77 + * If @devfn is 0, it will be replaced by devfn of the P2SB device. 78 + * 79 + * Caller must provide a valid pointer to @mem. 80 + * 81 + * Locking is handled by pci_rescan_remove_lock mutex. 82 + * 83 + * Return: 84 + * 0 on success or appropriate errno value on error. 85 + */ 86 + int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 87 + { 88 + struct pci_dev *pdev_p2sb; 89 + unsigned int devfn_p2sb; 90 + u32 value = P2SBC_HIDE; 91 + int ret; 92 + 93 + /* Get devfn for P2SB device itself */ 94 + ret = p2sb_get_devfn(&devfn_p2sb); 95 + if (ret) 96 + return ret; 97 + 98 + /* if @bus is NULL, use bus 0 in domain 0 */ 99 + bus = bus ?: pci_find_bus(0, 0); 100 + 101 + /* 102 + * Prevent concurrent PCI bus scan from seeing the P2SB device and 103 + * removing via sysfs while it is temporarily exposed. 104 + */ 105 + pci_lock_rescan_remove(); 106 + 107 + /* Unhide the P2SB device, if needed */ 108 + pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); 109 + if (value & P2SBC_HIDE) 110 + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); 111 + 112 + pdev_p2sb = pci_scan_single_device(bus, devfn_p2sb); 113 + if (devfn) 114 + ret = p2sb_scan_and_read(bus, devfn, mem); 115 + else 116 + ret = p2sb_read_bar0(pdev_p2sb, mem); 117 + pci_stop_and_remove_bus_device(pdev_p2sb); 118 + 119 + /* Hide the P2SB device, if it was hidden */ 120 + if (value & P2SBC_HIDE) 121 + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, P2SBC_HIDE); 122 + 123 + pci_unlock_rescan_remove(); 124 + 125 + if (ret) 126 + return ret; 127 + 128 + if (mem->flags == 0) 129 + return -ENODEV; 130 + 131 + return 0; 132 + } 133 + EXPORT_SYMBOL_GPL(p2sb_bar);
+16 -12
drivers/platform/x86/panasonic-laptop.c
··· 998 998 pr_err("Couldn't retrieve BIOS data\n"); 999 999 goto out_input; 1000 1000 } 1001 - /* initialize backlight */ 1002 - memset(&props, 0, sizeof(struct backlight_properties)); 1003 - props.type = BACKLIGHT_PLATFORM; 1004 - props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT]; 1005 - pcc->backlight = backlight_device_register("panasonic", NULL, pcc, 1006 - &pcc_backlight_ops, &props); 1007 - if (IS_ERR(pcc->backlight)) { 1008 - result = PTR_ERR(pcc->backlight); 1009 - goto out_input; 1010 - } 1011 1001 1012 - /* read the initial brightness setting from the hardware */ 1013 - pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; 1002 + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { 1003 + /* initialize backlight */ 1004 + memset(&props, 0, sizeof(struct backlight_properties)); 1005 + props.type = BACKLIGHT_PLATFORM; 1006 + props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT]; 1007 + 1008 + pcc->backlight = backlight_device_register("panasonic", NULL, pcc, 1009 + &pcc_backlight_ops, &props); 1010 + if (IS_ERR(pcc->backlight)) { 1011 + result = PTR_ERR(pcc->backlight); 1012 + goto out_input; 1013 + } 1014 + 1015 + /* read the initial brightness setting from the hardware */ 1016 + pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; 1017 + } 1014 1018 1015 1019 /* Reset initial sticky key mode since the hardware register state is not consistent */ 1016 1020 acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0);
+7 -12
drivers/platform/x86/pmc_atom.c
··· 389 389 }, 390 390 }, 391 391 { 392 - /* pmc_plt_clk0 - 3 are used for the 4 ethernet controllers */ 393 - .ident = "Lex 3I380D", 392 + /* 393 + * Lex System / Lex Computech Co. makes a lot of Bay Trail 394 + * based embedded boards which often come with multiple 395 + * ethernet controllers using multiple pmc_plt_clks. See: 396 + * https://www.lex.com.tw/products/embedded-ipc-board/ 397 + */ 398 + .ident = "Lex BayTrail", 394 399 .callback = dmi_callback, 395 400 .matches = { 396 401 DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), 397 - DMI_MATCH(DMI_PRODUCT_NAME, "3I380D"), 398 - }, 399 - }, 400 - { 401 - /* pmc_plt_clk* - are used for ethernet controllers */ 402 - .ident = "Lex 2I385SW", 403 - .callback = dmi_callback, 404 - .matches = { 405 - DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), 406 - DMI_MATCH(DMI_PRODUCT_NAME, "2I385SW"), 407 402 }, 408 403 }, 409 404 {
+34 -35
drivers/platform/x86/serial-multi-instantiate.c
··· 61 61 default: 62 62 return 0; 63 63 } 64 - 65 64 if (ret < 0) 66 - dev_err_probe(&pdev->dev, ret, "Error requesting irq at index %d: %d\n", 67 - inst->irq_idx, ret); 65 + return dev_err_probe(&pdev->dev, ret, "Error requesting irq at index %d\n", 66 + inst->irq_idx); 68 67 69 68 return ret; 70 69 } 71 70 72 71 static void smi_devs_unregister(struct smi *smi) 73 72 { 74 - while (smi->i2c_num > 0) 75 - i2c_unregister_device(smi->i2c_devs[--smi->i2c_num]); 73 + while (smi->i2c_num--) 74 + i2c_unregister_device(smi->i2c_devs[smi->i2c_num]); 76 75 77 - while (smi->spi_num > 0) 78 - spi_unregister_device(smi->spi_devs[--smi->spi_num]); 76 + while (smi->spi_num--) 77 + spi_unregister_device(smi->spi_devs[smi->spi_num]); 79 78 } 80 79 81 80 /** 82 81 * smi_spi_probe - Instantiate multiple SPI devices from inst array 83 82 * @pdev: Platform device 84 - * @adev: ACPI device 85 83 * @smi: Internal struct for Serial multi instantiate driver 86 84 * @inst_array: Array of instances to probe 87 85 * 88 86 * Returns the number of SPI devices instantiate, Zero if none is found or a negative error code. 89 87 */ 90 - static int smi_spi_probe(struct platform_device *pdev, struct acpi_device *adev, struct smi *smi, 88 + static int smi_spi_probe(struct platform_device *pdev, struct smi *smi, 91 89 const struct smi_instance *inst_array) 92 90 { 93 91 struct device *dev = &pdev->dev; 92 + struct acpi_device *adev = ACPI_COMPANION(dev); 94 93 struct spi_controller *ctlr; 95 94 struct spi_device *spi_dev; 96 95 char name[50]; ··· 98 99 ret = acpi_spi_count_resources(adev); 99 100 if (ret < 0) 100 101 return ret; 101 - else if (!ret) 102 - return -ENODEV; 102 + if (!ret) 103 + return -ENOENT; 103 104 104 105 count = ret; 105 106 ··· 111 112 112 113 spi_dev = acpi_spi_device_alloc(NULL, adev, i); 113 114 if (IS_ERR(spi_dev)) { 114 - ret = PTR_ERR(spi_dev); 115 - dev_err_probe(dev, ret, "failed to allocate SPI device %s from ACPI: %d\n", 116 - dev_name(&adev->dev), ret); 115 + ret = dev_err_probe(dev, PTR_ERR(spi_dev), "failed to allocate SPI device %s from ACPI\n", 116 + dev_name(&adev->dev)); 117 117 goto error; 118 118 } 119 119 ··· 133 135 134 136 ret = spi_add_device(spi_dev); 135 137 if (ret) { 136 - dev_err_probe(&ctlr->dev, ret, 137 - "failed to add SPI device %s from ACPI: %d\n", 138 - dev_name(&adev->dev), ret); 138 + dev_err_probe(&ctlr->dev, ret, "failed to add SPI device %s from ACPI\n", 139 + dev_name(&adev->dev)); 139 140 spi_dev_put(spi_dev); 140 141 goto error; 141 142 } ··· 163 166 /** 164 167 * smi_i2c_probe - Instantiate multiple I2C devices from inst array 165 168 * @pdev: Platform device 166 - * @adev: ACPI device 167 169 * @smi: Internal struct for Serial multi instantiate driver 168 170 * @inst_array: Array of instances to probe 169 171 * 170 172 * Returns the number of I2C devices instantiate, Zero if none is found or a negative error code. 171 173 */ 172 - static int smi_i2c_probe(struct platform_device *pdev, struct acpi_device *adev, struct smi *smi, 174 + static int smi_i2c_probe(struct platform_device *pdev, struct smi *smi, 173 175 const struct smi_instance *inst_array) 174 176 { 175 177 struct i2c_board_info board_info = {}; 176 178 struct device *dev = &pdev->dev; 179 + struct acpi_device *adev = ACPI_COMPANION(dev); 177 180 char name[32]; 178 181 int i, ret, count; 179 182 180 183 ret = i2c_acpi_client_count(adev); 181 184 if (ret < 0) 182 185 return ret; 183 - else if (!ret) 184 - return -ENODEV; 186 + if (!ret) 187 + return -ENOENT; 185 188 186 189 count = ret; 187 190 ··· 227 230 { 228 231 struct device *dev = &pdev->dev; 229 232 const struct smi_node *node; 230 - struct acpi_device *adev; 231 233 struct smi *smi; 232 - 233 - adev = ACPI_COMPANION(dev); 234 - if (!adev) 235 - return -ENODEV; 234 + int ret; 236 235 237 236 node = device_get_match_data(dev); 238 237 if (!node) { ··· 244 251 245 252 switch (node->bus_type) { 246 253 case SMI_I2C: 247 - return smi_i2c_probe(pdev, adev, smi, node->instances); 254 + return smi_i2c_probe(pdev, smi, node->instances); 248 255 case SMI_SPI: 249 - return smi_spi_probe(pdev, adev, smi, node->instances); 256 + return smi_spi_probe(pdev, smi, node->instances); 250 257 case SMI_AUTO_DETECT: 251 - if (i2c_acpi_client_count(adev) > 0) 252 - return smi_i2c_probe(pdev, adev, smi, node->instances); 253 - else 254 - return smi_spi_probe(pdev, adev, smi, node->instances); 258 + /* 259 + * For backwards-compatibility with the existing nodes I2C 260 + * is checked first and if such entries are found ONLY I2C 261 + * devices are created. Since some existing nodes that were 262 + * already handled by this driver could also contain unrelated 263 + * SpiSerialBus nodes that were previously ignored, and this 264 + * preserves that behavior. 265 + */ 266 + ret = smi_i2c_probe(pdev, smi, node->instances); 267 + if (ret != -ENOENT) 268 + return ret; 269 + return smi_spi_probe(pdev, smi, node->instances); 255 270 default: 256 271 return -EINVAL; 257 272 } 258 - 259 - return 0; /* never reached */ 260 273 } 261 274 262 275 static int smi_remove(struct platform_device *pdev) ··· 324 325 static const struct acpi_device_id smi_acpi_ids[] = { 325 326 { "BSG1160", (unsigned long)&bsg1160_data }, 326 327 { "BSG2150", (unsigned long)&bsg2150_data }, 327 - { "INT3515", (unsigned long)&int3515_data }, 328 328 { "CSC3551", (unsigned long)&cs35l41_hda }, 329 + { "INT3515", (unsigned long)&int3515_data }, 329 330 /* Non-conforming _HID for Cirrus Logic already released */ 330 331 { "CLSA0100", (unsigned long)&cs35l41_hda }, 331 332 { }
+4 -39
drivers/platform/x86/simatic-ipc.c
··· 51 51 { 52 52 u8 ledmode = SIMATIC_IPC_DEVICE_NONE; 53 53 u8 wdtmode = SIMATIC_IPC_DEVICE_NONE; 54 + char *pdevname = KBUILD_MODNAME "_leds"; 54 55 int i; 55 56 56 57 platform_data.devmode = SIMATIC_IPC_DEVICE_NONE; ··· 65 64 } 66 65 67 66 if (ledmode != SIMATIC_IPC_DEVICE_NONE) { 67 + if (ledmode == SIMATIC_IPC_DEVICE_127E) 68 + pdevname = KBUILD_MODNAME "_leds_gpio"; 68 69 platform_data.devmode = ledmode; 69 70 ipc_led_platform_device = 70 71 platform_device_register_data(NULL, 71 - KBUILD_MODNAME "_leds", PLATFORM_DEVID_NONE, 72 + pdevname, PLATFORM_DEVID_NONE, 72 73 &platform_data, 73 74 sizeof(struct simatic_ipc_platform)); 74 75 if (IS_ERR(ipc_led_platform_device)) ··· 103 100 104 101 return 0; 105 102 } 106 - 107 - /* FIXME: this should eventually be done with generic P2SB discovery code 108 - * the individual drivers for watchdogs and LEDs access memory that implements 109 - * GPIO, but pinctrl will not come up because of missing ACPI entries 110 - * 111 - * While there is no conflict a cleaner solution would be to somehow bring up 112 - * pinctrl even with these ACPI entries missing, and base the drivers on pinctrl. 113 - * After which the following function could be dropped, together with the code 114 - * poking the memory. 115 - */ 116 - /* 117 - * Get membase address from PCI, used in leds and wdt module. Here we read 118 - * the bar0. The final address calculation is done in the appropriate modules 119 - */ 120 - u32 simatic_ipc_get_membase0(unsigned int p2sb) 121 - { 122 - struct pci_bus *bus; 123 - u32 bar0 = 0; 124 - /* 125 - * The GPIO memory is in bar0 of the hidden P2SB device. 126 - * Unhide the device to have a quick look at it, before we hide it 127 - * again. 128 - * Also grab the pci rescan lock so that device does not get discovered 129 - * and remapped while it is visible. 130 - * This code is inspired by drivers/mfd/lpc_ich.c 131 - */ 132 - bus = pci_find_bus(0, 0); 133 - pci_lock_rescan_remove(); 134 - pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x0); 135 - pci_bus_read_config_dword(bus, p2sb, PCI_BASE_ADDRESS_0, &bar0); 136 - 137 - bar0 &= ~0xf; 138 - pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x1); 139 - pci_unlock_rescan_remove(); 140 - 141 - return bar0; 142 - } 143 - EXPORT_SYMBOL(simatic_ipc_get_membase0); 144 103 145 104 static int __init simatic_ipc_init_module(void) 146 105 {
+1 -6
drivers/platform/x86/sony-laptop.c
··· 4341 4341 { 4342 4342 struct acpi_resource_irq *p = &resource->data.irq; 4343 4343 struct sony_pic_irq *interrupt = NULL; 4344 - if (!p || !p->interrupt_count) { 4344 + if (!p->interrupt_count) { 4345 4345 /* 4346 4346 * IRQ descriptors may have no IRQ# bits set, 4347 4347 * particularly those those w/ _STA disabled ··· 4374 4374 struct acpi_resource_io *io = &resource->data.io; 4375 4375 struct sony_pic_ioport *ioport = 4376 4376 list_first_entry(&dev->ioports, struct sony_pic_ioport, list); 4377 - if (!io) { 4378 - dprintk("Blank IO resource\n"); 4379 - return AE_OK; 4380 - } 4381 - 4382 4377 if (!ioport->io1.minimum) { 4383 4378 memcpy(&ioport->io1, io, sizeof(*io)); 4384 4379 dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
+2 -2
drivers/platform/x86/system76_acpi.c
··· 339 339 struct led_classdev *led; 340 340 struct system76_data *data; 341 341 342 - led = (struct led_classdev *)dev->driver_data; 342 + led = dev_get_drvdata(dev); 343 343 data = container_of(led, struct system76_data, kb_led); 344 344 return sysfs_emit(buf, "%06X\n", data->kb_color); 345 345 } ··· 356 356 unsigned int val; 357 357 int ret; 358 358 359 - led = (struct led_classdev *)dev->driver_data; 359 + led = dev_get_drvdata(dev); 360 360 data = container_of(led, struct system76_data, kb_led); 361 361 ret = kstrtouint(buf, 16, &val); 362 362 if (ret)
+103 -65
drivers/platform/x86/thinkpad_acpi.c
··· 34 34 * thanks to Chris Wright <chrisw@osdl.org> 35 35 */ 36 36 37 - #include <linux/kernel.h> 38 - #include <linux/module.h> 39 - #include <linux/init.h> 40 - #include <linux/types.h> 41 - #include <linux/string.h> 42 - #include <linux/list.h> 43 - #include <linux/mutex.h> 44 - #include <linux/sched.h> 45 - #include <linux/sched/signal.h> 46 - #include <linux/kthread.h> 47 - #include <linux/freezer.h> 48 - #include <linux/delay.h> 49 - #include <linux/slab.h> 50 - #include <linux/nvram.h> 51 - #include <linux/proc_fs.h> 52 - #include <linux/seq_file.h> 53 - #include <linux/sysfs.h> 37 + #include <linux/acpi.h> 54 38 #include <linux/backlight.h> 55 39 #include <linux/bitops.h> 40 + #include <linux/delay.h> 41 + #include <linux/dmi.h> 56 42 #include <linux/fb.h> 57 - #include <linux/platform_device.h> 43 + #include <linux/freezer.h> 58 44 #include <linux/hwmon.h> 59 45 #include <linux/hwmon-sysfs.h> 46 + #include <linux/init.h> 60 47 #include <linux/input.h> 61 - #include <linux/leds.h> 62 - #include <linux/rfkill.h> 63 - #include <linux/dmi.h> 64 48 #include <linux/jiffies.h> 65 - #include <linux/workqueue.h> 66 - #include <linux/acpi.h> 49 + #include <linux/kernel.h> 50 + #include <linux/kthread.h> 51 + #include <linux/leds.h> 52 + #include <linux/list.h> 53 + #include <linux/module.h> 54 + #include <linux/mutex.h> 55 + #include <linux/nvram.h> 67 56 #include <linux/pci.h> 68 - #include <linux/power_supply.h> 57 + #include <linux/platform_device.h> 69 58 #include <linux/platform_profile.h> 70 - #include <sound/core.h> 71 - #include <sound/control.h> 72 - #include <sound/initval.h> 59 + #include <linux/power_supply.h> 60 + #include <linux/proc_fs.h> 61 + #include <linux/rfkill.h> 62 + #include <linux/sched.h> 63 + #include <linux/sched/signal.h> 64 + #include <linux/seq_file.h> 65 + #include <linux/slab.h> 66 + #include <linux/string.h> 67 + #include <linux/string_helpers.h> 68 + #include <linux/sysfs.h> 69 + #include <linux/types.h> 73 70 #include <linux/uaccess.h> 71 + #include <linux/workqueue.h> 72 + 74 73 #include <acpi/battery.h> 75 74 #include <acpi/video.h> 75 + 76 76 #include <drm/drm_privacy_screen_driver.h> 77 + 78 + #include <sound/control.h> 79 + #include <sound/core.h> 80 + #include <sound/initval.h> 81 + 77 82 #include "dual_accel_detect.h" 78 83 79 84 /* ThinkPad CMOS commands */ ··· 164 159 TP_HKEY_EV_VOL_DOWN = 0x1016, /* Volume down or unmute */ 165 160 TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ 166 161 TP_HKEY_EV_PRIVACYGUARD_TOGGLE = 0x130f, /* Toggle priv.guard on/off */ 162 + TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */ 167 163 168 164 /* Reasons for waking up from S3/S4 */ 169 165 TP_HKEY_EV_WKUP_S3_UNDOCK = 0x2304, /* undock requested, S3 */ ··· 263 257 #define TPACPI_DBG_BRGHT 0x0020 264 258 #define TPACPI_DBG_MIXER 0x0040 265 259 266 - #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") 267 - #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") 268 260 #define strlencmp(a, b) (strncmp((a), (b), strlen(b))) 269 261 270 262 ··· 1316 1312 return status; 1317 1313 } 1318 1314 1319 - seq_printf(m, "status:\t\t%s\n", 1320 - (status == TPACPI_RFK_RADIO_ON) ? 1321 - "enabled" : "disabled"); 1315 + seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status == TPACPI_RFK_RADIO_ON)); 1322 1316 seq_printf(m, "commands:\tenable, disable\n"); 1323 1317 } 1324 1318 ··· 1343 1341 1344 1342 if (status != -1) { 1345 1343 tpacpi_disclose_usertask("procfs", "attempt to %s %s\n", 1346 - (status == TPACPI_RFK_RADIO_ON) ? 1347 - "enable" : "disable", 1344 + str_enable_disable(status == TPACPI_RFK_RADIO_ON), 1348 1345 tpacpi_rfkill_names[id]); 1349 1346 res = (tpacpi_rfkill_switches[id]->ops->set_status)(status); 1350 1347 tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); ··· 3500 3499 if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { 3501 3500 tp_features.hotkey_wlsw = 1; 3502 3501 radiosw_state = !!status; 3503 - pr_info("radio switch found; radios are %s\n", 3504 - enabled(status, 0)); 3502 + pr_info("radio switch found; radios are %s\n", str_enabled_disabled(status & BIT(0))); 3505 3503 } 3506 3504 3507 3505 tabletsw_state = hotkey_init_tablet_mode(); ··· 3735 3735 3736 3736 switch (hkey) { 3737 3737 case TP_HKEY_EV_PRIVACYGUARD_TOGGLE: 3738 + case TP_HKEY_EV_AMT_TOGGLE: 3738 3739 tpacpi_driver_event(hkey); 3739 3740 return true; 3740 3741 } ··· 4160 4159 if (res) 4161 4160 return res; 4162 4161 4163 - seq_printf(m, "status:\t\t%s\n", enabled(status, 0)); 4162 + seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status & BIT(0))); 4164 4163 if (hotkey_all_mask) { 4165 4164 seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask); 4166 4165 seq_printf(m, "commands:\tenable, disable, reset, <mask>\n"); ··· 4293 4292 { 4294 4293 int status; 4295 4294 4296 - vdbg_printk(TPACPI_DBG_RFKILL, 4297 - "will attempt to %s bluetooth\n", 4298 - (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); 4295 + vdbg_printk(TPACPI_DBG_RFKILL, "will attempt to %s bluetooth\n", 4296 + str_enable_disable(state == TPACPI_RFK_RADIO_ON)); 4299 4297 4300 4298 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 4301 4299 if (dbg_bluetoothemul) { ··· 4659 4659 { 4660 4660 int status; 4661 4661 4662 - vdbg_printk(TPACPI_DBG_RFKILL, 4663 - "will attempt to %s wwan\n", 4664 - (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); 4662 + vdbg_printk(TPACPI_DBG_RFKILL, "will attempt to %s wwan\n", 4663 + str_enable_disable(state == TPACPI_RFK_RADIO_ON)); 4665 4664 4666 4665 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 4667 4666 if (dbg_wwanemul) { ··· 4836 4837 { 4837 4838 int status; 4838 4839 4839 - vdbg_printk(TPACPI_DBG_RFKILL, 4840 - "will attempt to %s UWB\n", 4841 - (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); 4840 + vdbg_printk(TPACPI_DBG_RFKILL, "will attempt to %s UWB\n", 4841 + str_enable_disable(state == TPACPI_RFK_RADIO_ON)); 4842 4842 4843 4843 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 4844 4844 if (dbg_uwbemul) { ··· 5191 5193 return autosw; 5192 5194 5193 5195 seq_printf(m, "status:\t\tsupported\n"); 5194 - seq_printf(m, "lcd:\t\t%s\n", enabled(status, 0)); 5195 - seq_printf(m, "crt:\t\t%s\n", enabled(status, 1)); 5196 + seq_printf(m, "lcd:\t\t%s\n", str_enabled_disabled(status & BIT(0))); 5197 + seq_printf(m, "crt:\t\t%s\n", str_enabled_disabled(status & BIT(1))); 5196 5198 if (video_supported == TPACPI_VIDEO_NEW) 5197 - seq_printf(m, "dvi:\t\t%s\n", enabled(status, 3)); 5198 - seq_printf(m, "auto:\t\t%s\n", enabled(autosw, 0)); 5199 + seq_printf(m, "dvi:\t\t%s\n", str_enabled_disabled(status & BIT(3))); 5200 + seq_printf(m, "auto:\t\t%s\n", str_enabled_disabled(autosw & BIT(0))); 5199 5201 seq_printf(m, "commands:\tlcd_enable, lcd_disable\n"); 5200 5202 seq_printf(m, "commands:\tcrt_enable, crt_disable\n"); 5201 5203 if (video_supported == TPACPI_VIDEO_NEW) ··· 5626 5628 status = light_get_status(); 5627 5629 if (status < 0) 5628 5630 return status; 5629 - seq_printf(m, "status:\t\t%s\n", onoff(status, 0)); 5631 + seq_printf(m, "status:\t\t%s\n", str_on_off(status & BIT(0))); 5630 5632 seq_printf(m, "commands:\ton, off\n"); 5631 5633 } 5632 5634 ··· 6082 6084 return 0; 6083 6085 } 6084 6086 6085 - #define str_led_status(s) \ 6086 - ((s) == TPACPI_LED_OFF ? "off" : \ 6087 - ((s) == TPACPI_LED_ON ? "on" : "blinking")) 6087 + #define str_led_status(s) ((s) >= TPACPI_LED_BLINK ? "blinking" : str_on_off(s)) 6088 6088 6089 6089 static int led_read(struct seq_file *m) 6090 6090 { ··· 6099 6103 status = led_get_status(i); 6100 6104 if (status < 0) 6101 6105 return -EIO; 6102 - seq_printf(m, "%d:\t\t%s\n", 6103 - i, str_led_status(status)); 6106 + seq_printf(m, "%d:\t\t%s\n", i, str_led_status(status)); 6104 6107 } 6105 6108 } 6106 6109 ··· 6792 6797 6793 6798 static int brightness_update_status(struct backlight_device *bd) 6794 6799 { 6795 - unsigned int level = 6796 - (bd->props.fb_blank == FB_BLANK_UNBLANK && 6797 - bd->props.power == FB_BLANK_UNBLANK) ? 6798 - bd->props.brightness : 0; 6800 + int level = backlight_get_brightness(bd); 6799 6801 6800 6802 dbg_printk(TPACPI_DBG_BRGHT, 6801 6803 "backlight: attempt to set level to %d\n", ··· 7822 7830 seq_printf(m, "level:\t\t%d\n", 7823 7831 status & TP_EC_AUDIO_LVL_MSK); 7824 7832 7825 - seq_printf(m, "mute:\t\t%s\n", 7826 - onoff(status, TP_EC_AUDIO_MUTESW)); 7833 + seq_printf(m, "mute:\t\t%s\n", str_on_off(status & BIT(TP_EC_AUDIO_MUTESW))); 7827 7834 7828 7835 if (volume_control_allowed) { 7829 7836 seq_printf(m, "commands:\tunmute, mute\n"); ··· 9051 9060 9052 9061 seq_printf(m, "status:\t\t%s\n" 9053 9062 "level:\t\t%d\n", 9054 - (status != 0) ? "enabled" : "disabled", status); 9063 + str_enabled_disabled(status), status); 9055 9064 break; 9056 9065 9057 9066 case TPACPI_FAN_RD_TPEC: ··· 9060 9069 if (rc) 9061 9070 return rc; 9062 9071 9063 - seq_printf(m, "status:\t\t%s\n", 9064 - (status != 0) ? "enabled" : "disabled"); 9072 + seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status)); 9065 9073 9066 9074 rc = fan_get_speed(&speed); 9067 9075 if (rc < 0) ··· 10258 10268 #define DYTC_CMD_FUNC_CAP 3 /* To get DYTC capabilities */ 10259 10269 #define DYTC_FC_MMC 27 /* MMC Mode supported */ 10260 10270 #define DYTC_FC_PSC 29 /* PSC Mode supported */ 10271 + #define DYTC_FC_AMT 31 /* AMT mode supported */ 10261 10272 10262 10273 #define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */ 10263 10274 #define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */ ··· 10271 10280 #define DYTC_FUNCTION_CQL 1 /* Function = 1, lap mode */ 10272 10281 #define DYTC_FUNCTION_MMC 11 /* Function = 11, MMC mode */ 10273 10282 #define DYTC_FUNCTION_PSC 13 /* Function = 13, PSC mode */ 10283 + #define DYTC_FUNCTION_AMT 15 /* Function = 15, AMT mode */ 10284 + 10285 + #define DYTC_MODE_AMT_ENABLE 0x1 /* Enable AMT (in balanced mode) */ 10286 + #define DYTC_MODE_AMT_DISABLE 0xF /* Disable AMT (in other modes) */ 10274 10287 10275 10288 #define DYTC_MODE_MMC_PERFORM 2 /* High power mode aka performance */ 10276 10289 #define DYTC_MODE_MMC_LOWPOWER 3 /* Low power mode */ ··· 10295 10300 10296 10301 #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0) 10297 10302 #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1) 10303 + static int dytc_control_amt(bool enable); 10304 + static bool dytc_amt_active; 10298 10305 10299 10306 static enum platform_profile_option dytc_current_profile; 10300 10307 static atomic_t dytc_ignore_event = ATOMIC_INIT(0); ··· 10376 10379 enum platform_profile_option *profile) 10377 10380 { 10378 10381 *profile = dytc_current_profile; 10382 + return 0; 10383 + } 10384 + 10385 + static int dytc_control_amt(bool enable) 10386 + { 10387 + int dummy; 10388 + int err; 10389 + int cmd; 10390 + 10391 + if (!(dytc_capabilities & BIT(DYTC_FC_AMT))) { 10392 + pr_warn("Attempting to toggle AMT on a system that doesn't advertise support\n"); 10393 + return -ENODEV; 10394 + } 10395 + 10396 + if (enable) 10397 + cmd = DYTC_SET_COMMAND(DYTC_FUNCTION_AMT, DYTC_MODE_AMT_ENABLE, enable); 10398 + else 10399 + cmd = DYTC_SET_COMMAND(DYTC_FUNCTION_AMT, DYTC_MODE_AMT_DISABLE, enable); 10400 + 10401 + pr_debug("%sabling AMT (cmd 0x%x)", enable ? "en":"dis", cmd); 10402 + err = dytc_command(cmd, &dummy); 10403 + if (err) 10404 + return err; 10405 + dytc_amt_active = enable; 10379 10406 return 0; 10380 10407 } 10381 10408 ··· 10485 10464 err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output); 10486 10465 if (err) 10487 10466 goto unlock; 10467 + /* system supports AMT, activate it when on balanced */ 10468 + if (dytc_capabilities & BIT(DYTC_FC_AMT)) 10469 + dytc_control_amt(profile == PLATFORM_PROFILE_BALANCED); 10488 10470 } 10489 10471 /* Success - update current profile */ 10490 10472 dytc_current_profile = profile; ··· 10591 10567 10592 10568 /* Ensure initial values are correct */ 10593 10569 dytc_profile_refresh(); 10570 + 10571 + /* Set AMT correctly now we know current profile */ 10572 + if ((dytc_capabilities & BIT(DYTC_FC_PSC)) && 10573 + (dytc_capabilities & BIT(DYTC_FC_AMT))) 10574 + dytc_control_amt(dytc_current_profile == PLATFORM_PROFILE_BALANCED); 10594 10575 10595 10576 return 0; 10596 10577 } ··· 11040 11011 if (changed) 11041 11012 drm_privacy_screen_call_notifier_chain(lcdshadow_dev); 11042 11013 } 11014 + if (hkey_event == TP_HKEY_EV_AMT_TOGGLE) { 11015 + /* If we're enabling AMT we need to force balanced mode */ 11016 + if (!dytc_amt_active) 11017 + /* This will also set AMT mode enabled */ 11018 + dytc_profile_set(NULL, PLATFORM_PROFILE_BALANCED); 11019 + else 11020 + dytc_control_amt(!dytc_amt_active); 11021 + } 11022 + 11043 11023 } 11044 11024 11045 11025 static void hotkey_driver_event(const unsigned int scancode)
+2 -2
drivers/power/supply/surface_battery.c
··· 802 802 if (IS_ERR(bat->psy)) 803 803 return PTR_ERR(bat->psy); 804 804 805 - return ssam_notifier_register(bat->sdev->ctrl, &bat->notif); 805 + return ssam_device_notifier_register(bat->sdev, &bat->notif); 806 806 } 807 807 808 808 ··· 837 837 { 838 838 struct spwr_battery_device *bat = ssam_device_get_drvdata(sdev); 839 839 840 - ssam_notifier_unregister(sdev->ctrl, &bat->notif); 840 + ssam_device_notifier_unregister(sdev, &bat->notif); 841 841 cancel_delayed_work_sync(&bat->update_work); 842 842 } 843 843
+2 -2
drivers/power/supply/surface_charger.c
··· 216 216 if (IS_ERR(ac->psy)) 217 217 return PTR_ERR(ac->psy); 218 218 219 - return ssam_notifier_register(ac->sdev->ctrl, &ac->notif); 219 + return ssam_device_notifier_register(ac->sdev, &ac->notif); 220 220 } 221 221 222 222 ··· 251 251 { 252 252 struct spwr_ac_device *ac = ssam_device_get_drvdata(sdev); 253 253 254 - ssam_notifier_unregister(sdev->ctrl, &ac->notif); 254 + ssam_device_notifier_unregister(sdev, &ac->notif); 255 255 } 256 256 257 257 static const struct spwr_psy_properties spwr_psy_props_adp1 = {
+1
drivers/watchdog/Kconfig
··· 1647 1647 tristate "Siemens Simatic IPC Watchdog" 1648 1648 depends on SIEMENS_SIMATIC_IPC 1649 1649 select WATCHDOG_CORE 1650 + select P2SB 1650 1651 help 1651 1652 This driver adds support for several watchdogs found in Industrial 1652 1653 PCs from Siemens.
+8 -7
drivers/watchdog/simatic-ipc-wdt.c
··· 16 16 #include <linux/kernel.h> 17 17 #include <linux/module.h> 18 18 #include <linux/pci.h> 19 + #include <linux/platform_data/x86/p2sb.h> 19 20 #include <linux/platform_data/x86/simatic-ipc-base.h> 20 21 #include <linux/platform_device.h> 21 22 #include <linux/sizes.h> ··· 55 54 DEFINE_RES_IO_NAMED(WD_TRIGGER_IOADR, SZ_1, 56 55 KBUILD_MODNAME " WD_TRIGGER_IOADR"); 57 56 58 - /* the actual start will be discovered with pci, 0 is a placeholder */ 57 + /* the actual start will be discovered with p2sb, 0 is a placeholder */ 59 58 static struct resource mem_resource = 60 - DEFINE_RES_MEM_NAMED(0, SZ_4, "WD_RESET_BASE_ADR"); 59 + DEFINE_RES_MEM_NAMED(0, 0, "WD_RESET_BASE_ADR"); 61 60 62 61 static u32 wd_timeout_table[] = {2, 4, 6, 8, 16, 32, 48, 64 }; 63 62 static void __iomem *wd_reset_base_addr; ··· 151 150 struct simatic_ipc_platform *plat = pdev->dev.platform_data; 152 151 struct device *dev = &pdev->dev; 153 152 struct resource *res; 153 + int ret; 154 154 155 155 switch (plat->devmode) { 156 156 case SIMATIC_IPC_DEVICE_227E: ··· 192 190 if (plat->devmode == SIMATIC_IPC_DEVICE_427E) { 193 191 res = &mem_resource; 194 192 195 - /* get GPIO base from PCI */ 196 - res->start = simatic_ipc_get_membase0(PCI_DEVFN(0x1f, 1)); 197 - if (res->start == 0) 198 - return -ENODEV; 193 + ret = p2sb_bar(NULL, 0, res); 194 + if (ret) 195 + return ret; 199 196 200 197 /* do the final address calculation */ 201 198 res->start = res->start + (GPIO_COMMUNITY0_PORT_ID << 16) + 202 199 PAD_CFG_DW0_GPP_A_23; 203 - res->end += res->start; 200 + res->end = res->start + SZ_4 - 1; 204 201 205 202 wd_reset_base_addr = devm_ioremap_resource(dev, res); 206 203 if (IS_ERR(wd_reset_base_addr))
+1
include/linux/platform_data/x86/asus-wmi.h
··· 49 49 #define ASUS_WMI_DEVID_LED4 0x00020014 50 50 #define ASUS_WMI_DEVID_LED5 0x00020015 51 51 #define ASUS_WMI_DEVID_LED6 0x00020016 52 + #define ASUS_WMI_DEVID_MICMUTE_LED 0x00040017 52 53 53 54 /* Backlight and Brightness */ 54 55 #define ASUS_WMI_DEVID_ALS_ENABLE 0x00050001 /* Ambient Light Sensor */
+28
include/linux/platform_data/x86/p2sb.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Primary to Sideband (P2SB) bridge access support 4 + */ 5 + 6 + #ifndef _PLATFORM_DATA_X86_P2SB_H 7 + #define _PLATFORM_DATA_X86_P2SB_H 8 + 9 + #include <linux/errno.h> 10 + #include <linux/kconfig.h> 11 + 12 + struct pci_bus; 13 + struct resource; 14 + 15 + #if IS_BUILTIN(CONFIG_P2SB) 16 + 17 + int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem); 18 + 19 + #else /* CONFIG_P2SB */ 20 + 21 + static inline int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 22 + { 23 + return -ENODEV; 24 + } 25 + 26 + #endif /* CONFIG_P2SB is not set */ 27 + 28 + #endif /* _PLATFORM_DATA_X86_P2SB_H */
+1 -1
include/linux/platform_data/x86/pmc_atom.h
··· 47 47 #define PMC_S0I2_TMR 0x88 48 48 #define PMC_S0I3_TMR 0x8C 49 49 #define PMC_S0_TMR 0x90 50 - /* Sleep state counter is in units of of 32us */ 50 + /* Sleep state counter is in units of 32us */ 51 51 #define PMC_TMR_SHIFT 5 52 52 53 53 /* Power status of power islands */
-2
include/linux/platform_data/x86/simatic-ipc-base.h
··· 24 24 u8 devmode; 25 25 }; 26 26 27 - u32 simatic_ipc_get_membase0(unsigned int p2sb); 28 - 29 27 #endif /* __PLATFORM_DATA_X86_SIMATIC_IPC_BASE_H */
+147 -2
include/linux/surface_aggregator/controller.h
··· 470 470 } 471 471 472 472 /** 473 + * SSAM_DEFINE_SYNC_REQUEST_WR() - Define synchronous SAM request function with 474 + * both argument and return value. 475 + * @name: Name of the generated function. 476 + * @atype: Type of the request's argument. 477 + * @rtype: Type of the request's return value. 478 + * @spec: Specification (&struct ssam_request_spec) defining the request. 479 + * 480 + * Defines a function executing the synchronous SAM request specified by @spec, 481 + * with the request taking an argument of type @atype and having a return value 482 + * of type @rtype. The generated function takes care of setting up the request 483 + * and response structs, buffer allocation, as well as execution of the request 484 + * itself, returning once the request has been fully completed. The required 485 + * transport buffer will be allocated on the stack. 486 + * 487 + * The generated function is defined as ``static int name(struct 488 + * ssam_controller *ctrl, const atype *arg, rtype *ret)``, returning the status 489 + * of the request, which is zero on success and negative on failure. The 490 + * ``ctrl`` parameter is the controller via which the request is sent. The 491 + * request argument is specified via the ``arg`` pointer. The request's return 492 + * value is written to the memory pointed to by the ``ret`` parameter. 493 + * 494 + * Refer to ssam_request_sync_onstack() for more details on the behavior of 495 + * the generated function. 496 + */ 497 + #define SSAM_DEFINE_SYNC_REQUEST_WR(name, atype, rtype, spec...) \ 498 + static int name(struct ssam_controller *ctrl, const atype *arg, rtype *ret) \ 499 + { \ 500 + struct ssam_request_spec s = (struct ssam_request_spec)spec; \ 501 + struct ssam_request rqst; \ 502 + struct ssam_response rsp; \ 503 + int status; \ 504 + \ 505 + rqst.target_category = s.target_category; \ 506 + rqst.target_id = s.target_id; \ 507 + rqst.command_id = s.command_id; \ 508 + rqst.instance_id = s.instance_id; \ 509 + rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \ 510 + rqst.length = sizeof(atype); \ 511 + rqst.payload = (u8 *)arg; \ 512 + \ 513 + rsp.capacity = sizeof(rtype); \ 514 + rsp.length = 0; \ 515 + rsp.pointer = (u8 *)ret; \ 516 + \ 517 + status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ 518 + if (status) \ 519 + return status; \ 520 + \ 521 + if (rsp.length != sizeof(rtype)) { \ 522 + struct device *dev = ssam_controller_device(ctrl); \ 523 + dev_err(dev, \ 524 + "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \ 525 + sizeof(rtype), rsp.length, rqst.target_category,\ 526 + rqst.command_id); \ 527 + return -EIO; \ 528 + } \ 529 + \ 530 + return 0; \ 531 + } 532 + 533 + /** 473 534 * SSAM_DEFINE_SYNC_REQUEST_MD_N() - Define synchronous multi-device SAM 474 535 * request function with neither argument nor return value. 475 536 * @name: Name of the generated function. ··· 659 598 rsp.pointer = (u8 *)ret; \ 660 599 \ 661 600 status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, 0); \ 601 + if (status) \ 602 + return status; \ 603 + \ 604 + if (rsp.length != sizeof(rtype)) { \ 605 + struct device *dev = ssam_controller_device(ctrl); \ 606 + dev_err(dev, \ 607 + "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \ 608 + sizeof(rtype), rsp.length, rqst.target_category,\ 609 + rqst.command_id); \ 610 + return -EIO; \ 611 + } \ 612 + \ 613 + return 0; \ 614 + } 615 + 616 + /** 617 + * SSAM_DEFINE_SYNC_REQUEST_MD_WR() - Define synchronous multi-device SAM 618 + * request function with both argument and return value. 619 + * @name: Name of the generated function. 620 + * @atype: Type of the request's argument. 621 + * @rtype: Type of the request's return value. 622 + * @spec: Specification (&struct ssam_request_spec_md) defining the request. 623 + * 624 + * Defines a function executing the synchronous SAM request specified by @spec, 625 + * with the request taking an argument of type @atype and having a return value 626 + * of type @rtype. Device specifying parameters are not hard-coded, but instead 627 + * must be provided to the function. The generated function takes care of 628 + * setting up the request and response structs, buffer allocation, as well as 629 + * execution of the request itself, returning once the request has been fully 630 + * completed. The required transport buffer will be allocated on the stack. 631 + * 632 + * The generated function is defined as ``static int name(struct 633 + * ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg, rtype *ret)``, 634 + * returning the status of the request, which is zero on success and negative 635 + * on failure. The ``ctrl`` parameter is the controller via which the request 636 + * is sent, ``tid`` the target ID for the request, and ``iid`` the instance ID. 637 + * The request argument is specified via the ``arg`` pointer. The request's 638 + * return value is written to the memory pointed to by the ``ret`` parameter. 639 + * 640 + * Refer to ssam_request_sync_onstack() for more details on the behavior of 641 + * the generated function. 642 + */ 643 + #define SSAM_DEFINE_SYNC_REQUEST_MD_WR(name, atype, rtype, spec...) \ 644 + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, \ 645 + const atype *arg, rtype *ret) \ 646 + { \ 647 + struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \ 648 + struct ssam_request rqst; \ 649 + struct ssam_response rsp; \ 650 + int status; \ 651 + \ 652 + rqst.target_category = s.target_category; \ 653 + rqst.target_id = tid; \ 654 + rqst.command_id = s.command_id; \ 655 + rqst.instance_id = iid; \ 656 + rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \ 657 + rqst.length = sizeof(atype); \ 658 + rqst.payload = (u8 *)arg; \ 659 + \ 660 + rsp.capacity = sizeof(rtype); \ 661 + rsp.length = 0; \ 662 + rsp.pointer = (u8 *)ret; \ 663 + \ 664 + status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ 662 665 if (status) \ 663 666 return status; \ 664 667 \ ··· 960 835 int ssam_notifier_register(struct ssam_controller *ctrl, 961 836 struct ssam_event_notifier *n); 962 837 963 - int ssam_notifier_unregister(struct ssam_controller *ctrl, 964 - struct ssam_event_notifier *n); 838 + int __ssam_notifier_unregister(struct ssam_controller *ctrl, 839 + struct ssam_event_notifier *n, bool disable); 840 + 841 + /** 842 + * ssam_notifier_unregister() - Unregister an event notifier. 843 + * @ctrl: The controller the notifier has been registered on. 844 + * @n: The event notifier to unregister. 845 + * 846 + * Unregister an event notifier. Decrement the usage counter of the associated 847 + * SAM event if the notifier is not marked as an observer. If the usage counter 848 + * reaches zero, the event will be disabled. 849 + * 850 + * Return: Returns zero on success, %-ENOENT if the given notifier block has 851 + * not been registered on the controller. If the given notifier block was the 852 + * last one associated with its specific event, returns the status of the 853 + * event-disable EC-command. 854 + */ 855 + static inline int ssam_notifier_unregister(struct ssam_controller *ctrl, 856 + struct ssam_event_notifier *n) 857 + { 858 + return __ssam_notifier_unregister(ctrl, n, true); 859 + } 965 860 966 861 int ssam_controller_event_enable(struct ssam_controller *ctrl, 967 862 struct ssam_event_registry reg,
+210 -3
include/linux/surface_aggregator/device.h
··· 15 15 16 16 #include <linux/device.h> 17 17 #include <linux/mod_devicetable.h> 18 + #include <linux/property.h> 18 19 #include <linux/types.h> 19 20 20 21 #include <linux/surface_aggregator/controller.h> ··· 149 148 #define SSAM_SDEV(cat, tid, iid, fun) \ 150 149 SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun) 151 150 151 + /* 152 + * enum ssam_device_flags - Flags for SSAM client devices. 153 + * @SSAM_DEVICE_HOT_REMOVED_BIT: 154 + * The device has been hot-removed. Further communication with it may time 155 + * out and should be avoided. 156 + */ 157 + enum ssam_device_flags { 158 + SSAM_DEVICE_HOT_REMOVED_BIT = 0, 159 + }; 160 + 152 161 /** 153 162 * struct ssam_device - SSAM client device. 154 - * @dev: Driver model representation of the device. 155 - * @ctrl: SSAM controller managing this device. 156 - * @uid: UID identifying the device. 163 + * @dev: Driver model representation of the device. 164 + * @ctrl: SSAM controller managing this device. 165 + * @uid: UID identifying the device. 166 + * @flags: Device state flags, see &enum ssam_device_flags. 157 167 */ 158 168 struct ssam_device { 159 169 struct device dev; 160 170 struct ssam_controller *ctrl; 161 171 162 172 struct ssam_device_uid uid; 173 + 174 + unsigned long flags; 163 175 }; 164 176 165 177 /** ··· 191 177 void (*remove)(struct ssam_device *sdev); 192 178 }; 193 179 180 + #ifdef CONFIG_SURFACE_AGGREGATOR_BUS 181 + 194 182 extern struct bus_type ssam_bus_type; 195 183 extern const struct device_type ssam_device_type; 196 184 ··· 208 192 { 209 193 return d->type == &ssam_device_type; 210 194 } 195 + 196 + #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ 197 + 198 + static inline bool is_ssam_device(struct device *d) 199 + { 200 + return false; 201 + } 202 + 203 + #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ 211 204 212 205 /** 213 206 * to_ssam_device() - Casts the given device to a SSAM client device. ··· 264 239 265 240 int ssam_device_add(struct ssam_device *sdev); 266 241 void ssam_device_remove(struct ssam_device *sdev); 242 + 243 + /** 244 + * ssam_device_mark_hot_removed() - Mark the given device as hot-removed. 245 + * @sdev: The device to mark as hot-removed. 246 + * 247 + * Mark the device as having been hot-removed. This signals drivers using the 248 + * device that communication with the device should be avoided and may lead to 249 + * timeouts. 250 + */ 251 + static inline void ssam_device_mark_hot_removed(struct ssam_device *sdev) 252 + { 253 + dev_dbg(&sdev->dev, "marking device as hot-removed\n"); 254 + set_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags); 255 + } 256 + 257 + /** 258 + * ssam_device_is_hot_removed() - Check if the given device has been 259 + * hot-removed. 260 + * @sdev: The device to check. 261 + * 262 + * Checks if the given device has been marked as hot-removed. See 263 + * ssam_device_mark_hot_removed() for more details. 264 + * 265 + * Return: Returns ``true`` if the device has been marked as hot-removed. 266 + */ 267 + static inline bool ssam_device_is_hot_removed(struct ssam_device *sdev) 268 + { 269 + return test_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags); 270 + } 267 271 268 272 /** 269 273 * ssam_device_get() - Increment reference count of SSAM client device. ··· 376 322 /* -- Helpers for controller and hub devices. ------------------------------- */ 377 323 378 324 #ifdef CONFIG_SURFACE_AGGREGATOR_BUS 325 + 326 + int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, 327 + struct fwnode_handle *node); 379 328 void ssam_remove_clients(struct device *dev); 329 + 380 330 #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ 331 + 332 + static inline int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, 333 + struct fwnode_handle *node) 334 + { 335 + return 0; 336 + } 337 + 381 338 static inline void ssam_remove_clients(struct device *dev) {} 339 + 382 340 #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ 341 + 342 + /** 343 + * ssam_register_clients() - Register all client devices defined under the 344 + * given parent device. 345 + * @dev: The parent device under which clients should be registered. 346 + * @ctrl: The controller with which client should be registered. 347 + * 348 + * Register all clients that have via firmware nodes been defined as children 349 + * of the given (parent) device. The respective child firmware nodes will be 350 + * associated with the correspondingly created child devices. 351 + * 352 + * The given controller will be used to instantiate the new devices. See 353 + * ssam_device_add() for details. 354 + * 355 + * Return: Returns zero on success, nonzero on failure. 356 + */ 357 + static inline int ssam_register_clients(struct device *dev, struct ssam_controller *ctrl) 358 + { 359 + return __ssam_register_clients(dev, ctrl, dev_fwnode(dev)); 360 + } 361 + 362 + /** 363 + * ssam_device_register_clients() - Register all client devices defined under 364 + * the given SSAM parent device. 365 + * @sdev: The parent device under which clients should be registered. 366 + * 367 + * Register all clients that have via firmware nodes been defined as children 368 + * of the given (parent) device. The respective child firmware nodes will be 369 + * associated with the correspondingly created child devices. 370 + * 371 + * The controller used by the parent device will be used to instantiate the new 372 + * devices. See ssam_device_add() for details. 373 + * 374 + * Return: Returns zero on success, nonzero on failure. 375 + */ 376 + static inline int ssam_device_register_clients(struct ssam_device *sdev) 377 + { 378 + return ssam_register_clients(&sdev->dev, sdev->ctrl); 379 + } 383 380 384 381 385 382 /* -- Helpers for client-device requests. ----------------------------------- */ ··· 534 429 return __raw_##name(sdev->ctrl, sdev->uid.target, \ 535 430 sdev->uid.instance, ret); \ 536 431 } 432 + 433 + /** 434 + * SSAM_DEFINE_SYNC_REQUEST_CL_WR() - Define synchronous client-device SAM 435 + * request function with argument and return value. 436 + * @name: Name of the generated function. 437 + * @atype: Type of the request's argument. 438 + * @rtype: Type of the request's return value. 439 + * @spec: Specification (&struct ssam_request_spec_md) defining the request. 440 + * 441 + * Defines a function executing the synchronous SAM request specified by @spec, 442 + * with the request taking an argument of type @atype and having a return value 443 + * of type @rtype. Device specifying parameters are not hard-coded, but instead 444 + * are provided via the client device, specifically its UID, supplied when 445 + * calling this function. The generated function takes care of setting up the 446 + * request struct, buffer allocation, as well as execution of the request 447 + * itself, returning once the request has been fully completed. The required 448 + * transport buffer will be allocated on the stack. 449 + * 450 + * The generated function is defined as ``static int name(struct ssam_device 451 + * *sdev, const atype *arg, rtype *ret)``, returning the status of the request, 452 + * which is zero on success and negative on failure. The ``sdev`` parameter 453 + * specifies both the target device of the request and by association the 454 + * controller via which the request is sent. The request's argument is 455 + * specified via the ``arg`` pointer. The request's return value is written to 456 + * the memory pointed to by the ``ret`` parameter. 457 + * 458 + * Refer to ssam_request_sync_onstack() for more details on the behavior of 459 + * the generated function. 460 + */ 461 + #define SSAM_DEFINE_SYNC_REQUEST_CL_WR(name, atype, rtype, spec...) \ 462 + SSAM_DEFINE_SYNC_REQUEST_MD_WR(__raw_##name, atype, rtype, spec) \ 463 + static int name(struct ssam_device *sdev, const atype *arg, rtype *ret) \ 464 + { \ 465 + return __raw_##name(sdev->ctrl, sdev->uid.target, \ 466 + sdev->uid.instance, arg, ret); \ 467 + } 468 + 469 + 470 + /* -- Helpers for client-device notifiers. ---------------------------------- */ 471 + 472 + /** 473 + * ssam_device_notifier_register() - Register an event notifier for the 474 + * specified client device. 475 + * @sdev: The device the notifier should be registered on. 476 + * @n: The event notifier to register. 477 + * 478 + * Register an event notifier. Increment the usage counter of the associated 479 + * SAM event if the notifier is not marked as an observer. If the event is not 480 + * marked as an observer and is currently not enabled, it will be enabled 481 + * during this call. If the notifier is marked as an observer, no attempt will 482 + * be made at enabling any event and no reference count will be modified. 483 + * 484 + * Notifiers marked as observers do not need to be associated with one specific 485 + * event, i.e. as long as no event matching is performed, only the event target 486 + * category needs to be set. 487 + * 488 + * Return: Returns zero on success, %-ENOSPC if there have already been 489 + * %INT_MAX notifiers for the event ID/type associated with the notifier block 490 + * registered, %-ENOMEM if the corresponding event entry could not be 491 + * allocated, %-ENODEV if the device is marked as hot-removed. If this is the 492 + * first time that a notifier block is registered for the specific associated 493 + * event, returns the status of the event-enable EC-command. 494 + */ 495 + static inline int ssam_device_notifier_register(struct ssam_device *sdev, 496 + struct ssam_event_notifier *n) 497 + { 498 + /* 499 + * Note that this check does not provide any guarantees whatsoever as 500 + * hot-removal could happen at any point and we can't protect against 501 + * it. Nevertheless, if we can detect hot-removal, bail early to avoid 502 + * communication timeouts. 503 + */ 504 + if (ssam_device_is_hot_removed(sdev)) 505 + return -ENODEV; 506 + 507 + return ssam_notifier_register(sdev->ctrl, n); 508 + } 509 + 510 + /** 511 + * ssam_device_notifier_unregister() - Unregister an event notifier for the 512 + * specified client device. 513 + * @sdev: The device the notifier has been registered on. 514 + * @n: The event notifier to unregister. 515 + * 516 + * Unregister an event notifier. Decrement the usage counter of the associated 517 + * SAM event if the notifier is not marked as an observer. If the usage counter 518 + * reaches zero, the event will be disabled. 519 + * 520 + * In case the device has been marked as hot-removed, the event will not be 521 + * disabled on the EC, as in those cases any attempt at doing so may time out. 522 + * 523 + * Return: Returns zero on success, %-ENOENT if the given notifier block has 524 + * not been registered on the controller. If the given notifier block was the 525 + * last one associated with its specific event, returns the status of the 526 + * event-disable EC-command. 527 + */ 528 + static inline int ssam_device_notifier_unregister(struct ssam_device *sdev, 529 + struct ssam_event_notifier *n) 530 + { 531 + return __ssam_notifier_unregister(sdev->ctrl, n, 532 + !ssam_device_is_hot_removed(sdev)); 533 + } 537 534 538 535 #endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */
+40 -35
include/linux/surface_aggregator/serial_hub.h
··· 201 201 * exception of zero, which is not an event ID. Thus, this is also the 202 202 * absolute maximum number of event handlers that can be registered. 203 203 */ 204 - #define SSH_NUM_EVENTS 34 204 + #define SSH_NUM_EVENTS 38 205 205 206 206 /* 207 207 * SSH_NUM_TARGETS - The number of communication targets used in the protocol. ··· 292 292 * Windows driver. 293 293 */ 294 294 enum ssam_ssh_tc { 295 - /* Category 0x00 is invalid for EC use. */ 296 - SSAM_SSH_TC_SAM = 0x01, /* Generic system functionality, real-time clock. */ 297 - SSAM_SSH_TC_BAT = 0x02, /* Battery/power subsystem. */ 298 - SSAM_SSH_TC_TMP = 0x03, /* Thermal subsystem. */ 299 - SSAM_SSH_TC_PMC = 0x04, 300 - SSAM_SSH_TC_FAN = 0x05, 301 - SSAM_SSH_TC_PoM = 0x06, 302 - SSAM_SSH_TC_DBG = 0x07, 303 - SSAM_SSH_TC_KBD = 0x08, /* Legacy keyboard (Laptop 1/2). */ 304 - SSAM_SSH_TC_FWU = 0x09, 305 - SSAM_SSH_TC_UNI = 0x0a, 306 - SSAM_SSH_TC_LPC = 0x0b, 307 - SSAM_SSH_TC_TCL = 0x0c, 308 - SSAM_SSH_TC_SFL = 0x0d, 309 - SSAM_SSH_TC_KIP = 0x0e, 310 - SSAM_SSH_TC_EXT = 0x0f, 311 - SSAM_SSH_TC_BLD = 0x10, 312 - SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */ 313 - SSAM_SSH_TC_SEN = 0x12, 314 - SSAM_SSH_TC_SRQ = 0x13, 315 - SSAM_SSH_TC_MCU = 0x14, 316 - SSAM_SSH_TC_HID = 0x15, /* Generic HID input subsystem. */ 317 - SSAM_SSH_TC_TCH = 0x16, 318 - SSAM_SSH_TC_BKL = 0x17, 319 - SSAM_SSH_TC_TAM = 0x18, 320 - SSAM_SSH_TC_ACC = 0x19, 321 - SSAM_SSH_TC_UFI = 0x1a, 322 - SSAM_SSH_TC_USC = 0x1b, 323 - SSAM_SSH_TC_PEN = 0x1c, 324 - SSAM_SSH_TC_VID = 0x1d, 325 - SSAM_SSH_TC_AUD = 0x1e, 326 - SSAM_SSH_TC_SMC = 0x1f, 327 - SSAM_SSH_TC_KPD = 0x20, 328 - SSAM_SSH_TC_REG = 0x21, /* Extended event registry. */ 295 + /* Category 0x00 is invalid for EC use. */ 296 + SSAM_SSH_TC_SAM = 0x01, /* Generic system functionality, real-time clock. */ 297 + SSAM_SSH_TC_BAT = 0x02, /* Battery/power subsystem. */ 298 + SSAM_SSH_TC_TMP = 0x03, /* Thermal subsystem. */ 299 + SSAM_SSH_TC_PMC = 0x04, 300 + SSAM_SSH_TC_FAN = 0x05, 301 + SSAM_SSH_TC_PoM = 0x06, 302 + SSAM_SSH_TC_DBG = 0x07, 303 + SSAM_SSH_TC_KBD = 0x08, /* Legacy keyboard (Laptop 1/2). */ 304 + SSAM_SSH_TC_FWU = 0x09, 305 + SSAM_SSH_TC_UNI = 0x0a, 306 + SSAM_SSH_TC_LPC = 0x0b, 307 + SSAM_SSH_TC_TCL = 0x0c, 308 + SSAM_SSH_TC_SFL = 0x0d, 309 + SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */ 310 + SSAM_SSH_TC_EXT = 0x0f, 311 + SSAM_SSH_TC_BLD = 0x10, 312 + SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */ 313 + SSAM_SSH_TC_SEN = 0x12, 314 + SSAM_SSH_TC_SRQ = 0x13, 315 + SSAM_SSH_TC_MCU = 0x14, 316 + SSAM_SSH_TC_HID = 0x15, /* Generic HID input subsystem. */ 317 + SSAM_SSH_TC_TCH = 0x16, 318 + SSAM_SSH_TC_BKL = 0x17, 319 + SSAM_SSH_TC_TAM = 0x18, 320 + SSAM_SSH_TC_ACC0 = 0x19, 321 + SSAM_SSH_TC_UFI = 0x1a, 322 + SSAM_SSH_TC_USC = 0x1b, 323 + SSAM_SSH_TC_PEN = 0x1c, 324 + SSAM_SSH_TC_VID = 0x1d, 325 + SSAM_SSH_TC_AUD = 0x1e, 326 + SSAM_SSH_TC_SMC = 0x1f, 327 + SSAM_SSH_TC_KPD = 0x20, 328 + SSAM_SSH_TC_REG = 0x21, /* Extended event registry. */ 329 + SSAM_SSH_TC_SPT = 0x22, 330 + SSAM_SSH_TC_SYS = 0x23, 331 + SSAM_SSH_TC_ACC1 = 0x24, 332 + SSAM_SSH_TC_SHB = 0x25, 333 + SSAM_SSH_TC_POS = 0x26, /* For obtaining Laptop Studio screen position. */ 329 334 }; 330 335 331 336
+1 -1
tools/power/x86/intel-speed-select/hfi-events.c
··· 144 144 continue; 145 145 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); 146 146 break; 147 - }; 147 + } 148 148 149 149 return 0; 150 150 }
+1 -1
tools/power/x86/intel-speed-select/isst-daemon.c
··· 41 41 time_t tm; 42 42 int ret; 43 43 44 - if (pkg_id >= MAX_PACKAGE_COUNT || die_id > MAX_DIE_PER_PACKAGE) { 44 + if (pkg_id >= MAX_PACKAGE_COUNT || die_id >= MAX_DIE_PER_PACKAGE) { 45 45 debug_printf("Invalid package/die info for cpu:%d\n", cpu); 46 46 return; 47 47 }