ACPI fixes for 6.9-rc6

- Allow two overlapping Low-Power S0 Idle _DSM function sets to be used
    at the same time (Rafael Wysocki).
 
  - Fix bit offset computation in MASK_VAL() macro used for applying
    a bitmask to a new CPPC register value (Jarred White).
 
  - Fix access width field usage for PCC registers in CPPC (Vanshidhar
    Konda).
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmYqlVUSHHJqd0Byand5
 c29ja2kubmV0AAoJEILEb/54YlRxuuIP/10TXZwAyUtYmHT6P9f+mcuUKs57E7zi
 IIfbubObVXHIOFa9CJWhfySm9qtbSQFZ/OjjTVZJKh511phVyCwWx+CJJqn4C1pH
 HVymTU7Vb1JFiW2rpUvwhqTPf+LmHF2U9+KS7OxBHTKrJMBYlQw6lPfhVFyWhFT2
 zVJT8GQNjSCAMUiPpPXSsL+rraaQo0mI0XVe8W6oE1zbaIYxVFLI2RmmR33A9Qpx
 2bO3XzO0QeXzaUiIdbyc/aH2yGL1f9NVuwdP9sudl6/tPz06WALzHpiCus5pO9Iv
 SRuWDUS5FOdqOJ0CTEsxtab1qQGsFcGe4HwI1sW8v4+HiqrMRTMPV0izhU2Oulpn
 n9x2QZj69W6iXVzY7l7bsI6ZvBjJIIzBZoEreKA9k2x+KIT0CseDQkGL+Ug7XKRt
 8mdhP4HkCbnHhqBQ6wZQpmZJi06Hle5ylvN9U3pSUsCyu/0wx47d56Q0sSKGRmUu
 NGgp4FKyUupcMouAYwZF4AR1oAdo+dCX/i2hKTg07vNolH4jSICKETSIDADbGS90
 AQxFKP66Xv2u/0akn3gXZQtlhFZppQjzpplYr5NPuhIQ9Uk2e2ItUXxd8DbXdD+v
 IMEh4yQ0NWTY/DaITPFvz6Yy2AZu4MDd5yOElk5pyL6Ca8j/4XcSBCG46unwNJJ3
 ahlFckAkqZ/D
 =r5Uu
 -----END PGP SIGNATURE-----

Merge tag 'acpi-6.9-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI fixes from Rafael Wysocki:
 "These fix three recent regressions, one introduced while enabling a
  new platform firmware feature for power management, and two introduced
  by a recent CPPC library update.

  Specifics:

   - Allow two overlapping Low-Power S0 Idle _DSM function sets to be
     used at the same time (Rafael Wysocki)

   - Fix bit offset computation in MASK_VAL() macro used for applying a
     bitmask to a new CPPC register value (Jarred White)

   - Fix access width field usage for PCC registers in CPPC (Vanshidhar
     Konda)"

* tag 'acpi-6.9-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI: PM: s2idle: Evaluate all Low-Power S0 Idle _DSM functions
  ACPI: CPPC: Fix access width used for PCC registers
  ACPI: CPPC: Fix bit_offset shift in MASK_VAL() macro
This commit is contained in:
Linus Torvalds 2024-04-25 11:28:00 -07:00
commit a93289b830
2 changed files with 42 additions and 23 deletions

View File

