From: Kate Hsuan Date: Fri, 20 Aug 2021 11:04:46 +0000 (+0300) Subject: platform/x86: intel_telemetry: Move to intel sub-directory X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=2b6cb8f2e88b416393d2b34cad51bfe6e1aae8a7;p=linux.git platform/x86: intel_telemetry: Move to intel sub-directory Move Intel telemetry driver to intel sub-directory to improve readability. While at it, spell APL fully in the Kconfig. Signed-off-by: Kate Hsuan Reviewed-by: Hans de Goede Signed-off-by: Andy Shevchenko Reviewed-by: Rajneesh Bhardwaj Link: https://lore.kernel.org/r/20210820110458.73018-9-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- diff --git a/MAINTAINERS b/MAINTAINERS index eefe4edb1b3dc..bb0fcf309cc8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9559,7 +9559,7 @@ M: "David E. Box" L: platform-driver-x86@vger.kernel.org S: Maintained F: arch/x86/include/asm/intel_telemetry.h -F: drivers/platform/x86/intel_telemetry* +F: drivers/platform/x86/intel/telemetry/ INTEL UNCORE FREQUENCY CONTROL M: Srinivas Pandruvada diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index aed7570388ef1..4e42ebac88921 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1206,18 +1206,6 @@ config INTEL_SCU_IPC_UTIL low level access for debug work and updating the firmware. Say N unless you will be doing this on an Intel MID platform. -config INTEL_TELEMETRY - tristate "Intel SoC Telemetry Driver" - depends on X86_64 - depends on MFD_INTEL_PMC_BXT - depends on INTEL_PUNIT_IPC - help - This driver provides interfaces to configure and use - telemetry for INTEL SoC from APL onwards. It is also - used to get various SoC events and parameters - directly via debugfs files. Various tools may use - this interface for SoC state monitoring. - endif # X86_PLATFORM_DEVICES config PMC_ATOM diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 1668f73608339..bde20c13ceac1 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -132,7 +132,4 @@ obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o obj-$(CONFIG_INTEL_SCU_PLATFORM) += intel_scu_pltdrv.o obj-$(CONFIG_INTEL_SCU_WDT) += intel_scu_wdt.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o -obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ - intel_telemetry_pltdrv.o \ - intel_telemetry_debugfs.o obj-$(CONFIG_PMC_ATOM) += pmc_atom.o diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index 7de11636904d9..379d9e425cc7a 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -21,6 +21,7 @@ source "drivers/platform/x86/intel/int33fe/Kconfig" source "drivers/platform/x86/intel/int3472/Kconfig" source "drivers/platform/x86/intel/pmc/Kconfig" source "drivers/platform/x86/intel/pmt/Kconfig" +source "drivers/platform/x86/intel/telemetry/Kconfig" config INTEL_BXTWC_PMIC_TMU tristate "Intel Broxton Whiskey Cove TMU Driver" diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index a1555a1e421d8..e8c2b1249f87e 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_INTEL_CHT_INT33FE) += int33fe/ obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/ obj-$(CONFIG_INTEL_PMC_CORE) += pmc/ obj-$(CONFIG_INTEL_PMT_CLASS) += pmt/ +obj-$(CONFIG_INTEL_TELEMETRY) += telemetry/ # Intel PMIC / PMC / P-Unit drivers intel_bxtwc_tmu-y := bxtwc_tmu.o diff --git a/drivers/platform/x86/intel/telemetry/Kconfig b/drivers/platform/x86/intel/telemetry/Kconfig new file mode 100644 index 0000000000000..da887bd037315 --- /dev/null +++ b/drivers/platform/x86/intel/telemetry/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Intel x86 Platform Specific Drivers +# + +config INTEL_TELEMETRY + tristate "Intel SoC Telemetry driver" + depends on X86_64 + depends on MFD_INTEL_PMC_BXT + depends on INTEL_PUNIT_IPC + help + This driver provides interfaces to configure and use + telemetry for Intel SoC from Apollo Lake onwards. + It is also used to get various SoC events and parameters + directly via debugfs files. Various tools may use + this interface for SoC state monitoring. diff --git a/drivers/platform/x86/intel/telemetry/Makefile b/drivers/platform/x86/intel/telemetry/Makefile new file mode 100644 index 0000000000000..bfdba5b6c59ad --- /dev/null +++ b/drivers/platform/x86/intel/telemetry/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Intel x86 Platform Specific Drivers +# + +intel_telemetry_core-y := core.o +obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o +intel_telemetry_pltdrv-y := pltdrv.o +obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_pltdrv.o +intel_telemetry_debugfs-y := debugfs.o +obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_debugfs.o diff --git a/drivers/platform/x86/intel/telemetry/core.c b/drivers/platform/x86/intel/telemetry/core.c new file mode 100644 index 0000000000000..fdf55b5d69480 --- /dev/null +++ b/drivers/platform/x86/intel/telemetry/core.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel SoC Core Telemetry Driver + * Copyright (C) 2015, Intel Corporation. + * All Rights Reserved. + * + * Telemetry Framework provides platform related PM and performance statistics. + * This file provides the core telemetry API implementation. + */ +#include +#include + +#include + +#define DRIVER_NAME "intel_telemetry_core" + +struct telemetry_core_config { + struct telemetry_plt_config *plt_config; + const struct telemetry_core_ops *telem_ops; +}; + +static struct telemetry_core_config telm_core_conf; + +static int telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig, + struct telemetry_evtconfig ioss_evtconfig) +{ + return 0; +} + +static int telemetry_def_set_sampling_period(u8 pss_period, u8 ioss_period) +{ + return 0; +} + +static int telemetry_def_get_sampling_period(u8 *pss_min_period, + u8 *pss_max_period, + u8 *ioss_min_period, + u8 *ioss_max_period) +{ + return 0; +} + +static int telemetry_def_get_eventconfig( + struct telemetry_evtconfig *pss_evtconfig, + struct telemetry_evtconfig *ioss_evtconfig, + int pss_len, int ioss_len) +{ + return 0; +} + +static int telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit, + u32 *verbosity) +{ + return 0; +} + + +static int telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit, + u32 verbosity) +{ + return 0; +} + +static int telemetry_def_raw_read_eventlog(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, + int len, int log_all_evts) +{ + return 0; +} + +static int telemetry_def_read_eventlog(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, + int len, int log_all_evts) +{ + return 0; +} + +static int telemetry_def_add_events(u8 num_pss_evts, u8 num_ioss_evts, + u32 *pss_evtmap, u32 *ioss_evtmap) +{ + return 0; +} + +static int telemetry_def_reset_events(void) +{ + return 0; +} + +static const struct telemetry_core_ops telm_defpltops = { + .set_sampling_period = telemetry_def_set_sampling_period, + .get_sampling_period = telemetry_def_get_sampling_period, + .get_trace_verbosity = telemetry_def_get_trace_verbosity, + .set_trace_verbosity = telemetry_def_set_trace_verbosity, + .raw_read_eventlog = telemetry_def_raw_read_eventlog, + .get_eventconfig = telemetry_def_get_eventconfig, + .read_eventlog = telemetry_def_read_eventlog, + .update_events = telemetry_def_update_events, + .reset_events = telemetry_def_reset_events, + .add_events = telemetry_def_add_events, +}; + +/** + * telemetry_update_events() - Update telemetry Configuration + * @pss_evtconfig: PSS related config. No change if num_evts = 0. + * @pss_evtconfig: IOSS related config. No change if num_evts = 0. + * + * This API updates the IOSS & PSS Telemetry configuration. Old config + * is overwritten. Call telemetry_reset_events when logging is over + * All sample period values should be in the form of: + * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) + * + * Return: 0 success, < 0 for failure + */ +int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig, + struct telemetry_evtconfig ioss_evtconfig) +{ + return telm_core_conf.telem_ops->update_events(pss_evtconfig, + ioss_evtconfig); +} +EXPORT_SYMBOL_GPL(telemetry_update_events); + + +/** + * telemetry_set_sampling_period() - Sets the IOSS & PSS sampling period + * @pss_period: placeholder for PSS Period to be set. + * Set to 0 if not required to be updated + * @ioss_period: placeholder for IOSS Period to be set + * Set to 0 if not required to be updated + * + * All values should be in the form of: + * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) + * + * Return: 0 success, < 0 for failure + */ +int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period) +{ + return telm_core_conf.telem_ops->set_sampling_period(pss_period, + ioss_period); +} +EXPORT_SYMBOL_GPL(telemetry_set_sampling_period); + +/** + * telemetry_get_sampling_period() - Get IOSS & PSS min & max sampling period + * @pss_min_period: placeholder for PSS Min Period supported + * @pss_max_period: placeholder for PSS Max Period supported + * @ioss_min_period: placeholder for IOSS Min Period supported + * @ioss_max_period: placeholder for IOSS Max Period supported + * + * All values should be in the form of: + * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) + * + * Return: 0 success, < 0 for failure + */ +int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period, + u8 *ioss_min_period, u8 *ioss_max_period) +{ + return telm_core_conf.telem_ops->get_sampling_period(pss_min_period, + pss_max_period, + ioss_min_period, + ioss_max_period); +} +EXPORT_SYMBOL_GPL(telemetry_get_sampling_period); + + +/** + * telemetry_reset_events() - Restore the IOSS & PSS configuration to default + * + * Return: 0 success, < 0 for failure + */ +int telemetry_reset_events(void) +{ + return telm_core_conf.telem_ops->reset_events(); +} +EXPORT_SYMBOL_GPL(telemetry_reset_events); + +/** + * telemetry_get_eventconfig() - Returns the pss and ioss events enabled + * @pss_evtconfig: Pointer to PSS related configuration. + * @pss_evtconfig: Pointer to IOSS related configuration. + * @pss_len: Number of u32 elements allocated for pss_evtconfig array + * @ioss_len: Number of u32 elements allocated for ioss_evtconfig array + * + * Return: 0 success, < 0 for failure + */ +int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_evtconfig, + struct telemetry_evtconfig *ioss_evtconfig, + int pss_len, int ioss_len) +{ + return telm_core_conf.telem_ops->get_eventconfig(pss_evtconfig, + ioss_evtconfig, + pss_len, ioss_len); +} +EXPORT_SYMBOL_GPL(telemetry_get_eventconfig); + +/** + * telemetry_add_events() - Add IOSS & PSS configuration to existing settings. + * @num_pss_evts: Number of PSS Events (<29) in pss_evtmap. Can be 0. + * @num_ioss_evts: Number of IOSS Events (<29) in ioss_evtmap. Can be 0. + * @pss_evtmap: Array of PSS Event-IDs to Enable + * @ioss_evtmap: Array of PSS Event-IDs to Enable + * + * Events are appended to Old Configuration. In case of total events > 28, it + * returns error. Call telemetry_reset_events to reset after eventlog done + * + * Return: 0 success, < 0 for failure + */ +int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts, + u32 *pss_evtmap, u32 *ioss_evtmap) +{ + return telm_core_conf.telem_ops->add_events(num_pss_evts, + num_ioss_evts, pss_evtmap, + ioss_evtmap); +} +EXPORT_SYMBOL_GPL(telemetry_add_events); + +/** + * telemetry_read_events() - Fetches samples as specified by evtlog.telem_evt_id + * @telem_unit: Specify whether IOSS or PSS Read + * @evtlog: Array of telemetry_evtlog structs to fill data + * evtlog.telem_evt_id specifies the ids to read + * @len: Length of array of evtlog + * + * Return: number of eventlogs read for success, < 0 for failure + */ +int telemetry_read_events(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, int len) +{ + return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog, + len, 0); +} +EXPORT_SYMBOL_GPL(telemetry_read_events); + +/** + * telemetry_raw_read_events() - Fetch samples specified by evtlog.telem_evt_id + * @telem_unit: Specify whether IOSS or PSS Read + * @evtlog: Array of telemetry_evtlog structs to fill data + * evtlog.telem_evt_id specifies the ids to read + * @len: Length of array of evtlog + * + * The caller must take care of locking in this case. + * + * Return: number of eventlogs read for success, < 0 for failure + */ +int telemetry_raw_read_events(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, int len) +{ + return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog, + len, 0); +} +EXPORT_SYMBOL_GPL(telemetry_raw_read_events); + +/** + * telemetry_read_eventlog() - Fetch the Telemetry log from PSS or IOSS + * @telem_unit: Specify whether IOSS or PSS Read + * @evtlog: Array of telemetry_evtlog structs to fill data + * @len: Length of array of evtlog + * + * Return: number of eventlogs read for success, < 0 for failure + */ +int telemetry_read_eventlog(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, int len) +{ + return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog, + len, 1); +} +EXPORT_SYMBOL_GPL(telemetry_read_eventlog); + +/** + * telemetry_raw_read_eventlog() - Fetch the Telemetry log from PSS or IOSS + * @telem_unit: Specify whether IOSS or PSS Read + * @evtlog: Array of telemetry_evtlog structs to fill data + * @len: Length of array of evtlog + * + * The caller must take care of locking in this case. + * + * Return: number of eventlogs read for success, < 0 for failure + */ +int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, int len) +{ + return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog, + len, 1); +} +EXPORT_SYMBOL_GPL(telemetry_raw_read_eventlog); + + +/** + * telemetry_get_trace_verbosity() - Get the IOSS & PSS Trace verbosity + * @telem_unit: Specify whether IOSS or PSS Read + * @verbosity: Pointer to return Verbosity + * + * Return: 0 success, < 0 for failure + */ +int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit, + u32 *verbosity) +{ + return telm_core_conf.telem_ops->get_trace_verbosity(telem_unit, + verbosity); +} +EXPORT_SYMBOL_GPL(telemetry_get_trace_verbosity); + + +/** + * telemetry_set_trace_verbosity() - Update the IOSS & PSS Trace verbosity + * @telem_unit: Specify whether IOSS or PSS Read + * @verbosity: Verbosity to set + * + * Return: 0 success, < 0 for failure + */ +int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit, u32 verbosity) +{ + return telm_core_conf.telem_ops->set_trace_verbosity(telem_unit, + verbosity); +} +EXPORT_SYMBOL_GPL(telemetry_set_trace_verbosity); + +/** + * telemetry_set_pltdata() - Set the platform specific Data + * @ops: Pointer to ops structure + * @pltconfig: Platform config data + * + * Usage by other than telemetry pltdrv module is invalid + * + * Return: 0 success, < 0 for failure + */ +int telemetry_set_pltdata(const struct telemetry_core_ops *ops, + struct telemetry_plt_config *pltconfig) +{ + if (ops) + telm_core_conf.telem_ops = ops; + + if (pltconfig) + telm_core_conf.plt_config = pltconfig; + + return 0; +} +EXPORT_SYMBOL_GPL(telemetry_set_pltdata); + +/** + * telemetry_clear_pltdata() - Clear the platform specific Data + * + * Usage by other than telemetry pltdrv module is invalid + * + * Return: 0 success, < 0 for failure + */ +int telemetry_clear_pltdata(void) +{ + telm_core_conf.telem_ops = &telm_defpltops; + telm_core_conf.plt_config = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(telemetry_clear_pltdata); + +/** + * telemetry_get_pltdata() - Return telemetry platform config + * + * May be used by other telemetry modules to get platform specific + * configuration. + */ +struct telemetry_plt_config *telemetry_get_pltdata(void) +{ + return telm_core_conf.plt_config; +} +EXPORT_SYMBOL_GPL(telemetry_get_pltdata); + +static inline int telemetry_get_pssevtname(enum telemetry_unit telem_unit, + const char **name, int len) +{ + struct telemetry_unit_config psscfg; + int i; + + if (!telm_core_conf.plt_config) + return -EINVAL; + + psscfg = telm_core_conf.plt_config->pss_config; + + if (len > psscfg.ssram_evts_used) + len = psscfg.ssram_evts_used; + + for (i = 0; i < len; i++) + name[i] = psscfg.telem_evts[i].name; + + return 0; +} + +static inline int telemetry_get_iossevtname(enum telemetry_unit telem_unit, + const char **name, int len) +{ + struct telemetry_unit_config iosscfg; + int i; + + if (!(telm_core_conf.plt_config)) + return -EINVAL; + + iosscfg = telm_core_conf.plt_config->ioss_config; + + if (len > iosscfg.ssram_evts_used) + len = iosscfg.ssram_evts_used; + + for (i = 0; i < len; i++) + name[i] = iosscfg.telem_evts[i].name; + + return 0; + +} + +/** + * telemetry_get_evtname() - Checkif platform config is valid + * @telem_unit: Telemetry Unit to check + * @name: Array of character pointers to contain name + * @len: length of array name provided by user + * + * Usage by other than telemetry debugfs module is invalid + * + * Return: 0 success, < 0 for failure + */ +int telemetry_get_evtname(enum telemetry_unit telem_unit, + const char **name, int len) +{ + int ret = -EINVAL; + + if (telem_unit == TELEM_PSS) + ret = telemetry_get_pssevtname(telem_unit, name, len); + + else if (telem_unit == TELEM_IOSS) + ret = telemetry_get_iossevtname(telem_unit, name, len); + + return ret; +} +EXPORT_SYMBOL_GPL(telemetry_get_evtname); + +static int __init telemetry_module_init(void) +{ + pr_info(pr_fmt(DRIVER_NAME) " Init\n"); + + telm_core_conf.telem_ops = &telm_defpltops; + return 0; +} + +static void __exit telemetry_module_exit(void) +{ +} + +module_init(telemetry_module_init); +module_exit(telemetry_module_exit); + +MODULE_AUTHOR("Souvik Kumar Chakravarty "); +MODULE_DESCRIPTION("Intel SoC Telemetry Interface"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel/telemetry/debugfs.c b/drivers/platform/x86/intel/telemetry/debugfs.c new file mode 100644 index 0000000000000..1d4d0fbfd63cc --- /dev/null +++ b/drivers/platform/x86/intel/telemetry/debugfs.c @@ -0,0 +1,961 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel SOC Telemetry debugfs Driver: Currently supports APL + * Copyright (c) 2015, Intel Corporation. + * All Rights Reserved. + * + * This file provides the debugfs interfaces for telemetry. + * /sys/kernel/debug/telemetry/pss_info: Shows Primary Control Sub-Sys Counters + * /sys/kernel/debug/telemetry/ioss_info: Shows IO Sub-System Counters + * /sys/kernel/debug/telemetry/soc_states: Shows SoC State + * /sys/kernel/debug/telemetry/pss_trace_verbosity: Read and Change Tracing + * Verbosity via firmware + * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing + * Verbosity via firmware + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DRIVER_NAME "telemetry_soc_debugfs" +#define DRIVER_VERSION "1.0.0" + +/* ApolloLake SoC Event-IDs */ +#define TELEM_APL_PSS_PSTATES_ID 0x2802 +#define TELEM_APL_PSS_IDLE_ID 0x2806 +#define TELEM_APL_PCS_IDLE_BLOCKED_ID 0x2C00 +#define TELEM_APL_PCS_S0IX_BLOCKED_ID 0x2C01 +#define TELEM_APL_PSS_WAKEUP_ID 0x2C02 +#define TELEM_APL_PSS_LTR_BLOCKING_ID 0x2C03 + +#define TELEM_APL_S0IX_TOTAL_OCC_ID 0x4000 +#define TELEM_APL_S0IX_SHLW_OCC_ID 0x4001 +#define TELEM_APL_S0IX_DEEP_OCC_ID 0x4002 +#define TELEM_APL_S0IX_TOTAL_RES_ID 0x4800 +#define TELEM_APL_S0IX_SHLW_RES_ID 0x4801 +#define TELEM_APL_S0IX_DEEP_RES_ID 0x4802 +#define TELEM_APL_D0IX_ID 0x581A +#define TELEM_APL_D3_ID 0x5819 +#define TELEM_APL_PG_ID 0x5818 + +#define TELEM_INFO_SRAMEVTS_MASK 0xFF00 +#define TELEM_INFO_SRAMEVTS_SHIFT 0x8 +#define TELEM_SSRAM_READ_TIMEOUT 10 + +#define TELEM_MASK_BIT 1 +#define TELEM_MASK_BYTE 0xFF +#define BYTES_PER_LONG 8 +#define TELEM_APL_MASK_PCS_STATE 0xF + +/* Max events in bitmap to check for */ +#define TELEM_PSS_IDLE_EVTS 25 +#define TELEM_PSS_IDLE_BLOCKED_EVTS 20 +#define TELEM_PSS_S0IX_BLOCKED_EVTS 20 +#define TELEM_PSS_S0IX_WAKEUP_EVTS 20 +#define TELEM_PSS_LTR_BLOCKING_EVTS 20 +#define TELEM_IOSS_DX_D0IX_EVTS 25 +#define TELEM_IOSS_PG_EVTS 30 + +#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \ + if (evtlog[index].telem_evtid == (EVTID)) { \ + for (idx = 0; idx < (EVTNUM); idx++) \ + (BUF)[idx] = ((EVTLOG) >> (EVTDAT)[idx].bit_pos) & \ + (MASK); \ + continue; \ + } \ +} + +#define TELEM_CHECK_AND_PARSE_CTRS(EVTID, CTR) { \ + if (evtlog[index].telem_evtid == (EVTID)) { \ + (CTR) = evtlog[index].telem_evtlog; \ + continue; \ + } \ +} + +static u8 suspend_prep_ok; +static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp; +static u64 suspend_shlw_res_temp, suspend_deep_res_temp; + +struct telemetry_susp_stats { + u32 shlw_ctr; + u32 deep_ctr; + u64 shlw_res; + u64 deep_res; +}; + +/* Bitmap definitions for default counters in APL */ +struct telem_pss_idle_stateinfo { + const char *name; + u32 bit_pos; +}; + +static struct telem_pss_idle_stateinfo telem_apl_pss_idle_data[] = { + {"IA_CORE0_C1E", 0}, + {"IA_CORE1_C1E", 1}, + {"IA_CORE2_C1E", 2}, + {"IA_CORE3_C1E", 3}, + {"IA_CORE0_C6", 16}, + {"IA_CORE1_C6", 17}, + {"IA_CORE2_C6", 18}, + {"IA_CORE3_C6", 19}, + {"IA_MODULE0_C7", 32}, + {"IA_MODULE1_C7", 33}, + {"GT_RC6", 40}, + {"IUNIT_PROCESSING_IDLE", 41}, + {"FAR_MEM_IDLE", 43}, + {"DISPLAY_IDLE", 44}, + {"IUNIT_INPUT_SYSTEM_IDLE", 45}, + {"PCS_STATUS", 60}, +}; + +struct telem_pcs_blkd_info { + const char *name; + u32 bit_pos; +}; + +static struct telem_pcs_blkd_info telem_apl_pcs_idle_blkd_data[] = { + {"COMPUTE", 0}, + {"MISC", 8}, + {"MODULE_ACTIONS_PENDING", 16}, + {"LTR", 24}, + {"DISPLAY_WAKE", 32}, + {"ISP_WAKE", 40}, + {"PSF0_ACTIVE", 48}, +}; + +static struct telem_pcs_blkd_info telem_apl_pcs_s0ix_blkd_data[] = { + {"LTR", 0}, + {"IRTL", 8}, + {"WAKE_DEADLINE_PENDING", 16}, + {"DISPLAY", 24}, + {"ISP", 32}, + {"CORE", 40}, + {"PMC", 48}, + {"MISC", 56}, +}; + +struct telem_pss_ltr_info { + const char *name; + u32 bit_pos; +}; + +static struct telem_pss_ltr_info telem_apl_pss_ltr_data[] = { + {"CORE_ACTIVE", 0}, + {"MEM_UP", 8}, + {"DFX", 16}, + {"DFX_FORCE_LTR", 24}, + {"DISPLAY", 32}, + {"ISP", 40}, + {"SOUTH", 48}, +}; + +struct telem_pss_wakeup_info { + const char *name; + u32 bit_pos; +}; + +static struct telem_pss_wakeup_info telem_apl_pss_wakeup[] = { + {"IP_IDLE", 0}, + {"DISPLAY_WAKE", 8}, + {"VOLTAGE_REG_INT", 16}, + {"DROWSY_TIMER (HOTPLUG)", 24}, + {"CORE_WAKE", 32}, + {"MISC_S0IX", 40}, + {"MISC_ABORT", 56}, +}; + +struct telem_ioss_d0ix_stateinfo { + const char *name; + u32 bit_pos; +}; + +static struct telem_ioss_d0ix_stateinfo telem_apl_ioss_d0ix_data[] = { + {"CSE", 0}, + {"SCC2", 1}, + {"GMM", 2}, + {"XDCI", 3}, + {"XHCI", 4}, + {"ISH", 5}, + {"AVS", 6}, + {"PCIE0P1", 7}, + {"PECI0P0", 8}, + {"LPSS", 9}, + {"SCC", 10}, + {"PWM", 11}, + {"PCIE1_P3", 12}, + {"PCIE1_P2", 13}, + {"PCIE1_P1", 14}, + {"PCIE1_P0", 15}, + {"CNV", 16}, + {"SATA", 17}, + {"PRTC", 18}, +}; + +struct telem_ioss_pg_info { + const char *name; + u32 bit_pos; +}; + +static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = { + {"LPSS", 0}, + {"SCC", 1}, + {"P2SB", 2}, + {"SCC2", 3}, + {"GMM", 4}, + {"PCIE0", 5}, + {"XDCI", 6}, + {"xHCI", 7}, + {"CSE", 8}, + {"SPI", 9}, + {"AVSPGD4", 10}, + {"AVSPGD3", 11}, + {"AVSPGD2", 12}, + {"AVSPGD1", 13}, + {"ISH", 14}, + {"EXI", 15}, + {"NPKVRC", 16}, + {"NPKVNN", 17}, + {"CUNIT", 18}, + {"FUSE_CTRL", 19}, + {"PCIE1", 20}, + {"CNV", 21}, + {"LPC", 22}, + {"SATA", 23}, + {"SMB", 24}, + {"PRTC", 25}, +}; + +struct telemetry_debugfs_conf { + struct telemetry_susp_stats suspend_stats; + struct dentry *telemetry_dbg_dir; + + /* Bitmap Data */ + struct telem_ioss_d0ix_stateinfo *ioss_d0ix_data; + struct telem_pss_idle_stateinfo *pss_idle_data; + struct telem_pcs_blkd_info *pcs_idle_blkd_data; + struct telem_pcs_blkd_info *pcs_s0ix_blkd_data; + struct telem_pss_wakeup_info *pss_wakeup; + struct telem_pss_ltr_info *pss_ltr_data; + struct telem_ioss_pg_info *ioss_pg_data; + u8 pcs_idle_blkd_evts; + u8 pcs_s0ix_blkd_evts; + u8 pss_wakeup_evts; + u8 pss_idle_evts; + u8 pss_ltr_evts; + u8 ioss_d0ix_evts; + u8 ioss_pg_evts; + + /* IDs */ + u16 pss_ltr_blocking_id; + u16 pcs_idle_blkd_id; + u16 pcs_s0ix_blkd_id; + u16 s0ix_total_occ_id; + u16 s0ix_shlw_occ_id; + u16 s0ix_deep_occ_id; + u16 s0ix_total_res_id; + u16 s0ix_shlw_res_id; + u16 s0ix_deep_res_id; + u16 pss_wakeup_id; + u16 ioss_d0ix_id; + u16 pstates_id; + u16 pss_idle_id; + u16 ioss_d3_id; + u16 ioss_pg_id; +}; + +static struct telemetry_debugfs_conf *debugfs_conf; + +static struct telemetry_debugfs_conf telem_apl_debugfs_conf = { + .pss_idle_data = telem_apl_pss_idle_data, + .pcs_idle_blkd_data = telem_apl_pcs_idle_blkd_data, + .pcs_s0ix_blkd_data = telem_apl_pcs_s0ix_blkd_data, + .pss_ltr_data = telem_apl_pss_ltr_data, + .pss_wakeup = telem_apl_pss_wakeup, + .ioss_d0ix_data = telem_apl_ioss_d0ix_data, + .ioss_pg_data = telem_apl_ioss_pg_data, + + .pss_idle_evts = ARRAY_SIZE(telem_apl_pss_idle_data), + .pcs_idle_blkd_evts = ARRAY_SIZE(telem_apl_pcs_idle_blkd_data), + .pcs_s0ix_blkd_evts = ARRAY_SIZE(telem_apl_pcs_s0ix_blkd_data), + .pss_ltr_evts = ARRAY_SIZE(telem_apl_pss_ltr_data), + .pss_wakeup_evts = ARRAY_SIZE(telem_apl_pss_wakeup), + .ioss_d0ix_evts = ARRAY_SIZE(telem_apl_ioss_d0ix_data), + .ioss_pg_evts = ARRAY_SIZE(telem_apl_ioss_pg_data), + + .pstates_id = TELEM_APL_PSS_PSTATES_ID, + .pss_idle_id = TELEM_APL_PSS_IDLE_ID, + .pcs_idle_blkd_id = TELEM_APL_PCS_IDLE_BLOCKED_ID, + .pcs_s0ix_blkd_id = TELEM_APL_PCS_S0IX_BLOCKED_ID, + .pss_wakeup_id = TELEM_APL_PSS_WAKEUP_ID, + .pss_ltr_blocking_id = TELEM_APL_PSS_LTR_BLOCKING_ID, + .s0ix_total_occ_id = TELEM_APL_S0IX_TOTAL_OCC_ID, + .s0ix_shlw_occ_id = TELEM_APL_S0IX_SHLW_OCC_ID, + .s0ix_deep_occ_id = TELEM_APL_S0IX_DEEP_OCC_ID, + .s0ix_total_res_id = TELEM_APL_S0IX_TOTAL_RES_ID, + .s0ix_shlw_res_id = TELEM_APL_S0IX_SHLW_RES_ID, + .s0ix_deep_res_id = TELEM_APL_S0IX_DEEP_RES_ID, + .ioss_d0ix_id = TELEM_APL_D0IX_ID, + .ioss_d3_id = TELEM_APL_D3_ID, + .ioss_pg_id = TELEM_APL_PG_ID, +}; + +static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = { + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &telem_apl_debugfs_conf), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &telem_apl_debugfs_conf), + {} +}; +MODULE_DEVICE_TABLE(x86cpu, telemetry_debugfs_cpu_ids); + +static int telemetry_debugfs_check_evts(void) +{ + if ((debugfs_conf->pss_idle_evts > TELEM_PSS_IDLE_EVTS) || + (debugfs_conf->pcs_idle_blkd_evts > TELEM_PSS_IDLE_BLOCKED_EVTS) || + (debugfs_conf->pcs_s0ix_blkd_evts > TELEM_PSS_S0IX_BLOCKED_EVTS) || + (debugfs_conf->pss_ltr_evts > TELEM_PSS_LTR_BLOCKING_EVTS) || + (debugfs_conf->pss_wakeup_evts > TELEM_PSS_S0IX_WAKEUP_EVTS) || + (debugfs_conf->ioss_d0ix_evts > TELEM_IOSS_DX_D0IX_EVTS) || + (debugfs_conf->ioss_pg_evts > TELEM_IOSS_PG_EVTS)) + return -EINVAL; + + return 0; +} + +static int telem_pss_states_show(struct seq_file *s, void *unused) +{ + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; + struct telemetry_debugfs_conf *conf = debugfs_conf; + const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS]; + u32 pcs_idle_blkd[TELEM_PSS_IDLE_BLOCKED_EVTS], + pcs_s0ix_blkd[TELEM_PSS_S0IX_BLOCKED_EVTS], + pss_s0ix_wakeup[TELEM_PSS_S0IX_WAKEUP_EVTS], + pss_ltr_blkd[TELEM_PSS_LTR_BLOCKING_EVTS], + pss_idle[TELEM_PSS_IDLE_EVTS]; + int index, idx, ret, err = 0; + u64 pstates = 0; + + ret = telemetry_read_eventlog(TELEM_PSS, evtlog, + TELEM_MAX_OS_ALLOCATED_EVENTS); + if (ret < 0) + return ret; + + err = telemetry_get_evtname(TELEM_PSS, name, + TELEM_MAX_OS_ALLOCATED_EVENTS); + if (err < 0) + return err; + + seq_puts(s, "\n----------------------------------------------------\n"); + seq_puts(s, "\tPSS TELEM EVENTLOG (Residency = field/19.2 us\n"); + seq_puts(s, "----------------------------------------------------\n"); + for (index = 0; index < ret; index++) { + seq_printf(s, "%-32s %llu\n", + name[index], evtlog[index].telem_evtlog); + + /* Fetch PSS IDLE State */ + if (evtlog[index].telem_evtid == conf->pss_idle_id) { + pss_idle[conf->pss_idle_evts - 1] = + (evtlog[index].telem_evtlog >> + conf->pss_idle_data[conf->pss_idle_evts - 1].bit_pos) & + TELEM_APL_MASK_PCS_STATE; + } + + TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id, + conf->pss_idle_evts - 1, + pss_idle, evtlog[index].telem_evtlog, + conf->pss_idle_data, TELEM_MASK_BIT); + + TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_idle_blkd_id, + conf->pcs_idle_blkd_evts, + pcs_idle_blkd, + evtlog[index].telem_evtlog, + conf->pcs_idle_blkd_data, + TELEM_MASK_BYTE); + + TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_s0ix_blkd_id, + conf->pcs_s0ix_blkd_evts, + pcs_s0ix_blkd, + evtlog[index].telem_evtlog, + conf->pcs_s0ix_blkd_data, + TELEM_MASK_BYTE); + + TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id, + conf->pss_wakeup_evts, + pss_s0ix_wakeup, + evtlog[index].telem_evtlog, + conf->pss_wakeup, TELEM_MASK_BYTE); + + TELEM_CHECK_AND_PARSE_EVTS(conf->pss_ltr_blocking_id, + conf->pss_ltr_evts, pss_ltr_blkd, + evtlog[index].telem_evtlog, + conf->pss_ltr_data, TELEM_MASK_BYTE); + + if (evtlog[index].telem_evtid == debugfs_conf->pstates_id) + pstates = evtlog[index].telem_evtlog; + } + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "PStates\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Domain\t\t\t\tFreq(Mhz)\n"); + seq_printf(s, " IA\t\t\t\t %llu\n GT\t\t\t\t %llu\n", + (pstates & TELEM_MASK_BYTE)*100, + ((pstates >> 8) & TELEM_MASK_BYTE)*50/3); + + seq_printf(s, " IUNIT\t\t\t\t %llu\n SA\t\t\t\t %llu\n", + ((pstates >> 16) & TELEM_MASK_BYTE)*25, + ((pstates >> 24) & TELEM_MASK_BYTE)*50/3); + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "PSS IDLE Status\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Device\t\t\t\t\tIDLE\n"); + for (index = 0; index < debugfs_conf->pss_idle_evts; index++) { + seq_printf(s, "%-32s\t%u\n", + debugfs_conf->pss_idle_data[index].name, + pss_idle[index]); + } + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "PSS Idle blkd Status (~1ms saturating bucket)\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Blocker\t\t\t\t\tCount\n"); + for (index = 0; index < debugfs_conf->pcs_idle_blkd_evts; index++) { + seq_printf(s, "%-32s\t%u\n", + debugfs_conf->pcs_idle_blkd_data[index].name, + pcs_idle_blkd[index]); + } + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "PSS S0ix blkd Status (~1ms saturating bucket)\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Blocker\t\t\t\t\tCount\n"); + for (index = 0; index < debugfs_conf->pcs_s0ix_blkd_evts; index++) { + seq_printf(s, "%-32s\t%u\n", + debugfs_conf->pcs_s0ix_blkd_data[index].name, + pcs_s0ix_blkd[index]); + } + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "LTR Blocking Status (~1ms saturating bucket)\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Blocker\t\t\t\t\tCount\n"); + for (index = 0; index < debugfs_conf->pss_ltr_evts; index++) { + seq_printf(s, "%-32s\t%u\n", + debugfs_conf->pss_ltr_data[index].name, + pss_s0ix_wakeup[index]); + } + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "Wakes Status (~1ms saturating bucket)\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Wakes\t\t\t\t\tCount\n"); + for (index = 0; index < debugfs_conf->pss_wakeup_evts; index++) { + seq_printf(s, "%-32s\t%u\n", + debugfs_conf->pss_wakeup[index].name, + pss_ltr_blkd[index]); + } + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(telem_pss_states); + +static int telem_ioss_states_show(struct seq_file *s, void *unused) +{ + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; + const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS]; + int index, ret, err; + + ret = telemetry_read_eventlog(TELEM_IOSS, evtlog, + TELEM_MAX_OS_ALLOCATED_EVENTS); + if (ret < 0) + return ret; + + err = telemetry_get_evtname(TELEM_IOSS, name, + TELEM_MAX_OS_ALLOCATED_EVENTS); + if (err < 0) + return err; + + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "\tI0SS TELEMETRY EVENTLOG\n"); + seq_puts(s, "--------------------------------------\n"); + for (index = 0; index < ret; index++) { + seq_printf(s, "%-32s 0x%llx\n", + name[index], evtlog[index].telem_evtlog); + } + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(telem_ioss_states); + +static int telem_soc_states_show(struct seq_file *s, void *unused) +{ + u32 d3_sts[TELEM_IOSS_DX_D0IX_EVTS], d0ix_sts[TELEM_IOSS_DX_D0IX_EVTS]; + u32 pg_sts[TELEM_IOSS_PG_EVTS], pss_idle[TELEM_PSS_IDLE_EVTS]; + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; + u32 s0ix_total_ctr = 0, s0ix_shlw_ctr = 0, s0ix_deep_ctr = 0; + u64 s0ix_total_res = 0, s0ix_shlw_res = 0, s0ix_deep_res = 0; + struct telemetry_debugfs_conf *conf = debugfs_conf; + struct pci_dev *dev = NULL; + int index, idx, ret; + u32 d3_state; + u16 pmcsr; + + ret = telemetry_read_eventlog(TELEM_IOSS, evtlog, + TELEM_MAX_OS_ALLOCATED_EVENTS); + if (ret < 0) + return ret; + + for (index = 0; index < ret; index++) { + TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d3_id, + conf->ioss_d0ix_evts, + d3_sts, evtlog[index].telem_evtlog, + conf->ioss_d0ix_data, + TELEM_MASK_BIT); + + TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_pg_id, conf->ioss_pg_evts, + pg_sts, evtlog[index].telem_evtlog, + conf->ioss_pg_data, TELEM_MASK_BIT); + + TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d0ix_id, + conf->ioss_d0ix_evts, + d0ix_sts, evtlog[index].telem_evtlog, + conf->ioss_d0ix_data, + TELEM_MASK_BIT); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_occ_id, + s0ix_total_ctr); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, + s0ix_shlw_ctr); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, + s0ix_deep_ctr); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_res_id, + s0ix_total_res); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, + s0ix_shlw_res); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, + s0ix_deep_res); + } + + seq_puts(s, "\n---------------------------------------------------\n"); + seq_puts(s, "S0IX Type\t\t\t Occurrence\t\t Residency(us)\n"); + seq_puts(s, "---------------------------------------------------\n"); + + seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n", + s0ix_shlw_ctr - + conf->suspend_stats.shlw_ctr, + (u64)((s0ix_shlw_res - + conf->suspend_stats.shlw_res)*10/192)); + + seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n", + s0ix_deep_ctr - + conf->suspend_stats.deep_ctr, + (u64)((s0ix_deep_res - + conf->suspend_stats.deep_res)*10/192)); + + seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n", + conf->suspend_stats.shlw_ctr, + (u64)(conf->suspend_stats.shlw_res*10)/192); + + seq_printf(s, "Suspend(With S0ixDeep)\t\t %10u\t %10llu\n", + conf->suspend_stats.deep_ctr, + (u64)(conf->suspend_stats.deep_res*10)/192); + + seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr, + (u64)(s0ix_total_res*10/192)); + seq_puts(s, "\n-------------------------------------------------\n"); + seq_puts(s, "\t\tDEVICE STATES\n"); + seq_puts(s, "-------------------------------------------------\n"); + + for_each_pci_dev(dev) { + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + d3_state = ((pmcsr & PCI_PM_CTRL_STATE_MASK) == + (__force int)PCI_D3hot) ? 1 : 0; + + seq_printf(s, "pci %04x %04X %s %20.20s: ", + dev->vendor, dev->device, dev_name(&dev->dev), + dev_driver_string(&dev->dev)); + seq_printf(s, " d3:%x\n", d3_state); + } + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "D3/D0i3 Status\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Block\t\t D3\t D0i3\n"); + for (index = 0; index < conf->ioss_d0ix_evts; index++) { + seq_printf(s, "%-10s\t %u\t %u\n", + conf->ioss_d0ix_data[index].name, + d3_sts[index], d0ix_sts[index]); + } + + seq_puts(s, "\n--------------------------------------\n"); + seq_puts(s, "South Complex PowerGate Status\n"); + seq_puts(s, "--------------------------------------\n"); + seq_puts(s, "Device\t\t PG\n"); + for (index = 0; index < conf->ioss_pg_evts; index++) { + seq_printf(s, "%-10s\t %u\n", + conf->ioss_pg_data[index].name, + pg_sts[index]); + } + + evtlog->telem_evtid = conf->pss_idle_id; + ret = telemetry_read_events(TELEM_PSS, evtlog, 1); + if (ret < 0) + return ret; + + seq_puts(s, "\n-----------------------------------------\n"); + seq_puts(s, "North Idle Status\n"); + seq_puts(s, "-----------------------------------------\n"); + for (idx = 0; idx < conf->pss_idle_evts - 1; idx++) { + pss_idle[idx] = (evtlog->telem_evtlog >> + conf->pss_idle_data[idx].bit_pos) & + TELEM_MASK_BIT; + } + + pss_idle[idx] = (evtlog->telem_evtlog >> + conf->pss_idle_data[idx].bit_pos) & + TELEM_APL_MASK_PCS_STATE; + + for (index = 0; index < conf->pss_idle_evts; index++) { + seq_printf(s, "%-30s %u\n", + conf->pss_idle_data[index].name, + pss_idle[index]); + } + + seq_puts(s, "\nPCS_STATUS Code\n"); + seq_puts(s, "0:C0 1:C1 2:C1_DN_WT_DEV 3:C2 4:C2_WT_DE_MEM_UP\n"); + seq_puts(s, "5:C2_WT_DE_MEM_DOWN 6:C2_UP_WT_DEV 7:C2_DN 8:C2_VOA\n"); + seq_puts(s, "9:C2_VOA_UP 10:S0IX_PRE 11:S0IX\n"); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(telem_soc_states); + +static int telem_s0ix_res_get(void *data, u64 *val) +{ + struct telemetry_plt_config *plt_config = telemetry_get_pltdata(); + u64 s0ix_total_res; + int ret; + + ret = intel_pmc_s0ix_counter_read(plt_config->pmc, &s0ix_total_res); + if (ret) { + pr_err("Failed to read S0ix residency"); + return ret; + } + + *val = s0ix_total_res; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(telem_s0ix_fops, telem_s0ix_res_get, NULL, "%llu\n"); + +static int telem_pss_trc_verb_show(struct seq_file *s, void *unused) +{ + u32 verbosity; + int err; + + err = telemetry_get_trace_verbosity(TELEM_PSS, &verbosity); + if (err) { + pr_err("Get PSS Trace Verbosity Failed with Error %d\n", err); + return -EFAULT; + } + + seq_printf(s, "PSS Trace Verbosity %u\n", verbosity); + return 0; +} + +static ssize_t telem_pss_trc_verb_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + u32 verbosity; + int err; + + err = kstrtou32_from_user(userbuf, count, 0, &verbosity); + if (err) + return err; + + err = telemetry_set_trace_verbosity(TELEM_PSS, verbosity); + if (err) { + pr_err("Changing PSS Trace Verbosity Failed. Error %d\n", err); + return err; + } + + return count; +} + +static int telem_pss_trc_verb_open(struct inode *inode, struct file *file) +{ + return single_open(file, telem_pss_trc_verb_show, inode->i_private); +} + +static const struct file_operations telem_pss_trc_verb_ops = { + .open = telem_pss_trc_verb_open, + .read = seq_read, + .write = telem_pss_trc_verb_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused) +{ + u32 verbosity; + int err; + + err = telemetry_get_trace_verbosity(TELEM_IOSS, &verbosity); + if (err) { + pr_err("Get IOSS Trace Verbosity Failed with Error %d\n", err); + return -EFAULT; + } + + seq_printf(s, "IOSS Trace Verbosity %u\n", verbosity); + return 0; +} + +static ssize_t telem_ioss_trc_verb_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + u32 verbosity; + int err; + + err = kstrtou32_from_user(userbuf, count, 0, &verbosity); + if (err) + return err; + + err = telemetry_set_trace_verbosity(TELEM_IOSS, verbosity); + if (err) { + pr_err("Changing IOSS Trace Verbosity Failed. Error %d\n", err); + return err; + } + + return count; +} + +static int telem_ioss_trc_verb_open(struct inode *inode, struct file *file) +{ + return single_open(file, telem_ioss_trc_verb_show, inode->i_private); +} + +static const struct file_operations telem_ioss_trc_verb_ops = { + .open = telem_ioss_trc_verb_open, + .read = seq_read, + .write = telem_ioss_trc_verb_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int pm_suspend_prep_cb(void) +{ + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; + struct telemetry_debugfs_conf *conf = debugfs_conf; + int ret, index; + + ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog, + TELEM_MAX_OS_ALLOCATED_EVENTS); + if (ret < 0) { + suspend_prep_ok = 0; + goto out; + } + + for (index = 0; index < ret; index++) { + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, + suspend_shlw_ctr_temp); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, + suspend_deep_ctr_temp); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, + suspend_shlw_res_temp); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, + suspend_deep_res_temp); + } + suspend_prep_ok = 1; +out: + return NOTIFY_OK; +} + +static int pm_suspend_exit_cb(void) +{ + struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; + static u32 suspend_shlw_ctr_exit, suspend_deep_ctr_exit; + static u64 suspend_shlw_res_exit, suspend_deep_res_exit; + struct telemetry_debugfs_conf *conf = debugfs_conf; + int ret, index; + + if (!suspend_prep_ok) + goto out; + + ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog, + TELEM_MAX_OS_ALLOCATED_EVENTS); + if (ret < 0) + goto out; + + for (index = 0; index < ret; index++) { + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, + suspend_shlw_ctr_exit); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, + suspend_deep_ctr_exit); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, + suspend_shlw_res_exit); + + TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, + suspend_deep_res_exit); + } + + if ((suspend_shlw_ctr_exit < suspend_shlw_ctr_temp) || + (suspend_deep_ctr_exit < suspend_deep_ctr_temp) || + (suspend_shlw_res_exit < suspend_shlw_res_temp) || + (suspend_deep_res_exit < suspend_deep_res_temp)) { + pr_err("Wrong s0ix counters detected\n"); + goto out; + } + + /* + * Due to some design limitations in the firmware, sometimes the + * counters do not get updated by the time we reach here. As a + * workaround, we try to see if this was a genuine case of sleep + * failure or not by cross-checking from PMC GCR registers directly. + */ + if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp && + suspend_deep_ctr_exit == suspend_deep_ctr_temp) { + struct telemetry_plt_config *plt_config = telemetry_get_pltdata(); + struct intel_pmc_dev *pmc = plt_config->pmc; + + ret = intel_pmc_gcr_read64(pmc, PMC_GCR_TELEM_SHLW_S0IX_REG, + &suspend_shlw_res_exit); + if (ret < 0) + goto out; + + ret = intel_pmc_gcr_read64(pmc, PMC_GCR_TELEM_DEEP_S0IX_REG, + &suspend_deep_res_exit); + if (ret < 0) + goto out; + + if (suspend_shlw_res_exit > suspend_shlw_res_temp) + suspend_shlw_ctr_exit++; + + if (suspend_deep_res_exit > suspend_deep_res_temp) + suspend_deep_ctr_exit++; + } + + suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp; + suspend_deep_ctr_exit -= suspend_deep_ctr_temp; + suspend_shlw_res_exit -= suspend_shlw_res_temp; + suspend_deep_res_exit -= suspend_deep_res_temp; + + if (suspend_shlw_ctr_exit != 0) { + conf->suspend_stats.shlw_ctr += + suspend_shlw_ctr_exit; + + conf->suspend_stats.shlw_res += + suspend_shlw_res_exit; + } + + if (suspend_deep_ctr_exit != 0) { + conf->suspend_stats.deep_ctr += + suspend_deep_ctr_exit; + + conf->suspend_stats.deep_res += + suspend_deep_res_exit; + } + +out: + suspend_prep_ok = 0; + return NOTIFY_OK; +} + +static int pm_notification(struct notifier_block *this, + unsigned long event, void *ptr) +{ + switch (event) { + case PM_SUSPEND_PREPARE: + return pm_suspend_prep_cb(); + case PM_POST_SUSPEND: + return pm_suspend_exit_cb(); + } + + return NOTIFY_DONE; +} + +static struct notifier_block pm_notifier = { + .notifier_call = pm_notification, +}; + +static int __init telemetry_debugfs_init(void) +{ + const struct x86_cpu_id *id; + int err; + struct dentry *dir; + + /* Only APL supported for now */ + id = x86_match_cpu(telemetry_debugfs_cpu_ids); + if (!id) + return -ENODEV; + + debugfs_conf = (struct telemetry_debugfs_conf *)id->driver_data; + + if (!telemetry_get_pltdata()) { + pr_info("Invalid pltconfig, ensure IPC1 device is enabled in BIOS\n"); + return -ENODEV; + } + + err = telemetry_debugfs_check_evts(); + if (err < 0) { + pr_info("telemetry_debugfs_check_evts failed\n"); + return -EINVAL; + } + + register_pm_notifier(&pm_notifier); + + dir = debugfs_create_dir("telemetry", NULL); + debugfs_conf->telemetry_dbg_dir = dir; + + debugfs_create_file("pss_info", S_IFREG | S_IRUGO, dir, NULL, + &telem_pss_states_fops); + debugfs_create_file("ioss_info", S_IFREG | S_IRUGO, dir, NULL, + &telem_ioss_states_fops); + debugfs_create_file("soc_states", S_IFREG | S_IRUGO, dir, NULL, + &telem_soc_states_fops); + debugfs_create_file("s0ix_residency_usec", S_IFREG | S_IRUGO, dir, NULL, + &telem_s0ix_fops); + debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO, dir, NULL, + &telem_pss_trc_verb_ops); + debugfs_create_file("ioss_trace_verbosity", S_IFREG | S_IRUGO, dir, + NULL, &telem_ioss_trc_verb_ops); + return 0; +} + +static void __exit telemetry_debugfs_exit(void) +{ + debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir); + debugfs_conf->telemetry_dbg_dir = NULL; + unregister_pm_notifier(&pm_notifier); +} + +late_initcall(telemetry_debugfs_init); +module_exit(telemetry_debugfs_exit); + +MODULE_AUTHOR("Souvik Kumar Chakravarty "); +MODULE_DESCRIPTION("Intel SoC Telemetry debugfs Interface"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel/telemetry/pltdrv.c b/drivers/platform/x86/intel/telemetry/pltdrv.c new file mode 100644 index 0000000000000..405dea87de6bf --- /dev/null +++ b/drivers/platform/x86/intel/telemetry/pltdrv.c @@ -0,0 +1,1189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel SOC Telemetry Platform Driver: Currently supports APL + * Copyright (c) 2015, Intel Corporation. + * All Rights Reserved. + * + * This file provides the platform specific telemetry implementation for APL. + * It used the PUNIT and PMC IPC interfaces for configuring the counters. + * The accumulated results are fetched from SRAM. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define DRIVER_NAME "intel_telemetry" +#define DRIVER_VERSION "1.0.0" + +#define TELEM_TRC_VERBOSITY_MASK 0x3 + +#define TELEM_MIN_PERIOD(x) ((x) & 0x7F0000) +#define TELEM_MAX_PERIOD(x) ((x) & 0x7F000000) +#define TELEM_SAMPLE_PERIOD_INVALID(x) ((x) & (BIT(7))) +#define TELEM_CLEAR_SAMPLE_PERIOD(x) ((x) &= ~0x7F) + +#define TELEM_SAMPLING_DEFAULT_PERIOD 0xD + +#define TELEM_MAX_EVENTS_SRAM 28 +#define TELEM_SSRAM_STARTTIME_OFFSET 8 +#define TELEM_SSRAM_EVTLOG_OFFSET 16 + +#define IOSS_TELEM 0xeb +#define IOSS_TELEM_EVENT_READ 0x0 +#define IOSS_TELEM_EVENT_WRITE 0x1 +#define IOSS_TELEM_INFO_READ 0x2 +#define IOSS_TELEM_TRACE_CTL_READ 0x5 +#define IOSS_TELEM_TRACE_CTL_WRITE 0x6 +#define IOSS_TELEM_EVENT_CTL_READ 0x7 +#define IOSS_TELEM_EVENT_CTL_WRITE 0x8 +#define IOSS_TELEM_EVT_WRITE_SIZE 0x3 + +#define TELEM_INFO_SRAMEVTS_MASK 0xFF00 +#define TELEM_INFO_SRAMEVTS_SHIFT 0x8 +#define TELEM_SSRAM_READ_TIMEOUT 10 + +#define TELEM_INFO_NENABLES_MASK 0xFF +#define TELEM_EVENT_ENABLE 0x8000 + +#define TELEM_MASK_BIT 1 +#define TELEM_MASK_BYTE 0xFF +#define BYTES_PER_LONG 8 +#define TELEM_MASK_PCS_STATE 0xF + +#define TELEM_DISABLE(x) ((x) &= ~(BIT(31))) +#define TELEM_CLEAR_EVENTS(x) ((x) |= (BIT(30))) +#define TELEM_ENABLE_SRAM_EVT_TRACE(x) ((x) &= ~(BIT(30) | BIT(24))) +#define TELEM_ENABLE_PERIODIC(x) ((x) |= (BIT(23) | BIT(31) | BIT(7))) +#define TELEM_EXTRACT_VERBOSITY(x, y) ((y) = (((x) >> 27) & 0x3)) +#define TELEM_CLEAR_VERBOSITY_BITS(x) ((x) &= ~(BIT(27) | BIT(28))) +#define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27)) + +enum telemetry_action { + TELEM_UPDATE = 0, + TELEM_ADD, + TELEM_RESET, + TELEM_ACTION_NONE +}; + +struct telem_ssram_region { + u64 timestamp; + u64 start_time; + u64 events[TELEM_MAX_EVENTS_SRAM]; +}; + +static struct telemetry_plt_config *telm_conf; + +/* + * The following counters are programmed by default during setup. + * Only 20 allocated to kernel driver + */ +static struct telemetry_evtmap + telemetry_apl_ioss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { + {"SOC_S0IX_TOTAL_RES", 0x4800}, + {"SOC_S0IX_TOTAL_OCC", 0x4000}, + {"SOC_S0IX_SHALLOW_RES", 0x4801}, + {"SOC_S0IX_SHALLOW_OCC", 0x4001}, + {"SOC_S0IX_DEEP_RES", 0x4802}, + {"SOC_S0IX_DEEP_OCC", 0x4002}, + {"PMC_POWER_GATE", 0x5818}, + {"PMC_D3_STATES", 0x5819}, + {"PMC_D0I3_STATES", 0x581A}, + {"PMC_S0IX_WAKE_REASON_GPIO", 0x6000}, + {"PMC_S0IX_WAKE_REASON_TIMER", 0x6001}, + {"PMC_S0IX_WAKE_REASON_VNNREQ", 0x6002}, + {"PMC_S0IX_WAKE_REASON_LOWPOWER", 0x6003}, + {"PMC_S0IX_WAKE_REASON_EXTERNAL", 0x6004}, + {"PMC_S0IX_WAKE_REASON_MISC", 0x6005}, + {"PMC_S0IX_BLOCKING_IPS_D3_D0I3", 0x6006}, + {"PMC_S0IX_BLOCKING_IPS_PG", 0x6007}, + {"PMC_S0IX_BLOCKING_MISC_IPS_PG", 0x6008}, + {"PMC_S0IX_BLOCK_IPS_VNN_REQ", 0x6009}, + {"PMC_S0IX_BLOCK_IPS_CLOCKS", 0x600B}, +}; + + +static struct telemetry_evtmap + telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { + {"IA_CORE0_C6_RES", 0x0400}, + {"IA_CORE0_C6_CTR", 0x0000}, + {"IA_MODULE0_C7_RES", 0x0410}, + {"IA_MODULE0_C7_CTR", 0x000E}, + {"IA_C0_RES", 0x0805}, + {"PCS_LTR", 0x2801}, + {"PSTATES", 0x2802}, + {"SOC_S0I3_RES", 0x0409}, + {"SOC_S0I3_CTR", 0x000A}, + {"PCS_S0I3_CTR", 0x0009}, + {"PCS_C1E_RES", 0x041A}, + {"PCS_IDLE_STATUS", 0x2806}, + {"IA_PERF_LIMITS", 0x280B}, + {"GT_PERF_LIMITS", 0x280C}, + {"PCS_WAKEUP_S0IX_CTR", 0x0030}, + {"PCS_IDLE_BLOCKED", 0x2C00}, + {"PCS_S0IX_BLOCKED", 0x2C01}, + {"PCS_S0IX_WAKE_REASONS", 0x2C02}, + {"PCS_LTR_BLOCKING", 0x2C03}, + {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40}, +}; + +static struct telemetry_evtmap + telemetry_glk_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { + {"IA_CORE0_C6_RES", 0x0400}, + {"IA_CORE0_C6_CTR", 0x0000}, + {"IA_MODULE0_C7_RES", 0x0410}, + {"IA_MODULE0_C7_CTR", 0x000C}, + {"IA_C0_RES", 0x0805}, + {"PCS_LTR", 0x2801}, + {"PSTATES", 0x2802}, + {"SOC_S0I3_RES", 0x0407}, + {"SOC_S0I3_CTR", 0x0008}, + {"PCS_S0I3_CTR", 0x0007}, + {"PCS_C1E_RES", 0x0414}, + {"PCS_IDLE_STATUS", 0x2806}, + {"IA_PERF_LIMITS", 0x280B}, + {"GT_PERF_LIMITS", 0x280C}, + {"PCS_WAKEUP_S0IX_CTR", 0x0025}, + {"PCS_IDLE_BLOCKED", 0x2C00}, + {"PCS_S0IX_BLOCKED", 0x2C01}, + {"PCS_S0IX_WAKE_REASONS", 0x2C02}, + {"PCS_LTR_BLOCKING", 0x2C03}, + {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40}, +}; + +/* APL specific Data */ +static struct telemetry_plt_config telem_apl_config = { + .pss_config = { + .telem_evts = telemetry_apl_pss_default_events, + }, + .ioss_config = { + .telem_evts = telemetry_apl_ioss_default_events, + }, +}; + +/* GLK specific Data */ +static struct telemetry_plt_config telem_glk_config = { + .pss_config = { + .telem_evts = telemetry_glk_pss_default_events, + }, + .ioss_config = { + .telem_evts = telemetry_apl_ioss_default_events, + }, +}; + +static const struct x86_cpu_id telemetry_cpu_ids[] = { + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &telem_apl_config), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &telem_glk_config), + {} +}; + +MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids); + +static inline int telem_get_unitconfig(enum telemetry_unit telem_unit, + struct telemetry_unit_config **unit_config) +{ + if (telem_unit == TELEM_PSS) + *unit_config = &(telm_conf->pss_config); + else if (telem_unit == TELEM_IOSS) + *unit_config = &(telm_conf->ioss_config); + else + return -EINVAL; + + return 0; + +} + +static int telemetry_check_evtid(enum telemetry_unit telem_unit, + u32 *evtmap, u8 len, + enum telemetry_action action) +{ + struct telemetry_unit_config *unit_config; + int ret; + + ret = telem_get_unitconfig(telem_unit, &unit_config); + if (ret < 0) + return ret; + + switch (action) { + case TELEM_RESET: + if (len > TELEM_MAX_EVENTS_SRAM) + return -EINVAL; + + break; + + case TELEM_UPDATE: + if (len > TELEM_MAX_EVENTS_SRAM) + return -EINVAL; + + if ((len > 0) && (evtmap == NULL)) + return -EINVAL; + + break; + + case TELEM_ADD: + if ((len + unit_config->ssram_evts_used) > + TELEM_MAX_EVENTS_SRAM) + return -EINVAL; + + if ((len > 0) && (evtmap == NULL)) + return -EINVAL; + + break; + + default: + pr_err("Unknown Telemetry action specified %d\n", action); + return -EINVAL; + } + + return 0; +} + + +static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index) +{ + u32 write_buf; + + write_buf = evt_id | TELEM_EVENT_ENABLE; + write_buf <<= BITS_PER_BYTE; + write_buf |= index; + + return intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, + IOSS_TELEM_EVENT_WRITE, &write_buf, + IOSS_TELEM_EVT_WRITE_SIZE, NULL, 0); +} + +static inline int telemetry_plt_config_pss_event(u32 evt_id, int index) +{ + u32 write_buf; + int ret; + + write_buf = evt_id | TELEM_EVENT_ENABLE; + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT, + index, 0, &write_buf, NULL); + + return ret; +} + +static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig, + enum telemetry_action action) +{ + struct intel_scu_ipc_dev *scu = telm_conf->scu; + u8 num_ioss_evts, ioss_period; + int ret, index, idx; + u32 *ioss_evtmap; + u32 telem_ctrl; + + num_ioss_evts = evtconfig.num_evts; + ioss_period = evtconfig.period; + ioss_evtmap = evtconfig.evtmap; + + /* Get telemetry EVENT CTL */ + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_READ, NULL, 0, + &telem_ctrl, sizeof(telem_ctrl)); + if (ret) { + pr_err("IOSS TELEM_CTRL Read Failed\n"); + return ret; + } + + /* Disable Telemetry */ + TELEM_DISABLE(telem_ctrl); + + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_WRITE, &telem_ctrl, + sizeof(telem_ctrl), NULL, 0); + if (ret) { + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); + return ret; + } + + + /* Reset Everything */ + if (action == TELEM_RESET) { + /* Clear All Events */ + TELEM_CLEAR_EVENTS(telem_ctrl); + + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_WRITE, + &telem_ctrl, sizeof(telem_ctrl), + NULL, 0); + if (ret) { + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); + return ret; + } + telm_conf->ioss_config.ssram_evts_used = 0; + + /* Configure Events */ + for (idx = 0; idx < num_ioss_evts; idx++) { + if (telemetry_plt_config_ioss_event( + telm_conf->ioss_config.telem_evts[idx].evt_id, + idx)) { + pr_err("IOSS TELEM_RESET Fail for data: %x\n", + telm_conf->ioss_config.telem_evts[idx].evt_id); + continue; + } + telm_conf->ioss_config.ssram_evts_used++; + } + } + + /* Re-Configure Everything */ + if (action == TELEM_UPDATE) { + /* Clear All Events */ + TELEM_CLEAR_EVENTS(telem_ctrl); + + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_WRITE, + &telem_ctrl, sizeof(telem_ctrl), + NULL, 0); + if (ret) { + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); + return ret; + } + telm_conf->ioss_config.ssram_evts_used = 0; + + /* Configure Events */ + for (index = 0; index < num_ioss_evts; index++) { + telm_conf->ioss_config.telem_evts[index].evt_id = + ioss_evtmap[index]; + + if (telemetry_plt_config_ioss_event( + telm_conf->ioss_config.telem_evts[index].evt_id, + index)) { + pr_err("IOSS TELEM_UPDATE Fail for Evt%x\n", + ioss_evtmap[index]); + continue; + } + telm_conf->ioss_config.ssram_evts_used++; + } + } + + /* Add some Events */ + if (action == TELEM_ADD) { + /* Configure Events */ + for (index = telm_conf->ioss_config.ssram_evts_used, idx = 0; + idx < num_ioss_evts; index++, idx++) { + telm_conf->ioss_config.telem_evts[index].evt_id = + ioss_evtmap[idx]; + + if (telemetry_plt_config_ioss_event( + telm_conf->ioss_config.telem_evts[index].evt_id, + index)) { + pr_err("IOSS TELEM_ADD Fail for Event %x\n", + ioss_evtmap[idx]); + continue; + } + telm_conf->ioss_config.ssram_evts_used++; + } + } + + /* Enable Periodic Telemetry Events and enable SRAM trace */ + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); + TELEM_ENABLE_PERIODIC(telem_ctrl); + telem_ctrl |= ioss_period; + + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_WRITE, + &telem_ctrl, sizeof(telem_ctrl), NULL, 0); + if (ret) { + pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n"); + return ret; + } + + telm_conf->ioss_config.curr_period = ioss_period; + + return 0; +} + + +static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig, + enum telemetry_action action) +{ + u8 num_pss_evts, pss_period; + int ret, index, idx; + u32 *pss_evtmap; + u32 telem_ctrl; + + num_pss_evts = evtconfig.num_evts; + pss_period = evtconfig.period; + pss_evtmap = evtconfig.evtmap; + + /* PSS Config */ + /* Get telemetry EVENT CTL */ + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL, + 0, 0, NULL, &telem_ctrl); + if (ret) { + pr_err("PSS TELEM_CTRL Read Failed\n"); + return ret; + } + + /* Disable Telemetry */ + TELEM_DISABLE(telem_ctrl); + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, + 0, 0, &telem_ctrl, NULL); + if (ret) { + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); + return ret; + } + + /* Reset Everything */ + if (action == TELEM_RESET) { + /* Clear All Events */ + TELEM_CLEAR_EVENTS(telem_ctrl); + + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, + 0, 0, &telem_ctrl, NULL); + if (ret) { + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); + return ret; + } + telm_conf->pss_config.ssram_evts_used = 0; + /* Configure Events */ + for (idx = 0; idx < num_pss_evts; idx++) { + if (telemetry_plt_config_pss_event( + telm_conf->pss_config.telem_evts[idx].evt_id, + idx)) { + pr_err("PSS TELEM_RESET Fail for Event %x\n", + telm_conf->pss_config.telem_evts[idx].evt_id); + continue; + } + telm_conf->pss_config.ssram_evts_used++; + } + } + + /* Re-Configure Everything */ + if (action == TELEM_UPDATE) { + /* Clear All Events */ + TELEM_CLEAR_EVENTS(telem_ctrl); + + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, + 0, 0, &telem_ctrl, NULL); + if (ret) { + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); + return ret; + } + telm_conf->pss_config.ssram_evts_used = 0; + + /* Configure Events */ + for (index = 0; index < num_pss_evts; index++) { + telm_conf->pss_config.telem_evts[index].evt_id = + pss_evtmap[index]; + + if (telemetry_plt_config_pss_event( + telm_conf->pss_config.telem_evts[index].evt_id, + index)) { + pr_err("PSS TELEM_UPDATE Fail for Event %x\n", + pss_evtmap[index]); + continue; + } + telm_conf->pss_config.ssram_evts_used++; + } + } + + /* Add some Events */ + if (action == TELEM_ADD) { + /* Configure Events */ + for (index = telm_conf->pss_config.ssram_evts_used, idx = 0; + idx < num_pss_evts; index++, idx++) { + + telm_conf->pss_config.telem_evts[index].evt_id = + pss_evtmap[idx]; + + if (telemetry_plt_config_pss_event( + telm_conf->pss_config.telem_evts[index].evt_id, + index)) { + pr_err("PSS TELEM_ADD Fail for Event %x\n", + pss_evtmap[idx]); + continue; + } + telm_conf->pss_config.ssram_evts_used++; + } + } + + /* Enable Periodic Telemetry Events and enable SRAM trace */ + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); + TELEM_ENABLE_PERIODIC(telem_ctrl); + telem_ctrl |= pss_period; + + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, + 0, 0, &telem_ctrl, NULL); + if (ret) { + pr_err("PSS TELEM_CTRL Event Enable Write Failed\n"); + return ret; + } + + telm_conf->pss_config.curr_period = pss_period; + + return 0; +} + +static int telemetry_setup_evtconfig(struct telemetry_evtconfig pss_evtconfig, + struct telemetry_evtconfig ioss_evtconfig, + enum telemetry_action action) +{ + int ret; + + mutex_lock(&(telm_conf->telem_lock)); + + if ((action == TELEM_UPDATE) && (telm_conf->telem_in_use)) { + ret = -EBUSY; + goto out; + } + + ret = telemetry_check_evtid(TELEM_PSS, pss_evtconfig.evtmap, + pss_evtconfig.num_evts, action); + if (ret) + goto out; + + ret = telemetry_check_evtid(TELEM_IOSS, ioss_evtconfig.evtmap, + ioss_evtconfig.num_evts, action); + if (ret) + goto out; + + if (ioss_evtconfig.num_evts) { + ret = telemetry_setup_iossevtconfig(ioss_evtconfig, action); + if (ret) + goto out; + } + + if (pss_evtconfig.num_evts) { + ret = telemetry_setup_pssevtconfig(pss_evtconfig, action); + if (ret) + goto out; + } + + if ((action == TELEM_UPDATE) || (action == TELEM_ADD)) + telm_conf->telem_in_use = true; + else + telm_conf->telem_in_use = false; + +out: + mutex_unlock(&(telm_conf->telem_lock)); + return ret; +} + +static int telemetry_setup(struct platform_device *pdev) +{ + struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; + u32 read_buf, events, event_regs; + int ret; + + ret = intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, + IOSS_TELEM_INFO_READ, NULL, 0, + &read_buf, sizeof(read_buf)); + if (ret) { + dev_err(&pdev->dev, "IOSS TELEM_INFO Read Failed\n"); + return ret; + } + + /* Get telemetry Info */ + events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >> + TELEM_INFO_SRAMEVTS_SHIFT; + event_regs = read_buf & TELEM_INFO_NENABLES_MASK; + if ((events < TELEM_MAX_EVENTS_SRAM) || + (event_regs < TELEM_MAX_EVENTS_SRAM)) { + dev_err(&pdev->dev, "IOSS:Insufficient Space for SRAM Trace\n"); + dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n", + events, event_regs); + return -ENOMEM; + } + + telm_conf->ioss_config.min_period = TELEM_MIN_PERIOD(read_buf); + telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf); + + /* PUNIT Mailbox Setup */ + ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0, + NULL, &read_buf); + if (ret) { + dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n"); + return ret; + } + + /* Get telemetry Info */ + events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >> + TELEM_INFO_SRAMEVTS_SHIFT; + event_regs = read_buf & TELEM_INFO_SRAMEVTS_MASK; + if ((events < TELEM_MAX_EVENTS_SRAM) || + (event_regs < TELEM_MAX_EVENTS_SRAM)) { + dev_err(&pdev->dev, "PSS:Insufficient Space for SRAM Trace\n"); + dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n", + events, event_regs); + return -ENOMEM; + } + + telm_conf->pss_config.min_period = TELEM_MIN_PERIOD(read_buf); + telm_conf->pss_config.max_period = TELEM_MAX_PERIOD(read_buf); + + pss_evtconfig.evtmap = NULL; + pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; + pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; + + ioss_evtconfig.evtmap = NULL; + ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; + ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; + + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, + TELEM_RESET); + if (ret) { + dev_err(&pdev->dev, "TELEMETRY Setup Failed\n"); + return ret; + } + return 0; +} + +static int telemetry_plt_update_events(struct telemetry_evtconfig pss_evtconfig, + struct telemetry_evtconfig ioss_evtconfig) +{ + int ret; + + if ((pss_evtconfig.num_evts > 0) && + (TELEM_SAMPLE_PERIOD_INVALID(pss_evtconfig.period))) { + pr_err("PSS Sampling Period Out of Range\n"); + return -EINVAL; + } + + if ((ioss_evtconfig.num_evts > 0) && + (TELEM_SAMPLE_PERIOD_INVALID(ioss_evtconfig.period))) { + pr_err("IOSS Sampling Period Out of Range\n"); + return -EINVAL; + } + + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, + TELEM_UPDATE); + if (ret) + pr_err("TELEMETRY Config Failed\n"); + + return ret; +} + + +static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period) +{ + u32 telem_ctrl = 0; + int ret = 0; + + mutex_lock(&(telm_conf->telem_lock)); + if (ioss_period) { + struct intel_scu_ipc_dev *scu = telm_conf->scu; + + if (TELEM_SAMPLE_PERIOD_INVALID(ioss_period)) { + pr_err("IOSS Sampling Period Out of Range\n"); + ret = -EINVAL; + goto out; + } + + /* Get telemetry EVENT CTL */ + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_READ, NULL, 0, + &telem_ctrl, sizeof(telem_ctrl)); + if (ret) { + pr_err("IOSS TELEM_CTRL Read Failed\n"); + goto out; + } + + /* Disable Telemetry */ + TELEM_DISABLE(telem_ctrl); + + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_WRITE, + &telem_ctrl, sizeof(telem_ctrl), + NULL, 0); + if (ret) { + pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); + goto out; + } + + /* Enable Periodic Telemetry Events and enable SRAM trace */ + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); + TELEM_ENABLE_PERIODIC(telem_ctrl); + telem_ctrl |= ioss_period; + + ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, + IOSS_TELEM_EVENT_CTL_WRITE, + &telem_ctrl, sizeof(telem_ctrl), + NULL, 0); + if (ret) { + pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n"); + goto out; + } + telm_conf->ioss_config.curr_period = ioss_period; + } + + if (pss_period) { + if (TELEM_SAMPLE_PERIOD_INVALID(pss_period)) { + pr_err("PSS Sampling Period Out of Range\n"); + ret = -EINVAL; + goto out; + } + + /* Get telemetry EVENT CTL */ + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL, + 0, 0, NULL, &telem_ctrl); + if (ret) { + pr_err("PSS TELEM_CTRL Read Failed\n"); + goto out; + } + + /* Disable Telemetry */ + TELEM_DISABLE(telem_ctrl); + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, + 0, 0, &telem_ctrl, NULL); + if (ret) { + pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); + goto out; + } + + /* Enable Periodic Telemetry Events and enable SRAM trace */ + TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); + TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); + TELEM_ENABLE_PERIODIC(telem_ctrl); + telem_ctrl |= pss_period; + + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, + 0, 0, &telem_ctrl, NULL); + if (ret) { + pr_err("PSS TELEM_CTRL Event Enable Write Failed\n"); + goto out; + } + telm_conf->pss_config.curr_period = pss_period; + } + +out: + mutex_unlock(&(telm_conf->telem_lock)); + return ret; +} + + +static int telemetry_plt_get_sampling_period(u8 *pss_min_period, + u8 *pss_max_period, + u8 *ioss_min_period, + u8 *ioss_max_period) +{ + *pss_min_period = telm_conf->pss_config.min_period; + *pss_max_period = telm_conf->pss_config.max_period; + *ioss_min_period = telm_conf->ioss_config.min_period; + *ioss_max_period = telm_conf->ioss_config.max_period; + + return 0; +} + + +static int telemetry_plt_reset_events(void) +{ + struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; + int ret; + + pss_evtconfig.evtmap = NULL; + pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; + pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; + + ioss_evtconfig.evtmap = NULL; + ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; + ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; + + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, + TELEM_RESET); + if (ret) + pr_err("TELEMETRY Reset Failed\n"); + + return ret; +} + + +static int telemetry_plt_get_eventconfig(struct telemetry_evtconfig *pss_config, + struct telemetry_evtconfig *ioss_config, + int pss_len, int ioss_len) +{ + u32 *pss_evtmap, *ioss_evtmap; + u32 index; + + pss_evtmap = pss_config->evtmap; + ioss_evtmap = ioss_config->evtmap; + + mutex_lock(&(telm_conf->telem_lock)); + pss_config->num_evts = telm_conf->pss_config.ssram_evts_used; + ioss_config->num_evts = telm_conf->ioss_config.ssram_evts_used; + + pss_config->period = telm_conf->pss_config.curr_period; + ioss_config->period = telm_conf->ioss_config.curr_period; + + if ((pss_len < telm_conf->pss_config.ssram_evts_used) || + (ioss_len < telm_conf->ioss_config.ssram_evts_used)) { + mutex_unlock(&(telm_conf->telem_lock)); + return -EINVAL; + } + + for (index = 0; index < telm_conf->pss_config.ssram_evts_used; + index++) { + pss_evtmap[index] = + telm_conf->pss_config.telem_evts[index].evt_id; + } + + for (index = 0; index < telm_conf->ioss_config.ssram_evts_used; + index++) { + ioss_evtmap[index] = + telm_conf->ioss_config.telem_evts[index].evt_id; + } + + mutex_unlock(&(telm_conf->telem_lock)); + return 0; +} + + +static int telemetry_plt_add_events(u8 num_pss_evts, u8 num_ioss_evts, + u32 *pss_evtmap, u32 *ioss_evtmap) +{ + struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; + int ret; + + pss_evtconfig.evtmap = pss_evtmap; + pss_evtconfig.num_evts = num_pss_evts; + pss_evtconfig.period = telm_conf->pss_config.curr_period; + + ioss_evtconfig.evtmap = ioss_evtmap; + ioss_evtconfig.num_evts = num_ioss_evts; + ioss_evtconfig.period = telm_conf->ioss_config.curr_period; + + ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, + TELEM_ADD); + if (ret) + pr_err("TELEMETRY ADD Failed\n"); + + return ret; +} + +static int telem_evtlog_read(enum telemetry_unit telem_unit, + struct telem_ssram_region *ssram_region, u8 len) +{ + struct telemetry_unit_config *unit_config; + u64 timestamp_prev, timestamp_next; + int ret, index, timeout = 0; + + ret = telem_get_unitconfig(telem_unit, &unit_config); + if (ret < 0) + return ret; + + if (len > unit_config->ssram_evts_used) + len = unit_config->ssram_evts_used; + + do { + timestamp_prev = readq(unit_config->regmap); + if (!timestamp_prev) { + pr_err("Ssram under update. Please Try Later\n"); + return -EBUSY; + } + + ssram_region->start_time = readq(unit_config->regmap + + TELEM_SSRAM_STARTTIME_OFFSET); + + for (index = 0; index < len; index++) { + ssram_region->events[index] = + readq(unit_config->regmap + TELEM_SSRAM_EVTLOG_OFFSET + + BYTES_PER_LONG*index); + } + + timestamp_next = readq(unit_config->regmap); + if (!timestamp_next) { + pr_err("Ssram under update. Please Try Later\n"); + return -EBUSY; + } + + if (timeout++ > TELEM_SSRAM_READ_TIMEOUT) { + pr_err("Timeout while reading Events\n"); + return -EBUSY; + } + + } while (timestamp_prev != timestamp_next); + + ssram_region->timestamp = timestamp_next; + + return len; +} + +static int telemetry_plt_raw_read_eventlog(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, + int len, int log_all_evts) +{ + int index, idx1, ret, readlen = len; + struct telem_ssram_region ssram_region; + struct telemetry_evtmap *evtmap; + + switch (telem_unit) { + case TELEM_PSS: + evtmap = telm_conf->pss_config.telem_evts; + break; + + case TELEM_IOSS: + evtmap = telm_conf->ioss_config.telem_evts; + break; + + default: + pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); + return -EINVAL; + } + + if (!log_all_evts) + readlen = TELEM_MAX_EVENTS_SRAM; + + ret = telem_evtlog_read(telem_unit, &ssram_region, readlen); + if (ret < 0) + return ret; + + /* Invalid evt-id array specified via length mismatch */ + if ((!log_all_evts) && (len > ret)) + return -EINVAL; + + if (log_all_evts) + for (index = 0; index < ret; index++) { + evtlog[index].telem_evtlog = ssram_region.events[index]; + evtlog[index].telem_evtid = evtmap[index].evt_id; + } + else + for (index = 0, readlen = 0; (index < ret) && (readlen < len); + index++) { + for (idx1 = 0; idx1 < len; idx1++) { + /* Elements matched */ + if (evtmap[index].evt_id == + evtlog[idx1].telem_evtid) { + evtlog[idx1].telem_evtlog = + ssram_region.events[index]; + readlen++; + + break; + } + } + } + + return readlen; +} + +static int telemetry_plt_read_eventlog(enum telemetry_unit telem_unit, + struct telemetry_evtlog *evtlog, int len, int log_all_evts) +{ + int ret; + + mutex_lock(&(telm_conf->telem_lock)); + ret = telemetry_plt_raw_read_eventlog(telem_unit, evtlog, + len, log_all_evts); + mutex_unlock(&(telm_conf->telem_lock)); + + return ret; +} + +static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit, + u32 *verbosity) +{ + u32 temp = 0; + int ret; + + if (verbosity == NULL) + return -EINVAL; + + mutex_lock(&(telm_conf->telem_trace_lock)); + switch (telem_unit) { + case TELEM_PSS: + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, + 0, 0, NULL, &temp); + if (ret) { + pr_err("PSS TRACE_CTRL Read Failed\n"); + goto out; + } + + break; + + case TELEM_IOSS: + ret = intel_scu_ipc_dev_command(telm_conf->scu, + IOSS_TELEM, IOSS_TELEM_TRACE_CTL_READ, + NULL, 0, &temp, sizeof(temp)); + if (ret) { + pr_err("IOSS TRACE_CTL Read Failed\n"); + goto out; + } + + break; + + default: + pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); + ret = -EINVAL; + break; + } + TELEM_EXTRACT_VERBOSITY(temp, *verbosity); + +out: + mutex_unlock(&(telm_conf->telem_trace_lock)); + return ret; +} + +static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit, + u32 verbosity) +{ + u32 temp = 0; + int ret; + + verbosity &= TELEM_TRC_VERBOSITY_MASK; + + mutex_lock(&(telm_conf->telem_trace_lock)); + switch (telem_unit) { + case TELEM_PSS: + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, + 0, 0, NULL, &temp); + if (ret) { + pr_err("PSS TRACE_CTRL Read Failed\n"); + goto out; + } + + TELEM_CLEAR_VERBOSITY_BITS(temp); + TELEM_SET_VERBOSITY_BITS(temp, verbosity); + + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL, + 0, 0, &temp, NULL); + if (ret) { + pr_err("PSS TRACE_CTRL Verbosity Set Failed\n"); + goto out; + } + break; + + case TELEM_IOSS: + ret = intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, + IOSS_TELEM_TRACE_CTL_READ, + NULL, 0, &temp, sizeof(temp)); + if (ret) { + pr_err("IOSS TRACE_CTL Read Failed\n"); + goto out; + } + + TELEM_CLEAR_VERBOSITY_BITS(temp); + TELEM_SET_VERBOSITY_BITS(temp, verbosity); + + ret = intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, + IOSS_TELEM_TRACE_CTL_WRITE, + &temp, sizeof(temp), NULL, 0); + if (ret) { + pr_err("IOSS TRACE_CTL Verbosity Set Failed\n"); + goto out; + } + break; + + default: + pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); + ret = -EINVAL; + break; + } + +out: + mutex_unlock(&(telm_conf->telem_trace_lock)); + return ret; +} + +static const struct telemetry_core_ops telm_pltops = { + .get_trace_verbosity = telemetry_plt_get_trace_verbosity, + .set_trace_verbosity = telemetry_plt_set_trace_verbosity, + .set_sampling_period = telemetry_plt_set_sampling_period, + .get_sampling_period = telemetry_plt_get_sampling_period, + .raw_read_eventlog = telemetry_plt_raw_read_eventlog, + .get_eventconfig = telemetry_plt_get_eventconfig, + .update_events = telemetry_plt_update_events, + .read_eventlog = telemetry_plt_read_eventlog, + .reset_events = telemetry_plt_reset_events, + .add_events = telemetry_plt_add_events, +}; + +static int telemetry_pltdrv_probe(struct platform_device *pdev) +{ + const struct x86_cpu_id *id; + void __iomem *mem; + int ret; + + id = x86_match_cpu(telemetry_cpu_ids); + if (!id) + return -ENODEV; + + telm_conf = (struct telemetry_plt_config *)id->driver_data; + + telm_conf->pmc = dev_get_drvdata(pdev->dev.parent); + + mem = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mem)) + return PTR_ERR(mem); + + telm_conf->pss_config.regmap = mem; + + mem = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(mem)) + return PTR_ERR(mem); + + telm_conf->ioss_config.regmap = mem; + + telm_conf->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); + if (!telm_conf->scu) { + ret = -EPROBE_DEFER; + goto out; + } + + mutex_init(&telm_conf->telem_lock); + mutex_init(&telm_conf->telem_trace_lock); + + ret = telemetry_setup(pdev); + if (ret) + goto out; + + ret = telemetry_set_pltdata(&telm_pltops, telm_conf); + if (ret) { + dev_err(&pdev->dev, "TELEMETRY Set Pltops Failed.\n"); + goto out; + } + + return 0; + +out: + dev_err(&pdev->dev, "TELEMETRY Setup Failed.\n"); + + return ret; +} + +static int telemetry_pltdrv_remove(struct platform_device *pdev) +{ + telemetry_clear_pltdata(); + return 0; +} + +static struct platform_driver telemetry_soc_driver = { + .probe = telemetry_pltdrv_probe, + .remove = telemetry_pltdrv_remove, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init telemetry_module_init(void) +{ + return platform_driver_register(&telemetry_soc_driver); +} + +static void __exit telemetry_module_exit(void) +{ + platform_driver_unregister(&telemetry_soc_driver); +} + +device_initcall(telemetry_module_init); +module_exit(telemetry_module_exit); + +MODULE_AUTHOR("Souvik Kumar Chakravarty "); +MODULE_DESCRIPTION("Intel SoC Telemetry Platform Driver"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel_telemetry_core.c b/drivers/platform/x86/intel_telemetry_core.c deleted file mode 100644 index fdf55b5d69480..0000000000000 --- a/drivers/platform/x86/intel_telemetry_core.c +++ /dev/null @@ -1,450 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel SoC Core Telemetry Driver - * Copyright (C) 2015, Intel Corporation. - * All Rights Reserved. - * - * Telemetry Framework provides platform related PM and performance statistics. - * This file provides the core telemetry API implementation. - */ -#include -#include - -#include - -#define DRIVER_NAME "intel_telemetry_core" - -struct telemetry_core_config { - struct telemetry_plt_config *plt_config; - const struct telemetry_core_ops *telem_ops; -}; - -static struct telemetry_core_config telm_core_conf; - -static int telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig, - struct telemetry_evtconfig ioss_evtconfig) -{ - return 0; -} - -static int telemetry_def_set_sampling_period(u8 pss_period, u8 ioss_period) -{ - return 0; -} - -static int telemetry_def_get_sampling_period(u8 *pss_min_period, - u8 *pss_max_period, - u8 *ioss_min_period, - u8 *ioss_max_period) -{ - return 0; -} - -static int telemetry_def_get_eventconfig( - struct telemetry_evtconfig *pss_evtconfig, - struct telemetry_evtconfig *ioss_evtconfig, - int pss_len, int ioss_len) -{ - return 0; -} - -static int telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit, - u32 *verbosity) -{ - return 0; -} - - -static int telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit, - u32 verbosity) -{ - return 0; -} - -static int telemetry_def_raw_read_eventlog(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, - int len, int log_all_evts) -{ - return 0; -} - -static int telemetry_def_read_eventlog(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, - int len, int log_all_evts) -{ - return 0; -} - -static int telemetry_def_add_events(u8 num_pss_evts, u8 num_ioss_evts, - u32 *pss_evtmap, u32 *ioss_evtmap) -{ - return 0; -} - -static int telemetry_def_reset_events(void) -{ - return 0; -} - -static const struct telemetry_core_ops telm_defpltops = { - .set_sampling_period = telemetry_def_set_sampling_period, - .get_sampling_period = telemetry_def_get_sampling_period, - .get_trace_verbosity = telemetry_def_get_trace_verbosity, - .set_trace_verbosity = telemetry_def_set_trace_verbosity, - .raw_read_eventlog = telemetry_def_raw_read_eventlog, - .get_eventconfig = telemetry_def_get_eventconfig, - .read_eventlog = telemetry_def_read_eventlog, - .update_events = telemetry_def_update_events, - .reset_events = telemetry_def_reset_events, - .add_events = telemetry_def_add_events, -}; - -/** - * telemetry_update_events() - Update telemetry Configuration - * @pss_evtconfig: PSS related config. No change if num_evts = 0. - * @pss_evtconfig: IOSS related config. No change if num_evts = 0. - * - * This API updates the IOSS & PSS Telemetry configuration. Old config - * is overwritten. Call telemetry_reset_events when logging is over - * All sample period values should be in the form of: - * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) - * - * Return: 0 success, < 0 for failure - */ -int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig, - struct telemetry_evtconfig ioss_evtconfig) -{ - return telm_core_conf.telem_ops->update_events(pss_evtconfig, - ioss_evtconfig); -} -EXPORT_SYMBOL_GPL(telemetry_update_events); - - -/** - * telemetry_set_sampling_period() - Sets the IOSS & PSS sampling period - * @pss_period: placeholder for PSS Period to be set. - * Set to 0 if not required to be updated - * @ioss_period: placeholder for IOSS Period to be set - * Set to 0 if not required to be updated - * - * All values should be in the form of: - * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) - * - * Return: 0 success, < 0 for failure - */ -int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period) -{ - return telm_core_conf.telem_ops->set_sampling_period(pss_period, - ioss_period); -} -EXPORT_SYMBOL_GPL(telemetry_set_sampling_period); - -/** - * telemetry_get_sampling_period() - Get IOSS & PSS min & max sampling period - * @pss_min_period: placeholder for PSS Min Period supported - * @pss_max_period: placeholder for PSS Max Period supported - * @ioss_min_period: placeholder for IOSS Min Period supported - * @ioss_max_period: placeholder for IOSS Max Period supported - * - * All values should be in the form of: - * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent) - * - * Return: 0 success, < 0 for failure - */ -int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period, - u8 *ioss_min_period, u8 *ioss_max_period) -{ - return telm_core_conf.telem_ops->get_sampling_period(pss_min_period, - pss_max_period, - ioss_min_period, - ioss_max_period); -} -EXPORT_SYMBOL_GPL(telemetry_get_sampling_period); - - -/** - * telemetry_reset_events() - Restore the IOSS & PSS configuration to default - * - * Return: 0 success, < 0 for failure - */ -int telemetry_reset_events(void) -{ - return telm_core_conf.telem_ops->reset_events(); -} -EXPORT_SYMBOL_GPL(telemetry_reset_events); - -/** - * telemetry_get_eventconfig() - Returns the pss and ioss events enabled - * @pss_evtconfig: Pointer to PSS related configuration. - * @pss_evtconfig: Pointer to IOSS related configuration. - * @pss_len: Number of u32 elements allocated for pss_evtconfig array - * @ioss_len: Number of u32 elements allocated for ioss_evtconfig array - * - * Return: 0 success, < 0 for failure - */ -int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_evtconfig, - struct telemetry_evtconfig *ioss_evtconfig, - int pss_len, int ioss_len) -{ - return telm_core_conf.telem_ops->get_eventconfig(pss_evtconfig, - ioss_evtconfig, - pss_len, ioss_len); -} -EXPORT_SYMBOL_GPL(telemetry_get_eventconfig); - -/** - * telemetry_add_events() - Add IOSS & PSS configuration to existing settings. - * @num_pss_evts: Number of PSS Events (<29) in pss_evtmap. Can be 0. - * @num_ioss_evts: Number of IOSS Events (<29) in ioss_evtmap. Can be 0. - * @pss_evtmap: Array of PSS Event-IDs to Enable - * @ioss_evtmap: Array of PSS Event-IDs to Enable - * - * Events are appended to Old Configuration. In case of total events > 28, it - * returns error. Call telemetry_reset_events to reset after eventlog done - * - * Return: 0 success, < 0 for failure - */ -int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts, - u32 *pss_evtmap, u32 *ioss_evtmap) -{ - return telm_core_conf.telem_ops->add_events(num_pss_evts, - num_ioss_evts, pss_evtmap, - ioss_evtmap); -} -EXPORT_SYMBOL_GPL(telemetry_add_events); - -/** - * telemetry_read_events() - Fetches samples as specified by evtlog.telem_evt_id - * @telem_unit: Specify whether IOSS or PSS Read - * @evtlog: Array of telemetry_evtlog structs to fill data - * evtlog.telem_evt_id specifies the ids to read - * @len: Length of array of evtlog - * - * Return: number of eventlogs read for success, < 0 for failure - */ -int telemetry_read_events(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, int len) -{ - return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog, - len, 0); -} -EXPORT_SYMBOL_GPL(telemetry_read_events); - -/** - * telemetry_raw_read_events() - Fetch samples specified by evtlog.telem_evt_id - * @telem_unit: Specify whether IOSS or PSS Read - * @evtlog: Array of telemetry_evtlog structs to fill data - * evtlog.telem_evt_id specifies the ids to read - * @len: Length of array of evtlog - * - * The caller must take care of locking in this case. - * - * Return: number of eventlogs read for success, < 0 for failure - */ -int telemetry_raw_read_events(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, int len) -{ - return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog, - len, 0); -} -EXPORT_SYMBOL_GPL(telemetry_raw_read_events); - -/** - * telemetry_read_eventlog() - Fetch the Telemetry log from PSS or IOSS - * @telem_unit: Specify whether IOSS or PSS Read - * @evtlog: Array of telemetry_evtlog structs to fill data - * @len: Length of array of evtlog - * - * Return: number of eventlogs read for success, < 0 for failure - */ -int telemetry_read_eventlog(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, int len) -{ - return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog, - len, 1); -} -EXPORT_SYMBOL_GPL(telemetry_read_eventlog); - -/** - * telemetry_raw_read_eventlog() - Fetch the Telemetry log from PSS or IOSS - * @telem_unit: Specify whether IOSS or PSS Read - * @evtlog: Array of telemetry_evtlog structs to fill data - * @len: Length of array of evtlog - * - * The caller must take care of locking in this case. - * - * Return: number of eventlogs read for success, < 0 for failure - */ -int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, int len) -{ - return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog, - len, 1); -} -EXPORT_SYMBOL_GPL(telemetry_raw_read_eventlog); - - -/** - * telemetry_get_trace_verbosity() - Get the IOSS & PSS Trace verbosity - * @telem_unit: Specify whether IOSS or PSS Read - * @verbosity: Pointer to return Verbosity - * - * Return: 0 success, < 0 for failure - */ -int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit, - u32 *verbosity) -{ - return telm_core_conf.telem_ops->get_trace_verbosity(telem_unit, - verbosity); -} -EXPORT_SYMBOL_GPL(telemetry_get_trace_verbosity); - - -/** - * telemetry_set_trace_verbosity() - Update the IOSS & PSS Trace verbosity - * @telem_unit: Specify whether IOSS or PSS Read - * @verbosity: Verbosity to set - * - * Return: 0 success, < 0 for failure - */ -int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit, u32 verbosity) -{ - return telm_core_conf.telem_ops->set_trace_verbosity(telem_unit, - verbosity); -} -EXPORT_SYMBOL_GPL(telemetry_set_trace_verbosity); - -/** - * telemetry_set_pltdata() - Set the platform specific Data - * @ops: Pointer to ops structure - * @pltconfig: Platform config data - * - * Usage by other than telemetry pltdrv module is invalid - * - * Return: 0 success, < 0 for failure - */ -int telemetry_set_pltdata(const struct telemetry_core_ops *ops, - struct telemetry_plt_config *pltconfig) -{ - if (ops) - telm_core_conf.telem_ops = ops; - - if (pltconfig) - telm_core_conf.plt_config = pltconfig; - - return 0; -} -EXPORT_SYMBOL_GPL(telemetry_set_pltdata); - -/** - * telemetry_clear_pltdata() - Clear the platform specific Data - * - * Usage by other than telemetry pltdrv module is invalid - * - * Return: 0 success, < 0 for failure - */ -int telemetry_clear_pltdata(void) -{ - telm_core_conf.telem_ops = &telm_defpltops; - telm_core_conf.plt_config = NULL; - - return 0; -} -EXPORT_SYMBOL_GPL(telemetry_clear_pltdata); - -/** - * telemetry_get_pltdata() - Return telemetry platform config - * - * May be used by other telemetry modules to get platform specific - * configuration. - */ -struct telemetry_plt_config *telemetry_get_pltdata(void) -{ - return telm_core_conf.plt_config; -} -EXPORT_SYMBOL_GPL(telemetry_get_pltdata); - -static inline int telemetry_get_pssevtname(enum telemetry_unit telem_unit, - const char **name, int len) -{ - struct telemetry_unit_config psscfg; - int i; - - if (!telm_core_conf.plt_config) - return -EINVAL; - - psscfg = telm_core_conf.plt_config->pss_config; - - if (len > psscfg.ssram_evts_used) - len = psscfg.ssram_evts_used; - - for (i = 0; i < len; i++) - name[i] = psscfg.telem_evts[i].name; - - return 0; -} - -static inline int telemetry_get_iossevtname(enum telemetry_unit telem_unit, - const char **name, int len) -{ - struct telemetry_unit_config iosscfg; - int i; - - if (!(telm_core_conf.plt_config)) - return -EINVAL; - - iosscfg = telm_core_conf.plt_config->ioss_config; - - if (len > iosscfg.ssram_evts_used) - len = iosscfg.ssram_evts_used; - - for (i = 0; i < len; i++) - name[i] = iosscfg.telem_evts[i].name; - - return 0; - -} - -/** - * telemetry_get_evtname() - Checkif platform config is valid - * @telem_unit: Telemetry Unit to check - * @name: Array of character pointers to contain name - * @len: length of array name provided by user - * - * Usage by other than telemetry debugfs module is invalid - * - * Return: 0 success, < 0 for failure - */ -int telemetry_get_evtname(enum telemetry_unit telem_unit, - const char **name, int len) -{ - int ret = -EINVAL; - - if (telem_unit == TELEM_PSS) - ret = telemetry_get_pssevtname(telem_unit, name, len); - - else if (telem_unit == TELEM_IOSS) - ret = telemetry_get_iossevtname(telem_unit, name, len); - - return ret; -} -EXPORT_SYMBOL_GPL(telemetry_get_evtname); - -static int __init telemetry_module_init(void) -{ - pr_info(pr_fmt(DRIVER_NAME) " Init\n"); - - telm_core_conf.telem_ops = &telm_defpltops; - return 0; -} - -static void __exit telemetry_module_exit(void) -{ -} - -module_init(telemetry_module_init); -module_exit(telemetry_module_exit); - -MODULE_AUTHOR("Souvik Kumar Chakravarty "); -MODULE_DESCRIPTION("Intel SoC Telemetry Interface"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c deleted file mode 100644 index 1d4d0fbfd63cc..0000000000000 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ /dev/null @@ -1,961 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel SOC Telemetry debugfs Driver: Currently supports APL - * Copyright (c) 2015, Intel Corporation. - * All Rights Reserved. - * - * This file provides the debugfs interfaces for telemetry. - * /sys/kernel/debug/telemetry/pss_info: Shows Primary Control Sub-Sys Counters - * /sys/kernel/debug/telemetry/ioss_info: Shows IO Sub-System Counters - * /sys/kernel/debug/telemetry/soc_states: Shows SoC State - * /sys/kernel/debug/telemetry/pss_trace_verbosity: Read and Change Tracing - * Verbosity via firmware - * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing - * Verbosity via firmware - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define DRIVER_NAME "telemetry_soc_debugfs" -#define DRIVER_VERSION "1.0.0" - -/* ApolloLake SoC Event-IDs */ -#define TELEM_APL_PSS_PSTATES_ID 0x2802 -#define TELEM_APL_PSS_IDLE_ID 0x2806 -#define TELEM_APL_PCS_IDLE_BLOCKED_ID 0x2C00 -#define TELEM_APL_PCS_S0IX_BLOCKED_ID 0x2C01 -#define TELEM_APL_PSS_WAKEUP_ID 0x2C02 -#define TELEM_APL_PSS_LTR_BLOCKING_ID 0x2C03 - -#define TELEM_APL_S0IX_TOTAL_OCC_ID 0x4000 -#define TELEM_APL_S0IX_SHLW_OCC_ID 0x4001 -#define TELEM_APL_S0IX_DEEP_OCC_ID 0x4002 -#define TELEM_APL_S0IX_TOTAL_RES_ID 0x4800 -#define TELEM_APL_S0IX_SHLW_RES_ID 0x4801 -#define TELEM_APL_S0IX_DEEP_RES_ID 0x4802 -#define TELEM_APL_D0IX_ID 0x581A -#define TELEM_APL_D3_ID 0x5819 -#define TELEM_APL_PG_ID 0x5818 - -#define TELEM_INFO_SRAMEVTS_MASK 0xFF00 -#define TELEM_INFO_SRAMEVTS_SHIFT 0x8 -#define TELEM_SSRAM_READ_TIMEOUT 10 - -#define TELEM_MASK_BIT 1 -#define TELEM_MASK_BYTE 0xFF -#define BYTES_PER_LONG 8 -#define TELEM_APL_MASK_PCS_STATE 0xF - -/* Max events in bitmap to check for */ -#define TELEM_PSS_IDLE_EVTS 25 -#define TELEM_PSS_IDLE_BLOCKED_EVTS 20 -#define TELEM_PSS_S0IX_BLOCKED_EVTS 20 -#define TELEM_PSS_S0IX_WAKEUP_EVTS 20 -#define TELEM_PSS_LTR_BLOCKING_EVTS 20 -#define TELEM_IOSS_DX_D0IX_EVTS 25 -#define TELEM_IOSS_PG_EVTS 30 - -#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \ - if (evtlog[index].telem_evtid == (EVTID)) { \ - for (idx = 0; idx < (EVTNUM); idx++) \ - (BUF)[idx] = ((EVTLOG) >> (EVTDAT)[idx].bit_pos) & \ - (MASK); \ - continue; \ - } \ -} - -#define TELEM_CHECK_AND_PARSE_CTRS(EVTID, CTR) { \ - if (evtlog[index].telem_evtid == (EVTID)) { \ - (CTR) = evtlog[index].telem_evtlog; \ - continue; \ - } \ -} - -static u8 suspend_prep_ok; -static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp; -static u64 suspend_shlw_res_temp, suspend_deep_res_temp; - -struct telemetry_susp_stats { - u32 shlw_ctr; - u32 deep_ctr; - u64 shlw_res; - u64 deep_res; -}; - -/* Bitmap definitions for default counters in APL */ -struct telem_pss_idle_stateinfo { - const char *name; - u32 bit_pos; -}; - -static struct telem_pss_idle_stateinfo telem_apl_pss_idle_data[] = { - {"IA_CORE0_C1E", 0}, - {"IA_CORE1_C1E", 1}, - {"IA_CORE2_C1E", 2}, - {"IA_CORE3_C1E", 3}, - {"IA_CORE0_C6", 16}, - {"IA_CORE1_C6", 17}, - {"IA_CORE2_C6", 18}, - {"IA_CORE3_C6", 19}, - {"IA_MODULE0_C7", 32}, - {"IA_MODULE1_C7", 33}, - {"GT_RC6", 40}, - {"IUNIT_PROCESSING_IDLE", 41}, - {"FAR_MEM_IDLE", 43}, - {"DISPLAY_IDLE", 44}, - {"IUNIT_INPUT_SYSTEM_IDLE", 45}, - {"PCS_STATUS", 60}, -}; - -struct telem_pcs_blkd_info { - const char *name; - u32 bit_pos; -}; - -static struct telem_pcs_blkd_info telem_apl_pcs_idle_blkd_data[] = { - {"COMPUTE", 0}, - {"MISC", 8}, - {"MODULE_ACTIONS_PENDING", 16}, - {"LTR", 24}, - {"DISPLAY_WAKE", 32}, - {"ISP_WAKE", 40}, - {"PSF0_ACTIVE", 48}, -}; - -static struct telem_pcs_blkd_info telem_apl_pcs_s0ix_blkd_data[] = { - {"LTR", 0}, - {"IRTL", 8}, - {"WAKE_DEADLINE_PENDING", 16}, - {"DISPLAY", 24}, - {"ISP", 32}, - {"CORE", 40}, - {"PMC", 48}, - {"MISC", 56}, -}; - -struct telem_pss_ltr_info { - const char *name; - u32 bit_pos; -}; - -static struct telem_pss_ltr_info telem_apl_pss_ltr_data[] = { - {"CORE_ACTIVE", 0}, - {"MEM_UP", 8}, - {"DFX", 16}, - {"DFX_FORCE_LTR", 24}, - {"DISPLAY", 32}, - {"ISP", 40}, - {"SOUTH", 48}, -}; - -struct telem_pss_wakeup_info { - const char *name; - u32 bit_pos; -}; - -static struct telem_pss_wakeup_info telem_apl_pss_wakeup[] = { - {"IP_IDLE", 0}, - {"DISPLAY_WAKE", 8}, - {"VOLTAGE_REG_INT", 16}, - {"DROWSY_TIMER (HOTPLUG)", 24}, - {"CORE_WAKE", 32}, - {"MISC_S0IX", 40}, - {"MISC_ABORT", 56}, -}; - -struct telem_ioss_d0ix_stateinfo { - const char *name; - u32 bit_pos; -}; - -static struct telem_ioss_d0ix_stateinfo telem_apl_ioss_d0ix_data[] = { - {"CSE", 0}, - {"SCC2", 1}, - {"GMM", 2}, - {"XDCI", 3}, - {"XHCI", 4}, - {"ISH", 5}, - {"AVS", 6}, - {"PCIE0P1", 7}, - {"PECI0P0", 8}, - {"LPSS", 9}, - {"SCC", 10}, - {"PWM", 11}, - {"PCIE1_P3", 12}, - {"PCIE1_P2", 13}, - {"PCIE1_P1", 14}, - {"PCIE1_P0", 15}, - {"CNV", 16}, - {"SATA", 17}, - {"PRTC", 18}, -}; - -struct telem_ioss_pg_info { - const char *name; - u32 bit_pos; -}; - -static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = { - {"LPSS", 0}, - {"SCC", 1}, - {"P2SB", 2}, - {"SCC2", 3}, - {"GMM", 4}, - {"PCIE0", 5}, - {"XDCI", 6}, - {"xHCI", 7}, - {"CSE", 8}, - {"SPI", 9}, - {"AVSPGD4", 10}, - {"AVSPGD3", 11}, - {"AVSPGD2", 12}, - {"AVSPGD1", 13}, - {"ISH", 14}, - {"EXI", 15}, - {"NPKVRC", 16}, - {"NPKVNN", 17}, - {"CUNIT", 18}, - {"FUSE_CTRL", 19}, - {"PCIE1", 20}, - {"CNV", 21}, - {"LPC", 22}, - {"SATA", 23}, - {"SMB", 24}, - {"PRTC", 25}, -}; - -struct telemetry_debugfs_conf { - struct telemetry_susp_stats suspend_stats; - struct dentry *telemetry_dbg_dir; - - /* Bitmap Data */ - struct telem_ioss_d0ix_stateinfo *ioss_d0ix_data; - struct telem_pss_idle_stateinfo *pss_idle_data; - struct telem_pcs_blkd_info *pcs_idle_blkd_data; - struct telem_pcs_blkd_info *pcs_s0ix_blkd_data; - struct telem_pss_wakeup_info *pss_wakeup; - struct telem_pss_ltr_info *pss_ltr_data; - struct telem_ioss_pg_info *ioss_pg_data; - u8 pcs_idle_blkd_evts; - u8 pcs_s0ix_blkd_evts; - u8 pss_wakeup_evts; - u8 pss_idle_evts; - u8 pss_ltr_evts; - u8 ioss_d0ix_evts; - u8 ioss_pg_evts; - - /* IDs */ - u16 pss_ltr_blocking_id; - u16 pcs_idle_blkd_id; - u16 pcs_s0ix_blkd_id; - u16 s0ix_total_occ_id; - u16 s0ix_shlw_occ_id; - u16 s0ix_deep_occ_id; - u16 s0ix_total_res_id; - u16 s0ix_shlw_res_id; - u16 s0ix_deep_res_id; - u16 pss_wakeup_id; - u16 ioss_d0ix_id; - u16 pstates_id; - u16 pss_idle_id; - u16 ioss_d3_id; - u16 ioss_pg_id; -}; - -static struct telemetry_debugfs_conf *debugfs_conf; - -static struct telemetry_debugfs_conf telem_apl_debugfs_conf = { - .pss_idle_data = telem_apl_pss_idle_data, - .pcs_idle_blkd_data = telem_apl_pcs_idle_blkd_data, - .pcs_s0ix_blkd_data = telem_apl_pcs_s0ix_blkd_data, - .pss_ltr_data = telem_apl_pss_ltr_data, - .pss_wakeup = telem_apl_pss_wakeup, - .ioss_d0ix_data = telem_apl_ioss_d0ix_data, - .ioss_pg_data = telem_apl_ioss_pg_data, - - .pss_idle_evts = ARRAY_SIZE(telem_apl_pss_idle_data), - .pcs_idle_blkd_evts = ARRAY_SIZE(telem_apl_pcs_idle_blkd_data), - .pcs_s0ix_blkd_evts = ARRAY_SIZE(telem_apl_pcs_s0ix_blkd_data), - .pss_ltr_evts = ARRAY_SIZE(telem_apl_pss_ltr_data), - .pss_wakeup_evts = ARRAY_SIZE(telem_apl_pss_wakeup), - .ioss_d0ix_evts = ARRAY_SIZE(telem_apl_ioss_d0ix_data), - .ioss_pg_evts = ARRAY_SIZE(telem_apl_ioss_pg_data), - - .pstates_id = TELEM_APL_PSS_PSTATES_ID, - .pss_idle_id = TELEM_APL_PSS_IDLE_ID, - .pcs_idle_blkd_id = TELEM_APL_PCS_IDLE_BLOCKED_ID, - .pcs_s0ix_blkd_id = TELEM_APL_PCS_S0IX_BLOCKED_ID, - .pss_wakeup_id = TELEM_APL_PSS_WAKEUP_ID, - .pss_ltr_blocking_id = TELEM_APL_PSS_LTR_BLOCKING_ID, - .s0ix_total_occ_id = TELEM_APL_S0IX_TOTAL_OCC_ID, - .s0ix_shlw_occ_id = TELEM_APL_S0IX_SHLW_OCC_ID, - .s0ix_deep_occ_id = TELEM_APL_S0IX_DEEP_OCC_ID, - .s0ix_total_res_id = TELEM_APL_S0IX_TOTAL_RES_ID, - .s0ix_shlw_res_id = TELEM_APL_S0IX_SHLW_RES_ID, - .s0ix_deep_res_id = TELEM_APL_S0IX_DEEP_RES_ID, - .ioss_d0ix_id = TELEM_APL_D0IX_ID, - .ioss_d3_id = TELEM_APL_D3_ID, - .ioss_pg_id = TELEM_APL_PG_ID, -}; - -static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = { - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &telem_apl_debugfs_conf), - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &telem_apl_debugfs_conf), - {} -}; -MODULE_DEVICE_TABLE(x86cpu, telemetry_debugfs_cpu_ids); - -static int telemetry_debugfs_check_evts(void) -{ - if ((debugfs_conf->pss_idle_evts > TELEM_PSS_IDLE_EVTS) || - (debugfs_conf->pcs_idle_blkd_evts > TELEM_PSS_IDLE_BLOCKED_EVTS) || - (debugfs_conf->pcs_s0ix_blkd_evts > TELEM_PSS_S0IX_BLOCKED_EVTS) || - (debugfs_conf->pss_ltr_evts > TELEM_PSS_LTR_BLOCKING_EVTS) || - (debugfs_conf->pss_wakeup_evts > TELEM_PSS_S0IX_WAKEUP_EVTS) || - (debugfs_conf->ioss_d0ix_evts > TELEM_IOSS_DX_D0IX_EVTS) || - (debugfs_conf->ioss_pg_evts > TELEM_IOSS_PG_EVTS)) - return -EINVAL; - - return 0; -} - -static int telem_pss_states_show(struct seq_file *s, void *unused) -{ - struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; - struct telemetry_debugfs_conf *conf = debugfs_conf; - const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS]; - u32 pcs_idle_blkd[TELEM_PSS_IDLE_BLOCKED_EVTS], - pcs_s0ix_blkd[TELEM_PSS_S0IX_BLOCKED_EVTS], - pss_s0ix_wakeup[TELEM_PSS_S0IX_WAKEUP_EVTS], - pss_ltr_blkd[TELEM_PSS_LTR_BLOCKING_EVTS], - pss_idle[TELEM_PSS_IDLE_EVTS]; - int index, idx, ret, err = 0; - u64 pstates = 0; - - ret = telemetry_read_eventlog(TELEM_PSS, evtlog, - TELEM_MAX_OS_ALLOCATED_EVENTS); - if (ret < 0) - return ret; - - err = telemetry_get_evtname(TELEM_PSS, name, - TELEM_MAX_OS_ALLOCATED_EVENTS); - if (err < 0) - return err; - - seq_puts(s, "\n----------------------------------------------------\n"); - seq_puts(s, "\tPSS TELEM EVENTLOG (Residency = field/19.2 us\n"); - seq_puts(s, "----------------------------------------------------\n"); - for (index = 0; index < ret; index++) { - seq_printf(s, "%-32s %llu\n", - name[index], evtlog[index].telem_evtlog); - - /* Fetch PSS IDLE State */ - if (evtlog[index].telem_evtid == conf->pss_idle_id) { - pss_idle[conf->pss_idle_evts - 1] = - (evtlog[index].telem_evtlog >> - conf->pss_idle_data[conf->pss_idle_evts - 1].bit_pos) & - TELEM_APL_MASK_PCS_STATE; - } - - TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id, - conf->pss_idle_evts - 1, - pss_idle, evtlog[index].telem_evtlog, - conf->pss_idle_data, TELEM_MASK_BIT); - - TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_idle_blkd_id, - conf->pcs_idle_blkd_evts, - pcs_idle_blkd, - evtlog[index].telem_evtlog, - conf->pcs_idle_blkd_data, - TELEM_MASK_BYTE); - - TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_s0ix_blkd_id, - conf->pcs_s0ix_blkd_evts, - pcs_s0ix_blkd, - evtlog[index].telem_evtlog, - conf->pcs_s0ix_blkd_data, - TELEM_MASK_BYTE); - - TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id, - conf->pss_wakeup_evts, - pss_s0ix_wakeup, - evtlog[index].telem_evtlog, - conf->pss_wakeup, TELEM_MASK_BYTE); - - TELEM_CHECK_AND_PARSE_EVTS(conf->pss_ltr_blocking_id, - conf->pss_ltr_evts, pss_ltr_blkd, - evtlog[index].telem_evtlog, - conf->pss_ltr_data, TELEM_MASK_BYTE); - - if (evtlog[index].telem_evtid == debugfs_conf->pstates_id) - pstates = evtlog[index].telem_evtlog; - } - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "PStates\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Domain\t\t\t\tFreq(Mhz)\n"); - seq_printf(s, " IA\t\t\t\t %llu\n GT\t\t\t\t %llu\n", - (pstates & TELEM_MASK_BYTE)*100, - ((pstates >> 8) & TELEM_MASK_BYTE)*50/3); - - seq_printf(s, " IUNIT\t\t\t\t %llu\n SA\t\t\t\t %llu\n", - ((pstates >> 16) & TELEM_MASK_BYTE)*25, - ((pstates >> 24) & TELEM_MASK_BYTE)*50/3); - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "PSS IDLE Status\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Device\t\t\t\t\tIDLE\n"); - for (index = 0; index < debugfs_conf->pss_idle_evts; index++) { - seq_printf(s, "%-32s\t%u\n", - debugfs_conf->pss_idle_data[index].name, - pss_idle[index]); - } - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "PSS Idle blkd Status (~1ms saturating bucket)\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Blocker\t\t\t\t\tCount\n"); - for (index = 0; index < debugfs_conf->pcs_idle_blkd_evts; index++) { - seq_printf(s, "%-32s\t%u\n", - debugfs_conf->pcs_idle_blkd_data[index].name, - pcs_idle_blkd[index]); - } - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "PSS S0ix blkd Status (~1ms saturating bucket)\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Blocker\t\t\t\t\tCount\n"); - for (index = 0; index < debugfs_conf->pcs_s0ix_blkd_evts; index++) { - seq_printf(s, "%-32s\t%u\n", - debugfs_conf->pcs_s0ix_blkd_data[index].name, - pcs_s0ix_blkd[index]); - } - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "LTR Blocking Status (~1ms saturating bucket)\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Blocker\t\t\t\t\tCount\n"); - for (index = 0; index < debugfs_conf->pss_ltr_evts; index++) { - seq_printf(s, "%-32s\t%u\n", - debugfs_conf->pss_ltr_data[index].name, - pss_s0ix_wakeup[index]); - } - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "Wakes Status (~1ms saturating bucket)\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Wakes\t\t\t\t\tCount\n"); - for (index = 0; index < debugfs_conf->pss_wakeup_evts; index++) { - seq_printf(s, "%-32s\t%u\n", - debugfs_conf->pss_wakeup[index].name, - pss_ltr_blkd[index]); - } - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(telem_pss_states); - -static int telem_ioss_states_show(struct seq_file *s, void *unused) -{ - struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; - const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS]; - int index, ret, err; - - ret = telemetry_read_eventlog(TELEM_IOSS, evtlog, - TELEM_MAX_OS_ALLOCATED_EVENTS); - if (ret < 0) - return ret; - - err = telemetry_get_evtname(TELEM_IOSS, name, - TELEM_MAX_OS_ALLOCATED_EVENTS); - if (err < 0) - return err; - - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "\tI0SS TELEMETRY EVENTLOG\n"); - seq_puts(s, "--------------------------------------\n"); - for (index = 0; index < ret; index++) { - seq_printf(s, "%-32s 0x%llx\n", - name[index], evtlog[index].telem_evtlog); - } - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(telem_ioss_states); - -static int telem_soc_states_show(struct seq_file *s, void *unused) -{ - u32 d3_sts[TELEM_IOSS_DX_D0IX_EVTS], d0ix_sts[TELEM_IOSS_DX_D0IX_EVTS]; - u32 pg_sts[TELEM_IOSS_PG_EVTS], pss_idle[TELEM_PSS_IDLE_EVTS]; - struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; - u32 s0ix_total_ctr = 0, s0ix_shlw_ctr = 0, s0ix_deep_ctr = 0; - u64 s0ix_total_res = 0, s0ix_shlw_res = 0, s0ix_deep_res = 0; - struct telemetry_debugfs_conf *conf = debugfs_conf; - struct pci_dev *dev = NULL; - int index, idx, ret; - u32 d3_state; - u16 pmcsr; - - ret = telemetry_read_eventlog(TELEM_IOSS, evtlog, - TELEM_MAX_OS_ALLOCATED_EVENTS); - if (ret < 0) - return ret; - - for (index = 0; index < ret; index++) { - TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d3_id, - conf->ioss_d0ix_evts, - d3_sts, evtlog[index].telem_evtlog, - conf->ioss_d0ix_data, - TELEM_MASK_BIT); - - TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_pg_id, conf->ioss_pg_evts, - pg_sts, evtlog[index].telem_evtlog, - conf->ioss_pg_data, TELEM_MASK_BIT); - - TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d0ix_id, - conf->ioss_d0ix_evts, - d0ix_sts, evtlog[index].telem_evtlog, - conf->ioss_d0ix_data, - TELEM_MASK_BIT); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_occ_id, - s0ix_total_ctr); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, - s0ix_shlw_ctr); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, - s0ix_deep_ctr); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_res_id, - s0ix_total_res); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, - s0ix_shlw_res); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, - s0ix_deep_res); - } - - seq_puts(s, "\n---------------------------------------------------\n"); - seq_puts(s, "S0IX Type\t\t\t Occurrence\t\t Residency(us)\n"); - seq_puts(s, "---------------------------------------------------\n"); - - seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n", - s0ix_shlw_ctr - - conf->suspend_stats.shlw_ctr, - (u64)((s0ix_shlw_res - - conf->suspend_stats.shlw_res)*10/192)); - - seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n", - s0ix_deep_ctr - - conf->suspend_stats.deep_ctr, - (u64)((s0ix_deep_res - - conf->suspend_stats.deep_res)*10/192)); - - seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n", - conf->suspend_stats.shlw_ctr, - (u64)(conf->suspend_stats.shlw_res*10)/192); - - seq_printf(s, "Suspend(With S0ixDeep)\t\t %10u\t %10llu\n", - conf->suspend_stats.deep_ctr, - (u64)(conf->suspend_stats.deep_res*10)/192); - - seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr, - (u64)(s0ix_total_res*10/192)); - seq_puts(s, "\n-------------------------------------------------\n"); - seq_puts(s, "\t\tDEVICE STATES\n"); - seq_puts(s, "-------------------------------------------------\n"); - - for_each_pci_dev(dev) { - pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); - d3_state = ((pmcsr & PCI_PM_CTRL_STATE_MASK) == - (__force int)PCI_D3hot) ? 1 : 0; - - seq_printf(s, "pci %04x %04X %s %20.20s: ", - dev->vendor, dev->device, dev_name(&dev->dev), - dev_driver_string(&dev->dev)); - seq_printf(s, " d3:%x\n", d3_state); - } - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "D3/D0i3 Status\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Block\t\t D3\t D0i3\n"); - for (index = 0; index < conf->ioss_d0ix_evts; index++) { - seq_printf(s, "%-10s\t %u\t %u\n", - conf->ioss_d0ix_data[index].name, - d3_sts[index], d0ix_sts[index]); - } - - seq_puts(s, "\n--------------------------------------\n"); - seq_puts(s, "South Complex PowerGate Status\n"); - seq_puts(s, "--------------------------------------\n"); - seq_puts(s, "Device\t\t PG\n"); - for (index = 0; index < conf->ioss_pg_evts; index++) { - seq_printf(s, "%-10s\t %u\n", - conf->ioss_pg_data[index].name, - pg_sts[index]); - } - - evtlog->telem_evtid = conf->pss_idle_id; - ret = telemetry_read_events(TELEM_PSS, evtlog, 1); - if (ret < 0) - return ret; - - seq_puts(s, "\n-----------------------------------------\n"); - seq_puts(s, "North Idle Status\n"); - seq_puts(s, "-----------------------------------------\n"); - for (idx = 0; idx < conf->pss_idle_evts - 1; idx++) { - pss_idle[idx] = (evtlog->telem_evtlog >> - conf->pss_idle_data[idx].bit_pos) & - TELEM_MASK_BIT; - } - - pss_idle[idx] = (evtlog->telem_evtlog >> - conf->pss_idle_data[idx].bit_pos) & - TELEM_APL_MASK_PCS_STATE; - - for (index = 0; index < conf->pss_idle_evts; index++) { - seq_printf(s, "%-30s %u\n", - conf->pss_idle_data[index].name, - pss_idle[index]); - } - - seq_puts(s, "\nPCS_STATUS Code\n"); - seq_puts(s, "0:C0 1:C1 2:C1_DN_WT_DEV 3:C2 4:C2_WT_DE_MEM_UP\n"); - seq_puts(s, "5:C2_WT_DE_MEM_DOWN 6:C2_UP_WT_DEV 7:C2_DN 8:C2_VOA\n"); - seq_puts(s, "9:C2_VOA_UP 10:S0IX_PRE 11:S0IX\n"); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(telem_soc_states); - -static int telem_s0ix_res_get(void *data, u64 *val) -{ - struct telemetry_plt_config *plt_config = telemetry_get_pltdata(); - u64 s0ix_total_res; - int ret; - - ret = intel_pmc_s0ix_counter_read(plt_config->pmc, &s0ix_total_res); - if (ret) { - pr_err("Failed to read S0ix residency"); - return ret; - } - - *val = s0ix_total_res; - - return 0; -} - -DEFINE_DEBUGFS_ATTRIBUTE(telem_s0ix_fops, telem_s0ix_res_get, NULL, "%llu\n"); - -static int telem_pss_trc_verb_show(struct seq_file *s, void *unused) -{ - u32 verbosity; - int err; - - err = telemetry_get_trace_verbosity(TELEM_PSS, &verbosity); - if (err) { - pr_err("Get PSS Trace Verbosity Failed with Error %d\n", err); - return -EFAULT; - } - - seq_printf(s, "PSS Trace Verbosity %u\n", verbosity); - return 0; -} - -static ssize_t telem_pss_trc_verb_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - u32 verbosity; - int err; - - err = kstrtou32_from_user(userbuf, count, 0, &verbosity); - if (err) - return err; - - err = telemetry_set_trace_verbosity(TELEM_PSS, verbosity); - if (err) { - pr_err("Changing PSS Trace Verbosity Failed. Error %d\n", err); - return err; - } - - return count; -} - -static int telem_pss_trc_verb_open(struct inode *inode, struct file *file) -{ - return single_open(file, telem_pss_trc_verb_show, inode->i_private); -} - -static const struct file_operations telem_pss_trc_verb_ops = { - .open = telem_pss_trc_verb_open, - .read = seq_read, - .write = telem_pss_trc_verb_write, - .llseek = seq_lseek, - .release = single_release, -}; - -static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused) -{ - u32 verbosity; - int err; - - err = telemetry_get_trace_verbosity(TELEM_IOSS, &verbosity); - if (err) { - pr_err("Get IOSS Trace Verbosity Failed with Error %d\n", err); - return -EFAULT; - } - - seq_printf(s, "IOSS Trace Verbosity %u\n", verbosity); - return 0; -} - -static ssize_t telem_ioss_trc_verb_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - u32 verbosity; - int err; - - err = kstrtou32_from_user(userbuf, count, 0, &verbosity); - if (err) - return err; - - err = telemetry_set_trace_verbosity(TELEM_IOSS, verbosity); - if (err) { - pr_err("Changing IOSS Trace Verbosity Failed. Error %d\n", err); - return err; - } - - return count; -} - -static int telem_ioss_trc_verb_open(struct inode *inode, struct file *file) -{ - return single_open(file, telem_ioss_trc_verb_show, inode->i_private); -} - -static const struct file_operations telem_ioss_trc_verb_ops = { - .open = telem_ioss_trc_verb_open, - .read = seq_read, - .write = telem_ioss_trc_verb_write, - .llseek = seq_lseek, - .release = single_release, -}; - -static int pm_suspend_prep_cb(void) -{ - struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; - struct telemetry_debugfs_conf *conf = debugfs_conf; - int ret, index; - - ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog, - TELEM_MAX_OS_ALLOCATED_EVENTS); - if (ret < 0) { - suspend_prep_ok = 0; - goto out; - } - - for (index = 0; index < ret; index++) { - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, - suspend_shlw_ctr_temp); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, - suspend_deep_ctr_temp); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, - suspend_shlw_res_temp); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, - suspend_deep_res_temp); - } - suspend_prep_ok = 1; -out: - return NOTIFY_OK; -} - -static int pm_suspend_exit_cb(void) -{ - struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; - static u32 suspend_shlw_ctr_exit, suspend_deep_ctr_exit; - static u64 suspend_shlw_res_exit, suspend_deep_res_exit; - struct telemetry_debugfs_conf *conf = debugfs_conf; - int ret, index; - - if (!suspend_prep_ok) - goto out; - - ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog, - TELEM_MAX_OS_ALLOCATED_EVENTS); - if (ret < 0) - goto out; - - for (index = 0; index < ret; index++) { - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id, - suspend_shlw_ctr_exit); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id, - suspend_deep_ctr_exit); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id, - suspend_shlw_res_exit); - - TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id, - suspend_deep_res_exit); - } - - if ((suspend_shlw_ctr_exit < suspend_shlw_ctr_temp) || - (suspend_deep_ctr_exit < suspend_deep_ctr_temp) || - (suspend_shlw_res_exit < suspend_shlw_res_temp) || - (suspend_deep_res_exit < suspend_deep_res_temp)) { - pr_err("Wrong s0ix counters detected\n"); - goto out; - } - - /* - * Due to some design limitations in the firmware, sometimes the - * counters do not get updated by the time we reach here. As a - * workaround, we try to see if this was a genuine case of sleep - * failure or not by cross-checking from PMC GCR registers directly. - */ - if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp && - suspend_deep_ctr_exit == suspend_deep_ctr_temp) { - struct telemetry_plt_config *plt_config = telemetry_get_pltdata(); - struct intel_pmc_dev *pmc = plt_config->pmc; - - ret = intel_pmc_gcr_read64(pmc, PMC_GCR_TELEM_SHLW_S0IX_REG, - &suspend_shlw_res_exit); - if (ret < 0) - goto out; - - ret = intel_pmc_gcr_read64(pmc, PMC_GCR_TELEM_DEEP_S0IX_REG, - &suspend_deep_res_exit); - if (ret < 0) - goto out; - - if (suspend_shlw_res_exit > suspend_shlw_res_temp) - suspend_shlw_ctr_exit++; - - if (suspend_deep_res_exit > suspend_deep_res_temp) - suspend_deep_ctr_exit++; - } - - suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp; - suspend_deep_ctr_exit -= suspend_deep_ctr_temp; - suspend_shlw_res_exit -= suspend_shlw_res_temp; - suspend_deep_res_exit -= suspend_deep_res_temp; - - if (suspend_shlw_ctr_exit != 0) { - conf->suspend_stats.shlw_ctr += - suspend_shlw_ctr_exit; - - conf->suspend_stats.shlw_res += - suspend_shlw_res_exit; - } - - if (suspend_deep_ctr_exit != 0) { - conf->suspend_stats.deep_ctr += - suspend_deep_ctr_exit; - - conf->suspend_stats.deep_res += - suspend_deep_res_exit; - } - -out: - suspend_prep_ok = 0; - return NOTIFY_OK; -} - -static int pm_notification(struct notifier_block *this, - unsigned long event, void *ptr) -{ - switch (event) { - case PM_SUSPEND_PREPARE: - return pm_suspend_prep_cb(); - case PM_POST_SUSPEND: - return pm_suspend_exit_cb(); - } - - return NOTIFY_DONE; -} - -static struct notifier_block pm_notifier = { - .notifier_call = pm_notification, -}; - -static int __init telemetry_debugfs_init(void) -{ - const struct x86_cpu_id *id; - int err; - struct dentry *dir; - - /* Only APL supported for now */ - id = x86_match_cpu(telemetry_debugfs_cpu_ids); - if (!id) - return -ENODEV; - - debugfs_conf = (struct telemetry_debugfs_conf *)id->driver_data; - - if (!telemetry_get_pltdata()) { - pr_info("Invalid pltconfig, ensure IPC1 device is enabled in BIOS\n"); - return -ENODEV; - } - - err = telemetry_debugfs_check_evts(); - if (err < 0) { - pr_info("telemetry_debugfs_check_evts failed\n"); - return -EINVAL; - } - - register_pm_notifier(&pm_notifier); - - dir = debugfs_create_dir("telemetry", NULL); - debugfs_conf->telemetry_dbg_dir = dir; - - debugfs_create_file("pss_info", S_IFREG | S_IRUGO, dir, NULL, - &telem_pss_states_fops); - debugfs_create_file("ioss_info", S_IFREG | S_IRUGO, dir, NULL, - &telem_ioss_states_fops); - debugfs_create_file("soc_states", S_IFREG | S_IRUGO, dir, NULL, - &telem_soc_states_fops); - debugfs_create_file("s0ix_residency_usec", S_IFREG | S_IRUGO, dir, NULL, - &telem_s0ix_fops); - debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO, dir, NULL, - &telem_pss_trc_verb_ops); - debugfs_create_file("ioss_trace_verbosity", S_IFREG | S_IRUGO, dir, - NULL, &telem_ioss_trc_verb_ops); - return 0; -} - -static void __exit telemetry_debugfs_exit(void) -{ - debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir); - debugfs_conf->telemetry_dbg_dir = NULL; - unregister_pm_notifier(&pm_notifier); -} - -late_initcall(telemetry_debugfs_init); -module_exit(telemetry_debugfs_exit); - -MODULE_AUTHOR("Souvik Kumar Chakravarty "); -MODULE_DESCRIPTION("Intel SoC Telemetry debugfs Interface"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c deleted file mode 100644 index 405dea87de6bf..0000000000000 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ /dev/null @@ -1,1189 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel SOC Telemetry Platform Driver: Currently supports APL - * Copyright (c) 2015, Intel Corporation. - * All Rights Reserved. - * - * This file provides the platform specific telemetry implementation for APL. - * It used the PUNIT and PMC IPC interfaces for configuring the counters. - * The accumulated results are fetched from SRAM. - */ - -#include -#include -#include - -#include -#include -#include -#include - -#define DRIVER_NAME "intel_telemetry" -#define DRIVER_VERSION "1.0.0" - -#define TELEM_TRC_VERBOSITY_MASK 0x3 - -#define TELEM_MIN_PERIOD(x) ((x) & 0x7F0000) -#define TELEM_MAX_PERIOD(x) ((x) & 0x7F000000) -#define TELEM_SAMPLE_PERIOD_INVALID(x) ((x) & (BIT(7))) -#define TELEM_CLEAR_SAMPLE_PERIOD(x) ((x) &= ~0x7F) - -#define TELEM_SAMPLING_DEFAULT_PERIOD 0xD - -#define TELEM_MAX_EVENTS_SRAM 28 -#define TELEM_SSRAM_STARTTIME_OFFSET 8 -#define TELEM_SSRAM_EVTLOG_OFFSET 16 - -#define IOSS_TELEM 0xeb -#define IOSS_TELEM_EVENT_READ 0x0 -#define IOSS_TELEM_EVENT_WRITE 0x1 -#define IOSS_TELEM_INFO_READ 0x2 -#define IOSS_TELEM_TRACE_CTL_READ 0x5 -#define IOSS_TELEM_TRACE_CTL_WRITE 0x6 -#define IOSS_TELEM_EVENT_CTL_READ 0x7 -#define IOSS_TELEM_EVENT_CTL_WRITE 0x8 -#define IOSS_TELEM_EVT_WRITE_SIZE 0x3 - -#define TELEM_INFO_SRAMEVTS_MASK 0xFF00 -#define TELEM_INFO_SRAMEVTS_SHIFT 0x8 -#define TELEM_SSRAM_READ_TIMEOUT 10 - -#define TELEM_INFO_NENABLES_MASK 0xFF -#define TELEM_EVENT_ENABLE 0x8000 - -#define TELEM_MASK_BIT 1 -#define TELEM_MASK_BYTE 0xFF -#define BYTES_PER_LONG 8 -#define TELEM_MASK_PCS_STATE 0xF - -#define TELEM_DISABLE(x) ((x) &= ~(BIT(31))) -#define TELEM_CLEAR_EVENTS(x) ((x) |= (BIT(30))) -#define TELEM_ENABLE_SRAM_EVT_TRACE(x) ((x) &= ~(BIT(30) | BIT(24))) -#define TELEM_ENABLE_PERIODIC(x) ((x) |= (BIT(23) | BIT(31) | BIT(7))) -#define TELEM_EXTRACT_VERBOSITY(x, y) ((y) = (((x) >> 27) & 0x3)) -#define TELEM_CLEAR_VERBOSITY_BITS(x) ((x) &= ~(BIT(27) | BIT(28))) -#define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27)) - -enum telemetry_action { - TELEM_UPDATE = 0, - TELEM_ADD, - TELEM_RESET, - TELEM_ACTION_NONE -}; - -struct telem_ssram_region { - u64 timestamp; - u64 start_time; - u64 events[TELEM_MAX_EVENTS_SRAM]; -}; - -static struct telemetry_plt_config *telm_conf; - -/* - * The following counters are programmed by default during setup. - * Only 20 allocated to kernel driver - */ -static struct telemetry_evtmap - telemetry_apl_ioss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { - {"SOC_S0IX_TOTAL_RES", 0x4800}, - {"SOC_S0IX_TOTAL_OCC", 0x4000}, - {"SOC_S0IX_SHALLOW_RES", 0x4801}, - {"SOC_S0IX_SHALLOW_OCC", 0x4001}, - {"SOC_S0IX_DEEP_RES", 0x4802}, - {"SOC_S0IX_DEEP_OCC", 0x4002}, - {"PMC_POWER_GATE", 0x5818}, - {"PMC_D3_STATES", 0x5819}, - {"PMC_D0I3_STATES", 0x581A}, - {"PMC_S0IX_WAKE_REASON_GPIO", 0x6000}, - {"PMC_S0IX_WAKE_REASON_TIMER", 0x6001}, - {"PMC_S0IX_WAKE_REASON_VNNREQ", 0x6002}, - {"PMC_S0IX_WAKE_REASON_LOWPOWER", 0x6003}, - {"PMC_S0IX_WAKE_REASON_EXTERNAL", 0x6004}, - {"PMC_S0IX_WAKE_REASON_MISC", 0x6005}, - {"PMC_S0IX_BLOCKING_IPS_D3_D0I3", 0x6006}, - {"PMC_S0IX_BLOCKING_IPS_PG", 0x6007}, - {"PMC_S0IX_BLOCKING_MISC_IPS_PG", 0x6008}, - {"PMC_S0IX_BLOCK_IPS_VNN_REQ", 0x6009}, - {"PMC_S0IX_BLOCK_IPS_CLOCKS", 0x600B}, -}; - - -static struct telemetry_evtmap - telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { - {"IA_CORE0_C6_RES", 0x0400}, - {"IA_CORE0_C6_CTR", 0x0000}, - {"IA_MODULE0_C7_RES", 0x0410}, - {"IA_MODULE0_C7_CTR", 0x000E}, - {"IA_C0_RES", 0x0805}, - {"PCS_LTR", 0x2801}, - {"PSTATES", 0x2802}, - {"SOC_S0I3_RES", 0x0409}, - {"SOC_S0I3_CTR", 0x000A}, - {"PCS_S0I3_CTR", 0x0009}, - {"PCS_C1E_RES", 0x041A}, - {"PCS_IDLE_STATUS", 0x2806}, - {"IA_PERF_LIMITS", 0x280B}, - {"GT_PERF_LIMITS", 0x280C}, - {"PCS_WAKEUP_S0IX_CTR", 0x0030}, - {"PCS_IDLE_BLOCKED", 0x2C00}, - {"PCS_S0IX_BLOCKED", 0x2C01}, - {"PCS_S0IX_WAKE_REASONS", 0x2C02}, - {"PCS_LTR_BLOCKING", 0x2C03}, - {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40}, -}; - -static struct telemetry_evtmap - telemetry_glk_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = { - {"IA_CORE0_C6_RES", 0x0400}, - {"IA_CORE0_C6_CTR", 0x0000}, - {"IA_MODULE0_C7_RES", 0x0410}, - {"IA_MODULE0_C7_CTR", 0x000C}, - {"IA_C0_RES", 0x0805}, - {"PCS_LTR", 0x2801}, - {"PSTATES", 0x2802}, - {"SOC_S0I3_RES", 0x0407}, - {"SOC_S0I3_CTR", 0x0008}, - {"PCS_S0I3_CTR", 0x0007}, - {"PCS_C1E_RES", 0x0414}, - {"PCS_IDLE_STATUS", 0x2806}, - {"IA_PERF_LIMITS", 0x280B}, - {"GT_PERF_LIMITS", 0x280C}, - {"PCS_WAKEUP_S0IX_CTR", 0x0025}, - {"PCS_IDLE_BLOCKED", 0x2C00}, - {"PCS_S0IX_BLOCKED", 0x2C01}, - {"PCS_S0IX_WAKE_REASONS", 0x2C02}, - {"PCS_LTR_BLOCKING", 0x2C03}, - {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40}, -}; - -/* APL specific Data */ -static struct telemetry_plt_config telem_apl_config = { - .pss_config = { - .telem_evts = telemetry_apl_pss_default_events, - }, - .ioss_config = { - .telem_evts = telemetry_apl_ioss_default_events, - }, -}; - -/* GLK specific Data */ -static struct telemetry_plt_config telem_glk_config = { - .pss_config = { - .telem_evts = telemetry_glk_pss_default_events, - }, - .ioss_config = { - .telem_evts = telemetry_apl_ioss_default_events, - }, -}; - -static const struct x86_cpu_id telemetry_cpu_ids[] = { - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &telem_apl_config), - X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &telem_glk_config), - {} -}; - -MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids); - -static inline int telem_get_unitconfig(enum telemetry_unit telem_unit, - struct telemetry_unit_config **unit_config) -{ - if (telem_unit == TELEM_PSS) - *unit_config = &(telm_conf->pss_config); - else if (telem_unit == TELEM_IOSS) - *unit_config = &(telm_conf->ioss_config); - else - return -EINVAL; - - return 0; - -} - -static int telemetry_check_evtid(enum telemetry_unit telem_unit, - u32 *evtmap, u8 len, - enum telemetry_action action) -{ - struct telemetry_unit_config *unit_config; - int ret; - - ret = telem_get_unitconfig(telem_unit, &unit_config); - if (ret < 0) - return ret; - - switch (action) { - case TELEM_RESET: - if (len > TELEM_MAX_EVENTS_SRAM) - return -EINVAL; - - break; - - case TELEM_UPDATE: - if (len > TELEM_MAX_EVENTS_SRAM) - return -EINVAL; - - if ((len > 0) && (evtmap == NULL)) - return -EINVAL; - - break; - - case TELEM_ADD: - if ((len + unit_config->ssram_evts_used) > - TELEM_MAX_EVENTS_SRAM) - return -EINVAL; - - if ((len > 0) && (evtmap == NULL)) - return -EINVAL; - - break; - - default: - pr_err("Unknown Telemetry action specified %d\n", action); - return -EINVAL; - } - - return 0; -} - - -static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index) -{ - u32 write_buf; - - write_buf = evt_id | TELEM_EVENT_ENABLE; - write_buf <<= BITS_PER_BYTE; - write_buf |= index; - - return intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, - IOSS_TELEM_EVENT_WRITE, &write_buf, - IOSS_TELEM_EVT_WRITE_SIZE, NULL, 0); -} - -static inline int telemetry_plt_config_pss_event(u32 evt_id, int index) -{ - u32 write_buf; - int ret; - - write_buf = evt_id | TELEM_EVENT_ENABLE; - ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT, - index, 0, &write_buf, NULL); - - return ret; -} - -static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig, - enum telemetry_action action) -{ - struct intel_scu_ipc_dev *scu = telm_conf->scu; - u8 num_ioss_evts, ioss_period; - int ret, index, idx; - u32 *ioss_evtmap; - u32 telem_ctrl; - - num_ioss_evts = evtconfig.num_evts; - ioss_period = evtconfig.period; - ioss_evtmap = evtconfig.evtmap; - - /* Get telemetry EVENT CTL */ - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_READ, NULL, 0, - &telem_ctrl, sizeof(telem_ctrl)); - if (ret) { - pr_err("IOSS TELEM_CTRL Read Failed\n"); - return ret; - } - - /* Disable Telemetry */ - TELEM_DISABLE(telem_ctrl); - - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_WRITE, &telem_ctrl, - sizeof(telem_ctrl), NULL, 0); - if (ret) { - pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); - return ret; - } - - - /* Reset Everything */ - if (action == TELEM_RESET) { - /* Clear All Events */ - TELEM_CLEAR_EVENTS(telem_ctrl); - - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_WRITE, - &telem_ctrl, sizeof(telem_ctrl), - NULL, 0); - if (ret) { - pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); - return ret; - } - telm_conf->ioss_config.ssram_evts_used = 0; - - /* Configure Events */ - for (idx = 0; idx < num_ioss_evts; idx++) { - if (telemetry_plt_config_ioss_event( - telm_conf->ioss_config.telem_evts[idx].evt_id, - idx)) { - pr_err("IOSS TELEM_RESET Fail for data: %x\n", - telm_conf->ioss_config.telem_evts[idx].evt_id); - continue; - } - telm_conf->ioss_config.ssram_evts_used++; - } - } - - /* Re-Configure Everything */ - if (action == TELEM_UPDATE) { - /* Clear All Events */ - TELEM_CLEAR_EVENTS(telem_ctrl); - - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_WRITE, - &telem_ctrl, sizeof(telem_ctrl), - NULL, 0); - if (ret) { - pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); - return ret; - } - telm_conf->ioss_config.ssram_evts_used = 0; - - /* Configure Events */ - for (index = 0; index < num_ioss_evts; index++) { - telm_conf->ioss_config.telem_evts[index].evt_id = - ioss_evtmap[index]; - - if (telemetry_plt_config_ioss_event( - telm_conf->ioss_config.telem_evts[index].evt_id, - index)) { - pr_err("IOSS TELEM_UPDATE Fail for Evt%x\n", - ioss_evtmap[index]); - continue; - } - telm_conf->ioss_config.ssram_evts_used++; - } - } - - /* Add some Events */ - if (action == TELEM_ADD) { - /* Configure Events */ - for (index = telm_conf->ioss_config.ssram_evts_used, idx = 0; - idx < num_ioss_evts; index++, idx++) { - telm_conf->ioss_config.telem_evts[index].evt_id = - ioss_evtmap[idx]; - - if (telemetry_plt_config_ioss_event( - telm_conf->ioss_config.telem_evts[index].evt_id, - index)) { - pr_err("IOSS TELEM_ADD Fail for Event %x\n", - ioss_evtmap[idx]); - continue; - } - telm_conf->ioss_config.ssram_evts_used++; - } - } - - /* Enable Periodic Telemetry Events and enable SRAM trace */ - TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); - TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); - TELEM_ENABLE_PERIODIC(telem_ctrl); - telem_ctrl |= ioss_period; - - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_WRITE, - &telem_ctrl, sizeof(telem_ctrl), NULL, 0); - if (ret) { - pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n"); - return ret; - } - - telm_conf->ioss_config.curr_period = ioss_period; - - return 0; -} - - -static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig, - enum telemetry_action action) -{ - u8 num_pss_evts, pss_period; - int ret, index, idx; - u32 *pss_evtmap; - u32 telem_ctrl; - - num_pss_evts = evtconfig.num_evts; - pss_period = evtconfig.period; - pss_evtmap = evtconfig.evtmap; - - /* PSS Config */ - /* Get telemetry EVENT CTL */ - ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL, - 0, 0, NULL, &telem_ctrl); - if (ret) { - pr_err("PSS TELEM_CTRL Read Failed\n"); - return ret; - } - - /* Disable Telemetry */ - TELEM_DISABLE(telem_ctrl); - ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, - 0, 0, &telem_ctrl, NULL); - if (ret) { - pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); - return ret; - } - - /* Reset Everything */ - if (action == TELEM_RESET) { - /* Clear All Events */ - TELEM_CLEAR_EVENTS(telem_ctrl); - - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, - 0, 0, &telem_ctrl, NULL); - if (ret) { - pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); - return ret; - } - telm_conf->pss_config.ssram_evts_used = 0; - /* Configure Events */ - for (idx = 0; idx < num_pss_evts; idx++) { - if (telemetry_plt_config_pss_event( - telm_conf->pss_config.telem_evts[idx].evt_id, - idx)) { - pr_err("PSS TELEM_RESET Fail for Event %x\n", - telm_conf->pss_config.telem_evts[idx].evt_id); - continue; - } - telm_conf->pss_config.ssram_evts_used++; - } - } - - /* Re-Configure Everything */ - if (action == TELEM_UPDATE) { - /* Clear All Events */ - TELEM_CLEAR_EVENTS(telem_ctrl); - - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, - 0, 0, &telem_ctrl, NULL); - if (ret) { - pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); - return ret; - } - telm_conf->pss_config.ssram_evts_used = 0; - - /* Configure Events */ - for (index = 0; index < num_pss_evts; index++) { - telm_conf->pss_config.telem_evts[index].evt_id = - pss_evtmap[index]; - - if (telemetry_plt_config_pss_event( - telm_conf->pss_config.telem_evts[index].evt_id, - index)) { - pr_err("PSS TELEM_UPDATE Fail for Event %x\n", - pss_evtmap[index]); - continue; - } - telm_conf->pss_config.ssram_evts_used++; - } - } - - /* Add some Events */ - if (action == TELEM_ADD) { - /* Configure Events */ - for (index = telm_conf->pss_config.ssram_evts_used, idx = 0; - idx < num_pss_evts; index++, idx++) { - - telm_conf->pss_config.telem_evts[index].evt_id = - pss_evtmap[idx]; - - if (telemetry_plt_config_pss_event( - telm_conf->pss_config.telem_evts[index].evt_id, - index)) { - pr_err("PSS TELEM_ADD Fail for Event %x\n", - pss_evtmap[idx]); - continue; - } - telm_conf->pss_config.ssram_evts_used++; - } - } - - /* Enable Periodic Telemetry Events and enable SRAM trace */ - TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); - TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); - TELEM_ENABLE_PERIODIC(telem_ctrl); - telem_ctrl |= pss_period; - - ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, - 0, 0, &telem_ctrl, NULL); - if (ret) { - pr_err("PSS TELEM_CTRL Event Enable Write Failed\n"); - return ret; - } - - telm_conf->pss_config.curr_period = pss_period; - - return 0; -} - -static int telemetry_setup_evtconfig(struct telemetry_evtconfig pss_evtconfig, - struct telemetry_evtconfig ioss_evtconfig, - enum telemetry_action action) -{ - int ret; - - mutex_lock(&(telm_conf->telem_lock)); - - if ((action == TELEM_UPDATE) && (telm_conf->telem_in_use)) { - ret = -EBUSY; - goto out; - } - - ret = telemetry_check_evtid(TELEM_PSS, pss_evtconfig.evtmap, - pss_evtconfig.num_evts, action); - if (ret) - goto out; - - ret = telemetry_check_evtid(TELEM_IOSS, ioss_evtconfig.evtmap, - ioss_evtconfig.num_evts, action); - if (ret) - goto out; - - if (ioss_evtconfig.num_evts) { - ret = telemetry_setup_iossevtconfig(ioss_evtconfig, action); - if (ret) - goto out; - } - - if (pss_evtconfig.num_evts) { - ret = telemetry_setup_pssevtconfig(pss_evtconfig, action); - if (ret) - goto out; - } - - if ((action == TELEM_UPDATE) || (action == TELEM_ADD)) - telm_conf->telem_in_use = true; - else - telm_conf->telem_in_use = false; - -out: - mutex_unlock(&(telm_conf->telem_lock)); - return ret; -} - -static int telemetry_setup(struct platform_device *pdev) -{ - struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; - u32 read_buf, events, event_regs; - int ret; - - ret = intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, - IOSS_TELEM_INFO_READ, NULL, 0, - &read_buf, sizeof(read_buf)); - if (ret) { - dev_err(&pdev->dev, "IOSS TELEM_INFO Read Failed\n"); - return ret; - } - - /* Get telemetry Info */ - events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >> - TELEM_INFO_SRAMEVTS_SHIFT; - event_regs = read_buf & TELEM_INFO_NENABLES_MASK; - if ((events < TELEM_MAX_EVENTS_SRAM) || - (event_regs < TELEM_MAX_EVENTS_SRAM)) { - dev_err(&pdev->dev, "IOSS:Insufficient Space for SRAM Trace\n"); - dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n", - events, event_regs); - return -ENOMEM; - } - - telm_conf->ioss_config.min_period = TELEM_MIN_PERIOD(read_buf); - telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf); - - /* PUNIT Mailbox Setup */ - ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0, - NULL, &read_buf); - if (ret) { - dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n"); - return ret; - } - - /* Get telemetry Info */ - events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >> - TELEM_INFO_SRAMEVTS_SHIFT; - event_regs = read_buf & TELEM_INFO_SRAMEVTS_MASK; - if ((events < TELEM_MAX_EVENTS_SRAM) || - (event_regs < TELEM_MAX_EVENTS_SRAM)) { - dev_err(&pdev->dev, "PSS:Insufficient Space for SRAM Trace\n"); - dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n", - events, event_regs); - return -ENOMEM; - } - - telm_conf->pss_config.min_period = TELEM_MIN_PERIOD(read_buf); - telm_conf->pss_config.max_period = TELEM_MAX_PERIOD(read_buf); - - pss_evtconfig.evtmap = NULL; - pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; - pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; - - ioss_evtconfig.evtmap = NULL; - ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; - ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; - - ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, - TELEM_RESET); - if (ret) { - dev_err(&pdev->dev, "TELEMETRY Setup Failed\n"); - return ret; - } - return 0; -} - -static int telemetry_plt_update_events(struct telemetry_evtconfig pss_evtconfig, - struct telemetry_evtconfig ioss_evtconfig) -{ - int ret; - - if ((pss_evtconfig.num_evts > 0) && - (TELEM_SAMPLE_PERIOD_INVALID(pss_evtconfig.period))) { - pr_err("PSS Sampling Period Out of Range\n"); - return -EINVAL; - } - - if ((ioss_evtconfig.num_evts > 0) && - (TELEM_SAMPLE_PERIOD_INVALID(ioss_evtconfig.period))) { - pr_err("IOSS Sampling Period Out of Range\n"); - return -EINVAL; - } - - ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, - TELEM_UPDATE); - if (ret) - pr_err("TELEMETRY Config Failed\n"); - - return ret; -} - - -static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period) -{ - u32 telem_ctrl = 0; - int ret = 0; - - mutex_lock(&(telm_conf->telem_lock)); - if (ioss_period) { - struct intel_scu_ipc_dev *scu = telm_conf->scu; - - if (TELEM_SAMPLE_PERIOD_INVALID(ioss_period)) { - pr_err("IOSS Sampling Period Out of Range\n"); - ret = -EINVAL; - goto out; - } - - /* Get telemetry EVENT CTL */ - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_READ, NULL, 0, - &telem_ctrl, sizeof(telem_ctrl)); - if (ret) { - pr_err("IOSS TELEM_CTRL Read Failed\n"); - goto out; - } - - /* Disable Telemetry */ - TELEM_DISABLE(telem_ctrl); - - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_WRITE, - &telem_ctrl, sizeof(telem_ctrl), - NULL, 0); - if (ret) { - pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n"); - goto out; - } - - /* Enable Periodic Telemetry Events and enable SRAM trace */ - TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); - TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); - TELEM_ENABLE_PERIODIC(telem_ctrl); - telem_ctrl |= ioss_period; - - ret = intel_scu_ipc_dev_command(scu, IOSS_TELEM, - IOSS_TELEM_EVENT_CTL_WRITE, - &telem_ctrl, sizeof(telem_ctrl), - NULL, 0); - if (ret) { - pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n"); - goto out; - } - telm_conf->ioss_config.curr_period = ioss_period; - } - - if (pss_period) { - if (TELEM_SAMPLE_PERIOD_INVALID(pss_period)) { - pr_err("PSS Sampling Period Out of Range\n"); - ret = -EINVAL; - goto out; - } - - /* Get telemetry EVENT CTL */ - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL, - 0, 0, NULL, &telem_ctrl); - if (ret) { - pr_err("PSS TELEM_CTRL Read Failed\n"); - goto out; - } - - /* Disable Telemetry */ - TELEM_DISABLE(telem_ctrl); - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, - 0, 0, &telem_ctrl, NULL); - if (ret) { - pr_err("PSS TELEM_CTRL Event Disable Write Failed\n"); - goto out; - } - - /* Enable Periodic Telemetry Events and enable SRAM trace */ - TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl); - TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl); - TELEM_ENABLE_PERIODIC(telem_ctrl); - telem_ctrl |= pss_period; - - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, - 0, 0, &telem_ctrl, NULL); - if (ret) { - pr_err("PSS TELEM_CTRL Event Enable Write Failed\n"); - goto out; - } - telm_conf->pss_config.curr_period = pss_period; - } - -out: - mutex_unlock(&(telm_conf->telem_lock)); - return ret; -} - - -static int telemetry_plt_get_sampling_period(u8 *pss_min_period, - u8 *pss_max_period, - u8 *ioss_min_period, - u8 *ioss_max_period) -{ - *pss_min_period = telm_conf->pss_config.min_period; - *pss_max_period = telm_conf->pss_config.max_period; - *ioss_min_period = telm_conf->ioss_config.min_period; - *ioss_max_period = telm_conf->ioss_config.max_period; - - return 0; -} - - -static int telemetry_plt_reset_events(void) -{ - struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; - int ret; - - pss_evtconfig.evtmap = NULL; - pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; - pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; - - ioss_evtconfig.evtmap = NULL; - ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS; - ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD; - - ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, - TELEM_RESET); - if (ret) - pr_err("TELEMETRY Reset Failed\n"); - - return ret; -} - - -static int telemetry_plt_get_eventconfig(struct telemetry_evtconfig *pss_config, - struct telemetry_evtconfig *ioss_config, - int pss_len, int ioss_len) -{ - u32 *pss_evtmap, *ioss_evtmap; - u32 index; - - pss_evtmap = pss_config->evtmap; - ioss_evtmap = ioss_config->evtmap; - - mutex_lock(&(telm_conf->telem_lock)); - pss_config->num_evts = telm_conf->pss_config.ssram_evts_used; - ioss_config->num_evts = telm_conf->ioss_config.ssram_evts_used; - - pss_config->period = telm_conf->pss_config.curr_period; - ioss_config->period = telm_conf->ioss_config.curr_period; - - if ((pss_len < telm_conf->pss_config.ssram_evts_used) || - (ioss_len < telm_conf->ioss_config.ssram_evts_used)) { - mutex_unlock(&(telm_conf->telem_lock)); - return -EINVAL; - } - - for (index = 0; index < telm_conf->pss_config.ssram_evts_used; - index++) { - pss_evtmap[index] = - telm_conf->pss_config.telem_evts[index].evt_id; - } - - for (index = 0; index < telm_conf->ioss_config.ssram_evts_used; - index++) { - ioss_evtmap[index] = - telm_conf->ioss_config.telem_evts[index].evt_id; - } - - mutex_unlock(&(telm_conf->telem_lock)); - return 0; -} - - -static int telemetry_plt_add_events(u8 num_pss_evts, u8 num_ioss_evts, - u32 *pss_evtmap, u32 *ioss_evtmap) -{ - struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig; - int ret; - - pss_evtconfig.evtmap = pss_evtmap; - pss_evtconfig.num_evts = num_pss_evts; - pss_evtconfig.period = telm_conf->pss_config.curr_period; - - ioss_evtconfig.evtmap = ioss_evtmap; - ioss_evtconfig.num_evts = num_ioss_evts; - ioss_evtconfig.period = telm_conf->ioss_config.curr_period; - - ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, - TELEM_ADD); - if (ret) - pr_err("TELEMETRY ADD Failed\n"); - - return ret; -} - -static int telem_evtlog_read(enum telemetry_unit telem_unit, - struct telem_ssram_region *ssram_region, u8 len) -{ - struct telemetry_unit_config *unit_config; - u64 timestamp_prev, timestamp_next; - int ret, index, timeout = 0; - - ret = telem_get_unitconfig(telem_unit, &unit_config); - if (ret < 0) - return ret; - - if (len > unit_config->ssram_evts_used) - len = unit_config->ssram_evts_used; - - do { - timestamp_prev = readq(unit_config->regmap); - if (!timestamp_prev) { - pr_err("Ssram under update. Please Try Later\n"); - return -EBUSY; - } - - ssram_region->start_time = readq(unit_config->regmap + - TELEM_SSRAM_STARTTIME_OFFSET); - - for (index = 0; index < len; index++) { - ssram_region->events[index] = - readq(unit_config->regmap + TELEM_SSRAM_EVTLOG_OFFSET + - BYTES_PER_LONG*index); - } - - timestamp_next = readq(unit_config->regmap); - if (!timestamp_next) { - pr_err("Ssram under update. Please Try Later\n"); - return -EBUSY; - } - - if (timeout++ > TELEM_SSRAM_READ_TIMEOUT) { - pr_err("Timeout while reading Events\n"); - return -EBUSY; - } - - } while (timestamp_prev != timestamp_next); - - ssram_region->timestamp = timestamp_next; - - return len; -} - -static int telemetry_plt_raw_read_eventlog(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, - int len, int log_all_evts) -{ - int index, idx1, ret, readlen = len; - struct telem_ssram_region ssram_region; - struct telemetry_evtmap *evtmap; - - switch (telem_unit) { - case TELEM_PSS: - evtmap = telm_conf->pss_config.telem_evts; - break; - - case TELEM_IOSS: - evtmap = telm_conf->ioss_config.telem_evts; - break; - - default: - pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); - return -EINVAL; - } - - if (!log_all_evts) - readlen = TELEM_MAX_EVENTS_SRAM; - - ret = telem_evtlog_read(telem_unit, &ssram_region, readlen); - if (ret < 0) - return ret; - - /* Invalid evt-id array specified via length mismatch */ - if ((!log_all_evts) && (len > ret)) - return -EINVAL; - - if (log_all_evts) - for (index = 0; index < ret; index++) { - evtlog[index].telem_evtlog = ssram_region.events[index]; - evtlog[index].telem_evtid = evtmap[index].evt_id; - } - else - for (index = 0, readlen = 0; (index < ret) && (readlen < len); - index++) { - for (idx1 = 0; idx1 < len; idx1++) { - /* Elements matched */ - if (evtmap[index].evt_id == - evtlog[idx1].telem_evtid) { - evtlog[idx1].telem_evtlog = - ssram_region.events[index]; - readlen++; - - break; - } - } - } - - return readlen; -} - -static int telemetry_plt_read_eventlog(enum telemetry_unit telem_unit, - struct telemetry_evtlog *evtlog, int len, int log_all_evts) -{ - int ret; - - mutex_lock(&(telm_conf->telem_lock)); - ret = telemetry_plt_raw_read_eventlog(telem_unit, evtlog, - len, log_all_evts); - mutex_unlock(&(telm_conf->telem_lock)); - - return ret; -} - -static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit, - u32 *verbosity) -{ - u32 temp = 0; - int ret; - - if (verbosity == NULL) - return -EINVAL; - - mutex_lock(&(telm_conf->telem_trace_lock)); - switch (telem_unit) { - case TELEM_PSS: - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, - 0, 0, NULL, &temp); - if (ret) { - pr_err("PSS TRACE_CTRL Read Failed\n"); - goto out; - } - - break; - - case TELEM_IOSS: - ret = intel_scu_ipc_dev_command(telm_conf->scu, - IOSS_TELEM, IOSS_TELEM_TRACE_CTL_READ, - NULL, 0, &temp, sizeof(temp)); - if (ret) { - pr_err("IOSS TRACE_CTL Read Failed\n"); - goto out; - } - - break; - - default: - pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); - ret = -EINVAL; - break; - } - TELEM_EXTRACT_VERBOSITY(temp, *verbosity); - -out: - mutex_unlock(&(telm_conf->telem_trace_lock)); - return ret; -} - -static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit, - u32 verbosity) -{ - u32 temp = 0; - int ret; - - verbosity &= TELEM_TRC_VERBOSITY_MASK; - - mutex_lock(&(telm_conf->telem_trace_lock)); - switch (telem_unit) { - case TELEM_PSS: - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, - 0, 0, NULL, &temp); - if (ret) { - pr_err("PSS TRACE_CTRL Read Failed\n"); - goto out; - } - - TELEM_CLEAR_VERBOSITY_BITS(temp); - TELEM_SET_VERBOSITY_BITS(temp, verbosity); - - ret = intel_punit_ipc_command( - IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL, - 0, 0, &temp, NULL); - if (ret) { - pr_err("PSS TRACE_CTRL Verbosity Set Failed\n"); - goto out; - } - break; - - case TELEM_IOSS: - ret = intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, - IOSS_TELEM_TRACE_CTL_READ, - NULL, 0, &temp, sizeof(temp)); - if (ret) { - pr_err("IOSS TRACE_CTL Read Failed\n"); - goto out; - } - - TELEM_CLEAR_VERBOSITY_BITS(temp); - TELEM_SET_VERBOSITY_BITS(temp, verbosity); - - ret = intel_scu_ipc_dev_command(telm_conf->scu, IOSS_TELEM, - IOSS_TELEM_TRACE_CTL_WRITE, - &temp, sizeof(temp), NULL, 0); - if (ret) { - pr_err("IOSS TRACE_CTL Verbosity Set Failed\n"); - goto out; - } - break; - - default: - pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit); - ret = -EINVAL; - break; - } - -out: - mutex_unlock(&(telm_conf->telem_trace_lock)); - return ret; -} - -static const struct telemetry_core_ops telm_pltops = { - .get_trace_verbosity = telemetry_plt_get_trace_verbosity, - .set_trace_verbosity = telemetry_plt_set_trace_verbosity, - .set_sampling_period = telemetry_plt_set_sampling_period, - .get_sampling_period = telemetry_plt_get_sampling_period, - .raw_read_eventlog = telemetry_plt_raw_read_eventlog, - .get_eventconfig = telemetry_plt_get_eventconfig, - .update_events = telemetry_plt_update_events, - .read_eventlog = telemetry_plt_read_eventlog, - .reset_events = telemetry_plt_reset_events, - .add_events = telemetry_plt_add_events, -}; - -static int telemetry_pltdrv_probe(struct platform_device *pdev) -{ - const struct x86_cpu_id *id; - void __iomem *mem; - int ret; - - id = x86_match_cpu(telemetry_cpu_ids); - if (!id) - return -ENODEV; - - telm_conf = (struct telemetry_plt_config *)id->driver_data; - - telm_conf->pmc = dev_get_drvdata(pdev->dev.parent); - - mem = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(mem)) - return PTR_ERR(mem); - - telm_conf->pss_config.regmap = mem; - - mem = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(mem)) - return PTR_ERR(mem); - - telm_conf->ioss_config.regmap = mem; - - telm_conf->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); - if (!telm_conf->scu) { - ret = -EPROBE_DEFER; - goto out; - } - - mutex_init(&telm_conf->telem_lock); - mutex_init(&telm_conf->telem_trace_lock); - - ret = telemetry_setup(pdev); - if (ret) - goto out; - - ret = telemetry_set_pltdata(&telm_pltops, telm_conf); - if (ret) { - dev_err(&pdev->dev, "TELEMETRY Set Pltops Failed.\n"); - goto out; - } - - return 0; - -out: - dev_err(&pdev->dev, "TELEMETRY Setup Failed.\n"); - - return ret; -} - -static int telemetry_pltdrv_remove(struct platform_device *pdev) -{ - telemetry_clear_pltdata(); - return 0; -} - -static struct platform_driver telemetry_soc_driver = { - .probe = telemetry_pltdrv_probe, - .remove = telemetry_pltdrv_remove, - .driver = { - .name = DRIVER_NAME, - }, -}; - -static int __init telemetry_module_init(void) -{ - return platform_driver_register(&telemetry_soc_driver); -} - -static void __exit telemetry_module_exit(void) -{ - platform_driver_unregister(&telemetry_soc_driver); -} - -device_initcall(telemetry_module_init); -module_exit(telemetry_module_exit); - -MODULE_AUTHOR("Souvik Kumar Chakravarty "); -MODULE_DESCRIPTION("Intel SoC Telemetry Platform Driver"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL v2");