[PATCH v4 2/2] PCI/TPH: Fix get cpu steer-tag fail on ARM64 platform
From: Chengwen Feng
Date: Mon Mar 09 2026 - 00:17:30 EST
Currently the pcie_tph_get_cpu_st() has an issue on ARM64 platform:
1. The pcie_tph_get_cpu_st() function directly uses cpu_uid as the input
parameter to call the PCI ACPI DSM method. According to the DSM
definition, the input value should be the ACPI Processor UID (see [1]
for details).
2. In the Broadcom driver implementation [2] (which invokes
pcie_tph_get_cpu_st()), cpu_uid is obtained via
cpumask_first(irq->cpu_mask) - this is the logical CPU ID of a CPU
core, generated and managed by kernel (e.g., [0,255] for a system
with 256 logical CPU cores).
3. On ARM64 platforms, ACPI assigns Processor UID to cores listed in the
MADT table, and this UID may not match the kernel's logical CPU ID.
As a result, the current implementation fails to retrieve the correct
CPU steer-tag in such cases.
4. The function works on AMD x86 platforms only because the logical CPU
ID is identical to the ACPI Processor UID on those systems.
This commit fixes it by:
1. Add new acpi_get_cpu_acpi_id() implementation on x86 that wraps
cpu_acpi_id(), completing the unified ACPI CPU ID retrieval interface
across ACPI-enabled platforms.
2. Update pcie_tph_get_cpu_st() to use acpi_get_cpu_acpi_id(cpu) to get
valid ACPI Processor UID for DSM calls.
3. Renaming pcie_tph_get_cpu_st()'s input parameter cpu_uid to cpu for
clarity, as the parameter now represents a logical CPU ID (not a
UID).
[1] According to ECN_TPH-ST_Revision_20200924
(https://members.pcisig.com/wg/PCI-SIG/document/15470), the input
is defined as: "If the target is a processor, then this field
represents the ACPI Processor UID of the processor as specified in
the MADT. If the target is a processor container, then this field
represents the ACPI Processor UID of the processor container as
specified in the PPTT."
[2] commit c214410c47d6e ("bnxt_en: Add TPH support in BNXT driver")
Fixes: d2e8a34876ce ("PCI/TPH: Add Steering Tag support")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Chengwen Feng <fengchengwen@xxxxxxxxxx>
---
Documentation/PCI/tph.rst | 4 ++--
arch/x86/include/asm/acpi.h | 2 ++
arch/x86/kernel/cpu/common.c | 8 ++++++++
drivers/pci/tph.c | 11 ++++++-----
include/linux/pci-tph.h | 4 ++--
5 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/Documentation/PCI/tph.rst b/Documentation/PCI/tph.rst
index e8993be64fd6..b6cf22b9bd90 100644
--- a/Documentation/PCI/tph.rst
+++ b/Documentation/PCI/tph.rst
@@ -79,10 +79,10 @@ To retrieve a Steering Tag for a target memory associated with a specific
CPU, use the following function::
int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type type,
- unsigned int cpu_uid, u16 *tag);
+ unsigned int cpu, u16 *tag);
The `type` argument is used to specify the memory type, either volatile
-or persistent, of the target memory. The `cpu_uid` argument specifies the
+or persistent, of the target memory. The `cpu` argument specifies the
CPU where the memory is associated to.
After the ST value is retrieved, the device driver can use the following
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index a03aa6f999d1..b968369715c1 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -157,6 +157,8 @@ static inline bool acpi_has_cpu_in_madt(void)
return !!acpi_lapic;
}
+u32 acpi_get_cpu_acpi_id(unsigned int cpu);
+
#define ACPI_HAVE_ARCH_SET_ROOT_POINTER
static __always_inline void acpi_arch_set_root_pointer(u64 addr)
{
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 1c3261cae40c..1c7aa7a4faa0 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -29,6 +29,7 @@
#include <linux/utsname.h>
#include <linux/efi.h>
+#include <asm/acpi.h>
#include <asm/alternative.h>
#include <asm/cmdline.h>
#include <asm/cpuid/api.h>
@@ -57,6 +58,7 @@
#include <asm/asm.h>
#include <asm/bugs.h>
#include <asm/cpu.h>
+#include <asm/smp.h>
#include <asm/mce.h>
#include <asm/msr.h>
#include <asm/cacheinfo.h>
@@ -2643,3 +2645,9 @@ void __init arch_cpu_finalize_init(void)
*/
mem_encrypt_init();
}
+
+u32 acpi_get_cpu_acpi_id(unsigned int cpu)
+{
+ return cpu_acpi_id(cpu);
+}
+EXPORT_SYMBOL_GPL(acpi_get_cpu_acpi_id);
diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c
index ca4f97be7538..c1bd60637b5a 100644
--- a/drivers/pci/tph.c
+++ b/drivers/pci/tph.c
@@ -236,18 +236,19 @@ static int write_tag_to_st_table(struct pci_dev *pdev, int index, u16 tag)
* with a specific CPU
* @pdev: PCI device
* @mem_type: target memory type (volatile or persistent RAM)
- * @cpu_uid: associated CPU id
+ * @cpu: associated CPU id
* @tag: Steering Tag to be returned
*
* Return the Steering Tag for a target memory that is associated with a
- * specific CPU as indicated by cpu_uid.
+ * specific CPU as indicated by cpu.
*
* Return: 0 if success, otherwise negative value (-errno)
*/
int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type mem_type,
- unsigned int cpu_uid, u16 *tag)
+ unsigned int cpu, u16 *tag)
{
#ifdef CONFIG_ACPI
+ u32 cpu_uid = acpi_get_cpu_acpi_id(cpu);
struct pci_dev *rp;
acpi_handle rp_acpi_handle;
union st_info info;
@@ -265,9 +266,9 @@ int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type mem_type,
*tag = tph_extract_tag(mem_type, pdev->tph_req_type, &info);
- pci_dbg(pdev, "get steering tag: mem_type=%s, cpu_uid=%d, tag=%#04x\n",
+ pci_dbg(pdev, "get steering tag: mem_type=%s, cpu=%d, tag=%#04x\n",
(mem_type == TPH_MEM_TYPE_VM) ? "volatile" : "persistent",
- cpu_uid, *tag);
+ cpu, *tag);
return 0;
#else
diff --git a/include/linux/pci-tph.h b/include/linux/pci-tph.h
index ba28140ce670..be68cd17f2f8 100644
--- a/include/linux/pci-tph.h
+++ b/include/linux/pci-tph.h
@@ -25,7 +25,7 @@ int pcie_tph_set_st_entry(struct pci_dev *pdev,
unsigned int index, u16 tag);
int pcie_tph_get_cpu_st(struct pci_dev *dev,
enum tph_mem_type mem_type,
- unsigned int cpu_uid, u16 *tag);
+ unsigned int cpu, u16 *tag);
void pcie_disable_tph(struct pci_dev *pdev);
int pcie_enable_tph(struct pci_dev *pdev, int mode);
u16 pcie_tph_get_st_table_size(struct pci_dev *pdev);
@@ -36,7 +36,7 @@ static inline int pcie_tph_set_st_entry(struct pci_dev *pdev,
{ return -EINVAL; }
static inline int pcie_tph_get_cpu_st(struct pci_dev *dev,
enum tph_mem_type mem_type,
- unsigned int cpu_uid, u16 *tag)
+ unsigned int cpu, u16 *tag)
{ return -EINVAL; }
static inline void pcie_disable_tph(struct pci_dev *pdev) { }
static inline int pcie_enable_tph(struct pci_dev *pdev, int mode)
--
2.17.1