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

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

Pull x86 platform driver updates from Darren Hart:
"Add intel punit and telemetry driver for APL SoCs.
Add intel-hid driver for various laptop hotkey support.
Add asus-wireless radio control driver.
Keyboard backlight support/improvements for ThinkPads, Vaio, and Toshiba.
Several hotkey related fixes and improvements for dell and toshiba.
Fix oops on dual GPU Macs in apple-gmux.
A few new device IDs and quirks.
Various minor config related build issues and cleanups.

surface pro 4:
- fix compare_const_fl.cocci warnings
- Add support for Surface Pro 4 Buttons

platform/x86:
- Add Intel Telemetry Debugfs interfaces
- Add Intel telemetry platform device
- Add Intel telemetry platform driver
- Add Intel Telemetry Core Driver
- add NULL check for input parameters
- add Intel P-Unit mailbox IPC driver
- update acpi resource structure for Punit

thinkpad_acpi:
- Add support for keyboard backlight

dell-wmi:
- Process only one event on devices with interface version 0
- Check if Dell WMI descriptor structure is valid
- Improve unknown hotkey handling
- Use a C99-style array for bios_to_linux_keycode

tc1100-wmi:
- fix build warning when CONFIG_PM not enabled

asus-wireless:
- Add ACPI HID ATK4001
- Add Asus Wireless Radio Control driver

asus-wmi:
- drop to_platform_driver macro

intel-hid:
- new hid event driver for hotkeys

sony-laptop:
- Keyboard backlight control for some Vaio Fit models

ideapad-laptop:
- Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list

apple-gmux:
- Assign apple_gmux_data before registering

toshiba_acpi:
- Add rfkill dependency to ACPI_TOSHIBA entry
- Fix keyboard backlight sysfs entries not being updated
- Add WWAN RFKill support
- Add support for WWAN devices
- Fix blank screen at boot if transflective backlight is supported
- Propagate the hotkey value via genetlink

toshiba_bluetooth:
- Add missing newline in toshiba_bluetooth_present function"

* tag 'platform-drivers-x86-v4.5-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (29 commits)
surface pro 4: fix compare_const_fl.cocci warnings
surface pro 4: Add support for Surface Pro 4 Buttons
platform:x86: Add Intel Telemetry Debugfs interfaces
platform:x86: Add Intel telemetry platform device
platform:x86: Add Intel telemetry platform driver
platform/x86: Add Intel Telemetry Core Driver
intel_punit_ipc: add NULL check for input parameters
thinkpad_acpi: Add support for keyboard backlight
dell-wmi: Process only one event on devices with interface version 0
dell-wmi: Check if Dell WMI descriptor structure is valid
tc1100-wmi: fix build warning when CONFIG_PM not enabled
asus-wireless: Add ACPI HID ATK4001
platform/x86: Add Asus Wireless Radio Control driver
asus-wmi: drop to_platform_driver macro
intel-hid: new hid event driver for hotkeys
Keyboard backlight control for some Vaio Fit models
platform/x86: Add rfkill dependency to ACPI_TOSHIBA entry
platform:x86: add Intel P-Unit mailbox IPC driver
intel_pmc_ipc: update acpi resource structure for Punit
ideapad-laptop: Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list
...

