[PATCH v2 2/2] perf/dwc_pcie: Skip sibling walks for new group leaders

Zhanpeng Zhang zhangzhanpeng.jasper at bytedance.com
Tue Aug 11 09:07:20 PDT 2026


for_each_sibling_event() requires the event context lock to be held.
perf_try_init_event() only takes that lock when initializing a group
member.
The DWC PCIe PMU walks the sibling list twice for every event, including a
new group leader whose event_init() method runs without the lock. Although
the leader cannot have siblings yet, the lock assertion is evaluated before
the empty list is walked and produces two lockdep warnings.

Skip both sibling walks while initializing a group leader. Group member
validation is unchanged and continues to run with the event context mutex
held.

Fixes: af9597adc2f1 ("drivers/perf: add DesignWare PCIe PMU driver")
Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com>
---
A system-wide DWC PCIe PMU perf stat completed successfully with the same
debug configuration, without lockdep reports or kernel taint.

 drivers/perf/dwc_pcie_pmu.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c
index 7b2e28aade73..a6667ac19a99 100644
--- a/drivers/perf/dwc_pcie_pmu.c
+++ b/drivers/perf/dwc_pcie_pmu.c
@@ -417,6 +417,10 @@ static int dwc_pcie_pmu_validate_group(struct perf_event *event)
 		if (dwc_pcie_pmu_validate_add_lane_event(leader, val_lane_events))
 			return -ENOSPC;
 
+	/* A new group leader cannot have any siblings yet. */
+	if (event == leader)
+		return 0;
+
 	for_each_sibling_event(sibling, leader) {
 		type = DWC_PCIE_EVENT_TYPE(sibling);
 		if (type == DWC_PCIE_TIME_BASE_EVENT) {
@@ -452,9 +456,11 @@ static int dwc_pcie_pmu_event_init(struct perf_event *event)
 	if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK)
 		return -EINVAL;
 
-	for_each_sibling_event(sibling, event->group_leader) {
-		if (sibling->pmu != event->pmu && !is_software_event(sibling))
-			return -EINVAL;
+	if (event != event->group_leader) {
+		for_each_sibling_event(sibling, event->group_leader) {
+			if (sibling->pmu != event->pmu && !is_software_event(sibling))
+				return -EINVAL;
+		}
 	}
 
 	if (type < 0 || type >= DWC_PCIE_EVENT_TYPE_MAX)
-- 
2.50.1 (Apple Git-155)



More information about the linux-arm-kernel mailing list