961 lines · 26.8 KB · C
RawDownload
// 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 <linux/debugfs.h>#include <linux/device.h>#include <linux/mfd/intel_pmc_bxt.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/seq_file.h>#include <linux/suspend.h> #include <asm/cpu_device_id.h>#include <asm/intel-family.h>#include <asm/intel_telemetry.h> #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_VFM(INTEL_ATOM_GOLDMONT,	&telem_apl_debugfs_conf),	X86_MATCH_VFM(INTEL_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_ltr_blkd[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_s0ix_wakeup[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){

Lines 1–500 of 961.