+4580 -111
+24 -1
MAINTAINERS
··· 1806 1806 F: drivers/platform/x86/asus*.c 1807 1807 F: drivers/platform/x86/eeepc*.c 1808 1808 1809 + ASUS WIRELESS RADIO CONTROL DRIVER 1810 + M: João Paulo Rechi Vita <jprvita@gmail.com> 1811 + L: platform-driver-x86@vger.kernel.org 1812 + S: Maintained 1813 + F: drivers/platform/x86/asus-wireless.c 1814 + 1809 1815 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API 1810 1816 R: Dan Williams <dan.j.williams@intel.com> 1811 1817 W: http://sourceforge.net/projects/xscaleiop ··· 5539 5533 S: Supported 5540 5534 F: drivers/scsi/isci/ 5541 5535 5536 + INTEL HID EVENT DRIVER 5537 + M: Alex Hung <alex.hung@canonical.com> 5538 + L: platform-driver-x86@vger.kernel.org 5539 + S: Maintained 5540 + F: drivers/platform/x86/intel-hid.c 5541 + 5542 5542 INTEL IDLE DRIVER 5543 5543 M: Len Brown <lenb@kernel.org> 5544 5544 L: linux-pm@vger.kernel.org ··· 5725 5713 F: drivers/dma/mic_x100_dma.h 5726 5714 F Documentation/mic/ 5727 5715 5728 - INTEL PMC IPC DRIVER 5716 + INTEL PMC/P-Unit IPC DRIVER 5729 5717 M: Zha Qipeng<qipeng.zha@intel.com> 5730 5718 L: platform-driver-x86@vger.kernel.org 5731 5719 S: Maintained 5732 5720 F: drivers/platform/x86/intel_pmc_ipc.c 5721 + F: drivers/platform/x86/intel_punit_ipc.c 5733 5722 F: arch/x86/include/asm/intel_pmc_ipc.h 5723 + F: arch/x86/include/asm/intel_punit_ipc.h 5724 + 5725 + INTEL TELEMETRY DRIVER 5726 + M: Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com> 5727 + L: platform-driver-x86@vger.kernel.org 5728 + S: Maintained 5729 + F: drivers/platform/x86/intel_telemetry_core.c 5730 + F: arch/x86/include/asm/intel_telemetry.h 5731 + F: drivers/platform/x86/intel_telemetry_pltdrv.c 5732 + F: drivers/platform/x86/intel_telemetry_debugfs.c 5734 5733 5735 5734 IOC3 ETHERNET DRIVER 5736 5735 M: Ralf Baechle <ralf@linux-mips.org>
+101
arch/x86/include/asm/intel_punit_ipc.h
··· 1 + #ifndef _ASM_X86_INTEL_PUNIT_IPC_H_ 2 + #define _ASM_X86_INTEL_PUNIT_IPC_H_ 3 + 4 + /* 5 + * Three types of 8bit P-Unit IPC commands are supported, 6 + * bit[7:6]: [00]: BIOS; [01]: GTD; [10]: ISPD. 7 + */ 8 + typedef enum { 9 + BIOS_IPC = 0, 10 + GTDRIVER_IPC, 11 + ISPDRIVER_IPC, 12 + RESERVED_IPC, 13 + } IPC_TYPE; 14 + 15 + #define IPC_TYPE_OFFSET 6 16 + #define IPC_PUNIT_BIOS_CMD_BASE (BIOS_IPC << IPC_TYPE_OFFSET) 17 + #define IPC_PUNIT_GTD_CMD_BASE (GTDDRIVER_IPC << IPC_TYPE_OFFSET) 18 + #define IPC_PUNIT_ISPD_CMD_BASE (ISPDRIVER_IPC << IPC_TYPE_OFFSET) 19 + #define IPC_PUNIT_CMD_TYPE_MASK (RESERVED_IPC << IPC_TYPE_OFFSET) 20 + 21 + /* BIOS => Pcode commands */ 22 + #define IPC_PUNIT_BIOS_ZERO (IPC_PUNIT_BIOS_CMD_BASE | 0x00) 23 + #define IPC_PUNIT_BIOS_VR_INTERFACE (IPC_PUNIT_BIOS_CMD_BASE | 0x01) 24 + #define IPC_PUNIT_BIOS_READ_PCS (IPC_PUNIT_BIOS_CMD_BASE | 0x02) 25 + #define IPC_PUNIT_BIOS_WRITE_PCS (IPC_PUNIT_BIOS_CMD_BASE | 0x03) 26 + #define IPC_PUNIT_BIOS_READ_PCU_CONFIG (IPC_PUNIT_BIOS_CMD_BASE | 0x04) 27 + #define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG (IPC_PUNIT_BIOS_CMD_BASE | 0x05) 28 + #define IPC_PUNIT_BIOS_READ_PL1_SETTING (IPC_PUNIT_BIOS_CMD_BASE | 0x06) 29 + #define IPC_PUNIT_BIOS_WRITE_PL1_SETTING (IPC_PUNIT_BIOS_CMD_BASE | 0x07) 30 + #define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM (IPC_PUNIT_BIOS_CMD_BASE | 0x08) 31 + #define IPC_PUNIT_BIOS_READ_TELE_INFO (IPC_PUNIT_BIOS_CMD_BASE | 0x09) 32 + #define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0a) 33 + #define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0b) 34 + #define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0c) 35 + #define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0d) 36 + #define IPC_PUNIT_BIOS_READ_TELE_TRACE (IPC_PUNIT_BIOS_CMD_BASE | 0x0e) 37 + #define IPC_PUNIT_BIOS_WRITE_TELE_TRACE (IPC_PUNIT_BIOS_CMD_BASE | 0x0f) 38 + #define IPC_PUNIT_BIOS_READ_TELE_EVENT (IPC_PUNIT_BIOS_CMD_BASE | 0x10) 39 + #define IPC_PUNIT_BIOS_WRITE_TELE_EVENT (IPC_PUNIT_BIOS_CMD_BASE | 0x11) 40 + #define IPC_PUNIT_BIOS_READ_MODULE_TEMP (IPC_PUNIT_BIOS_CMD_BASE | 0x12) 41 + #define IPC_PUNIT_BIOS_RESERVED (IPC_PUNIT_BIOS_CMD_BASE | 0x13) 42 + #define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x14) 43 + #define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x15) 44 + #define IPC_PUNIT_BIOS_READ_RATIO_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x16) 45 + #define IPC_PUNIT_BIOS_WRITE_RATIO_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x17) 46 + #define IPC_PUNIT_BIOS_READ_VF_GL_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x18) 47 + #define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x19) 48 + #define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH (IPC_PUNIT_BIOS_CMD_BASE | 0x1a) 49 + #define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH (IPC_PUNIT_BIOS_CMD_BASE | 0x1b) 50 + 51 + /* GT Driver => Pcode commands */ 52 + #define IPC_PUNIT_GTD_ZERO (IPC_PUNIT_GTD_CMD_BASE | 0x00) 53 + #define IPC_PUNIT_GTD_CONFIG (IPC_PUNIT_GTD_CMD_BASE | 0x01) 54 + #define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL (IPC_PUNIT_GTD_CMD_BASE | 0x02) 55 + #define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL (IPC_PUNIT_GTD_CMD_BASE | 0x03) 56 + #define IPC_PUNIT_GTD_GET_WM_VAL (IPC_PUNIT_GTD_CMD_BASE | 0x06) 57 + #define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ (IPC_PUNIT_GTD_CMD_BASE | 0x07) 58 + #define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE (IPC_PUNIT_GTD_CMD_BASE | 0x16) 59 + #define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST (IPC_PUNIT_GTD_CMD_BASE | 0x17) 60 + #define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL (IPC_PUNIT_GTD_CMD_BASE | 0x1a) 61 + #define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING (IPC_PUNIT_GTD_CMD_BASE | 0x1c) 62 + 63 + /* ISP Driver => Pcode commands */ 64 + #define IPC_PUNIT_ISPD_ZERO (IPC_PUNIT_ISPD_CMD_BASE | 0x00) 65 + #define IPC_PUNIT_ISPD_CONFIG (IPC_PUNIT_ISPD_CMD_BASE | 0x01) 66 + #define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL (IPC_PUNIT_ISPD_CMD_BASE | 0x02) 67 + #define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS (IPC_PUNIT_ISPD_CMD_BASE | 0x03) 68 + #define IPC_PUNIT_ISPD_READ_CDYN_LEVEL (IPC_PUNIT_ISPD_CMD_BASE | 0x04) 69 + #define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL (IPC_PUNIT_ISPD_CMD_BASE | 0x05) 70 + 71 + /* Error codes */ 72 + #define IPC_PUNIT_ERR_SUCCESS 0 73 + #define IPC_PUNIT_ERR_INVALID_CMD 1 74 + #define IPC_PUNIT_ERR_INVALID_PARAMETER 2 75 + #define IPC_PUNIT_ERR_CMD_TIMEOUT 3 76 + #define IPC_PUNIT_ERR_CMD_LOCKED 4 77 + #define IPC_PUNIT_ERR_INVALID_VR_ID 5 78 + #define IPC_PUNIT_ERR_VR_ERR 6 79 + 80 + #if IS_ENABLED(CONFIG_INTEL_PUNIT_IPC) 81 + 82 + int intel_punit_ipc_simple_command(int cmd, int para1, int para2); 83 + int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out); 84 + 85 + #else 86 + 87 + static inline int intel_punit_ipc_simple_command(int cmd, 88 + int para1, int para2) 89 + { 90 + return -ENODEV; 91 + } 92 + 93 + static inline int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, 94 + u32 *in, u32 *out) 95 + { 96 + return -ENODEV; 97 + } 98 + 99 + #endif /* CONFIG_INTEL_PUNIT_IPC */ 100 + 101 + #endif
+147
arch/x86/include/asm/intel_telemetry.h
··· 1 + /* 2 + * Intel SOC Telemetry Driver Header File 3 + * Copyright (C) 2015, Intel Corporation. 4 + * All Rights Reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + */ 16 + #ifndef INTEL_TELEMETRY_H 17 + #define INTEL_TELEMETRY_H 18 + 19 + #define TELEM_MAX_EVENTS_SRAM 28 20 + #define TELEM_MAX_OS_ALLOCATED_EVENTS 20 21 + 22 + enum telemetry_unit { 23 + TELEM_PSS = 0, 24 + TELEM_IOSS, 25 + TELEM_UNIT_NONE 26 + }; 27 + 28 + struct telemetry_evtlog { 29 + u32 telem_evtid; 30 + u64 telem_evtlog; 31 + }; 32 + 33 + struct telemetry_evtconfig { 34 + /* Array of Event-IDs to Enable */ 35 + u32 *evtmap; 36 + 37 + /* Number of Events (<29) in evtmap */ 38 + u8 num_evts; 39 + 40 + /* Sampling period */ 41 + u8 period; 42 + }; 43 + 44 + struct telemetry_evtmap { 45 + const char *name; 46 + u32 evt_id; 47 + }; 48 + 49 + struct telemetry_unit_config { 50 + struct telemetry_evtmap *telem_evts; 51 + void __iomem *regmap; 52 + u32 ssram_base_addr; 53 + u8 ssram_evts_used; 54 + u8 curr_period; 55 + u8 max_period; 56 + u8 min_period; 57 + u32 ssram_size; 58 + 59 + }; 60 + 61 + struct telemetry_plt_config { 62 + struct telemetry_unit_config pss_config; 63 + struct telemetry_unit_config ioss_config; 64 + struct mutex telem_trace_lock; 65 + struct mutex telem_lock; 66 + bool telem_in_use; 67 + }; 68 + 69 + struct telemetry_core_ops { 70 + int (*get_sampling_period)(u8 *pss_min_period, u8 *pss_max_period, 71 + u8 *ioss_min_period, u8 *ioss_max_period); 72 + 73 + int (*get_eventconfig)(struct telemetry_evtconfig *pss_evtconfig, 74 + struct telemetry_evtconfig *ioss_evtconfig, 75 + int pss_len, int ioss_len); 76 + 77 + int (*update_events)(struct telemetry_evtconfig pss_evtconfig, 78 + struct telemetry_evtconfig ioss_evtconfig); 79 + 80 + int (*set_sampling_period)(u8 pss_period, u8 ioss_period); 81 + 82 + int (*get_trace_verbosity)(enum telemetry_unit telem_unit, 83 + u32 *verbosity); 84 + 85 + int (*set_trace_verbosity)(enum telemetry_unit telem_unit, 86 + u32 verbosity); 87 + 88 + int (*raw_read_eventlog)(enum telemetry_unit telem_unit, 89 + struct telemetry_evtlog *evtlog, 90 + int len, int log_all_evts); 91 + 92 + int (*read_eventlog)(enum telemetry_unit telem_unit, 93 + struct telemetry_evtlog *evtlog, 94 + int len, int log_all_evts); 95 + 96 + int (*add_events)(u8 num_pss_evts, u8 num_ioss_evts, 97 + u32 *pss_evtmap, u32 *ioss_evtmap); 98 + 99 + int (*reset_events)(void); 100 + }; 101 + 102 + int telemetry_set_pltdata(struct telemetry_core_ops *ops, 103 + struct telemetry_plt_config *pltconfig); 104 + 105 + int telemetry_clear_pltdata(void); 106 + 107 + int telemetry_pltconfig_valid(void); 108 + 109 + int telemetry_get_evtname(enum telemetry_unit telem_unit, 110 + const char **name, int len); 111 + 112 + int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig, 113 + struct telemetry_evtconfig ioss_evtconfig); 114 + 115 + int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts, 116 + u32 *pss_evtmap, u32 *ioss_evtmap); 117 + 118 + int telemetry_reset_events(void); 119 + 120 + int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_config, 121 + struct telemetry_evtconfig *ioss_config, 122 + int pss_len, int ioss_len); 123 + 124 + int telemetry_read_events(enum telemetry_unit telem_unit, 125 + struct telemetry_evtlog *evtlog, int len); 126 + 127 + int telemetry_raw_read_events(enum telemetry_unit telem_unit, 128 + struct telemetry_evtlog *evtlog, int len); 129 + 130 + int telemetry_read_eventlog(enum telemetry_unit telem_unit, 131 + struct telemetry_evtlog *evtlog, int len); 132 + 133 + int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit, 134 + struct telemetry_evtlog *evtlog, int len); 135 + 136 + int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period, 137 + u8 *ioss_min_period, u8 *ioss_max_period); 138 + 139 + int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period); 140 + 141 + int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit, 142 + u32 verbosity); 143 + 144 + int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit, 145 + u32 *verbosity); 146 + 147 + #endif /* INTEL_TELEMETRY_H */
+46 -2
drivers/platform/x86/Kconfig
··· 587 587 If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M 588 588 here. 589 589 590 + config ASUS_WIRELESS 591 + tristate "Asus Wireless Radio Control Driver" 592 + depends on ACPI 593 + depends on INPUT 594 + ---help--- 595 + The Asus Wireless Radio Control handles the airplane mode hotkey 596 + present on some Asus laptops. 597 + 598 + Say Y or M here if you have an ASUS notebook with an airplane mode 599 + hotkey. 600 + 601 + If you choose to compile this driver as a module the module will be 602 + called asus-wireless. 603 + 590 604 config ACPI_WMI 591 605 tristate "WMI" 592 606 depends on ACPI ··· 655 641 depends on INPUT 656 642 depends on SERIO_I8042 || SERIO_I8042 = n 657 643 depends on ACPI_VIDEO || ACPI_VIDEO = n 644 + depends on RFKILL || RFKILL = n 658 645 select INPUT_POLLDEV 659 646 select INPUT_SPARSEKMAP 660 647 ---help--- ··· 745 730 Support for Intel Classmate PC ACPI devices, including some 746 731 keys as input device, backlight device, tablet and accelerometer 747 732 devices. 733 + 734 + config INTEL_HID_EVENT 735 + tristate "INTEL HID Event" 736 + depends on ACPI 737 + depends on INPUT 738 + select INPUT_SPARSEKMAP 739 + help 740 + This driver provides support for the Intel HID Event hotkey interface. 741 + Some laptops require this driver for hotkey support. 742 + 743 + To compile this driver as a module, choose M here: the module will 744 + be called intel_hid. 748 745 749 746 config INTEL_SCU_IPC 750 747 bool "Intel SCU IPC Support" ··· 967 940 with other entities in the CPU. 968 941 969 942 config SURFACE_PRO3_BUTTON 970 - tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3 tablet" 943 + tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet" 971 944 depends on ACPI && INPUT 972 945 ---help--- 973 - This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3 tablet. 946 + This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet. 947 + 948 + config INTEL_PUNIT_IPC 949 + tristate "Intel P-Unit IPC Driver" 950 + ---help--- 951 + This driver provides support for Intel P-Unit Mailbox IPC mechanism, 952 + which is used to bridge the communications between kernel and P-Unit. 953 + 954 + config INTEL_TELEMETRY 955 + tristate "Intel SoC Telemetry Driver" 956 + default n 957 + depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64 958 + ---help--- 959 + This driver provides interfaces to configure and use 960 + telemetry for INTEL SoC from APL onwards. It is also 961 + used to get various SoC events and parameters 962 + directly via debugfs files. Various tools may use 963 + this interface for SoC state monitoring. 974 964 endif # X86_PLATFORM_DEVICES
+6
drivers/platform/x86/Makefile
··· 5 5 obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 6 6 obj-$(CONFIG_ASUS_WMI) += asus-wmi.o 7 7 obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o 8 + obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o 8 9 obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 9 10 obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o 10 11 obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o ··· 42 41 obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 43 42 obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o 44 43 obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o 44 + obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o 45 45 obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 46 46 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o 47 47 obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o ··· 64 62 obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o 65 63 obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o 66 64 obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o 65 + obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o 66 + obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ 67 + intel_telemetry_pltdrv.o \ 68 + intel_telemetry_debugfs.o
+6 -4
drivers/platform/x86/apple-gmux.c
··· 701 701 gmux_data->gpe = -1; 702 702 } 703 703 704 + apple_gmux_data = gmux_data; 705 + init_completion(&gmux_data->powerchange_done); 706 + gmux_enable_interrupts(gmux_data); 707 + 704 708 if (vga_switcheroo_register_handler(&gmux_handler)) { 705 709 ret = -ENODEV; 706 710 goto err_register_handler; 707 711 } 708 712 709 - init_completion(&gmux_data->powerchange_done); 710 - apple_gmux_data = gmux_data; 711 - gmux_enable_interrupts(gmux_data); 712 - 713 713 return 0; 714 714 715 715 err_register_handler: 716 + gmux_disable_interrupts(gmux_data); 717 + apple_gmux_data = NULL; 716 718 if (gmux_data->gpe >= 0) 717 719 acpi_disable_gpe(NULL, gmux_data->gpe); 718 720 err_enable_gpe:
+84
drivers/platform/x86/asus-wireless.c
··· 1 + /* 2 + * Asus Wireless Radio Control Driver 3 + * 4 + * Copyright (C) 2015-2016 Endless Mobile, Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/init.h> 14 + #include <linux/types.h> 15 + #include <linux/acpi.h> 16 + #include <linux/input.h> 17 + #include <linux/pci_ids.h> 18 + 19 + struct asus_wireless_data { 20 + struct input_dev *idev; 21 + }; 22 + 23 + static void asus_wireless_notify(struct acpi_device *adev, u32 event) 24 + { 25 + struct asus_wireless_data *data = acpi_driver_data(adev); 26 + 27 + dev_dbg(&adev->dev, "event=%#x\n", event); 28 + if (event != 0x88) { 29 + dev_notice(&adev->dev, "Unknown ASHS event: %#x\n", event); 30 + return; 31 + } 32 + input_report_key(data->idev, KEY_RFKILL, 1); 33 + input_report_key(data->idev, KEY_RFKILL, 0); 34 + input_sync(data->idev); 35 + } 36 + 37 + static int asus_wireless_add(struct acpi_device *adev) 38 + { 39 + struct asus_wireless_data *data; 40 + 41 + data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL); 42 + if (!data) 43 + return -ENOMEM; 44 + adev->driver_data = data; 45 + 46 + data->idev = devm_input_allocate_device(&adev->dev); 47 + if (!data->idev) 48 + return -ENOMEM; 49 + data->idev->name = "Asus Wireless Radio Control"; 50 + data->idev->phys = "asus-wireless/input0"; 51 + data->idev->id.bustype = BUS_HOST; 52 + data->idev->id.vendor = PCI_VENDOR_ID_ASUSTEK; 53 + set_bit(EV_KEY, data->idev->evbit); 54 + set_bit(KEY_RFKILL, data->idev->keybit); 55 + return input_register_device(data->idev); 56 + } 57 + 58 + static int asus_wireless_remove(struct acpi_device *adev) 59 + { 60 + return 0; 61 + } 62 + 63 + static const struct acpi_device_id device_ids[] = { 64 + {"ATK4001", 0}, 65 + {"ATK4002", 0}, 66 + {"", 0}, 67 + }; 68 + MODULE_DEVICE_TABLE(acpi, device_ids); 69 + 70 + static struct acpi_driver asus_wireless_driver = { 71 + .name = "Asus Wireless Radio Control Driver", 72 + .class = "hotkey", 73 + .ids = device_ids, 74 + .ops = { 75 + .add = asus_wireless_add, 76 + .remove = asus_wireless_remove, 77 + .notify = asus_wireless_notify, 78 + }, 79 + }; 80 + module_acpi_driver(asus_wireless_driver); 81 + 82 + MODULE_DESCRIPTION("Asus Wireless Radio Control Driver"); 83 + MODULE_AUTHOR("João Paulo Rechi Vita <jprvita@gmail.com>"); 84 + MODULE_LICENSE("GPL");
-3
drivers/platform/x86/asus-wmi.c
··· 56 56 MODULE_DESCRIPTION("Asus Generic WMI Driver"); 57 57 MODULE_LICENSE("GPL"); 58 58 59 - #define to_platform_driver(drv) \ 60 - (container_of((drv), struct platform_driver, driver)) 61 - 62 59 #define to_asus_wmi_driver(pdrv) \ 63 60 (container_of((pdrv), struct asus_wmi_driver, platform_driver)) 64 61
+155 -27
drivers/platform/x86/dell-wmi.c
··· 2 2 * Dell WMI hotkeys 3 3 * 4 4 * Copyright (C) 2008 Red Hat <mjg@redhat.com> 5 + * Copyright (C) 2014-2015 Pali Rohár <pali.rohar@gmail.com> 5 6 * 6 7 * Portions based on wistron_btns.c: 7 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> ··· 39 38 #include <acpi/video.h> 40 39 41 40 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); 41 + MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); 42 42 MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); 43 43 MODULE_LICENSE("GPL"); 44 44 45 45 #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" 46 + #define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492" 47 + 48 + static u32 dell_wmi_interface_version; 46 49 47 50 MODULE_ALIAS("wmi:"DELL_EVENT_GUID); 51 + MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID); 48 52 49 53 /* 50 54 * Certain keys are flagged as KE_IGNORE. All of these are either ··· 122 116 123 117 static const struct dell_bios_hotkey_table *dell_bios_hotkey_table; 124 118 119 + /* Uninitialized entries here are KEY_RESERVED == 0. */ 125 120 static const u16 bios_to_linux_keycode[256] __initconst = { 126 - 127 - KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG, 128 - KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 129 - KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE, 130 - KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD, 131 - KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN, 132 - KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE, 133 - KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, 134 - KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2, 135 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 136 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_MICMUTE, 137 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146 - 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PROG3 121 + [0] = KEY_MEDIA, 122 + [1] = KEY_NEXTSONG, 123 + [2] = KEY_PLAYPAUSE, 124 + [3] = KEY_PREVIOUSSONG, 125 + [4] = KEY_STOPCD, 126 + [5] = KEY_UNKNOWN, 127 + [6] = KEY_UNKNOWN, 128 + [7] = KEY_UNKNOWN, 129 + [8] = KEY_WWW, 130 + [9] = KEY_UNKNOWN, 131 + [10] = KEY_VOLUMEDOWN, 132 + [11] = KEY_MUTE, 133 + [12] = KEY_VOLUMEUP, 134 + [13] = KEY_UNKNOWN, 135 + [14] = KEY_BATTERY, 136 + [15] = KEY_EJECTCD, 137 + [16] = KEY_UNKNOWN, 138 + [17] = KEY_SLEEP, 139 + [18] = KEY_PROG1, 140 + [19] = KEY_BRIGHTNESSDOWN, 141 + [20] = KEY_BRIGHTNESSUP, 142 + [21] = KEY_UNKNOWN, 143 + [22] = KEY_KBDILLUMTOGGLE, 144 + [23] = KEY_UNKNOWN, 145 + [24] = KEY_SWITCHVIDEOMODE, 146 + [25] = KEY_UNKNOWN, 147 + [26] = KEY_UNKNOWN, 148 + [27] = KEY_SWITCHVIDEOMODE, 149 + [28] = KEY_UNKNOWN, 150 + [29] = KEY_UNKNOWN, 151 + [30] = KEY_PROG2, 152 + [31] = KEY_UNKNOWN, 153 + [32] = KEY_UNKNOWN, 154 + [33] = KEY_UNKNOWN, 155 + [34] = KEY_UNKNOWN, 156 + [35] = KEY_UNKNOWN, 157 + [36] = KEY_UNKNOWN, 158 + [37] = KEY_UNKNOWN, 159 + [38] = KEY_MICMUTE, 160 + [255] = KEY_PROG3, 147 161 }; 148 162 149 163 static struct input_dev *dell_wmi_input_dev; ··· 175 149 key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, 176 150 reported_key); 177 151 if (!key) { 178 - pr_info("Unknown key %x pressed\n", reported_key); 152 + pr_info("Unknown key with scancode 0x%x pressed\n", 153 + reported_key); 179 154 return; 180 155 } 181 156 ··· 236 209 } 237 210 238 211 buffer_end = buffer_entry + buffer_size; 212 + 213 + /* 214 + * BIOS/ACPI on devices with WMI interface version 0 does not clear 215 + * buffer before filling it. So next time when BIOS/ACPI send WMI event 216 + * which is smaller as previous then it contains garbage in buffer from 217 + * previous event. 218 + * 219 + * BIOS/ACPI on devices with WMI interface version 1 clears buffer and 220 + * sometimes send more events in buffer at one call. 221 + * 222 + * So to prevent reading garbage from buffer we will process only first 223 + * one event on devices with WMI interface version 0. 224 + */ 225 + if (dell_wmi_interface_version == 0 && buffer_entry < buffer_end) 226 + if (buffer_end > buffer_entry + buffer_entry[0] + 1) 227 + buffer_end = buffer_entry + buffer_entry[0] + 1; 239 228 240 229 while (buffer_entry < buffer_end) { 241 230 ··· 351 308 for (i = 0; i < hotkey_num; i++) { 352 309 const struct dell_bios_keymap_entry *bios_entry = 353 310 &dell_bios_hotkey_table->keymap[i]; 354 - u16 keycode = bios_entry->keycode < 256 ? 355 - bios_to_linux_keycode[bios_entry->keycode] : 356 - KEY_RESERVED; 311 + 312 + /* Uninitialized entries are 0 aka KEY_RESERVED. */ 313 + u16 keycode = (bios_entry->keycode < 314 + ARRAY_SIZE(bios_to_linux_keycode)) ? 315 + bios_to_linux_keycode[bios_entry->keycode] : 316 + KEY_RESERVED; 317 + 318 + /* 319 + * Log if we find an entry in the DMI table that we don't 320 + * understand. If this happens, we should figure out what 321 + * the entry means and add it to bios_to_linux_keycode. 322 + */ 323 + if (keycode == KEY_RESERVED) { 324 + pr_info("firmware scancode 0x%x maps to unrecognized keycode 0x%x\n", 325 + bios_entry->scancode, bios_entry->keycode); 326 + continue; 327 + } 357 328 358 329 if (keycode == KEY_KBDILLUMTOGGLE) 359 330 keymap[i].type = KE_IGNORE; ··· 443 386 } 444 387 } 445 388 389 + /* 390 + * Descriptor buffer is 128 byte long and contains: 391 + * 392 + * Name Offset Length Value 393 + * Vendor Signature 0 4 "DELL" 394 + * Object Signature 4 4 " WMI" 395 + * WMI Interface Version 8 4 <version> 396 + * WMI buffer length 12 4 4096 397 + */ 398 + static int __init dell_wmi_check_descriptor_buffer(void) 399 + { 400 + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 401 + union acpi_object *obj; 402 + acpi_status status; 403 + u32 *buffer; 404 + 405 + status = wmi_query_block(DELL_DESCRIPTOR_GUID, 0, &out); 406 + if (ACPI_FAILURE(status)) { 407 + pr_err("Cannot read Dell descriptor buffer - %d\n", status); 408 + return status; 409 + } 410 + 411 + obj = (union acpi_object *)out.pointer; 412 + if (!obj) { 413 + pr_err("Dell descriptor buffer is empty\n"); 414 + return -EINVAL; 415 + } 416 + 417 + if (obj->type != ACPI_TYPE_BUFFER) { 418 + pr_err("Cannot read Dell descriptor buffer\n"); 419 + kfree(obj); 420 + return -EINVAL; 421 + } 422 + 423 + if (obj->buffer.length != 128) { 424 + pr_err("Dell descriptor buffer has invalid length (%d)\n", 425 + obj->buffer.length); 426 + if (obj->buffer.length < 16) { 427 + kfree(obj); 428 + return -EINVAL; 429 + } 430 + } 431 + 432 + buffer = (u32 *)obj->buffer.pointer; 433 + 434 + if (buffer[0] != 0x4C4C4544 && buffer[1] != 0x494D5720) 435 + pr_warn("Dell descriptor buffer has invalid signature (%*ph)\n", 436 + 8, buffer); 437 + 438 + if (buffer[2] != 0 && buffer[2] != 1) 439 + pr_warn("Dell descriptor buffer has unknown version (%d)\n", 440 + buffer[2]); 441 + 442 + if (buffer[3] != 4096) 443 + pr_warn("Dell descriptor buffer has invalid buffer length (%d)\n", 444 + buffer[3]); 445 + 446 + dell_wmi_interface_version = buffer[2]; 447 + 448 + pr_info("Detected Dell WMI interface version %u\n", 449 + dell_wmi_interface_version); 450 + 451 + kfree(obj); 452 + return 0; 453 + } 454 + 446 455 static int __init dell_wmi_init(void) 447 456 { 448 457 int err; 449 458 acpi_status status; 450 459 451 - if (!wmi_has_guid(DELL_EVENT_GUID)) { 452 - pr_warn("No known WMI GUID found\n"); 460 + if (!wmi_has_guid(DELL_EVENT_GUID) || 461 + !wmi_has_guid(DELL_DESCRIPTOR_GUID)) { 462 + pr_warn("Dell WMI GUID were not found\n"); 453 463 return -ENODEV; 454 464 } 465 + 466 + err = dell_wmi_check_descriptor_buffer(); 467 + if (err) 468 + return err; 455 469 456 470 dmi_walk(find_hk_type, NULL); 457 471
+7
drivers/platform/x86/ideapad-laptop.c
··· 865 865 }, 866 866 }, 867 867 { 868 + .ident = "Lenovo ideapad Y700-17ISK", 869 + .matches = { 870 + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 871 + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"), 872 + }, 873 + }, 874 + { 868 875 .ident = "Lenovo Yoga 2 11 / 13 / Pro", 869 876 .matches = { 870 877 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+289
drivers/platform/x86/intel-hid.c
··· 1 + /* 2 + * Intel HID event driver for Windows 8 3 + * 4 + * Copyright (C) 2015 Alex Hung <alex.hung@canonical.com> 5 + * Copyright (C) 2015 Andrew Lutomirski <luto@kernel.org> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + */ 18 + 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/init.h> 22 + #include <linux/input.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/input/sparse-keymap.h> 25 + #include <linux/acpi.h> 26 + #include <acpi/acpi_bus.h> 27 + 28 + MODULE_LICENSE("GPL"); 29 + MODULE_AUTHOR("Alex Hung"); 30 + 31 + static const struct acpi_device_id intel_hid_ids[] = { 32 + {"INT33D5", 0}, 33 + {"", 0}, 34 + }; 35 + 36 + /* In theory, these are HID usages. */ 37 + static const struct key_entry intel_hid_keymap[] = { 38 + /* 1: LSuper (Page 0x07, usage 0xE3) -- unclear what to do */ 39 + /* 2: Toggle SW_ROTATE_LOCK -- easy to implement if seen in wild */ 40 + { KE_KEY, 3, { KEY_NUMLOCK } }, 41 + { KE_KEY, 4, { KEY_HOME } }, 42 + { KE_KEY, 5, { KEY_END } }, 43 + { KE_KEY, 6, { KEY_PAGEUP } }, 44 + { KE_KEY, 4, { KEY_PAGEDOWN } }, 45 + { KE_KEY, 4, { KEY_HOME } }, 46 + { KE_KEY, 8, { KEY_RFKILL } }, 47 + { KE_KEY, 9, { KEY_POWER } }, 48 + { KE_KEY, 11, { KEY_SLEEP } }, 49 + /* 13 has two different meanings in the spec -- ignore it. */ 50 + { KE_KEY, 14, { KEY_STOPCD } }, 51 + { KE_KEY, 15, { KEY_PLAYPAUSE } }, 52 + { KE_KEY, 16, { KEY_MUTE } }, 53 + { KE_KEY, 17, { KEY_VOLUMEUP } }, 54 + { KE_KEY, 18, { KEY_VOLUMEDOWN } }, 55 + { KE_KEY, 19, { KEY_BRIGHTNESSUP } }, 56 + { KE_KEY, 20, { KEY_BRIGHTNESSDOWN } }, 57 + /* 27: wake -- needs special handling */ 58 + { KE_END }, 59 + }; 60 + 61 + struct intel_hid_priv { 62 + struct input_dev *input_dev; 63 + }; 64 + 65 + static int intel_hid_set_enable(struct device *device, int enable) 66 + { 67 + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; 68 + struct acpi_object_list args = { 1, &arg0 }; 69 + acpi_status status; 70 + 71 + arg0.integer.value = enable; 72 + status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL); 73 + if (!ACPI_SUCCESS(status)) { 74 + dev_warn(device, "failed to %sable hotkeys\n", 75 + enable ? "en" : "dis"); 76 + return -EIO; 77 + } 78 + 79 + return 0; 80 + } 81 + 82 + static int intel_hid_pl_suspend_handler(struct device *device) 83 + { 84 + intel_hid_set_enable(device, 0); 85 + return 0; 86 + } 87 + 88 + static int intel_hid_pl_resume_handler(struct device *device) 89 + { 90 + intel_hid_set_enable(device, 1); 91 + return 0; 92 + } 93 + 94 + static const struct dev_pm_ops intel_hid_pl_pm_ops = { 95 + .suspend = intel_hid_pl_suspend_handler, 96 + .resume = intel_hid_pl_resume_handler, 97 + }; 98 + 99 + static int intel_hid_input_setup(struct platform_device *device) 100 + { 101 + struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); 102 + int ret; 103 + 104 + priv->input_dev = input_allocate_device(); 105 + if (!priv->input_dev) 106 + return -ENOMEM; 107 + 108 + ret = sparse_keymap_setup(priv->input_dev, intel_hid_keymap, NULL); 109 + if (ret) 110 + goto err_free_device; 111 + 112 + priv->input_dev->dev.parent = &device->dev; 113 + priv->input_dev->name = "Intel HID events"; 114 + priv->input_dev->id.bustype = BUS_HOST; 115 + set_bit(KEY_RFKILL, priv->input_dev->keybit); 116 + 117 + ret = input_register_device(priv->input_dev); 118 + if (ret) 119 + goto err_free_device; 120 + 121 + return 0; 122 + 123 + err_free_device: 124 + input_free_device(priv->input_dev); 125 + return ret; 126 + } 127 + 128 + static void intel_hid_input_destroy(struct platform_device *device) 129 + { 130 + struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); 131 + 132 + input_unregister_device(priv->input_dev); 133 + } 134 + 135 + static void notify_handler(acpi_handle handle, u32 event, void *context) 136 + { 137 + struct platform_device *device = context; 138 + struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); 139 + unsigned long long ev_index; 140 + acpi_status status; 141 + 142 + /* The platform spec only defines one event code: 0xC0. */ 143 + if (event != 0xc0) { 144 + dev_warn(&device->dev, "received unknown event (0x%x)\n", 145 + event); 146 + return; 147 + } 148 + 149 + status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index); 150 + if (!ACPI_SUCCESS(status)) { 151 + dev_warn(&device->dev, "failed to get event index\n"); 152 + return; 153 + } 154 + 155 + if (!sparse_keymap_report_event(priv->input_dev, ev_index, 1, true)) 156 + dev_info(&device->dev, "unknown event index 0x%llx\n", 157 + ev_index); 158 + } 159 + 160 + static int intel_hid_probe(struct platform_device *device) 161 + { 162 + acpi_handle handle = ACPI_HANDLE(&device->dev); 163 + struct intel_hid_priv *priv; 164 + unsigned long long mode; 165 + acpi_status status; 166 + int err; 167 + 168 + status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode); 169 + if (!ACPI_SUCCESS(status)) { 170 + dev_warn(&device->dev, "failed to read mode\n"); 171 + return -ENODEV; 172 + } 173 + 174 + if (mode != 0) { 175 + /* 176 + * This driver only implements "simple" mode. There appear 177 + * to be no other modes, but we should be paranoid and check 178 + * for compatibility. 179 + */ 180 + dev_info(&device->dev, "platform is not in simple mode\n"); 181 + return -ENODEV; 182 + } 183 + 184 + priv = devm_kzalloc(&device->dev, 185 + sizeof(struct intel_hid_priv *), GFP_KERNEL); 186 + if (!priv) 187 + return -ENOMEM; 188 + dev_set_drvdata(&device->dev, priv); 189 + 190 + err = intel_hid_input_setup(device); 191 + if (err) { 192 + pr_err("Failed to setup Intel HID hotkeys\n"); 193 + return err; 194 + } 195 + 196 + status = acpi_install_notify_handler(handle, 197 + ACPI_DEVICE_NOTIFY, 198 + notify_handler, 199 + device); 200 + if (ACPI_FAILURE(status)) { 201 + err = -EBUSY; 202 + goto err_remove_input; 203 + } 204 + 205 + err = intel_hid_set_enable(&device->dev, 1); 206 + if (err) 207 + goto err_remove_notify; 208 + 209 + return 0; 210 + 211 + err_remove_notify: 212 + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); 213 + 214 + err_remove_input: 215 + intel_hid_input_destroy(device); 216 + 217 + return err; 218 + } 219 + 220 + static int intel_hid_remove(struct platform_device *device) 221 + { 222 + acpi_handle handle = ACPI_HANDLE(&device->dev); 223 + 224 + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); 225 + intel_hid_input_destroy(device); 226 + intel_hid_set_enable(&device->dev, 0); 227 + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); 228 + 229 + /* 230 + * Even if we failed to shut off the event stream, we can still 231 + * safely detach from the device. 232 + */ 233 + return 0; 234 + } 235 + 236 + static struct platform_driver intel_hid_pl_driver = { 237 + .driver = { 238 + .name = "intel-hid", 239 + .acpi_match_table = intel_hid_ids, 240 + .pm = &intel_hid_pl_pm_ops, 241 + }, 242 + .probe = intel_hid_probe, 243 + .remove = intel_hid_remove, 244 + }; 245 + MODULE_DEVICE_TABLE(acpi, intel_hid_ids); 246 + 247 + /* 248 + * Unfortunately, some laptops provide a _HID="INT33D5" device with 249 + * _CID="PNP0C02". This causes the pnpacpi scan driver to claim the 250 + * ACPI node, so no platform device will be created. The pnpacpi 251 + * driver rejects this device in subsequent processing, so no physical 252 + * node is created at all. 253 + * 254 + * As a workaround until the ACPI core figures out how to handle 255 + * this corner case, manually ask the ACPI platform device code to 256 + * claim the ACPI node. 257 + */ 258 + static acpi_status __init 259 + check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv) 260 + { 261 + const struct acpi_device_id *ids = context; 262 + struct acpi_device *dev; 263 + 264 + if (acpi_bus_get_device(handle, &dev) != 0) 265 + return AE_OK; 266 + 267 + if (acpi_match_device_ids(dev, ids) == 0) 268 + if (acpi_create_platform_device(dev)) 269 + dev_info(&dev->dev, 270 + "intel-hid: created platform device\n"); 271 + 272 + return AE_OK; 273 + } 274 + 275 + static int __init intel_hid_init(void) 276 + { 277 + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 278 + ACPI_UINT32_MAX, check_acpi_dev, NULL, 279 + (void *)intel_hid_ids, NULL); 280 + 281 + return platform_driver_register(&intel_hid_pl_driver); 282 + } 283 + module_init(intel_hid_init); 284 + 285 + static void __exit intel_hid_exit(void) 286 + { 287 + platform_driver_unregister(&intel_hid_pl_driver); 288 + } 289 + module_exit(intel_hid_exit);
+174 -40
drivers/platform/x86/intel_pmc_ipc.c
··· 68 68 #define PLAT_RESOURCE_IPC_INDEX 0 69 69 #define PLAT_RESOURCE_IPC_SIZE 0x1000 70 70 #define PLAT_RESOURCE_GCR_SIZE 0x1000 71 - #define PLAT_RESOURCE_PUNIT_DATA_INDEX 1 72 - #define PLAT_RESOURCE_PUNIT_INTER_INDEX 2 71 + #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 72 + #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 73 + #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 74 + #define PLAT_RESOURCE_ISP_DATA_INDEX 4 75 + #define PLAT_RESOURCE_ISP_IFACE_INDEX 5 76 + #define PLAT_RESOURCE_GTD_DATA_INDEX 6 77 + #define PLAT_RESOURCE_GTD_IFACE_INDEX 7 73 78 #define PLAT_RESOURCE_ACPI_IO_INDEX 0 74 79 75 80 /* ··· 89 84 #define TCO_BASE_OFFSET 0x60 90 85 #define TCO_REGS_SIZE 16 91 86 #define PUNIT_DEVICE_NAME "intel_punit_ipc" 87 + #define TELEMETRY_DEVICE_NAME "intel_telemetry" 88 + #define TELEM_SSRAM_SIZE 240 89 + #define TELEM_PMC_SSRAM_OFFSET 0x1B00 90 + #define TELEM_PUNIT_SSRAM_OFFSET 0x1A00 92 91 93 92 static const int iTCO_version = 3; 94 93 ··· 114 105 int gcr_size; 115 106 116 107 /* punit */ 117 - resource_size_t punit_base; 118 - int punit_size; 119 - resource_size_t punit_base2; 120 - int punit_size2; 121 108 struct platform_device *punit_dev; 109 + 110 + /* Telemetry */ 111 + resource_size_t telem_pmc_ssram_base; 112 + resource_size_t telem_punit_ssram_base; 113 + int telem_pmc_ssram_size; 114 + int telem_punit_ssram_size; 115 + u8 telem_res_inval; 116 + struct platform_device *telemetry_dev; 122 117 } ipcdev; 123 118 124 119 static char *ipc_err_sources[] = { ··· 457 444 .attrs = intel_ipc_attrs, 458 445 }; 459 446 460 - #define PUNIT_RESOURCE_INTER 1 461 - static struct resource punit_res[] = { 462 - /* Punit */ 447 + static struct resource punit_res_array[] = { 448 + /* Punit BIOS */ 449 + { 450 + .flags = IORESOURCE_MEM, 451 + }, 452 + { 453 + .flags = IORESOURCE_MEM, 454 + }, 455 + /* Punit ISP */ 456 + { 457 + .flags = IORESOURCE_MEM, 458 + }, 459 + { 460 + .flags = IORESOURCE_MEM, 461 + }, 462 + /* Punit GTD */ 463 463 { 464 464 .flags = IORESOURCE_MEM, 465 465 }, ··· 504 478 .version = 3, 505 479 }; 506 480 481 + #define TELEMETRY_RESOURCE_PUNIT_SSRAM 0 482 + #define TELEMETRY_RESOURCE_PMC_SSRAM 1 483 + static struct resource telemetry_res[] = { 484 + /*Telemetry*/ 485 + { 486 + .flags = IORESOURCE_MEM, 487 + }, 488 + { 489 + .flags = IORESOURCE_MEM, 490 + }, 491 + }; 492 + 507 493 static int ipc_create_punit_device(void) 508 494 { 509 495 struct platform_device *pdev; 510 - struct resource *res; 511 496 int ret; 512 497 513 498 pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1); ··· 528 491 } 529 492 530 493 pdev->dev.parent = ipcdev.dev; 531 - 532 - res = punit_res; 533 - res->start = ipcdev.punit_base; 534 - res->end = res->start + ipcdev.punit_size - 1; 535 - 536 - res = punit_res + PUNIT_RESOURCE_INTER; 537 - res->start = ipcdev.punit_base2; 538 - res->end = res->start + ipcdev.punit_size2 - 1; 539 - 540 - ret = platform_device_add_resources(pdev, punit_res, 541 - ARRAY_SIZE(punit_res)); 494 + ret = platform_device_add_resources(pdev, punit_res_array, 495 + ARRAY_SIZE(punit_res_array)); 542 496 if (ret) { 543 497 dev_err(ipcdev.dev, "Failed to add platform punit resources\n"); 544 498 goto err; ··· 599 571 return ret; 600 572 } 601 573 574 + static int ipc_create_telemetry_device(void) 575 + { 576 + struct platform_device *pdev; 577 + struct resource *res; 578 + int ret; 579 + 580 + pdev = platform_device_alloc(TELEMETRY_DEVICE_NAME, -1); 581 + if (!pdev) { 582 + dev_err(ipcdev.dev, 583 + "Failed to allocate telemetry platform device\n"); 584 + return -ENOMEM; 585 + } 586 + 587 + pdev->dev.parent = ipcdev.dev; 588 + 589 + res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM; 590 + res->start = ipcdev.telem_punit_ssram_base; 591 + res->end = res->start + ipcdev.telem_punit_ssram_size - 1; 592 + 593 + res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM; 594 + res->start = ipcdev.telem_pmc_ssram_base; 595 + res->end = res->start + ipcdev.telem_pmc_ssram_size - 1; 596 + 597 + ret = platform_device_add_resources(pdev, telemetry_res, 598 + ARRAY_SIZE(telemetry_res)); 599 + if (ret) { 600 + dev_err(ipcdev.dev, 601 + "Failed to add telemetry platform resources\n"); 602 + goto err; 603 + } 604 + 605 + ret = platform_device_add(pdev); 606 + if (ret) { 607 + dev_err(ipcdev.dev, 608 + "Failed to add telemetry platform device\n"); 609 + goto err; 610 + } 611 + ipcdev.telemetry_dev = pdev; 612 + 613 + return 0; 614 + err: 615 + platform_device_put(pdev); 616 + return ret; 617 + } 618 + 602 619 static int ipc_create_pmc_devices(void) 603 620 { 604 621 int ret; ··· 658 585 dev_err(ipcdev.dev, "Failed to add punit platform device\n"); 659 586 platform_device_unregister(ipcdev.tco_dev); 660 587 } 588 + 589 + if (!ipcdev.telem_res_inval) { 590 + ret = ipc_create_telemetry_device(); 591 + if (ret) 592 + dev_warn(ipcdev.dev, 593 + "Failed to add telemetry platform device\n"); 594 + } 595 + 661 596 return ret; 662 597 } 663 598 664 599 static int ipc_plat_get_res(struct platform_device *pdev) 665 600 { 666 - struct resource *res; 601 + struct resource *res, *punit_res; 667 602 void __iomem *addr; 668 603 int size; 669 604 ··· 684 603 size = resource_size(res); 685 604 ipcdev.acpi_io_base = res->start; 686 605 ipcdev.acpi_io_size = size; 687 - dev_info(&pdev->dev, "io res: %llx %x\n", 688 - (long long)res->start, (int)resource_size(res)); 606 + dev_info(&pdev->dev, "io res: %pR\n", res); 689 607 608 + /* This is index 0 to cover BIOS data register */ 609 + punit_res = punit_res_array; 690 610 res = platform_get_resource(pdev, IORESOURCE_MEM, 691 - PLAT_RESOURCE_PUNIT_DATA_INDEX); 611 + PLAT_RESOURCE_BIOS_DATA_INDEX); 692 612 if (!res) { 693 - dev_err(&pdev->dev, "Failed to get punit resource\n"); 613 + dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n"); 694 614 return -ENXIO; 695 615 } 696 - size = resource_size(res); 697 - ipcdev.punit_base = res->start; 698 - ipcdev.punit_size = size; 699 - dev_info(&pdev->dev, "punit data res: %llx %x\n", 700 - (long long)res->start, (int)resource_size(res)); 616 + *punit_res = *res; 617 + dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res); 701 618 702 619 res = platform_get_resource(pdev, IORESOURCE_MEM, 703 - PLAT_RESOURCE_PUNIT_INTER_INDEX); 620 + PLAT_RESOURCE_BIOS_IFACE_INDEX); 704 621 if (!res) { 705 - dev_err(&pdev->dev, "Failed to get punit inter resource\n"); 622 + dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n"); 706 623 return -ENXIO; 707 624 } 708 - size = resource_size(res); 709 - ipcdev.punit_base2 = res->start; 710 - ipcdev.punit_size2 = size; 711 - dev_info(&pdev->dev, "punit interface res: %llx %x\n", 712 - (long long)res->start, (int)resource_size(res)); 625 + /* This is index 1 to cover BIOS interface register */ 626 + *++punit_res = *res; 627 + dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res); 628 + 629 + res = platform_get_resource(pdev, IORESOURCE_MEM, 630 + PLAT_RESOURCE_ISP_DATA_INDEX); 631 + if (!res) { 632 + dev_err(&pdev->dev, "Failed to get res of punit ISP data\n"); 633 + return -ENXIO; 634 + } 635 + /* This is index 2 to cover ISP data register */ 636 + *++punit_res = *res; 637 + dev_info(&pdev->dev, "punit ISP data res: %pR\n", res); 638 + 639 + res = platform_get_resource(pdev, IORESOURCE_MEM, 640 + PLAT_RESOURCE_ISP_IFACE_INDEX); 641 + if (!res) { 642 + dev_err(&pdev->dev, "Failed to get res of punit ISP iface\n"); 643 + return -ENXIO; 644 + } 645 + /* This is index 3 to cover ISP interface register */ 646 + *++punit_res = *res; 647 + dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res); 648 + 649 + res = platform_get_resource(pdev, IORESOURCE_MEM, 650 + PLAT_RESOURCE_GTD_DATA_INDEX); 651 + if (!res) { 652 + dev_err(&pdev->dev, "Failed to get res of punit GTD data\n"); 653 + return -ENXIO; 654 + } 655 + /* This is index 4 to cover GTD data register */ 656 + *++punit_res = *res; 657 + dev_info(&pdev->dev, "punit GTD data res: %pR\n", res); 658 + 659 + res = platform_get_resource(pdev, IORESOURCE_MEM, 660 + PLAT_RESOURCE_GTD_IFACE_INDEX); 661 + if (!res) { 662 + dev_err(&pdev->dev, "Failed to get res of punit GTD iface\n"); 663 + return -ENXIO; 664 + } 665 + /* This is index 5 to cover GTD interface register */ 666 + *++punit_res = *res; 667 + dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res); 713 668 714 669 res = platform_get_resource(pdev, IORESOURCE_MEM, 715 670 PLAT_RESOURCE_IPC_INDEX); ··· 768 651 769 652 ipcdev.gcr_base = res->start + size; 770 653 ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; 771 - dev_info(&pdev->dev, "ipc res: %llx %x\n", 772 - (long long)res->start, (int)resource_size(res)); 654 + dev_info(&pdev->dev, "ipc res: %pR\n", res); 655 + 656 + ipcdev.telem_res_inval = 0; 657 + res = platform_get_resource(pdev, IORESOURCE_MEM, 658 + PLAT_RESOURCE_TELEM_SSRAM_INDEX); 659 + if (!res) { 660 + dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n"); 661 + ipcdev.telem_res_inval = 1; 662 + } else { 663 + ipcdev.telem_punit_ssram_base = res->start + 664 + TELEM_PUNIT_SSRAM_OFFSET; 665 + ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE; 666 + ipcdev.telem_pmc_ssram_base = res->start + 667 + TELEM_PMC_SSRAM_OFFSET; 668 + ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE; 669 + dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res); 670 + } 773 671 774 672 return 0; 775 673 } ··· 843 711 err_irq: 844 712 platform_device_unregister(ipcdev.tco_dev); 845 713 platform_device_unregister(ipcdev.punit_dev); 714 + platform_device_unregister(ipcdev.telemetry_dev); 846 715 err_device: 847 716 iounmap(ipcdev.ipc_base); 848 717 res = platform_get_resource(pdev, IORESOURCE_MEM, ··· 861 728 free_irq(ipcdev.irq, &ipcdev); 862 729 platform_device_unregister(ipcdev.tco_dev); 863 730 platform_device_unregister(ipcdev.punit_dev); 731 + platform_device_unregister(ipcdev.telemetry_dev); 864 732 iounmap(ipcdev.ipc_base); 865 733 res = platform_get_resource(pdev, IORESOURCE_MEM, 866 734 PLAT_RESOURCE_IPC_INDEX);
+342
drivers/platform/x86/intel_punit_ipc.c
··· 1 + /* 2 + * Driver for the Intel P-Unit Mailbox IPC mechanism 3 + * 4 + * (C) Copyright 2015 Intel Corporation 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * The heart of the P-Unit is the Foxton microcontroller and its firmware, 11 + * which provide mailbox interface for power management usage. 12 + */ 13 + 14 + #include <linux/module.h> 15 + #include <linux/acpi.h> 16 + #include <linux/delay.h> 17 + #include <linux/bitops.h> 18 + #include <linux/device.h> 19 + #include <linux/interrupt.h> 20 + #include <linux/platform_device.h> 21 + #include <asm/intel_punit_ipc.h> 22 + 23 + /* IPC Mailbox registers */ 24 + #define OFFSET_DATA_LOW 0x0 25 + #define OFFSET_DATA_HIGH 0x4 26 + /* bit field of interface register */ 27 + #define CMD_RUN BIT(31) 28 + #define CMD_ERRCODE_MASK GENMASK(7, 0) 29 + #define CMD_PARA1_SHIFT 8 30 + #define CMD_PARA2_SHIFT 16 31 + 32 + #define CMD_TIMEOUT_SECONDS 1 33 + 34 + enum { 35 + BASE_DATA = 0, 36 + BASE_IFACE, 37 + BASE_MAX, 38 + }; 39 + 40 + typedef struct { 41 + struct device *dev; 42 + struct mutex lock; 43 + int irq; 44 + struct completion cmd_complete; 45 + /* base of interface and data registers */ 46 + void __iomem *base[RESERVED_IPC][BASE_MAX]; 47 + IPC_TYPE type; 48 + } IPC_DEV; 49 + 50 + static IPC_DEV *punit_ipcdev; 51 + 52 + static inline u32 ipc_read_status(IPC_DEV *ipcdev, IPC_TYPE type) 53 + { 54 + return readl(ipcdev->base[type][BASE_IFACE]); 55 + } 56 + 57 + static inline void ipc_write_cmd(IPC_DEV *ipcdev, IPC_TYPE type, u32 cmd) 58 + { 59 + writel(cmd, ipcdev->base[type][BASE_IFACE]); 60 + } 61 + 62 + static inline u32 ipc_read_data_low(IPC_DEV *ipcdev, IPC_TYPE type) 63 + { 64 + return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW); 65 + } 66 + 67 + static inline u32 ipc_read_data_high(IPC_DEV *ipcdev, IPC_TYPE type) 68 + { 69 + return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH); 70 + } 71 + 72 + static inline void ipc_write_data_low(IPC_DEV *ipcdev, IPC_TYPE type, u32 data) 73 + { 74 + writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW); 75 + } 76 + 77 + static inline void ipc_write_data_high(IPC_DEV *ipcdev, IPC_TYPE type, u32 data) 78 + { 79 + writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH); 80 + } 81 + 82 + static const char *ipc_err_string(int error) 83 + { 84 + if (error == IPC_PUNIT_ERR_SUCCESS) 85 + return "no error"; 86 + else if (error == IPC_PUNIT_ERR_INVALID_CMD) 87 + return "invalid command"; 88 + else if (error == IPC_PUNIT_ERR_INVALID_PARAMETER) 89 + return "invalid parameter"; 90 + else if (error == IPC_PUNIT_ERR_CMD_TIMEOUT) 91 + return "command timeout"; 92 + else if (error == IPC_PUNIT_ERR_CMD_LOCKED) 93 + return "command locked"; 94 + else if (error == IPC_PUNIT_ERR_INVALID_VR_ID) 95 + return "invalid vr id"; 96 + else if (error == IPC_PUNIT_ERR_VR_ERR) 97 + return "vr error"; 98 + else 99 + return "unknown error"; 100 + } 101 + 102 + static int intel_punit_ipc_check_status(IPC_DEV *ipcdev, IPC_TYPE type) 103 + { 104 + int loops = CMD_TIMEOUT_SECONDS * USEC_PER_SEC; 105 + int errcode; 106 + int status; 107 + 108 + if (ipcdev->irq) { 109 + if (!wait_for_completion_timeout(&ipcdev->cmd_complete, 110 + CMD_TIMEOUT_SECONDS * HZ)) { 111 + dev_err(ipcdev->dev, "IPC timed out\n"); 112 + return -ETIMEDOUT; 113 + } 114 + } else { 115 + while ((ipc_read_status(ipcdev, type) & CMD_RUN) && --loops) 116 + udelay(1); 117 + if (!loops) { 118 + dev_err(ipcdev->dev, "IPC timed out\n"); 119 + return -ETIMEDOUT; 120 + } 121 + } 122 + 123 + status = ipc_read_status(ipcdev, type); 124 + errcode = status & CMD_ERRCODE_MASK; 125 + if (errcode) { 126 + dev_err(ipcdev->dev, "IPC failed: %s, IPC_STS=0x%x\n", 127 + ipc_err_string(errcode), status); 128 + return -EIO; 129 + } 130 + 131 + return 0; 132 + } 133 + 134 + /** 135 + * intel_punit_ipc_simple_command() - Simple IPC command 136 + * @cmd: IPC command code. 137 + * @para1: First 8bit parameter, set 0 if not used. 138 + * @para2: Second 8bit parameter, set 0 if not used. 139 + * 140 + * Send a IPC command to P-Unit when there is no data transaction 141 + * 142 + * Return: IPC error code or 0 on success. 143 + */ 144 + int intel_punit_ipc_simple_command(int cmd, int para1, int para2) 145 + { 146 + IPC_DEV *ipcdev = punit_ipcdev; 147 + IPC_TYPE type; 148 + u32 val; 149 + int ret; 150 + 151 + mutex_lock(&ipcdev->lock); 152 + 153 + reinit_completion(&ipcdev->cmd_complete); 154 + type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET; 155 + 156 + val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK; 157 + val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT; 158 + ipc_write_cmd(ipcdev, type, val); 159 + ret = intel_punit_ipc_check_status(ipcdev, type); 160 + 161 + mutex_unlock(&ipcdev->lock); 162 + 163 + return ret; 164 + } 165 + EXPORT_SYMBOL(intel_punit_ipc_simple_command); 166 + 167 + /** 168 + * intel_punit_ipc_command() - IPC command with data and pointers 169 + * @cmd: IPC command code. 170 + * @para1: First 8bit parameter, set 0 if not used. 171 + * @para2: Second 8bit parameter, set 0 if not used. 172 + * @in: Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD. 173 + * @out: Output data. 174 + * 175 + * Send a IPC command to P-Unit with data transaction 176 + * 177 + * Return: IPC error code or 0 on success. 178 + */ 179 + int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out) 180 + { 181 + IPC_DEV *ipcdev = punit_ipcdev; 182 + IPC_TYPE type; 183 + u32 val; 184 + int ret; 185 + 186 + mutex_lock(&ipcdev->lock); 187 + 188 + reinit_completion(&ipcdev->cmd_complete); 189 + type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET; 190 + 191 + if (in) { 192 + ipc_write_data_low(ipcdev, type, *in); 193 + if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC) 194 + ipc_write_data_high(ipcdev, type, *++in); 195 + } 196 + 197 + val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK; 198 + val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT; 199 + ipc_write_cmd(ipcdev, type, val); 200 + 201 + ret = intel_punit_ipc_check_status(ipcdev, type); 202 + if (ret) 203 + goto out; 204 + 205 + if (out) { 206 + *out = ipc_read_data_low(ipcdev, type); 207 + if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC) 208 + *++out = ipc_read_data_high(ipcdev, type); 209 + } 210 + 211 + out: 212 + mutex_unlock(&ipcdev->lock); 213 + return ret; 214 + } 215 + EXPORT_SYMBOL_GPL(intel_punit_ipc_command); 216 + 217 + static irqreturn_t intel_punit_ioc(int irq, void *dev_id) 218 + { 219 + IPC_DEV *ipcdev = dev_id; 220 + 221 + complete(&ipcdev->cmd_complete); 222 + return IRQ_HANDLED; 223 + } 224 + 225 + static int intel_punit_get_bars(struct platform_device *pdev) 226 + { 227 + struct resource *res; 228 + void __iomem *addr; 229 + 230 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 231 + addr = devm_ioremap_resource(&pdev->dev, res); 232 + if (IS_ERR(addr)) 233 + return PTR_ERR(addr); 234 + punit_ipcdev->base[BIOS_IPC][BASE_DATA] = addr; 235 + 236 + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 237 + addr = devm_ioremap_resource(&pdev->dev, res); 238 + if (IS_ERR(addr)) 239 + return PTR_ERR(addr); 240 + punit_ipcdev->base[BIOS_IPC][BASE_IFACE] = addr; 241 + 242 + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 243 + addr = devm_ioremap_resource(&pdev->dev, res); 244 + if (IS_ERR(addr)) 245 + return PTR_ERR(addr); 246 + punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr; 247 + 248 + res = platform_get_resource(pdev, IORESOURCE_MEM, 3); 249 + addr = devm_ioremap_resource(&pdev->dev, res); 250 + if (IS_ERR(addr)) 251 + return PTR_ERR(addr); 252 + punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr; 253 + 254 + res = platform_get_resource(pdev, IORESOURCE_MEM, 4); 255 + addr = devm_ioremap_resource(&pdev->dev, res); 256 + if (IS_ERR(addr)) 257 + return PTR_ERR(addr); 258 + punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr; 259 + 260 + res = platform_get_resource(pdev, IORESOURCE_MEM, 5); 261 + addr = devm_ioremap_resource(&pdev->dev, res); 262 + if (IS_ERR(addr)) 263 + return PTR_ERR(addr); 264 + punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr; 265 + 266 + return 0; 267 + } 268 + 269 + static int intel_punit_ipc_probe(struct platform_device *pdev) 270 + { 271 + int irq, ret; 272 + 273 + punit_ipcdev = devm_kzalloc(&pdev->dev, 274 + sizeof(*punit_ipcdev), GFP_KERNEL); 275 + if (!punit_ipcdev) 276 + return -ENOMEM; 277 + 278 + platform_set_drvdata(pdev, punit_ipcdev); 279 + 280 + irq = platform_get_irq(pdev, 0); 281 + if (irq < 0) { 282 + punit_ipcdev->irq = 0; 283 + dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n"); 284 + } else { 285 + ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc, 286 + IRQF_NO_SUSPEND, "intel_punit_ipc", 287 + &punit_ipcdev); 288 + if (ret) { 289 + dev_err(&pdev->dev, "Failed to request irq: %d\n", irq); 290 + return ret; 291 + } 292 + punit_ipcdev->irq = irq; 293 + } 294 + 295 + ret = intel_punit_get_bars(pdev); 296 + if (ret) 297 + goto out; 298 + 299 + punit_ipcdev->dev = &pdev->dev; 300 + mutex_init(&punit_ipcdev->lock); 301 + init_completion(&punit_ipcdev->cmd_complete); 302 + 303 + out: 304 + return ret; 305 + } 306 + 307 + static int intel_punit_ipc_remove(struct platform_device *pdev) 308 + { 309 + return 0; 310 + } 311 + 312 + static const struct acpi_device_id punit_ipc_acpi_ids[] = { 313 + { "INT34D4", 0 }, 314 + { } 315 + }; 316 + 317 + static struct platform_driver intel_punit_ipc_driver = { 318 + .probe = intel_punit_ipc_probe, 319 + .remove = intel_punit_ipc_remove, 320 + .driver = { 321 + .name = "intel_punit_ipc", 322 + .acpi_match_table = ACPI_PTR(punit_ipc_acpi_ids), 323 + }, 324 + }; 325 + 326 + static int __init intel_punit_ipc_init(void) 327 + { 328 + return platform_driver_register(&intel_punit_ipc_driver); 329 + } 330 + 331 + static void __exit intel_punit_ipc_exit(void) 332 + { 333 + platform_driver_unregister(&intel_punit_ipc_driver); 334 + } 335 + 336 + MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); 337 + MODULE_DESCRIPTION("Intel P-Unit IPC driver"); 338 + MODULE_LICENSE("GPL v2"); 339 + 340 + /* Some modules are dependent on this, so init earlier */ 341 + fs_initcall(intel_punit_ipc_init); 342 + module_exit(intel_punit_ipc_exit);
+464
drivers/platform/x86/intel_telemetry_core.c
··· 1 + /* 2 + * Intel SoC Core Telemetry Driver 3 + * Copyright (C) 2015, Intel Corporation. 4 + * All Rights Reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + * Telemetry Framework provides platform related PM and performance statistics. 16 + * This file provides the core telemetry API implementation. 17 + */ 18 + #include <linux/module.h> 19 + #include <linux/init.h> 20 + #include <linux/device.h> 21 + 22 + #include <asm/intel_telemetry.h> 23 + 24 + #define DRIVER_NAME "intel_telemetry_core" 25 + 26 + struct telemetry_core_config { 27 + struct telemetry_plt_config *plt_config; 28 + struct telemetry_core_ops *telem_ops; 29 + }; 30 + 31 + static struct telemetry_core_config telm_core_conf; 32 + 33 + static int telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig, 34 + struct telemetry_evtconfig ioss_evtconfig) 35 + { 36 + return 0; 37 + } 38 + 39 + static int telemetry_def_set_sampling_period(u8 pss_period, u8 ioss_period) 40 + { 41 + return 0; 42 + } 43 + 44 + static int telemetry_def_get_sampling_period(u8 *pss_min_period, 45 + u8 *pss_max_period, 46 + u8 *ioss_min_period, 47 + u8 *ioss_max_period) 48 + { 49 + return 0; 50 + } 51 + 52 + static int telemetry_def_get_eventconfig( 53 + struct telemetry_evtconfig *pss_evtconfig, 54 + struct telemetry_evtconfig *ioss_evtconfig, 55 + int pss_len, int ioss_len) 56 + { 57 + return 0; 58 + } 59 + 60 + static int telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit, 61 + u32 *verbosity) 62 + { 63 + return 0; 64 + } 65 + 66 + 67 + static int telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit, 68 + u32 verbosity) 69 + { 70 + return 0; 71 + } 72 + 73 + static int telemetry_def_raw_read_eventlog(enum telemetry_unit telem_unit, 74 + struct telemetry_evtlog *evtlog, 75 + int len, int log_all_evts) 76 + { 77 + return 0; 78 + } 79 + 80 + static int telemetry_def_read_eventlog(enum telemetry_unit telem_unit, 81 + struct telemetry_evtlog *evtlog, 82 + int len, int log_all_evts) 83 + { 84 + return 0; 85 + } 86 + 87 + static int telemetry_def_add_events(u8 num_pss_evts, u8 num_ioss_evts, 88 + u32 *pss_evtmap, u32 *ioss_evtmap) 89 + { 90 + return 0; 91 + } 92 + 93 + static int telemetry_def_reset_events(void) 94 + { 95 + return 0; 96 + } 97 + 98 + static struct telemetry_core_ops telm_defpltops = { 99 + .set_sampling_period = telemetry_def_set_sampling_period, 100 + .get_sampling_period = telemetry_def_get_sampling_period, 101 + .get_trace_verbosity = telemetry_def_get_trace_verbosity, 102 + .set_trace_verbosity = telemetry_def_set_trace_verbosity, 103 + .raw_read_eventlog = telemetry_def_raw_read_eventlog, 104 + .get_eventconfig = telemetry_def_get_eventconfig, 105 + .read_eventlog = telemetry_def_read_eventlog, 106 + .update_events = telemetry_def_update_events, 107 + .reset_events = telemetry_def_reset_events, 108 + .add_events = telemetry_def_add_events, 109 + }; 110 + 111 + /** 112 + * telemetry_update_events() - Update telemetry Configuration 113 + * @pss_evtconfig: PSS related config. No change if num_evts = 0. 114 + * @pss_evtconfig: IOSS related config. No change if num_evts = 0. 115 + * 116 + * This API updates the IOSS & PSS Telemetry configuration. Old config 117 + * is overwritten. Call telemetry_reset_events when logging is over 118 + * All sample period values should be in the form of: 119 + * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) 120 + * 121 + * Return: 0 success, < 0 for failure 122 + */ 123 + int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig, 124 + struct telemetry_evtconfig ioss_evtconfig) 125 + { 126 + return telm_core_conf.telem_ops->update_events(pss_evtconfig, 127 + ioss_evtconfig); 128 + } 129 + EXPORT_SYMBOL_GPL(telemetry_update_events); 130 + 131 + 132 + /** 133 + * telemetry_set_sampling_period() - Sets the IOSS & PSS sampling period 134 + * @pss_period: placeholder for PSS Period to be set. 135 + * Set to 0 if not required to be updated 136 + * @ioss_period: placeholder for IOSS Period to be set 137 + * Set to 0 if not required to be updated 138 + * 139 + * All values should be in the form of: 140 + * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) 141 + * 142 + * Return: 0 success, < 0 for failure 143 + */ 144 + int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period) 145 + { 146 + return telm_core_conf.telem_ops->set_sampling_period(pss_period, 147 + ioss_period); 148 + } 149 + EXPORT_SYMBOL_GPL(telemetry_set_sampling_period); 150 + 151 + /** 152 + * telemetry_get_sampling_period() - Get IOSS & PSS min & max sampling period 153 + * @pss_min_period: placeholder for PSS Min Period supported 154 + * @pss_max_period: placeholder for PSS Max Period supported 155 + * @ioss_min_period: placeholder for IOSS Min Period supported 156 + * @ioss_max_period: placeholder for IOSS Max Period supported 157 + * 158 + * All values should be in the form of: 159 + * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) 160 + * 161 + * Return: 0 success, < 0 for failure 162 + */ 163 + int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period, 164 + u8 *ioss_min_period, u8 *ioss_max_period) 165 + { 166 + return telm_core_conf.telem_ops->get_sampling_period(pss_min_period, 167 + pss_max_period, 168 + ioss_min_period, 169 + ioss_max_period); 170 + } 171 + EXPORT_SYMBOL_GPL(telemetry_get_sampling_period); 172 + 173 + 174 + /** 175 + * telemetry_reset_events() - Restore the IOSS & PSS configuration to default 176 + * 177 + * Return: 0 success, < 0 for failure 178 + */ 179 + int telemetry_reset_events(void) 180 + { 181 + return telm_core_conf.telem_ops->reset_events(); 182 + } 183 + EXPORT_SYMBOL_GPL(telemetry_reset_events); 184 + 185 + /** 186 + * telemetry_get_eventconfig() - Returns the pss and ioss events enabled 187 + * @pss_evtconfig: Pointer to PSS related configuration. 188 + * @pss_evtconfig: Pointer to IOSS related configuration. 189 + * @pss_len: Number of u32 elements allocated for pss_evtconfig array 190 + * @ioss_len: Number of u32 elements allocated for ioss_evtconfig array 191 + * 192 + * Return: 0 success, < 0 for failure 193 + */ 194 + int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_evtconfig, 195 + struct telemetry_evtconfig *ioss_evtconfig, 196 + int pss_len, int ioss_len) 197 + { 198 + return telm_core_conf.telem_ops->get_eventconfig(pss_evtconfig, 199 + ioss_evtconfig, 200 + pss_len, ioss_len); 201 + } 202 + EXPORT_SYMBOL_GPL(telemetry_get_eventconfig); 203 + 204 + /** 205 + * telemetry_add_events() - Add IOSS & PSS configuration to existing settings. 206 + * @num_pss_evts: Number of PSS Events (<29) in pss_evtmap. Can be 0. 207 + * @num_ioss_evts: Number of IOSS Events (<29) in ioss_evtmap. Can be 0. 208 + * @pss_evtmap: Array of PSS Event-IDs to Enable 209 + * @ioss_evtmap: Array of PSS Event-IDs to Enable 210 + * 211 + * Events are appended to Old Configuration. In case of total events > 28, it 212 + * returns error. Call telemetry_reset_events to reset after eventlog done 213 + * 214 + * Return: 0 success, < 0 for failure 215 + */ 216 + int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts, 217 + u32 *pss_evtmap, u32 *ioss_evtmap) 218 + { 219 + return telm_core_conf.telem_ops->add_events(num_pss_evts, 220 + num_ioss_evts, pss_evtmap, 221 + ioss_evtmap); 222 + } 223 + EXPORT_SYMBOL_GPL(telemetry_add_events); 224 + 225 + /** 226 + * telemetry_read_events() - Fetches samples as specified by evtlog.telem_evt_id 227 + * @telem_unit: Specify whether IOSS or PSS Read 228 + * @evtlog: Array of telemetry_evtlog structs to fill data 229 + * evtlog.telem_evt_id specifies the ids to read 230 + * @len: Length of array of evtlog 231 + * 232 + * Return: number of eventlogs read for success, < 0 for failure 233 + */ 234 + int telemetry_read_events(enum telemetry_unit telem_unit, 235 + struct telemetry_evtlog *evtlog, int len) 236 + { 237 + return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog, 238 + len, 0); 239 + } 240 + EXPORT_SYMBOL_GPL(telemetry_read_events); 241 + 242 + /** 243 + * telemetry_raw_read_events() - Fetch samples specified by evtlog.telem_evt_id 244 + * @telem_unit: Specify whether IOSS or PSS Read 245 + * @evtlog: Array of telemetry_evtlog structs to fill data 246 + * evtlog.telem_evt_id specifies the ids to read 247 + * @len: Length of array of evtlog 248 + * 249 + * The caller must take care of locking in this case. 250 + * 251 + * Return: number of eventlogs read for success, < 0 for failure 252 + */ 253 + int telemetry_raw_read_events(enum telemetry_unit telem_unit, 254 + struct telemetry_evtlog *evtlog, int len) 255 + { 256 + return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog, 257 + len, 0); 258 + } 259 + EXPORT_SYMBOL_GPL(telemetry_raw_read_events); 260 + 261 + /** 262 + * telemetry_read_eventlog() - Fetch the Telemetry log from PSS or IOSS 263 + * @telem_unit: Specify whether IOSS or PSS Read 264 + * @evtlog: Array of telemetry_evtlog structs to fill data 265 + * @len: Length of array of evtlog 266 + * 267 + * Return: number of eventlogs read for success, < 0 for failure 268 + */ 269 + int telemetry_read_eventlog(enum telemetry_unit telem_unit, 270 + struct telemetry_evtlog *evtlog, int len) 271 + { 272 + return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog, 273 + len, 1); 274 + } 275 + EXPORT_SYMBOL_GPL(telemetry_read_eventlog); 276 + 277 + /** 278 + * telemetry_raw_read_eventlog() - Fetch the Telemetry log from PSS or IOSS 279 + * @telem_unit: Specify whether IOSS or PSS Read 280 + * @evtlog: Array of telemetry_evtlog structs to fill data 281 + * @len: Length of array of evtlog 282 + * 283 + * The caller must take care of locking in this case. 284 + * 285 + * Return: number of eventlogs read for success, < 0 for failure 286 + */ 287 + int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit, 288 + struct telemetry_evtlog *evtlog, int len) 289 + { 290 + return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog, 291 + len, 1); 292 + } 293 + EXPORT_SYMBOL_GPL(telemetry_raw_read_eventlog); 294 + 295 + 296 + /** 297 + * telemetry_get_trace_verbosity() - Get the IOSS & PSS Trace verbosity 298 + * @telem_unit: Specify whether IOSS or PSS Read 299 + * @verbosity: Pointer to return Verbosity 300 + * 301 + * Return: 0 success, < 0 for failure 302 + */ 303 + int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit, 304 + u32 *verbosity) 305 + { 306 + return telm_core_conf.telem_ops->get_trace_verbosity(telem_unit, 307 + verbosity); 308 + } 309 + EXPORT_SYMBOL_GPL(telemetry_get_trace_verbosity); 310 + 311 + 312 + /** 313 + * telemetry_set_trace_verbosity() - Update the IOSS & PSS Trace verbosity 314 + * @telem_unit: Specify whether IOSS or PSS Read 315 + * @verbosity: Verbosity to set 316 + * 317 + * Return: 0 success, < 0 for failure 318 + */ 319 + int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit, u32 verbosity) 320 + { 321 + return telm_core_conf.telem_ops->set_trace_verbosity(telem_unit, 322 + verbosity); 323 + } 324 + EXPORT_SYMBOL_GPL(telemetry_set_trace_verbosity); 325 + 326 + /** 327 + * telemetry_set_pltdata() - Set the platform specific Data 328 + * @ops: Pointer to ops structure 329 + * @pltconfig: Platform config data 330 + * 331 + * Usage by other than telemetry pltdrv module is invalid 332 + * 333 + * Return: 0 success, < 0 for failure 334 + */ 335 + int telemetry_set_pltdata(struct telemetry_core_ops *ops, 336 + struct telemetry_plt_config *pltconfig) 337 + { 338 + if (ops) 339 + telm_core_conf.telem_ops = ops; 340 + 341 + if (pltconfig) 342 + telm_core_conf.plt_config = pltconfig; 343 + 344 + return 0; 345 + } 346 + EXPORT_SYMBOL_GPL(telemetry_set_pltdata); 347 + 348 + /** 349 + * telemetry_clear_pltdata() - Clear the platform specific Data 350 + * 351 + * Usage by other than telemetry pltdrv module is invalid 352 + * 353 + * Return: 0 success, < 0 for failure 354 + */ 355 + int telemetry_clear_pltdata(void) 356 + { 357 + telm_core_conf.telem_ops = &telm_defpltops; 358 + telm_core_conf.plt_config = NULL; 359 + 360 + return 0; 361 + } 362 + EXPORT_SYMBOL_GPL(telemetry_clear_pltdata); 363 + 364 + /** 365 + * telemetry_pltconfig_valid() - Checkif platform config is valid 366 + * 367 + * Usage by other than telemetry module is invalid 368 + * 369 + * Return: 0 success, < 0 for failure 370 + */ 371 + int telemetry_pltconfig_valid(void) 372 + { 373 + if (telm_core_conf.plt_config) 374 + return 0; 375 + 376 + else 377 + return -EINVAL; 378 + } 379 + EXPORT_SYMBOL_GPL(telemetry_pltconfig_valid); 380 + 381 + static inline int telemetry_get_pssevtname(enum telemetry_unit telem_unit, 382 + const char **name, int len) 383 + { 384 + struct telemetry_unit_config psscfg; 385 + int i; 386 + 387 + if (!telm_core_conf.plt_config) 388 + return -EINVAL; 389 + 390 + psscfg = telm_core_conf.plt_config->pss_config; 391 + 392 + if (len > psscfg.ssram_evts_used) 393 + len = psscfg.ssram_evts_used; 394 + 395 + for (i = 0; i < len; i++) 396 + name[i] = psscfg.telem_evts[i].name; 397 + 398 + return 0; 399 + } 400 + 401 + static inline int telemetry_get_iossevtname(enum telemetry_unit telem_unit, 402 + const char **name, int len) 403 + { 404 + struct telemetry_unit_config iosscfg; 405 + int i; 406 + 407 + if (!(telm_core_conf.plt_config)) 408 + return -EINVAL; 409 + 410 + iosscfg = telm_core_conf.plt_config->ioss_config; 411 + 412 + if (len > iosscfg.ssram_evts_used) 413 + len = iosscfg.ssram_evts_used; 414 + 415 + for (i = 0; i < len; i++) 416 + name[i] = iosscfg.telem_evts[i].name; 417 + 418 + return 0; 419 + 420 + } 421 + 422 + /** 423 + * telemetry_get_evtname() - Checkif platform config is valid 424 + * @telem_unit: Telemetry Unit to check 425 + * @name: Array of character pointers to contain name 426 + * @len: length of array name provided by user 427 + * 428 + * Usage by other than telemetry debugfs module is invalid 429 + * 430 + * Return: 0 success, < 0 for failure 431 + */ 432 + int telemetry_get_evtname(enum telemetry_unit telem_unit, 433 + const char **name, int len) 434 + { 435 + int ret = -EINVAL; 436 + 437 + if (telem_unit == TELEM_PSS) 438 + ret = telemetry_get_pssevtname(telem_unit, name, len); 439 + 440 + else if (telem_unit == TELEM_IOSS) 441 + ret = telemetry_get_iossevtname(telem_unit, name, len); 442 + 443 + return ret; 444 + } 445 + EXPORT_SYMBOL_GPL(telemetry_get_evtname); 446 + 447 + static int __init telemetry_module_init(void) 448 + { 449 + pr_info(pr_fmt(DRIVER_NAME) " Init\n"); 450 + 451 + telm_core_conf.telem_ops = &telm_defpltops; 452 + return 0; 453 + } 454 + 455 + static void __exit telemetry_module_exit(void) 456 + { 457 + } 458 + 459 + module_init(telemetry_module_init); 460 + module_exit(telemetry_module_exit); 461 + 462 + MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>"); 463 + MODULE_DESCRIPTION("Intel SoC Telemetry Interface"); 464 + MODULE_LICENSE("GPL");
+1030
drivers/platform/x86/intel_telemetry_debugfs.c
··· 1 + /* 2 + * Intel SOC Telemetry debugfs Driver: Currently supports APL 3 + * Copyright (c) 2015, Intel Corporation. 4 + * All Rights Reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + * This file provides the debugfs interfaces for telemetry. 16 + * /sys/kernel/debug/telemetry/pss_info: Shows Primary Control Sub-Sys Counters 17 + * /sys/kernel/debug/telemetry/ioss_info: Shows IO Sub-System Counters 18 + * /sys/kernel/debug/telemetry/soc_states: Shows SoC State 19 + * /sys/kernel/debug/telemetry/pss_trace_verbosity: Read and Change Tracing 20 + * Verbosity via firmware 21 + * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing 22 + * Verbosity via firmware 23 + */ 24 + #include <linux/module.h> 25 + #include <linux/init.h> 26 + #include <linux/device.h> 27 + #include <linux/debugfs.h> 28 + #include <linux/seq_file.h> 29 + #include <linux/io.h> 30 + #include <linux/uaccess.h> 31 + #include <linux/pci.h> 32 + #include <linux/suspend.h> 33 + 34 + #include <asm/cpu_device_id.h> 35 + #include <asm/intel_pmc_ipc.h> 36 + #include <asm/intel_punit_ipc.h> 37 + #include <asm/intel_telemetry.h> 38 + 39 + #define DRIVER_NAME "telemetry_soc_debugfs" 40 + #define DRIVER_VERSION "1.0.0" 41 + 42 + /* ApolloLake SoC Event-IDs */ 43 + #define TELEM_APL_PSS_PSTATES_ID 0x2802 44 + #define TELEM_APL_PSS_IDLE_ID 0x2806 45 + #define TELEM_APL_PCS_IDLE_BLOCKED_ID 0x2C00 46 + #define TELEM_APL_PCS_S0IX_BLOCKED_ID 0x2C01 47 + #define TELEM_APL_PSS_WAKEUP_ID 0x2C02 48 + #define TELEM_APL_PSS_LTR_BLOCKING_ID 0x2C03 49 + 50 + #define TELEM_APL_S0IX_TOTAL_OCC_ID 0x4000 51 + #define TELEM_APL_S0IX_SHLW_OCC_ID 0x4001 52 + #define TELEM_APL_S0IX_DEEP_OCC_ID 0x4002 53 + #define TELEM_APL_S0IX_TOTAL_RES_ID 0x4800 54 + #define TELEM_APL_S0IX_SHLW_RES_ID 0x4801 55 + #define TELEM_APL_S0IX_DEEP_RES_ID 0x4802 56 + #define TELEM_APL_D0IX_ID 0x581A 57 + #define TELEM_APL_D3_ID 0x5819 58 + #define TELEM_APL_PG_ID 0x5818 59 + 60 + #define TELEM_INFO_SRAMEVTS_MASK 0xFF00 61 + #define TELEM_INFO_SRAMEVTS_SHIFT 0x8 62 + #define TELEM_SSRAM_READ_TIMEOUT 10 63 + 64 + #define TELEM_MASK_BIT 1 65 + #define TELEM_MASK_BYTE 0xFF 66 + #define BYTES_PER_LONG 8 67 + #define TELEM_APL_MASK_PCS_STATE 0xF 68 + 69 + /* Max events in bitmap to check for */ 70 + #define TELEM_PSS_IDLE_EVTS 25 71 + #define TELEM_PSS_IDLE_BLOCKED_EVTS 20 72 + #define TELEM_PSS_S0IX_BLOCKED_EVTS 20 73 + #define TELEM_PSS_S0IX_WAKEUP_EVTS 20 74 + #define TELEM_PSS_LTR_BLOCKING_EVTS 20 75 + #define TELEM_IOSS_DX_D0IX_EVTS 25 76 + #define TELEM_IOSS_PG_EVTS 30 77 + 78 + #define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0])) 79 + 80 + #define TELEM_DEBUGFS_CPU(model, data) \ 81 + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data} 82 + 83 + #define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \ 84 + if (evtlog[index].telem_evtid == (EVTID)) { \ 85 + for (idx = 0; idx < (EVTNUM); idx++) \ 86 + (BUF)[idx] = ((EVTLOG) >> (EVTDAT)[idx].bit_pos) & \ 87 + (MASK); \ 88 + continue; \ 89 + } \ 90 + } 91 + 92 + #define TELEM_CHECK_AND_PARSE_CTRS(EVTID, CTR) { \ 93 + if (evtlog[index].telem_evtid == (EVTID)) { \ 94 + (CTR) = evtlog[index].telem_evtlog; \ 95 + continue; \ 96 + } \ 97 + } 98 + 99 + static u8 suspend_prep_ok; 100 + static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp; 101 + static u64 suspend_shlw_res_temp, suspend_deep_res_temp; 102 + 103 + struct telemetry_susp_stats { 104 + u32 shlw_swake_ctr; 105 + u32 deep_swake_ctr; 106 + u64 shlw_swake_res; 107 + u64 deep_swake_res; 108 + u32 shlw_ctr; 109 + u32 deep_ctr; 110 + u64 shlw_res; 111 + u64 deep_res; 112 + }; 113 + 114 + /* Bitmap definitions for default counters in APL */ 115 + struct telem_pss_idle_stateinfo { 116 + const char *name; 117 + u32 bit_pos; 118 + }; 119 + 120 + static struct telem_pss_idle_stateinfo telem_apl_pss_idle_data[] = { 121 + {"IA_CORE0_C1E", 0}, 122 + {"IA_CORE1_C1E", 1}, 123 + {"IA_CORE2_C1E", 2}, 124 + {"IA_CORE3_C1E", 3}, 125 + {"IA_CORE0_C6", 16}, 126 + {"IA_CORE1_C6", 17}, 127 + {"IA_CORE2_C6", 18}, 128 + {"IA_CORE3_C6", 19}, 129 + {"IA_MODULE0_C7", 32}, 130 + {"IA_MODULE1_C7", 33}, 131 + {"GT_RC6", 40}, 132 + {"IUNIT_PROCESSING_IDLE", 41}, 133 + {"FAR_MEM_IDLE", 43}, 134 + {"DISPLAY_IDLE", 44}, 135 + {"IUNIT_INPUT_SYSTEM_IDLE", 45}, 136 + {"PCS_STATUS", 60}, 137 + }; 138 + 139 + struct telem_pcs_blkd_info { 140 + const char *name; 141 + u32 bit_pos; 142 + }; 143 + 144 + static struct telem_pcs_blkd_info telem_apl_pcs_idle_blkd_data[] = { 145 + {"COMPUTE", 0}, 146 + {"MISC", 8}, 147 + {"MODULE_ACTIONS_PENDING", 16}, 148 + {"LTR", 24}, 149 + {"DISPLAY_WAKE", 32}, 150 + {"ISP_WAKE", 40}, 151 + {"PSF0_ACTIVE", 48}, 152 + }; 153 + 154 + static struct telem_pcs_blkd_info telem_apl_pcs_s0ix_blkd_data[] = { 155 + {"LTR", 0}, 156 + {"IRTL", 8}, 157 + {"WAKE_DEADLINE_PENDING", 16}, 158 + {"DISPLAY", 24}, 159 + {"ISP", 32}, 160 + {"CORE", 40}, 161 + {"PMC", 48}, 162 + {"MISC", 56}, 163 + }; 164 + 165 + struct telem_pss_ltr_info { 166 + const char *name; 167 + u32 bit_pos; 168 + }; 169 + 170 + static struct telem_pss_ltr_info telem_apl_pss_ltr_data[] = { 171 + {"CORE_ACTIVE", 0}, 172 + {"MEM_UP", 8}, 173 + {"DFX", 16}, 174 + {"DFX_FORCE_LTR", 24}, 175 + {"DISPLAY", 32}, 176 + {"ISP", 40}, 177 + {"SOUTH", 48}, 178 + }; 179 + 180 + struct telem_pss_wakeup_info { 181 + const char *name; 182 + u32 bit_pos; 183 + }; 184 + 185 + static struct telem_pss_wakeup_info telem_apl_pss_wakeup[] = { 186 + {"IP_IDLE", 0}, 187 + {"DISPLAY_WAKE", 8}, 188 + {"VOLTAGE_REG_INT", 16}, 189 + {"DROWSY_TIMER (HOTPLUG)", 24}, 190 + {"CORE_WAKE", 32}, 191 + {"MISC_S0IX", 40}, 192 + {"MISC_ABORT", 56}, 193 + }; 194 + 195 + struct telem_ioss_d0ix_stateinfo { 196 + const char *name; 197 + u32 bit_pos; 198 + }; 199 + 200 + static struct telem_ioss_d0ix_stateinfo telem_apl_ioss_d0ix_data[] = { 201 + {"CSE", 0}, 202 + {"SCC2", 1}, 203 + {"GMM", 2}, 204 + {"XDCI", 3}, 205 + {"XHCI", 4}, 206 + {"ISH", 5}, 207 + {"AVS", 6}, 208 + {"PCIE0P1", 7}, 209 + {"PECI0P0", 8}, 210 + {"LPSS", 9}, 211 + {"SCC", 10}, 212 + {"PWM", 11}, 213 + {"PCIE1_P3", 12}, 214 + {"PCIE1_P2", 13}, 215 + {"PCIE1_P1", 14}, 216 + {"PCIE1_P0", 15}, 217 + {"CNV", 16}, 218 + {"SATA", 17}, 219 + {"PRTC", 18}, 220 + }; 221 + 222 + struct telem_ioss_pg_info { 223 + const char *name; 224 + u32 bit_pos; 225 + }; 226 + 227 + static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = { 228 + {"LPSS", 0}, 229 + {"SCC", 1}, 230 + {"P2SB", 2}, 231 + {"SCC2", 3}, 232 + {"GMM", 4}, 233 + {"PCIE0", 5}, 234 + {"XDCI", 6}, 235 + {"xHCI", 7}, 236 + {"CSE", 8}, 237 + {"SPI", 9}, 238 + {"AVSPGD4", 10}, 239 + {"AVSPGD3", 11}, 240 + {"AVSPGD2", 12}, 241 + {"AVSPGD1", 13}, 242 + {"ISH", 14}, 243 + {"EXI", 15}, 244 + {"NPKVRC", 16}, 245 + {"NPKVNN", 17}, 246 + {"CUNIT", 18}, 247 + {"FUSE_CTRL", 19}, 248 + {"PCIE1", 20}, 249 + {"CNV", 21}, 250 + {"LPC", 22}, 251 + {"SATA", 23}, 252 + {"SMB", 24}, 253 + {"PRTC", 25}, 254 + }; 255 + 256 + 257 + struct telemetry_debugfs_conf { 258 + struct telemetry_susp_stats suspend_stats; 259 + struct dentry *telemetry_dbg_dir; 260 + 261 + /* Bitmap Data */ 262 + struct telem_ioss_d0ix_stateinfo *ioss_d0ix_data; 263 + struct telem_pss_idle_stateinfo *pss_idle_data; 264 + struct telem_pcs_blkd_info *pcs_idle_blkd_data; 265 + struct telem_pcs_blkd_info *pcs_s0ix_blkd_data; 266 + struct telem_pss_wakeup_info *pss_wakeup; 267 + struct telem_pss_ltr_info *pss_ltr_data; 268 + struct telem_ioss_pg_info *ioss_pg_data; 269 + u8 pcs_idle_blkd_evts; 270 + u8 pcs_s0ix_blkd_evts; 271 + u8 pss_wakeup_evts; 272 + u8 pss_idle_evts; 273 + u8 pss_ltr_evts; 274 + u8 ioss_d0ix_evts; 275 + u8 ioss_pg_evts; 276 + 277 + /* IDs */ 278 + u16 pss_ltr_blocking_id; 279 + u16 pcs_idle_blkd_id; 280 + u16 pcs_s0ix_blkd_id; 281 + u16 s0ix_total_occ_id; 282 + u16 s0ix_shlw_occ_id; 283 + u16 s0ix_deep_occ_id; 284 + u16 s0ix_total_res_id; 285 + u16 s0ix_shlw_res_id; 286 + u16 s0ix_deep_res_id; 287 + u16 pss_wakeup_id; 288 + u16 ioss_d0ix_id; 289 + u16 pstates_id; 290 + u16 pss_idle_id; 291 + u16 ioss_d3_id; 292 + u16 ioss_pg_id; 293 + }; 294 + 295 + static struct telemetry_debugfs_conf *debugfs_conf; 296 + 297 + static struct telemetry_debugfs_conf telem_apl_debugfs_conf = { 298 + .pss_idle_data = telem_apl_pss_idle_data, 299 + .pcs_idle_blkd_data = telem_apl_pcs_idle_blkd_data, 300 + .pcs_s0ix_blkd_data = telem_apl_pcs_s0ix_blkd_data, 301 + .pss_ltr_data = telem_apl_pss_ltr_data, 302 + .pss_wakeup = telem_apl_pss_wakeup, 303 + .ioss_d0ix_data = telem_apl_ioss_d0ix_data, 304 + .ioss_pg_data = telem_apl_ioss_pg_data, 305 + 306 + .pss_idle_evts = TELEM_EVT_LEN(telem_apl_pss_idle_data), 307 + .pcs_idle_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_idle_blkd_data), 308 + .pcs_s0ix_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_s0ix_blkd_data), 309 + .pss_ltr_evts = TELEM_EVT_LEN(telem_apl_pss_ltr_data), 310 + .pss_wakeup_evts = TELEM_EVT_LEN(telem_apl_pss_wakeup), 311 + .ioss_d0ix_evts = TELEM_EVT_LEN(telem_apl_ioss_d0ix_data), 312 + .ioss_pg_evts = TELEM_EVT_LEN(telem_apl_ioss_pg_data), 313 + 314 + .pstates_id = TELEM_APL_PSS_PSTATES_ID, 315 + .pss_idle_id = TELEM_APL_PSS_IDLE_ID, 316 + .pcs_idle_blkd_id = TELEM_APL_PCS_IDLE_BLOCKED_ID, 317 + .pcs_s0ix_blkd_id = TELEM_APL_PCS_S0IX_BLOCKED_ID, 318 + .pss_wakeup_id = TELEM_APL_PSS_WAKEUP_ID, 319 + .pss_ltr_blocking_id = TELEM_APL_PSS_LTR_BLOCKING_ID, 320 + .s0ix_total_occ_id = TELEM_APL_S0IX_TOTAL_OCC_ID, 321 + .s0ix_shlw_occ_id = TELEM_APL_S0IX_SHLW_OCC_ID, 322 + .s0ix_deep_occ_id = TELEM_APL_S0IX_DEEP_OCC_ID, 323 + .s0ix_total_res_id = TELEM_APL_S0IX_TOTAL_RES_ID, 324 + .s0ix_shlw_res_id = TELEM_APL_S0IX_SHLW_RES_ID, 325 + .s0ix_deep_res_id = TELEM_APL_S0IX_DEEP_RES_ID, 326 + .ioss_d0ix_id = TELEM_APL_D0IX_ID, 327 + .ioss_d3_id = TELEM_APL_D3_ID, 328 + .ioss_pg_id = TELEM_APL_PG_ID, 329 + }; 330 + 331 + static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = { 332 + TELEM_DEBUGFS_CPU(0x5c, telem_apl_debugfs_conf), 333 + {} 334 + }; 335 + 336 + MODULE_DEVICE_TABLE(x86cpu, telemetry_debugfs_cpu_ids); 337 + 338 + static int telemetry_debugfs_check_evts(void) 339 + { 340 + if ((debugfs_conf->pss_idle_evts > TELEM_PSS_IDLE_EVTS) || 341 + (debugfs_conf->pcs_idle_blkd_evts > TELEM_PSS_IDLE_BLOCKED_EVTS) || 342 + (debugfs_conf->pcs_s0ix_blkd_evts > TELEM_PSS_S0IX_BLOCKED_EVTS) || 343 + (debugfs_conf->pss_ltr_evts > TELEM_PSS_LTR_BLOCKING_EVTS) || 344 + (debugfs_conf->pss_wakeup_evts > TELEM_PSS_S0IX_WAKEUP_EVTS) || 345 + (debugfs_conf->ioss_d0ix_evts > TELEM_IOSS_DX_D0IX_EVTS) || 346 + (debugfs_conf->ioss_pg_evts > TELEM_IOSS_PG_EVTS)) 347 + return -EINVAL; 348 + 349 + return 0; 350 + } 351 + 352 + static int telem_pss_states_show(struct seq_file *s, void *unused) 353 + { 354 + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; 355 + struct telemetry_debugfs_conf *conf = debugfs_conf; 356 + const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS]; 357 + u32 pcs_idle_blkd[TELEM_PSS_IDLE_BLOCKED_EVTS], 358 + pcs_s0ix_blkd[TELEM_PSS_S0IX_BLOCKED_EVTS], 359 + pss_s0ix_wakeup[TELEM_PSS_S0IX_WAKEUP_EVTS], 360 + pss_ltr_blkd[TELEM_PSS_LTR_BLOCKING_EVTS], 361 + pss_idle[TELEM_PSS_IDLE_EVTS]; 362 + int index, idx, ret, err = 0; 363 + u64 pstates = 0; 364 + 365 + ret = telemetry_read_eventlog(TELEM_PSS, evtlog, 366 + TELEM_MAX_OS_ALLOCATED_EVENTS); 367 + if (ret < 0) 368 + return ret; 369 + 370 + err = telemetry_get_evtname(TELEM_PSS, name, 371 + TELEM_MAX_OS_ALLOCATED_EVENTS); 372 + if (err < 0) 373 + return err; 374 + 375 + seq_puts(s, "\n----------------------------------------------------\n"); 376 + seq_puts(s, "\tPSS TELEM EVENTLOG (Residency = field/19.2 us\n"); 377 + seq_puts(s, "----------------------------------------------------\n"); 378 + for (index = 0; index < ret; index++) { 379 + seq_printf(s, "%-32s %llu\n", 380 + name[index], evtlog[index].telem_evtlog); 381 + 382 + /* Fetch PSS IDLE State */ 383 + if (evtlog[index].telem_evtid == conf->pss_idle_id) { 384 + pss_idle[conf->pss_idle_evts - 1] = 385 + (evtlog[index].telem_evtlog >> 386 + conf->pss_idle_data[conf->pss_idle_evts - 1].bit_pos) & 387 + TELEM_APL_MASK_PCS_STATE; 388 + } 389 + 390 + 391 + TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id, 392 + conf->pss_idle_evts - 1, 393 + pss_idle, evtlog[index].telem_evtlog, 394 + conf->pss_idle_data, TELEM_MASK_BIT); 395 + 396 + TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_idle_blkd_id, 397 + conf->pcs_idle_blkd_evts, 398 + pcs_idle_blkd, 399 + evtlog[index].telem_evtlog, 400 + conf->pcs_idle_blkd_data, 401 + TELEM_MASK_BYTE); 402 + 403 + TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_s0ix_blkd_id, 404 + conf->pcs_s0ix_blkd_evts, 405 + pcs_s0ix_blkd, 406 + evtlog[index].telem_evtlog, 407 + conf->pcs_s0ix_blkd_data, 408 + TELEM_MASK_BYTE); 409 + 410 + 411 + TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id, 412 + conf->pss_wakeup_evts, 413 + pss_s0ix_wakeup, 414 + evtlog[index].telem_evtlog, 415 + conf->pss_wakeup, TELEM_MASK_BYTE); 416 + 417 + TELEM_CHECK_AND_PARSE_EVTS(conf->pss_ltr_blocking_id, 418 + conf->pss_ltr_evts, pss_ltr_blkd, 419 + evtlog[index].telem_evtlog, 420 + conf->pss_ltr_data, TELEM_MASK_BYTE); 421 + 422 + if (evtlog[index].telem_evtid == debugfs_conf->pstates_id) 423 + pstates = evtlog[index].telem_evtlog; 424 + } 425 + 426 + seq_puts(s, "\n--------------------------------------\n"); 427 + seq_puts(s, "PStates\n"); 428 + seq_puts(s, "--------------------------------------\n"); 429 + seq_puts(s, "Domain\t\t\t\tFreq(Mhz)\n"); 430 + seq_printf(s, " IA\t\t\t\t %llu\n GT\t\t\t\t %llu\n", 431 + (pstates & TELEM_MASK_BYTE)*100, 432 + ((pstates >> 8) & TELEM_MASK_BYTE)*50/3); 433 + 434 + seq_printf(s, " IUNIT\t\t\t\t %llu\n SA\t\t\t\t %llu\n", 435 + ((pstates >> 16) & TELEM_MASK_BYTE)*25, 436 + ((pstates >> 24) & TELEM_MASK_BYTE)*50/3); 437 + 438 + seq_puts(s, "\n--------------------------------------\n"); 439 + seq_puts(s, "PSS IDLE Status\n"); 440 + seq_puts(s, "--------------------------------------\n"); 441 + seq_puts(s, "Device\t\t\t\t\tIDLE\n"); 442 + for (index = 0; index < debugfs_conf->pss_idle_evts; index++) { 443 + seq_printf(s, "%-32s\t%u\n", 444 + debugfs_conf->pss_idle_data[index].name, 445 + pss_idle[index]); 446 + } 447 + 448 + seq_puts(s, "\n--------------------------------------\n"); 449 + seq_puts(s, "PSS Idle blkd Status (~1ms saturating bucket)\n"); 450 + seq_puts(s, "--------------------------------------\n"); 451 + seq_puts(s, "Blocker\t\t\t\t\tCount\n"); 452 + for (index = 0; index < debugfs_conf->pcs_idle_blkd_evts; index++) { 453 + seq_printf(s, "%-32s\t%u\n", 454 + debugfs_conf->pcs_idle_blkd_data[index].name, 455 + pcs_idle_blkd[index]); 456 + } 457 + 458 + seq_puts(s, "\n--------------------------------------\n"); 459 + seq_puts(s, "PSS S0ix blkd Status (~1ms saturating bucket)\n"); 460 + seq_puts(s, "--------------------------------------\n"); 461 + seq_puts(s, "Blocker\t\t\t\t\tCount\n"); 462 + for (index = 0; index < debugfs_conf->pcs_s0ix_blkd_evts; index++) { 463 + seq_printf(s, "%-32s\t%u\n", 464 + debugfs_conf->pcs_s0ix_blkd_data[index].name, 465 + pcs_s0ix_blkd[index]); 466 + } 467 + 468 + seq_puts(s, "\n--------------------------------------\n"); 469 + seq_puts(s, "LTR Blocking Status (~1ms saturating bucket)\n"); 470 + seq_puts(s, "--------------------------------------\n"); 471 + seq_puts(s, "Blocker\t\t\t\t\tCount\n"); 472 + for (index = 0; index < debugfs_conf->pss_ltr_evts; index++) { 473 + seq_printf(s, "%-32s\t%u\n", 474 + debugfs_conf->pss_ltr_data[index].name, 475 + pss_s0ix_wakeup[index]); 476 + } 477 + 478 + seq_puts(s, "\n--------------------------------------\n"); 479 + seq_puts(s, "Wakes Status (~1ms saturating bucket)\n"); 480 + seq_puts(s, "--------------------------------------\n"); 481 + seq_puts(s, "Wakes\t\t\t\t\tCount\n"); 482 + for (index = 0; index < debugfs_conf->pss_wakeup_evts; index++) { 483 + seq_printf(s, "%-32s\t%u\n", 484 + debugfs_conf->pss_wakeup[index].name, 485 + pss_ltr_blkd[index]); 486 + } 487 + 488 + return 0; 489 + } 490 + 491 + static int telem_pss_state_open(struct inode *inode, struct file *file) 492 + { 493 + return single_open(file, telem_pss_states_show, inode->i_private); 494 + } 495 + 496 + static const struct file_operations telem_pss_ops = { 497 + .open = telem_pss_state_open, 498 + .read = seq_read, 499 + .llseek = seq_lseek, 500 + .release = single_release, 501 + }; 502 + 503 + 504 + static int telem_ioss_states_show(struct seq_file *s, void *unused) 505 + { 506 + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; 507 + const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS]; 508 + int index, ret, err; 509 + 510 + ret = telemetry_read_eventlog(TELEM_IOSS, evtlog, 511 + TELEM_MAX_OS_ALLOCATED_EVENTS); 512 + if (ret < 0) 513 + return ret; 514 + 515 + err = telemetry_get_evtname(TELEM_IOSS, name, 516 + TELEM_MAX_OS_ALLOCATED_EVENTS); 517 + if (err < 0) 518 + return err; 519 + 520 + seq_puts(s, "--------------------------------------\n"); 521 + seq_puts(s, "\tI0SS TELEMETRY EVENTLOG\n"); 522 + seq_puts(s, "--------------------------------------\n"); 523 + for (index = 0; index < ret; index++) { 524 + seq_printf(s, "%-32s 0x%llx\n", 525 + name[index], evtlog[index].telem_evtlog); 526 + } 527 + 528 + return 0; 529 + } 530 + 531 + static int telem_ioss_state_open(struct inode *inode, struct file *file) 532 + { 533 + return single_open(file, telem_ioss_states_show, inode->i_private); 534 + } 535 + 536 + static const struct file_operations telem_ioss_ops = { 537 + .open = telem_ioss_state_open, 538 + .read = seq_read, 539 + .llseek = seq_lseek, 540 + .release = single_release, 541 + }; 542 + 543 + static int telem_soc_states_show(struct seq_file *s, void *unused) 544 + { 545 + u32 d3_sts[TELEM_IOSS_DX_D0IX_EVTS], d0ix_sts[TELEM_IOSS_DX_D0IX_EVTS]; 546 + u32 pg_sts[TELEM_IOSS_PG_EVTS], pss_idle[TELEM_PSS_IDLE_EVTS]; 547 + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; 548 + u32 s0ix_total_ctr = 0, s0ix_shlw_ctr = 0, s0ix_deep_ctr = 0; 549 + u64 s0ix_total_res = 0, s0ix_shlw_res = 0, s0ix_deep_res = 0; 550 + struct telemetry_debugfs_conf *conf = debugfs_conf; 551 + struct pci_dev *dev = NULL; 552 + int index, idx, ret; 553 + u32 d3_state; 554 + u16 pmcsr; 555 + 556 + ret = telemetry_read_eventlog(TELEM_IOSS, evtlog, 557 + TELEM_MAX_OS_ALLOCATED_EVENTS); 558 + if (ret < 0) 559 + return ret; 560 + 561 + for (index = 0; index < ret; index++) { 562 + TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d3_id, 563 + conf->ioss_d0ix_evts, 564 + d3_sts, evtlog[index].telem_evtlog, 565 + conf->ioss_d0ix_data, 566 + TELEM_MASK_BIT); 567 + 568 + TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_pg_id, conf->ioss_pg_evts, 569 + pg_sts, evtlog[index].telem_evtlog, 570 + conf->ioss_pg_data, TELEM_MASK_BIT); 571 + 572 + TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d0ix_id, 573 + conf->ioss_d0ix_evts, 574 + d0ix_sts, evtlog[index].telem_evtlog, 575 + conf->ioss_d0ix_data, 576 + TELEM_MASK_BIT); 577 + 578 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_occ_id, 579 + s0ix_total_ctr); 580 + 581 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, 582 + s0ix_shlw_ctr); 583 + 584 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, 585 + s0ix_deep_ctr); 586 + 587 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_res_id, 588 + s0ix_total_res); 589 + 590 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, 591 + s0ix_shlw_res); 592 + 593 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, 594 + s0ix_deep_res); 595 + } 596 + 597 + seq_puts(s, "\n---------------------------------------------------\n"); 598 + seq_puts(s, "S0IX Type\t\t\t Occurrence\t\t Residency(us)\n"); 599 + seq_puts(s, "---------------------------------------------------\n"); 600 + 601 + seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n", 602 + s0ix_shlw_ctr - 603 + conf->suspend_stats.shlw_ctr - 604 + conf->suspend_stats.shlw_swake_ctr, 605 + (u64)((s0ix_shlw_res - 606 + conf->suspend_stats.shlw_res - 607 + conf->suspend_stats.shlw_swake_res)*10/192)); 608 + 609 + seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n", 610 + s0ix_deep_ctr - 611 + conf->suspend_stats.deep_ctr - 612 + conf->suspend_stats.deep_swake_ctr, 613 + (u64)((s0ix_deep_res - 614 + conf->suspend_stats.deep_res - 615 + conf->suspend_stats.deep_swake_res)*10/192)); 616 + 617 + seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n", 618 + conf->suspend_stats.shlw_ctr, 619 + (u64)(conf->suspend_stats.shlw_res*10)/192); 620 + 621 + seq_printf(s, "Suspend(With S0ixDeep)\t\t %10u\t %10llu\n", 622 + conf->suspend_stats.deep_ctr, 623 + (u64)(conf->suspend_stats.deep_res*10)/192); 624 + 625 + seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n", 626 + conf->suspend_stats.shlw_swake_ctr + 627 + conf->suspend_stats.deep_swake_ctr, 628 + (u64)((conf->suspend_stats.shlw_swake_res + 629 + conf->suspend_stats.deep_swake_res)*10/192)); 630 + 631 + seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr, 632 + (u64)(s0ix_total_res*10/192)); 633 + seq_puts(s, "\n-------------------------------------------------\n"); 634 + seq_puts(s, "\t\tDEVICE STATES\n"); 635 + seq_puts(s, "-------------------------------------------------\n"); 636 + 637 + for_each_pci_dev(dev) { 638 + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); 639 + d3_state = ((pmcsr & PCI_PM_CTRL_STATE_MASK) == 640 + (__force int)PCI_D3hot) ? 1 : 0; 641 + 642 + seq_printf(s, "pci %04x %04X %s %20.20s: ", 643 + dev->vendor, dev->device, dev_name(&dev->dev), 644 + dev_driver_string(&dev->dev)); 645 + seq_printf(s, " d3:%x\n", d3_state); 646 + } 647 + 648 + seq_puts(s, "\n--------------------------------------\n"); 649 + seq_puts(s, "D3/D0i3 Status\n"); 650 + seq_puts(s, "--------------------------------------\n"); 651 + seq_puts(s, "Block\t\t D3\t D0i3\n"); 652 + for (index = 0; index < conf->ioss_d0ix_evts; index++) { 653 + seq_printf(s, "%-10s\t %u\t %u\n", 654 + conf->ioss_d0ix_data[index].name, 655 + d3_sts[index], d0ix_sts[index]); 656 + } 657 + 658 + seq_puts(s, "\n--------------------------------------\n"); 659 + seq_puts(s, "South Complex PowerGate Status\n"); 660 + seq_puts(s, "--------------------------------------\n"); 661 + seq_puts(s, "Device\t\t PG\n"); 662 + for (index = 0; index < conf->ioss_pg_evts; index++) { 663 + seq_printf(s, "%-10s\t %u\n", 664 + conf->ioss_pg_data[index].name, 665 + pg_sts[index]); 666 + } 667 + 668 + evtlog->telem_evtid = conf->pss_idle_id; 669 + ret = telemetry_read_events(TELEM_PSS, evtlog, 1); 670 + if (ret < 0) 671 + return ret; 672 + 673 + seq_puts(s, "\n-----------------------------------------\n"); 674 + seq_puts(s, "North Idle Status\n"); 675 + seq_puts(s, "-----------------------------------------\n"); 676 + for (idx = 0; idx < conf->pss_idle_evts - 1; idx++) { 677 + pss_idle[idx] = (evtlog->telem_evtlog >> 678 + conf->pss_idle_data[idx].bit_pos) & 679 + TELEM_MASK_BIT; 680 + } 681 + 682 + pss_idle[idx] = (evtlog->telem_evtlog >> 683 + conf->pss_idle_data[idx].bit_pos) & 684 + TELEM_APL_MASK_PCS_STATE; 685 + 686 + for (index = 0; index < conf->pss_idle_evts; index++) { 687 + seq_printf(s, "%-30s %u\n", 688 + conf->pss_idle_data[index].name, 689 + pss_idle[index]); 690 + } 691 + 692 + seq_puts(s, "\nPCS_STATUS Code\n"); 693 + seq_puts(s, "0:C0 1:C1 2:C1_DN_WT_DEV 3:C2 4:C2_WT_DE_MEM_UP\n"); 694 + seq_puts(s, "5:C2_WT_DE_MEM_DOWN 6:C2_UP_WT_DEV 7:C2_DN 8:C2_VOA\n"); 695 + seq_puts(s, "9:C2_VOA_UP 10:S0IX_PRE 11:S0IX\n"); 696 + 697 + return 0; 698 + } 699 + 700 + static int telem_soc_state_open(struct inode *inode, struct file *file) 701 + { 702 + return single_open(file, telem_soc_states_show, inode->i_private); 703 + } 704 + 705 + static const struct file_operations telem_socstate_ops = { 706 + .open = telem_soc_state_open, 707 + .read = seq_read, 708 + .llseek = seq_lseek, 709 + .release = single_release, 710 + }; 711 + 712 + static int telem_pss_trc_verb_show(struct seq_file *s, void *unused) 713 + { 714 + u32 verbosity; 715 + int err; 716 + 717 + err = telemetry_get_trace_verbosity(TELEM_PSS, &verbosity); 718 + if (err) { 719 + pr_err("Get PSS Trace Verbosity Failed with Error %d\n", err); 720 + return -EFAULT; 721 + } 722 + 723 + seq_printf(s, "PSS Trace Verbosity %u\n", verbosity); 724 + return 0; 725 + } 726 + 727 + static ssize_t telem_pss_trc_verb_write(struct file *file, 728 + const char __user *userbuf, 729 + size_t count, loff_t *ppos) 730 + { 731 + u32 verbosity; 732 + int err; 733 + 734 + if (kstrtou32_from_user(userbuf, count, 0, &verbosity)) 735 + return -EFAULT; 736 + 737 + err = telemetry_set_trace_verbosity(TELEM_PSS, verbosity); 738 + if (err) { 739 + pr_err("Changing PSS Trace Verbosity Failed. Error %d\n", err); 740 + count = err; 741 + } 742 + 743 + return count; 744 + } 745 + 746 + static int telem_pss_trc_verb_open(struct inode *inode, struct file *file) 747 + { 748 + return single_open(file, telem_pss_trc_verb_show, inode->i_private); 749 + } 750 + 751 + static const struct file_operations telem_pss_trc_verb_ops = { 752 + .open = telem_pss_trc_verb_open, 753 + .read = seq_read, 754 + .write = telem_pss_trc_verb_write, 755 + .llseek = seq_lseek, 756 + .release = single_release, 757 + }; 758 + 759 + 760 + static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused) 761 + { 762 + u32 verbosity; 763 + int err; 764 + 765 + err = telemetry_get_trace_verbosity(TELEM_IOSS, &verbosity); 766 + if (err) { 767 + pr_err("Get IOSS Trace Verbosity Failed with Error %d\n", err); 768 + return -EFAULT; 769 + } 770 + 771 + seq_printf(s, "IOSS Trace Verbosity %u\n", verbosity); 772 + return 0; 773 + } 774 + 775 + static ssize_t telem_ioss_trc_verb_write(struct file *file, 776 + const char __user *userbuf, 777 + size_t count, loff_t *ppos) 778 + { 779 + u32 verbosity; 780 + int err; 781 + 782 + if (kstrtou32_from_user(userbuf, count, 0, &verbosity)) 783 + return -EFAULT; 784 + 785 + err = telemetry_set_trace_verbosity(TELEM_IOSS, verbosity); 786 + if (err) { 787 + pr_err("Changing IOSS Trace Verbosity Failed. Error %d\n", err); 788 + count = err; 789 + } 790 + 791 + return count; 792 + } 793 + 794 + static int telem_ioss_trc_verb_open(struct inode *inode, struct file *file) 795 + { 796 + return single_open(file, telem_ioss_trc_verb_show, inode->i_private); 797 + } 798 + 799 + static const struct file_operations telem_ioss_trc_verb_ops = { 800 + .open = telem_ioss_trc_verb_open, 801 + .read = seq_read, 802 + .write = telem_ioss_trc_verb_write, 803 + .llseek = seq_lseek, 804 + .release = single_release, 805 + }; 806 + 807 + #ifdef CONFIG_PM_SLEEP 808 + static int pm_suspend_prep_cb(void) 809 + { 810 + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; 811 + struct telemetry_debugfs_conf *conf = debugfs_conf; 812 + int ret, index; 813 + 814 + ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog, 815 + TELEM_MAX_OS_ALLOCATED_EVENTS); 816 + if (ret < 0) { 817 + suspend_prep_ok = 0; 818 + goto out; 819 + } 820 + 821 + for (index = 0; index < ret; index++) { 822 + 823 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, 824 + suspend_shlw_ctr_temp); 825 + 826 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, 827 + suspend_deep_ctr_temp); 828 + 829 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, 830 + suspend_shlw_res_temp); 831 + 832 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, 833 + suspend_deep_res_temp); 834 + } 835 + suspend_prep_ok = 1; 836 + out: 837 + return NOTIFY_OK; 838 + } 839 + 840 + static int pm_suspend_exit_cb(void) 841 + { 842 + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; 843 + static u32 suspend_shlw_ctr_exit, suspend_deep_ctr_exit; 844 + static u64 suspend_shlw_res_exit, suspend_deep_res_exit; 845 + struct telemetry_debugfs_conf *conf = debugfs_conf; 846 + int ret, index; 847 + 848 + if (!suspend_prep_ok) 849 + goto out; 850 + 851 + ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog, 852 + TELEM_MAX_OS_ALLOCATED_EVENTS); 853 + if (ret < 0) 854 + goto out; 855 + 856 + for (index = 0; index < ret; index++) { 857 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, 858 + suspend_shlw_ctr_exit); 859 + 860 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, 861 + suspend_deep_ctr_exit); 862 + 863 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, 864 + suspend_shlw_res_exit); 865 + 866 + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, 867 + suspend_deep_res_exit); 868 + } 869 + 870 + if ((suspend_shlw_ctr_exit < suspend_shlw_ctr_temp) || 871 + (suspend_deep_ctr_exit < suspend_deep_ctr_temp) || 872 + (suspend_shlw_res_exit < suspend_shlw_res_temp) || 873 + (suspend_deep_res_exit < suspend_deep_res_temp)) { 874 + pr_err("Wrong s0ix counters detected\n"); 875 + goto out; 876 + } 877 + 878 + suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp; 879 + suspend_deep_ctr_exit -= suspend_deep_ctr_temp; 880 + suspend_shlw_res_exit -= suspend_shlw_res_temp; 881 + suspend_deep_res_exit -= suspend_deep_res_temp; 882 + 883 + if (suspend_shlw_ctr_exit == 1) { 884 + conf->suspend_stats.shlw_ctr += 885 + suspend_shlw_ctr_exit; 886 + 887 + conf->suspend_stats.shlw_res += 888 + suspend_shlw_res_exit; 889 + } 890 + /* Shallow Wakes Case */ 891 + else if (suspend_shlw_ctr_exit > 1) { 892 + conf->suspend_stats.shlw_swake_ctr += 893 + suspend_shlw_ctr_exit; 894 + 895 + conf->suspend_stats.shlw_swake_res += 896 + suspend_shlw_res_exit; 897 + } 898 + 899 + if (suspend_deep_ctr_exit == 1) { 900 + conf->suspend_stats.deep_ctr += 901 + suspend_deep_ctr_exit; 902 + 903 + conf->suspend_stats.deep_res += 904 + suspend_deep_res_exit; 905 + } 906 + 907 + /* Shallow Wakes Case */ 908 + else if (suspend_deep_ctr_exit > 1) { 909 + conf->suspend_stats.deep_swake_ctr += 910 + suspend_deep_ctr_exit; 911 + 912 + conf->suspend_stats.deep_swake_res += 913 + suspend_deep_res_exit; 914 + } 915 + 916 + out: 917 + suspend_prep_ok = 0; 918 + return NOTIFY_OK; 919 + } 920 + 921 + static int pm_notification(struct notifier_block *this, 922 + unsigned long event, void *ptr) 923 + { 924 + switch (event) { 925 + case PM_SUSPEND_PREPARE: 926 + return pm_suspend_prep_cb(); 927 + case PM_POST_SUSPEND: 928 + return pm_suspend_exit_cb(); 929 + } 930 + 931 + return NOTIFY_DONE; 932 + } 933 + 934 + static struct notifier_block pm_notifier = { 935 + .notifier_call = pm_notification, 936 + }; 937 + #endif /* CONFIG_PM_SLEEP */ 938 + 939 + static int __init telemetry_debugfs_init(void) 940 + { 941 + const struct x86_cpu_id *id; 942 + int err = -ENOMEM; 943 + struct dentry *f; 944 + 945 + /* Only APL supported for now */ 946 + id = x86_match_cpu(telemetry_debugfs_cpu_ids); 947 + if (!id) 948 + return -ENODEV; 949 + 950 + debugfs_conf = (struct telemetry_debugfs_conf *)id->driver_data; 951 + 952 + err = telemetry_pltconfig_valid(); 953 + if (err < 0) 954 + return -ENODEV; 955 + 956 + err = telemetry_debugfs_check_evts(); 957 + if (err < 0) 958 + return -EINVAL; 959 + 960 + 961 + #ifdef CONFIG_PM_SLEEP 962 + register_pm_notifier(&pm_notifier); 963 + #endif /* CONFIG_PM_SLEEP */ 964 + 965 + debugfs_conf->telemetry_dbg_dir = debugfs_create_dir("telemetry", NULL); 966 + if (!debugfs_conf->telemetry_dbg_dir) 967 + return -ENOMEM; 968 + 969 + f = debugfs_create_file("pss_info", S_IFREG | S_IRUGO, 970 + debugfs_conf->telemetry_dbg_dir, NULL, 971 + &telem_pss_ops); 972 + if (!f) { 973 + pr_err("pss_sample_info debugfs register failed\n"); 974 + goto out; 975 + } 976 + 977 + f = debugfs_create_file("ioss_info", S_IFREG | S_IRUGO, 978 + debugfs_conf->telemetry_dbg_dir, NULL, 979 + &telem_ioss_ops); 980 + if (!f) { 981 + pr_err("ioss_sample_info debugfs register failed\n"); 982 + goto out; 983 + } 984 + 985 + f = debugfs_create_file("soc_states", S_IFREG | S_IRUGO, 986 + debugfs_conf->telemetry_dbg_dir, 987 + NULL, &telem_socstate_ops); 988 + if (!f) { 989 + pr_err("ioss_sample_info debugfs register failed\n"); 990 + goto out; 991 + } 992 + 993 + f = debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO, 994 + debugfs_conf->telemetry_dbg_dir, NULL, 995 + &telem_pss_trc_verb_ops); 996 + if (!f) { 997 + pr_err("pss_trace_verbosity debugfs register failed\n"); 998 + goto out; 999 + } 1000 + 1001 + f = debugfs_create_file("ioss_trace_verbosity", S_IFREG | S_IRUGO, 1002 + debugfs_conf->telemetry_dbg_dir, NULL, 1003 + &telem_ioss_trc_verb_ops); 1004 + if (!f) { 1005 + pr_err("ioss_trace_verbosity debugfs register failed\n"); 1006 + goto out; 1007 + } 1008 + 1009 + return 0; 1010 + 1011 + out: 1012 + debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir); 1013 + debugfs_conf->telemetry_dbg_dir = NULL; 1014 + 1015 + return err; 1016 + } 1017 + 1018 + static void __exit telemetry_debugfs_exit(void) 1019 + { 1020 + debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir); 1021 + debugfs_conf->telemetry_dbg_dir = NULL; 1022 + } 1023 + 1024 + late_initcall(telemetry_debugfs_init); 1025 + module_exit(telemetry_debugfs_exit); 1026 + 1027 + MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>"); 1028 + MODULE_DESCRIPTION("Intel SoC Telemetry debugfs Interface"); 1029 + MODULE_VERSION(DRIVER_VERSION); 1030 + MODULE_LICENSE("GPL");
+1206
drivers/platform/x86/intel_telemetry_pltdrv.c
··· 1 + /* 2 + * Intel SOC Telemetry Platform Driver: Currently supports APL 3 + * Copyright (c) 2015, Intel Corporation. 4 + * All Rights Reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + * This file provides the platform specific telemetry implementation for APL. 16 + * It used the PUNIT and PMC IPC interfaces for configuring the counters. 17 + * The accumulated results are fetched from SRAM. 18 + */ 19 + #include <linux/module.h> 20 + #include <linux/init.h> 21 + #include <linux/device.h> 22 + #include <linux/debugfs.h> 23 + #include <linux/seq_file.h> 24 + #include <linux/io.h> 25 + #include <linux/uaccess.h> 26 + #include <linux/pci.h> 27 + #include <linux/suspend.h> 28 + #include <linux/platform_device.h> 29 + 30 + #include <asm/cpu_device_id.h> 31 + #include <asm/intel_pmc_ipc.h> 32 + #include <asm/intel_punit_ipc.h> 33 + #include <asm/intel_telemetry.h> 34 + 35 + #define DRIVER_NAME "intel_telemetry" 36 + #define DRIVER_VERSION "1.0.0" 37 + 38 + #define TELEM_TRC_VERBOSITY_MASK 0x3 39 + 40 + #define TELEM_MIN_PERIOD(x) ((x) & 0x7F0000) 41 + #define TELEM_MAX_PERIOD(x) ((x) & 0x7F000000) 42 + #define TELEM_SAMPLE_PERIOD_INVALID(x) ((x) & (BIT(7))) 43 + #define TELEM_CLEAR_SAMPLE_PERIOD(x) ((x) &= ~0x7F) 44 + 45 + #define TELEM_SAMPLING_DEFAULT_PERIOD 0xD 46 + 47 + #define TELEM_MAX_EVENTS_SRAM 28 48 + #define TELEM_MAX_OS_ALLOCATED_EVENTS 20 49 + #define TELEM_SSRAM_STARTTIME_OFFSET 8 50 + #define TELEM_SSRAM_EVTLOG_OFFSET 16 51 + 52 + #define IOSS_TELEM_EVENT_READ 0x0 53 + #define IOSS_TELEM_EVENT_WRITE 0x1 54 + #define IOSS_TELEM_INFO_READ 0x2 55 + #define IOSS_TELEM_TRACE_CTL_READ 0x5 56 + #define IOSS_TELEM_TRACE_CTL_WRITE 0x6 57 + #define IOSS_TELEM_EVENT_CTL_READ 0x7 58 + #define IOSS_TELEM_EVENT_CTL_WRITE 0x8 59 + #define IOSS_TELEM_EVT_CTRL_WRITE_SIZE 0x4 60 + #define IOSS_TELEM_READ_WORD 0x1 61 + #define IOSS_TELEM_WRITE_FOURBYTES 0x4 62 + #define IOSS_TELEM_EVT_WRITE_SIZE 0x3 63 + 64 + #define TELEM_INFO_SRAMEVTS_MASK 0xFF00 65 + #define TELEM_INFO_SRAMEVTS_SHIFT 0x8 66 + #define TELEM_SSRAM_READ_TIMEOUT 10 67 + 68 + #define TELEM_INFO_NENABLES_MASK 0xFF 69 + #define TELEM_EVENT_ENABLE 0x8000 70 + 71 + #define TELEM_MASK_BIT 1 72 + #define TELEM_MASK_BYTE 0xFF 73 + #define BYTES_PER_LONG 8 74 + #define TELEM_MASK_PCS_STATE 0xF 75 + 76 + #define TELEM_DISABLE(x) ((x) &= ~(BIT(31))) 77 + #define TELEM_CLEAR_EVENTS(x) ((x) |= (BIT(30))) 78 + #define TELEM_ENABLE_SRAM_EVT_TRACE(x) ((x) &= ~(BIT(30) | BIT(24))) 79 + #define TELEM_ENABLE_PERIODIC(x) ((x) |= (BIT(23) | BIT(31) | BIT(7))) 80 + #define TELEM_EXTRACT_VERBOSITY(x, y) ((y) = (((x) >> 27) & 0x3)) 81 + #define TELEM_CLEAR_VERBOSITY_BITS(x) ((x) &= ~(BIT(27) | BIT(28))) 82 + #define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27)) 83 + 84 + #define TELEM_CPU(model, data) \ 85 + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data } 86 + 87 + enum telemetry_action { 88 + TELEM_UPDATE = 0, 89 + TELEM_ADD, 90 + TELEM_RESET, 91 + TELEM_ACTION_NONE 92 + }; 93 + 94 + struct telem_ssram_region { 95 + u64 timestamp; 96 + u64 start_time; 97 + u64 events[TELEM_MAX_EVENTS_SRAM]; 98 + }; 99 + 100 + static struct telemetry_plt_config *telm_conf; 101 + 102 + /* 103 + * The following counters are programmed by default during setup. 104 + * Only 20 allocated to kernel driver 105 + */ 106 + static struct telemetry_evtmap 107 + telemetry_apl_ioss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { 108 + {"SOC_S0IX_TOTAL_RES", 0x4800}, 109 + {"SOC_S0IX_TOTAL_OCC", 0x4000}, 110 + {"SOC_S0IX_SHALLOW_RES", 0x4801}, 111 + {"SOC_S0IX_SHALLOW_OCC", 0x4001}, 112 + {"SOC_S0IX_DEEP_RES", 0x4802}, 113 + {"SOC_S0IX_DEEP_OCC", 0x4002}, 114 + {"PMC_POWER_GATE", 0x5818}, 115 + {"PMC_D3_STATES", 0x5819}, 116 + {"PMC_D0I3_STATES", 0x581A}, 117 + {"PMC_S0IX_WAKE_REASON_GPIO", 0x6000}, 118 + {"PMC_S0IX_WAKE_REASON_TIMER", 0x6001}, 119 + {"PMC_S0IX_WAKE_REASON_VNNREQ", 0x6002}, 120 + {"PMC_S0IX_WAKE_REASON_LOWPOWER", 0x6003}, 121 + {"PMC_S0IX_WAKE_REASON_EXTERNAL", 0x6004}, 122 + {"PMC_S0IX_WAKE_REASON_MISC", 0x6005}, 123 + {"PMC_S0IX_BLOCKING_IPS_D3_D0I3", 0x6006}, 124 + {"PMC_S0IX_BLOCKING_IPS_PG", 0x6007}, 125 + {"PMC_S0IX_BLOCKING_MISC_IPS_PG", 0x6008}, 126 + {"PMC_S0IX_BLOCK_IPS_VNN_REQ", 0x6009}, 127 + {"PMC_S0IX_BLOCK_IPS_CLOCKS", 0x600B}, 128 + }; 129 + 130 + 131 + static struct telemetry_evtmap 132 + telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { 133 + {"IA_CORE0_C6_RES", 0x0400}, 134 + {"IA_CORE0_C6_CTR", 0x0000}, 135 + {"IA_MODULE0_C7_RES", 0x0410}, 136 + {"IA_MODULE0_C7_CTR", 0x000E}, 137 + {"IA_C0_RES", 0x0805}, 138 + {"PCS_LTR", 0x2801}, 139 + {"PSTATES", 0x2802}, 140 + {"SOC_S0I3_RES", 0x0409}, 141 + {"SOC_S0I3_CTR", 0x000A}, 142 + {"PCS_S0I3_CTR", 0x0009}, 143 + {"PCS_C1E_RES", 0x041A}, 144 + {"PCS_IDLE_STATUS", 0x2806}, 145 + {"IA_PERF_LIMITS", 0x280B}, 146 + {"GT_PERF_LIMITS", 0x280C}, 147 + {"PCS_WAKEUP_S0IX_CTR", 0x0030}, 148 + {"PCS_IDLE_BLOCKED", 0x2C00}, 149 + {"PCS_S0IX_BLOCKED", 0x2C01}, 150 + {"PCS_S0IX_WAKE_REASONS", 0x2C02}, 151 + {"PCS_LTR_BLOCKING", 0x2C03}, 152 + {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40}, 153 + }; 154 + 155 + /* APL specific Data */ 156 + static struct telemetry_plt_config telem_apl_config = { 157 + .pss_config = { 158 + .telem_evts = telemetry_apl_pss_default_events, 159 + }, 160 + .ioss_config = { 161 + .telem_evts = telemetry_apl_ioss_default_events, 162 + }, 163 + }; 164 + 165 + static const struct x86_cpu_id telemetry_cpu_ids[] = { 166 + TELEM_CPU(0x5c, telem_apl_config), 167 + {} 168 + }; 169 + 170 + MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids); 171 + 172 + static inline int telem_get_unitconfig(enum telemetry_unit telem_unit, 173 + struct telemetry_unit_config **unit_config) 174 + { 175 + if (telem_unit == TELEM_PSS) 176 + *unit_config = &(telm_conf->pss_config); 177 + else if (telem_unit == TELEM_IOSS) 178 + *unit_config = &(telm_conf->ioss_config); 179 + else 180 + return -EINVAL; 181 + 182 + return 0; 183 + 184 + } 185 + 186 + static int telemetry_check_evtid(enum telemetry_unit telem_unit, 187 + u32 *evtmap, u8 len, 188 + enum telemetry_action action) 189 + { 190 + struct telemetry_unit_config *unit_config; 191 + int ret; 192 + 193 + ret = telem_get_unitconfig(telem_unit, &unit_config); 194 + if (ret < 0) 195 + return ret; 196 + 197 + switch (action) { 198 + case TELEM_RESET: 199 + if (len > TELEM_MAX_EVENTS_SRAM) 200 + return -EINVAL; 201 + 202 + break; 203 + 204 + case TELEM_UPDATE: 205 + if (len > TELEM_MAX_EVENTS_SRAM) 206 + return -EINVAL; 207 + 208 + if ((len > 0) && (evtmap == NULL)) 209 + return -EINVAL; 210 + 211 + break; 212 + 213 + case TELEM_ADD: 214 + if ((len + unit_config->ssram_evts_used) > 215 + TELEM_MAX_EVENTS_SRAM) 216 + return -EINVAL; 217 + 218 + if ((len > 0) && (evtmap == NULL)) 219 + return -EINVAL; 220 + 221 + break; 222 + 223 + default: 224 + pr_err("Unknown Telemetry action Specified %d\n", action); 225 + return -EINVAL; 226 + } 227 + 228 + return 0; 229 + } 230 + 231 + 232 + static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index) 233 + { 234 + u32 write_buf; 235 + int ret; 236 + 237 + write_buf = evt_id | TELEM_EVENT_ENABLE; 238 + write_buf <<= BITS_PER_BYTE; 239 + write_buf |= index; 240 + 241 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 242 + IOSS_TELEM_EVENT_WRITE, (u8 *)&write_buf, 243 + IOSS_TELEM_EVT_WRITE_SIZE, NULL, 0); 244 + 245 + return ret; 246 + } 247 + 248 + static inline int telemetry_plt_config_pss_event(u32 evt_id, int index) 249 + { 250 + u32 write_buf; 251 + int ret; 252 + 253 + write_buf = evt_id | TELEM_EVENT_ENABLE; 254 + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT, 255 + index, 0, &write_buf, NULL); 256 + 257 + return ret; 258 + } 259 + 260 + static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig, 261 + enum telemetry_action action) 262 + { 263 + u8 num_ioss_evts, ioss_period; 264 + int ret, index, idx; 265 + u32 *ioss_evtmap; 266 + u32 telem_ctrl; 267 + 268 + num_ioss_evts = evtconfig.num_evts; 269 + ioss_period = evtconfig.period; 270 + ioss_evtmap = evtconfig.evtmap; 271 + 272 + /* Get telemetry EVENT CTL */ 273 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 274 + IOSS_TELEM_EVENT_CTL_READ, NULL, 0, 275 + &telem_ctrl, IOSS_TELEM_READ_WORD); 276 + if (ret) { 277 + pr_err("IOSS TELEM_CTRL Read Failed\n"); 278 + return ret; 279 + } 280 + 281 + /* Disable Telemetry */ 282 + TELEM_DISABLE(telem_ctrl); 283 + 284 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 285 + IOSS_TELEM_EVENT_CTL_WRITE, 286 + (u8 *)&telem_ctrl, 287 + IOSS_TELEM_EVT_CTRL_WRITE_SIZE, 288 + NULL, 0); 289 + if (ret) { 290 + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); 291 + return ret; 292 + } 293 + 294 + 295 + /* Reset Everything */ 296 + if (action == TELEM_RESET) { 297 + /* Clear All Events */ 298 + TELEM_CLEAR_EVENTS(telem_ctrl); 299 + 300 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 301 + IOSS_TELEM_EVENT_CTL_WRITE, 302 + (u8 *)&telem_ctrl, 303 + IOSS_TELEM_EVT_CTRL_WRITE_SIZE, 304 + NULL, 0); 305 + if (ret) { 306 + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); 307 + return ret; 308 + } 309 + telm_conf->ioss_config.ssram_evts_used = 0; 310 + 311 + /* Configure Events */ 312 + for (idx = 0; idx < num_ioss_evts; idx++) { 313 + if (telemetry_plt_config_ioss_event( 314 + telm_conf->ioss_config.telem_evts[idx].evt_id, 315 + idx)) { 316 + pr_err("IOSS TELEM_RESET Fail for data: %x\n", 317 + telm_conf->ioss_config.telem_evts[idx].evt_id); 318 + continue; 319 + } 320 + telm_conf->ioss_config.ssram_evts_used++; 321 + } 322 + } 323 + 324 + /* Re-Configure Everything */ 325 + if (action == TELEM_UPDATE) { 326 + /* Clear All Events */ 327 + TELEM_CLEAR_EVENTS(telem_ctrl); 328 + 329 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 330 + IOSS_TELEM_EVENT_CTL_WRITE, 331 + (u8 *)&telem_ctrl, 332 + IOSS_TELEM_EVT_CTRL_WRITE_SIZE, 333 + NULL, 0); 334 + if (ret) { 335 + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); 336 + return ret; 337 + } 338 + telm_conf->ioss_config.ssram_evts_used = 0; 339 + 340 + /* Configure Events */ 341 + for (index = 0; index < num_ioss_evts; index++) { 342 + telm_conf->ioss_config.telem_evts[index].evt_id = 343 + ioss_evtmap[index]; 344 + 345 + if (telemetry_plt_config_ioss_event( 346 + telm_conf->ioss_config.telem_evts[index].evt_id, 347 + index)) { 348 + pr_err("IOSS TELEM_UPDATE Fail for Evt%x\n", 349 + ioss_evtmap[index]); 350 + continue; 351 + } 352 + telm_conf->ioss_config.ssram_evts_used++; 353 + } 354 + } 355 + 356 + /* Add some Events */ 357 + if (action == TELEM_ADD) { 358 + /* Configure Events */ 359 + for (index = telm_conf->ioss_config.ssram_evts_used, idx = 0; 360 + idx < num_ioss_evts; index++, idx++) { 361 + telm_conf->ioss_config.telem_evts[index].evt_id = 362 + ioss_evtmap[idx]; 363 + 364 + if (telemetry_plt_config_ioss_event( 365 + telm_conf->ioss_config.telem_evts[index].evt_id, 366 + index)) { 367 + pr_err("IOSS TELEM_ADD Fail for Event %x\n", 368 + ioss_evtmap[idx]); 369 + continue; 370 + } 371 + telm_conf->ioss_config.ssram_evts_used++; 372 + } 373 + } 374 + 375 + /* Enable Periodic Telemetry Events and enable SRAM trace */ 376 + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); 377 + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); 378 + TELEM_ENABLE_PERIODIC(telem_ctrl); 379 + telem_ctrl |= ioss_period; 380 + 381 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 382 + IOSS_TELEM_EVENT_CTL_WRITE, 383 + (u8 *)&telem_ctrl, 384 + IOSS_TELEM_EVT_CTRL_WRITE_SIZE, NULL, 0); 385 + if (ret) { 386 + pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n"); 387 + return ret; 388 + } 389 + 390 + telm_conf->ioss_config.curr_period = ioss_period; 391 + 392 + return 0; 393 + } 394 + 395 + 396 + static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig, 397 + enum telemetry_action action) 398 + { 399 + u8 num_pss_evts, pss_period; 400 + int ret, index, idx; 401 + u32 *pss_evtmap; 402 + u32 telem_ctrl; 403 + 404 + num_pss_evts = evtconfig.num_evts; 405 + pss_period = evtconfig.period; 406 + pss_evtmap = evtconfig.evtmap; 407 + 408 + /* PSS Config */ 409 + /* Get telemetry EVENT CTL */ 410 + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL, 411 + 0, 0, NULL, &telem_ctrl); 412 + if (ret) { 413 + pr_err("PSS TELEM_CTRL Read Failed\n"); 414 + return ret; 415 + } 416 + 417 + /* Disable Telemetry */ 418 + TELEM_DISABLE(telem_ctrl); 419 + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 420 + 0, 0, &telem_ctrl, NULL); 421 + if (ret) { 422 + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); 423 + return ret; 424 + } 425 + 426 + /* Reset Everything */ 427 + if (action == TELEM_RESET) { 428 + /* Clear All Events */ 429 + TELEM_CLEAR_EVENTS(telem_ctrl); 430 + 431 + ret = intel_punit_ipc_command( 432 + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 433 + 0, 0, &telem_ctrl, NULL); 434 + if (ret) { 435 + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); 436 + return ret; 437 + } 438 + telm_conf->pss_config.ssram_evts_used = 0; 439 + /* Configure Events */ 440 + for (idx = 0; idx < num_pss_evts; idx++) { 441 + if (telemetry_plt_config_pss_event( 442 + telm_conf->pss_config.telem_evts[idx].evt_id, 443 + idx)) { 444 + pr_err("PSS TELEM_RESET Fail for Event %x\n", 445 + telm_conf->pss_config.telem_evts[idx].evt_id); 446 + continue; 447 + } 448 + telm_conf->pss_config.ssram_evts_used++; 449 + } 450 + } 451 + 452 + /* Re-Configure Everything */ 453 + if (action == TELEM_UPDATE) { 454 + /* Clear All Events */ 455 + TELEM_CLEAR_EVENTS(telem_ctrl); 456 + 457 + ret = intel_punit_ipc_command( 458 + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 459 + 0, 0, &telem_ctrl, NULL); 460 + if (ret) { 461 + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); 462 + return ret; 463 + } 464 + telm_conf->pss_config.ssram_evts_used = 0; 465 + 466 + /* Configure Events */ 467 + for (index = 0; index < num_pss_evts; index++) { 468 + telm_conf->pss_config.telem_evts[index].evt_id = 469 + pss_evtmap[index]; 470 + 471 + if (telemetry_plt_config_pss_event( 472 + telm_conf->pss_config.telem_evts[index].evt_id, 473 + index)) { 474 + pr_err("PSS TELEM_UPDATE Fail for Event %x\n", 475 + pss_evtmap[index]); 476 + continue; 477 + } 478 + telm_conf->pss_config.ssram_evts_used++; 479 + } 480 + } 481 + 482 + /* Add some Events */ 483 + if (action == TELEM_ADD) { 484 + /* Configure Events */ 485 + for (index = telm_conf->pss_config.ssram_evts_used, idx = 0; 486 + idx < num_pss_evts; index++, idx++) { 487 + 488 + telm_conf->pss_config.telem_evts[index].evt_id = 489 + pss_evtmap[idx]; 490 + 491 + if (telemetry_plt_config_pss_event( 492 + telm_conf->pss_config.telem_evts[index].evt_id, 493 + index)) { 494 + pr_err("PSS TELEM_ADD Fail for Event %x\n", 495 + pss_evtmap[idx]); 496 + continue; 497 + } 498 + telm_conf->pss_config.ssram_evts_used++; 499 + } 500 + } 501 + 502 + /* Enable Periodic Telemetry Events and enable SRAM trace */ 503 + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); 504 + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); 505 + TELEM_ENABLE_PERIODIC(telem_ctrl); 506 + telem_ctrl |= pss_period; 507 + 508 + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 509 + 0, 0, &telem_ctrl, NULL); 510 + if (ret) { 511 + pr_err("PSS TELEM_CTRL Event Enable Write Failed\n"); 512 + return ret; 513 + } 514 + 515 + telm_conf->pss_config.curr_period = pss_period; 516 + 517 + return 0; 518 + } 519 + 520 + static int telemetry_setup_evtconfig(struct telemetry_evtconfig pss_evtconfig, 521 + struct telemetry_evtconfig ioss_evtconfig, 522 + enum telemetry_action action) 523 + { 524 + int ret; 525 + 526 + mutex_lock(&(telm_conf->telem_lock)); 527 + 528 + if ((action == TELEM_UPDATE) && (telm_conf->telem_in_use)) { 529 + ret = -EBUSY; 530 + goto out; 531 + } 532 + 533 + ret = telemetry_check_evtid(TELEM_PSS, pss_evtconfig.evtmap, 534 + pss_evtconfig.num_evts, action); 535 + if (ret) 536 + goto out; 537 + 538 + ret = telemetry_check_evtid(TELEM_IOSS, ioss_evtconfig.evtmap, 539 + ioss_evtconfig.num_evts, action); 540 + if (ret) 541 + goto out; 542 + 543 + if (ioss_evtconfig.num_evts) { 544 + ret = telemetry_setup_iossevtconfig(ioss_evtconfig, action); 545 + if (ret) 546 + goto out; 547 + } 548 + 549 + if (pss_evtconfig.num_evts) { 550 + ret = telemetry_setup_pssevtconfig(pss_evtconfig, action); 551 + if (ret) 552 + goto out; 553 + } 554 + 555 + if ((action == TELEM_UPDATE) || (action == TELEM_ADD)) 556 + telm_conf->telem_in_use = true; 557 + else 558 + telm_conf->telem_in_use = false; 559 + 560 + out: 561 + mutex_unlock(&(telm_conf->telem_lock)); 562 + return ret; 563 + } 564 + 565 + static int telemetry_setup(struct platform_device *pdev) 566 + { 567 + struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; 568 + u32 read_buf, events, event_regs; 569 + int ret; 570 + 571 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, IOSS_TELEM_INFO_READ, 572 + NULL, 0, &read_buf, IOSS_TELEM_READ_WORD); 573 + if (ret) { 574 + dev_err(&pdev->dev, "IOSS TELEM_INFO Read Failed\n"); 575 + return ret; 576 + } 577 + 578 + /* Get telemetry Info */ 579 + events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >> 580 + TELEM_INFO_SRAMEVTS_SHIFT; 581 + event_regs = read_buf & TELEM_INFO_NENABLES_MASK; 582 + if ((events < TELEM_MAX_EVENTS_SRAM) || 583 + (event_regs < TELEM_MAX_EVENTS_SRAM)) { 584 + dev_err(&pdev->dev, "IOSS:Insufficient Space for SRAM Trace\n"); 585 + dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n", 586 + events, event_regs); 587 + return -ENOMEM; 588 + } 589 + 590 + telm_conf->ioss_config.min_period = TELEM_MIN_PERIOD(read_buf); 591 + telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf); 592 + 593 + /* PUNIT Mailbox Setup */ 594 + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0, 595 + NULL, &read_buf); 596 + if (ret) { 597 + dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n"); 598 + return ret; 599 + } 600 + 601 + /* Get telemetry Info */ 602 + events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >> 603 + TELEM_INFO_SRAMEVTS_SHIFT; 604 + event_regs = read_buf & TELEM_INFO_SRAMEVTS_MASK; 605 + if ((events < TELEM_MAX_EVENTS_SRAM) || 606 + (event_regs < TELEM_MAX_EVENTS_SRAM)) { 607 + dev_err(&pdev->dev, "PSS:Insufficient Space for SRAM Trace\n"); 608 + dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n", 609 + events, event_regs); 610 + return -ENOMEM; 611 + } 612 + 613 + telm_conf->pss_config.min_period = TELEM_MIN_PERIOD(read_buf); 614 + telm_conf->pss_config.max_period = TELEM_MAX_PERIOD(read_buf); 615 + 616 + pss_evtconfig.evtmap = NULL; 617 + pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; 618 + pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; 619 + 620 + ioss_evtconfig.evtmap = NULL; 621 + ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; 622 + ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; 623 + 624 + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 625 + TELEM_RESET); 626 + if (ret) { 627 + dev_err(&pdev->dev, "TELEMTRY Setup Failed\n"); 628 + return ret; 629 + } 630 + return 0; 631 + } 632 + 633 + static int telemetry_plt_update_events(struct telemetry_evtconfig pss_evtconfig, 634 + struct telemetry_evtconfig ioss_evtconfig) 635 + { 636 + int ret; 637 + 638 + if ((pss_evtconfig.num_evts > 0) && 639 + (TELEM_SAMPLE_PERIOD_INVALID(pss_evtconfig.period))) { 640 + pr_err("PSS Sampling Period Out of Range\n"); 641 + return -EINVAL; 642 + } 643 + 644 + if ((ioss_evtconfig.num_evts > 0) && 645 + (TELEM_SAMPLE_PERIOD_INVALID(ioss_evtconfig.period))) { 646 + pr_err("IOSS Sampling Period Out of Range\n"); 647 + return -EINVAL; 648 + } 649 + 650 + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 651 + TELEM_UPDATE); 652 + if (ret) 653 + pr_err("TELEMTRY Config Failed\n"); 654 + 655 + return ret; 656 + } 657 + 658 + 659 + static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period) 660 + { 661 + u32 telem_ctrl = 0; 662 + int ret; 663 + 664 + mutex_lock(&(telm_conf->telem_lock)); 665 + if (ioss_period) { 666 + if (TELEM_SAMPLE_PERIOD_INVALID(ioss_period)) { 667 + pr_err("IOSS Sampling Period Out of Range\n"); 668 + ret = -EINVAL; 669 + goto out; 670 + } 671 + 672 + /* Get telemetry EVENT CTL */ 673 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 674 + IOSS_TELEM_EVENT_CTL_READ, NULL, 0, 675 + &telem_ctrl, IOSS_TELEM_READ_WORD); 676 + if (ret) { 677 + pr_err("IOSS TELEM_CTRL Read Failed\n"); 678 + goto out; 679 + } 680 + 681 + /* Disable Telemetry */ 682 + TELEM_DISABLE(telem_ctrl); 683 + 684 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 685 + IOSS_TELEM_EVENT_CTL_WRITE, 686 + (u8 *)&telem_ctrl, 687 + IOSS_TELEM_EVT_CTRL_WRITE_SIZE, 688 + NULL, 0); 689 + if (ret) { 690 + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); 691 + goto out; 692 + } 693 + 694 + /* Enable Periodic Telemetry Events and enable SRAM trace */ 695 + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); 696 + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); 697 + TELEM_ENABLE_PERIODIC(telem_ctrl); 698 + telem_ctrl |= ioss_period; 699 + 700 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 701 + IOSS_TELEM_EVENT_CTL_WRITE, 702 + (u8 *)&telem_ctrl, 703 + IOSS_TELEM_EVT_CTRL_WRITE_SIZE, 704 + NULL, 0); 705 + if (ret) { 706 + pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n"); 707 + goto out; 708 + } 709 + telm_conf->ioss_config.curr_period = ioss_period; 710 + } 711 + 712 + if (pss_period) { 713 + if (TELEM_SAMPLE_PERIOD_INVALID(pss_period)) { 714 + pr_err("PSS Sampling Period Out of Range\n"); 715 + ret = -EINVAL; 716 + goto out; 717 + } 718 + 719 + /* Get telemetry EVENT CTL */ 720 + ret = intel_punit_ipc_command( 721 + IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL, 722 + 0, 0, NULL, &telem_ctrl); 723 + if (ret) { 724 + pr_err("PSS TELEM_CTRL Read Failed\n"); 725 + goto out; 726 + } 727 + 728 + /* Disable Telemetry */ 729 + TELEM_DISABLE(telem_ctrl); 730 + ret = intel_punit_ipc_command( 731 + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 732 + 0, 0, &telem_ctrl, NULL); 733 + if (ret) { 734 + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); 735 + goto out; 736 + } 737 + 738 + /* Enable Periodic Telemetry Events and enable SRAM trace */ 739 + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); 740 + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); 741 + TELEM_ENABLE_PERIODIC(telem_ctrl); 742 + telem_ctrl |= pss_period; 743 + 744 + ret = intel_punit_ipc_command( 745 + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 746 + 0, 0, &telem_ctrl, NULL); 747 + if (ret) { 748 + pr_err("PSS TELEM_CTRL Event Enable Write Failed\n"); 749 + goto out; 750 + } 751 + telm_conf->pss_config.curr_period = pss_period; 752 + } 753 + 754 + out: 755 + mutex_unlock(&(telm_conf->telem_lock)); 756 + return ret; 757 + } 758 + 759 + 760 + static int telemetry_plt_get_sampling_period(u8 *pss_min_period, 761 + u8 *pss_max_period, 762 + u8 *ioss_min_period, 763 + u8 *ioss_max_period) 764 + { 765 + *pss_min_period = telm_conf->pss_config.min_period; 766 + *pss_max_period = telm_conf->pss_config.max_period; 767 + *ioss_min_period = telm_conf->ioss_config.min_period; 768 + *ioss_max_period = telm_conf->ioss_config.max_period; 769 + 770 + return 0; 771 + } 772 + 773 + 774 + static int telemetry_plt_reset_events(void) 775 + { 776 + struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; 777 + int ret; 778 + 779 + pss_evtconfig.evtmap = NULL; 780 + pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; 781 + pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; 782 + 783 + ioss_evtconfig.evtmap = NULL; 784 + ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; 785 + ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; 786 + 787 + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 788 + TELEM_RESET); 789 + if (ret) 790 + pr_err("TELEMTRY Reset Failed\n"); 791 + 792 + return ret; 793 + } 794 + 795 + 796 + static int telemetry_plt_get_eventconfig(struct telemetry_evtconfig *pss_config, 797 + struct telemetry_evtconfig *ioss_config, 798 + int pss_len, int ioss_len) 799 + { 800 + u32 *pss_evtmap, *ioss_evtmap; 801 + u32 index; 802 + 803 + pss_evtmap = pss_config->evtmap; 804 + ioss_evtmap = ioss_config->evtmap; 805 + 806 + mutex_lock(&(telm_conf->telem_lock)); 807 + pss_config->num_evts = telm_conf->pss_config.ssram_evts_used; 808 + ioss_config->num_evts = telm_conf->ioss_config.ssram_evts_used; 809 + 810 + pss_config->period = telm_conf->pss_config.curr_period; 811 + ioss_config->period = telm_conf->ioss_config.curr_period; 812 + 813 + if ((pss_len < telm_conf->pss_config.ssram_evts_used) || 814 + (ioss_len < telm_conf->ioss_config.ssram_evts_used)) { 815 + mutex_unlock(&(telm_conf->telem_lock)); 816 + return -EINVAL; 817 + } 818 + 819 + for (index = 0; index < telm_conf->pss_config.ssram_evts_used; 820 + index++) { 821 + pss_evtmap[index] = 822 + telm_conf->pss_config.telem_evts[index].evt_id; 823 + } 824 + 825 + for (index = 0; index < telm_conf->ioss_config.ssram_evts_used; 826 + index++) { 827 + ioss_evtmap[index] = 828 + telm_conf->ioss_config.telem_evts[index].evt_id; 829 + } 830 + 831 + mutex_unlock(&(telm_conf->telem_lock)); 832 + return 0; 833 + } 834 + 835 + 836 + static int telemetry_plt_add_events(u8 num_pss_evts, u8 num_ioss_evts, 837 + u32 *pss_evtmap, u32 *ioss_evtmap) 838 + { 839 + struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; 840 + int ret; 841 + 842 + pss_evtconfig.evtmap = pss_evtmap; 843 + pss_evtconfig.num_evts = num_pss_evts; 844 + pss_evtconfig.period = telm_conf->pss_config.curr_period; 845 + 846 + ioss_evtconfig.evtmap = ioss_evtmap; 847 + ioss_evtconfig.num_evts = num_ioss_evts; 848 + ioss_evtconfig.period = telm_conf->ioss_config.curr_period; 849 + 850 + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 851 + TELEM_ADD); 852 + if (ret) 853 + pr_err("TELEMTRY ADD Failed\n"); 854 + 855 + return ret; 856 + } 857 + 858 + static int telem_evtlog_read(enum telemetry_unit telem_unit, 859 + struct telem_ssram_region *ssram_region, u8 len) 860 + { 861 + struct telemetry_unit_config *unit_config; 862 + u64 timestamp_prev, timestamp_next; 863 + int ret, index, timeout = 0; 864 + 865 + ret = telem_get_unitconfig(telem_unit, &unit_config); 866 + if (ret < 0) 867 + return ret; 868 + 869 + if (len > unit_config->ssram_evts_used) 870 + len = unit_config->ssram_evts_used; 871 + 872 + do { 873 + timestamp_prev = readq(unit_config->regmap); 874 + if (!timestamp_prev) { 875 + pr_err("Ssram under update. Please Try Later\n"); 876 + return -EBUSY; 877 + } 878 + 879 + ssram_region->start_time = readq(unit_config->regmap + 880 + TELEM_SSRAM_STARTTIME_OFFSET); 881 + 882 + for (index = 0; index < len; index++) { 883 + ssram_region->events[index] = 884 + readq(unit_config->regmap + TELEM_SSRAM_EVTLOG_OFFSET + 885 + BYTES_PER_LONG*index); 886 + } 887 + 888 + timestamp_next = readq(unit_config->regmap); 889 + if (!timestamp_next) { 890 + pr_err("Ssram under update. Please Try Later\n"); 891 + return -EBUSY; 892 + } 893 + 894 + if (timeout++ > TELEM_SSRAM_READ_TIMEOUT) { 895 + pr_err("Timeout while reading Events\n"); 896 + return -EBUSY; 897 + } 898 + 899 + } while (timestamp_prev != timestamp_next); 900 + 901 + ssram_region->timestamp = timestamp_next; 902 + 903 + return len; 904 + } 905 + 906 + static int telemetry_plt_raw_read_eventlog(enum telemetry_unit telem_unit, 907 + struct telemetry_evtlog *evtlog, 908 + int len, int log_all_evts) 909 + { 910 + int index, idx1, ret, readlen = len; 911 + struct telem_ssram_region ssram_region; 912 + struct telemetry_evtmap *evtmap; 913 + 914 + switch (telem_unit) { 915 + case TELEM_PSS: 916 + evtmap = telm_conf->pss_config.telem_evts; 917 + break; 918 + 919 + case TELEM_IOSS: 920 + evtmap = telm_conf->ioss_config.telem_evts; 921 + break; 922 + 923 + default: 924 + pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); 925 + return -EINVAL; 926 + } 927 + 928 + if (!log_all_evts) 929 + readlen = TELEM_MAX_EVENTS_SRAM; 930 + 931 + ret = telem_evtlog_read(telem_unit, &ssram_region, readlen); 932 + if (ret < 0) 933 + return ret; 934 + 935 + /* Invalid evt-id array specified via length mismatch */ 936 + if ((!log_all_evts) && (len > ret)) 937 + return -EINVAL; 938 + 939 + if (log_all_evts) 940 + for (index = 0; index < ret; index++) { 941 + evtlog[index].telem_evtlog = ssram_region.events[index]; 942 + evtlog[index].telem_evtid = evtmap[index].evt_id; 943 + } 944 + else 945 + for (index = 0, readlen = 0; (index < ret) && (readlen < len); 946 + index++) { 947 + for (idx1 = 0; idx1 < len; idx1++) { 948 + /* Elements matched */ 949 + if (evtmap[index].evt_id == 950 + evtlog[idx1].telem_evtid) { 951 + evtlog[idx1].telem_evtlog = 952 + ssram_region.events[index]; 953 + readlen++; 954 + 955 + break; 956 + } 957 + } 958 + } 959 + 960 + return readlen; 961 + } 962 + 963 + static int telemetry_plt_read_eventlog(enum telemetry_unit telem_unit, 964 + struct telemetry_evtlog *evtlog, int len, int log_all_evts) 965 + { 966 + int ret; 967 + 968 + mutex_lock(&(telm_conf->telem_lock)); 969 + ret = telemetry_plt_raw_read_eventlog(telem_unit, evtlog, 970 + len, log_all_evts); 971 + mutex_unlock(&(telm_conf->telem_lock)); 972 + 973 + return ret; 974 + } 975 + 976 + static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit, 977 + u32 *verbosity) 978 + { 979 + u32 temp = 0; 980 + int ret; 981 + 982 + if (verbosity == NULL) 983 + return -EINVAL; 984 + 985 + mutex_lock(&(telm_conf->telem_trace_lock)); 986 + switch (telem_unit) { 987 + case TELEM_PSS: 988 + ret = intel_punit_ipc_command( 989 + IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, 990 + 0, 0, NULL, &temp); 991 + if (ret) { 992 + pr_err("PSS TRACE_CTRL Read Failed\n"); 993 + goto out; 994 + } 995 + 996 + break; 997 + 998 + case TELEM_IOSS: 999 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 1000 + IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp, 1001 + IOSS_TELEM_READ_WORD); 1002 + if (ret) { 1003 + pr_err("IOSS TRACE_CTL Read Failed\n"); 1004 + goto out; 1005 + } 1006 + 1007 + break; 1008 + 1009 + default: 1010 + pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); 1011 + ret = -EINVAL; 1012 + break; 1013 + } 1014 + TELEM_EXTRACT_VERBOSITY(temp, *verbosity); 1015 + 1016 + out: 1017 + mutex_unlock(&(telm_conf->telem_trace_lock)); 1018 + return ret; 1019 + } 1020 + 1021 + static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit, 1022 + u32 verbosity) 1023 + { 1024 + u32 temp = 0; 1025 + int ret; 1026 + 1027 + verbosity &= TELEM_TRC_VERBOSITY_MASK; 1028 + 1029 + mutex_lock(&(telm_conf->telem_trace_lock)); 1030 + switch (telem_unit) { 1031 + case TELEM_PSS: 1032 + ret = intel_punit_ipc_command( 1033 + IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL, 1034 + 0, 0, &verbosity, NULL); 1035 + if (ret) { 1036 + pr_err("PSS TRACE_CTRL Verbosity Set Failed\n"); 1037 + goto out; 1038 + } 1039 + break; 1040 + 1041 + case TELEM_IOSS: 1042 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 1043 + IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp, 1044 + IOSS_TELEM_READ_WORD); 1045 + if (ret) { 1046 + pr_err("IOSS TRACE_CTL Read Failed\n"); 1047 + goto out; 1048 + } 1049 + 1050 + TELEM_CLEAR_VERBOSITY_BITS(temp); 1051 + TELEM_SET_VERBOSITY_BITS(temp, verbosity); 1052 + 1053 + ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, 1054 + IOSS_TELEM_TRACE_CTL_WRITE, (u8 *)&temp, 1055 + IOSS_TELEM_WRITE_FOURBYTES, NULL, 0); 1056 + if (ret) { 1057 + pr_err("IOSS TRACE_CTL Verbosity Set Failed\n"); 1058 + goto out; 1059 + } 1060 + break; 1061 + 1062 + default: 1063 + pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); 1064 + ret = -EINVAL; 1065 + break; 1066 + } 1067 + 1068 + out: 1069 + mutex_unlock(&(telm_conf->telem_trace_lock)); 1070 + return ret; 1071 + } 1072 + 1073 + static struct telemetry_core_ops telm_pltops = { 1074 + .get_trace_verbosity = telemetry_plt_get_trace_verbosity, 1075 + .set_trace_verbosity = telemetry_plt_set_trace_verbosity, 1076 + .set_sampling_period = telemetry_plt_set_sampling_period, 1077 + .get_sampling_period = telemetry_plt_get_sampling_period, 1078 + .raw_read_eventlog = telemetry_plt_raw_read_eventlog, 1079 + .get_eventconfig = telemetry_plt_get_eventconfig, 1080 + .update_events = telemetry_plt_update_events, 1081 + .read_eventlog = telemetry_plt_read_eventlog, 1082 + .reset_events = telemetry_plt_reset_events, 1083 + .add_events = telemetry_plt_add_events, 1084 + }; 1085 + 1086 + static int telemetry_pltdrv_probe(struct platform_device *pdev) 1087 + { 1088 + struct resource *res0 = NULL, *res1 = NULL; 1089 + const struct x86_cpu_id *id; 1090 + int size, ret = -ENOMEM; 1091 + 1092 + id = x86_match_cpu(telemetry_cpu_ids); 1093 + if (!id) 1094 + return -ENODEV; 1095 + 1096 + telm_conf = (struct telemetry_plt_config *)id->driver_data; 1097 + 1098 + res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1099 + if (!res0) { 1100 + ret = -EINVAL; 1101 + goto out; 1102 + } 1103 + size = resource_size(res0); 1104 + if (!devm_request_mem_region(&pdev->dev, res0->start, size, 1105 + pdev->name)) { 1106 + ret = -EBUSY; 1107 + goto out; 1108 + } 1109 + telm_conf->pss_config.ssram_base_addr = res0->start; 1110 + telm_conf->pss_config.ssram_size = size; 1111 + 1112 + res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1113 + if (!res1) { 1114 + ret = -EINVAL; 1115 + goto out; 1116 + } 1117 + size = resource_size(res1); 1118 + if (!devm_request_mem_region(&pdev->dev, res1->start, size, 1119 + pdev->name)) { 1120 + ret = -EBUSY; 1121 + goto out; 1122 + } 1123 + 1124 + telm_conf->ioss_config.ssram_base_addr = res1->start; 1125 + telm_conf->ioss_config.ssram_size = size; 1126 + 1127 + telm_conf->pss_config.regmap = ioremap_nocache( 1128 + telm_conf->pss_config.ssram_base_addr, 1129 + telm_conf->pss_config.ssram_size); 1130 + if (!telm_conf->pss_config.regmap) { 1131 + ret = -ENOMEM; 1132 + goto out; 1133 + } 1134 + 1135 + telm_conf->ioss_config.regmap = ioremap_nocache( 1136 + telm_conf->ioss_config.ssram_base_addr, 1137 + telm_conf->ioss_config.ssram_size); 1138 + if (!telm_conf->ioss_config.regmap) { 1139 + ret = -ENOMEM; 1140 + goto out; 1141 + } 1142 + 1143 + mutex_init(&telm_conf->telem_lock); 1144 + mutex_init(&telm_conf->telem_trace_lock); 1145 + 1146 + ret = telemetry_setup(pdev); 1147 + if (ret) 1148 + goto out; 1149 + 1150 + ret = telemetry_set_pltdata(&telm_pltops, telm_conf); 1151 + if (ret) { 1152 + dev_err(&pdev->dev, "TELEMTRY Set Pltops Failed.\n"); 1153 + goto out; 1154 + } 1155 + 1156 + return 0; 1157 + 1158 + out: 1159 + if (res0) 1160 + release_mem_region(res0->start, resource_size(res0)); 1161 + if (res1) 1162 + release_mem_region(res1->start, resource_size(res1)); 1163 + if (telm_conf->pss_config.regmap) 1164 + iounmap(telm_conf->pss_config.regmap); 1165 + if (telm_conf->ioss_config.regmap) 1166 + iounmap(telm_conf->ioss_config.regmap); 1167 + dev_err(&pdev->dev, "TELEMTRY Setup Failed.\n"); 1168 + 1169 + return ret; 1170 + } 1171 + 1172 + static int telemetry_pltdrv_remove(struct platform_device *pdev) 1173 + { 1174 + telemetry_clear_pltdata(); 1175 + iounmap(telm_conf->pss_config.regmap); 1176 + iounmap(telm_conf->ioss_config.regmap); 1177 + 1178 + return 0; 1179 + } 1180 + 1181 + static struct platform_driver telemetry_soc_driver = { 1182 + .probe = telemetry_pltdrv_probe, 1183 + .remove = telemetry_pltdrv_remove, 1184 + .driver = { 1185 + .name = DRIVER_NAME, 1186 + }, 1187 + }; 1188 + 1189 + static int __init telemetry_module_init(void) 1190 + { 1191 + pr_info(DRIVER_NAME ": version %s loaded\n", DRIVER_VERSION); 1192 + return platform_driver_register(&telemetry_soc_driver); 1193 + } 1194 + 1195 + static void __exit telemetry_module_exit(void) 1196 + { 1197 + platform_driver_unregister(&telemetry_soc_driver); 1198 + } 1199 + 1200 + device_initcall(telemetry_module_init); 1201 + module_exit(telemetry_module_exit); 1202 + 1203 + MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>"); 1204 + MODULE_DESCRIPTION("Intel SoC Telemetry Platform Driver"); 1205 + MODULE_VERSION(DRIVER_VERSION); 1206 + MODULE_LICENSE("GPL");
+45 -20
drivers/platform/x86/sony-laptop.c
··· 1393 1393 case 0x0143: 1394 1394 case 0x014b: 1395 1395 case 0x014c: 1396 + case 0x0153: 1396 1397 case 0x0163: 1397 1398 result = sony_nc_kbd_backlight_setup(pf_device, handle); 1398 1399 if (result) ··· 1491 1490 case 0x0143: 1492 1491 case 0x014b: 1493 1492 case 0x014c: 1493 + case 0x0153: 1494 1494 case 0x0163: 1495 1495 sony_nc_kbd_backlight_cleanup(pd, handle); 1496 1496 break; ··· 1775 1773 unsigned int base; 1776 1774 unsigned int mode; 1777 1775 unsigned int timeout; 1776 + unsigned int has_timeout; 1778 1777 struct device_attribute mode_attr; 1779 1778 struct device_attribute timeout_attr; 1780 1779 }; ··· 1880 1877 unsigned int handle) 1881 1878 { 1882 1879 int result; 1880 + int probe_base = 0; 1881 + int ctl_base = 0; 1883 1882 int ret = 0; 1884 1883 1885 1884 if (kbdbl_ctl) { ··· 1890 1885 return -EBUSY; 1891 1886 } 1892 1887 1893 - /* verify the kbd backlight presence, these handles are not used for 1894 - * keyboard backlight only 1888 + /* verify the kbd backlight presence, some of these handles are not used 1889 + * for keyboard backlight only 1895 1890 */ 1896 - ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100, 1897 - &result); 1891 + switch (handle) { 1892 + case 0x0153: 1893 + probe_base = 0x0; 1894 + ctl_base = 0x0; 1895 + break; 1896 + case 0x0137: 1897 + probe_base = 0x0B00; 1898 + ctl_base = 0x0C00; 1899 + break; 1900 + default: 1901 + probe_base = 0x0100; 1902 + ctl_base = 0x4000; 1903 + break; 1904 + } 1905 + 1906 + ret = sony_call_snc_handle(handle, probe_base, &result); 1898 1907 if (ret) 1899 1908 return ret; 1900 1909 ··· 1925 1906 kbdbl_ctl->mode = kbd_backlight; 1926 1907 kbdbl_ctl->timeout = kbd_backlight_timeout; 1927 1908 kbdbl_ctl->handle = handle; 1928 - if (handle == 0x0137) 1929 - kbdbl_ctl->base = 0x0C00; 1930 - else 1931 - kbdbl_ctl->base = 0x4000; 1909 + kbdbl_ctl->base = ctl_base; 1910 + /* Some models do not allow timeout control */ 1911 + kbdbl_ctl->has_timeout = handle != 0x0153; 1932 1912 1933 1913 sysfs_attr_init(&kbdbl_ctl->mode_attr.attr); 1934 1914 kbdbl_ctl->mode_attr.attr.name = "kbd_backlight"; ··· 1935 1917 kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show; 1936 1918 kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store; 1937 1919 1938 - sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr); 1939 - kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout"; 1940 - kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; 1941 - kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; 1942 - kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; 1943 - 1944 1920 ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr); 1945 1921 if (ret) 1946 1922 goto outkzalloc; 1947 1923 1948 - ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr); 1949 - if (ret) 1950 - goto outmode; 1951 - 1952 1924 __sony_nc_kbd_backlight_mode_set(kbdbl_ctl->mode); 1953 - __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout); 1925 + 1926 + if (kbdbl_ctl->has_timeout) { 1927 + sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr); 1928 + kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout"; 1929 + kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; 1930 + kbdbl_ctl->timeout_attr.show = 1931 + sony_nc_kbd_backlight_timeout_show; 1932 + kbdbl_ctl->timeout_attr.store = 1933 + sony_nc_kbd_backlight_timeout_store; 1934 + 1935 + ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr); 1936 + if (ret) 1937 + goto outmode; 1938 + 1939 + __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout); 1940 + } 1941 + 1954 1942 1955 1943 return 0; 1956 1944 ··· 1973 1949 { 1974 1950 if (kbdbl_ctl && handle == kbdbl_ctl->handle) { 1975 1951 device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); 1976 - device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); 1952 + if (kbdbl_ctl->has_timeout) 1953 + device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); 1977 1954 kfree(kbdbl_ctl); 1978 1955 kbdbl_ctl = NULL; 1979 1956 }
+7 -5
drivers/platform/x86/surfacepro3_button.c
··· 1 1 /* 2 2 * power/home/volume button support for 3 - * Microsoft Surface Pro 3 tablet. 3 + * Microsoft Surface Pro 3/4 tablet. 4 4 * 5 5 * Copyright (c) 2015 Intel Corporation. 6 6 * All rights reserved. ··· 19 19 #include <linux/acpi.h> 20 20 #include <acpi/button.h> 21 21 22 - #define SURFACE_BUTTON_HID "MSHW0028" 22 + #define SURFACE_PRO3_BUTTON_HID "MSHW0028" 23 + #define SURFACE_PRO4_BUTTON_HID "MSHW0040" 23 24 #define SURFACE_BUTTON_OBJ_NAME "VGBI" 24 - #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3 Buttons" 25 + #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons" 25 26 26 27 #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6 27 28 #define SURFACE_BUTTON_NOTIFY_RELEASE_POWER 0xc7 ··· 55 54 * acpi_driver. 56 55 */ 57 56 static const struct acpi_device_id surface_button_device_ids[] = { 58 - {SURFACE_BUTTON_HID, 0}, 57 + {SURFACE_PRO3_BUTTON_HID, 0}, 58 + {SURFACE_PRO4_BUTTON_HID, 0}, 59 59 {"", 0}, 60 60 }; 61 61 MODULE_DEVICE_TABLE(acpi, surface_button_device_ids); ··· 111 109 break; 112 110 } 113 111 input = button->input; 114 - if (KEY_RESERVED == key_code) 112 + if (key_code == KEY_RESERVED) 115 113 return; 116 114 if (pressed) 117 115 pm_wakeup_event(&device->dev, 0);
+2
drivers/platform/x86/tc1100-wmi.c
··· 52 52 u32 jogdial; 53 53 }; 54 54 55 + #ifdef CONFIG_PM 55 56 static struct tc1100_data suspend_data; 57 + #endif 56 58 57 59 /* -------------------------------------------------------------------------- 58 60 Device Management
+206
drivers/platform/x86/thinkpad_acpi.c
··· 303 303 u32 hotkey_mask:1; 304 304 u32 hotkey_wlsw:1; 305 305 u32 hotkey_tablet:1; 306 + u32 kbdlight:1; 306 307 u32 light:1; 307 308 u32 light_status:1; 308 309 u32 bright_acpimode:1; ··· 4987 4986 #endif /* CONFIG_THINKPAD_ACPI_VIDEO */ 4988 4987 4989 4988 /************************************************************************* 4989 + * Keyboard backlight subdriver 4990 + */ 4991 + 4992 + static int kbdlight_set_level(int level) 4993 + { 4994 + if (!hkey_handle) 4995 + return -ENXIO; 4996 + 4997 + if (!acpi_evalf(hkey_handle, NULL, "MLCS", "dd", level)) 4998 + return -EIO; 4999 + 5000 + return 0; 5001 + } 5002 + 5003 + static int kbdlight_get_level(void) 5004 + { 5005 + int status = 0; 5006 + 5007 + if (!hkey_handle) 5008 + return -ENXIO; 5009 + 5010 + if (!acpi_evalf(hkey_handle, &status, "MLCG", "dd", 0)) 5011 + return -EIO; 5012 + 5013 + if (status < 0) 5014 + return status; 5015 + 5016 + return status & 0x3; 5017 + } 5018 + 5019 + static bool kbdlight_is_supported(void) 5020 + { 5021 + int status = 0; 5022 + 5023 + if (!hkey_handle) 5024 + return false; 5025 + 5026 + if (!acpi_has_method(hkey_handle, "MLCG")) { 5027 + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG is unavailable\n"); 5028 + return false; 5029 + } 5030 + 5031 + if (!acpi_evalf(hkey_handle, &status, "MLCG", "qdd", 0)) { 5032 + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG failed\n"); 5033 + return false; 5034 + } 5035 + 5036 + if (status < 0) { 5037 + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG err: %d\n", status); 5038 + return false; 5039 + } 5040 + 5041 + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG returned 0x%x\n", status); 5042 + /* 5043 + * Guessed test for keyboard backlight: 5044 + * 5045 + * Machines with backlight keyboard return: 5046 + * b010100000010000000XX - ThinkPad X1 Carbon 3rd 5047 + * b110100010010000000XX - ThinkPad x230 5048 + * b010100000010000000XX - ThinkPad x240 5049 + * b010100000010000000XX - ThinkPad W541 5050 + * (XX is current backlight level) 5051 + * 5052 + * Machines without backlight keyboard return: 5053 + * b10100001000000000000 - ThinkPad x230 5054 + * b10110001000000000000 - ThinkPad E430 5055 + * b00000000000000000000 - ThinkPad E450 5056 + * 5057 + * Candidate BITs for detection test (XOR): 5058 + * b01000000001000000000 5059 + * ^ 5060 + */ 5061 + return status & BIT(9); 5062 + } 5063 + 5064 + static void kbdlight_set_worker(struct work_struct *work) 5065 + { 5066 + struct tpacpi_led_classdev *data = 5067 + container_of(work, struct tpacpi_led_classdev, work); 5068 + 5069 + if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) 5070 + kbdlight_set_level(data->new_state); 5071 + } 5072 + 5073 + static void kbdlight_sysfs_set(struct led_classdev *led_cdev, 5074 + enum led_brightness brightness) 5075 + { 5076 + struct tpacpi_led_classdev *data = 5077 + container_of(led_cdev, 5078 + struct tpacpi_led_classdev, 5079 + led_classdev); 5080 + data->new_state = brightness; 5081 + queue_work(tpacpi_wq, &data->work); 5082 + } 5083 + 5084 + static enum led_brightness kbdlight_sysfs_get(struct led_classdev *led_cdev) 5085 + { 5086 + int level; 5087 + 5088 + level = kbdlight_get_level(); 5089 + if (level < 0) 5090 + return 0; 5091 + 5092 + return level; 5093 + } 5094 + 5095 + static struct tpacpi_led_classdev tpacpi_led_kbdlight = { 5096 + .led_classdev = { 5097 + .name = "tpacpi::kbd_backlight", 5098 + .max_brightness = 2, 5099 + .brightness_set = &kbdlight_sysfs_set, 5100 + .brightness_get = &kbdlight_sysfs_get, 5101 + .flags = LED_CORE_SUSPENDRESUME, 5102 + } 5103 + }; 5104 + 5105 + static int __init kbdlight_init(struct ibm_init_struct *iibm) 5106 + { 5107 + int rc; 5108 + 5109 + vdbg_printk(TPACPI_DBG_INIT, "initializing kbdlight subdriver\n"); 5110 + 5111 + TPACPI_ACPIHANDLE_INIT(hkey); 5112 + INIT_WORK(&tpacpi_led_kbdlight.work, kbdlight_set_worker); 5113 + 5114 + if (!kbdlight_is_supported()) { 5115 + tp_features.kbdlight = 0; 5116 + vdbg_printk(TPACPI_DBG_INIT, "kbdlight is unsupported\n"); 5117 + return 1; 5118 + } 5119 + 5120 + tp_features.kbdlight = 1; 5121 + 5122 + rc = led_classdev_register(&tpacpi_pdev->dev, 5123 + &tpacpi_led_kbdlight.led_classdev); 5124 + if (rc < 0) { 5125 + tp_features.kbdlight = 0; 5126 + return rc; 5127 + } 5128 + 5129 + return 0; 5130 + } 5131 + 5132 + static void kbdlight_exit(void) 5133 + { 5134 + if (tp_features.kbdlight) 5135 + led_classdev_unregister(&tpacpi_led_kbdlight.led_classdev); 5136 + flush_workqueue(tpacpi_wq); 5137 + } 5138 + 5139 + static int kbdlight_read(struct seq_file *m) 5140 + { 5141 + int level; 5142 + 5143 + if (!tp_features.kbdlight) { 5144 + seq_printf(m, "status:\t\tnot supported\n"); 5145 + } else { 5146 + level = kbdlight_get_level(); 5147 + if (level < 0) 5148 + seq_printf(m, "status:\t\terror %d\n", level); 5149 + else 5150 + seq_printf(m, "status:\t\t%d\n", level); 5151 + seq_printf(m, "commands:\t0, 1, 2\n"); 5152 + } 5153 + 5154 + return 0; 5155 + } 5156 + 5157 + static int kbdlight_write(char *buf) 5158 + { 5159 + char *cmd; 5160 + int level = -1; 5161 + 5162 + if (!tp_features.kbdlight) 5163 + return -ENODEV; 5164 + 5165 + while ((cmd = next_cmd(&buf))) { 5166 + if (strlencmp(cmd, "0") == 0) 5167 + level = 0; 5168 + else if (strlencmp(cmd, "1") == 0) 5169 + level = 1; 5170 + else if (strlencmp(cmd, "2") == 0) 5171 + level = 2; 5172 + else 5173 + return -EINVAL; 5174 + } 5175 + 5176 + if (level == -1) 5177 + return -EINVAL; 5178 + 5179 + return kbdlight_set_level(level); 5180 + } 5181 + 5182 + static struct ibm_struct kbdlight_driver_data = { 5183 + .name = "kbdlight", 5184 + .read = kbdlight_read, 5185 + .write = kbdlight_write, 5186 + .exit = kbdlight_exit, 5187 + }; 5188 + 5189 + /************************************************************************* 4990 5190 * Light (thinklight) subdriver 4991 5191 */ 4992 5192 ··· 9408 9206 .data = &video_driver_data, 9409 9207 }, 9410 9208 #endif 9209 + { 9210 + .init = kbdlight_init, 9211 + .data = &kbdlight_driver_data, 9212 + }, 9411 9213 { 9412 9214 .init = light_init, 9413 9215 .data = &light_driver_data,
+238 -8
drivers/platform/x86/toshiba_acpi.c
··· 51 51 #include <linux/dmi.h> 52 52 #include <linux/uaccess.h> 53 53 #include <linux/miscdevice.h> 54 + #include <linux/rfkill.h> 54 55 #include <linux/toshiba.h> 55 56 #include <acpi/video.h> 56 57 ··· 115 114 #define HCI_VIDEO_OUT 0x001c 116 115 #define HCI_HOTKEY_EVENT 0x001e 117 116 #define HCI_LCD_BRIGHTNESS 0x002a 117 + #define HCI_WIRELESS 0x0056 118 118 #define HCI_ACCELEROMETER 0x006d 119 119 #define HCI_KBD_ILLUMINATION 0x0095 120 120 #define HCI_ECO_MODE 0x0097 ··· 150 148 #define SCI_KBD_MODE_ON 0x8 151 149 #define SCI_KBD_MODE_OFF 0x10 152 150 #define SCI_KBD_TIME_MAX 0x3c001a 151 + #define HCI_WIRELESS_STATUS 0x1 152 + #define HCI_WIRELESS_WWAN 0x3 153 + #define HCI_WIRELESS_WWAN_STATUS 0x2000 154 + #define HCI_WIRELESS_WWAN_POWER 0x4000 153 155 #define SCI_USB_CHARGE_MODE_MASK 0xff 154 156 #define SCI_USB_CHARGE_DISABLED 0x00 155 157 #define SCI_USB_CHARGE_ALTERNATE 0x09 ··· 175 169 struct led_classdev kbd_led; 176 170 struct led_classdev eco_led; 177 171 struct miscdevice miscdev; 172 + struct rfkill *wwan_rfk; 178 173 179 174 int force_fan; 180 175 int last_key_event; ··· 204 197 unsigned int kbd_function_keys_supported:1; 205 198 unsigned int panel_power_on_supported:1; 206 199 unsigned int usb_three_supported:1; 200 + unsigned int wwan_supported:1; 207 201 unsigned int sysfs_created:1; 208 202 unsigned int special_functions; 209 203 204 + bool kbd_event_generated; 210 205 bool kbd_led_registered; 211 206 bool illumination_led_registered; 212 207 bool eco_led_registered; 208 + bool killswitch; 213 209 }; 214 210 215 211 static struct toshiba_acpi_dev *toshiba_acpi; ··· 526 516 527 517 dev->kbd_illum_supported = 0; 528 518 dev->kbd_led_registered = false; 519 + dev->kbd_event_generated = false; 529 520 530 521 if (!sci_open(dev)) 531 522 return; ··· 1096 1085 return -EIO; 1097 1086 } 1098 1087 1088 + /* Wireless status (RFKill, WLAN, BT, WWAN) */ 1089 + static int toshiba_wireless_status(struct toshiba_acpi_dev *dev) 1090 + { 1091 + u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 1092 + u32 out[TCI_WORDS]; 1093 + acpi_status status; 1094 + 1095 + in[3] = HCI_WIRELESS_STATUS; 1096 + status = tci_raw(dev, in, out); 1097 + 1098 + if (ACPI_FAILURE(status)) { 1099 + pr_err("ACPI call to get Wireless status failed\n"); 1100 + return -EIO; 1101 + } 1102 + 1103 + if (out[0] == TOS_NOT_SUPPORTED) 1104 + return -ENODEV; 1105 + 1106 + if (out[0] != TOS_SUCCESS) 1107 + return -EIO; 1108 + 1109 + dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS); 1110 + 1111 + return 0; 1112 + } 1113 + 1114 + /* WWAN */ 1115 + static void toshiba_wwan_available(struct toshiba_acpi_dev *dev) 1116 + { 1117 + u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 1118 + u32 out[TCI_WORDS]; 1119 + acpi_status status; 1120 + 1121 + dev->wwan_supported = 0; 1122 + 1123 + /* 1124 + * WWAN support can be queried by setting the in[3] value to 1125 + * HCI_WIRELESS_WWAN (0x03). 1126 + * 1127 + * If supported, out[0] contains TOS_SUCCESS and out[2] contains 1128 + * HCI_WIRELESS_WWAN_STATUS (0x2000). 1129 + * 1130 + * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300) 1131 + * or TOS_NOT_SUPPORTED (0x8000). 1132 + */ 1133 + in[3] = HCI_WIRELESS_WWAN; 1134 + status = tci_raw(dev, in, out); 1135 + 1136 + if (ACPI_FAILURE(status)) { 1137 + pr_err("ACPI call to get WWAN status failed\n"); 1138 + return; 1139 + } 1140 + 1141 + if (out[0] != TOS_SUCCESS) 1142 + return; 1143 + 1144 + dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS); 1145 + } 1146 + 1147 + static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) 1148 + { 1149 + u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 }; 1150 + u32 out[TCI_WORDS]; 1151 + acpi_status status; 1152 + 1153 + in[3] = HCI_WIRELESS_WWAN_STATUS; 1154 + status = tci_raw(dev, in, out); 1155 + 1156 + if (ACPI_FAILURE(status)) { 1157 + pr_err("ACPI call to set WWAN status failed\n"); 1158 + return -EIO; 1159 + } 1160 + 1161 + if (out[0] == TOS_NOT_SUPPORTED) 1162 + return -ENODEV; 1163 + 1164 + if (out[0] != TOS_SUCCESS) 1165 + return -EIO; 1166 + 1167 + /* 1168 + * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to 1169 + * (de)activate the device, but some others need the 1170 + * HCI_WIRELESS_WWAN_POWER call as well. 1171 + */ 1172 + in[3] = HCI_WIRELESS_WWAN_POWER; 1173 + status = tci_raw(dev, in, out); 1174 + 1175 + if (ACPI_FAILURE(status)) { 1176 + pr_err("ACPI call to set WWAN power failed\n"); 1177 + return -EIO; 1178 + } 1179 + 1180 + if (out[0] == TOS_NOT_SUPPORTED) 1181 + return -ENODEV; 1182 + 1183 + return out[0] == TOS_SUCCESS ? 0 : -EIO; 1184 + } 1185 + 1099 1186 /* Transflective Backlight */ 1100 1187 static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1101 1188 { ··· 1644 1535 .update_status = set_lcd_status, 1645 1536 }; 1646 1537 1538 + /* Keyboard backlight work */ 1539 + static void toshiba_acpi_kbd_bl_work(struct work_struct *work); 1540 + 1541 + static DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work); 1542 + 1647 1543 /* 1648 1544 * Sysfs files 1649 1545 */ ··· 1748 1634 return ret; 1749 1635 1750 1636 toshiba->kbd_mode = mode; 1637 + 1638 + /* 1639 + * Some laptop models with the second generation backlit 1640 + * keyboard (type 2) do not generate the keyboard backlight 1641 + * changed event (0x92), and thus, the driver will never update 1642 + * the sysfs entries. 1643 + * 1644 + * The event is generated right when changing the keyboard 1645 + * backlight mode and the *notify function will set the 1646 + * kbd_event_generated to true. 1647 + * 1648 + * In case the event is not generated, schedule the keyboard 1649 + * backlight work to update the sysfs entries and emulate the 1650 + * event via genetlink. 1651 + */ 1652 + if (toshiba->kbd_type == 2 && 1653 + !toshiba_acpi->kbd_event_generated) 1654 + schedule_work(&kbd_bl_work); 1751 1655 } 1752 1656 1753 1657 return count; ··· 2298 2166 .attrs = toshiba_attributes, 2299 2167 }; 2300 2168 2169 + static void toshiba_acpi_kbd_bl_work(struct work_struct *work) 2170 + { 2171 + struct acpi_device *acpi_dev = toshiba_acpi->acpi_dev; 2172 + 2173 + /* Update the sysfs entries */ 2174 + if (sysfs_update_group(&acpi_dev->dev.kobj, 2175 + &toshiba_attr_group)) 2176 + pr_err("Unable to update sysfs entries\n"); 2177 + 2178 + /* Emulate the keyboard backlight event */ 2179 + acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2180 + dev_name(&acpi_dev->dev), 2181 + 0x92, 0); 2182 + } 2183 + 2301 2184 /* 2302 2185 * Misc device 2303 2186 */ ··· 2387 2240 .unlocked_ioctl = toshiba_acpi_ioctl, 2388 2241 .llseek = noop_llseek, 2389 2242 }; 2243 + 2244 + /* 2245 + * WWAN RFKill handlers 2246 + */ 2247 + static int toshiba_acpi_wwan_set_block(void *data, bool blocked) 2248 + { 2249 + struct toshiba_acpi_dev *dev = data; 2250 + int ret; 2251 + 2252 + ret = toshiba_wireless_status(dev); 2253 + if (ret) 2254 + return ret; 2255 + 2256 + if (!dev->killswitch) 2257 + return 0; 2258 + 2259 + return toshiba_wwan_set(dev, !blocked); 2260 + } 2261 + 2262 + static void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data) 2263 + { 2264 + struct toshiba_acpi_dev *dev = data; 2265 + 2266 + if (toshiba_wireless_status(dev)) 2267 + return; 2268 + 2269 + rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 2270 + } 2271 + 2272 + static const struct rfkill_ops wwan_rfk_ops = { 2273 + .set_block = toshiba_acpi_wwan_set_block, 2274 + .poll = toshiba_acpi_wwan_poll, 2275 + }; 2276 + 2277 + static int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev) 2278 + { 2279 + int ret = toshiba_wireless_status(dev); 2280 + 2281 + if (ret) 2282 + return ret; 2283 + 2284 + dev->wwan_rfk = rfkill_alloc("Toshiba WWAN", 2285 + &dev->acpi_dev->dev, 2286 + RFKILL_TYPE_WWAN, 2287 + &wwan_rfk_ops, 2288 + dev); 2289 + if (!dev->wwan_rfk) { 2290 + pr_err("Unable to allocate WWAN rfkill device\n"); 2291 + return -ENOMEM; 2292 + } 2293 + 2294 + rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 2295 + 2296 + ret = rfkill_register(dev->wwan_rfk); 2297 + if (ret) { 2298 + pr_err("Unable to register WWAN rfkill device\n"); 2299 + rfkill_destroy(dev->wwan_rfk); 2300 + } 2301 + 2302 + return ret; 2303 + } 2390 2304 2391 2305 /* 2392 2306 * Hotkeys ··· 2692 2484 brightness = __get_lcd_brightness(dev); 2693 2485 if (brightness < 0) 2694 2486 return 0; 2487 + /* 2488 + * If transflective backlight is supported and the brightness is zero 2489 + * (lowest brightness level), the set_lcd_brightness function will 2490 + * activate the transflective backlight, making the LCD appear to be 2491 + * turned off, simply increment the brightness level to avoid that. 2492 + */ 2493 + if (dev->tr_backlight_supported && brightness == 0) 2494 + brightness++; 2695 2495 ret = set_lcd_brightness(dev, brightness); 2696 2496 if (ret) { 2697 2497 pr_debug("Backlight method is read-only, disabling backlight support\n"); ··· 2777 2561 pr_cont(" panel-power-on"); 2778 2562 if (dev->usb_three_supported) 2779 2563 pr_cont(" usb3"); 2564 + if (dev->wwan_supported) 2565 + pr_cont(" wwan"); 2780 2566 2781 2567 pr_cont("\n"); 2782 2568 } ··· 2815 2597 2816 2598 if (dev->eco_led_registered) 2817 2599 led_classdev_unregister(&dev->eco_led); 2600 + 2601 + if (dev->wwan_rfk) { 2602 + rfkill_unregister(dev->wwan_rfk); 2603 + rfkill_destroy(dev->wwan_rfk); 2604 + } 2818 2605 2819 2606 if (toshiba_acpi) 2820 2607 toshiba_acpi = NULL; ··· 2959 2736 ret = get_fan_status(dev, &dummy); 2960 2737 dev->fan_supported = !ret; 2961 2738 2739 + toshiba_wwan_available(dev); 2740 + if (dev->wwan_supported) 2741 + toshiba_acpi_setup_wwan_rfkill(dev); 2742 + 2962 2743 print_supported_features(dev); 2963 2744 2964 2745 ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, ··· 2987 2760 static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2988 2761 { 2989 2762 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2990 - int ret; 2991 2763 2992 2764 switch (event) { 2993 2765 case 0x80: /* Hotkeys and some system events */ ··· 3016 2790 pr_info("SATA power event received %x\n", event); 3017 2791 break; 3018 2792 case 0x92: /* Keyboard backlight mode changed */ 2793 + toshiba_acpi->kbd_event_generated = true; 3019 2794 /* Update sysfs entries */ 3020 - ret = sysfs_update_group(&acpi_dev->dev.kobj, 3021 - &toshiba_attr_group); 3022 - if (ret) 2795 + if (sysfs_update_group(&acpi_dev->dev.kobj, 2796 + &toshiba_attr_group)) 3023 2797 pr_err("Unable to update sysfs entries\n"); 3024 2798 break; 3025 2799 case 0x85: /* Unknown */ ··· 3034 2808 3035 2809 acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 3036 2810 dev_name(&acpi_dev->dev), 3037 - event, 0); 2811 + event, (event == 0x80) ? 2812 + dev->last_key_event : 0); 3038 2813 } 3039 2814 3040 2815 #ifdef CONFIG_PM_SLEEP ··· 3059 2832 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 3060 2833 3061 2834 if (dev->hotkey_dev) { 3062 - int error = toshiba_acpi_enable_hotkeys(dev); 3063 - 3064 - if (error) 2835 + if (toshiba_acpi_enable_hotkeys(dev)) 3065 2836 pr_info("Unable to re-enable hotkeys\n"); 2837 + } 2838 + 2839 + if (dev->wwan_rfk) { 2840 + if (!toshiba_wireless_status(dev)) 2841 + rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 3066 2842 } 3067 2843 3068 2844 return 0;
+1 -1
drivers/platform/x86/toshiba_bluetooth.c
··· 78 78 */ 79 79 result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present); 80 80 if (ACPI_FAILURE(result)) { 81 - pr_err("ACPI call to query Bluetooth presence failed"); 81 + pr_err("ACPI call to query Bluetooth presence failed\n"); 82 82 return -ENXIO; 83 83 } else if (!bt_present) { 84 84 pr_info("Bluetooth device not present\n");