* [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups
@ 2026-05-11 23:05 Zide Chen
2026-05-11 23:05 ` [PATCH 1/6] perf/x86/intel/uncore: Fix discovery unit lookup for multi-die systems Zide Chen
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Zide Chen @ 2026-05-11 23:05 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen
This series includes bug fixes and cleanups for the Intel uncore PMU
driver.
- Patch 1 fixes a theoretical bug in discovery unit lookup on multi-die
systems.
- Patch 2 fixes a PCI device refcount leak in UPI topology discovery.
- Patch 3 works around a hardware issue on Raptor Cove CPUs.
- Patches 4-6 implement a global MSR init callback for GNR/GRR/SRF/CWF
uncore.
Zide Chen (6):
perf/x86/intel/uncore: Fix discovery unit lookup for multi-die systems
perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery
perf/x86/intel/uncore: Defer ADL global PMON enable to enable_box()
perf/x86/intel/uncore: Move die_to_cpu() to uncore.c
perf/x86/intel/uncore: Fix uncore_die_to_cpu() for offline dies
perf/x86/intel/uncore: Implement global init callback for GNR uncore
arch/x86/events/intel/uncore.c | 33 ++++++++++++++++++++++-
arch/x86/events/intel/uncore.h | 3 ++-
arch/x86/events/intel/uncore_discovery.c | 4 +--
arch/x86/events/intel/uncore_snb.c | 7 -----
arch/x86/events/intel/uncore_snbep.c | 34 +++++++-----------------
5 files changed, 46 insertions(+), 35 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/6] perf/x86/intel/uncore: Fix discovery unit lookup for multi-die systems
2026-05-11 23:05 [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups Zide Chen
@ 2026-05-11 23:05 ` Zide Chen
2026-05-11 23:05 ` [PATCH 2/6] perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery Zide Chen
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Zide Chen @ 2026-05-11 23:05 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen
In uncore_find_add_unit(), PMON units with the same unit ID may be
added to the uncore discovery RB tree for different dies. These units
are distinguished by node->die.
However, intel_generic_uncore_box_ctl() uses fixes die ID -1 when
looking up the discovery unit, which may retrieve the wrong node on
multi-die systems.
Use box->dieid instead so the correct discovery unit is selected.
No functional issue has been observed so far because currently supported
platforms happen to use the same unit control register for such units.
Fixes: b1d9ea2e1ca4 ("perf/x86/uncore: Apply the unit control RB tree to MSR uncore units")
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
arch/x86/events/intel/uncore_discovery.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/events/intel/uncore_discovery.c b/arch/x86/events/intel/uncore_discovery.c
index 583cbd06b9b8..1d22d7c00ee0 100644
--- a/arch/x86/events/intel/uncore_discovery.c
+++ b/arch/x86/events/intel/uncore_discovery.c
@@ -481,7 +481,7 @@ static u64 intel_generic_uncore_box_ctl(struct intel_uncore_box *box)
struct intel_uncore_discovery_unit *unit;
unit = intel_uncore_find_discovery_unit(box->pmu->type->boxes,
- -1, box->pmu->pmu_idx);
+ box->dieid, box->pmu->pmu_idx);
if (WARN_ON_ONCE(!unit))
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/6] perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery
2026-05-11 23:05 [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups Zide Chen
2026-05-11 23:05 ` [PATCH 1/6] perf/x86/intel/uncore: Fix discovery unit lookup for multi-die systems Zide Chen
@ 2026-05-11 23:05 ` Zide Chen
2026-05-12 9:27 ` Mi, Dapeng
2026-05-11 23:05 ` [PATCH 3/6] perf/x86/intel/uncore: Defer ADL global PMON enable to enable_box() Zide Chen
` (3 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Zide Chen @ 2026-05-11 23:05 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen
pci_get_domain_bus_and_slot() increments the reference count of the
returned PCI device and therefore requires a matching pci_dev_put().
In skx_upi_topology_cb() and discover_upi_topology(), the lookup is
performed inside a loop, but pci_dev_put() is only called once after
the loop. As a result, references from all previous iterations are
leaked.
Move pci_dev_put(dev) into the if (dev) block immediately after
upi_fill_topology() returns.
Opportunistically, fix uninitialized variable in skx_upi_topology_cb().
Fixes: 4cfce57fa42d ("perf/x86/intel/uncore: Enable UPI topology discovery for Skylake Server")
Fixes: f680b6e6062e ("perf/x86/intel/uncore: Enable UPI topology discovery for Icelake Server")
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
arch/x86/events/intel/uncore_snbep.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
index 215d33e260ed..c9ce206fcbb6 100644
--- a/arch/x86/events/intel/uncore_snbep.c
+++ b/arch/x86/events/intel/uncore_snbep.c
@@ -4261,7 +4261,7 @@ static int upi_fill_topology(struct pci_dev *dev, struct intel_uncore_topology *
static int skx_upi_topology_cb(struct intel_uncore_type *type, int segment,
int die, u64 cpu_bus_msr)
{
- int idx, ret;
+ int idx, ret = 0;
struct intel_uncore_topology *upi;
unsigned int devfn;
struct pci_dev *dev = NULL;
@@ -4274,12 +4274,12 @@ static int skx_upi_topology_cb(struct intel_uncore_type *type, int segment,
dev = pci_get_domain_bus_and_slot(segment, bus, devfn);
if (dev) {
ret = upi_fill_topology(dev, upi, idx);
+ pci_dev_put(dev);
if (ret)
break;
}
}
- pci_dev_put(dev);
return ret;
}
@@ -5499,6 +5499,7 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i
devfn);
if (dev) {
ret = upi_fill_topology(dev, upi, idx);
+ pci_dev_put(dev);
if (ret)
goto err;
}
@@ -5506,7 +5507,6 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i
}
err:
pci_dev_put(ubox);
- pci_dev_put(dev);
return ret;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/6] perf/x86/intel/uncore: Defer ADL global PMON enable to enable_box()
2026-05-11 23:05 [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups Zide Chen
2026-05-11 23:05 ` [PATCH 1/6] perf/x86/intel/uncore: Fix discovery unit lookup for multi-die systems Zide Chen
2026-05-11 23:05 ` [PATCH 2/6] perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery Zide Chen
@ 2026-05-11 23:05 ` Zide Chen
2026-05-11 23:05 ` [PATCH 4/6] perf/x86/intel/uncore: Move die_to_cpu() to uncore.c Zide Chen
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Zide Chen @ 2026-05-11 23:05 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen, stable
On some Raptor Cove CPUs, enabling uncore PMON globally at driver init
may increase power consumption even when no perf events are in use.
Drop adl_uncore_msr_init_box() and defer programming the global control
register to enable_box(), so it is only set when a box is actually used.
Cc: stable@vger.kernel.org
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
arch/x86/events/intel/uncore_snb.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/arch/x86/events/intel/uncore_snb.c b/arch/x86/events/intel/uncore_snb.c
index 3dbc6bacbd9d..edddd4f9ab5f 100644
--- a/arch/x86/events/intel/uncore_snb.c
+++ b/arch/x86/events/intel/uncore_snb.c
@@ -563,12 +563,6 @@ void tgl_uncore_cpu_init(void)
skl_uncore_msr_ops.init_box = rkl_uncore_msr_init_box;
}
-static void adl_uncore_msr_init_box(struct intel_uncore_box *box)
-{
- if (box->pmu->pmu_idx == 0)
- wrmsrq(ADL_UNC_PERF_GLOBAL_CTL, SNB_UNC_GLOBAL_CTL_EN);
-}
-
static void adl_uncore_msr_enable_box(struct intel_uncore_box *box)
{
wrmsrq(ADL_UNC_PERF_GLOBAL_CTL, SNB_UNC_GLOBAL_CTL_EN);
@@ -587,7 +581,6 @@ static void adl_uncore_msr_exit_box(struct intel_uncore_box *box)
}
static struct intel_uncore_ops adl_uncore_msr_ops = {
- .init_box = adl_uncore_msr_init_box,
.enable_box = adl_uncore_msr_enable_box,
.disable_box = adl_uncore_msr_disable_box,
.exit_box = adl_uncore_msr_exit_box,
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/6] perf/x86/intel/uncore: Move die_to_cpu() to uncore.c
2026-05-11 23:05 [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups Zide Chen
` (2 preceding siblings ...)
2026-05-11 23:05 ` [PATCH 3/6] perf/x86/intel/uncore: Defer ADL global PMON enable to enable_box() Zide Chen
@ 2026-05-11 23:05 ` Zide Chen
2026-05-11 23:05 ` [PATCH 5/6] perf/x86/intel/uncore: Fix uncore_die_to_cpu() for offline dies Zide Chen
2026-05-11 23:05 ` [PATCH 6/6] perf/x86/intel/uncore: Implement global init callback for GNR uncore Zide Chen
5 siblings, 0 replies; 9+ messages in thread
From: Zide Chen @ 2026-05-11 23:05 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen
Move die_to_cpu() into uncore.c so it can be reused by the MSR
initialization path, preparing for the introduction of an MSR global
initialization callback.
Add the uncore_ prefix for consistency with other uncore APIs.
No functional change intended.
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
arch/x86/events/intel/uncore.c | 19 +++++++++++++++++++
arch/x86/events/intel/uncore.h | 1 +
arch/x86/events/intel/uncore_snbep.c | 21 +--------------------
3 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c
index e9cc1ba921c5..2bbe4cc1df3e 100644
--- a/arch/x86/events/intel/uncore.c
+++ b/arch/x86/events/intel/uncore.c
@@ -83,6 +83,25 @@ int uncore_device_to_die(struct pci_dev *dev)
return -1;
}
+int uncore_die_to_cpu(int die)
+{
+ int res = 0, cpu;
+
+ /*
+ * Using cpus_read_lock() to ensure cpu is not going down between
+ * looking at cpu_online_mask.
+ */
+ cpus_read_lock();
+ for_each_online_cpu(cpu) {
+ if (topology_logical_die_id(cpu) == die) {
+ res = cpu;
+ break;
+ }
+ }
+ cpus_read_unlock();
+ return res;
+}
+
static void uncore_free_pcibus_map(void)
{
struct pci2phy_map *map, *tmp;
diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h
index c35918c01afa..94c68e3417b6 100644
--- a/arch/x86/events/intel/uncore.h
+++ b/arch/x86/events/intel/uncore.h
@@ -235,6 +235,7 @@ struct pci2phy_map *__find_pci2phy_map(int segment);
int uncore_pcibus_to_dieid(struct pci_bus *bus);
int uncore_die_to_segment(int die);
int uncore_device_to_die(struct pci_dev *dev);
+int uncore_die_to_cpu(int die);
ssize_t uncore_event_show(struct device *dev,
struct device_attribute *attr, char *buf);
diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
index c9ce206fcbb6..30c6a9306c54 100644
--- a/arch/x86/events/intel/uncore_snbep.c
+++ b/arch/x86/events/intel/uncore_snbep.c
@@ -3704,25 +3704,6 @@ static int skx_msr_cpu_bus_read(int cpu, u64 *topology)
return 0;
}
-static int die_to_cpu(int die)
-{
- int res = 0, cpu, current_die;
- /*
- * Using cpus_read_lock() to ensure cpu is not going down between
- * looking at cpu_online_mask.
- */
- cpus_read_lock();
- for_each_online_cpu(cpu) {
- current_die = topology_logical_die_id(cpu);
- if (current_die == die) {
- res = cpu;
- break;
- }
- }
- cpus_read_unlock();
- return res;
-}
-
enum {
IIO_TOPOLOGY_TYPE,
UPI_TOPOLOGY_TYPE,
@@ -3795,7 +3776,7 @@ static int skx_pmu_get_topology(struct intel_uncore_type *type,
u64 cpu_bus_msr;
for (die = 0; die < uncore_max_dies(); die++) {
- ret = skx_msr_cpu_bus_read(die_to_cpu(die), &cpu_bus_msr);
+ ret = skx_msr_cpu_bus_read(uncore_die_to_cpu(die), &cpu_bus_msr);
if (ret)
break;
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/6] perf/x86/intel/uncore: Fix uncore_die_to_cpu() for offline dies
2026-05-11 23:05 [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups Zide Chen
` (3 preceding siblings ...)
2026-05-11 23:05 ` [PATCH 4/6] perf/x86/intel/uncore: Move die_to_cpu() to uncore.c Zide Chen
@ 2026-05-11 23:05 ` Zide Chen
2026-05-11 23:05 ` [PATCH 6/6] perf/x86/intel/uncore: Implement global init callback for GNR uncore Zide Chen
5 siblings, 0 replies; 9+ messages in thread
From: Zide Chen @ 2026-05-11 23:05 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen
If the die is offline when uncore_die_to_cpu() is called, it silently
returns 0, which is misleading. Return -1 in this case to indicate
that all CPUs on the die are offline and the caller can take care of
it accordingly.
Opportunistically, replace -EPERM with -ENODEV, as -ENODEV is
the appropriate error when no CPUs are online across all dies.
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
arch/x86/events/intel/uncore.c | 2 +-
arch/x86/events/intel/uncore_snbep.c | 9 +++++++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c
index 2bbe4cc1df3e..19056514b081 100644
--- a/arch/x86/events/intel/uncore.c
+++ b/arch/x86/events/intel/uncore.c
@@ -85,7 +85,7 @@ int uncore_device_to_die(struct pci_dev *dev)
int uncore_die_to_cpu(int die)
{
- int res = 0, cpu;
+ int res = -1, cpu;
/*
* Using cpus_read_lock() to ensure cpu is not going down between
diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
index 30c6a9306c54..251c7bdbe30b 100644
--- a/arch/x86/events/intel/uncore_snbep.c
+++ b/arch/x86/events/intel/uncore_snbep.c
@@ -3772,11 +3772,16 @@ static void pmu_free_topology(struct intel_uncore_type *type)
static int skx_pmu_get_topology(struct intel_uncore_type *type,
int (*topology_cb)(struct intel_uncore_type*, int, int, u64))
{
- int die, ret = -EPERM;
+ int die, ret = -ENODEV;
u64 cpu_bus_msr;
+ int cpu;
for (die = 0; die < uncore_max_dies(); die++) {
- ret = skx_msr_cpu_bus_read(uncore_die_to_cpu(die), &cpu_bus_msr);
+ cpu = uncore_die_to_cpu(die);
+ if (cpu == -1)
+ continue;
+
+ ret = skx_msr_cpu_bus_read(cpu, &cpu_bus_msr);
if (ret)
break;
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6/6] perf/x86/intel/uncore: Implement global init callback for GNR uncore
2026-05-11 23:05 [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups Zide Chen
` (4 preceding siblings ...)
2026-05-11 23:05 ` [PATCH 5/6] perf/x86/intel/uncore: Fix uncore_die_to_cpu() for offline dies Zide Chen
@ 2026-05-11 23:05 ` Zide Chen
5 siblings, 0 replies; 9+ messages in thread
From: Zide Chen @ 2026-05-11 23:05 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen
On Sierra Forest and Clearwater Forest, the FRZ_ALL bit in the global
control register defaults to 0 at boot, but UBOX PMON units do not
work until the global control register is explicitly written with 0
to trigger hardware initialization properly.
Implement the generic uncore_msr_global_init() callback and add it to
gnr_uncore_init[], which is shared by GNR, GRR, SRF, and CWF.
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
arch/x86/events/intel/uncore.c | 14 +++++++++++++-
arch/x86/events/intel/uncore.h | 2 +-
arch/x86/events/intel/uncore_discovery.c | 2 +-
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c
index 19056514b081..a7780c5cd419 100644
--- a/arch/x86/events/intel/uncore.c
+++ b/arch/x86/events/intel/uncore.c
@@ -1716,7 +1716,7 @@ static int __init uncore_mmio_init(void)
return ret;
}
-static int uncore_mmio_global_init(u64 ctl)
+static int uncore_mmio_global_init(int die, u64 ctl)
{
void __iomem *io_addr;
@@ -1731,6 +1731,17 @@ static int uncore_mmio_global_init(u64 ctl)
return 0;
}
+static int uncore_msr_global_init(int die, u64 msr)
+{
+ int cpu = uncore_die_to_cpu(die);
+
+ if (cpu == -1)
+ return -ENODEV;
+
+ wrmsrq_on_cpu(cpu, msr, 0);
+ return 0;
+}
+
static const struct uncore_plat_init nhm_uncore_init __initconst = {
.cpu_init = nhm_uncore_cpu_init,
};
@@ -1871,6 +1882,7 @@ static const struct uncore_plat_init gnr_uncore_init __initconst = {
.domain[0].base_is_pci = true,
.domain[0].discovery_base = UNCORE_DISCOVERY_TABLE_DEVICE,
.domain[0].units_ignore = gnr_uncore_units_ignore,
+ .domain[0].global_init = uncore_msr_global_init,
};
static const struct uncore_plat_init dmr_uncore_init __initconst = {
diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h
index 94c68e3417b6..c2e5ccb1d72c 100644
--- a/arch/x86/events/intel/uncore.h
+++ b/arch/x86/events/intel/uncore.h
@@ -53,7 +53,7 @@ struct uncore_discovery_domain {
/* MSR address or PCI device used as the discovery base */
u32 discovery_base;
bool base_is_pci;
- int (*global_init)(u64 ctl);
+ int (*global_init)(int die, u64 ctl);
/* The units in the discovery table should be ignored. */
int *units_ignore;
diff --git a/arch/x86/events/intel/uncore_discovery.c b/arch/x86/events/intel/uncore_discovery.c
index 1d22d7c00ee0..49183d607a34 100644
--- a/arch/x86/events/intel/uncore_discovery.c
+++ b/arch/x86/events/intel/uncore_discovery.c
@@ -287,7 +287,7 @@ static int __parse_discovery_table(struct uncore_discovery_domain *domain,
if (!io_addr)
return -ENOMEM;
- if (domain->global_init && domain->global_init(global.ctl)) {
+ if (domain->global_init && domain->global_init(die, global.ctl)) {
ret = -ENODEV;
goto out;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 2/6] perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery
2026-05-11 23:05 ` [PATCH 2/6] perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery Zide Chen
@ 2026-05-12 9:27 ` Mi, Dapeng
2026-05-12 17:35 ` Chen, Zide
0 siblings, 1 reply; 9+ messages in thread
From: Mi, Dapeng @ 2026-05-12 9:27 UTC (permalink / raw)
To: Zide Chen, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users
On 5/12/2026 7:05 AM, Zide Chen wrote:
> pci_get_domain_bus_and_slot() increments the reference count of the
> returned PCI device and therefore requires a matching pci_dev_put().
>
> In skx_upi_topology_cb() and discover_upi_topology(), the lookup is
> performed inside a loop, but pci_dev_put() is only called once after
> the loop. As a result, references from all previous iterations are
> leaked.
>
> Move pci_dev_put(dev) into the if (dev) block immediately after
> upi_fill_topology() returns.
>
> Opportunistically, fix uninitialized variable in skx_upi_topology_cb().
>
> Fixes: 4cfce57fa42d ("perf/x86/intel/uncore: Enable UPI topology discovery for Skylake Server")
> Fixes: f680b6e6062e ("perf/x86/intel/uncore: Enable UPI topology discovery for Icelake Server")
> Signed-off-by: Zide Chen <zide.chen@intel.com>
> ---
> arch/x86/events/intel/uncore_snbep.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
> index 215d33e260ed..c9ce206fcbb6 100644
> --- a/arch/x86/events/intel/uncore_snbep.c
> +++ b/arch/x86/events/intel/uncore_snbep.c
> @@ -4261,7 +4261,7 @@ static int upi_fill_topology(struct pci_dev *dev, struct intel_uncore_topology *
> static int skx_upi_topology_cb(struct intel_uncore_type *type, int segment,
> int die, u64 cpu_bus_msr)
> {
> - int idx, ret;
> + int idx, ret = 0;
> struct intel_uncore_topology *upi;
> unsigned int devfn;
> struct pci_dev *dev = NULL;
> @@ -4274,12 +4274,12 @@ static int skx_upi_topology_cb(struct intel_uncore_type *type, int segment,
> dev = pci_get_domain_bus_and_slot(segment, bus, devfn);
> if (dev) {
> ret = upi_fill_topology(dev, upi, idx);
> + pci_dev_put(dev);
> if (ret)
> break;
> }
> }
>
> - pci_dev_put(dev);
> return ret;
> }
>
> @@ -5499,6 +5499,7 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i
> devfn);
> if (dev) {
> ret = upi_fill_topology(dev, upi, idx);
> + pci_dev_put(dev);
> if (ret)
> goto err;
> }
> @@ -5506,7 +5507,6 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i
> }
> err:
> pci_dev_put(ubox);
> - pci_dev_put(dev);
Should we move the "pci_dev_put(ubox)" into the while loop as well? In
theory, the ubox device could be found multiple times.
Besides, could you please search "pci_get_device()" in uncore code, it
seems some functions don't call pci_dev_put() or only calls it once, like
the funciton spr_update_device_location() ...
Thanks.
> return ret;
> }
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/6] perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery
2026-05-12 9:27 ` Mi, Dapeng
@ 2026-05-12 17:35 ` Chen, Zide
0 siblings, 0 replies; 9+ messages in thread
From: Chen, Zide @ 2026-05-12 17:35 UTC (permalink / raw)
To: Mi, Dapeng, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users
On 5/12/2026 2:27 AM, Mi, Dapeng wrote:
>
> On 5/12/2026 7:05 AM, Zide Chen wrote:
>> pci_get_domain_bus_and_slot() increments the reference count of the
>> returned PCI device and therefore requires a matching pci_dev_put().
>>
>> In skx_upi_topology_cb() and discover_upi_topology(), the lookup is
>> performed inside a loop, but pci_dev_put() is only called once after
>> the loop. As a result, references from all previous iterations are
>> leaked.
>>
>> Move pci_dev_put(dev) into the if (dev) block immediately after
>> upi_fill_topology() returns.
>>
>> Opportunistically, fix uninitialized variable in skx_upi_topology_cb().
>>
>> Fixes: 4cfce57fa42d ("perf/x86/intel/uncore: Enable UPI topology discovery for Skylake Server")
>> Fixes: f680b6e6062e ("perf/x86/intel/uncore: Enable UPI topology discovery for Icelake Server")
>> Signed-off-by: Zide Chen <zide.chen@intel.com>
>> ---
>> arch/x86/events/intel/uncore_snbep.c | 6 +++---
>> 1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
>> index 215d33e260ed..c9ce206fcbb6 100644
>> --- a/arch/x86/events/intel/uncore_snbep.c
>> +++ b/arch/x86/events/intel/uncore_snbep.c
>> @@ -4261,7 +4261,7 @@ static int upi_fill_topology(struct pci_dev *dev, struct intel_uncore_topology *
>> static int skx_upi_topology_cb(struct intel_uncore_type *type, int segment,
>> int die, u64 cpu_bus_msr)
>> {
>> - int idx, ret;
>> + int idx, ret = 0;
>> struct intel_uncore_topology *upi;
>> unsigned int devfn;
>> struct pci_dev *dev = NULL;
>> @@ -4274,12 +4274,12 @@ static int skx_upi_topology_cb(struct intel_uncore_type *type, int segment,
>> dev = pci_get_domain_bus_and_slot(segment, bus, devfn);
>> if (dev) {
>> ret = upi_fill_topology(dev, upi, idx);
>> + pci_dev_put(dev);
>> if (ret)
>> break;
>> }
>> }
>>
>> - pci_dev_put(dev);
>> return ret;
>> }
>>
>> @@ -5499,6 +5499,7 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i
>> devfn);
>> if (dev) {
>> ret = upi_fill_topology(dev, upi, idx);
>> + pci_dev_put(dev);
>> if (ret)
>> goto err;
>> }
>> @@ -5506,7 +5507,6 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i
>> }
>> err:
>> pci_dev_put(ubox);
>> - pci_dev_put(dev);
>
> Should we move the "pci_dev_put(ubox)" into the while loop as well? In
> theory, the ubox device could be found multiple times.
As mentioned below, pci_dev_put(ubox) is needed for the two 'goto err"
breaks. Moving it into the main loop would require two pci_dev_put()
calls, which adds no benefit.
>
> Besides, could you please search "pci_get_device()" in uncore code, it
> seems some functions don't call pci_dev_put() or only calls it once, like
> the funciton spr_update_device_location() ...
pci_get_device() calls pci_dev_put() internally on the previous device
before returning the next one, so if the "while (pci_get_device())" loop
runs to completion without a break, no extra pci_dev_put() is needed:
https://elixir.bootlin.com/linux/v7.1-rc3/source/drivers/pci/search.c#L283
> Thanks.
>
>
>
>> return ret;
>> }
>>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-05-12 17:35 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11 23:05 [PATCH 0/6] perf/x86/intel/uncore: Bug fixes and cleanups Zide Chen
2026-05-11 23:05 ` [PATCH 1/6] perf/x86/intel/uncore: Fix discovery unit lookup for multi-die systems Zide Chen
2026-05-11 23:05 ` [PATCH 2/6] perf/x86/intel/uncore: Fix PCI device refcount leak in UPI discovery Zide Chen
2026-05-12 9:27 ` Mi, Dapeng
2026-05-12 17:35 ` Chen, Zide
2026-05-11 23:05 ` [PATCH 3/6] perf/x86/intel/uncore: Defer ADL global PMON enable to enable_box() Zide Chen
2026-05-11 23:05 ` [PATCH 4/6] perf/x86/intel/uncore: Move die_to_cpu() to uncore.c Zide Chen
2026-05-11 23:05 ` [PATCH 5/6] perf/x86/intel/uncore: Fix uncore_die_to_cpu() for offline dies Zide Chen
2026-05-11 23:05 ` [PATCH 6/6] perf/x86/intel/uncore: Implement global init callback for GNR uncore Zide Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox