diff options
Diffstat (limited to 'drivers/platform/x86/intel')
| -rw-r--r-- | drivers/platform/x86/intel/ifs/load.c | 2 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/ifs/runtest.c | 27 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/pmc/arl.c | 2 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/pmc/core.c | 38 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/pmc/core.h | 9 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/pmc/lnl.c | 477 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/rst.c | 1 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/sdsi.c | 118 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/smartconnect.c | 1 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/speed_select_if/isst_if_common.c | 1 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c | 383 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/tpmi.c | 39 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c | 7 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/vbtn.c | 3 | 
14 files changed, 772 insertions, 336 deletions
| diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index 584c44387e10..39f19cb51749 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -233,7 +233,9 @@ static int copy_hashes_authenticate_chunks_gen2(struct device *dev)  		chunk_table[0] = starting_chunk_nr + i;  		chunk_table[1] = linear_addr;  		do { +			local_irq_disable();  			wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table); +			local_irq_enable();  			rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);  			err_code = chunk_status.error_code;  		} while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count); diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c index 95b4b71fab53..282e4bfe30da 100644 --- a/drivers/platform/x86/intel/ifs/runtest.c +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -69,6 +69,19 @@ static const char * const scan_test_status[] = {  static void message_not_tested(struct device *dev, int cpu, union ifs_status status)  { +	struct ifs_data *ifsd = ifs_get_data(dev); + +	/* +	 * control_error is set when the microcode runs into a problem +	 * loading the image from the reserved BIOS memory, or it has +	 * been corrupted. Reloading the image may fix this issue. +	 */ +	if (status.control_error) { +		dev_warn(dev, "CPU(s) %*pbl: Scan controller error. Batch: %02x version: 0x%x\n", +			 cpumask_pr_args(cpu_smt_mask(cpu)), ifsd->cur_batch, ifsd->loaded_version); +		return; +	} +  	if (status.error_code < ARRAY_SIZE(scan_test_status)) {  		dev_info(dev, "CPU(s) %*pbl: SCAN operation did not start. %s\n",  			 cpumask_pr_args(cpu_smt_mask(cpu)), @@ -91,16 +104,6 @@ static void message_fail(struct device *dev, int cpu, union ifs_status status)  	struct ifs_data *ifsd = ifs_get_data(dev);  	/* -	 * control_error is set when the microcode runs into a problem -	 * loading the image from the reserved BIOS memory, or it has -	 * been corrupted. Reloading the image may fix this issue. -	 */ -	if (status.control_error) { -		dev_err(dev, "CPU(s) %*pbl: could not execute from loaded scan image. Batch: %02x version: 0x%x\n", -			cpumask_pr_args(cpu_smt_mask(cpu)), ifsd->cur_batch, ifsd->loaded_version); -	} - -	/*  	 * signature_error is set when the output from the scan chains does not  	 * match the expected signature. This might be a transient problem (e.g.  	 * due to a bit flip from an alpha particle or neutron). If the problem @@ -285,10 +288,10 @@ static void ifs_test_core(int cpu, struct device *dev)  	/* Update status for this core */  	ifsd->scan_details = status.data; -	if (status.control_error || status.signature_error) { +	if (status.signature_error) {  		ifsd->status = SCAN_TEST_FAIL;  		message_fail(dev, cpu, status); -	} else if (status.error_code) { +	} else if (status.control_error || status.error_code) {  		ifsd->status = SCAN_NOT_TESTED;  		message_not_tested(dev, cpu, status);  	} else { diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c index 34b4cd23bfe5..e10527c4e3e0 100644 --- a/drivers/platform/x86/intel/pmc/arl.c +++ b/drivers/platform/x86/intel/pmc/arl.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  /*   * This file contains platform specific structure definitions - * and init function used by Meteor Lake PCH. + * and init function used by Arrow Lake PCH.   *   * Copyright (c) 2022, Intel Corporation.   * All Rights Reserved. diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 10c96c1a850a..2ad2f8753e5d 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -678,6 +678,41 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused)  }  DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr); +static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused) +{ +	struct pmc_dev *pmcdev = s->private; +	unsigned int pmcidx; + +	for (pmcidx = 0; pmcidx < ARRAY_SIZE(pmcdev->pmcs); pmcidx++) { +		const struct pmc_bit_map **maps; +		unsigned int arr_size, r_idx; +		u32 offset, counter; +		struct pmc *pmc; + +		pmc = pmcdev->pmcs[pmcidx]; +		if (!pmc) +			continue; +		maps = pmc->map->s0ix_blocker_maps; +		offset = pmc->map->s0ix_blocker_offset; +		arr_size = pmc_core_lpm_get_arr_size(maps); + +		for (r_idx = 0; r_idx < arr_size; r_idx++) { +			const struct pmc_bit_map *map; + +			for (map = maps[r_idx]; map->name; map++) { +				if (!map->blk) +					continue; +				counter = pmc_core_reg_read(pmc, offset); +				seq_printf(s, "PMC%d:%-30s %-30d\n", pmcidx, +					   map->name, counter); +				offset += map->blk * S0IX_BLK_SIZE; +			} +		} +	} +	return 0; +} +DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker); +  static inline u64 adjust_lpm_residency(struct pmc *pmc, u32 offset,  				       const int lpm_adj_x2)  { @@ -1197,6 +1232,9 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)  	debugfs_create_file("ltr_show", 0444, dir, pmcdev, &pmc_core_ltr_fops); +	if (primary_pmc->map->s0ix_blocker_maps) +		debugfs_create_file("s0ix_blocker", 0444, dir, pmcdev, &pmc_core_s0ix_blocker_fops); +  	debugfs_create_file("package_cstate_show", 0444, dir, primary_pmc,  			    &pmc_core_pkgc_fops); diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h index 83504c49a0e3..ea04de7eb9e8 100644 --- a/drivers/platform/x86/intel/pmc/core.h +++ b/drivers/platform/x86/intel/pmc/core.h @@ -22,6 +22,7 @@ struct telem_endpoint;  #define PMC_BASE_ADDR_DEFAULT			0xFE000000  #define MAX_NUM_PMC			3 +#define S0IX_BLK_SIZE			4  /* Sunrise Point Power Management Controller PCI Device ID */  #define SPT_PMC_PCI_DEVICE_ID			0x9d21 @@ -282,12 +283,14 @@ enum ppfear_regs {  #define LNL_PMC_LTR_OSSE			0x1B88  #define LNL_NUM_IP_IGN_ALLOWED			27  #define LNL_PPFEAR_NUM_ENTRIES			12 +#define LNL_S0IX_BLOCKER_OFFSET			0x2004  extern const char *pmc_lpm_modes[];  struct pmc_bit_map {  	const char *name;  	u32 bit_mask; +	u8 blk;  };  /** @@ -298,6 +301,7 @@ struct pmc_bit_map {   * @pll_sts:		Maps name of PLL to corresponding bit status   * @slps0_dbg_maps:	Array of SLP_S0_DBG* registers containing debug info   * @ltr_show_sts:	Maps PCH IP Names to their MMIO register offsets + * @s0ix_blocker_maps:	Maps name of IP block to S0ix blocker counter   * @slp_s0_offset:	PWRMBASE offset to read SLP_S0 residency   * @ltr_ignore_offset:	PWRMBASE offset to read/write LTR ignore bit   * @regmap_length:	Length of memory to map from PWRMBASE address to access @@ -307,6 +311,7 @@ struct pmc_bit_map {   * @pm_cfg_offset:	PWRMBASE offset to PM_CFG register   * @pm_read_disable_bit: Bit index to read PMC_READ_DISABLE   * @slps0_dbg_offset:	PWRMBASE offset to SLP_S0_DEBUG_REG* + * @s0ix_blocker_offset PWRMBASE offset to S0ix blocker counter   *   * Each PCH has unique set of register offsets and bit indexes. This structure   * captures them to have a common implementation. @@ -319,6 +324,7 @@ struct pmc_reg_map {  	const struct pmc_bit_map *ltr_show_sts;  	const struct pmc_bit_map *msr_sts;  	const struct pmc_bit_map **lpm_sts; +	const struct pmc_bit_map **s0ix_blocker_maps;  	const u32 slp_s0_offset;  	const int slp_s0_res_counter_step;  	const u32 ltr_ignore_offset; @@ -330,6 +336,7 @@ struct pmc_reg_map {  	const u32 slps0_dbg_offset;  	const u32 ltr_ignore_max;  	const u32 pm_vric1_offset; +	const u32 s0ix_blocker_offset;  	/* Low Power Mode registers */  	const int lpm_num_maps;  	const int lpm_num_modes; @@ -535,8 +542,10 @@ extern const struct pmc_bit_map lnl_vnn_req_status_2_map[];  extern const struct pmc_bit_map lnl_vnn_req_status_3_map[];  extern const struct pmc_bit_map lnl_vnn_misc_status_map[];  extern const struct pmc_bit_map *lnl_lpm_maps[]; +extern const struct pmc_bit_map *lnl_blk_maps[];  extern const struct pmc_bit_map lnl_pfear_map[];  extern const struct pmc_bit_map *ext_lnl_pfear_map[]; +extern const struct pmc_bit_map lnl_signal_status_map[];  /* ARL */  extern const struct pmc_bit_map arl_socs_ltr_show_map[]; diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c index 068d72504683..e7a8077d1a3e 100644 --- a/drivers/platform/x86/intel/pmc/lnl.c +++ b/drivers/platform/x86/intel/pmc/lnl.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  /*   * This file contains platform specific structure definitions - * and init function used by Meteor Lake PCH. + * and init function used by Lunar Lake PCH.   *   * Copyright (c) 2022, Intel Corporation.   * All Rights Reserved. @@ -56,264 +56,296 @@ const struct pmc_bit_map lnl_ltr_show_map[] = {  };  const struct pmc_bit_map lnl_power_gating_status_0_map[] = { -	{"PMC_PGD0_PG_STS",			BIT(0)}, -	{"FUSE_OSSE_PGD0_PG_STS",		BIT(1)}, -	{"ESPISPI_PGD0_PG_STS",			BIT(2)}, -	{"XHCI_PGD0_PG_STS",			BIT(3)}, -	{"SPA_PGD0_PG_STS",			BIT(4)}, -	{"SPB_PGD0_PG_STS",			BIT(5)}, -	{"SPR16B0_PGD0_PG_STS",			BIT(6)}, -	{"GBE_PGD0_PG_STS",			BIT(7)}, -	{"SBR8B7_PGD0_PG_STS",			BIT(8)}, -	{"SBR8B6_PGD0_PG_STS",			BIT(9)}, -	{"SBR16B1_PGD0_PG_STS",			BIT(10)}, -	{"SBR8B8_PGD0_PG_STS",			BIT(11)}, -	{"ESE_PGD3_PG_STS",			BIT(12)}, -	{"D2D_DISP_PGD0_PG_STS",		BIT(13)}, -	{"LPSS_PGD0_PG_STS",			BIT(14)}, -	{"LPC_PGD0_PG_STS",			BIT(15)}, -	{"SMB_PGD0_PG_STS",			BIT(16)}, -	{"ISH_PGD0_PG_STS",			BIT(17)}, -	{"SBR8B2_PGD0_PG_STS",			BIT(18)}, -	{"NPK_PGD0_PG_STS",			BIT(19)}, -	{"D2D_NOC_PGD0_PG_STS",			BIT(20)}, -	{"SAFSS_PGD0_PG_STS",			BIT(21)}, -	{"FUSE_PGD0_PG_STS",			BIT(22)}, -	{"D2D_DISP_PGD1_PG_STS",		BIT(23)}, -	{"MPFPW1_PGD0_PG_STS",			BIT(24)}, -	{"XDCI_PGD0_PG_STS",			BIT(25)}, -	{"EXI_PGD0_PG_STS",			BIT(26)}, -	{"CSE_PGD0_PG_STS",			BIT(27)}, -	{"KVMCC_PGD0_PG_STS",			BIT(28)}, -	{"PMT_PGD0_PG_STS",			BIT(29)}, -	{"CLINK_PGD0_PG_STS",			BIT(30)}, -	{"PTIO_PGD0_PG_STS",			BIT(31)}, +	{"PMC_PGD0_PG_STS",			BIT(0),		0}, +	{"FUSE_OSSE_PGD0_PG_STS",		BIT(1),		0}, +	{"ESPISPI_PGD0_PG_STS",			BIT(2),		0}, +	{"XHCI_PGD0_PG_STS",			BIT(3),		1}, +	{"SPA_PGD0_PG_STS",			BIT(4),		1}, +	{"SPB_PGD0_PG_STS",			BIT(5),		1}, +	{"SPR16B0_PGD0_PG_STS",			BIT(6),		0}, +	{"GBE_PGD0_PG_STS",			BIT(7),		1}, +	{"SBR8B7_PGD0_PG_STS",			BIT(8),		0}, +	{"SBR8B6_PGD0_PG_STS",			BIT(9),		0}, +	{"SBR16B1_PGD0_PG_STS",			BIT(10),	0}, +	{"SBR8B8_PGD0_PG_STS",			BIT(11),	0}, +	{"ESE_PGD3_PG_STS",			BIT(12),	1}, +	{"D2D_DISP_PGD0_PG_STS",		BIT(13),	1}, +	{"LPSS_PGD0_PG_STS",			BIT(14),	1}, +	{"LPC_PGD0_PG_STS",			BIT(15),	0}, +	{"SMB_PGD0_PG_STS",			BIT(16),	0}, +	{"ISH_PGD0_PG_STS",			BIT(17),	0}, +	{"SBR8B2_PGD0_PG_STS",			BIT(18),	0}, +	{"NPK_PGD0_PG_STS",			BIT(19),	0}, +	{"D2D_NOC_PGD0_PG_STS",			BIT(20),	0}, +	{"SAFSS_PGD0_PG_STS",			BIT(21),	0}, +	{"FUSE_PGD0_PG_STS",			BIT(22),	0}, +	{"D2D_DISP_PGD1_PG_STS",		BIT(23),	1}, +	{"MPFPW1_PGD0_PG_STS",			BIT(24),	0}, +	{"XDCI_PGD0_PG_STS",			BIT(25),	1}, +	{"EXI_PGD0_PG_STS",			BIT(26),	0}, +	{"CSE_PGD0_PG_STS",			BIT(27),	1}, +	{"KVMCC_PGD0_PG_STS",			BIT(28),	1}, +	{"PMT_PGD0_PG_STS",			BIT(29),	1}, +	{"CLINK_PGD0_PG_STS",			BIT(30),	1}, +	{"PTIO_PGD0_PG_STS",			BIT(31),	1},  	{}  };  const struct pmc_bit_map lnl_power_gating_status_1_map[] = { -	{"USBR0_PGD0_PG_STS",			BIT(0)}, -	{"SUSRAM_PGD0_PG_STS",			BIT(1)}, -	{"SMT1_PGD0_PG_STS",			BIT(2)}, -	{"U3FPW1_PGD0_PG_STS",			BIT(3)}, -	{"SMS2_PGD0_PG_STS",			BIT(4)}, -	{"SMS1_PGD0_PG_STS",			BIT(5)}, -	{"CSMERTC_PGD0_PG_STS",			BIT(6)}, -	{"CSMEPSF_PGD0_PG_STS",			BIT(7)}, -	{"FIA_PG_PGD0_PG_STS",			BIT(8)}, -	{"SBR16B4_PGD0_PG_STS",			BIT(9)}, -	{"P2SB8B_PGD0_PG_STS",			BIT(10)}, -	{"DBG_SBR_PGD0_PG_STS",			BIT(11)}, -	{"SBR8B9_PGD0_PG_STS",			BIT(12)}, -	{"OSSE_SMT1_PGD0_PG_STS",		BIT(13)}, -	{"SBR8B10_PGD0_PG_STS",			BIT(14)}, -	{"SBR16B3_PGD0_PG_STS",			BIT(15)}, -	{"G5FPW1_PGD0_PG_STS",			BIT(16)}, -	{"SBRG_PGD0_PG_STS",			BIT(17)}, -	{"PSF4_PGD0_PG_STS",			BIT(18)}, -	{"CNVI_PGD0_PG_STS",			BIT(19)}, -	{"USFX2_PGD0_PG_STS",			BIT(20)}, -	{"ENDBG_PGD0_PG_STS",			BIT(21)}, -	{"FIACPCB_P5X4_PGD0_PG_STS",		BIT(22)}, -	{"SBR8B3_PGD0_PG_STS",			BIT(23)}, -	{"SBR8B0_PGD0_PG_STS",			BIT(24)}, -	{"NPK_PGD1_PG_STS",			BIT(25)}, -	{"OSSE_HOTHAM_PGD0_PG_STS",		BIT(26)}, -	{"D2D_NOC_PGD2_PG_STS",			BIT(27)}, -	{"SBR8B1_PGD0_PG_STS",			BIT(28)}, -	{"PSF6_PGD0_PG_STS",			BIT(29)}, -	{"PSF7_PGD0_PG_STS",			BIT(30)}, -	{"FIA_U_PGD0_PG_STS",			BIT(31)}, +	{"USBR0_PGD0_PG_STS",			BIT(0),		1}, +	{"SUSRAM_PGD0_PG_STS",			BIT(1),		1}, +	{"SMT1_PGD0_PG_STS",			BIT(2),		1}, +	{"U3FPW1_PGD0_PG_STS",			BIT(3),		0}, +	{"SMS2_PGD0_PG_STS",			BIT(4),		1}, +	{"SMS1_PGD0_PG_STS",			BIT(5),		1}, +	{"CSMERTC_PGD0_PG_STS",			BIT(6),		0}, +	{"CSMEPSF_PGD0_PG_STS",			BIT(7),		0}, +	{"FIA_PG_PGD0_PG_STS",			BIT(8),		0}, +	{"SBR16B4_PGD0_PG_STS",			BIT(9),		0}, +	{"P2SB8B_PGD0_PG_STS",			BIT(10),	1}, +	{"DBG_SBR_PGD0_PG_STS",			BIT(11),	0}, +	{"SBR8B9_PGD0_PG_STS",			BIT(12),	0}, +	{"OSSE_SMT1_PGD0_PG_STS",		BIT(13),	1}, +	{"SBR8B10_PGD0_PG_STS",			BIT(14),	0}, +	{"SBR16B3_PGD0_PG_STS",			BIT(15),	0}, +	{"G5FPW1_PGD0_PG_STS",			BIT(16),	0}, +	{"SBRG_PGD0_PG_STS",			BIT(17),	0}, +	{"PSF4_PGD0_PG_STS",			BIT(18),	0}, +	{"CNVI_PGD0_PG_STS",			BIT(19),	0}, +	{"USFX2_PGD0_PG_STS",			BIT(20),	1}, +	{"ENDBG_PGD0_PG_STS",			BIT(21),	0}, +	{"FIACPCB_P5X4_PGD0_PG_STS",		BIT(22),	0}, +	{"SBR8B3_PGD0_PG_STS",			BIT(23),	0}, +	{"SBR8B0_PGD0_PG_STS",			BIT(24),	0}, +	{"NPK_PGD1_PG_STS",			BIT(25),	0}, +	{"OSSE_HOTHAM_PGD0_PG_STS",		BIT(26),	1}, +	{"D2D_NOC_PGD2_PG_STS",			BIT(27),	1}, +	{"SBR8B1_PGD0_PG_STS",			BIT(28),	0}, +	{"PSF6_PGD0_PG_STS",			BIT(29),	0}, +	{"PSF7_PGD0_PG_STS",			BIT(30),	0}, +	{"FIA_U_PGD0_PG_STS",			BIT(31),	0},  	{}  };  const struct pmc_bit_map lnl_power_gating_status_2_map[] = { -	{"PSF8_PGD0_PG_STS",			BIT(0)}, -	{"SBR16B2_PGD0_PG_STS",			BIT(1)}, -	{"D2D_IPU_PGD0_PG_STS",			BIT(2)}, -	{"FIACPCB_U_PGD0_PG_STS",		BIT(3)}, -	{"TAM_PGD0_PG_STS",			BIT(4)}, -	{"D2D_NOC_PGD1_PG_STS",			BIT(5)}, -	{"TBTLSX_PGD0_PG_STS",			BIT(6)}, -	{"THC0_PGD0_PG_STS",			BIT(7)}, -	{"THC1_PGD0_PG_STS",			BIT(8)}, -	{"PMC_PGD0_PG_STS",			BIT(9)}, -	{"SBR8B5_PGD0_PG_STS",			BIT(10)}, -	{"UFSPW1_PGD0_PG_STS",			BIT(11)}, -	{"DBC_PGD0_PG_STS",			BIT(12)}, -	{"TCSS_PGD0_PG_STS",			BIT(13)}, -	{"FIA_P5X4_PGD0_PG_STS",		BIT(14)}, -	{"DISP_PGA_PGD0_PG_STS",		BIT(15)}, -	{"DISP_PSF_PGD0_PG_STS",		BIT(16)}, -	{"PSF0_PGD0_PG_STS",			BIT(17)}, -	{"P2SB16B_PGD0_PG_STS",			BIT(18)}, -	{"ACE_PGD0_PG_STS",			BIT(19)}, -	{"ACE_PGD1_PG_STS",			BIT(20)}, -	{"ACE_PGD2_PG_STS",			BIT(21)}, -	{"ACE_PGD3_PG_STS",			BIT(22)}, -	{"ACE_PGD4_PG_STS",			BIT(23)}, -	{"ACE_PGD5_PG_STS",			BIT(24)}, -	{"ACE_PGD6_PG_STS",			BIT(25)}, -	{"ACE_PGD7_PG_STS",			BIT(26)}, -	{"ACE_PGD8_PG_STS",			BIT(27)}, -	{"ACE_PGD9_PG_STS",			BIT(28)}, -	{"ACE_PGD10_PG_STS",			BIT(29)}, -	{"FIACPCB_PG_PGD0_PG_STS",		BIT(30)}, -	{"OSSE_PGD0_PG_STS",			BIT(31)}, +	{"PSF8_PGD0_PG_STS",			BIT(0),		0}, +	{"SBR16B2_PGD0_PG_STS",			BIT(1),		0}, +	{"D2D_IPU_PGD0_PG_STS",			BIT(2),		1}, +	{"FIACPCB_U_PGD0_PG_STS",		BIT(3),		0}, +	{"TAM_PGD0_PG_STS",			BIT(4),		1}, +	{"D2D_NOC_PGD1_PG_STS",			BIT(5),		1}, +	{"TBTLSX_PGD0_PG_STS",			BIT(6),		1}, +	{"THC0_PGD0_PG_STS",			BIT(7),		1}, +	{"THC1_PGD0_PG_STS",			BIT(8),		1}, +	{"PMC_PGD0_PG_STS",			BIT(9),		0}, +	{"SBR8B5_PGD0_PG_STS",			BIT(10),	0}, +	{"UFSPW1_PGD0_PG_STS",			BIT(11),	0}, +	{"DBC_PGD0_PG_STS",			BIT(12),	0}, +	{"TCSS_PGD0_PG_STS",			BIT(13),	0}, +	{"FIA_P5X4_PGD0_PG_STS",		BIT(14),	0}, +	{"DISP_PGA_PGD0_PG_STS",		BIT(15),	0}, +	{"DISP_PSF_PGD0_PG_STS",		BIT(16),	0}, +	{"PSF0_PGD0_PG_STS",			BIT(17),	0}, +	{"P2SB16B_PGD0_PG_STS",			BIT(18),	1}, +	{"ACE_PGD0_PG_STS",			BIT(19),	0}, +	{"ACE_PGD1_PG_STS",			BIT(20),	0}, +	{"ACE_PGD2_PG_STS",			BIT(21),	0}, +	{"ACE_PGD3_PG_STS",			BIT(22),	0}, +	{"ACE_PGD4_PG_STS",			BIT(23),	0}, +	{"ACE_PGD5_PG_STS",			BIT(24),	0}, +	{"ACE_PGD6_PG_STS",			BIT(25),	0}, +	{"ACE_PGD7_PG_STS",			BIT(26),	0}, +	{"ACE_PGD8_PG_STS",			BIT(27),	0}, +	{"ACE_PGD9_PG_STS",			BIT(28),	0}, +	{"ACE_PGD10_PG_STS",			BIT(29),	0}, +	{"FIACPCB_PG_PGD0_PG_STS",		BIT(30),	0}, +	{"OSSE_PGD0_PG_STS",			BIT(31),	1},  	{}  };  const struct pmc_bit_map lnl_d3_status_0_map[] = { -	{"LPSS_D3_STS",				BIT(3)}, -	{"XDCI_D3_STS",				BIT(4)}, -	{"XHCI_D3_STS",				BIT(5)}, -	{"SPA_D3_STS",				BIT(12)}, -	{"SPB_D3_STS",				BIT(13)}, -	{"OSSE_D3_STS",				BIT(15)}, -	{"ESPISPI_D3_STS",			BIT(18)}, -	{"PSTH_D3_STS",				BIT(21)}, +	{"LPSS_D3_STS",				BIT(3),		1}, +	{"XDCI_D3_STS",				BIT(4),		1}, +	{"XHCI_D3_STS",				BIT(5),		1}, +	{"SPA_D3_STS",				BIT(12),	0}, +	{"SPB_D3_STS",				BIT(13),	0}, +	{"OSSE_D3_STS",				BIT(15),	0}, +	{"ESPISPI_D3_STS",			BIT(18),	0}, +	{"PSTH_D3_STS",				BIT(21),	0},  	{}  };  const struct pmc_bit_map lnl_d3_status_1_map[] = { -	{"OSSE_SMT1_D3_STS",			BIT(7)}, -	{"GBE_D3_STS",				BIT(19)}, -	{"ITSS_D3_STS",				BIT(23)}, -	{"CNVI_D3_STS",				BIT(27)}, -	{"UFSX2_D3_STS",			BIT(28)}, -	{"OSSE_HOTHAM_D3_STS",			BIT(31)}, +	{"OSSE_SMT1_D3_STS",			BIT(7),		0}, +	{"GBE_D3_STS",				BIT(19),	0}, +	{"ITSS_D3_STS",				BIT(23),	0}, +	{"CNVI_D3_STS",				BIT(27),	0}, +	{"UFSX2_D3_STS",			BIT(28),	1}, +	{"OSSE_HOTHAM_D3_STS",			BIT(31),	0},  	{}  };  const struct pmc_bit_map lnl_d3_status_2_map[] = { -	{"ESE_D3_STS",				BIT(0)}, -	{"CSMERTC_D3_STS",			BIT(1)}, -	{"SUSRAM_D3_STS",			BIT(2)}, -	{"CSE_D3_STS",				BIT(4)}, -	{"KVMCC_D3_STS",			BIT(5)}, -	{"USBR0_D3_STS",			BIT(6)}, -	{"ISH_D3_STS",				BIT(7)}, -	{"SMT1_D3_STS",				BIT(8)}, -	{"SMT2_D3_STS",				BIT(9)}, -	{"SMT3_D3_STS",				BIT(10)}, -	{"OSSE_SMT2_D3_STS",			BIT(13)}, -	{"CLINK_D3_STS",			BIT(14)}, -	{"PTIO_D3_STS",				BIT(16)}, -	{"PMT_D3_STS",				BIT(17)}, -	{"SMS1_D3_STS",				BIT(18)}, -	{"SMS2_D3_STS",				BIT(19)}, +	{"ESE_D3_STS",				BIT(0),		0}, +	{"CSMERTC_D3_STS",			BIT(1),		0}, +	{"SUSRAM_D3_STS",			BIT(2),		0}, +	{"CSE_D3_STS",				BIT(4),		0}, +	{"KVMCC_D3_STS",			BIT(5),		0}, +	{"USBR0_D3_STS",			BIT(6),		0}, +	{"ISH_D3_STS",				BIT(7),		0}, +	{"SMT1_D3_STS",				BIT(8),		0}, +	{"SMT2_D3_STS",				BIT(9),		0}, +	{"SMT3_D3_STS",				BIT(10),	0}, +	{"OSSE_SMT2_D3_STS",			BIT(13),	0}, +	{"CLINK_D3_STS",			BIT(14),	0}, +	{"PTIO_D3_STS",				BIT(16),	0}, +	{"PMT_D3_STS",				BIT(17),	0}, +	{"SMS1_D3_STS",				BIT(18),	0}, +	{"SMS2_D3_STS",				BIT(19),	0},  	{}  };  const struct pmc_bit_map lnl_d3_status_3_map[] = { -	{"THC0_D3_STS",				BIT(14)}, -	{"THC1_D3_STS",				BIT(15)}, -	{"OSSE_SMT3_D3_STS",			BIT(21)}, -	{"ACE_D3_STS",				BIT(23)}, +	{"THC0_D3_STS",				BIT(14),	1}, +	{"THC1_D3_STS",				BIT(15),	1}, +	{"OSSE_SMT3_D3_STS",			BIT(21),	0}, +	{"ACE_D3_STS",				BIT(23),	0},  	{}  };  const struct pmc_bit_map lnl_vnn_req_status_0_map[] = { -	{"LPSS_VNN_REQ_STS",			BIT(3)}, -	{"OSSE_VNN_REQ_STS",			BIT(15)}, -	{"ESPISPI_VNN_REQ_STS",			BIT(18)}, +	{"LPSS_VNN_REQ_STS",			BIT(3),		1}, +	{"OSSE_VNN_REQ_STS",			BIT(15),	1}, +	{"ESPISPI_VNN_REQ_STS",			BIT(18),	1},  	{}  };  const struct pmc_bit_map lnl_vnn_req_status_1_map[] = { -	{"NPK_VNN_REQ_STS",			BIT(4)}, -	{"OSSE_SMT1_VNN_REQ_STS",		BIT(7)}, -	{"DFXAGG_VNN_REQ_STS",			BIT(8)}, -	{"EXI_VNN_REQ_STS",			BIT(9)}, -	{"P2D_VNN_REQ_STS",			BIT(18)}, -	{"GBE_VNN_REQ_STS",			BIT(19)}, -	{"SMB_VNN_REQ_STS",			BIT(25)}, -	{"LPC_VNN_REQ_STS",			BIT(26)}, +	{"NPK_VNN_REQ_STS",			BIT(4),		1}, +	{"OSSE_SMT1_VNN_REQ_STS",		BIT(7),		1}, +	{"DFXAGG_VNN_REQ_STS",			BIT(8),		0}, +	{"EXI_VNN_REQ_STS",			BIT(9),		1}, +	{"P2D_VNN_REQ_STS",			BIT(18),	1}, +	{"GBE_VNN_REQ_STS",			BIT(19),	1}, +	{"SMB_VNN_REQ_STS",			BIT(25),	1}, +	{"LPC_VNN_REQ_STS",			BIT(26),	0},  	{}  };  const struct pmc_bit_map lnl_vnn_req_status_2_map[] = { -	{"eSE_VNN_REQ_STS",			BIT(0)}, -	{"CSMERTC_VNN_REQ_STS",			BIT(1)}, -	{"CSE_VNN_REQ_STS",			BIT(4)}, -	{"ISH_VNN_REQ_STS",			BIT(7)}, -	{"SMT1_VNN_REQ_STS",			BIT(8)}, -	{"CLINK_VNN_REQ_STS",			BIT(14)}, -	{"SMS1_VNN_REQ_STS",			BIT(18)}, -	{"SMS2_VNN_REQ_STS",			BIT(19)}, -	{"GPIOCOM4_VNN_REQ_STS",		BIT(20)}, -	{"GPIOCOM3_VNN_REQ_STS",		BIT(21)}, -	{"GPIOCOM2_VNN_REQ_STS",		BIT(22)}, -	{"GPIOCOM1_VNN_REQ_STS",		BIT(23)}, -	{"GPIOCOM0_VNN_REQ_STS",		BIT(24)}, +	{"eSE_VNN_REQ_STS",			BIT(0),		1}, +	{"CSMERTC_VNN_REQ_STS",			BIT(1),		1}, +	{"CSE_VNN_REQ_STS",			BIT(4),		1}, +	{"ISH_VNN_REQ_STS",			BIT(7),		1}, +	{"SMT1_VNN_REQ_STS",			BIT(8),		1}, +	{"CLINK_VNN_REQ_STS",			BIT(14),	1}, +	{"SMS1_VNN_REQ_STS",			BIT(18),	1}, +	{"SMS2_VNN_REQ_STS",			BIT(19),	1}, +	{"GPIOCOM4_VNN_REQ_STS",		BIT(20),	1}, +	{"GPIOCOM3_VNN_REQ_STS",		BIT(21),	1}, +	{"GPIOCOM2_VNN_REQ_STS",		BIT(22),	0}, +	{"GPIOCOM1_VNN_REQ_STS",		BIT(23),	1}, +	{"GPIOCOM0_VNN_REQ_STS",		BIT(24),	1},  	{}  };  const struct pmc_bit_map lnl_vnn_req_status_3_map[] = { -	{"DISP_SHIM_VNN_REQ_STS",		BIT(2)}, -	{"DTS0_VNN_REQ_STS",			BIT(7)}, -	{"GPIOCOM5_VNN_REQ_STS",		BIT(11)}, +	{"DISP_SHIM_VNN_REQ_STS",		BIT(2),		0}, +	{"DTS0_VNN_REQ_STS",			BIT(7),		0}, +	{"GPIOCOM5_VNN_REQ_STS",		BIT(11),	2},  	{}  };  const struct pmc_bit_map lnl_vnn_misc_status_map[] = { -	{"CPU_C10_REQ_STS",			BIT(0)}, -	{"TS_OFF_REQ_STS",			BIT(1)}, -	{"PNDE_MET_REQ_STS",			BIT(2)}, -	{"PCIE_DEEP_PM_REQ_STS",		BIT(3)}, -	{"PMC_CLK_THROTTLE_EN_REQ_STS",		BIT(4)}, -	{"NPK_VNNAON_REQ_STS",			BIT(5)}, -	{"VNN_SOC_REQ_STS",			BIT(6)}, -	{"ISH_VNNAON_REQ_STS",			BIT(7)}, -	{"D2D_NOC_CFI_QACTIVE_REQ_STS",		BIT(8)}, -	{"D2D_NOC_GPSB_QACTIVE_REQ_STS",	BIT(9)}, -	{"D2D_NOC_IPU_QACTIVE_REQ_STS",		BIT(10)}, -	{"PLT_GREATER_REQ_STS",			BIT(11)}, -	{"PCIE_CLKREQ_REQ_STS",			BIT(12)}, -	{"PMC_IDLE_FB_OCP_REQ_STS",		BIT(13)}, -	{"PM_SYNC_STATES_REQ_STS",		BIT(14)}, -	{"EA_REQ_STS",				BIT(15)}, -	{"MPHY_CORE_OFF_REQ_STS",		BIT(16)}, -	{"BRK_EV_EN_REQ_STS",			BIT(17)}, -	{"AUTO_DEMO_EN_REQ_STS",		BIT(18)}, -	{"ITSS_CLK_SRC_REQ_STS",		BIT(19)}, -	{"LPC_CLK_SRC_REQ_STS",			BIT(20)}, -	{"ARC_IDLE_REQ_STS",			BIT(21)}, -	{"MPHY_SUS_REQ_STS",			BIT(22)}, -	{"FIA_DEEP_PM_REQ_STS",			BIT(23)}, -	{"UXD_CONNECTED_REQ_STS",		BIT(24)}, -	{"ARC_INTERRUPT_WAKE_REQ_STS",	BIT(25)}, -	{"D2D_NOC_DISP_DDI_QACTIVE_REQ_STS",	BIT(26)}, -	{"PRE_WAKE0_REQ_STS",			BIT(27)}, -	{"PRE_WAKE1_REQ_STS",			BIT(28)}, -	{"PRE_WAKE2_EN_REQ_STS",		BIT(29)}, -	{"WOV_REQ_STS",				BIT(30)}, -	{"D2D_NOC_DISP_EDP_QACTIVE_REQ_STS_31",	BIT(31)}, +	{"CPU_C10_REQ_STS",			BIT(0),		0}, +	{"TS_OFF_REQ_STS",			BIT(1),		0}, +	{"PNDE_MET_REQ_STS",			BIT(2),		1}, +	{"PCIE_DEEP_PM_REQ_STS",		BIT(3),		0}, +	{"PMC_CLK_THROTTLE_EN_REQ_STS",		BIT(4),		0}, +	{"NPK_VNNAON_REQ_STS",			BIT(5),		0}, +	{"VNN_SOC_REQ_STS",			BIT(6),		1}, +	{"ISH_VNNAON_REQ_STS",			BIT(7),		0}, +	{"D2D_NOC_CFI_QACTIVE_REQ_STS",		BIT(8),		1}, +	{"D2D_NOC_GPSB_QACTIVE_REQ_STS",	BIT(9),		1}, +	{"D2D_NOC_IPU_QACTIVE_REQ_STS",		BIT(10),	1}, +	{"PLT_GREATER_REQ_STS",			BIT(11),	1}, +	{"PCIE_CLKREQ_REQ_STS",			BIT(12),	0}, +	{"PMC_IDLE_FB_OCP_REQ_STS",		BIT(13),	0}, +	{"PM_SYNC_STATES_REQ_STS",		BIT(14),	0}, +	{"EA_REQ_STS",				BIT(15),	0}, +	{"MPHY_CORE_OFF_REQ_STS",		BIT(16),	0}, +	{"BRK_EV_EN_REQ_STS",			BIT(17),	0}, +	{"AUTO_DEMO_EN_REQ_STS",		BIT(18),	0}, +	{"ITSS_CLK_SRC_REQ_STS",		BIT(19),	1}, +	{"LPC_CLK_SRC_REQ_STS",			BIT(20),	0}, +	{"ARC_IDLE_REQ_STS",			BIT(21),	0}, +	{"MPHY_SUS_REQ_STS",			BIT(22),	0}, +	{"FIA_DEEP_PM_REQ_STS",			BIT(23),	0}, +	{"UXD_CONNECTED_REQ_STS",		BIT(24),	1}, +	{"ARC_INTERRUPT_WAKE_REQ_STS",		BIT(25),	0}, +	{"D2D_NOC_DISP_DDI_QACTIVE_REQ_STS",	BIT(26),	1}, +	{"PRE_WAKE0_REQ_STS",			BIT(27),	1}, +	{"PRE_WAKE1_REQ_STS",			BIT(28),	1}, +	{"PRE_WAKE2_EN_REQ_STS",		BIT(29),	1}, +	{"WOV_REQ_STS",				BIT(30),	0}, +	{"D2D_NOC_DISP_EDP_QACTIVE_REQ_STS_31",	BIT(31),	1},  	{}  };  const struct pmc_bit_map lnl_clocksource_status_map[] = { -	{"AON2_OFF_STS",			BIT(0)}, -	{"AON3_OFF_STS",			BIT(1)}, -	{"AON4_OFF_STS",			BIT(2)}, -	{"AON5_OFF_STS",			BIT(3)}, -	{"AON1_OFF_STS",			BIT(4)}, -	{"MPFPW1_0_PLL_OFF_STS",		BIT(6)}, -	{"USB3_PLL_OFF_STS",			BIT(8)}, -	{"AON3_SPL_OFF_STS",			BIT(9)}, -	{"G5FPW1_PLL_OFF_STS",			BIT(15)}, -	{"XTAL_AGGR_OFF_STS",			BIT(17)}, -	{"USB2_PLL_OFF_STS",			BIT(18)}, -	{"SAF_PLL_OFF_STS",			BIT(19)}, -	{"SE_TCSS_PLL_OFF_STS",			BIT(20)}, -	{"DDI_PLL_OFF_STS",			BIT(21)}, -	{"FILTER_PLL_OFF_STS",			BIT(22)}, -	{"ACE_PLL_OFF_STS",			BIT(24)}, -	{"FABRIC_PLL_OFF_STS",			BIT(25)}, -	{"SOC_PLL_OFF_STS",			BIT(26)}, -	{"REF_OFF_STS",				BIT(28)}, -	{"IMG_OFF_STS",				BIT(29)}, -	{"RTC_PLL_OFF_STS",			BIT(31)}, +	{"AON2_OFF_STS",			BIT(0),		0}, +	{"AON3_OFF_STS",			BIT(1),		1}, +	{"AON4_OFF_STS",			BIT(2),		1}, +	{"AON5_OFF_STS",			BIT(3),		1}, +	{"AON1_OFF_STS",			BIT(4),		0}, +	{"MPFPW1_0_PLL_OFF_STS",		BIT(6),		1}, +	{"USB3_PLL_OFF_STS",			BIT(8),		1}, +	{"AON3_SPL_OFF_STS",			BIT(9),		1}, +	{"G5FPW1_PLL_OFF_STS",			BIT(15),	1}, +	{"XTAL_AGGR_OFF_STS",			BIT(17),	1}, +	{"USB2_PLL_OFF_STS",			BIT(18),	0}, +	{"SAF_PLL_OFF_STS",			BIT(19),	1}, +	{"SE_TCSS_PLL_OFF_STS",			BIT(20),	1}, +	{"DDI_PLL_OFF_STS",			BIT(21),	1}, +	{"FILTER_PLL_OFF_STS",			BIT(22),	1}, +	{"ACE_PLL_OFF_STS",			BIT(24),	0}, +	{"FABRIC_PLL_OFF_STS",			BIT(25),	1}, +	{"SOC_PLL_OFF_STS",			BIT(26),	1}, +	{"REF_OFF_STS",				BIT(28),	1}, +	{"IMG_OFF_STS",				BIT(29),	1}, +	{"RTC_PLL_OFF_STS",			BIT(31),	0}, +	{} +}; + +const struct pmc_bit_map lnl_signal_status_map[] = { +	{"LSX_Wake0_STS",			BIT(0),		0}, +	{"LSX_Wake1_STS",			BIT(1),		0}, +	{"LSX_Wake2_STS",			BIT(2),		0}, +	{"LSX_Wake3_STS",			BIT(3),		0}, +	{"LSX_Wake4_STS",			BIT(4),		0}, +	{"LSX_Wake5_STS",			BIT(5),		0}, +	{"LSX_Wake6_STS",			BIT(6),		0}, +	{"LSX_Wake7_STS",			BIT(7),		0}, +	{"LPSS_Wake0_STS",			BIT(8),		1}, +	{"LPSS_Wake1_STS",			BIT(9),		1}, +	{"Int_Timer_SS_Wake0_STS",		BIT(10),	1}, +	{"Int_Timer_SS_Wake1_STS",		BIT(11),	1}, +	{"Int_Timer_SS_Wake2_STS",		BIT(12),	1}, +	{"Int_Timer_SS_Wake3_STS",		BIT(13),	1}, +	{"Int_Timer_SS_Wake4_STS",		BIT(14),	1}, +	{"Int_Timer_SS_Wake5_STS",		BIT(15),	1}, +	{} +}; + +const struct pmc_bit_map lnl_rsc_status_map[] = { +	{"Memory",				0,		1}, +	{"PSF0",				0,		1}, +	{"PSF4",				0,		1}, +	{"PSF6",				0,		1}, +	{"PSF7",				0,		1}, +	{"PSF8",				0,		1}, +	{"SAF_CFI_LINK",			0,		1}, +	{"SBR",					0,		1},  	{}  }; @@ -331,7 +363,26 @@ const struct pmc_bit_map *lnl_lpm_maps[] = {  	lnl_vnn_req_status_2_map,  	lnl_vnn_req_status_3_map,  	lnl_vnn_misc_status_map, -	mtl_socm_signal_status_map, +	lnl_signal_status_map, +	NULL +}; + +const struct pmc_bit_map *lnl_blk_maps[] = { +	lnl_power_gating_status_0_map, +	lnl_power_gating_status_1_map, +	lnl_power_gating_status_2_map, +	lnl_rsc_status_map, +	lnl_vnn_req_status_0_map, +	lnl_vnn_req_status_1_map, +	lnl_vnn_req_status_2_map, +	lnl_vnn_req_status_3_map, +	lnl_d3_status_0_map, +	lnl_d3_status_1_map, +	lnl_d3_status_2_map, +	lnl_d3_status_3_map, +	lnl_clocksource_status_map, +	lnl_vnn_misc_status_map, +	lnl_signal_status_map,  	NULL  }; @@ -475,6 +526,8 @@ const struct pmc_reg_map lnl_socm_reg_map = {  	.lpm_sts = lnl_lpm_maps,  	.lpm_status_offset = MTL_LPM_STATUS_OFFSET,  	.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET, +	.s0ix_blocker_maps = lnl_blk_maps, +	.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,  };  #define LNL_NPU_PCI_DEV		0x643e diff --git a/drivers/platform/x86/intel/rst.c b/drivers/platform/x86/intel/rst.c index 35814a7707af..6bc9c4a603e0 100644 --- a/drivers/platform/x86/intel/rst.c +++ b/drivers/platform/x86/intel/rst.c @@ -125,7 +125,6 @@ static const struct acpi_device_id irst_ids[] = {  };  static struct acpi_driver irst_driver = { -	.owner = THIS_MODULE,  	.name = "intel_rapid_start",  	.class = "intel_rapid_start",  	.ids = irst_ids, diff --git a/drivers/platform/x86/intel/sdsi.c b/drivers/platform/x86/intel/sdsi.c index 556e7c6dbb05..277e4f4b20ac 100644 --- a/drivers/platform/x86/intel/sdsi.c +++ b/drivers/platform/x86/intel/sdsi.c @@ -15,6 +15,7 @@  #include <linux/iopoll.h>  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/overflow.h>  #include <linux/pci.h>  #include <linux/slab.h>  #include <linux/sysfs.h> @@ -66,6 +67,8 @@  #define CTRL_OWNER			GENMASK(5, 4)  #define CTRL_COMPLETE			BIT(6)  #define CTRL_READY			BIT(7) +#define CTRL_INBAND_LOCK		BIT(32) +#define CTRL_METER_ENABLE_DRAM		BIT(33)  #define CTRL_STATUS			GENMASK(15, 8)  #define CTRL_PACKET_SIZE		GENMASK(31, 16)  #define CTRL_MSG_SIZE			GENMASK(63, 48) @@ -93,6 +96,7 @@ enum sdsi_command {  struct sdsi_mbox_info {  	u64	*payload;  	void	*buffer; +	u64	control_flags;  	int	size;  }; @@ -156,8 +160,8 @@ static int sdsi_status_to_errno(u32 status)  	}  } -static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, -			      size_t *data_size) +static int sdsi_mbox_poll(struct sdsi_priv *priv, struct sdsi_mbox_info *info, +			  size_t *data_size)  {  	struct device *dev = priv->dev;  	u32 total, loop, eom, status, message_size; @@ -166,18 +170,10 @@ static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *inf  	lockdep_assert_held(&priv->mb_lock); -	/* Format and send the read command */ -	control = FIELD_PREP(CTRL_EOM, 1) | -		  FIELD_PREP(CTRL_SOM, 1) | -		  FIELD_PREP(CTRL_RUN_BUSY, 1) | -		  FIELD_PREP(CTRL_PACKET_SIZE, info->size); -	writeq(control, priv->control_addr); -  	/* For reads, data sizes that are larger than the mailbox size are read in packets. */  	total = 0;  	loop = 0;  	do { -		void *buf = info->buffer + (SDSI_SIZE_MAILBOX * loop);  		u32 packet_size;  		/* Poll on ready bit */ @@ -195,6 +191,11 @@ static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *inf  		if (ret)  			break; +		if (!packet_size) { +			sdsi_complete_transaction(priv); +			break; +		} +  		/* Only the last packet can be less than the mailbox size. */  		if (!eom && packet_size != SDSI_SIZE_MAILBOX) {  			dev_err(dev, "Invalid packet size\n"); @@ -208,9 +209,13 @@ static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *inf  			break;  		} -		sdsi_memcpy64_fromio(buf, priv->mbox_addr, round_up(packet_size, SDSI_SIZE_CMD)); +		if (info->buffer) { +			void *buf = info->buffer + array_size(SDSI_SIZE_MAILBOX, loop); -		total += packet_size; +			sdsi_memcpy64_fromio(buf, priv->mbox_addr, +					     round_up(packet_size, SDSI_SIZE_CMD)); +			total += packet_size; +		}  		sdsi_complete_transaction(priv);  	} while (!eom && ++loop < MBOX_MAX_PACKETS); @@ -230,16 +235,34 @@ static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *inf  		dev_warn(dev, "Read count %u differs from expected count %u\n",  			 total, message_size); -	*data_size = total; +	if (data_size) +		*data_size = total;  	return 0;  } -static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info) +static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, +			      size_t *data_size) +{ +	u64 control; + +	lockdep_assert_held(&priv->mb_lock); + +	/* Format and send the read command */ +	control = FIELD_PREP(CTRL_EOM, 1) | +		  FIELD_PREP(CTRL_SOM, 1) | +		  FIELD_PREP(CTRL_RUN_BUSY, 1) | +		  FIELD_PREP(CTRL_PACKET_SIZE, info->size) | +		  info->control_flags; +	writeq(control, priv->control_addr); + +	return sdsi_mbox_poll(priv, info, data_size); +} + +static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info, +			       size_t *data_size)  {  	u64 control; -	u32 status; -	int ret;  	lockdep_assert_held(&priv->mb_lock); @@ -252,23 +275,11 @@ static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *in  		  FIELD_PREP(CTRL_SOM, 1) |  		  FIELD_PREP(CTRL_RUN_BUSY, 1) |  		  FIELD_PREP(CTRL_READ_WRITE, 1) | +		  FIELD_PREP(CTRL_MSG_SIZE, info->size) |  		  FIELD_PREP(CTRL_PACKET_SIZE, info->size);  	writeq(control, priv->control_addr); -	/* Poll on ready bit */ -	ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY, -				 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US); - -	if (ret) -		goto release_mbox; - -	status = FIELD_GET(CTRL_STATUS, control); -	ret = sdsi_status_to_errno(status); - -release_mbox: -	sdsi_complete_transaction(priv); - -	return ret; +	return sdsi_mbox_poll(priv, info, data_size);  }  static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info) @@ -312,7 +323,8 @@ static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info  	return ret;  } -static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info) +static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info, +			   size_t *data_size)  {  	int ret; @@ -322,7 +334,7 @@ static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info)  	if (ret)  		return ret; -	return sdsi_mbox_cmd_write(priv, info); +	return sdsi_mbox_cmd_write(priv, info, data_size);  }  static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size) @@ -338,15 +350,24 @@ static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, s  	return sdsi_mbox_cmd_read(priv, info, data_size);  } +static bool sdsi_ib_locked(struct sdsi_priv *priv) +{ +	return !!FIELD_GET(CTRL_INBAND_LOCK, readq(priv->control_addr)); +} +  static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,  			      enum sdsi_command command)  { -	struct sdsi_mbox_info info; +	struct sdsi_mbox_info info = {};  	int ret;  	if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))  		return -EOVERFLOW; +	/* Make sure In-band lock is not set */ +	if (sdsi_ib_locked(priv)) +		return -EPERM; +  	/* Qword aligned message + command qword */  	info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD; @@ -363,7 +384,9 @@ static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,  	ret = mutex_lock_interruptible(&priv->mb_lock);  	if (ret)  		goto free_payload; -	ret = sdsi_mbox_write(priv, &info); + +	ret = sdsi_mbox_write(priv, &info, NULL); +  	mutex_unlock(&priv->mb_lock);  free_payload: @@ -404,10 +427,10 @@ static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,  static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);  static ssize_t -certificate_read(u64 command, struct sdsi_priv *priv, char *buf, loff_t off, -		 size_t count) +certificate_read(u64 command, u64 control_flags, struct sdsi_priv *priv, +		 char *buf, loff_t off, size_t count)  { -	struct sdsi_mbox_info info; +	struct sdsi_mbox_info info = {};  	size_t size;  	int ret; @@ -421,6 +444,7 @@ certificate_read(u64 command, struct sdsi_priv *priv, char *buf, loff_t off,  	info.payload = &command;  	info.size = sizeof(command); +	info.control_flags = control_flags;  	ret = mutex_lock_interruptible(&priv->mb_lock);  	if (ret) @@ -452,7 +476,7 @@ state_certificate_read(struct file *filp, struct kobject *kobj,  	struct device *dev = kobj_to_dev(kobj);  	struct sdsi_priv *priv = dev_get_drvdata(dev); -	return certificate_read(SDSI_CMD_READ_STATE, priv, buf, off, count); +	return certificate_read(SDSI_CMD_READ_STATE, 0, priv, buf, off, count);  }  static BIN_ATTR_ADMIN_RO(state_certificate, SDSI_SIZE_READ_MSG); @@ -464,10 +488,23 @@ meter_certificate_read(struct file *filp, struct kobject *kobj,  	struct device *dev = kobj_to_dev(kobj);  	struct sdsi_priv *priv = dev_get_drvdata(dev); -	return certificate_read(SDSI_CMD_READ_METER, priv, buf, off, count); +	return certificate_read(SDSI_CMD_READ_METER, 0, priv, buf, off, count);  }  static BIN_ATTR_ADMIN_RO(meter_certificate, SDSI_SIZE_READ_MSG); +static ssize_t +meter_current_read(struct file *filp, struct kobject *kobj, +		   struct bin_attribute *attr, char *buf, loff_t off, +		   size_t count) +{ +	struct device *dev = kobj_to_dev(kobj); +	struct sdsi_priv *priv = dev_get_drvdata(dev); + +	return certificate_read(SDSI_CMD_READ_METER, CTRL_METER_ENABLE_DRAM, +				priv, buf, off, count); +} +static BIN_ATTR_ADMIN_RO(meter_current, SDSI_SIZE_READ_MSG); +  static ssize_t registers_read(struct file *filp, struct kobject *kobj,  			      struct bin_attribute *attr, char *buf, loff_t off,  			      size_t count) @@ -498,6 +535,7 @@ static struct bin_attribute *sdsi_bin_attrs[] = {  	&bin_attr_registers,  	&bin_attr_state_certificate,  	&bin_attr_meter_certificate, +	&bin_attr_meter_current,  	&bin_attr_provision_akc,  	&bin_attr_provision_cap,  	NULL @@ -517,7 +555,7 @@ sdsi_battr_is_visible(struct kobject *kobj, struct bin_attribute *attr, int n)  	if (!(priv->features & SDSI_FEATURE_SDSI))  		return 0; -	if (attr == &bin_attr_meter_certificate) +	if (attr == &bin_attr_meter_certificate || attr == &bin_attr_meter_current)  		return (priv->features & SDSI_FEATURE_METERING) ?  				attr->attr.mode : 0; diff --git a/drivers/platform/x86/intel/smartconnect.c b/drivers/platform/x86/intel/smartconnect.c index 64c2dc93472f..cd25d0585324 100644 --- a/drivers/platform/x86/intel/smartconnect.c +++ b/drivers/platform/x86/intel/smartconnect.c @@ -32,7 +32,6 @@ static const struct acpi_device_id smartconnect_ids[] = {  MODULE_DEVICE_TABLE(acpi, smartconnect_ids);  static struct acpi_driver smartconnect_driver = { -	.owner = THIS_MODULE,  	.name = "intel_smart_connect",  	.class = "intel_smart_connect",  	.ids = smartconnect_ids, diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c index 1accdaaf282c..713c0d1fa85f 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c @@ -839,4 +839,5 @@ void isst_if_cdev_unregister(int device_type)  }  EXPORT_SYMBOL_GPL(isst_if_cdev_unregister); +MODULE_DESCRIPTION("ISST common interface module");  MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index 1d918000d72b..7fa360073f6e 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -17,12 +17,15 @@   * the hardware mapping.   */ +#define dev_fmt(fmt) "tpmi_sst: " fmt +  #include <linux/auxiliary_bus.h>  #include <linux/delay.h>  #include <linux/intel_tpmi.h>  #include <linux/fs.h>  #include <linux/io.h>  #include <linux/kernel.h> +#include <linux/minmax.h>  #include <linux/module.h>  #include <uapi/linux/isst_if.h> @@ -263,20 +266,33 @@ struct tpmi_per_power_domain_info {  	bool write_blocked;  }; +/* Supported maximum partitions */ +#define SST_MAX_PARTITIONS	2 +  /**   * struct tpmi_sst_struct -	Store sst info for a package   * @package_id:			Package id for this aux device instance   * @number_of_power_domains:	Number of power_domains pointed by power_domain_info pointer   * @power_domain_info:		Pointer to power domains information + * @cdie_mask:			Mask of compute dies present in a partition from hardware. + *				This mask is not present in the version 1 information header. + * @io_dies:			Number of IO dies in a partition. This will be 0 for TPMI + *				version 1 information header. + * @partition_mask:		Mask of all partitions. + * @partition_mask_current:	Current partition mask as some may have been unbound.   *   * This structure is used store full SST information for a package. - * Each package has a unique OOB PCI device, which enumerates TPMI. - * Each Package will have multiple power_domains. + * Each package has one or multiple OOB PCI devices. Each package can contain multiple + * power domains.   */  struct tpmi_sst_struct {  	int package_id; -	int number_of_power_domains; -	struct tpmi_per_power_domain_info *power_domain_info; +	struct tpmi_per_power_domain_info *power_domain_info[SST_MAX_PARTITIONS]; +	u16 cdie_mask[SST_MAX_PARTITIONS]; +	u8 number_of_power_domains[SST_MAX_PARTITIONS]; +	u8 io_dies[SST_MAX_PARTITIONS]; +	u8 partition_mask; +	u8 partition_mask_current;  };  /** @@ -313,12 +329,11 @@ static int sst_add_perf_profiles(struct auxiliary_device *auxdev,  				 struct tpmi_per_power_domain_info *pd_info,  				 int levels)  { +	struct device *dev = &auxdev->dev;  	u64 perf_level_offsets;  	int i; -	pd_info->perf_levels = devm_kcalloc(&auxdev->dev, levels, -					    sizeof(struct perf_level), -					    GFP_KERNEL); +	pd_info->perf_levels = devm_kcalloc(dev, levels, sizeof(struct perf_level), GFP_KERNEL);  	if (!pd_info->perf_levels)  		return 0; @@ -349,6 +364,7 @@ static int sst_add_perf_profiles(struct auxiliary_device *auxdev,  static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domain_info *pd_info)  { +	struct device *dev = &auxdev->dev;  	int i, mask, levels;  	*((u64 *)&pd_info->sst_header) = readq(pd_info->sst_base); @@ -359,13 +375,13 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai  		return -ENODEV;  	if (TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version) != ISST_MAJOR_VERSION) { -		dev_err(&auxdev->dev, "SST: Unsupported major version:%lx\n", +		dev_err(dev, "SST: Unsupported major version:%lx\n",  			TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version));  		return -ENODEV;  	}  	if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION) -		dev_info(&auxdev->dev, "SST: Ignore: Unsupported minor version:%lx\n", +		dev_info(dev, "SST: Ignore: Unsupported minor version:%lx\n",  			 TPMI_MINOR_VERSION(pd_info->sst_header.interface_version));  	/* Read SST CP Header */ @@ -387,6 +403,126 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai  	return 0;  } +static u8 isst_instance_count(struct tpmi_sst_struct *sst_inst) +{ +	u8 i, max_part, count = 0; + +	/* Partition mask starts from bit 0 and contains 1s only */ +	max_part = hweight8(sst_inst->partition_mask); +	for (i = 0; i < max_part; i++) +		count += sst_inst->number_of_power_domains[i]; + +	return count; +} + +/** + * map_cdies() - Map user domain ID to compute domain ID + * @sst_inst: TPMI Instance + * @id: User domain ID + * @partition: Resolved partition + * + * Helper function to map_partition_power_domain_id() to resolve compute + * domain ID and partition. Use hardware provided cdie_mask for a partition + * as is to resolve a compute domain ID. + * + * Return: %-EINVAL on error, otherwise mapped domain ID >= 0. + */ +static int map_cdies(struct tpmi_sst_struct *sst_inst, u8 id, u8 *partition) +{ +	u8 i, max_part; + +	max_part = hweight8(sst_inst->partition_mask); +	for (i = 0; i < max_part; i++) { +		if (!(sst_inst->cdie_mask[i] & BIT(id))) +			continue; + +		*partition = i; +		return id - ffs(sst_inst->cdie_mask[i]) + 1; +	} + +	return -EINVAL; +} + +/** + * map_partition_power_domain_id() - Map user domain ID to partition domain ID + * @sst_inst: TPMI Instance + * @id: User domain ID + * @partition: Resolved partition + * + * In a partitioned system a CPU package has two separate MMIO ranges (Under + * two PCI devices). But the CPU package compute die/power domain IDs are + * unique in a package. User space can get compute die/power domain ID from + * CPUID and MSR 0x54 for a CPU. So, those IDs need to be preserved even if + * they are present in two different partitions with its own order. + * + * For example for command ISST_IF_COUNT_TPMI_INSTANCES, the valid_mask + * is 111111b for a 4 compute and 2 IO dies system. This is presented as + * provided by the hardware in a non-partitioned system with the following + * order: + *	I1-I0-C3-C2-C1-C0 + * Here: "C": for compute and "I" for IO die. + * Compute dies are always present first in TPMI instances, as they have + * to map to the real power domain/die ID of a system. In a non-partitioned + * system there is no way to identify compute and IO die boundaries from + * this driver without reading each CPU's mapping. + * + * The same order needs to be preserved, even if those compute dies are + * distributed among multiple partitions. For example: + * Partition 1 can contain: I1-C1-C0 + * Partition 2 can contain: I2-C3-C2 + * + * This will require a conversion of user space IDs to the actual index into + * array of stored power domains for each partition. For the above example + * this function will return partition and index as follows: + * + * =============	=========	=====	======== + * User space ID	Partition	Index	Die type + * =============	=========	=====	======== + * 0			0		0	Compute + * 1			0		1	Compute + * 2			1		0	Compute + * 3			1		1	Compute + * 4			0		2	IO + * 5			1		2	IO + * =============	=========	=====	======== + * + * Return: %-EINVAL on error, otherwise mapped domain ID >= 0. + */ +static int map_partition_power_domain_id(struct tpmi_sst_struct *sst_inst, u8 id, u8 *partition) +{ +	u8 i, io_start_id, max_part; + +	*partition = 0; + +	/* If any PCI device for partition is unbound, treat this as failure */ +	if (sst_inst->partition_mask != sst_inst->partition_mask_current) +		return -EINVAL; + +	max_part = hweight8(sst_inst->partition_mask); + +	/* IO Index begin here */ +	io_start_id = fls(sst_inst->cdie_mask[max_part - 1]); + +	if (id < io_start_id) +		return map_cdies(sst_inst, id, partition); + +	for (i = 0; i < max_part; i++) { +		u8 io_id; + +		io_id = id - io_start_id; +		if (io_id < sst_inst->io_dies[i]) { +			u8 cdie_range; + +			cdie_range = fls(sst_inst->cdie_mask[i]) - ffs(sst_inst->cdie_mask[i]) + 1; +			*partition = i; +			return cdie_range + io_id; +		} +		io_start_id += sst_inst->io_dies[i]; +	} + +	return -EINVAL; +} +  /*   * Map a package and power_domain id to SST information structure unique for a power_domain.   * The caller should call under isst_tpmi_dev_lock. @@ -395,19 +531,20 @@ static struct tpmi_per_power_domain_info *get_instance(int pkg_id, int power_dom  {  	struct tpmi_per_power_domain_info *power_domain_info;  	struct tpmi_sst_struct *sst_inst; +	u8 part; -	if (pkg_id < 0 || pkg_id > isst_common.max_index || -	    pkg_id >= topology_max_packages()) +	if (!in_range(pkg_id, 0, topology_max_packages()) || pkg_id > isst_common.max_index)  		return NULL;  	sst_inst = isst_common.sst_inst[pkg_id];  	if (!sst_inst)  		return NULL; -	if (power_domain_id < 0 || power_domain_id >= sst_inst->number_of_power_domains) +	power_domain_id = map_partition_power_domain_id(sst_inst, power_domain_id, &part); +	if (power_domain_id < 0)  		return NULL; -	power_domain_info = &sst_inst->power_domain_info[power_domain_id]; +	power_domain_info = &sst_inst->power_domain_info[part][power_domain_id];  	if (power_domain_info && !power_domain_info->sst_base)  		return NULL; @@ -579,6 +716,7 @@ static long isst_if_clos_assoc(void __user *argp)  		struct tpmi_sst_struct *sst_inst;  		int offset, shift, cpu;  		u64 val, mask, clos; +		u8 part;  		if (copy_from_user(&clos_assoc, ptr, sizeof(clos_assoc)))  			return -EFAULT; @@ -602,10 +740,11 @@ static long isst_if_clos_assoc(void __user *argp)  		sst_inst = isst_common.sst_inst[pkg_id]; -		if (clos_assoc.power_domain_id > sst_inst->number_of_power_domains) +		punit_id = map_partition_power_domain_id(sst_inst, punit_id, &part); +		if (punit_id < 0)  			return -EINVAL; -		power_domain_info = &sst_inst->power_domain_info[punit_id]; +		power_domain_info = &sst_inst->power_domain_info[part][punit_id];  		if (assoc_cmds.get_set && power_domain_info->write_blocked)  			return -EPERM; @@ -708,6 +847,8 @@ static int isst_if_get_perf_level(void __user *argp)  {  	struct isst_perf_level_info perf_level;  	struct tpmi_per_power_domain_info *power_domain_info; +	unsigned long level_mask; +	u8 level, support;  	if (copy_from_user(&perf_level, argp, sizeof(perf_level)))  		return -EFAULT; @@ -727,12 +868,34 @@ static int isst_if_get_perf_level(void __user *argp)  		      SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH, SST_MUL_FACTOR_NONE)  	perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1)); -	_read_bf_level_info("bf_support", perf_level.sst_bf_support, 0, 0, -			    SST_BF_FEATURE_SUPPORTED_START, SST_BF_FEATURE_SUPPORTED_WIDTH, -			    SST_MUL_FACTOR_NONE); -	_read_tf_level_info("tf_support", perf_level.sst_tf_support, 0, 0, -			    SST_TF_FEATURE_SUPPORTED_START, SST_TF_FEATURE_SUPPORTED_WIDTH, -			    SST_MUL_FACTOR_NONE); +	level_mask = perf_level.level_mask; +	perf_level.sst_bf_support = 0; +	for_each_set_bit(level, &level_mask, BITS_PER_BYTE) { +		/* +		 * Read BF support for a level. Read output is updated +		 * to "support" variable by the below macro. +		 */ +		_read_bf_level_info("bf_support", support, level, 0, SST_BF_FEATURE_SUPPORTED_START, +				    SST_BF_FEATURE_SUPPORTED_WIDTH, SST_MUL_FACTOR_NONE); + +		/* If supported set the bit for the level */ +		if (support) +			perf_level.sst_bf_support |= BIT(level); +	} + +	perf_level.sst_tf_support = 0; +	for_each_set_bit(level, &level_mask, BITS_PER_BYTE) { +		/* +		 * Read TF support for a level. Read output is updated +		 * to "support" variable by the below macro. +		 */ +		_read_tf_level_info("tf_support", support, level, 0, SST_TF_FEATURE_SUPPORTED_START, +				    SST_TF_FEATURE_SUPPORTED_WIDTH, SST_MUL_FACTOR_NONE); + +		/* If supported set the bit for the level */ +		if (support) +			perf_level.sst_tf_support |= BIT(level); +	}  	if (copy_to_user(argp, &perf_level, sizeof(perf_level)))  		return -EFAULT; @@ -1134,18 +1297,28 @@ static int isst_if_get_tpmi_instance_count(void __user *argp)  	if (tpmi_inst.socket_id >= topology_max_packages())  		return -EINVAL; -	tpmi_inst.count = isst_common.sst_inst[tpmi_inst.socket_id]->number_of_power_domains; -  	sst_inst = isst_common.sst_inst[tpmi_inst.socket_id]; + +	tpmi_inst.count = isst_instance_count(sst_inst); +  	tpmi_inst.valid_mask = 0; -	for (i = 0; i < sst_inst->number_of_power_domains; ++i) { +	for (i = 0; i < tpmi_inst.count; i++) {  		struct tpmi_per_power_domain_info *pd_info; +		u8 part; +		int pd; -		pd_info = &sst_inst->power_domain_info[i]; +		pd = map_partition_power_domain_id(sst_inst, i, &part); +		if (pd < 0) +			continue; + +		pd_info = &sst_inst->power_domain_info[part][pd];  		if (pd_info->sst_base)  			tpmi_inst.valid_mask |= BIT(i);  	} +	if (!tpmi_inst.valid_mask) +		tpmi_inst.count = 0; +  	if (copy_to_user(argp, &tpmi_inst, sizeof(tpmi_inst)))  		return -EFAULT; @@ -1271,102 +1444,175 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,  int tpmi_sst_dev_add(struct auxiliary_device *auxdev)  { +	struct tpmi_per_power_domain_info *pd_info;  	bool read_blocked = 0, write_blocked = 0;  	struct intel_tpmi_plat_info *plat_info; +	struct device *dev = &auxdev->dev;  	struct tpmi_sst_struct *tpmi_sst; -	int i, ret, pkg = 0, inst = 0; -	int num_resources; +	u8 i, num_resources, io_die_cnt; +	int ret, pkg = 0, inst = 0; +	bool first_enum = false; +	u16 cdie_mask; +	u8 partition;  	ret = tpmi_get_feature_status(auxdev, TPMI_ID_SST, &read_blocked, &write_blocked);  	if (ret) -		dev_info(&auxdev->dev, "Can't read feature status: ignoring read/write blocked status\n"); +		dev_info(dev, "Can't read feature status: ignoring read/write blocked status\n");  	if (read_blocked) { -		dev_info(&auxdev->dev, "Firmware has blocked reads, exiting\n"); +		dev_info(dev, "Firmware has blocked reads, exiting\n");  		return -ENODEV;  	}  	plat_info = tpmi_get_platform_data(auxdev);  	if (!plat_info) { -		dev_err(&auxdev->dev, "No platform info\n"); +		dev_err(dev, "No platform info\n");  		return -EINVAL;  	}  	pkg = plat_info->package_id;  	if (pkg >= topology_max_packages()) { -		dev_err(&auxdev->dev, "Invalid package id :%x\n", pkg); +		dev_err(dev, "Invalid package id :%x\n", pkg);  		return -EINVAL;  	} -	if (isst_common.sst_inst[pkg]) -		return -EEXIST; +	partition = plat_info->partition; +	if (partition >= SST_MAX_PARTITIONS) { +		dev_err(&auxdev->dev, "Invalid partition :%x\n", partition); +		return -EINVAL; +	}  	num_resources = tpmi_get_resource_count(auxdev);  	if (!num_resources)  		return -EINVAL; -	tpmi_sst = devm_kzalloc(&auxdev->dev, sizeof(*tpmi_sst), GFP_KERNEL); -	if (!tpmi_sst) -		return -ENOMEM; +	mutex_lock(&isst_tpmi_dev_lock); + +	if (isst_common.sst_inst[pkg]) { +		tpmi_sst = isst_common.sst_inst[pkg]; +	} else { +		/* +		 * tpmi_sst instance is for a package. So needs to be +		 * allocated only once for both partitions. We can't use +		 * devm_* allocation here as each partition is a +		 * different device, which can be unbound. +		 */ +		tpmi_sst = kzalloc(sizeof(*tpmi_sst), GFP_KERNEL); +		if (!tpmi_sst) { +			ret = -ENOMEM; +			goto unlock_exit; +		} +		first_enum = true; +	} -	tpmi_sst->power_domain_info = devm_kcalloc(&auxdev->dev, num_resources, -						   sizeof(*tpmi_sst->power_domain_info), -						   GFP_KERNEL); -	if (!tpmi_sst->power_domain_info) -		return -ENOMEM; +	ret = 0; -	tpmi_sst->number_of_power_domains = num_resources; +	pd_info = devm_kcalloc(dev, num_resources, sizeof(*pd_info), GFP_KERNEL); +	if (!pd_info) { +		ret = -ENOMEM; +		goto unlock_free; +	} + +	/* Get the IO die count, if cdie_mask is present */ +	if (plat_info->cdie_mask) { +		u8 cdie_range; + +		cdie_mask = plat_info->cdie_mask; +		cdie_range = fls(cdie_mask) - ffs(cdie_mask) + 1; +		io_die_cnt = num_resources - cdie_range; +	} else { +		/* +		 * This is a synthetic mask, careful when assuming that +		 * they are compute dies only. +		 */ +		cdie_mask = (1 << num_resources) - 1; +		io_die_cnt = 0; +	}  	for (i = 0; i < num_resources; ++i) {  		struct resource *res;  		res = tpmi_get_resource_at_index(auxdev, i);  		if (!res) { -			tpmi_sst->power_domain_info[i].sst_base = NULL; +			pd_info[i].sst_base = NULL;  			continue;  		} -		tpmi_sst->power_domain_info[i].package_id = pkg; -		tpmi_sst->power_domain_info[i].power_domain_id = i; -		tpmi_sst->power_domain_info[i].auxdev = auxdev; -		tpmi_sst->power_domain_info[i].write_blocked = write_blocked; -		tpmi_sst->power_domain_info[i].sst_base = devm_ioremap_resource(&auxdev->dev, res); -		if (IS_ERR(tpmi_sst->power_domain_info[i].sst_base)) -			return PTR_ERR(tpmi_sst->power_domain_info[i].sst_base); +		pd_info[i].package_id = pkg; +		pd_info[i].power_domain_id = i; +		pd_info[i].auxdev = auxdev; +		pd_info[i].write_blocked = write_blocked; +		pd_info[i].sst_base = devm_ioremap_resource(dev, res); +		if (IS_ERR(pd_info[i].sst_base)) { +			ret = PTR_ERR(pd_info[i].sst_base); +			goto unlock_free; +		} -		ret = sst_main(auxdev, &tpmi_sst->power_domain_info[i]); +		ret = sst_main(auxdev, &pd_info[i]);  		if (ret) { -			devm_iounmap(&auxdev->dev, tpmi_sst->power_domain_info[i].sst_base); -			tpmi_sst->power_domain_info[i].sst_base =  NULL; +			/* +			 * This entry is not valid, hardware can partially +			 * populate dies. In this case MMIO will have 0xFFs. +			 * Also possible some pre-production hardware has +			 * invalid data. But don't fail and continue to use +			 * other dies with valid data. +			 */ +			devm_iounmap(dev, pd_info[i].sst_base); +			pd_info[i].sst_base = NULL;  			continue;  		}  		++inst;  	} -	if (!inst) -		return -ENODEV; +	if (!inst) { +		ret = -ENODEV; +		goto unlock_free; +	}  	tpmi_sst->package_id = pkg; + +	tpmi_sst->power_domain_info[partition] = pd_info; +	tpmi_sst->number_of_power_domains[partition] = num_resources; +	tpmi_sst->cdie_mask[partition] = cdie_mask; +	tpmi_sst->io_dies[partition] = io_die_cnt; +	tpmi_sst->partition_mask |= BIT(partition); +	tpmi_sst->partition_mask_current |= BIT(partition); +  	auxiliary_set_drvdata(auxdev, tpmi_sst); -	mutex_lock(&isst_tpmi_dev_lock);  	if (isst_common.max_index < pkg)  		isst_common.max_index = pkg;  	isst_common.sst_inst[pkg] = tpmi_sst; + +unlock_free: +	if (ret && first_enum) +		kfree(tpmi_sst); +unlock_exit:  	mutex_unlock(&isst_tpmi_dev_lock); -	return 0; +	return ret;  }  EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_add, INTEL_TPMI_SST);  void tpmi_sst_dev_remove(struct auxiliary_device *auxdev)  {  	struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev); +	struct intel_tpmi_plat_info *plat_info; + +	plat_info = tpmi_get_platform_data(auxdev); +	if (!plat_info) +		return;  	mutex_lock(&isst_tpmi_dev_lock); -	isst_common.sst_inst[tpmi_sst->package_id] = NULL; +	tpmi_sst->power_domain_info[plat_info->partition] = NULL; +	tpmi_sst->partition_mask_current &= ~BIT(plat_info->partition); +	/* Free the package instance when the all partitions are removed */ +	if (!tpmi_sst->partition_mask_current) { +		isst_common.sst_inst[tpmi_sst->package_id] = NULL; +		kfree(tpmi_sst); +	}  	mutex_unlock(&isst_tpmi_dev_lock);  }  EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_remove, INTEL_TPMI_SST); @@ -1374,9 +1620,16 @@ EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_remove, INTEL_TPMI_SST);  void tpmi_sst_dev_suspend(struct auxiliary_device *auxdev)  {  	struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev); -	struct tpmi_per_power_domain_info *power_domain_info = tpmi_sst->power_domain_info; +	struct tpmi_per_power_domain_info *power_domain_info; +	struct intel_tpmi_plat_info *plat_info;  	void __iomem *cp_base; +	plat_info = tpmi_get_platform_data(auxdev); +	if (!plat_info) +		return; + +	power_domain_info = tpmi_sst->power_domain_info[plat_info->partition]; +  	cp_base = power_domain_info->sst_base + power_domain_info->sst_header.cp_offset;  	power_domain_info->saved_sst_cp_control = readq(cp_base + SST_CP_CONTROL_OFFSET); @@ -1395,9 +1648,16 @@ EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_suspend, INTEL_TPMI_SST);  void tpmi_sst_dev_resume(struct auxiliary_device *auxdev)  {  	struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev); -	struct tpmi_per_power_domain_info *power_domain_info = tpmi_sst->power_domain_info; +	struct tpmi_per_power_domain_info *power_domain_info; +	struct intel_tpmi_plat_info *plat_info;  	void __iomem *cp_base; +	plat_info = tpmi_get_platform_data(auxdev); +	if (!plat_info) +		return; + +	power_domain_info = tpmi_sst->power_domain_info[plat_info->partition]; +  	cp_base = power_domain_info->sst_base + power_domain_info->sst_header.cp_offset;  	writeq(power_domain_info->saved_sst_cp_control, cp_base + SST_CP_CONTROL_OFFSET); @@ -1412,7 +1672,7 @@ void tpmi_sst_dev_resume(struct auxiliary_device *auxdev)  }  EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_resume, INTEL_TPMI_SST); -#define ISST_TPMI_API_VERSION	0x02 +#define ISST_TPMI_API_VERSION	0x03  int tpmi_sst_init(void)  { @@ -1469,4 +1729,5 @@ EXPORT_SYMBOL_NS_GPL(tpmi_sst_exit, INTEL_TPMI_SST);  MODULE_IMPORT_NS(INTEL_TPMI);  MODULE_IMPORT_NS(INTEL_TPMI_POWER_DOMAIN); +MODULE_DESCRIPTION("ISST TPMI interface module");  MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index 910df7c654f4..6c0cbccd80bb 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -128,6 +128,9 @@ struct intel_tpmi_info {   * @dev:	PCI device number   * @bus:	PCI bus number   * @pkg:	CPU Package id + * @segment:	PCI segment id + * @partition:	Package Partition id + * @cdie_mask:	Bitmap of compute dies in the current partition   * @reserved:	Reserved for future use   * @lock:	When set to 1 the register is locked and becomes read-only   *		until next reset. Not for use by the OS driver. @@ -139,7 +142,10 @@ struct tpmi_info_header {  	u64 dev:5;  	u64 bus:8;  	u64 pkg:8; -	u64 reserved:39; +	u64 segment:8; +	u64 partition:2; +	u64 cdie_mask:16; +	u64 reserved:13;  	u64 lock:1;  } __packed; @@ -666,28 +672,44 @@ static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info)  }  #define TPMI_INFO_BUS_INFO_OFFSET	0x08 +#define TPMI_INFO_MAJOR_VERSION		0x00 +#define TPMI_INFO_MINOR_VERSION		0x02  static int tpmi_process_info(struct intel_tpmi_info *tpmi_info,  			     struct intel_tpmi_pm_feature *pfs)  {  	struct tpmi_info_header header;  	void __iomem *info_mem; +	u64 feature_header; +	int ret = 0; -	info_mem = ioremap(pfs->vsec_offset + TPMI_INFO_BUS_INFO_OFFSET, -			   pfs->pfs_header.entry_size * sizeof(u32) - TPMI_INFO_BUS_INFO_OFFSET); +	info_mem = ioremap(pfs->vsec_offset, pfs->pfs_header.entry_size * sizeof(u32));  	if (!info_mem)  		return -ENOMEM; -	memcpy_fromio(&header, info_mem, sizeof(header)); +	feature_header = readq(info_mem); +	if (TPMI_MAJOR_VERSION(feature_header) != TPMI_INFO_MAJOR_VERSION) { +		ret = -ENODEV; +		goto error_info_header; +	} + +	memcpy_fromio(&header, info_mem + TPMI_INFO_BUS_INFO_OFFSET, sizeof(header));  	tpmi_info->plat_info.package_id = header.pkg;  	tpmi_info->plat_info.bus_number = header.bus;  	tpmi_info->plat_info.device_number = header.dev;  	tpmi_info->plat_info.function_number = header.fn; +	if (TPMI_MINOR_VERSION(feature_header) >= TPMI_INFO_MINOR_VERSION) { +		tpmi_info->plat_info.cdie_mask = header.cdie_mask; +		tpmi_info->plat_info.partition = header.partition; +		tpmi_info->plat_info.segment = header.segment; +	} + +error_info_header:  	iounmap(info_mem); -	return 0; +	return ret;  }  static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size) @@ -763,8 +785,11 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)  		 * when actual device nodes created outside this  		 * loop via tpmi_create_devices().  		 */ -		if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) -			tpmi_process_info(tpmi_info, pfs); +		if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) { +			ret = tpmi_process_info(tpmi_info, pfs); +			if (ret) +				return ret; +		}  		if (pfs->pfs_header.tpmi_id == TPMI_CONTROL_ID)  			tpmi_set_control_base(auxdev, tpmi_info, pfs); diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index ef730200a04b..bb8e72deb354 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -240,6 +240,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_  	bool read_blocked = 0, write_blocked = 0;  	struct intel_tpmi_plat_info *plat_info;  	struct tpmi_uncore_struct *tpmi_uncore; +	bool uncore_sysfs_added = false;  	int ret, i, pkg = 0;  	int num_resources; @@ -384,9 +385,15 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_  			}  			/* Point to next cluster offset */  			cluster_offset >>= UNCORE_MAX_CLUSTER_PER_DOMAIN; +			uncore_sysfs_added = true;  		}  	} +	if (!uncore_sysfs_added) { +		ret = -ENODEV; +		goto remove_clusters; +	} +  	auxiliary_set_drvdata(auxdev, tpmi_uncore);  	tpmi_uncore->root_cluster.root_domain = true; diff --git a/drivers/platform/x86/intel/vbtn.c b/drivers/platform/x86/intel/vbtn.c index 79bb2c801daa..84c1353eb12b 100644 --- a/drivers/platform/x86/intel/vbtn.c +++ b/drivers/platform/x86/intel/vbtn.c @@ -156,7 +156,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)  	if ((ke = sparse_keymap_entry_from_scancode(priv->buttons_dev, event))) {  		if (!priv->has_buttons) { -			dev_warn(&device->dev, "Warning: received a button event on a device without buttons, please report this.\n"); +			dev_warn(&device->dev, "Warning: received 0x%02x button event on a device without buttons, please report this.\n", +				 event);  			return;  		}  		input_dev = priv->buttons_dev; | 