@ -170,8 +170,8 @@ show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
#define GET_BIT_WIDTH(reg) ((reg)->access_width ? (8 << ((reg)->access_width - 1)) : (reg)->bit_width) #define GET_BIT_WIDTH(reg) ((reg)->access_width ? (8 << ((reg)->access_width - 1)) : (reg)->bit_width)
/* Shift and apply the mask for CPC reads/writes */ /* Shift and apply the mask for CPC reads/writes */
#define MASK_VAL(reg, val) ((val) >> ((reg)->bit_offset & \ #define MASK_VAL(reg, val) (((val) >> (reg)->bit_offset) & \
GENMASK(((reg)->bit_width), 0))) GENMASK(((reg)->bit_width) - 1, 0))
static ssize_t show_feedback_ctrs(struct kobject *kobj, static ssize_t show_feedback_ctrs(struct kobject *kobj,
struct kobj_attribute *attr, char *buf) struct kobj_attribute *attr, char *buf)
@ -1002,14 +1002,14 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
} }
*val = 0; *val = 0;
size = GET_BIT_WIDTH(reg);
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
u32 width = GET_BIT_WIDTH(reg);
u32 val_u32; u32 val_u32;
acpi_status status; acpi_status status;
status = acpi_os_read_port((acpi_io_address)reg->address, status = acpi_os_read_port((acpi_io_address)reg->address,
&val_u32, width); &val_u32, size);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_debug("Error: Failed to read SystemIO port %llx\n", pr_debug("Error: Failed to read SystemIO port %llx\n",
reg->address); reg->address);
@ -1018,17 +1018,22 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
*val = val_u32; *val = val_u32;
return 0; return 0;
} else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) {
/*
* For registers in PCC space, the register size is determined
* by the bit width field; the access size is used to indicate
* the PCC subspace id.
*/
size = reg->bit_width;
vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
}
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
vaddr = reg_res->sys_mem_vaddr; vaddr = reg_res->sys_mem_vaddr;
else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
return cpc_read_ffh(cpu, reg, val); return cpc_read_ffh(cpu, reg, val);
else else
return acpi_os_read_memory((acpi_physical_address)reg->address, return acpi_os_read_memory((acpi_physical_address)reg->address,
val, reg->bit_width); val, size);
size = GET_BIT_WIDTH(reg);
switch (size) { switch (size) {
case 8: case 8:
@ -1044,8 +1049,13 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
*val = readq_relaxed(vaddr); *val = readq_relaxed(vaddr);
break; break;
default: default:
pr_debug("Error: Cannot read %u bit width from PCC for ss: %d\n", if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
reg->bit_width, pcc_ss_id); pr_debug("Error: Cannot read %u bit width from system memory: 0x%llx\n",
size, reg->address);
} else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
pr_debug("Error: Cannot read %u bit width from PCC for ss: %d\n",
size, pcc_ss_id);
}
return -EFAULT; return -EFAULT;
} }
@ -1063,12 +1073,13 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
struct cpc_reg *reg = &reg_res->cpc_entry.reg; struct cpc_reg *reg = &reg_res->cpc_entry.reg;
size = GET_BIT_WIDTH(reg);
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
u32 width = GET_BIT_WIDTH(reg);
acpi_status status; acpi_status status;
status = acpi_os_write_port((acpi_io_address)reg->address, status = acpi_os_write_port((acpi_io_address)reg->address,
(u32)val, width); (u32)val, size);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_debug("Error: Failed to write SystemIO port %llx\n", pr_debug("Error: Failed to write SystemIO port %llx\n",
reg->address); reg->address);
@ -1076,17 +1087,22 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
} }
return 0; return 0;
} else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) {
/*
* For registers in PCC space, the register size is determined
* by the bit width field; the access size is used to indicate
* the PCC subspace id.
*/
size = reg->bit_width;
vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
}
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
vaddr = reg_res->sys_mem_vaddr; vaddr = reg_res->sys_mem_vaddr;
else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
return cpc_write_ffh(cpu, reg, val); return cpc_write_ffh(cpu, reg, val);
else else
return acpi_os_write_memory((acpi_physical_address)reg->address, return acpi_os_write_memory((acpi_physical_address)reg->address,
val, reg->bit_width); val, size);
size = GET_BIT_WIDTH(reg);
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
val = MASK_VAL(reg, val); val = MASK_VAL(reg, val);
@ -1105,8 +1121,13 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
writeq_relaxed(val, vaddr); writeq_relaxed(val, vaddr);
break; break;
default: default:
pr_debug("Error: Cannot write %u bit width to PCC for ss: %d\n", if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
reg->bit_width, pcc_ss_id); pr_debug("Error: Cannot write %u bit width to system memory: 0x%llx\n",
size, reg->address);
} else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
pr_debug("Error: Cannot write %u bit width to PCC for ss: %d\n",
size, pcc_ss_id);
}
ret_val = -EFAULT; ret_val = -EFAULT;
break; break;
} }

View File

@ -492,16 +492,14 @@ static int lps0_device_attach(struct acpi_device *adev,
unsigned int func_mask; unsigned int func_mask;
/* /*
* Avoid evaluating the same _DSM function for two * Log a message if the _DSM function sets for two
* different UUIDs and prioritize the MSFT one. * different UUIDs overlap.
*/ */
func_mask = lps0_dsm_func_mask & lps0_dsm_func_mask_microsoft; func_mask = lps0_dsm_func_mask & lps0_dsm_func_mask_microsoft;
if (func_mask) { if (func_mask)
acpi_handle_info(adev->handle, acpi_handle_info(adev->handle,
"Duplicate LPS0 _DSM functions (mask: 0x%x)\n", "Duplicate LPS0 _DSM functions (mask: 0x%x)\n",
func_mask); func_mask);
lps0_dsm_func_mask &= ~func_mask;
}
} }
} }