From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC745C433FE for ; Mon, 21 Feb 2022 23:17:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236059AbiBUXRx (ORCPT ); Mon, 21 Feb 2022 18:17:53 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:32892 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236010AbiBUXRp (ORCPT ); Mon, 21 Feb 2022 18:17:45 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 358752458C; Mon, 21 Feb 2022 15:17:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485441; x=1677021441; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5NTVg/3b+n9yGWloqSIjoBVRuhweq0kc3TvI9tdbCGE=; b=KIkDkrUmfu0I7pPb73M8+vrLjnfx8As+92J6Gmaag9t5h/AcssV5DMuR HSJQqPPzwO2akrsSPU/JdtWdc6PutZnewVhz9oHr6NSboWpNQE7IAgpSR ScSTxO64NQUyZ9IK/IpGfzM0Bq7Wx337BPhC/9KJ7dAJluDveuvAi2ZW8 rdAMcdU0n6jcmQzmLzy9/pOYHLy+pFE/Qn9nPje1gPU1qNUAhH6Nx2R5O VxZaT9oNVWmFK72pdGQaD/U8OhmCDEPxTC3Y1pkLXoItrDkD+MwEukUCP Rb3PVsLOnSWbS0NeL7WEIsrsCgQSRBRVWhztQFjDA76oH8BGe4qXaqUOc A==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530339" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530339" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:21 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694359" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:18 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Eric Dumazet , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Dmitry Vyukov , Jakub Kicinski , "David S . Miller" Subject: [PATCH v2 01/11] [DO NOT MERGE] ref_tracker: implement use-after-free detection Date: Tue, 22 Feb 2022 00:16:43 +0100 Message-Id: <20220221231705.1481059-2-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Eric Dumazet Whenever ref_tracker_dir_init() is called, mark the struct ref_tracker_dir as dead. Test the dead status from ref_tracker_alloc() and ref_tracker_free() This should detect buggy dev_put()/dev_hold() happening too late in netdevice dismantle process. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Andrzej Hajda --- include/linux/ref_tracker.h | 2 ++ lib/ref_tracker.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 60f3453be23e6..a443abda937d8 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -13,6 +13,7 @@ struct ref_tracker_dir { spinlock_t lock; unsigned int quarantine_avail; refcount_t untracked; + bool dead; struct list_head list; /* List of active trackers */ struct list_head quarantine; /* List of dead trackers */ #endif @@ -26,6 +27,7 @@ static inline void ref_tracker_dir_init(struct ref_tracke= r_dir *dir, INIT_LIST_HEAD(&dir->quarantine); spin_lock_init(&dir->lock); dir->quarantine_avail =3D quarantine_count; + dir->dead =3D false; refcount_set(&dir->untracked, 1); stack_depot_init(); } diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index a6789c0c626b0..32ff6bd497f8e 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -20,6 +20,7 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) unsigned long flags; bool leak =3D false; =20 + dir->dead =3D true; spin_lock_irqsave(&dir->lock, flags); list_for_each_entry_safe(tracker, n, &dir->quarantine, head) { list_del(&tracker->head); @@ -72,6 +73,8 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, gfp_t gfp_mask =3D gfp; unsigned long flags; =20 + WARN_ON_ONCE(dir->dead); + if (gfp & __GFP_DIRECT_RECLAIM) gfp_mask |=3D __GFP_NOFAIL; *trackerp =3D tracker =3D kzalloc(sizeof(*tracker), gfp_mask); @@ -100,6 +103,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, unsigned int nr_entries; unsigned long flags; =20 + WARN_ON_ONCE(dir->dead); + if (!tracker) { refcount_dec(&dir->untracked); return -EEXIST; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CFAF6C433EF for ; Mon, 21 Feb 2022 23:17:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236093AbiBUXR5 (ORCPT ); Mon, 21 Feb 2022 18:17:57 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:32912 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236030AbiBUXRs (ORCPT ); Mon, 21 Feb 2022 18:17:48 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 14D682458C; Mon, 21 Feb 2022 15:17:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485444; x=1677021444; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Pk7RlYaQyw781A8X6p8V9ya5Qc0/GolTrSOpzx8g9s8=; b=nTHPdJqDDC3GLzN/RnP+TC6nLtyKUUtWPzSYAgDvVJosES6cBnMj7oiA Wd46wnp+vtw6wXClMUB7mtrndLKX4SEj1RuFpbNLkhnz68WoI1hPzh97j HqT7/vU5mDAYFqsyHrnkUlEf1xOH2VfWlsgrFdTrKAgvH9/vej5rF1p3m 0cjTLUI+rIJDxeZUfSgVCzG1FuO3eJPnoxR1Vt7oH03GrwnTHyB2fEDpK DP1LR6h84L74LIoq5GlFJET/FUioDo6aVKQXJkGjbuP04LkN6RO3TgsUz bcVqkXiJfL0dAmIvG6M3NUiosXQvcdsVCuRaaDol0udb4TScLRRP9/qSk A==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530340" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530340" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:23 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694370" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:21 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 1/9] lib/ref_tracker: add unlocked leak print helper Date: Tue, 22 Feb 2022 00:16:44 +0100 Message-Id: <20220221231705.1481059-3-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" To have reliable detection of leaks, caller must be able to check under the= same lock both: tracked counter and the leaks. dir.lock is natural candidate for= such lock and unlocked print helper can be called with this lock taken. As a bonus we can reuse this helper in ref_tracker_dir_exit. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- include/linux/ref_tracker.h | 8 +++++ lib/ref_tracker.c | 66 +++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 60f3453be23e6..b9c968a716483 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -32,6 +32,9 @@ static inline void ref_tracker_dir_init(struct ref_tracke= r_dir *dir, =20 void ref_tracker_dir_exit(struct ref_tracker_dir *dir); =20 +void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit); + void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit); =20 @@ -52,6 +55,11 @@ static inline void ref_tracker_dir_exit(struct ref_track= er_dir *dir) { } =20 +static inline void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ +} + static inline void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit) { diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index a6789c0c626b0..1b0c6d645d64a 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -14,6 +14,38 @@ struct ref_tracker { depot_stack_handle_t free_stack_handle; }; =20 +void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ref_tracker *tracker; + unsigned int i =3D 0; + + lockdep_assert_held(&dir->lock); + + list_for_each_entry(tracker, &dir->list, head) { + if (i < display_limit) { + pr_err("leaked reference.\n"); + if (tracker->alloc_stack_handle) + stack_depot_print(tracker->alloc_stack_handle); + i++; + } else { + break; + } + } +} +EXPORT_SYMBOL(__ref_tracker_dir_print); + +void ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + unsigned long flags; + + spin_lock_irqsave(&dir->lock, flags); + __ref_tracker_dir_print(dir, display_limit); + spin_unlock_irqrestore(&dir->lock, flags); +} +EXPORT_SYMBOL(ref_tracker_dir_print); + void ref_tracker_dir_exit(struct ref_tracker_dir *dir) { struct ref_tracker *tracker, *n; @@ -26,13 +58,13 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) kfree(tracker); dir->quarantine_avail++; } - list_for_each_entry_safe(tracker, n, &dir->list, head) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); + if (!list_empty(&dir->list)) { + __ref_tracker_dir_print(dir, 16); leak =3D true; - list_del(&tracker->head); - kfree(tracker); + list_for_each_entry_safe(tracker, n, &dir->list, head) { + list_del(&tracker->head); + kfree(tracker); + } } spin_unlock_irqrestore(&dir->lock, flags); WARN_ON_ONCE(leak); @@ -40,28 +72,6 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) } EXPORT_SYMBOL(ref_tracker_dir_exit); =20 -void ref_tracker_dir_print(struct ref_tracker_dir *dir, - unsigned int display_limit) -{ - struct ref_tracker *tracker; - unsigned long flags; - unsigned int i =3D 0; - - spin_lock_irqsave(&dir->lock, flags); - list_for_each_entry(tracker, &dir->list, head) { - if (i < display_limit) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); - i++; - } else { - break; - } - } - spin_unlock_irqrestore(&dir->lock, flags); -} -EXPORT_SYMBOL(ref_tracker_dir_print); - int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp) --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9D79AC4332F for ; Mon, 21 Feb 2022 23:17:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236113AbiBUXR7 (ORCPT ); Mon, 21 Feb 2022 18:17:59 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:32932 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236051AbiBUXRv (ORCPT ); Mon, 21 Feb 2022 18:17:51 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 494C32459C; Mon, 21 Feb 2022 15:17:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485447; x=1677021447; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5NTVg/3b+n9yGWloqSIjoBVRuhweq0kc3TvI9tdbCGE=; b=WjhAFSS//BAgw81ig+c5vCwM1p1hizaLB8hCwvvrCAYwXyJnGg+t2amH Nyy8FPPZAX7VN1umUlON2x7JH1weX8j179Yl5iKLCFeMKSytlW7GR5jnu kHvp+1Gh9JNyP3bLkhBXj2hlHwnW5nyVwp2uEuFFCm9k/ipQ2pBodNQPk puksrxSvTcq+Dg0WWLQBz5phaDu/zncUxUsDExjx59dBVQjt0xbKO89Fe Cq51JUDLBNbDPPHiHSFWSZ+dNaIWXrYV82imsD4tnWWBBiO49NLw2AWr7 BClugg7YhI8fjLBvJniZvu2mIoaozYDjVDu6kR0U7IaSyHxfXOnikPiVO A==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530344" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530344" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:27 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694376" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:24 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Eric Dumazet , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Dmitry Vyukov , Jakub Kicinski , "David S . Miller" Subject: [PATCH v2 01/11] ref_tracker: implement use-after-free detection Date: Tue, 22 Feb 2022 00:16:45 +0100 Message-Id: <20220221231705.1481059-4-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Eric Dumazet Whenever ref_tracker_dir_init() is called, mark the struct ref_tracker_dir as dead. Test the dead status from ref_tracker_alloc() and ref_tracker_free() This should detect buggy dev_put()/dev_hold() happening too late in netdevice dismantle process. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Andrzej Hajda --- include/linux/ref_tracker.h | 2 ++ lib/ref_tracker.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 60f3453be23e6..a443abda937d8 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -13,6 +13,7 @@ struct ref_tracker_dir { spinlock_t lock; unsigned int quarantine_avail; refcount_t untracked; + bool dead; struct list_head list; /* List of active trackers */ struct list_head quarantine; /* List of dead trackers */ #endif @@ -26,6 +27,7 @@ static inline void ref_tracker_dir_init(struct ref_tracke= r_dir *dir, INIT_LIST_HEAD(&dir->quarantine); spin_lock_init(&dir->lock); dir->quarantine_avail =3D quarantine_count; + dir->dead =3D false; refcount_set(&dir->untracked, 1); stack_depot_init(); } diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index a6789c0c626b0..32ff6bd497f8e 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -20,6 +20,7 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) unsigned long flags; bool leak =3D false; =20 + dir->dead =3D true; spin_lock_irqsave(&dir->lock, flags); list_for_each_entry_safe(tracker, n, &dir->quarantine, head) { list_del(&tracker->head); @@ -72,6 +73,8 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, gfp_t gfp_mask =3D gfp; unsigned long flags; =20 + WARN_ON_ONCE(dir->dead); + if (gfp & __GFP_DIRECT_RECLAIM) gfp_mask |=3D __GFP_NOFAIL; *trackerp =3D tracker =3D kzalloc(sizeof(*tracker), gfp_mask); @@ -100,6 +103,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, unsigned int nr_entries; unsigned long flags; =20 + WARN_ON_ONCE(dir->dead); + if (!tracker) { refcount_dec(&dir->untracked); return -EEXIST; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A3E2EC4332F for ; Mon, 21 Feb 2022 23:17:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236134AbiBUXSD (ORCPT ); Mon, 21 Feb 2022 18:18:03 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:32962 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236064AbiBUXRy (ORCPT ); Mon, 21 Feb 2022 18:17:54 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C8F9245B2; Mon, 21 Feb 2022 15:17:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485450; x=1677021450; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Hxxx7U/IhkSHLnB5PbYul9lg1GjO2Izf/ptB46o3iFI=; b=Cto2hUqZmmwrZaR2suOPcFb0xcxSyoyJXQ7O2RQ5rytqnxmAxpHmhcw2 5GZSDCxNq8+WzGkn1YViF6+hlaHSySRmdpGC0K31EsU70cnk8hEjAy7Ch qMBWbbmOk9dRstc2CKpbG5nDDZ4XGBJEzHsYItVFHcmX0686x8fqsvJ2h gwPwXNjcrtZ7DGASfmkhhVcwDCXIUXwzZ47ZjW+A7U1eWerUcdmq5DNI1 bjmT7HV+U9LFLgosqKtnDEGyFk1tIHnfoi5croLk3JAeuXCKaXx54Pae8 OdTc91oE6+INiJmmmgy+8Hm/Q2lKijnNnw2OG0694CvF52Qe6xQyClw5u g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530348" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530348" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:30 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694383" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:27 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Eric Dumazet , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Dmitry Vyukov , Jakub Kicinski , "David S . Miller" Subject: [PATCH v2 02/11] [DO NOT MERGE] ref_tracker: add a count of untracked references Date: Tue, 22 Feb 2022 00:16:46 +0100 Message-Id: <20220221231705.1481059-5-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Eric Dumazet We are still chasing a netdev refcount imbalance, and we suspect we have one rogue dev_put() that is consuming a reference taken from a dev_hold_track() To detect this case, allow ref_tracker_alloc() and ref_tracker_free() to be called with a NULL @trackerp parameter, and use a dedicated refcount_t just for them. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Andrzej Hajda --- include/linux/ref_tracker.h | 2 ++ lib/ref_tracker.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index a443abda937d8..9ca353ab712b5 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -13,6 +13,7 @@ struct ref_tracker_dir { spinlock_t lock; unsigned int quarantine_avail; refcount_t untracked; + refcount_t no_tracker; bool dead; struct list_head list; /* List of active trackers */ struct list_head quarantine; /* List of dead trackers */ @@ -29,6 +30,7 @@ static inline void ref_tracker_dir_init(struct ref_tracke= r_dir *dir, dir->quarantine_avail =3D quarantine_count; dir->dead =3D false; refcount_set(&dir->untracked, 1); + refcount_set(&dir->no_tracker, 1); stack_depot_init(); } =20 diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 32ff6bd497f8e..9c0c2e09df666 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -38,6 +38,7 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) spin_unlock_irqrestore(&dir->lock, flags); WARN_ON_ONCE(leak); WARN_ON_ONCE(refcount_read(&dir->untracked) !=3D 1); + WARN_ON_ONCE(refcount_read(&dir->no_tracker) !=3D 1); } EXPORT_SYMBOL(ref_tracker_dir_exit); =20 @@ -75,6 +76,10 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, =20 WARN_ON_ONCE(dir->dead); =20 + if (!trackerp) { + refcount_inc(&dir->no_tracker); + return 0; + } if (gfp & __GFP_DIRECT_RECLAIM) gfp_mask |=3D __GFP_NOFAIL; *trackerp =3D tracker =3D kzalloc(sizeof(*tracker), gfp_mask); @@ -98,13 +103,18 @@ int ref_tracker_free(struct ref_tracker_dir *dir, struct ref_tracker **trackerp) { unsigned long entries[REF_TRACKER_STACK_ENTRIES]; - struct ref_tracker *tracker =3D *trackerp; depot_stack_handle_t stack_handle; + struct ref_tracker *tracker; unsigned int nr_entries; unsigned long flags; =20 WARN_ON_ONCE(dir->dead); =20 + if (!trackerp) { + refcount_dec(&dir->no_tracker); + return 0; + } + tracker =3D *trackerp; if (!tracker) { refcount_dec(&dir->untracked); return -EEXIST; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DB569C433EF for ; Mon, 21 Feb 2022 23:17:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236179AbiBUXSG (ORCPT ); Mon, 21 Feb 2022 18:18:06 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:32994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236111AbiBUXR7 (ORCPT ); Mon, 21 Feb 2022 18:17:59 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 469FA2458C; Mon, 21 Feb 2022 15:17:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485455; x=1677021455; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=hKcMNiYsgJWI/tUBCVHZc6qZhjqO+LBrBiPvfP3KNy0=; b=eiuylxvohcefrmbZjrk0rkrhxxfPkDJ59lV/fVVflPT4Cjy5LIDlcIJK KEnmHz3ErJ531cAkbuR+Ws4uqukpzy36mRmqjnoNMWnTIpmWZUE01e9ZS DkZ93H5ohJXb4q+xZcifFmsoGYOsgRTpo06v5BMN9SmAuKClvveB7pvxr CF7sl4852lyyAtg8c3n83f27Np4V9McEGxgNaSXDgECXP+cTCe4+0fNnG 2oYi5FQ30AaQ/wh95Rsa/AZiKQc/Je7UWaAWeFr9x0lMSofsPuB12zpoN bDYVVqzPNat3WZjI8W6n0l/6eHQHOCrzI2iSo7ez4/UDIj0Hmhv5FtONO Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530372" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530372" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:34 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694396" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:30 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 2/9] lib/ref_tracker: compact stacktraces before printing Date: Tue, 22 Feb 2022 00:16:47 +0100 Message-Id: <20220221231705.1481059-6-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In cases references are taken alternately on multiple exec paths leak report can grow substantially, sorting and grouping leaks by stack_handle allows to compact it. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- lib/ref_tracker.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 1b0c6d645d64a..0e9c7d2828ccb 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include #include @@ -14,23 +15,41 @@ struct ref_tracker { depot_stack_handle_t free_stack_handle; }; =20 +static int ref_tracker_cmp(void *priv, const struct list_head *a, const st= ruct list_head *b) +{ + const struct ref_tracker *ta =3D list_entry(a, const struct ref_tracker, = head); + const struct ref_tracker *tb =3D list_entry(b, const struct ref_tracker, = head); + + return ta->alloc_stack_handle - tb->alloc_stack_handle; +} + void __ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit) { + unsigned int i =3D 0, count =3D 0; struct ref_tracker *tracker; - unsigned int i =3D 0; + depot_stack_handle_t stack; =20 lockdep_assert_held(&dir->lock); =20 + if (list_empty(&dir->list)) + return; + + list_sort(NULL, &dir->list, ref_tracker_cmp); + list_for_each_entry(tracker, &dir->list, head) { - if (i < display_limit) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); - i++; - } else { + if (i++ >=3D display_limit) break; - } + if (!count++) + stack =3D tracker->alloc_stack_handle; + if (stack =3D=3D tracker->alloc_stack_handle && + !list_is_last(&tracker->head, &dir->list)) + continue; + + pr_err("leaked %d references.\n", count); + if (stack) + stack_depot_print(stack); + count =3D 0; } } EXPORT_SYMBOL(__ref_tracker_dir_print); --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3693AC433EF for ; Mon, 21 Feb 2022 23:17:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236241AbiBUXSM (ORCPT ); Mon, 21 Feb 2022 18:18:12 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33012 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236051AbiBUXSB (ORCPT ); Mon, 21 Feb 2022 18:18:01 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 865C8245AD; Mon, 21 Feb 2022 15:17:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485457; x=1677021457; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Hxxx7U/IhkSHLnB5PbYul9lg1GjO2Izf/ptB46o3iFI=; b=gmmZK8abjwwCvc5LvvB8sjTAnReXC0LHRqiXqjpUyFZgiX9oNWSQAeR8 hj13Up6cC2NugLzumx0ljHXsbnPKH12V0VcBWhNuW6hEVPj6BSTZICK4M UQO2vg+cgXmD5jAgQP3t0JpLzi6e4USVn3KxasPmVuv3b+4wCHT8dryXZ 7bKF34IhHoMop/ys114yeAH7vyXEiCUf9sy0p8iQFHLzDO3JE1M2XBZmc zwW4Txutssw83vePN/3eD/RxWH9iF+UgjFmg3bBYugf3TG30BJe9NBVDO ExXel8rbItnnXVqYyzIqqsJ4EVH7SpfdFUKMZpWHRGIrfP85rP2wFvulK A==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530383" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530383" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:37 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694418" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:34 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Eric Dumazet , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Dmitry Vyukov , Jakub Kicinski , "David S . Miller" Subject: [PATCH v2 02/11] ref_tracker: add a count of untracked references Date: Tue, 22 Feb 2022 00:16:48 +0100 Message-Id: <20220221231705.1481059-7-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Eric Dumazet We are still chasing a netdev refcount imbalance, and we suspect we have one rogue dev_put() that is consuming a reference taken from a dev_hold_track() To detect this case, allow ref_tracker_alloc() and ref_tracker_free() to be called with a NULL @trackerp parameter, and use a dedicated refcount_t just for them. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Andrzej Hajda --- include/linux/ref_tracker.h | 2 ++ lib/ref_tracker.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index a443abda937d8..9ca353ab712b5 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -13,6 +13,7 @@ struct ref_tracker_dir { spinlock_t lock; unsigned int quarantine_avail; refcount_t untracked; + refcount_t no_tracker; bool dead; struct list_head list; /* List of active trackers */ struct list_head quarantine; /* List of dead trackers */ @@ -29,6 +30,7 @@ static inline void ref_tracker_dir_init(struct ref_tracke= r_dir *dir, dir->quarantine_avail =3D quarantine_count; dir->dead =3D false; refcount_set(&dir->untracked, 1); + refcount_set(&dir->no_tracker, 1); stack_depot_init(); } =20 diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 32ff6bd497f8e..9c0c2e09df666 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -38,6 +38,7 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) spin_unlock_irqrestore(&dir->lock, flags); WARN_ON_ONCE(leak); WARN_ON_ONCE(refcount_read(&dir->untracked) !=3D 1); + WARN_ON_ONCE(refcount_read(&dir->no_tracker) !=3D 1); } EXPORT_SYMBOL(ref_tracker_dir_exit); =20 @@ -75,6 +76,10 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, =20 WARN_ON_ONCE(dir->dead); =20 + if (!trackerp) { + refcount_inc(&dir->no_tracker); + return 0; + } if (gfp & __GFP_DIRECT_RECLAIM) gfp_mask |=3D __GFP_NOFAIL; *trackerp =3D tracker =3D kzalloc(sizeof(*tracker), gfp_mask); @@ -98,13 +103,18 @@ int ref_tracker_free(struct ref_tracker_dir *dir, struct ref_tracker **trackerp) { unsigned long entries[REF_TRACKER_STACK_ENTRIES]; - struct ref_tracker *tracker =3D *trackerp; depot_stack_handle_t stack_handle; + struct ref_tracker *tracker; unsigned int nr_entries; unsigned long flags; =20 WARN_ON_ONCE(dir->dead); =20 + if (!trackerp) { + refcount_dec(&dir->no_tracker); + return 0; + } + tracker =3D *trackerp; if (!tracker) { refcount_dec(&dir->untracked); return -EEXIST; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C9435C433EF for ; Mon, 21 Feb 2022 23:17:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236207AbiBUXSQ (ORCPT ); Mon, 21 Feb 2022 18:18:16 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33056 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236154AbiBUXSE (ORCPT ); Mon, 21 Feb 2022 18:18:04 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F3D99245BD; Mon, 21 Feb 2022 15:17:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485461; x=1677021461; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mCvpydHF1iIboEBA+Uw1DVwXJZydjDJfqmrcbQB+Qt0=; b=N1U1BgoygZTPBRZWdVDXoBTFW6VgSSYMIRxermN2rX/MVjvK8DaNwNUK rcJhOPVGXTx9d+5d4+wjxSArLG2nlxo9QG6OZ4GubgCse4wLZUH5pg3S+ 66D/buX2Fcx+GjRoKXqHiD05tks2In1vrrGl256X2sN2ApitMn/wl+2we pJRIsi2g5PCg+qfQFDdY1UTkjSx1M91dx2VOaEvhj3MSUjvepW6OEaZy7 ol7Oo6tJrWVZXJIZjgoPltmPF4w9OiJHDUMIRaoB5wGMNJ3qRqbd2Gy/A w/k5DJT8RVlqAMVMF/WtDS0M8EInvFe44qQYgo2w5an0dgQNHbyGKqrGq Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530388" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530388" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:40 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694432" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:37 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Eric Dumazet , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Dmitry Vyukov , Jakub Kicinski , Marco Elver , Alexander Potapenko , "David S . Miller" Subject: [PATCH v2 03/11] [DO NOT MERGE] ref_tracker: remove filter_irq_stacks() call Date: Tue, 22 Feb 2022 00:16:49 +0100 Message-Id: <20220221231705.1481059-8-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Eric Dumazet After commit e94006608949 ("lib/stackdepot: always do filter_irq_stacks() in stack_depot_save()") it became unnecessary to filter the stack before calling stack_depot_save(). Signed-off-by: Eric Dumazet Cc: Marco Elver Cc: Alexander Potapenko Cc: Dmitry Vyukov Signed-off-by: David S. Miller Signed-off-by: Andrzej Hajda --- lib/ref_tracker.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 9c0c2e09df666..dc7b14aa3431e 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -89,7 +89,6 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, return -ENOMEM; } nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - nr_entries =3D filter_irq_stacks(entries, nr_entries); tracker->alloc_stack_handle =3D stack_depot_save(entries, nr_entries, gfp= ); =20 spin_lock_irqsave(&dir->lock, flags); @@ -120,7 +119,6 @@ int ref_tracker_free(struct ref_tracker_dir *dir, return -EEXIST; } nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - nr_entries =3D filter_irq_stacks(entries, nr_entries); stack_handle =3D stack_depot_save(entries, nr_entries, GFP_ATOMIC); =20 spin_lock_irqsave(&dir->lock, flags); --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3EB64C4332F for ; Mon, 21 Feb 2022 23:18:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236291AbiBUXS0 (ORCPT ); Mon, 21 Feb 2022 18:18:26 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33144 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236213AbiBUXSI (ORCPT ); Mon, 21 Feb 2022 18:18:08 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4960245AD; Mon, 21 Feb 2022 15:17:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485463; x=1677021463; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+ysWCOx8Qe0FgPrL7lCitOlIRN7GA/uTSmYciHcbFL0=; b=E5atYg51AyAZOv7HVW0+MOP4iBgpbKpLlSL4lVyJqeMAsjpAmQIsLAdc InPjpHI4ezQhWYK1RcfCqR1yc5yXlys7FNnLd1/QxBH2RFVgDcDbShRpN WyocrjmUdnL6qbo9dcDlclScXkJlcTNS7q/rnWQQt9N8CRIpcaWJwPrIH k7U4c8yXvTrGHDkNKBMmVx6Q5imOH5cQl1avTh0cev2EcGDzsAW+pKC1A 6ttTChlts39sZ2KdcqH7S8c1mOsvAP8TI3/Le4TX/mqTzKIZYdUS5OXs5 9vD6tso+fe8VkCm6xqxCh1RvXEnjbJyvCMk5YTXY2Zs0q25xR9c0SHnpk w==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530392" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530392" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:43 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694447" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:40 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 3/9] lib/ref_tracker: __ref_tracker_dir_print improve printing Date: Tue, 22 Feb 2022 00:16:50 +0100 Message-Id: <20220221231705.1481059-9-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" To improve readibility of ref_tracker printing following changes have been performed: - added display name for ref_tracker_dir, - stack trace is printed indented, in the same printk call, - total number of references is printed every time, - print info about dropped references. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- include/linux/ref_tracker.h | 15 ++++++++++++--- lib/ref_tracker.c | 28 ++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index b9c968a716483..090230e5b485d 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -15,18 +15,26 @@ struct ref_tracker_dir { refcount_t untracked; struct list_head list; /* List of active trackers */ struct list_head quarantine; /* List of dead trackers */ + char name[32]; #endif }; =20 #ifdef CONFIG_REF_TRACKER -static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, - unsigned int quarantine_count) + +// Temporary allow two and three arguments, until consumers are converted +#define ref_tracker_dir_init(_d, _q, args...) _ref_tracker_dir_init(_d, _q= , ##args, #_d) +#define _ref_tracker_dir_init(_d, _q, _n, ...) __ref_tracker_dir_init(_d, = _q, _n) + +static inline void __ref_tracker_dir_init(struct ref_tracker_dir *dir, + unsigned int quarantine_count, + const char *name) { INIT_LIST_HEAD(&dir->list); INIT_LIST_HEAD(&dir->quarantine); spin_lock_init(&dir->lock); dir->quarantine_avail =3D quarantine_count; refcount_set(&dir->untracked, 1); + strlcpy(dir->name, name, sizeof(dir->name)); stack_depot_init(); } =20 @@ -47,7 +55,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, #else /* CONFIG_REF_TRACKER */ =20 static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, - unsigned int quarantine_count) + unsigned int quarantine_count, + ...) { } =20 diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 0e9c7d2828ccb..943cff08110e3 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -1,4 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later + +#define pr_fmt(fmt) "ref_tracker: " fmt + #include #include #include @@ -7,6 +10,7 @@ #include =20 #define REF_TRACKER_STACK_ENTRIES 16 +#define STACK_BUF_SIZE 1024 =20 struct ref_tracker { struct list_head head; /* anchor into dir->list or dir->quarantine */ @@ -26,31 +30,43 @@ static int ref_tracker_cmp(void *priv, const struct lis= t_head *a, const struct l void __ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit) { - unsigned int i =3D 0, count =3D 0; + unsigned int i =3D 0, count =3D 0, total =3D 0; struct ref_tracker *tracker; depot_stack_handle_t stack; + char *sbuf; =20 lockdep_assert_held(&dir->lock); =20 if (list_empty(&dir->list)) return; =20 + sbuf =3D kmalloc(STACK_BUF_SIZE, GFP_NOWAIT); + + list_for_each_entry(tracker, &dir->list, head) + ++total; + list_sort(NULL, &dir->list, ref_tracker_cmp); =20 list_for_each_entry(tracker, &dir->list, head) { - if (i++ >=3D display_limit) - break; if (!count++) stack =3D tracker->alloc_stack_handle; if (stack =3D=3D tracker->alloc_stack_handle && !list_is_last(&tracker->head, &dir->list)) continue; + if (i++ >=3D display_limit) + continue; =20 - pr_err("leaked %d references.\n", count); - if (stack) - stack_depot_print(stack); + if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4)) + sbuf[0] =3D 0; + pr_err("%s@%pK has %d/%d users at\n%s\n", + dir->name, dir, count, total, sbuf); count =3D 0; } + if (i > display_limit) + pr_err("%s@%pK skipped %d/%d reports with %d unique stacks.\n", + dir->name, dir, count, total, i - display_limit); + + kfree(sbuf); } EXPORT_SYMBOL(__ref_tracker_dir_print); =20 --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B89D8C433FE for ; Mon, 21 Feb 2022 23:18:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236455AbiBUXS3 (ORCPT ); Mon, 21 Feb 2022 18:18:29 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236302AbiBUXSY (ORCPT ); Mon, 21 Feb 2022 18:18:24 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7B1C324BEA; Mon, 21 Feb 2022 15:17:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485467; x=1677021467; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mCvpydHF1iIboEBA+Uw1DVwXJZydjDJfqmrcbQB+Qt0=; b=lTyCsGjf2n6WIT2zvreJYX1VNOUc7vhktSEGLfxPuNey+y8dP31QUDP3 WRZsg6dM+E1eeoKliuJHEuEKNXbt2wIJU1MXDy2CF/mbMggHBVX5jLYLM 0BhESim1a6+u76B0XVVoCPVOJCDSTC1Emd4qQxXiftJSvGlJ6BvfwlcTn 0uyUgwKsD8yF7E8W4z3Ja9d4vAxGYPY+cZHtIaotAceAdpyixNzY+g2T3 ZBM4pnEhihaBNjyAYuc4IDKAB6moOV/WZPqxwzrzETVyoefdtIp5Oanfr ynP02eZlZOzMabX7d1m0Im5dJDazcEJ093ZS73t7aOcJusEGDYb9O8Ke/ w==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530401" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530401" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:47 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694463" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:43 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Eric Dumazet , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Dmitry Vyukov , Jakub Kicinski , Marco Elver , Alexander Potapenko , "David S . Miller" Subject: [PATCH v2 03/11] ref_tracker: remove filter_irq_stacks() call Date: Tue, 22 Feb 2022 00:16:51 +0100 Message-Id: <20220221231705.1481059-10-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Eric Dumazet After commit e94006608949 ("lib/stackdepot: always do filter_irq_stacks() in stack_depot_save()") it became unnecessary to filter the stack before calling stack_depot_save(). Signed-off-by: Eric Dumazet Cc: Marco Elver Cc: Alexander Potapenko Cc: Dmitry Vyukov Signed-off-by: David S. Miller Signed-off-by: Andrzej Hajda --- lib/ref_tracker.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 9c0c2e09df666..dc7b14aa3431e 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -89,7 +89,6 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, return -ENOMEM; } nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - nr_entries =3D filter_irq_stacks(entries, nr_entries); tracker->alloc_stack_handle =3D stack_depot_save(entries, nr_entries, gfp= ); =20 spin_lock_irqsave(&dir->lock, flags); @@ -120,7 +119,6 @@ int ref_tracker_free(struct ref_tracker_dir *dir, return -EEXIST; } nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - nr_entries =3D filter_irq_stacks(entries, nr_entries); stack_handle =3D stack_depot_save(entries, nr_entries, GFP_ATOMIC); =20 spin_lock_irqsave(&dir->lock, flags); --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65490C433FE for ; Mon, 21 Feb 2022 23:18:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236529AbiBUXSe (ORCPT ); Mon, 21 Feb 2022 18:18:34 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236320AbiBUXSZ (ORCPT ); Mon, 21 Feb 2022 18:18:25 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 59C1F24BF4; Mon, 21 Feb 2022 15:17:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485470; x=1677021470; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=pUuimvezQ3JaPbwU/OO8a8pmkIn4yGNg2mdyK8ncgME=; b=As5pnyMj7aiyDDFfZNejLls24/ITUXcAdNdsxz+AOXGMQyT9HCgvLmXk 2BbwY19ldQNjg3khKFM2Yv/w8id6Ft4WMkAh3JBYWl0b5Gym167p717WC uJRUxkcZcSmpjOr4Ja/RUxA3Vsvu54wOQh2F9fbkecPBqCDjg9s74rGaI 7K7+RS4KGIH0wqPnVojOrGCpDfhFRws27501h75qGOdA+S9Xiu1dR4LB8 AFPwSTZ8nq4aINH2oem1rhn5o58g8jJf4222BuYp0jWBvcK30a/LSWj2N GRHMFbrLtgw5vtvwh9ssUWyCeuy9eN/suvmAhGXZ741Z/2nW1SPxuLrG8 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530404" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530404" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:50 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694479" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:47 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 4/9] lib/ref_tracker: add printing to memory buffer Date: Tue, 22 Feb 2022 00:16:52 +0100 Message-Id: <20220221231705.1481059-11-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In case one wants to show stats via debugfs. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- include/linux/ref_tracker.h | 8 ++++++ lib/ref_tracker.c | 52 ++++++++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 090230e5b485d..6d2634590ee5a 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -46,6 +46,8 @@ void __ref_tracker_dir_print(struct ref_tracker_dir *dir, void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit); =20 +int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t= size); + int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp); =20 @@ -74,6 +76,12 @@ static inline void ref_tracker_dir_print(struct ref_trac= ker_dir *dir, { } =20 +static inline int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, + char *buf, size_t size) +{ + return 0; +} + static inline int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 943cff08110e3..7b00bca300043 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -27,8 +27,27 @@ static int ref_tracker_cmp(void *priv, const struct list= _head *a, const struct l return ta->alloc_stack_handle - tb->alloc_stack_handle; } =20 -void __ref_tracker_dir_print(struct ref_tracker_dir *dir, - unsigned int display_limit) +struct ostream { + char *buf; + int size, used; +}; + +#define pr_ostream(stream, fmt, args...) \ +({ \ + struct ostream *_s =3D (stream); \ +\ + if (!_s->buf) { \ + pr_err(fmt, ##args); \ + } else { \ + int ret, len =3D _s->size - _s->used; \ + ret =3D snprintf(_s->buf + _s->used, len, pr_fmt(fmt), ##args); \ + _s->used +=3D min(ret, len); \ + } \ +}) + +static void +__ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir, + unsigned int display_limit, struct ostream *s) { unsigned int i =3D 0, count =3D 0, total =3D 0; struct ref_tracker *tracker; @@ -58,16 +77,24 @@ void __ref_tracker_dir_print(struct ref_tracker_dir *di= r, =20 if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4)) sbuf[0] =3D 0; - pr_err("%s@%pK has %d/%d users at\n%s\n", - dir->name, dir, count, total, sbuf); + pr_ostream(s, "%s@%pK has %d/%d users at\n%s\n", + dir->name, dir, count, total, sbuf); count =3D 0; } if (i > display_limit) - pr_err("%s@%pK skipped %d/%d reports with %d unique stacks.\n", - dir->name, dir, count, total, i - display_limit); + pr_ostream(s, "%s@%pK skipped %d/%d reports with %d unique stacks.\n", + dir->name, dir, count, total, i - display_limit); =20 kfree(sbuf); } + +void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ostream os =3D {}; + + __ref_tracker_dir_pr_ostream(dir, display_limit, &os); +} EXPORT_SYMBOL(__ref_tracker_dir_print); =20 void ref_tracker_dir_print(struct ref_tracker_dir *dir, @@ -81,6 +108,19 @@ void ref_tracker_dir_print(struct ref_tracker_dir *dir, } EXPORT_SYMBOL(ref_tracker_dir_print); =20 +int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t= size) +{ + struct ostream os =3D { .buf =3D buf, .size =3D size }; + unsigned long flags; + + spin_lock_irqsave(&dir->lock, flags); + __ref_tracker_dir_pr_ostream(dir, 16, &os); + spin_unlock_irqrestore(&dir->lock, flags); + + return os.used; +} +EXPORT_SYMBOL(ref_tracker_dir_snprint); + void ref_tracker_dir_exit(struct ref_tracker_dir *dir) { struct ref_tracker *tracker, *n; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8D8CFC433FE for ; Mon, 21 Feb 2022 23:18:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236360AbiBUXSt (ORCPT ); Mon, 21 Feb 2022 18:18:49 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33512 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236348AbiBUXSZ (ORCPT ); Mon, 21 Feb 2022 18:18:25 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 610CC24F06; Mon, 21 Feb 2022 15:17:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485473; x=1677021473; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=tQY4mR2KDwyrHcJb7GxZeyIMhFFAwu7Cvbv8/dkN8c0=; b=QfhJPG3XQrsENJ6Ab4usoaF9vDm5kIFUoesn62gbybpdATkTvsIlSI18 YR56q7vnmNSbzPW55sWqH8ivLCsZBHxveFpqKZbKmZzGB7yq85uqqpPGf 0xj6iX2pzb4reQ8XhnXf3beVdq+Lj7iasaJXrCNMGB8DkAYc6/rouv0il 5VH/vAqip9UxTa4F61VWFLcx4wDK6Pu6cSIUteyIq5uo/4zhc/Zzmox8n +VfmfYBE9Os+F1fiZCobzsBkYgh7Ku0gbXKeqxKGonP/zavVDkCMHPQqU nIq1IdjqXd6bD7WaVGV59O4IWhGQwP82PaFhWkSuOWdMvL8U2JKb5bO1I A==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530408" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530408" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:53 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694491" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:50 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 04/11] lib/ref_tracker: add unlocked leak print helper Date: Tue, 22 Feb 2022 00:16:53 +0100 Message-Id: <20220221231705.1481059-12-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" To have reliable detection of leaks, caller must be able to check under the= same lock both: tracked counter and the leaks. dir.lock is natural candidate for= such lock and unlocked print helper can be called with this lock taken. As a bonus we can reuse this helper in ref_tracker_dir_exit. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- include/linux/ref_tracker.h | 8 +++++ lib/ref_tracker.c | 66 +++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 9ca353ab712b5..3e9e9df2a41f5 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -36,6 +36,9 @@ static inline void ref_tracker_dir_init(struct ref_tracke= r_dir *dir, =20 void ref_tracker_dir_exit(struct ref_tracker_dir *dir); =20 +void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit); + void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit); =20 @@ -56,6 +59,11 @@ static inline void ref_tracker_dir_exit(struct ref_track= er_dir *dir) { } =20 +static inline void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ +} + static inline void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit) { diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index dc7b14aa3431e..5e9f90bbf771b 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -14,6 +14,38 @@ struct ref_tracker { depot_stack_handle_t free_stack_handle; }; =20 +void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ref_tracker *tracker; + unsigned int i =3D 0; + + lockdep_assert_held(&dir->lock); + + list_for_each_entry(tracker, &dir->list, head) { + if (i < display_limit) { + pr_err("leaked reference.\n"); + if (tracker->alloc_stack_handle) + stack_depot_print(tracker->alloc_stack_handle); + i++; + } else { + break; + } + } +} +EXPORT_SYMBOL(__ref_tracker_dir_print); + +void ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + unsigned long flags; + + spin_lock_irqsave(&dir->lock, flags); + __ref_tracker_dir_print(dir, display_limit); + spin_unlock_irqrestore(&dir->lock, flags); +} +EXPORT_SYMBOL(ref_tracker_dir_print); + void ref_tracker_dir_exit(struct ref_tracker_dir *dir) { struct ref_tracker *tracker, *n; @@ -27,13 +59,13 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) kfree(tracker); dir->quarantine_avail++; } - list_for_each_entry_safe(tracker, n, &dir->list, head) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); + if (!list_empty(&dir->list)) { + __ref_tracker_dir_print(dir, 16); leak =3D true; - list_del(&tracker->head); - kfree(tracker); + list_for_each_entry_safe(tracker, n, &dir->list, head) { + list_del(&tracker->head); + kfree(tracker); + } } spin_unlock_irqrestore(&dir->lock, flags); WARN_ON_ONCE(leak); @@ -42,28 +74,6 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) } EXPORT_SYMBOL(ref_tracker_dir_exit); =20 -void ref_tracker_dir_print(struct ref_tracker_dir *dir, - unsigned int display_limit) -{ - struct ref_tracker *tracker; - unsigned long flags; - unsigned int i =3D 0; - - spin_lock_irqsave(&dir->lock, flags); - list_for_each_entry(tracker, &dir->list, head) { - if (i < display_limit) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); - i++; - } else { - break; - } - } - spin_unlock_irqrestore(&dir->lock, flags); -} -EXPORT_SYMBOL(ref_tracker_dir_print); - int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp) --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 866BDC4332F for ; Mon, 21 Feb 2022 23:18:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236263AbiBUXSi (ORCPT ); Mon, 21 Feb 2022 18:18:38 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236370AbiBUXSZ (ORCPT ); Mon, 21 Feb 2022 18:18:25 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D76F124F16; Mon, 21 Feb 2022 15:17:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485476; x=1677021476; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mmcVCbEg/LT9UwII2j+BYuiQo6K4SH6OPf0Nj6nyyHk=; b=dJy8ppYBHg4tNF/k+o/hbmdmt/Z9aEPxbIWAVfHVtsNt0+GLHbwpQnfb GN5TWIxVlwDOj3AUBu5McN1biHEYl4MPoQ7/Uj1s/o786NSXj4+wu/PYn W2+iR1Q3R60NjIoxHy0AufdV8SSWO0G2nzcSKC1ivbj2iNRzX7DM3xa9X DIfNzUnB3yp/H9u+FzmeJEY9PQy9MCwbOEvn6hBRqZQmI/ATxMIWHPaCo vCIcMat5qRURG+ccAzERSu7xA+nkIXCZY60oWRWTLttzl+K3vb4DiCAz9 4F4fQH2z6osrrZ/eMh2vYkOHip9/SB/5QUN43JucdBprS+x4TPz67D2Pi Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530413" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530413" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:56 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694503" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:53 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 5/9] lib/ref_tracker: improve allocation flags Date: Tue, 22 Feb 2022 00:16:54 +0100 Message-Id: <20220221231705.1481059-13-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Library can be called in non-sleeping context, so it should not use __GFP_NOFAIL. Instead it should calmly handle allocation fails, for this __GFP_NOWARN has been added as well. Signed-off-by: Andrzej Hajda --- lib/ref_tracker.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 7b00bca300043..c8441ffbb058a 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -59,7 +59,7 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir, if (list_empty(&dir->list)) return; =20 - sbuf =3D kmalloc(STACK_BUF_SIZE, GFP_NOWAIT); + sbuf =3D kmalloc(STACK_BUF_SIZE, GFP_NOWAIT | __GFP_NOWARN); =20 list_for_each_entry(tracker, &dir->list, head) ++total; @@ -154,11 +154,11 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, unsigned long entries[REF_TRACKER_STACK_ENTRIES]; struct ref_tracker *tracker; unsigned int nr_entries; - gfp_t gfp_mask =3D gfp; + gfp_t gfp_mask; unsigned long flags; =20 - if (gfp & __GFP_DIRECT_RECLAIM) - gfp_mask |=3D __GFP_NOFAIL; + gfp |=3D __GFP_NOWARN; + gfp_mask =3D (gfp & __GFP_DIRECT_RECLAIM) ? (gfp | __GFP_NOFAIL) : gfp; *trackerp =3D tracker =3D kzalloc(sizeof(*tracker), gfp_mask); if (unlikely(!tracker)) { pr_err_once("memory allocation failure, unreliable refcount tracker.\n"); @@ -191,7 +191,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, } nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); nr_entries =3D filter_irq_stacks(entries, nr_entries); - stack_handle =3D stack_depot_save(entries, nr_entries, GFP_ATOMIC); + stack_handle =3D stack_depot_save(entries, nr_entries, + GFP_NOWAIT | __GFP_NOWARN); =20 spin_lock_irqsave(&dir->lock, flags); if (tracker->dead) { --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A01F3C433F5 for ; Mon, 21 Feb 2022 23:18:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231409AbiBUXSo (ORCPT ); Mon, 21 Feb 2022 18:18:44 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33558 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236418AbiBUXS0 (ORCPT ); Mon, 21 Feb 2022 18:18:26 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39C2024F26; Mon, 21 Feb 2022 15:17:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485479; x=1677021479; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=g08j7LXB1cG4K+7SmHFS/Pc2Q959AY3yWgcIbyn6GFQ=; b=ii+TO4NeXTpbVV4c7UuYcDz2LFZONXN2oo/reYKQcG3G2gYgGpb93NXH jJqtXzuYIlfuNrUFHtsvlOitpXnlM4bDJEh7ajDHAtxeLq617+WI0kzOP kZtlhLEJ1X8fvJnMlRaNFeAWoip5GR3yBLqYvNHt9eGfJdLow0qnz3W1H h30KB45IrNjS9IxFs91CsSqEH6rVwLQVgCKd9uBpQTh+r5zpmGBHFeddB Yc8H1ZAVUFZoGTb6ayofBG5G6fh+/uXLcdeS2SW/7GQ8fdExt9P5VR6sh A5HYViowChbYx3j0KNBOYf+7BYzVmwk7bU2Fwbx5DIQT1mXMDr4XYefH9 A==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530415" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530415" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:59 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694516" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:56 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 05/11] lib/ref_tracker: __ref_tracker_dir_print improve printing Date: Tue, 22 Feb 2022 00:16:55 +0100 Message-Id: <20220221231705.1481059-14-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" To improve readibility of ref_tracker printing following changes have been performed: - reports are printed per stack_handle - log is more compact, - added display name for ref_tracker_dir, - stack trace is printed indented, in the same printk call, - total number of references is printed every time, - print info about dropped references. Signed-off-by: Andrzej Hajda --- include/linux/ref_tracker.h | 15 +++++-- lib/ref_tracker.c | 90 ++++++++++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 14 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 3e9e9df2a41f5..a2cf1f6309adb 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -17,12 +17,19 @@ struct ref_tracker_dir { bool dead; struct list_head list; /* List of active trackers */ struct list_head quarantine; /* List of dead trackers */ + char name[32]; #endif }; =20 #ifdef CONFIG_REF_TRACKER -static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, - unsigned int quarantine_count) + +// Temporary allow two and three arguments, until consumers are converted +#define ref_tracker_dir_init(_d, _q, args...) _ref_tracker_dir_init(_d, _q= , ##args, #_d) +#define _ref_tracker_dir_init(_d, _q, _n, ...) __ref_tracker_dir_init(_d, = _q, _n) + +static inline void __ref_tracker_dir_init(struct ref_tracker_dir *dir, + unsigned int quarantine_count, + const char *name) { INIT_LIST_HEAD(&dir->list); INIT_LIST_HEAD(&dir->quarantine); @@ -31,6 +38,7 @@ static inline void ref_tracker_dir_init(struct ref_tracke= r_dir *dir, dir->dead =3D false; refcount_set(&dir->untracked, 1); refcount_set(&dir->no_tracker, 1); + strlcpy(dir->name, name, sizeof(dir->name)); stack_depot_init(); } =20 @@ -51,7 +59,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, #else /* CONFIG_REF_TRACKER */ =20 static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, - unsigned int quarantine_count) + unsigned int quarantine_count, + ...) { } =20 diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 5e9f90bbf771b..ab1253fde244e 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later + +#define pr_fmt(fmt) "ref_tracker: " fmt + #include +#include #include #include #include #include =20 #define REF_TRACKER_STACK_ENTRIES 16 +#define STACK_BUF_SIZE 1024 =20 struct ref_tracker { struct list_head head; /* anchor into dir->list or dir->quarantine */ @@ -14,24 +19,87 @@ struct ref_tracker { depot_stack_handle_t free_stack_handle; }; =20 -void __ref_tracker_dir_print(struct ref_tracker_dir *dir, - unsigned int display_limit) +struct ref_tracker_dir_stats { + int total; + int count; + struct { + depot_stack_handle_t stack_handle; + unsigned int count; + } stacks[]; +}; + +static struct ref_tracker_dir_stats * +ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit) { + struct ref_tracker_dir_stats *stats; struct ref_tracker *tracker; - unsigned int i =3D 0; =20 - lockdep_assert_held(&dir->lock); + stats =3D kmalloc(struct_size(stats, stacks, limit), + GFP_NOWAIT | __GFP_NOWARN); + if (!stats) + return ERR_PTR(-ENOMEM); + stats->total =3D 0; + stats->count =3D 0; =20 list_for_each_entry(tracker, &dir->list, head) { - if (i < display_limit) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); - i++; - } else { - break; + depot_stack_handle_t stack =3D tracker->alloc_stack_handle; + int i; + + ++stats->total; + for (i =3D 0; i < stats->count; ++i) + if (stats->stacks[i].stack_handle =3D=3D stack) + break; + if (i >=3D limit) + continue; + if (i >=3D stats->count) { + stats->stacks[i].stack_handle =3D stack; + stats->stacks[i].count =3D 0; + ++stats->count; } + ++stats->stacks[i].count; + } + + return stats; +} + +void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ref_tracker_dir_stats *stats; + unsigned int i =3D 0, skipped; + depot_stack_handle_t stack; + char *sbuf; + + lockdep_assert_held(&dir->lock); + + if (list_empty(&dir->list)) + return; + + stats =3D ref_tracker_get_stats(dir, display_limit); + if (IS_ERR(stats)) { + pr_err("%s@%pK: couldn't get stats, error %pe\n", + dir->name, dir, stats); + return; } + + sbuf =3D kmalloc(STACK_BUF_SIZE, GFP_NOWAIT | __GFP_NOWARN); + + for (i =3D 0, skipped =3D stats->total; i < stats->count; ++i) { + stack =3D stats->stacks[i].stack_handle; + if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4)) + sbuf[0] =3D 0; + pr_err("%s@%pK has %d/%d users at\n%s\n", dir->name, dir, + stats->stacks[i].count, stats->total, sbuf); + skipped -=3D stats->stacks[i].count; + } + + if (skipped) + pr_err("%s@%pK skipped reports about %d/%d users.\n", + dir->name, dir, skipped, stats->total); + + kfree(sbuf); + + kfree(stats); } EXPORT_SYMBOL(__ref_tracker_dir_print); =20 --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 47F18C433FE for ; Mon, 21 Feb 2022 23:18:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236594AbiBUXTB (ORCPT ); Mon, 21 Feb 2022 18:19:01 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33650 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236487AbiBUXSb (ORCPT ); Mon, 21 Feb 2022 18:18:31 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5DF8A24BFC; Mon, 21 Feb 2022 15:18:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485485; x=1677021485; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mmpDbho6EFBReIp+UJ+Rf409yBMByOTa3FwPx9dN22o=; b=au0okqs5NLhxGOVu+96uqqJ5gqW6IuVDXN9gzxnb1zXaUsimZbYteaaT XAxuv1zeZRnwKMBCtNvgUDjG9hVigHDFMU0wYn1891jVU35JpTqQzeHck +BtnTBssVW3Wo7Xy/DaL2RFsecBDffn7//XA32EcT5N55ZoopYJ7ejiR/ nj9hn78td8XUa3WCwUVHXxHr9tR/AReNo3U67dc5B+3Fjkiwf2vdaimwp lneOXsGHACFHi4azQHKkNNw9oCxmm2aUgTIsr5xIYDkYGFxQ6CG/aO2TC cpbA6kZZrdSTGMn6OyWz8gieUBrgU74jVqsZ86rvW8JmH2qfFXaCkdLFf Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530441" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530441" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:02 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694532" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:17:59 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Chris Wilson , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski , Chris Wilson Subject: [PATCH v2 6/9] drm/i915: Separate wakeref tracking Date: Tue, 22 Feb 2022 00:16:56 +0100 Message-Id: <20220221231705.1481059-15-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chris Wilson Extract the callstack tracking of intel_runtime_pm.c into its own utility so that that we can reuse it for other online debugging of scoped wakerefs. Signed-off-by: Chris Wilson Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda --- drivers/gpu/drm/i915/Kconfig.debug | 9 + drivers/gpu/drm/i915/Makefile | 4 + drivers/gpu/drm/i915/intel_runtime_pm.c | 244 +++---------------- drivers/gpu/drm/i915/intel_runtime_pm.h | 10 +- drivers/gpu/drm/i915/intel_wakeref.h | 6 +- drivers/gpu/drm/i915/intel_wakeref_tracker.c | 234 ++++++++++++++++++ drivers/gpu/drm/i915/intel_wakeref_tracker.h | 76 ++++++ 7 files changed, 355 insertions(+), 228 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.c create mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.h diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kcon= fig.debug index e7fd3e76f8a20..8b1973146e848 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -33,6 +33,7 @@ config DRM_I915_DEBUG select PREEMPT_COUNT select I2C_CHARDEV select STACKDEPOT + select STACKTRACE select DRM_DP_AUX_CHARDEV select X86_MSR # used by igt/pm_rpm select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) @@ -45,6 +46,7 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_GEM select DRM_I915_DEBUG_GEM_ONCE select DRM_I915_DEBUG_MMIO + select DRM_I915_TRACK_WAKEREF select DRM_I915_DEBUG_RUNTIME_PM select DRM_I915_SW_FENCE_DEBUG_OBJECTS select DRM_I915_SELFTEST @@ -235,11 +237,18 @@ config DRM_I915_DEBUG_VBLANK_EVADE =20 If in doubt, say "N". =20 +config DRM_I915_TRACK_WAKEREF + depends on STACKDEPOT + depends on STACKTRACE + bool + config DRM_I915_DEBUG_RUNTIME_PM bool "Enable extra state checking for runtime PM" depends on DRM_I915 default n select STACKDEPOT + select STACKTRACE + select DRM_I915_TRACK_WAKEREF help Choose this option to turn on extra state checking for the runtime PM functionality. This may introduce overhead during diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 9d588d936e3dc..88a403d3294cb 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -75,6 +75,10 @@ i915-$(CONFIG_DEBUG_FS) +=3D \ i915_debugfs_params.o \ display/intel_display_debugfs.o \ display/intel_pipe_crc.o + +i915-$(CONFIG_DRM_I915_TRACK_WAKEREF) +=3D \ + intel_wakeref_tracker.o + i915-$(CONFIG_PERF_EVENTS) +=3D i915_pmu.o =20 # "Graphics Technology" (aka we talk to the gpu) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915= /intel_runtime_pm.c index 6ed5786bcd299..7bd10efa56bf3 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -52,182 +52,37 @@ =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) =20 -#include - -#define STACKDEPTH 8 - -static noinline depot_stack_handle_t __save_depot_stack(void) -{ - unsigned long entries[STACKDEPTH]; - unsigned int n; - - n =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); -} - static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - spin_lock_init(&rpm->debug.lock); - stack_depot_init(); + intel_wakeref_tracker_init(&rpm->debug); } =20 -static noinline depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - depot_stack_handle_t stack, *stacks; - unsigned long flags; - - if (rpm->no_wakeref_tracking) - return -1; - - stack =3D __save_depot_stack(); - if (!stack) + if (!rpm->available) return -1; =20 - spin_lock_irqsave(&rpm->debug.lock, flags); - - if (!rpm->debug.count) - rpm->debug.last_acquire =3D stack; - - stacks =3D krealloc(rpm->debug.owners, - (rpm->debug.count + 1) * sizeof(*stacks), - GFP_NOWAIT | __GFP_NOWARN); - if (stacks) { - stacks[rpm->debug.count++] =3D stack; - rpm->debug.owners =3D stacks; - } else { - stack =3D -1; - } - - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - return stack; + return intel_wakeref_tracker_add(&rpm->debug); } =20 static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - depot_stack_handle_t stack) + intel_wakeref_t wakeref) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); - unsigned long flags, n; - bool found =3D false; - - if (unlikely(stack =3D=3D -1)) - return; - - spin_lock_irqsave(&rpm->debug.lock, flags); - for (n =3D rpm->debug.count; n--; ) { - if (rpm->debug.owners[n] =3D=3D stack) { - memmove(rpm->debug.owners + n, - rpm->debug.owners + n + 1, - (--rpm->debug.count - n) * sizeof(stack)); - found =3D true; - break; - } - } - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - if (drm_WARN(&i915->drm, !found, - "Unmatched wakeref (tracking %lu), count %u\n", - rpm->debug.count, atomic_read(&rpm->wakeref_count))) { - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref %x from\n%s", stack, buf); - - stack =3D READ_ONCE(rpm->debug.last_release); - if (stack) { - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref last released at\n%s", buf); - } - - kfree(buf); - } + intel_wakeref_tracker_remove(&rpm->debug, wakeref); } =20 -static int cmphandle(const void *_a, const void *_b) +static void untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm = *rpm) { - const depot_stack_handle_t * const a =3D _a, * const b =3D _b; + struct drm_printer p =3D drm_debug_printer("i915"); =20 - if (*a < *b) - return -1; - else if (*a > *b) - return 1; - else - return 0; -} - -static void -__print_intel_runtime_pm_wakeref(struct drm_printer *p, - const struct intel_runtime_pm_debug *dbg) -{ - unsigned long i; - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - if (dbg->last_acquire) { - stack_depot_snprint(dbg->last_acquire, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last acquired:\n%s", buf); - } - - if (dbg->last_release) { - stack_depot_snprint(dbg->last_release, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last released:\n%s", buf); - } - - drm_printf(p, "Wakeref count: %lu\n", dbg->count); - - sort(dbg->owners, dbg->count, sizeof(*dbg->owners), cmphandle, NULL); - - for (i =3D 0; i < dbg->count; i++) { - depot_stack_handle_t stack =3D dbg->owners[i]; - unsigned long rep; - - rep =3D 1; - while (i + 1 < dbg->count && dbg->owners[i + 1] =3D=3D stack) - rep++, i++; - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); - } - - kfree(buf); -} - -static noinline void -__untrack_all_wakerefs(struct intel_runtime_pm_debug *debug, - struct intel_runtime_pm_debug *saved) -{ - *saved =3D *debug; - - debug->owners =3D NULL; - debug->count =3D 0; - debug->last_release =3D __save_depot_stack(); -} - -static void -dump_and_free_wakeref_tracking(struct intel_runtime_pm_debug *debug) -{ - if (debug->count) { - struct drm_printer p =3D drm_debug_printer("i915"); - - __print_intel_runtime_pm_wakeref(&p, debug); - } - - kfree(debug->owners); + intel_wakeref_tracker_reset(&rpm->debug, &p); } =20 static noinline void __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) { - struct intel_runtime_pm_debug dbg =3D {}; + struct intel_wakeref_tracker saved; unsigned long flags; =20 if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count, @@ -235,60 +90,21 @@ __intel_wakeref_dec_and_check_tracking(struct intel_ru= ntime_pm *rpm) flags)) return; =20 - __untrack_all_wakerefs(&rpm->debug, &dbg); + saved =3D __intel_wakeref_tracker_reset(&rpm->debug); spin_unlock_irqrestore(&rpm->debug.lock, flags); =20 - dump_and_free_wakeref_tracking(&dbg); -} - -static noinline void -untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) -{ - struct intel_runtime_pm_debug dbg =3D {}; - unsigned long flags; - - spin_lock_irqsave(&rpm->debug.lock, flags); - __untrack_all_wakerefs(&rpm->debug, &dbg); - spin_unlock_irqrestore(&rpm->debug.lock, flags); + if (saved.count) { + struct drm_printer p =3D drm_debug_printer("i915"); =20 - dump_and_free_wakeref_tracking(&dbg); + __intel_wakeref_tracker_show(&saved, &p); + intel_wakeref_tracker_fini(&saved); + } } =20 void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, struct drm_printer *p) { - struct intel_runtime_pm_debug dbg =3D {}; - - do { - unsigned long alloc =3D dbg.count; - depot_stack_handle_t *s; - - spin_lock_irq(&rpm->debug.lock); - dbg.count =3D rpm->debug.count; - if (dbg.count <=3D alloc) { - memcpy(dbg.owners, - rpm->debug.owners, - dbg.count * sizeof(*s)); - } - dbg.last_acquire =3D rpm->debug.last_acquire; - dbg.last_release =3D rpm->debug.last_release; - spin_unlock_irq(&rpm->debug.lock); - if (dbg.count <=3D alloc) - break; - - s =3D krealloc(dbg.owners, - dbg.count * sizeof(*s), - GFP_NOWAIT | __GFP_NOWARN); - if (!s) - goto out; - - dbg.owners =3D s; - } while (1); - - __print_intel_runtime_pm_wakeref(p, &dbg); - -out: - kfree(dbg.owners); + intel_wakeref_tracker_show(&rpm->debug, p); } =20 #else @@ -297,14 +113,14 @@ static void init_intel_runtime_pm_wakeref(struct inte= l_runtime_pm *rpm) { } =20 -static depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { return -1; } =20 static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - intel_wakeref_t wref) + intel_wakeref_t wakeref) { } =20 @@ -349,9 +165,8 @@ intel_runtime_pm_release(struct intel_runtime_pm *rpm, = int wakelock) static intel_wakeref_t __intel_runtime_pm_get(struct intel_runtime_pm *rpm, bool wakelock) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); int ret; =20 ret =3D pm_runtime_get_sync(rpm->kdev); @@ -556,9 +371,8 @@ void intel_runtime_pm_put(struct intel_runtime_pm *rpm,= intel_wakeref_t wref) */ void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); struct device *kdev =3D rpm->kdev; =20 /* @@ -604,9 +418,8 @@ void intel_runtime_pm_enable(struct intel_runtime_pm *r= pm) =20 void intel_runtime_pm_disable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); struct device *kdev =3D rpm->kdev; =20 /* Transfer rpm ownership back to core */ @@ -621,9 +434,8 @@ void intel_runtime_pm_disable(struct intel_runtime_pm *= rpm) =20 void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); int count =3D atomic_read(&rpm->wakeref_count); =20 drm_WARN(&i915->drm, count, @@ -637,7 +449,7 @@ void intel_runtime_pm_driver_release(struct intel_runti= me_pm *rpm) void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) { struct drm_i915_private *i915 =3D - container_of(rpm, struct drm_i915_private, runtime_pm); + container_of(rpm, struct drm_i915_private, runtime_pm); struct pci_dev *pdev =3D to_pci_dev(i915->drm.dev); struct device *kdev =3D &pdev->dev; =20 diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915= /intel_runtime_pm.h index d9160e3ff4afc..0871fa2176474 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -61,15 +61,7 @@ struct intel_runtime_pm { * paired rpm_put) we can remove corresponding pairs of and keep * the array trimmed to active wakerefs. */ - struct intel_runtime_pm_debug { - spinlock_t lock; - - depot_stack_handle_t last_acquire; - depot_stack_handle_t last_release; - - depot_stack_handle_t *owners; - unsigned long count; - } debug; + struct intel_wakeref_tracker debug; #endif }; =20 diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/in= tel_wakeref.h index 4f4c2e15e736e..e6ba389652d74 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -17,7 +17,9 @@ #include #include =20 -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) +#include "intel_wakeref_tracker.h" + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) #else #define INTEL_WAKEREF_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) @@ -26,8 +28,6 @@ struct intel_runtime_pm; struct intel_wakeref; =20 -typedef depot_stack_handle_t intel_wakeref_t; - struct intel_wakeref_ops { int (*get)(struct intel_wakeref *wf); int (*put)(struct intel_wakeref *wf); diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.c b/drivers/gpu/drm= /i915/intel_wakeref_tracker.c new file mode 100644 index 0000000000000..a0bcef13a1085 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_wakeref_tracker.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright =C2=A9 2021 Intel Corporation + */ + +#include +#include +#include +#include + +#include + +#include "intel_wakeref.h" + +#define STACKDEPTH 8 + +static noinline depot_stack_handle_t __save_depot_stack(void) +{ + unsigned long entries[STACKDEPTH]; + unsigned int n; + + n =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); + return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); +} + +static void __print_depot_stack(depot_stack_handle_t stack, + char *buf, int sz, int indent) +{ + unsigned long *entries; + unsigned int nr_entries; + + nr_entries =3D stack_depot_fetch(stack, &entries); + stack_trace_snprint(buf, sz, entries, nr_entries, indent); +} + +static int cmphandle(const void *_a, const void *_b) +{ + const depot_stack_handle_t * const a =3D _a, * const b =3D _b; + + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else + return 0; +} + +void +__intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, + struct drm_printer *p) +{ + unsigned long i; + char *buf; + + buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); + if (!buf) + return; + + if (w->last_acquire) { + __print_depot_stack(w->last_acquire, buf, PAGE_SIZE, 2); + drm_printf(p, "Wakeref last acquired:\n%s", buf); + } + + if (w->last_release) { + __print_depot_stack(w->last_release, buf, PAGE_SIZE, 2); + drm_printf(p, "Wakeref last released:\n%s", buf); + } + + drm_printf(p, "Wakeref count: %lu\n", w->count); + + sort(w->owners, w->count, sizeof(*w->owners), cmphandle, NULL); + + for (i =3D 0; i < w->count; i++) { + depot_stack_handle_t stack =3D w->owners[i]; + unsigned long rep; + + rep =3D 1; + while (i + 1 < w->count && w->owners[i + 1] =3D=3D stack) + rep++, i++; + __print_depot_stack(stack, buf, PAGE_SIZE, 2); + drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); + } + + kfree(buf); +} + +void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, + struct drm_printer *p) +{ + struct intel_wakeref_tracker tmp =3D {}; + + do { + unsigned long alloc =3D tmp.count; + depot_stack_handle_t *s; + + spin_lock_irq(&w->lock); + tmp.count =3D w->count; + if (tmp.count <=3D alloc) + memcpy(tmp.owners, w->owners, tmp.count * sizeof(*s)); + tmp.last_acquire =3D w->last_acquire; + tmp.last_release =3D w->last_release; + spin_unlock_irq(&w->lock); + if (tmp.count <=3D alloc) + break; + + s =3D krealloc(tmp.owners, + tmp.count * sizeof(*s), + GFP_NOWAIT | __GFP_NOWARN); + if (!s) + goto out; + + tmp.owners =3D s; + } while (1); + + __intel_wakeref_tracker_show(&tmp, p); + +out: + intel_wakeref_tracker_fini(&tmp); +} + +intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) +{ + depot_stack_handle_t stack, *stacks; + unsigned long flags; + + stack =3D __save_depot_stack(); + if (!stack) + return -1; + + spin_lock_irqsave(&w->lock, flags); + + if (!w->count) + w->last_acquire =3D stack; + + stacks =3D krealloc(w->owners, + (w->count + 1) * sizeof(*stacks), + GFP_NOWAIT | __GFP_NOWARN); + if (stacks) { + stacks[w->count++] =3D stack; + w->owners =3D stacks; + } else { + stack =3D -1; + } + + spin_unlock_irqrestore(&w->lock, flags); + + return stack; +} + +void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, + intel_wakeref_t stack) +{ + unsigned long flags, n; + bool found =3D false; + + if (unlikely(stack =3D=3D -1)) + return; + + spin_lock_irqsave(&w->lock, flags); + for (n =3D w->count; n--; ) { + if (w->owners[n] =3D=3D stack) { + memmove(w->owners + n, + w->owners + n + 1, + (--w->count - n) * sizeof(stack)); + found =3D true; + break; + } + } + spin_unlock_irqrestore(&w->lock, flags); + + if (WARN(!found, + "Unmatched wakeref %x, tracking %lu\n", + stack, w->count)) { + char *buf; + + buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); + if (!buf) + return; + + __print_depot_stack(stack, buf, PAGE_SIZE, 2); + pr_err("wakeref %x from\n%s", stack, buf); + + stack =3D READ_ONCE(w->last_release); + if (stack && !w->count) { + __print_depot_stack(stack, buf, PAGE_SIZE, 2); + pr_err("wakeref last released at\n%s", buf); + } + + kfree(buf); + } +} + +struct intel_wakeref_tracker +__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) +{ + struct intel_wakeref_tracker saved; + + lockdep_assert_held(&w->lock); + + saved =3D *w; + + w->owners =3D NULL; + w->count =3D 0; + w->last_release =3D __save_depot_stack(); + + return saved; +} + +void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, + struct drm_printer *p) +{ + struct intel_wakeref_tracker tmp; + + spin_lock_irq(&w->lock); + tmp =3D __intel_wakeref_tracker_reset(w); + spin_unlock_irq(&w->lock); + + if (tmp.count) + __intel_wakeref_tracker_show(&tmp, p); + + intel_wakeref_tracker_fini(&tmp); +} + +void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w) +{ + memset(w, 0, sizeof(*w)); + spin_lock_init(&w->lock); + stack_depot_init(); +} + +void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w) +{ + kfree(w->owners); +} diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.h b/drivers/gpu/drm= /i915/intel_wakeref_tracker.h new file mode 100644 index 0000000000000..61df68e28c0fb --- /dev/null +++ b/drivers/gpu/drm/i915/intel_wakeref_tracker.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright =C2=A9 2019 Intel Corporation + */ + +#ifndef INTEL_WAKEREF_TRACKER_H +#define INTEL_WAKEREF_TRACKER_H + +#include +#include +#include + +typedef depot_stack_handle_t intel_wakeref_t; + +struct drm_printer; + +struct intel_wakeref_tracker { + spinlock_t lock; + + depot_stack_handle_t last_acquire; + depot_stack_handle_t last_release; + + depot_stack_handle_t *owners; + unsigned long count; +}; + +#if IS_ENABLED(CONFIG_DRM_I915_TRACK_WAKEREF) + +void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w); +void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w); + +intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w); +void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, + intel_wakeref_t handle); + +struct intel_wakeref_tracker +__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w); +void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, + struct drm_printer *p); + +void __intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, + struct drm_printer *p); +void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, + struct drm_printer *p); + +#else + +static inline void intel_wakeref_tracker_init(struct intel_wakeref_tracker= *w) {} +static inline void intel_wakeref_tracker_fini(struct intel_wakeref_tracker= *w) {} + +static inline intel_wakeref_t +intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) +{ + return -1; +} + +static inline void +intel_wakeref_untrack_remove(struct intel_wakeref_tracker *w, intel_wakere= f_t handle) {} + +static inline struct intel_wakeref_tracker +__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) +{ + return (struct intel_wakeref_tracker){}; +} + +static inline void intel_wakeref_tracker_reset(struct intel_wakeref_tracke= r *w, + struct drm_printer *p) +{ +} + +static inline void __intel_wakeref_tracker_show(const struct intel_wakeref= _tracker *w, struct drm_printer *p) {} +static inline void intel_wakeref_tracker_show(struct intel_wakeref_tracker= *w, struct drm_printer *p) {} + +#endif + +#endif /* INTEL_WAKEREF_TRACKER_H */ --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 18008C433EF for ; Mon, 21 Feb 2022 23:18:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236583AbiBUXS5 (ORCPT ); Mon, 21 Feb 2022 18:18:57 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236488AbiBUXSb (ORCPT ); Mon, 21 Feb 2022 18:18:31 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0A90624F0A; Mon, 21 Feb 2022 15:18:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485486; x=1677021486; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yBcBvjJ/VepSDsCpwUwjixNuXeR4oixpM4h2duuH8BA=; b=EKhMYs83K7pNBYzT2/qbZpdD7m2S3okxSx3yy6btuFCcNpc2usTmMKuM 2ot/2jaBId0vCUpjIZosAG0tVKvU3dknbXw5sLFvgpGUF0NtQMcGI3CjO 6O52l+mG2M5fe9fNtHGYZOPoI77iohOQY17iFA1r9XAw9jIxHqBlO9bEK 8gDWz1C2GL14qJumkh/i3TpDhkgbgLvMBMqNNsE4MaqAk9WvExSINgHt1 62vTW0SUvEwNl2xMa3nay7dYJzU4qbKgknuu3TiKz2QSV65pxqZysh+Ua UF2+cqFTK3bf99GwQ88h0fVYIzgO05gMhtdeKyMPVPRQmNLq8XYdTNBQj g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530444" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530444" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:05 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694547" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:02 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 06/11] lib/ref_tracker: add printing to memory buffer Date: Tue, 22 Feb 2022 00:16:57 +0100 Message-Id: <20220221231705.1481059-16-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In case one wants to show stats via debugfs. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- include/linux/ref_tracker.h | 8 ++++++ lib/ref_tracker.c | 56 +++++++++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index a2cf1f6309adb..2fdbfd2e14797 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -50,6 +50,8 @@ void __ref_tracker_dir_print(struct ref_tracker_dir *dir, void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit); =20 +int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t= size); + int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp); =20 @@ -78,6 +80,12 @@ static inline void ref_tracker_dir_print(struct ref_trac= ker_dir *dir, { } =20 +static inline int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, + char *buf, size_t size) +{ + return 0; +} + static inline int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index ab1253fde244e..2ef4596b6b36f 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -62,8 +62,27 @@ ref_tracker_get_stats(struct ref_tracker_dir *dir, unsig= ned int limit) return stats; } =20 -void __ref_tracker_dir_print(struct ref_tracker_dir *dir, - unsigned int display_limit) +struct ostream { + char *buf; + int size, used; +}; + +#define pr_ostream(stream, fmt, args...) \ +({ \ + struct ostream *_s =3D (stream); \ +\ + if (!_s->buf) { \ + pr_err(fmt, ##args); \ + } else { \ + int ret, len =3D _s->size - _s->used; \ + ret =3D snprintf(_s->buf + _s->used, len, pr_fmt(fmt), ##args); \ + _s->used +=3D min(ret, len); \ + } \ +}) + +static void +__ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir, + unsigned int display_limit, struct ostream *s) { struct ref_tracker_dir_stats *stats; unsigned int i =3D 0, skipped; @@ -77,8 +96,8 @@ void __ref_tracker_dir_print(struct ref_tracker_dir *dir, =20 stats =3D ref_tracker_get_stats(dir, display_limit); if (IS_ERR(stats)) { - pr_err("%s@%pK: couldn't get stats, error %pe\n", - dir->name, dir, stats); + pr_ostream(s, "%s@%pK: couldn't get stats, error %pe\n", + dir->name, dir, stats); return; } =20 @@ -88,19 +107,27 @@ void __ref_tracker_dir_print(struct ref_tracker_dir *d= ir, stack =3D stats->stacks[i].stack_handle; if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4)) sbuf[0] =3D 0; - pr_err("%s@%pK has %d/%d users at\n%s\n", dir->name, dir, - stats->stacks[i].count, stats->total, sbuf); + pr_ostream(s, "%s@%pK has %d/%d users at\n%s\n", dir->name, dir, + stats->stacks[i].count, stats->total, sbuf); skipped -=3D stats->stacks[i].count; } =20 if (skipped) - pr_err("%s@%pK skipped reports about %d/%d users.\n", - dir->name, dir, skipped, stats->total); + pr_ostream(s, "%s@%pK skipped reports about %d/%d users.\n", + dir->name, dir, skipped, stats->total); =20 kfree(sbuf); =20 kfree(stats); } + +void __ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ostream os =3D {}; + + __ref_tracker_dir_pr_ostream(dir, display_limit, &os); +} EXPORT_SYMBOL(__ref_tracker_dir_print); =20 void ref_tracker_dir_print(struct ref_tracker_dir *dir, @@ -114,6 +141,19 @@ void ref_tracker_dir_print(struct ref_tracker_dir *dir, } EXPORT_SYMBOL(ref_tracker_dir_print); =20 +int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t= size) +{ + struct ostream os =3D { .buf =3D buf, .size =3D size }; + unsigned long flags; + + spin_lock_irqsave(&dir->lock, flags); + __ref_tracker_dir_pr_ostream(dir, 16, &os); + spin_unlock_irqrestore(&dir->lock, flags); + + return os.used; +} +EXPORT_SYMBOL(ref_tracker_dir_snprint); + void ref_tracker_dir_exit(struct ref_tracker_dir *dir) { struct ref_tracker *tracker, *n; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D037C433EF for ; Mon, 21 Feb 2022 23:18:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236414AbiBUXTF (ORCPT ); Mon, 21 Feb 2022 18:19:05 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:34016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236304AbiBUXSg (ORCPT ); Mon, 21 Feb 2022 18:18:36 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7AFE924BE0; Mon, 21 Feb 2022 15:18:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485489; x=1677021489; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qlFqLRfrfrx4mNRF6vVIBqvEiaofH2gyPUSV1nRx1WA=; b=YoBpEHZ3ryqadGDlR5NPfuSioiQVjVZKPkASohIpV3BvtqVNNrQ0dCyJ qy6EHg1hQKeM82os3e31cCOlxWQzMAIYstuErzFCQj4i4wL91hPHAc8ig O7o3SANKLqss2NBPRqxnvPeqYyxwyzsnel0+9t8LneJ1idHkH+F+SP+jL Xsm7fPKgu6AVM+21idTbstO8bFD+V0ChNE4yUAlq/kmamZF8vnWPOARDL t9R3MkoMsVbksKszuweCPLiUqsyODHQG9pW17fpgi/rddMollUDURcgYv zlsAoyoeM10vdL/wYZynxSTguWiq28ExVcrO7Px6CJvMy3W+EFbLO+NgP g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530449" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530449" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:09 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694559" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:05 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Chris Wilson , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 7/9] drm/i915: Track leaked gt->wakerefs Date: Tue, 22 Feb 2022 00:16:58 +0100 Message-Id: <20220221231705.1481059-17-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Chris Wilson Track every intel_gt_pm_get() until its corresponding release in intel_gt_pm_put() by returning a cookie to the caller for acquire that must be passed by on rleased. When there is an imbalance, we can see who either tried to free a stale wakeref, or who forgot to free theirs. v2: Rebase from backporting wakeref leak (Umesh) Signed-off-by: Chris Wilson Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda --- drivers/gpu/drm/i915/Kconfig.debug | 15 +++++++ .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 7 ++-- .../i915/gem/selftests/i915_gem_coherency.c | 10 +++-- .../drm/i915/gem/selftests/i915_gem_mman.c | 14 ++++--- drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 13 ++++-- .../gpu/drm/i915/gt/intel_breadcrumbs_types.h | 3 +- drivers/gpu/drm/i915/gt/intel_engine_pm.c | 4 +- drivers/gpu/drm/i915/gt/intel_engine_types.h | 2 + .../drm/i915/gt/intel_execlists_submission.c | 2 +- drivers/gpu/drm/i915/gt/intel_gt_pm.c | 10 +++-- drivers/gpu/drm/i915/gt/intel_gt_pm.h | 36 ++++++++++++---- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 4 +- drivers/gpu/drm/i915/gt/selftest_engine_cs.c | 20 +++++---- drivers/gpu/drm/i915/gt/selftest_gt_pm.c | 5 ++- drivers/gpu/drm/i915/gt/selftest_reset.c | 10 +++-- drivers/gpu/drm/i915/gt/selftest_rps.c | 17 ++++---- drivers/gpu/drm/i915/gt/selftest_slpc.c | 10 +++-- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 9 ++-- drivers/gpu/drm/i915/i915_pmu.c | 16 +++---- drivers/gpu/drm/i915/intel_wakeref.c | 4 ++ drivers/gpu/drm/i915/intel_wakeref.h | 42 +++++++++++++++++++ 21 files changed, 182 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kcon= fig.debug index 8b1973146e848..3bdc73f30a9e1 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -48,6 +48,7 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_MMIO select DRM_I915_TRACK_WAKEREF select DRM_I915_DEBUG_RUNTIME_PM + select DRM_I915_DEBUG_WAKEREF select DRM_I915_SW_FENCE_DEBUG_OBJECTS select DRM_I915_SELFTEST select BROKEN # for prototype uAPI @@ -257,3 +258,17 @@ config DRM_I915_DEBUG_RUNTIME_PM Recommended for driver developers only. =20 If in doubt, say "N" + +config DRM_I915_DEBUG_WAKEREF + bool "Enable extra tracking for wakerefs" + depends on DRM_I915 + default n + select STACKDEPOT + select STACKTRACE + select DRM_I915_TRACK_WAKEREF + help + Choose this option to turn on extra state checking and usage + tracking for the wakerefPM functionality. This may introduce + overhead during driver runtime. + + If in doubt, say "N" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/d= rm/i915/gem/i915_gem_execbuffer.c index 13c975da77474..4b6c144f706da 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -252,6 +252,7 @@ struct i915_execbuffer { struct intel_gt *gt; /* gt for the execbuf */ struct intel_context *context; /* logical state for the request */ struct i915_gem_context *gem_context; /** caller's context */ + intel_wakeref_t wakeref; =20 /** our requests to build */ struct i915_request *requests[MAX_ENGINE_INSTANCE + 1]; @@ -2679,7 +2680,7 @@ eb_select_engine(struct i915_execbuffer *eb) =20 for_each_child(ce, child) intel_context_get(child); - intel_gt_pm_get(ce->engine->gt); + eb->wakeref =3D intel_gt_pm_get(ce->engine->gt); =20 if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) { err =3D intel_context_alloc_state(ce); @@ -2713,7 +2714,7 @@ eb_select_engine(struct i915_execbuffer *eb) return err; =20 err: - intel_gt_pm_put(ce->engine->gt); + intel_gt_pm_put(ce->engine->gt, eb->wakeref); for_each_child(ce, child) intel_context_put(child); intel_context_put(ce); @@ -2725,7 +2726,7 @@ eb_put_engine(struct i915_execbuffer *eb) { struct intel_context *child; =20 - intel_gt_pm_put(eb->gt); + intel_gt_pm_put(eb->context->engine->gt, eb->wakeref); for_each_child(eb->context, child) intel_context_put(child); intel_context_put(eb->context); diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c b/driv= ers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c index 13b088cc787eb..553f2730c2a76 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c @@ -85,6 +85,7 @@ static int cpu_get(struct context *ctx, unsigned long off= set, u32 *v) =20 static int gtt_set(struct context *ctx, unsigned long offset, u32 v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err =3D 0; @@ -99,7 +100,7 @@ static int gtt_set(struct context *ctx, unsigned long of= fset, u32 v) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); =20 map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -112,12 +113,13 @@ static int gtt_set(struct context *ctx, unsigned long= offset, u32 v) i915_vma_unpin_iomap(vma); =20 out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err =3D 0; @@ -132,7 +134,7 @@ static int gtt_get(struct context *ctx, unsigned long o= ffset, u32 *v) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); =20 map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -145,7 +147,7 @@ static int gtt_get(struct context *ctx, unsigned long o= ffset, u32 *v) i915_vma_unpin_iomap(vma); =20 out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/g= pu/drm/i915/gem/selftests/i915_gem_mman.c index 8ae1a1530bd80..dea5e8e39ab2d 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -624,14 +624,14 @@ static bool assert_mmap_offset(struct drm_i915_privat= e *i915, static void disable_retire_worker(struct drm_i915_private *i915) { i915_gem_driver_unregister__shrinker(i915); - intel_gt_pm_get(to_gt(i915)); + intel_gt_pm_get_untracked(to_gt(i915)); cancel_delayed_work_sync(&to_gt(i915)->requests.retire_work); } =20 static void restore_retire_worker(struct drm_i915_private *i915) { igt_flush_test(i915); - intel_gt_pm_put(to_gt(i915)); + intel_gt_pm_put_untracked(to_gt(i915)); i915_gem_driver_register__shrinker(i915); } =20 @@ -772,6 +772,7 @@ static int igt_mmap_offset_exhaustion(void *arg) =20 static int gtt_set(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err =3D 0; @@ -780,7 +781,7 @@ static int gtt_set(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -792,12 +793,13 @@ static int gtt_set(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); =20 out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 static int gtt_check(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err =3D 0; @@ -806,7 +808,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -822,7 +824,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); =20 out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/= i915/gt/intel_breadcrumbs.c index 209cf265bf746..f061d93c27357 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -27,11 +27,14 @@ static void irq_disable(struct intel_breadcrumbs *b) =20 static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref; + /* * Since we are waiting on a request, the GPU should be busy * and should have its own rpm reference. */ - if (GEM_WARN_ON(!intel_gt_pm_get_if_awake(b->irq_engine->gt))) + wakeref =3D intel_gt_pm_get_if_awake(b->irq_engine->gt); + if (GEM_WARN_ON(!wakeref)) return; =20 /* @@ -40,7 +43,7 @@ static void __intel_breadcrumbs_arm_irq(struct intel_brea= dcrumbs *b) * which we can add a new waiter and avoid the cost of re-enabling * the irq. */ - WRITE_ONCE(b->irq_armed, true); + WRITE_ONCE(b->irq_armed, wakeref); =20 /* Requests may have completed before we could enable the interrupt. */ if (!b->irq_enabled++ && b->irq_enable(b)) @@ -60,12 +63,14 @@ static void intel_breadcrumbs_arm_irq(struct intel_brea= dcrumbs *b) =20 static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref =3D b->irq_armed; + GEM_BUG_ON(!b->irq_enabled); if (!--b->irq_enabled) b->irq_disable(b); =20 - WRITE_ONCE(b->irq_armed, false); - intel_gt_pm_put_async(b->irq_engine->gt); + WRITE_ONCE(b->irq_armed, 0); + intel_gt_pm_put_async(b->irq_engine->gt, wakeref); } =20 static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h b/drivers/gp= u/drm/i915/gt/intel_breadcrumbs_types.h index 72dfd3748c4c3..bdf09fd67b6e7 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h @@ -13,6 +13,7 @@ #include =20 #include "intel_engine_types.h" +#include "intel_wakeref.h" =20 /* * Rather than have every client wait upon all user interrupts, @@ -43,7 +44,7 @@ struct intel_breadcrumbs { spinlock_t irq_lock; /* protects the interrupt from hardirq context */ struct irq_work irq_work; /* for use from inside irq_lock */ unsigned int irq_enabled; - bool irq_armed; + intel_wakeref_t irq_armed; =20 /* Not all breadcrumbs are attached to physical HW */ intel_engine_mask_t engine_mask; diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i9= 15/gt/intel_engine_pm.c index b0a4a2dbe3ee9..52e46e7830ff5 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -47,7 +47,7 @@ static int __engine_unpark(struct intel_wakeref *wf) =20 ENGINE_TRACE(engine, "\n"); =20 - intel_gt_pm_get(engine->gt); + engine->wakeref_track =3D intel_gt_pm_get(engine->gt); =20 /* Discard stale context state from across idling */ ce =3D engine->kernel_context; @@ -260,7 +260,7 @@ static int __engine_park(struct intel_wakeref *wf) engine->park(engine); =20 /* While gt calls i915_vma_parked(), we have to break the lock cycle */ - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async(engine->gt, engine->wakeref_track); return 0; } =20 diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm= /i915/gt/intel_engine_types.h index 36365bdbe1ee7..dcd84d1eb90b7 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -382,7 +382,9 @@ struct intel_engine_cs { unsigned long serial; =20 unsigned long wakeref_serial; + intel_wakeref_t wakeref_track; struct intel_wakeref wakeref; + struct file *default_state; =20 struct { diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers= /gpu/drm/i915/gt/intel_execlists_submission.c index 961d795220a30..4ff269b2697d5 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -630,7 +630,7 @@ static void __execlists_schedule_out(struct i915_reques= t * const rq, execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT); if (engine->fw_domain && !--engine->fw_active) intel_uncore_forcewake_put(engine->uncore, engine->fw_domain); - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async_untracked(engine->gt); =20 /* * If this is part of a virtual engine, its next request may diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/g= t/intel_gt_pm.c index c0fa41e4c8030..7ee65a93f926f 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -25,19 +25,20 @@ static void user_forcewake(struct intel_gt *gt, bool suspend) { int count =3D atomic_read(>->user_wakeref); + intel_wakeref_t wakeref; =20 /* Inside suspend/resume so single threaded, no races to worry about. */ if (likely(!count)) return; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); if (suspend) { GEM_BUG_ON(count > atomic_read(>->wakeref.count)); atomic_sub(count, >->wakeref.count); } else { atomic_add(count, >->wakeref.count); } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); } =20 static void runtime_begin(struct intel_gt *gt) @@ -210,6 +211,7 @@ int intel_gt_resume(struct intel_gt *gt) { struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err; =20 err =3D intel_gt_has_unrecoverable_error(gt); @@ -226,7 +228,7 @@ int intel_gt_resume(struct intel_gt *gt) */ gt_sanitize(gt, true); =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); =20 intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); intel_rc6_sanitize(>->rc6); @@ -273,7 +275,7 @@ int intel_gt_resume(struct intel_gt *gt) =20 out_fw: intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; =20 err_wedged: diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/g= t/intel_gt_pm.h index bc898df7a48cc..3ab06d897df25 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h @@ -16,19 +16,28 @@ static inline bool intel_gt_pm_is_awake(const struct in= tel_gt *gt) return intel_wakeref_is_active(>->wakeref); } =20 -static inline void intel_gt_pm_get(struct intel_gt *gt) +static inline void intel_gt_pm_get_untracked(struct intel_gt *gt) { intel_wakeref_get(>->wakeref); } =20 +static inline intel_wakeref_t intel_gt_pm_get(struct intel_gt *gt) +{ + intel_gt_pm_get_untracked(gt); + return intel_wakeref_track(>->wakeref); +} + static inline void __intel_gt_pm_get(struct intel_gt *gt) { __intel_wakeref_get(>->wakeref); } =20 -static inline bool intel_gt_pm_get_if_awake(struct intel_gt *gt) +static inline intel_wakeref_t intel_gt_pm_get_if_awake(struct intel_gt *gt) { - return intel_wakeref_get_if_active(>->wakeref); + if (!intel_wakeref_get_if_active(>->wakeref)) + return 0; + + return intel_wakeref_track(>->wakeref); } =20 static inline void intel_gt_pm_might_get(struct intel_gt *gt) @@ -36,12 +45,18 @@ static inline void intel_gt_pm_might_get(struct intel_g= t *gt) intel_wakeref_might_get(>->wakeref); } =20 -static inline void intel_gt_pm_put(struct intel_gt *gt) +static inline void intel_gt_pm_put_untracked(struct intel_gt *gt) { intel_wakeref_put(>->wakeref); } =20 -static inline void intel_gt_pm_put_async(struct intel_gt *gt) +static inline void intel_gt_pm_put(struct intel_gt *gt, intel_wakeref_t ha= ndle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_untracked(gt); +} + +static inline void intel_gt_pm_put_async_untracked(struct intel_gt *gt) { intel_wakeref_put_async(>->wakeref); } @@ -51,9 +66,14 @@ static inline void intel_gt_pm_might_put(struct intel_gt= *gt) intel_wakeref_might_put(>->wakeref); } =20 -#define with_intel_gt_pm(gt, tmp) \ - for (tmp =3D 1, intel_gt_pm_get(gt); tmp; \ - intel_gt_pm_put(gt), tmp =3D 0) +static inline void intel_gt_pm_put_async(struct intel_gt *gt, intel_wakere= f_t handle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_async_untracked(gt); +} + +#define with_intel_gt_pm(gt, wf) \ + for (wf =3D intel_gt_pm_get(gt); wf; intel_gt_pm_put(gt, wf), wf =3D 0) =20 static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt) { diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/dr= m/i915/gt/intel_gt_pm_debugfs.c index 37765919fe322..e02a3e26e0d02 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -26,7 +26,7 @@ int intel_gt_pm_debugfs_forcewake_user_open(struct intel_gt *gt) { atomic_inc(>->user_wakeref); - intel_gt_pm_get(gt); + intel_gt_pm_get_untracked(gt); if (GRAPHICS_VER(gt->i915) >=3D 6) intel_uncore_forcewake_user_get(gt->uncore); =20 @@ -37,7 +37,7 @@ int intel_gt_pm_debugfs_forcewake_user_release(struct int= el_gt *gt) { if (GRAPHICS_VER(gt->i915) >=3D 6) intel_uncore_forcewake_user_put(gt->uncore); - intel_gt_pm_put(gt); + intel_gt_pm_put_untracked(gt); atomic_dec(>->user_wakeref); =20 return 0; diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm= /i915/gt/selftest_engine_cs.c index 1b75f478d1b83..8ea6bf4c987e2 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c @@ -21,20 +21,22 @@ static int cmp_u32(const void *A, const void *B) return *a - *b; } =20 -static void perf_begin(struct intel_gt *gt) +static intel_wakeref_t perf_begin(struct intel_gt *gt) { - intel_gt_pm_get(gt); + intel_wakeref_t wakeref =3D intel_gt_pm_get(gt); =20 /* Boost gpufreq to max [waitboost] and keep it fixed */ atomic_inc(>->rps.num_waiters); schedule_work(>->rps.work); flush_work(>->rps.work); + + return wakeref; } =20 -static int perf_end(struct intel_gt *gt) +static int perf_end(struct intel_gt *gt, intel_wakeref_t wakeref) { atomic_dec(>->rps.num_waiters); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return igt_flush_test(gt->i915); } @@ -123,12 +125,13 @@ static int perf_mi_bb_start(void *arg) struct intel_gt *gt =3D arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */ return 0; =20 - perf_begin(gt); + wakeref =3D perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce =3D engine->kernel_context; struct i915_vma *batch; @@ -194,7 +197,7 @@ static int perf_mi_bb_start(void *arg) pr_info("%s: MI_BB_START cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err =3D -EIO; =20 return err; @@ -247,12 +250,13 @@ static int perf_mi_noop(void *arg) struct intel_gt *gt =3D arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */ return 0; =20 - perf_begin(gt); + wakeref =3D perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce =3D engine->kernel_context; struct i915_vma *base, *nop; @@ -348,7 +352,7 @@ static int perf_mi_noop(void *arg) pr_info("%s: 16K MI_NOOP cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err =3D -EIO; =20 return err; diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i91= 5/gt/selftest_gt_pm.c index be94f863bdeff..f0f9983a6fbb2 100644 --- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c @@ -68,6 +68,7 @@ static int live_gt_clocks(void *arg) struct intel_gt *gt =3D arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 if (!gt->clock_frequency) { /* unknown */ @@ -97,7 +98,7 @@ static int live_gt_clocks(void *arg) */ return 0; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); =20 for_each_engine(engine, gt, id) { @@ -134,7 +135,7 @@ static int live_gt_clocks(void *arg) } =20 intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i91= 5/gt/selftest_reset.c index 37c38bdd5f474..cb01901c94e94 100644 --- a/drivers/gpu/drm/i915/gt/selftest_reset.c +++ b/drivers/gpu/drm/i915/gt/selftest_reset.c @@ -257,11 +257,12 @@ static int igt_atomic_reset(void *arg) { struct intel_gt *gt =3D arg; const typeof(*igt_atomic_phases) *p; + intel_wakeref_t wakeref; int err =3D 0; =20 /* Check that the resets are usable from atomic context */ =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); igt_global_reset_lock(gt); =20 /* Flush any requests before we get started and check basics */ @@ -292,7 +293,7 @@ static int igt_atomic_reset(void *arg) =20 unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return err; } @@ -303,6 +304,7 @@ static int igt_atomic_engine_reset(void *arg) const typeof(*igt_atomic_phases) *p; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 /* Check that the resets are usable from atomic context */ @@ -313,7 +315,7 @@ static int igt_atomic_engine_reset(void *arg) if (intel_uc_uses_guc_submission(>->uc)) return 0; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); igt_global_reset_lock(gt); =20 /* Flush any requests before we get started and check basics */ @@ -361,7 +363,7 @@ static int igt_atomic_engine_reset(void *arg) =20 out_unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/= gt/selftest_rps.c index 6a69ac0184ad8..7effd09ced988 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rps.c +++ b/drivers/gpu/drm/i915/gt/selftest_rps.c @@ -223,6 +223,7 @@ int live_rps_clock_interval(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err =3D 0; =20 if (!intel_rps_is_enabled(rps) || GRAPHICS_VER(gt->i915) < 6) @@ -235,7 +236,7 @@ int live_rps_clock_interval(void *arg) saved_work =3D rps->work.func; rps->work.func =3D dummy_rps_work; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); intel_rps_disable(>->rps); =20 intel_gt_check_clock_frequency(gt); @@ -354,7 +355,7 @@ int live_rps_clock_interval(void *arg) } =20 intel_rps_enable(>->rps); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 igt_spinner_fini(&spin); =20 @@ -375,6 +376,7 @@ int live_rps_control(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err =3D 0; =20 /* @@ -397,7 +399,7 @@ int live_rps_control(void *arg) saved_work =3D rps->work.func; rps->work.func =3D dummy_rps_work; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; ktime_t min_dt, max_dt; @@ -487,7 +489,7 @@ int live_rps_control(void *arg) break; } } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 igt_spinner_fini(&spin); =20 @@ -1026,6 +1028,7 @@ int live_rps_interrupt(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; u32 pm_events; int err =3D 0; =20 @@ -1036,9 +1039,9 @@ int live_rps_interrupt(void *arg) if (!intel_rps_has_interrupts(rps) || GRAPHICS_VER(gt->i915) < 6) return 0; =20 - intel_gt_pm_get(gt); - pm_events =3D rps->pm_events; - intel_gt_pm_put(gt); + pm_events =3D 0; + with_intel_gt_pm(gt, wakeref) + pm_events =3D rps->pm_events; if (!pm_events) { pr_err("No RPS PM events registered, but RPS is enabled?\n"); return -ENODEV; diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915= /gt/selftest_slpc.c index b768cea5943dd..27be3c9b29b13 100644 --- a/drivers/gpu/drm/i915/gt/selftest_slpc.c +++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c @@ -44,6 +44,7 @@ static int live_slpc_clamp_min(void *arg) struct intel_rps *rps =3D >->rps; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; struct igt_spinner spin; u32 slpc_min_freq, slpc_max_freq; int err =3D 0; @@ -70,7 +71,7 @@ static int live_slpc_clamp_min(void *arg) } =20 intel_gt_pm_wait_for_idle(gt); - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; u32 step, min_freq, req_freq; @@ -156,7 +157,7 @@ static int live_slpc_clamp_min(void *arg) if (igt_flush_test(gt->i915)) err =3D -EIO; =20 - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); intel_gt_pm_wait_for_idle(gt); =20 @@ -171,6 +172,7 @@ static int live_slpc_clamp_max(void *arg) struct intel_rps *rps; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; struct igt_spinner spin; int err =3D 0; u32 slpc_min_freq, slpc_max_freq; @@ -200,7 +202,7 @@ static int live_slpc_clamp_max(void *arg) } =20 intel_gt_pm_wait_for_idle(gt); - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; u32 max_freq, req_freq; @@ -290,7 +292,7 @@ static int live_slpc_clamp_max(void *arg) slpc_set_max_freq(slpc, slpc_max_freq); slpc_set_min_freq(slpc, slpc_min_freq); =20 - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); intel_gt_pm_wait_for_idle(gt); =20 diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gp= u/drm/i915/gt/uc/intel_guc_submission.c index b3a429a92c0da..7799939c38945 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1048,7 +1048,7 @@ static void scrub_guc_desc_for_outstanding_g2h(struct= intel_guc *guc) if (deregister) guc_signal_context_fence(ce); if (destroyed) { - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } @@ -1254,6 +1254,7 @@ static ktime_t guc_engine_busyness(struct intel_engin= e_cs *engine, ktime_t *now) unsigned long flags; u32 reset_count; bool in_reset; + intel_wakeref_t wakeref; =20 spin_lock_irqsave(&guc->timestamp.lock, flags); =20 @@ -1276,7 +1277,7 @@ static ktime_t guc_engine_busyness(struct intel_engin= e_cs *engine, ktime_t *now) * start_gt_clk is derived from GuC state. To get a consistent * view of activity, we query the GuC state only if gt is awake. */ - if (!in_reset && intel_gt_pm_get_if_awake(gt)) { + if (!in_reset && (wakeref =3D intel_gt_pm_get_if_awake(gt))) { stats_saved =3D *stats; gt_stamp_saved =3D guc->timestamp.gt_stamp; /* @@ -1285,7 +1286,7 @@ static ktime_t guc_engine_busyness(struct intel_engin= e_cs *engine, ktime_t *now) */ guc_update_engine_gt_clks(engine); guc_update_pm_timestamp(guc, now); - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); if (i915_reset_count(gpu_error) !=3D reset_count) { *stats =3D stats_saved; guc->timestamp.gt_stamp =3D gt_stamp_saved; @@ -3903,7 +3904,7 @@ int intel_guc_deregister_done_process_msg(struct inte= l_guc *guc, intel_context_put(ce); } else if (context_destroyed(ce)) { /* Context has been destroyed */ - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pm= u.c index cfc21042499d0..3bd0c75c2ee69 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -171,19 +171,19 @@ static u64 get_rc6(struct intel_gt *gt) { struct drm_i915_private *i915 =3D gt->i915; struct i915_pmu *pmu =3D &i915->pmu; + intel_wakeref_t wakeref; unsigned long flags; - bool awake =3D false; u64 val; =20 - if (intel_gt_pm_get_if_awake(gt)) { + wakeref =3D intel_gt_pm_get_if_awake(gt); + if (wakeref) { val =3D __get_rc6(gt); - intel_gt_pm_put_async(gt); - awake =3D true; + intel_gt_pm_put_async(gt, wakeref); } =20 spin_lock_irqsave(&pmu->lock, flags); =20 - if (awake) { + if (wakeref) { pmu->sample[__I915_SAMPLE_RC6].cur =3D val; } else { /* @@ -377,12 +377,14 @@ frequency_sample(struct intel_gt *gt, unsigned int pe= riod_ns) struct intel_uncore *uncore =3D gt->uncore; struct i915_pmu *pmu =3D &i915->pmu; struct intel_rps *rps =3D >->rps; + intel_wakeref_t wakeref; =20 if (!frequency_sampling_enabled(pmu)) return; =20 /* Report 0/0 (actual/requested) frequency while parked. */ - if (!intel_gt_pm_get_if_awake(gt)) + wakeref =3D intel_gt_pm_get_if_awake(gt); + if (!wakeref) return; =20 if (pmu->enable & config_mask(I915_PMU_ACTUAL_FREQUENCY)) { @@ -413,7 +415,7 @@ frequency_sample(struct intel_gt *gt, unsigned int peri= od_ns) period_ns / 1000); } =20 - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); } =20 static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/in= tel_wakeref.c index dfd87d0822180..db4887e33ea60 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -108,6 +108,10 @@ void __intel_wakeref_init(struct intel_wakeref *wf, INIT_DELAYED_WORK(&wf->work, __intel_wakeref_put_work); lockdep_init_map(&wf->work.work.lockdep_map, "wakeref.work", &key->work, 0); + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + intel_wakeref_tracker_init(&wf->debug); +#endif } =20 int intel_wakeref_wait_for_idle(struct intel_wakeref *wf) diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/in= tel_wakeref.h index e6ba389652d74..38439deefc5cc 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -43,6 +43,10 @@ struct intel_wakeref { const struct intel_wakeref_ops *ops; =20 struct delayed_work work; + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + struct intel_wakeref_tracker debug; +#endif }; =20 struct intel_wakeref_lockclass { @@ -262,6 +266,44 @@ __intel_wakeref_defer_park(struct intel_wakeref *wf) */ int intel_wakeref_wait_for_idle(struct intel_wakeref *wf); =20 +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return intel_wakeref_tracker_add(&wf->debug); +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ + intel_wakeref_tracker_remove(&wf->debug, handle); +} + +static inline void intel_wakeref_show(struct intel_wakeref *wf, + struct drm_printer *p) +{ + intel_wakeref_tracker_show(&wf->debug, p); +} + +#else + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return -1; +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ +} + +static inline void intel_wakeref_show(struct intel_wakeref *wf, + struct drm_printer *p) +{ +} + +#endif + struct intel_wakeref_auto { struct intel_runtime_pm *rpm; struct timer_list timer; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B82C5C433F5 for ; Mon, 21 Feb 2022 23:18:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236640AbiBUXTH (ORCPT ); Mon, 21 Feb 2022 18:19:07 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33824 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236480AbiBUXSk (ORCPT ); Mon, 21 Feb 2022 18:18:40 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9EA4A24F30; Mon, 21 Feb 2022 15:18:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485492; x=1677021492; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=2rbHPotT4d3VveAdnF6hqk3OexpJY7+ajj6Stm674Oc=; b=bUSDeOko8aQWJiStkQK/B0FHeVZ7PKXyiqaVNtvlNKr3h/JfWQr//VUi I37LXMUZ58lgbfSaGx7Xj47jebz4rVAfWCG8zQBub56xnVN1tt6DB/+ga yyYTk88W/GdK0iyk2lpuSTSysIotPlhaxkHImKvCsA+s3N0e/HBRyGBIS a6J0V7M/zmQZxjbbZTRzhLn3KOOHlt6gqbs4+8TvPp5TWEzcRz2LRgaTb DwGRxBSGA259QXK/Wea0MFl6w3lLfLMRykW6JLlW+9ZjD051ed/RwFwQx L9A+4l/3z65rqzWnBBDc8Z0tqXu9rDK5TWYAAnELHMA5ZrTjQCWDT20Ag g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530456" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530456" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:12 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694575" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:09 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 07/11] lib/ref_tracker: remove warnings in case of allocation failure Date: Tue, 22 Feb 2022 00:16:59 +0100 Message-Id: <20220221231705.1481059-18-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Library can handle allocation failures. To avoid allocation warnings __GFP_NOWARN has been added everywhere. Moreover GFP_ATOMIC has been replaced with GFP_NOWAIT in case of stack allocation on tracker free call. Signed-off-by: Andrzej Hajda --- lib/ref_tracker.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 2ef4596b6b36f..cae4498fcfd70 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -189,7 +189,7 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, unsigned long entries[REF_TRACKER_STACK_ENTRIES]; struct ref_tracker *tracker; unsigned int nr_entries; - gfp_t gfp_mask =3D gfp; + gfp_t gfp_mask =3D gfp | __GFP_NOWARN; unsigned long flags; =20 WARN_ON_ONCE(dir->dead); @@ -237,7 +237,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, return -EEXIST; } nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - stack_handle =3D stack_depot_save(entries, nr_entries, GFP_ATOMIC); + stack_handle =3D stack_depot_save(entries, nr_entries, + GFP_NOWAIT | __GFP_NOWARN); =20 spin_lock_irqsave(&dir->lock, flags); if (tracker->dead) { --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 762FDC433EF for ; Mon, 21 Feb 2022 23:19:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233302AbiBUXT2 (ORCPT ); Mon, 21 Feb 2022 18:19:28 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:34476 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236220AbiBUXSu (ORCPT ); Mon, 21 Feb 2022 18:18:50 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D6A3F24BFF; Mon, 21 Feb 2022 15:18:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485496; x=1677021496; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JVXkGTgMk0f0BZi0vzDMp/6U04Z0YVjDjG523a9A54I=; b=dky4AdLTHfRrhWg04YEZvQXjE93QrNgekhRPXw+NR02/IatoI4XstTG8 rnwBbFXDYl0qpXIlM/DvfDeFjixoyQmWYHXdTCs7uVW/CIqqIWL5/Bxh2 zJykcy5Do5b+9sQflLX79OJeqxI7NHHnYpxpu83M6m/4DQcK1HR4joXl2 dknYK4dVNn5uIuzk1/nnOUFGt1SgaJV83hxkmV24lsWrdKfP+MePJHYXy gfQEN3DMP8gacIZBRX3ABvVVY9LU1kkK7G2t52ljOi7UOPzWt9FNWaF4f hsGau0Y/d8TF/w3UCN53CpQIlAgIy4xuYfqHAmYvmlX8lxAN+3QHHKGJe A==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530462" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530462" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:15 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694587" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:12 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 8/9] drm/i915: Correct type of wakeref variable Date: Tue, 22 Feb 2022 00:17:00 +0100 Message-Id: <20220221231705.1481059-19-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Wakeref has dedicated type. Assumption it will be int compatible forever is incorrect. Signed-off-by: Andrzej Hajda --- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gp= u/drm/i915/gt/uc/intel_guc_submission.c index 7799939c38945..b308dd0866eaf 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -2797,7 +2797,7 @@ static void destroyed_worker_func(struct work_struct = *w) struct intel_guc *guc =3D container_of(w, struct intel_guc, submission_state.destroyed_worker); struct intel_gt *gt =3D guc_to_gt(guc); - int tmp; + intel_wakeref_t tmp; =20 with_intel_gt_pm(gt, tmp) deregister_destroyed_contexts(guc); --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2EAADC433FE for ; Mon, 21 Feb 2022 23:19:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236641AbiBUXTl (ORCPT ); Mon, 21 Feb 2022 18:19:41 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:33654 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236649AbiBUXTQ (ORCPT ); Mon, 21 Feb 2022 18:19:16 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0242B24BE3; Mon, 21 Feb 2022 15:18:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485499; x=1677021499; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mmpDbho6EFBReIp+UJ+Rf409yBMByOTa3FwPx9dN22o=; b=nt452AQ3Rku0CNBKou+BLAAZqa7A6gEEN2tMvQbGRYKCvQM9PhBIapc3 hu5WTwyoyWIk7xJgJBpQKcCi0Dq+RyGN7bMTsnfMc7CViRsoidfCsVSD/ TL4/m1BiW9AHCIHN8I8hJ6rOZwqCtN9x2OqBaQJnDVnGpLfcm9K2+MoUm Cl47OxpAxJ3cVWPqSYAV4AEQqSx49aHyHTUqaCPRFmfbKelcOXxIG8qTm w77nlJ90mPovXLhNf4+GZBihXQELBZW9a34+mswo7YkslM9ofE/w++Iuz /UBcdiQoL1P0yFtIydv34FAd4RaW2CuG3AYNHTA0LMCF4zsyO++0cEHbk g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530465" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530465" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:18 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694599" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:15 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Chris Wilson , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski , Chris Wilson Subject: [PATCH v2 08/11] drm/i915: Separate wakeref tracking Date: Tue, 22 Feb 2022 00:17:01 +0100 Message-Id: <20220221231705.1481059-20-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chris Wilson Extract the callstack tracking of intel_runtime_pm.c into its own utility so that that we can reuse it for other online debugging of scoped wakerefs. Signed-off-by: Chris Wilson Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda --- drivers/gpu/drm/i915/Kconfig.debug | 9 + drivers/gpu/drm/i915/Makefile | 4 + drivers/gpu/drm/i915/intel_runtime_pm.c | 244 +++---------------- drivers/gpu/drm/i915/intel_runtime_pm.h | 10 +- drivers/gpu/drm/i915/intel_wakeref.h | 6 +- drivers/gpu/drm/i915/intel_wakeref_tracker.c | 234 ++++++++++++++++++ drivers/gpu/drm/i915/intel_wakeref_tracker.h | 76 ++++++ 7 files changed, 355 insertions(+), 228 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.c create mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.h diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kcon= fig.debug index e7fd3e76f8a20..8b1973146e848 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -33,6 +33,7 @@ config DRM_I915_DEBUG select PREEMPT_COUNT select I2C_CHARDEV select STACKDEPOT + select STACKTRACE select DRM_DP_AUX_CHARDEV select X86_MSR # used by igt/pm_rpm select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) @@ -45,6 +46,7 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_GEM select DRM_I915_DEBUG_GEM_ONCE select DRM_I915_DEBUG_MMIO + select DRM_I915_TRACK_WAKEREF select DRM_I915_DEBUG_RUNTIME_PM select DRM_I915_SW_FENCE_DEBUG_OBJECTS select DRM_I915_SELFTEST @@ -235,11 +237,18 @@ config DRM_I915_DEBUG_VBLANK_EVADE =20 If in doubt, say "N". =20 +config DRM_I915_TRACK_WAKEREF + depends on STACKDEPOT + depends on STACKTRACE + bool + config DRM_I915_DEBUG_RUNTIME_PM bool "Enable extra state checking for runtime PM" depends on DRM_I915 default n select STACKDEPOT + select STACKTRACE + select DRM_I915_TRACK_WAKEREF help Choose this option to turn on extra state checking for the runtime PM functionality. This may introduce overhead during diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 9d588d936e3dc..88a403d3294cb 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -75,6 +75,10 @@ i915-$(CONFIG_DEBUG_FS) +=3D \ i915_debugfs_params.o \ display/intel_display_debugfs.o \ display/intel_pipe_crc.o + +i915-$(CONFIG_DRM_I915_TRACK_WAKEREF) +=3D \ + intel_wakeref_tracker.o + i915-$(CONFIG_PERF_EVENTS) +=3D i915_pmu.o =20 # "Graphics Technology" (aka we talk to the gpu) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915= /intel_runtime_pm.c index 6ed5786bcd299..7bd10efa56bf3 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -52,182 +52,37 @@ =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) =20 -#include - -#define STACKDEPTH 8 - -static noinline depot_stack_handle_t __save_depot_stack(void) -{ - unsigned long entries[STACKDEPTH]; - unsigned int n; - - n =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); -} - static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - spin_lock_init(&rpm->debug.lock); - stack_depot_init(); + intel_wakeref_tracker_init(&rpm->debug); } =20 -static noinline depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - depot_stack_handle_t stack, *stacks; - unsigned long flags; - - if (rpm->no_wakeref_tracking) - return -1; - - stack =3D __save_depot_stack(); - if (!stack) + if (!rpm->available) return -1; =20 - spin_lock_irqsave(&rpm->debug.lock, flags); - - if (!rpm->debug.count) - rpm->debug.last_acquire =3D stack; - - stacks =3D krealloc(rpm->debug.owners, - (rpm->debug.count + 1) * sizeof(*stacks), - GFP_NOWAIT | __GFP_NOWARN); - if (stacks) { - stacks[rpm->debug.count++] =3D stack; - rpm->debug.owners =3D stacks; - } else { - stack =3D -1; - } - - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - return stack; + return intel_wakeref_tracker_add(&rpm->debug); } =20 static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - depot_stack_handle_t stack) + intel_wakeref_t wakeref) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); - unsigned long flags, n; - bool found =3D false; - - if (unlikely(stack =3D=3D -1)) - return; - - spin_lock_irqsave(&rpm->debug.lock, flags); - for (n =3D rpm->debug.count; n--; ) { - if (rpm->debug.owners[n] =3D=3D stack) { - memmove(rpm->debug.owners + n, - rpm->debug.owners + n + 1, - (--rpm->debug.count - n) * sizeof(stack)); - found =3D true; - break; - } - } - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - if (drm_WARN(&i915->drm, !found, - "Unmatched wakeref (tracking %lu), count %u\n", - rpm->debug.count, atomic_read(&rpm->wakeref_count))) { - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref %x from\n%s", stack, buf); - - stack =3D READ_ONCE(rpm->debug.last_release); - if (stack) { - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref last released at\n%s", buf); - } - - kfree(buf); - } + intel_wakeref_tracker_remove(&rpm->debug, wakeref); } =20 -static int cmphandle(const void *_a, const void *_b) +static void untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm = *rpm) { - const depot_stack_handle_t * const a =3D _a, * const b =3D _b; + struct drm_printer p =3D drm_debug_printer("i915"); =20 - if (*a < *b) - return -1; - else if (*a > *b) - return 1; - else - return 0; -} - -static void -__print_intel_runtime_pm_wakeref(struct drm_printer *p, - const struct intel_runtime_pm_debug *dbg) -{ - unsigned long i; - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - if (dbg->last_acquire) { - stack_depot_snprint(dbg->last_acquire, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last acquired:\n%s", buf); - } - - if (dbg->last_release) { - stack_depot_snprint(dbg->last_release, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last released:\n%s", buf); - } - - drm_printf(p, "Wakeref count: %lu\n", dbg->count); - - sort(dbg->owners, dbg->count, sizeof(*dbg->owners), cmphandle, NULL); - - for (i =3D 0; i < dbg->count; i++) { - depot_stack_handle_t stack =3D dbg->owners[i]; - unsigned long rep; - - rep =3D 1; - while (i + 1 < dbg->count && dbg->owners[i + 1] =3D=3D stack) - rep++, i++; - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); - } - - kfree(buf); -} - -static noinline void -__untrack_all_wakerefs(struct intel_runtime_pm_debug *debug, - struct intel_runtime_pm_debug *saved) -{ - *saved =3D *debug; - - debug->owners =3D NULL; - debug->count =3D 0; - debug->last_release =3D __save_depot_stack(); -} - -static void -dump_and_free_wakeref_tracking(struct intel_runtime_pm_debug *debug) -{ - if (debug->count) { - struct drm_printer p =3D drm_debug_printer("i915"); - - __print_intel_runtime_pm_wakeref(&p, debug); - } - - kfree(debug->owners); + intel_wakeref_tracker_reset(&rpm->debug, &p); } =20 static noinline void __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) { - struct intel_runtime_pm_debug dbg =3D {}; + struct intel_wakeref_tracker saved; unsigned long flags; =20 if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count, @@ -235,60 +90,21 @@ __intel_wakeref_dec_and_check_tracking(struct intel_ru= ntime_pm *rpm) flags)) return; =20 - __untrack_all_wakerefs(&rpm->debug, &dbg); + saved =3D __intel_wakeref_tracker_reset(&rpm->debug); spin_unlock_irqrestore(&rpm->debug.lock, flags); =20 - dump_and_free_wakeref_tracking(&dbg); -} - -static noinline void -untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) -{ - struct intel_runtime_pm_debug dbg =3D {}; - unsigned long flags; - - spin_lock_irqsave(&rpm->debug.lock, flags); - __untrack_all_wakerefs(&rpm->debug, &dbg); - spin_unlock_irqrestore(&rpm->debug.lock, flags); + if (saved.count) { + struct drm_printer p =3D drm_debug_printer("i915"); =20 - dump_and_free_wakeref_tracking(&dbg); + __intel_wakeref_tracker_show(&saved, &p); + intel_wakeref_tracker_fini(&saved); + } } =20 void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, struct drm_printer *p) { - struct intel_runtime_pm_debug dbg =3D {}; - - do { - unsigned long alloc =3D dbg.count; - depot_stack_handle_t *s; - - spin_lock_irq(&rpm->debug.lock); - dbg.count =3D rpm->debug.count; - if (dbg.count <=3D alloc) { - memcpy(dbg.owners, - rpm->debug.owners, - dbg.count * sizeof(*s)); - } - dbg.last_acquire =3D rpm->debug.last_acquire; - dbg.last_release =3D rpm->debug.last_release; - spin_unlock_irq(&rpm->debug.lock); - if (dbg.count <=3D alloc) - break; - - s =3D krealloc(dbg.owners, - dbg.count * sizeof(*s), - GFP_NOWAIT | __GFP_NOWARN); - if (!s) - goto out; - - dbg.owners =3D s; - } while (1); - - __print_intel_runtime_pm_wakeref(p, &dbg); - -out: - kfree(dbg.owners); + intel_wakeref_tracker_show(&rpm->debug, p); } =20 #else @@ -297,14 +113,14 @@ static void init_intel_runtime_pm_wakeref(struct inte= l_runtime_pm *rpm) { } =20 -static depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { return -1; } =20 static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - intel_wakeref_t wref) + intel_wakeref_t wakeref) { } =20 @@ -349,9 +165,8 @@ intel_runtime_pm_release(struct intel_runtime_pm *rpm, = int wakelock) static intel_wakeref_t __intel_runtime_pm_get(struct intel_runtime_pm *rpm, bool wakelock) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); int ret; =20 ret =3D pm_runtime_get_sync(rpm->kdev); @@ -556,9 +371,8 @@ void intel_runtime_pm_put(struct intel_runtime_pm *rpm,= intel_wakeref_t wref) */ void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); struct device *kdev =3D rpm->kdev; =20 /* @@ -604,9 +418,8 @@ void intel_runtime_pm_enable(struct intel_runtime_pm *r= pm) =20 void intel_runtime_pm_disable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); struct device *kdev =3D rpm->kdev; =20 /* Transfer rpm ownership back to core */ @@ -621,9 +434,8 @@ void intel_runtime_pm_disable(struct intel_runtime_pm *= rpm) =20 void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 =3D container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 =3D + container_of(rpm, struct drm_i915_private, runtime_pm); int count =3D atomic_read(&rpm->wakeref_count); =20 drm_WARN(&i915->drm, count, @@ -637,7 +449,7 @@ void intel_runtime_pm_driver_release(struct intel_runti= me_pm *rpm) void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) { struct drm_i915_private *i915 =3D - container_of(rpm, struct drm_i915_private, runtime_pm); + container_of(rpm, struct drm_i915_private, runtime_pm); struct pci_dev *pdev =3D to_pci_dev(i915->drm.dev); struct device *kdev =3D &pdev->dev; =20 diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915= /intel_runtime_pm.h index d9160e3ff4afc..0871fa2176474 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -61,15 +61,7 @@ struct intel_runtime_pm { * paired rpm_put) we can remove corresponding pairs of and keep * the array trimmed to active wakerefs. */ - struct intel_runtime_pm_debug { - spinlock_t lock; - - depot_stack_handle_t last_acquire; - depot_stack_handle_t last_release; - - depot_stack_handle_t *owners; - unsigned long count; - } debug; + struct intel_wakeref_tracker debug; #endif }; =20 diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/in= tel_wakeref.h index 4f4c2e15e736e..e6ba389652d74 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -17,7 +17,9 @@ #include #include =20 -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) +#include "intel_wakeref_tracker.h" + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) #else #define INTEL_WAKEREF_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) @@ -26,8 +28,6 @@ struct intel_runtime_pm; struct intel_wakeref; =20 -typedef depot_stack_handle_t intel_wakeref_t; - struct intel_wakeref_ops { int (*get)(struct intel_wakeref *wf); int (*put)(struct intel_wakeref *wf); diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.c b/drivers/gpu/drm= /i915/intel_wakeref_tracker.c new file mode 100644 index 0000000000000..a0bcef13a1085 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_wakeref_tracker.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright =C2=A9 2021 Intel Corporation + */ + +#include +#include +#include +#include + +#include + +#include "intel_wakeref.h" + +#define STACKDEPTH 8 + +static noinline depot_stack_handle_t __save_depot_stack(void) +{ + unsigned long entries[STACKDEPTH]; + unsigned int n; + + n =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); + return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); +} + +static void __print_depot_stack(depot_stack_handle_t stack, + char *buf, int sz, int indent) +{ + unsigned long *entries; + unsigned int nr_entries; + + nr_entries =3D stack_depot_fetch(stack, &entries); + stack_trace_snprint(buf, sz, entries, nr_entries, indent); +} + +static int cmphandle(const void *_a, const void *_b) +{ + const depot_stack_handle_t * const a =3D _a, * const b =3D _b; + + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else + return 0; +} + +void +__intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, + struct drm_printer *p) +{ + unsigned long i; + char *buf; + + buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); + if (!buf) + return; + + if (w->last_acquire) { + __print_depot_stack(w->last_acquire, buf, PAGE_SIZE, 2); + drm_printf(p, "Wakeref last acquired:\n%s", buf); + } + + if (w->last_release) { + __print_depot_stack(w->last_release, buf, PAGE_SIZE, 2); + drm_printf(p, "Wakeref last released:\n%s", buf); + } + + drm_printf(p, "Wakeref count: %lu\n", w->count); + + sort(w->owners, w->count, sizeof(*w->owners), cmphandle, NULL); + + for (i =3D 0; i < w->count; i++) { + depot_stack_handle_t stack =3D w->owners[i]; + unsigned long rep; + + rep =3D 1; + while (i + 1 < w->count && w->owners[i + 1] =3D=3D stack) + rep++, i++; + __print_depot_stack(stack, buf, PAGE_SIZE, 2); + drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); + } + + kfree(buf); +} + +void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, + struct drm_printer *p) +{ + struct intel_wakeref_tracker tmp =3D {}; + + do { + unsigned long alloc =3D tmp.count; + depot_stack_handle_t *s; + + spin_lock_irq(&w->lock); + tmp.count =3D w->count; + if (tmp.count <=3D alloc) + memcpy(tmp.owners, w->owners, tmp.count * sizeof(*s)); + tmp.last_acquire =3D w->last_acquire; + tmp.last_release =3D w->last_release; + spin_unlock_irq(&w->lock); + if (tmp.count <=3D alloc) + break; + + s =3D krealloc(tmp.owners, + tmp.count * sizeof(*s), + GFP_NOWAIT | __GFP_NOWARN); + if (!s) + goto out; + + tmp.owners =3D s; + } while (1); + + __intel_wakeref_tracker_show(&tmp, p); + +out: + intel_wakeref_tracker_fini(&tmp); +} + +intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) +{ + depot_stack_handle_t stack, *stacks; + unsigned long flags; + + stack =3D __save_depot_stack(); + if (!stack) + return -1; + + spin_lock_irqsave(&w->lock, flags); + + if (!w->count) + w->last_acquire =3D stack; + + stacks =3D krealloc(w->owners, + (w->count + 1) * sizeof(*stacks), + GFP_NOWAIT | __GFP_NOWARN); + if (stacks) { + stacks[w->count++] =3D stack; + w->owners =3D stacks; + } else { + stack =3D -1; + } + + spin_unlock_irqrestore(&w->lock, flags); + + return stack; +} + +void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, + intel_wakeref_t stack) +{ + unsigned long flags, n; + bool found =3D false; + + if (unlikely(stack =3D=3D -1)) + return; + + spin_lock_irqsave(&w->lock, flags); + for (n =3D w->count; n--; ) { + if (w->owners[n] =3D=3D stack) { + memmove(w->owners + n, + w->owners + n + 1, + (--w->count - n) * sizeof(stack)); + found =3D true; + break; + } + } + spin_unlock_irqrestore(&w->lock, flags); + + if (WARN(!found, + "Unmatched wakeref %x, tracking %lu\n", + stack, w->count)) { + char *buf; + + buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); + if (!buf) + return; + + __print_depot_stack(stack, buf, PAGE_SIZE, 2); + pr_err("wakeref %x from\n%s", stack, buf); + + stack =3D READ_ONCE(w->last_release); + if (stack && !w->count) { + __print_depot_stack(stack, buf, PAGE_SIZE, 2); + pr_err("wakeref last released at\n%s", buf); + } + + kfree(buf); + } +} + +struct intel_wakeref_tracker +__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) +{ + struct intel_wakeref_tracker saved; + + lockdep_assert_held(&w->lock); + + saved =3D *w; + + w->owners =3D NULL; + w->count =3D 0; + w->last_release =3D __save_depot_stack(); + + return saved; +} + +void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, + struct drm_printer *p) +{ + struct intel_wakeref_tracker tmp; + + spin_lock_irq(&w->lock); + tmp =3D __intel_wakeref_tracker_reset(w); + spin_unlock_irq(&w->lock); + + if (tmp.count) + __intel_wakeref_tracker_show(&tmp, p); + + intel_wakeref_tracker_fini(&tmp); +} + +void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w) +{ + memset(w, 0, sizeof(*w)); + spin_lock_init(&w->lock); + stack_depot_init(); +} + +void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w) +{ + kfree(w->owners); +} diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.h b/drivers/gpu/drm= /i915/intel_wakeref_tracker.h new file mode 100644 index 0000000000000..61df68e28c0fb --- /dev/null +++ b/drivers/gpu/drm/i915/intel_wakeref_tracker.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright =C2=A9 2019 Intel Corporation + */ + +#ifndef INTEL_WAKEREF_TRACKER_H +#define INTEL_WAKEREF_TRACKER_H + +#include +#include +#include + +typedef depot_stack_handle_t intel_wakeref_t; + +struct drm_printer; + +struct intel_wakeref_tracker { + spinlock_t lock; + + depot_stack_handle_t last_acquire; + depot_stack_handle_t last_release; + + depot_stack_handle_t *owners; + unsigned long count; +}; + +#if IS_ENABLED(CONFIG_DRM_I915_TRACK_WAKEREF) + +void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w); +void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w); + +intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w); +void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, + intel_wakeref_t handle); + +struct intel_wakeref_tracker +__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w); +void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, + struct drm_printer *p); + +void __intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, + struct drm_printer *p); +void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, + struct drm_printer *p); + +#else + +static inline void intel_wakeref_tracker_init(struct intel_wakeref_tracker= *w) {} +static inline void intel_wakeref_tracker_fini(struct intel_wakeref_tracker= *w) {} + +static inline intel_wakeref_t +intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) +{ + return -1; +} + +static inline void +intel_wakeref_untrack_remove(struct intel_wakeref_tracker *w, intel_wakere= f_t handle) {} + +static inline struct intel_wakeref_tracker +__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) +{ + return (struct intel_wakeref_tracker){}; +} + +static inline void intel_wakeref_tracker_reset(struct intel_wakeref_tracke= r *w, + struct drm_printer *p) +{ +} + +static inline void __intel_wakeref_tracker_show(const struct intel_wakeref= _tracker *w, struct drm_printer *p) {} +static inline void intel_wakeref_tracker_show(struct intel_wakeref_tracker= *w, struct drm_printer *p) {} + +#endif + +#endif /* INTEL_WAKEREF_TRACKER_H */ --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5F2AEC433FE for ; Mon, 21 Feb 2022 23:19:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236544AbiBUXUH (ORCPT ); Mon, 21 Feb 2022 18:20:07 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:34094 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236546AbiBUXTS (ORCPT ); Mon, 21 Feb 2022 18:19:18 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9910C255B4; Mon, 21 Feb 2022 15:18:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485502; x=1677021502; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oausHsFMvXj5B+qizgOxlxKt+444ZkIfhgF1cXdIgiQ=; b=e1eAalSTA8XWJYhkIKvxeEdRwiB5GRYoEBolkbI/cbA0guZCO+F1/q1O WOXW9qLCbt/TlwkedoGSqInzMX0gJhdcRAP7ErclHYKGGVivLEmEDrALm YKPSoSRHMJsDp/x3R9m/DgLKpjwNAEcKkTFaqsrMNKdRiIFpHpZMilZl2 sulUwUWUP7/PMn897R4swEvxPrCaVtj2UqgPRfwcBwp0cyyoK8UmUztFf irle92x7lRLRs5F5fVeVgYMkJLXijTJ4+f1Kj1t78PzwTQyRT4nFErXRY djxjtws60vUAGvVwR9FgivwKcPYzmUfmJTYp69IsoGiaQTWWJYEndTGnn g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530470" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530470" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:21 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694612" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:18 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 9/9] drm/i915: replace Intel internal tracker with kernel core ref_tracker Date: Tue, 22 Feb 2022 00:17:02 +0100 Message-Id: <20220221231705.1481059-21-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Beside reusing existing code, the main advantage of ref_tracker is tracking per instance of wakeref. It allows also to catch double put. On the other side we lose information about the first acquire and the last release, but the advantages outweigh it. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/Kconfig.debug | 11 +- drivers/gpu/drm/i915/Makefile | 3 - .../drm/i915/display/intel_display_power.c | 2 +- drivers/gpu/drm/i915/gt/intel_engine_pm.c | 2 +- drivers/gpu/drm/i915/gt/intel_gt_pm.c | 2 +- drivers/gpu/drm/i915/intel_runtime_pm.c | 23 +- drivers/gpu/drm/i915/intel_runtime_pm.h | 2 +- drivers/gpu/drm/i915/intel_wakeref.c | 8 +- drivers/gpu/drm/i915/intel_wakeref.h | 72 +++++- drivers/gpu/drm/i915/intel_wakeref_tracker.c | 234 ------------------ drivers/gpu/drm/i915/intel_wakeref_tracker.h | 76 ------ 11 files changed, 86 insertions(+), 349 deletions(-) delete mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.c delete mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.h diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kcon= fig.debug index 3bdc73f30a9e1..6c57f3e265f20 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -32,6 +32,7 @@ config DRM_I915_DEBUG select DEBUG_FS select PREEMPT_COUNT select I2C_CHARDEV + select REF_TRACKER select STACKDEPOT select STACKTRACE select DRM_DP_AUX_CHARDEV @@ -46,7 +47,6 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_GEM select DRM_I915_DEBUG_GEM_ONCE select DRM_I915_DEBUG_MMIO - select DRM_I915_TRACK_WAKEREF select DRM_I915_DEBUG_RUNTIME_PM select DRM_I915_DEBUG_WAKEREF select DRM_I915_SW_FENCE_DEBUG_OBJECTS @@ -238,18 +238,13 @@ config DRM_I915_DEBUG_VBLANK_EVADE =20 If in doubt, say "N". =20 -config DRM_I915_TRACK_WAKEREF - depends on STACKDEPOT - depends on STACKTRACE - bool - config DRM_I915_DEBUG_RUNTIME_PM bool "Enable extra state checking for runtime PM" depends on DRM_I915 default n + select REF_TRACKER select STACKDEPOT select STACKTRACE - select DRM_I915_TRACK_WAKEREF help Choose this option to turn on extra state checking for the runtime PM functionality. This may introduce overhead during @@ -263,9 +258,9 @@ config DRM_I915_DEBUG_WAKEREF bool "Enable extra tracking for wakerefs" depends on DRM_I915 default n + select REF_TRACKER select STACKDEPOT select STACKTRACE - select DRM_I915_TRACK_WAKEREF help Choose this option to turn on extra state checking and usage tracking for the wakerefPM functionality. This may introduce diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 88a403d3294cb..1f8d71430e2e6 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -76,9 +76,6 @@ i915-$(CONFIG_DEBUG_FS) +=3D \ display/intel_display_debugfs.o \ display/intel_pipe_crc.o =20 -i915-$(CONFIG_DRM_I915_TRACK_WAKEREF) +=3D \ - intel_wakeref_tracker.o - i915-$(CONFIG_PERF_EVENTS) +=3D i915_pmu.o =20 # "Graphics Technology" (aka we talk to the gpu) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/g= pu/drm/i915/display/intel_display_power.c index 9ebae7ac32356..0e1bf724f89b5 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -2107,7 +2107,7 @@ print_async_put_domains_state(struct i915_power_domai= ns *power_domains) struct drm_i915_private, power_domains); =20 - drm_dbg(&i915->drm, "async_put_wakeref %u\n", + drm_dbg(&i915->drm, "async_put_wakeref %lu\n", power_domains->async_put_wakeref); =20 print_power_domains(power_domains, "async_put_domains[0]", diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i9= 15/gt/intel_engine_pm.c index 52e46e7830ff5..cf8cc348942cb 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -273,7 +273,7 @@ void intel_engine_init__pm(struct intel_engine_cs *engi= ne) { struct intel_runtime_pm *rpm =3D engine->uncore->rpm; =20 - intel_wakeref_init(&engine->wakeref, rpm, &wf_ops); + intel_wakeref_init(&engine->wakeref, rpm, &wf_ops, engine->name); intel_engine_init_heartbeat(engine); } =20 diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/g= t/intel_gt_pm.c index 7ee65a93f926f..01a055d0d0989 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -129,7 +129,7 @@ static const struct intel_wakeref_ops wf_ops =3D { =20 void intel_gt_pm_init_early(struct intel_gt *gt) { - intel_wakeref_init(>->wakeref, gt->uncore->rpm, &wf_ops); + intel_wakeref_init(>->wakeref, gt->uncore->rpm, &wf_ops, "GT"); seqcount_mutex_init(>->stats.lock, >->wakeref.mutex); } =20 diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915= /intel_runtime_pm.c index 7bd10efa56bf3..e923ab8d8da08 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -54,7 +54,7 @@ =20 static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - intel_wakeref_tracker_init(&rpm->debug); + ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, dev_name(rpm= ->kdev)); } =20 static intel_wakeref_t @@ -63,26 +63,26 @@ track_intel_runtime_pm_wakeref(struct intel_runtime_pm = *rpm) if (!rpm->available) return -1; =20 - return intel_wakeref_tracker_add(&rpm->debug); + return intel_ref_tracker_alloc(&rpm->debug); } =20 static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, intel_wakeref_t wakeref) { - intel_wakeref_tracker_remove(&rpm->debug, wakeref); + if (!rpm->available) + return; + + intel_ref_tracker_free(&rpm->debug, wakeref); } =20 static void untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm = *rpm) { - struct drm_printer p =3D drm_debug_printer("i915"); - - intel_wakeref_tracker_reset(&rpm->debug, &p); + ref_tracker_dir_exit(&rpm->debug); } =20 static noinline void __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) { - struct intel_wakeref_tracker saved; unsigned long flags; =20 if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count, @@ -90,15 +90,8 @@ __intel_wakeref_dec_and_check_tracking(struct intel_runt= ime_pm *rpm) flags)) return; =20 - saved =3D __intel_wakeref_tracker_reset(&rpm->debug); + __ref_tracker_dir_print(&rpm->debug, INTEL_REFTRACK_PRINT_LIMIT); spin_unlock_irqrestore(&rpm->debug.lock, flags); - - if (saved.count) { - struct drm_printer p =3D drm_debug_printer("i915"); - - __intel_wakeref_tracker_show(&saved, &p); - intel_wakeref_tracker_fini(&saved); - } } =20 void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915= /intel_runtime_pm.h index 0871fa2176474..db5692f1eb67e 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -61,7 +61,7 @@ struct intel_runtime_pm { * paired rpm_put) we can remove corresponding pairs of and keep * the array trimmed to active wakerefs. */ - struct intel_wakeref_tracker debug; + struct ref_tracker_dir debug; #endif }; =20 diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/in= tel_wakeref.c index db4887e33ea60..97fe9a0f0adbd 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -62,6 +62,9 @@ static void ____intel_wakeref_put_last(struct intel_waker= ef *wf) if (likely(!wf->ops->put(wf))) { rpm_put(wf); wake_up_var(&wf->wakeref); +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + ref_tracker_dir_exit(&wf->debug); +#endif } =20 unlock: @@ -96,7 +99,8 @@ static void __intel_wakeref_put_work(struct work_struct *= wrk) void __intel_wakeref_init(struct intel_wakeref *wf, struct intel_runtime_pm *rpm, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key) + struct intel_wakeref_lockclass *key, + const char *name) { wf->rpm =3D rpm; wf->ops =3D ops; @@ -110,7 +114,7 @@ void __intel_wakeref_init(struct intel_wakeref *wf, "wakeref.work", &key->work, 0); =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) - intel_wakeref_tracker_init(&wf->debug); + ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, name); #endif } =20 diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/in= tel_wakeref.h index 38439deefc5cc..c694d129aca7b 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -7,17 +7,24 @@ #ifndef INTEL_WAKEREF_H #define INTEL_WAKEREF_H =20 +#include + #include #include #include #include #include #include +#include +#include #include #include #include =20 -#include "intel_wakeref_tracker.h" +typedef unsigned long intel_wakeref_t; + +#define INTEL_REFTRACK_DEAD_COUNT 16 +#define INTEL_REFTRACK_PRINT_LIMIT 16 =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) @@ -45,7 +52,7 @@ struct intel_wakeref { struct delayed_work work; =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) - struct intel_wakeref_tracker debug; + struct ref_tracker_dir debug; #endif }; =20 @@ -57,11 +64,12 @@ struct intel_wakeref_lockclass { void __intel_wakeref_init(struct intel_wakeref *wf, struct intel_runtime_pm *rpm, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key); -#define intel_wakeref_init(wf, rpm, ops) do { \ + struct intel_wakeref_lockclass *key, + const char *name); +#define intel_wakeref_init(wf, rpm, ops, name) do { \ static struct intel_wakeref_lockclass __key; \ \ - __intel_wakeref_init((wf), (rpm), (ops), &__key); \ + __intel_wakeref_init((wf), (rpm), (ops), &__key, name); \ } while (0) =20 int __intel_wakeref_get_first(struct intel_wakeref *wf); @@ -266,17 +274,67 @@ __intel_wakeref_defer_park(struct intel_wakeref *wf) */ int intel_wakeref_wait_for_idle(struct intel_wakeref *wf); =20 +#define INTEL_WAKEREF_DEF ((intel_wakeref_t)(-1)) + +static inline intel_wakeref_t intel_ref_tracker_alloc(struct ref_tracker_d= ir *dir) +{ + struct ref_tracker *user =3D NULL; + + ref_tracker_alloc(dir, &user, GFP_NOWAIT); + + return (intel_wakeref_t)user ?: INTEL_WAKEREF_DEF; +} + +static inline void intel_ref_tracker_free(struct ref_tracker_dir *dir, + intel_wakeref_t handle) +{ + struct ref_tracker *user; + + user =3D (handle =3D=3D INTEL_WAKEREF_DEF) ? NULL : (void *)handle; + + ref_tracker_free(dir, &user); +} + +static inline void +intel_wakeref_tracker_show(struct ref_tracker_dir *dir, + struct drm_printer *p) +{ + const size_t buf_size =3D PAGE_SIZE; + char *buf, *sb, *se; + size_t count; + + buf =3D kmalloc(buf_size, GFP_NOWAIT); + if (!buf) + return; + + count =3D ref_tracker_dir_snprint(dir, buf, buf_size); + if (!count) + goto free; + /* printk does not like big buffers, so we split it */ + for (sb =3D buf; *sb; sb =3D se + 1) { + se =3D strchrnul(sb, '\n'); + drm_printf(p, "%.*s", (int)(se - sb + 1), sb); + if (!*se) + break; + } + if (count >=3D buf_size) + drm_printf(p, "dropped %zd extra bytes of leak report.\n", + count + 1 - buf_size); +free: + kfree(buf); +} + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) =20 static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) { - return intel_wakeref_tracker_add(&wf->debug); + return intel_ref_tracker_alloc(&wf->debug); } =20 static inline void intel_wakeref_untrack(struct intel_wakeref *wf, intel_wakeref_t handle) { - intel_wakeref_tracker_remove(&wf->debug, handle); + intel_ref_tracker_free(&wf->debug, handle); } =20 static inline void intel_wakeref_show(struct intel_wakeref *wf, diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.c b/drivers/gpu/drm= /i915/intel_wakeref_tracker.c deleted file mode 100644 index a0bcef13a1085..0000000000000 --- a/drivers/gpu/drm/i915/intel_wakeref_tracker.c +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright =C2=A9 2021 Intel Corporation - */ - -#include -#include -#include -#include - -#include - -#include "intel_wakeref.h" - -#define STACKDEPTH 8 - -static noinline depot_stack_handle_t __save_depot_stack(void) -{ - unsigned long entries[STACKDEPTH]; - unsigned int n; - - n =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); -} - -static void __print_depot_stack(depot_stack_handle_t stack, - char *buf, int sz, int indent) -{ - unsigned long *entries; - unsigned int nr_entries; - - nr_entries =3D stack_depot_fetch(stack, &entries); - stack_trace_snprint(buf, sz, entries, nr_entries, indent); -} - -static int cmphandle(const void *_a, const void *_b) -{ - const depot_stack_handle_t * const a =3D _a, * const b =3D _b; - - if (*a < *b) - return -1; - else if (*a > *b) - return 1; - else - return 0; -} - -void -__intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, - struct drm_printer *p) -{ - unsigned long i; - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - if (w->last_acquire) { - __print_depot_stack(w->last_acquire, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last acquired:\n%s", buf); - } - - if (w->last_release) { - __print_depot_stack(w->last_release, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last released:\n%s", buf); - } - - drm_printf(p, "Wakeref count: %lu\n", w->count); - - sort(w->owners, w->count, sizeof(*w->owners), cmphandle, NULL); - - for (i =3D 0; i < w->count; i++) { - depot_stack_handle_t stack =3D w->owners[i]; - unsigned long rep; - - rep =3D 1; - while (i + 1 < w->count && w->owners[i + 1] =3D=3D stack) - rep++, i++; - __print_depot_stack(stack, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); - } - - kfree(buf); -} - -void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, - struct drm_printer *p) -{ - struct intel_wakeref_tracker tmp =3D {}; - - do { - unsigned long alloc =3D tmp.count; - depot_stack_handle_t *s; - - spin_lock_irq(&w->lock); - tmp.count =3D w->count; - if (tmp.count <=3D alloc) - memcpy(tmp.owners, w->owners, tmp.count * sizeof(*s)); - tmp.last_acquire =3D w->last_acquire; - tmp.last_release =3D w->last_release; - spin_unlock_irq(&w->lock); - if (tmp.count <=3D alloc) - break; - - s =3D krealloc(tmp.owners, - tmp.count * sizeof(*s), - GFP_NOWAIT | __GFP_NOWARN); - if (!s) - goto out; - - tmp.owners =3D s; - } while (1); - - __intel_wakeref_tracker_show(&tmp, p); - -out: - intel_wakeref_tracker_fini(&tmp); -} - -intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) -{ - depot_stack_handle_t stack, *stacks; - unsigned long flags; - - stack =3D __save_depot_stack(); - if (!stack) - return -1; - - spin_lock_irqsave(&w->lock, flags); - - if (!w->count) - w->last_acquire =3D stack; - - stacks =3D krealloc(w->owners, - (w->count + 1) * sizeof(*stacks), - GFP_NOWAIT | __GFP_NOWARN); - if (stacks) { - stacks[w->count++] =3D stack; - w->owners =3D stacks; - } else { - stack =3D -1; - } - - spin_unlock_irqrestore(&w->lock, flags); - - return stack; -} - -void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, - intel_wakeref_t stack) -{ - unsigned long flags, n; - bool found =3D false; - - if (unlikely(stack =3D=3D -1)) - return; - - spin_lock_irqsave(&w->lock, flags); - for (n =3D w->count; n--; ) { - if (w->owners[n] =3D=3D stack) { - memmove(w->owners + n, - w->owners + n + 1, - (--w->count - n) * sizeof(stack)); - found =3D true; - break; - } - } - spin_unlock_irqrestore(&w->lock, flags); - - if (WARN(!found, - "Unmatched wakeref %x, tracking %lu\n", - stack, w->count)) { - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - __print_depot_stack(stack, buf, PAGE_SIZE, 2); - pr_err("wakeref %x from\n%s", stack, buf); - - stack =3D READ_ONCE(w->last_release); - if (stack && !w->count) { - __print_depot_stack(stack, buf, PAGE_SIZE, 2); - pr_err("wakeref last released at\n%s", buf); - } - - kfree(buf); - } -} - -struct intel_wakeref_tracker -__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) -{ - struct intel_wakeref_tracker saved; - - lockdep_assert_held(&w->lock); - - saved =3D *w; - - w->owners =3D NULL; - w->count =3D 0; - w->last_release =3D __save_depot_stack(); - - return saved; -} - -void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, - struct drm_printer *p) -{ - struct intel_wakeref_tracker tmp; - - spin_lock_irq(&w->lock); - tmp =3D __intel_wakeref_tracker_reset(w); - spin_unlock_irq(&w->lock); - - if (tmp.count) - __intel_wakeref_tracker_show(&tmp, p); - - intel_wakeref_tracker_fini(&tmp); -} - -void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w) -{ - memset(w, 0, sizeof(*w)); - spin_lock_init(&w->lock); - stack_depot_init(); -} - -void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w) -{ - kfree(w->owners); -} diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.h b/drivers/gpu/drm= /i915/intel_wakeref_tracker.h deleted file mode 100644 index 61df68e28c0fb..0000000000000 --- a/drivers/gpu/drm/i915/intel_wakeref_tracker.h +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright =C2=A9 2019 Intel Corporation - */ - -#ifndef INTEL_WAKEREF_TRACKER_H -#define INTEL_WAKEREF_TRACKER_H - -#include -#include -#include - -typedef depot_stack_handle_t intel_wakeref_t; - -struct drm_printer; - -struct intel_wakeref_tracker { - spinlock_t lock; - - depot_stack_handle_t last_acquire; - depot_stack_handle_t last_release; - - depot_stack_handle_t *owners; - unsigned long count; -}; - -#if IS_ENABLED(CONFIG_DRM_I915_TRACK_WAKEREF) - -void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w); -void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w); - -intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w); -void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, - intel_wakeref_t handle); - -struct intel_wakeref_tracker -__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w); -void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, - struct drm_printer *p); - -void __intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, - struct drm_printer *p); -void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, - struct drm_printer *p); - -#else - -static inline void intel_wakeref_tracker_init(struct intel_wakeref_tracker= *w) {} -static inline void intel_wakeref_tracker_fini(struct intel_wakeref_tracker= *w) {} - -static inline intel_wakeref_t -intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) -{ - return -1; -} - -static inline void -intel_wakeref_untrack_remove(struct intel_wakeref_tracker *w, intel_wakere= f_t handle) {} - -static inline struct intel_wakeref_tracker -__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) -{ - return (struct intel_wakeref_tracker){}; -} - -static inline void intel_wakeref_tracker_reset(struct intel_wakeref_tracke= r *w, - struct drm_printer *p) -{ -} - -static inline void __intel_wakeref_tracker_show(const struct intel_wakeref= _tracker *w, struct drm_printer *p) {} -static inline void intel_wakeref_tracker_show(struct intel_wakeref_tracker= *w, struct drm_printer *p) {} - -#endif - -#endif /* INTEL_WAKEREF_TRACKER_H */ --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1F52BC433EF for ; Mon, 21 Feb 2022 23:20:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236421AbiBUXUa (ORCPT ); Mon, 21 Feb 2022 18:20:30 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:35162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236719AbiBUXTV (ORCPT ); Mon, 21 Feb 2022 18:19:21 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5D96E25C5B; Mon, 21 Feb 2022 15:18:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485507; x=1677021507; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qlFqLRfrfrx4mNRF6vVIBqvEiaofH2gyPUSV1nRx1WA=; b=Qb0x3wY5UAkZ9FlMKRR/FnBsv5FznIjQsFBX50TsMZuhnfrBbNH6JRhd HFBm43RYFqOjsjzkIR7tx0eduty3vn/H5XPOMT4EWd8ZyuCLvINGsvDY4 6QvyHW9OK0YEEdZayNuSIVEDcUrtGSBqK7iXAqsNCHkV9wZ39ePetHVL1 v/AhPR6oBR9AjTkxXIDh1Bn+utXatBE75zu5F3Vml2leNpKyuZGlxwZYm PwECGJiKOHwk09x2LXps1aVhfuymA5TfAfAmj7EAQWa7JKcmD4lGt2UZy yrxDTEuCwwwMHgLQkucimVrCmGDSc+TUlcOswqK9ciQI6gP7WwVIz0d0X Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530474" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530474" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:24 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694621" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:21 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Chris Wilson , Jani Nikula , Daniel Vetter , Lucas De Marchi , Andrzej Hajda , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 09/11] drm/i915: Track leaked gt->wakerefs Date: Tue, 22 Feb 2022 00:17:03 +0100 Message-Id: <20220221231705.1481059-22-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Chris Wilson Track every intel_gt_pm_get() until its corresponding release in intel_gt_pm_put() by returning a cookie to the caller for acquire that must be passed by on rleased. When there is an imbalance, we can see who either tried to free a stale wakeref, or who forgot to free theirs. v2: Rebase from backporting wakeref leak (Umesh) Signed-off-by: Chris Wilson Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda --- drivers/gpu/drm/i915/Kconfig.debug | 15 +++++++ .../gpu/drm/i915/gem/i915_gem_execbuffer.c | 7 ++-- .../i915/gem/selftests/i915_gem_coherency.c | 10 +++-- .../drm/i915/gem/selftests/i915_gem_mman.c | 14 ++++--- drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 13 ++++-- .../gpu/drm/i915/gt/intel_breadcrumbs_types.h | 3 +- drivers/gpu/drm/i915/gt/intel_engine_pm.c | 4 +- drivers/gpu/drm/i915/gt/intel_engine_types.h | 2 + .../drm/i915/gt/intel_execlists_submission.c | 2 +- drivers/gpu/drm/i915/gt/intel_gt_pm.c | 10 +++-- drivers/gpu/drm/i915/gt/intel_gt_pm.h | 36 ++++++++++++---- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 4 +- drivers/gpu/drm/i915/gt/selftest_engine_cs.c | 20 +++++---- drivers/gpu/drm/i915/gt/selftest_gt_pm.c | 5 ++- drivers/gpu/drm/i915/gt/selftest_reset.c | 10 +++-- drivers/gpu/drm/i915/gt/selftest_rps.c | 17 ++++---- drivers/gpu/drm/i915/gt/selftest_slpc.c | 10 +++-- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 9 ++-- drivers/gpu/drm/i915/i915_pmu.c | 16 +++---- drivers/gpu/drm/i915/intel_wakeref.c | 4 ++ drivers/gpu/drm/i915/intel_wakeref.h | 42 +++++++++++++++++++ 21 files changed, 182 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kcon= fig.debug index 8b1973146e848..3bdc73f30a9e1 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -48,6 +48,7 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_MMIO select DRM_I915_TRACK_WAKEREF select DRM_I915_DEBUG_RUNTIME_PM + select DRM_I915_DEBUG_WAKEREF select DRM_I915_SW_FENCE_DEBUG_OBJECTS select DRM_I915_SELFTEST select BROKEN # for prototype uAPI @@ -257,3 +258,17 @@ config DRM_I915_DEBUG_RUNTIME_PM Recommended for driver developers only. =20 If in doubt, say "N" + +config DRM_I915_DEBUG_WAKEREF + bool "Enable extra tracking for wakerefs" + depends on DRM_I915 + default n + select STACKDEPOT + select STACKTRACE + select DRM_I915_TRACK_WAKEREF + help + Choose this option to turn on extra state checking and usage + tracking for the wakerefPM functionality. This may introduce + overhead during driver runtime. + + If in doubt, say "N" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/d= rm/i915/gem/i915_gem_execbuffer.c index 13c975da77474..4b6c144f706da 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -252,6 +252,7 @@ struct i915_execbuffer { struct intel_gt *gt; /* gt for the execbuf */ struct intel_context *context; /* logical state for the request */ struct i915_gem_context *gem_context; /** caller's context */ + intel_wakeref_t wakeref; =20 /** our requests to build */ struct i915_request *requests[MAX_ENGINE_INSTANCE + 1]; @@ -2679,7 +2680,7 @@ eb_select_engine(struct i915_execbuffer *eb) =20 for_each_child(ce, child) intel_context_get(child); - intel_gt_pm_get(ce->engine->gt); + eb->wakeref =3D intel_gt_pm_get(ce->engine->gt); =20 if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) { err =3D intel_context_alloc_state(ce); @@ -2713,7 +2714,7 @@ eb_select_engine(struct i915_execbuffer *eb) return err; =20 err: - intel_gt_pm_put(ce->engine->gt); + intel_gt_pm_put(ce->engine->gt, eb->wakeref); for_each_child(ce, child) intel_context_put(child); intel_context_put(ce); @@ -2725,7 +2726,7 @@ eb_put_engine(struct i915_execbuffer *eb) { struct intel_context *child; =20 - intel_gt_pm_put(eb->gt); + intel_gt_pm_put(eb->context->engine->gt, eb->wakeref); for_each_child(eb->context, child) intel_context_put(child); intel_context_put(eb->context); diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c b/driv= ers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c index 13b088cc787eb..553f2730c2a76 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c @@ -85,6 +85,7 @@ static int cpu_get(struct context *ctx, unsigned long off= set, u32 *v) =20 static int gtt_set(struct context *ctx, unsigned long offset, u32 v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err =3D 0; @@ -99,7 +100,7 @@ static int gtt_set(struct context *ctx, unsigned long of= fset, u32 v) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); =20 map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -112,12 +113,13 @@ static int gtt_set(struct context *ctx, unsigned long= offset, u32 v) i915_vma_unpin_iomap(vma); =20 out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err =3D 0; @@ -132,7 +134,7 @@ static int gtt_get(struct context *ctx, unsigned long o= ffset, u32 *v) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); =20 map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -145,7 +147,7 @@ static int gtt_get(struct context *ctx, unsigned long o= ffset, u32 *v) i915_vma_unpin_iomap(vma); =20 out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/g= pu/drm/i915/gem/selftests/i915_gem_mman.c index 8ae1a1530bd80..dea5e8e39ab2d 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -624,14 +624,14 @@ static bool assert_mmap_offset(struct drm_i915_privat= e *i915, static void disable_retire_worker(struct drm_i915_private *i915) { i915_gem_driver_unregister__shrinker(i915); - intel_gt_pm_get(to_gt(i915)); + intel_gt_pm_get_untracked(to_gt(i915)); cancel_delayed_work_sync(&to_gt(i915)->requests.retire_work); } =20 static void restore_retire_worker(struct drm_i915_private *i915) { igt_flush_test(i915); - intel_gt_pm_put(to_gt(i915)); + intel_gt_pm_put_untracked(to_gt(i915)); i915_gem_driver_register__shrinker(i915); } =20 @@ -772,6 +772,7 @@ static int igt_mmap_offset_exhaustion(void *arg) =20 static int gtt_set(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err =3D 0; @@ -780,7 +781,7 @@ static int gtt_set(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -792,12 +793,13 @@ static int gtt_set(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); =20 out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 static int gtt_check(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err =3D 0; @@ -806,7 +808,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); =20 - intel_gt_pm_get(vma->vm->gt); + wakeref =3D intel_gt_pm_get(vma->vm->gt); map =3D i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -822,7 +824,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); =20 out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } =20 diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/= i915/gt/intel_breadcrumbs.c index 209cf265bf746..f061d93c27357 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -27,11 +27,14 @@ static void irq_disable(struct intel_breadcrumbs *b) =20 static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref; + /* * Since we are waiting on a request, the GPU should be busy * and should have its own rpm reference. */ - if (GEM_WARN_ON(!intel_gt_pm_get_if_awake(b->irq_engine->gt))) + wakeref =3D intel_gt_pm_get_if_awake(b->irq_engine->gt); + if (GEM_WARN_ON(!wakeref)) return; =20 /* @@ -40,7 +43,7 @@ static void __intel_breadcrumbs_arm_irq(struct intel_brea= dcrumbs *b) * which we can add a new waiter and avoid the cost of re-enabling * the irq. */ - WRITE_ONCE(b->irq_armed, true); + WRITE_ONCE(b->irq_armed, wakeref); =20 /* Requests may have completed before we could enable the interrupt. */ if (!b->irq_enabled++ && b->irq_enable(b)) @@ -60,12 +63,14 @@ static void intel_breadcrumbs_arm_irq(struct intel_brea= dcrumbs *b) =20 static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref =3D b->irq_armed; + GEM_BUG_ON(!b->irq_enabled); if (!--b->irq_enabled) b->irq_disable(b); =20 - WRITE_ONCE(b->irq_armed, false); - intel_gt_pm_put_async(b->irq_engine->gt); + WRITE_ONCE(b->irq_armed, 0); + intel_gt_pm_put_async(b->irq_engine->gt, wakeref); } =20 static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h b/drivers/gp= u/drm/i915/gt/intel_breadcrumbs_types.h index 72dfd3748c4c3..bdf09fd67b6e7 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h @@ -13,6 +13,7 @@ #include =20 #include "intel_engine_types.h" +#include "intel_wakeref.h" =20 /* * Rather than have every client wait upon all user interrupts, @@ -43,7 +44,7 @@ struct intel_breadcrumbs { spinlock_t irq_lock; /* protects the interrupt from hardirq context */ struct irq_work irq_work; /* for use from inside irq_lock */ unsigned int irq_enabled; - bool irq_armed; + intel_wakeref_t irq_armed; =20 /* Not all breadcrumbs are attached to physical HW */ intel_engine_mask_t engine_mask; diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i9= 15/gt/intel_engine_pm.c index b0a4a2dbe3ee9..52e46e7830ff5 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -47,7 +47,7 @@ static int __engine_unpark(struct intel_wakeref *wf) =20 ENGINE_TRACE(engine, "\n"); =20 - intel_gt_pm_get(engine->gt); + engine->wakeref_track =3D intel_gt_pm_get(engine->gt); =20 /* Discard stale context state from across idling */ ce =3D engine->kernel_context; @@ -260,7 +260,7 @@ static int __engine_park(struct intel_wakeref *wf) engine->park(engine); =20 /* While gt calls i915_vma_parked(), we have to break the lock cycle */ - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async(engine->gt, engine->wakeref_track); return 0; } =20 diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm= /i915/gt/intel_engine_types.h index 36365bdbe1ee7..dcd84d1eb90b7 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -382,7 +382,9 @@ struct intel_engine_cs { unsigned long serial; =20 unsigned long wakeref_serial; + intel_wakeref_t wakeref_track; struct intel_wakeref wakeref; + struct file *default_state; =20 struct { diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers= /gpu/drm/i915/gt/intel_execlists_submission.c index 961d795220a30..4ff269b2697d5 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -630,7 +630,7 @@ static void __execlists_schedule_out(struct i915_reques= t * const rq, execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT); if (engine->fw_domain && !--engine->fw_active) intel_uncore_forcewake_put(engine->uncore, engine->fw_domain); - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async_untracked(engine->gt); =20 /* * If this is part of a virtual engine, its next request may diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/g= t/intel_gt_pm.c index c0fa41e4c8030..7ee65a93f926f 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -25,19 +25,20 @@ static void user_forcewake(struct intel_gt *gt, bool suspend) { int count =3D atomic_read(>->user_wakeref); + intel_wakeref_t wakeref; =20 /* Inside suspend/resume so single threaded, no races to worry about. */ if (likely(!count)) return; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); if (suspend) { GEM_BUG_ON(count > atomic_read(>->wakeref.count)); atomic_sub(count, >->wakeref.count); } else { atomic_add(count, >->wakeref.count); } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); } =20 static void runtime_begin(struct intel_gt *gt) @@ -210,6 +211,7 @@ int intel_gt_resume(struct intel_gt *gt) { struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err; =20 err =3D intel_gt_has_unrecoverable_error(gt); @@ -226,7 +228,7 @@ int intel_gt_resume(struct intel_gt *gt) */ gt_sanitize(gt, true); =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); =20 intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); intel_rc6_sanitize(>->rc6); @@ -273,7 +275,7 @@ int intel_gt_resume(struct intel_gt *gt) =20 out_fw: intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; =20 err_wedged: diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/g= t/intel_gt_pm.h index bc898df7a48cc..3ab06d897df25 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h @@ -16,19 +16,28 @@ static inline bool intel_gt_pm_is_awake(const struct in= tel_gt *gt) return intel_wakeref_is_active(>->wakeref); } =20 -static inline void intel_gt_pm_get(struct intel_gt *gt) +static inline void intel_gt_pm_get_untracked(struct intel_gt *gt) { intel_wakeref_get(>->wakeref); } =20 +static inline intel_wakeref_t intel_gt_pm_get(struct intel_gt *gt) +{ + intel_gt_pm_get_untracked(gt); + return intel_wakeref_track(>->wakeref); +} + static inline void __intel_gt_pm_get(struct intel_gt *gt) { __intel_wakeref_get(>->wakeref); } =20 -static inline bool intel_gt_pm_get_if_awake(struct intel_gt *gt) +static inline intel_wakeref_t intel_gt_pm_get_if_awake(struct intel_gt *gt) { - return intel_wakeref_get_if_active(>->wakeref); + if (!intel_wakeref_get_if_active(>->wakeref)) + return 0; + + return intel_wakeref_track(>->wakeref); } =20 static inline void intel_gt_pm_might_get(struct intel_gt *gt) @@ -36,12 +45,18 @@ static inline void intel_gt_pm_might_get(struct intel_g= t *gt) intel_wakeref_might_get(>->wakeref); } =20 -static inline void intel_gt_pm_put(struct intel_gt *gt) +static inline void intel_gt_pm_put_untracked(struct intel_gt *gt) { intel_wakeref_put(>->wakeref); } =20 -static inline void intel_gt_pm_put_async(struct intel_gt *gt) +static inline void intel_gt_pm_put(struct intel_gt *gt, intel_wakeref_t ha= ndle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_untracked(gt); +} + +static inline void intel_gt_pm_put_async_untracked(struct intel_gt *gt) { intel_wakeref_put_async(>->wakeref); } @@ -51,9 +66,14 @@ static inline void intel_gt_pm_might_put(struct intel_gt= *gt) intel_wakeref_might_put(>->wakeref); } =20 -#define with_intel_gt_pm(gt, tmp) \ - for (tmp =3D 1, intel_gt_pm_get(gt); tmp; \ - intel_gt_pm_put(gt), tmp =3D 0) +static inline void intel_gt_pm_put_async(struct intel_gt *gt, intel_wakere= f_t handle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_async_untracked(gt); +} + +#define with_intel_gt_pm(gt, wf) \ + for (wf =3D intel_gt_pm_get(gt); wf; intel_gt_pm_put(gt, wf), wf =3D 0) =20 static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt) { diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/dr= m/i915/gt/intel_gt_pm_debugfs.c index 37765919fe322..e02a3e26e0d02 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -26,7 +26,7 @@ int intel_gt_pm_debugfs_forcewake_user_open(struct intel_gt *gt) { atomic_inc(>->user_wakeref); - intel_gt_pm_get(gt); + intel_gt_pm_get_untracked(gt); if (GRAPHICS_VER(gt->i915) >=3D 6) intel_uncore_forcewake_user_get(gt->uncore); =20 @@ -37,7 +37,7 @@ int intel_gt_pm_debugfs_forcewake_user_release(struct int= el_gt *gt) { if (GRAPHICS_VER(gt->i915) >=3D 6) intel_uncore_forcewake_user_put(gt->uncore); - intel_gt_pm_put(gt); + intel_gt_pm_put_untracked(gt); atomic_dec(>->user_wakeref); =20 return 0; diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm= /i915/gt/selftest_engine_cs.c index 1b75f478d1b83..8ea6bf4c987e2 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c @@ -21,20 +21,22 @@ static int cmp_u32(const void *A, const void *B) return *a - *b; } =20 -static void perf_begin(struct intel_gt *gt) +static intel_wakeref_t perf_begin(struct intel_gt *gt) { - intel_gt_pm_get(gt); + intel_wakeref_t wakeref =3D intel_gt_pm_get(gt); =20 /* Boost gpufreq to max [waitboost] and keep it fixed */ atomic_inc(>->rps.num_waiters); schedule_work(>->rps.work); flush_work(>->rps.work); + + return wakeref; } =20 -static int perf_end(struct intel_gt *gt) +static int perf_end(struct intel_gt *gt, intel_wakeref_t wakeref) { atomic_dec(>->rps.num_waiters); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return igt_flush_test(gt->i915); } @@ -123,12 +125,13 @@ static int perf_mi_bb_start(void *arg) struct intel_gt *gt =3D arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */ return 0; =20 - perf_begin(gt); + wakeref =3D perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce =3D engine->kernel_context; struct i915_vma *batch; @@ -194,7 +197,7 @@ static int perf_mi_bb_start(void *arg) pr_info("%s: MI_BB_START cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err =3D -EIO; =20 return err; @@ -247,12 +250,13 @@ static int perf_mi_noop(void *arg) struct intel_gt *gt =3D arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */ return 0; =20 - perf_begin(gt); + wakeref =3D perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce =3D engine->kernel_context; struct i915_vma *base, *nop; @@ -348,7 +352,7 @@ static int perf_mi_noop(void *arg) pr_info("%s: 16K MI_NOOP cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err =3D -EIO; =20 return err; diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i91= 5/gt/selftest_gt_pm.c index be94f863bdeff..f0f9983a6fbb2 100644 --- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c @@ -68,6 +68,7 @@ static int live_gt_clocks(void *arg) struct intel_gt *gt =3D arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 if (!gt->clock_frequency) { /* unknown */ @@ -97,7 +98,7 @@ static int live_gt_clocks(void *arg) */ return 0; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); =20 for_each_engine(engine, gt, id) { @@ -134,7 +135,7 @@ static int live_gt_clocks(void *arg) } =20 intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i91= 5/gt/selftest_reset.c index 37c38bdd5f474..cb01901c94e94 100644 --- a/drivers/gpu/drm/i915/gt/selftest_reset.c +++ b/drivers/gpu/drm/i915/gt/selftest_reset.c @@ -257,11 +257,12 @@ static int igt_atomic_reset(void *arg) { struct intel_gt *gt =3D arg; const typeof(*igt_atomic_phases) *p; + intel_wakeref_t wakeref; int err =3D 0; =20 /* Check that the resets are usable from atomic context */ =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); igt_global_reset_lock(gt); =20 /* Flush any requests before we get started and check basics */ @@ -292,7 +293,7 @@ static int igt_atomic_reset(void *arg) =20 unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return err; } @@ -303,6 +304,7 @@ static int igt_atomic_engine_reset(void *arg) const typeof(*igt_atomic_phases) *p; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err =3D 0; =20 /* Check that the resets are usable from atomic context */ @@ -313,7 +315,7 @@ static int igt_atomic_engine_reset(void *arg) if (intel_uc_uses_guc_submission(>->uc)) return 0; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); igt_global_reset_lock(gt); =20 /* Flush any requests before we get started and check basics */ @@ -361,7 +363,7 @@ static int igt_atomic_engine_reset(void *arg) =20 out_unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/= gt/selftest_rps.c index 6a69ac0184ad8..7effd09ced988 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rps.c +++ b/drivers/gpu/drm/i915/gt/selftest_rps.c @@ -223,6 +223,7 @@ int live_rps_clock_interval(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err =3D 0; =20 if (!intel_rps_is_enabled(rps) || GRAPHICS_VER(gt->i915) < 6) @@ -235,7 +236,7 @@ int live_rps_clock_interval(void *arg) saved_work =3D rps->work.func; rps->work.func =3D dummy_rps_work; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); intel_rps_disable(>->rps); =20 intel_gt_check_clock_frequency(gt); @@ -354,7 +355,7 @@ int live_rps_clock_interval(void *arg) } =20 intel_rps_enable(>->rps); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 igt_spinner_fini(&spin); =20 @@ -375,6 +376,7 @@ int live_rps_control(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err =3D 0; =20 /* @@ -397,7 +399,7 @@ int live_rps_control(void *arg) saved_work =3D rps->work.func; rps->work.func =3D dummy_rps_work; =20 - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; ktime_t min_dt, max_dt; @@ -487,7 +489,7 @@ int live_rps_control(void *arg) break; } } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); =20 igt_spinner_fini(&spin); =20 @@ -1026,6 +1028,7 @@ int live_rps_interrupt(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; u32 pm_events; int err =3D 0; =20 @@ -1036,9 +1039,9 @@ int live_rps_interrupt(void *arg) if (!intel_rps_has_interrupts(rps) || GRAPHICS_VER(gt->i915) < 6) return 0; =20 - intel_gt_pm_get(gt); - pm_events =3D rps->pm_events; - intel_gt_pm_put(gt); + pm_events =3D 0; + with_intel_gt_pm(gt, wakeref) + pm_events =3D rps->pm_events; if (!pm_events) { pr_err("No RPS PM events registered, but RPS is enabled?\n"); return -ENODEV; diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915= /gt/selftest_slpc.c index b768cea5943dd..27be3c9b29b13 100644 --- a/drivers/gpu/drm/i915/gt/selftest_slpc.c +++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c @@ -44,6 +44,7 @@ static int live_slpc_clamp_min(void *arg) struct intel_rps *rps =3D >->rps; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; struct igt_spinner spin; u32 slpc_min_freq, slpc_max_freq; int err =3D 0; @@ -70,7 +71,7 @@ static int live_slpc_clamp_min(void *arg) } =20 intel_gt_pm_wait_for_idle(gt); - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; u32 step, min_freq, req_freq; @@ -156,7 +157,7 @@ static int live_slpc_clamp_min(void *arg) if (igt_flush_test(gt->i915)) err =3D -EIO; =20 - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); intel_gt_pm_wait_for_idle(gt); =20 @@ -171,6 +172,7 @@ static int live_slpc_clamp_max(void *arg) struct intel_rps *rps; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; struct igt_spinner spin; int err =3D 0; u32 slpc_min_freq, slpc_max_freq; @@ -200,7 +202,7 @@ static int live_slpc_clamp_max(void *arg) } =20 intel_gt_pm_wait_for_idle(gt); - intel_gt_pm_get(gt); + wakeref =3D intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; u32 max_freq, req_freq; @@ -290,7 +292,7 @@ static int live_slpc_clamp_max(void *arg) slpc_set_max_freq(slpc, slpc_max_freq); slpc_set_min_freq(slpc, slpc_min_freq); =20 - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); intel_gt_pm_wait_for_idle(gt); =20 diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gp= u/drm/i915/gt/uc/intel_guc_submission.c index b3a429a92c0da..7799939c38945 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1048,7 +1048,7 @@ static void scrub_guc_desc_for_outstanding_g2h(struct= intel_guc *guc) if (deregister) guc_signal_context_fence(ce); if (destroyed) { - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } @@ -1254,6 +1254,7 @@ static ktime_t guc_engine_busyness(struct intel_engin= e_cs *engine, ktime_t *now) unsigned long flags; u32 reset_count; bool in_reset; + intel_wakeref_t wakeref; =20 spin_lock_irqsave(&guc->timestamp.lock, flags); =20 @@ -1276,7 +1277,7 @@ static ktime_t guc_engine_busyness(struct intel_engin= e_cs *engine, ktime_t *now) * start_gt_clk is derived from GuC state. To get a consistent * view of activity, we query the GuC state only if gt is awake. */ - if (!in_reset && intel_gt_pm_get_if_awake(gt)) { + if (!in_reset && (wakeref =3D intel_gt_pm_get_if_awake(gt))) { stats_saved =3D *stats; gt_stamp_saved =3D guc->timestamp.gt_stamp; /* @@ -1285,7 +1286,7 @@ static ktime_t guc_engine_busyness(struct intel_engin= e_cs *engine, ktime_t *now) */ guc_update_engine_gt_clks(engine); guc_update_pm_timestamp(guc, now); - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); if (i915_reset_count(gpu_error) !=3D reset_count) { *stats =3D stats_saved; guc->timestamp.gt_stamp =3D gt_stamp_saved; @@ -3903,7 +3904,7 @@ int intel_guc_deregister_done_process_msg(struct inte= l_guc *guc, intel_context_put(ce); } else if (context_destroyed(ce)) { /* Context has been destroyed */ - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pm= u.c index cfc21042499d0..3bd0c75c2ee69 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -171,19 +171,19 @@ static u64 get_rc6(struct intel_gt *gt) { struct drm_i915_private *i915 =3D gt->i915; struct i915_pmu *pmu =3D &i915->pmu; + intel_wakeref_t wakeref; unsigned long flags; - bool awake =3D false; u64 val; =20 - if (intel_gt_pm_get_if_awake(gt)) { + wakeref =3D intel_gt_pm_get_if_awake(gt); + if (wakeref) { val =3D __get_rc6(gt); - intel_gt_pm_put_async(gt); - awake =3D true; + intel_gt_pm_put_async(gt, wakeref); } =20 spin_lock_irqsave(&pmu->lock, flags); =20 - if (awake) { + if (wakeref) { pmu->sample[__I915_SAMPLE_RC6].cur =3D val; } else { /* @@ -377,12 +377,14 @@ frequency_sample(struct intel_gt *gt, unsigned int pe= riod_ns) struct intel_uncore *uncore =3D gt->uncore; struct i915_pmu *pmu =3D &i915->pmu; struct intel_rps *rps =3D >->rps; + intel_wakeref_t wakeref; =20 if (!frequency_sampling_enabled(pmu)) return; =20 /* Report 0/0 (actual/requested) frequency while parked. */ - if (!intel_gt_pm_get_if_awake(gt)) + wakeref =3D intel_gt_pm_get_if_awake(gt); + if (!wakeref) return; =20 if (pmu->enable & config_mask(I915_PMU_ACTUAL_FREQUENCY)) { @@ -413,7 +415,7 @@ frequency_sample(struct intel_gt *gt, unsigned int peri= od_ns) period_ns / 1000); } =20 - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); } =20 static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/in= tel_wakeref.c index dfd87d0822180..db4887e33ea60 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -108,6 +108,10 @@ void __intel_wakeref_init(struct intel_wakeref *wf, INIT_DELAYED_WORK(&wf->work, __intel_wakeref_put_work); lockdep_init_map(&wf->work.work.lockdep_map, "wakeref.work", &key->work, 0); + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + intel_wakeref_tracker_init(&wf->debug); +#endif } =20 int intel_wakeref_wait_for_idle(struct intel_wakeref *wf) diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/in= tel_wakeref.h index e6ba389652d74..38439deefc5cc 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -43,6 +43,10 @@ struct intel_wakeref { const struct intel_wakeref_ops *ops; =20 struct delayed_work work; + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + struct intel_wakeref_tracker debug; +#endif }; =20 struct intel_wakeref_lockclass { @@ -262,6 +266,44 @@ __intel_wakeref_defer_park(struct intel_wakeref *wf) */ int intel_wakeref_wait_for_idle(struct intel_wakeref *wf); =20 +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return intel_wakeref_tracker_add(&wf->debug); +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ + intel_wakeref_tracker_remove(&wf->debug, handle); +} + +static inline void intel_wakeref_show(struct intel_wakeref *wf, + struct drm_printer *p) +{ + intel_wakeref_tracker_show(&wf->debug, p); +} + +#else + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return -1; +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ +} + +static inline void intel_wakeref_show(struct intel_wakeref *wf, + struct drm_printer *p) +{ +} + +#endif + struct intel_wakeref_auto { struct intel_runtime_pm *rpm; struct timer_list timer; --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B0F1DC433F5 for ; Mon, 21 Feb 2022 23:20:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236679AbiBUXUn (ORCPT ); Mon, 21 Feb 2022 18:20:43 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:35194 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236737AbiBUXTy (ORCPT ); Mon, 21 Feb 2022 18:19:54 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D8BDF25E93; Mon, 21 Feb 2022 15:18:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485514; x=1677021514; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JVXkGTgMk0f0BZi0vzDMp/6U04Z0YVjDjG523a9A54I=; b=lrP+PaA3wb2lQS8gMMtrU+QaCIbJtIVLrXYUlrw77ciR465csEmM4mPm W1wXc9vKGM6DaEE3RmUa7nHnT3yK3gb9EwgU8vzV8J2udbm4O+lV1x2Yk 1Z3RyFCTPsxsvzRhIdBXaFhjOXI/BLzNQuot1dGfZFX9J9uggXPPIyAB8 d40TRstYpx4lXBPkiMT+fvfTLXbwELxCXmH/ej+H/gHJ+nCtXreF+C0z1 Wre6M2rLUHYWSaoA93E4aa77Lr5ZAvWz4FcQtdLhYgdoz4jA7jSlZvQvV V+rixVT735IsLJX5HXKxzAC3xGzfI/YM+LMGIOHk/hAo091+2NrL29CbD Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530478" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530478" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:27 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694636" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:25 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 10/11] drm/i915: Correct type of wakeref variable Date: Tue, 22 Feb 2022 00:17:04 +0100 Message-Id: <20220221231705.1481059-23-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Wakeref has dedicated type. Assumption it will be int compatible forever is incorrect. Signed-off-by: Andrzej Hajda --- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gp= u/drm/i915/gt/uc/intel_guc_submission.c index 7799939c38945..b308dd0866eaf 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -2797,7 +2797,7 @@ static void destroyed_worker_func(struct work_struct = *w) struct intel_guc *guc =3D container_of(w, struct intel_guc, submission_state.destroyed_worker); struct intel_gt *gt =3D guc_to_gt(guc); - int tmp; + intel_wakeref_t tmp; =20 with_intel_gt_pm(gt, tmp) deregister_destroyed_contexts(guc); --=20 2.25.1 From nobody Fri Jun 26 16:01:25 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DA55BC433F5 for ; Mon, 21 Feb 2022 23:20:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236538AbiBUXUi (ORCPT ); Mon, 21 Feb 2022 18:20:38 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:34498 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236464AbiBUXUX (ORCPT ); Mon, 21 Feb 2022 18:20:23 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D8CE25EBC; Mon, 21 Feb 2022 15:18:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645485518; x=1677021518; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+cYQCtajtLHF13wD1Ab8Zm6c/BiUXjG1ZHacvq+QS4Q=; b=dG8ply9p6ZTMbhYxIB7AtYT9wM+4pYImkUpb8oOL/ZqzsJRxeANzy53N nbiqTpfBJUdWRl8VYYg/YGQRREwSRTDOzleC2/sGiyuY9StMnTY31v78G tloTRVWCO7imFP9V7waA8v0N2ydFDdTfAMYvG6HQ0ALLAjrQ7Yg9gLmaH XaGVsUFnoJAndJFZ1uFnElCuUjhAp/24qkqp9nSsxJJ6crZHXjy+GAqZk Rx5t7+KTnLxRD45BRL9FUdIc6JxiKGgmzcR06KnaSQEnfDK6h+Raska0d +knN4Yf0qOQCna1azbifm1/ZZiM+XKpXzs0ZDTutLpis06bNBhAK2hIe3 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10265"; a="251530483" X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="251530483" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:30 -0800 X-IronPort-AV: E=Sophos;i="5.88,386,1635231600"; d="scan'208";a="638694648" Received: from lab-ah.igk.intel.com ([10.91.215.196]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2022 15:18:28 -0800 From: Andrzej Hajda To: linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, netdev Cc: Andrzej Hajda , Jani Nikula , Daniel Vetter , Lucas De Marchi , Chris Wilson , Eric Dumazet , Dmitry Vyukov , Jakub Kicinski Subject: [PATCH v2 11/11] drm/i915: replace Intel internal tracker with kernel core ref_tracker Date: Tue, 22 Feb 2022 00:17:05 +0100 Message-Id: <20220221231705.1481059-24-andrzej.hajda@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220221231705.1481059-1-andrzej.hajda@intel.com> References: <20220221231705.1481059-1-andrzej.hajda@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Beside reusing existing code, the main advantage of ref_tracker is tracking per instance of wakeref. It allows also to catch double put. On the other side we lose information about the first acquire and the last release, but the advantages outweigh it. Signed-off-by: Andrzej Hajda Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/Kconfig.debug | 11 +- drivers/gpu/drm/i915/Makefile | 3 - .../drm/i915/display/intel_display_power.c | 2 +- drivers/gpu/drm/i915/gt/intel_engine_pm.c | 2 +- drivers/gpu/drm/i915/gt/intel_gt_pm.c | 2 +- drivers/gpu/drm/i915/intel_runtime_pm.c | 25 +- drivers/gpu/drm/i915/intel_runtime_pm.h | 2 +- drivers/gpu/drm/i915/intel_wakeref.c | 8 +- drivers/gpu/drm/i915/intel_wakeref.h | 72 +++++- drivers/gpu/drm/i915/intel_wakeref_tracker.c | 234 ------------------ drivers/gpu/drm/i915/intel_wakeref_tracker.h | 76 ------ 11 files changed, 87 insertions(+), 350 deletions(-) delete mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.c delete mode 100644 drivers/gpu/drm/i915/intel_wakeref_tracker.h diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kcon= fig.debug index 3bdc73f30a9e1..6c57f3e265f20 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -32,6 +32,7 @@ config DRM_I915_DEBUG select DEBUG_FS select PREEMPT_COUNT select I2C_CHARDEV + select REF_TRACKER select STACKDEPOT select STACKTRACE select DRM_DP_AUX_CHARDEV @@ -46,7 +47,6 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_GEM select DRM_I915_DEBUG_GEM_ONCE select DRM_I915_DEBUG_MMIO - select DRM_I915_TRACK_WAKEREF select DRM_I915_DEBUG_RUNTIME_PM select DRM_I915_DEBUG_WAKEREF select DRM_I915_SW_FENCE_DEBUG_OBJECTS @@ -238,18 +238,13 @@ config DRM_I915_DEBUG_VBLANK_EVADE =20 If in doubt, say "N". =20 -config DRM_I915_TRACK_WAKEREF - depends on STACKDEPOT - depends on STACKTRACE - bool - config DRM_I915_DEBUG_RUNTIME_PM bool "Enable extra state checking for runtime PM" depends on DRM_I915 default n + select REF_TRACKER select STACKDEPOT select STACKTRACE - select DRM_I915_TRACK_WAKEREF help Choose this option to turn on extra state checking for the runtime PM functionality. This may introduce overhead during @@ -263,9 +258,9 @@ config DRM_I915_DEBUG_WAKEREF bool "Enable extra tracking for wakerefs" depends on DRM_I915 default n + select REF_TRACKER select STACKDEPOT select STACKTRACE - select DRM_I915_TRACK_WAKEREF help Choose this option to turn on extra state checking and usage tracking for the wakerefPM functionality. This may introduce diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 88a403d3294cb..1f8d71430e2e6 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -76,9 +76,6 @@ i915-$(CONFIG_DEBUG_FS) +=3D \ display/intel_display_debugfs.o \ display/intel_pipe_crc.o =20 -i915-$(CONFIG_DRM_I915_TRACK_WAKEREF) +=3D \ - intel_wakeref_tracker.o - i915-$(CONFIG_PERF_EVENTS) +=3D i915_pmu.o =20 # "Graphics Technology" (aka we talk to the gpu) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/g= pu/drm/i915/display/intel_display_power.c index 9ebae7ac32356..0e1bf724f89b5 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -2107,7 +2107,7 @@ print_async_put_domains_state(struct i915_power_domai= ns *power_domains) struct drm_i915_private, power_domains); =20 - drm_dbg(&i915->drm, "async_put_wakeref %u\n", + drm_dbg(&i915->drm, "async_put_wakeref %lu\n", power_domains->async_put_wakeref); =20 print_power_domains(power_domains, "async_put_domains[0]", diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i9= 15/gt/intel_engine_pm.c index 52e46e7830ff5..cf8cc348942cb 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -273,7 +273,7 @@ void intel_engine_init__pm(struct intel_engine_cs *engi= ne) { struct intel_runtime_pm *rpm =3D engine->uncore->rpm; =20 - intel_wakeref_init(&engine->wakeref, rpm, &wf_ops); + intel_wakeref_init(&engine->wakeref, rpm, &wf_ops, engine->name); intel_engine_init_heartbeat(engine); } =20 diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/g= t/intel_gt_pm.c index 7ee65a93f926f..01a055d0d0989 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -129,7 +129,7 @@ static const struct intel_wakeref_ops wf_ops =3D { =20 void intel_gt_pm_init_early(struct intel_gt *gt) { - intel_wakeref_init(>->wakeref, gt->uncore->rpm, &wf_ops); + intel_wakeref_init(>->wakeref, gt->uncore->rpm, &wf_ops, "GT"); seqcount_mutex_init(>->stats.lock, >->wakeref.mutex); } =20 diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915= /intel_runtime_pm.c index 7bd10efa56bf3..18e4b2f169e75 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -54,35 +54,35 @@ =20 static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - intel_wakeref_tracker_init(&rpm->debug); + ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, dev_name(rpm= ->kdev)); } =20 static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - if (!rpm->available) + if (!rpm->available || rpm->no_wakeref_tracking) return -1; =20 - return intel_wakeref_tracker_add(&rpm->debug); + return intel_ref_tracker_alloc(&rpm->debug); } =20 static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, intel_wakeref_t wakeref) { - intel_wakeref_tracker_remove(&rpm->debug, wakeref); + if (!rpm->available || rpm->no_wakeref_tracking) + return; + + intel_ref_tracker_free(&rpm->debug, wakeref); } =20 static void untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm = *rpm) { - struct drm_printer p =3D drm_debug_printer("i915"); - - intel_wakeref_tracker_reset(&rpm->debug, &p); + ref_tracker_dir_exit(&rpm->debug); } =20 static noinline void __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) { - struct intel_wakeref_tracker saved; unsigned long flags; =20 if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count, @@ -90,15 +90,8 @@ __intel_wakeref_dec_and_check_tracking(struct intel_runt= ime_pm *rpm) flags)) return; =20 - saved =3D __intel_wakeref_tracker_reset(&rpm->debug); + __ref_tracker_dir_print(&rpm->debug, INTEL_REFTRACK_PRINT_LIMIT); spin_unlock_irqrestore(&rpm->debug.lock, flags); - - if (saved.count) { - struct drm_printer p =3D drm_debug_printer("i915"); - - __intel_wakeref_tracker_show(&saved, &p); - intel_wakeref_tracker_fini(&saved); - } } =20 void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915= /intel_runtime_pm.h index 0871fa2176474..db5692f1eb67e 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -61,7 +61,7 @@ struct intel_runtime_pm { * paired rpm_put) we can remove corresponding pairs of and keep * the array trimmed to active wakerefs. */ - struct intel_wakeref_tracker debug; + struct ref_tracker_dir debug; #endif }; =20 diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/in= tel_wakeref.c index db4887e33ea60..97fe9a0f0adbd 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -62,6 +62,9 @@ static void ____intel_wakeref_put_last(struct intel_waker= ef *wf) if (likely(!wf->ops->put(wf))) { rpm_put(wf); wake_up_var(&wf->wakeref); +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + ref_tracker_dir_exit(&wf->debug); +#endif } =20 unlock: @@ -96,7 +99,8 @@ static void __intel_wakeref_put_work(struct work_struct *= wrk) void __intel_wakeref_init(struct intel_wakeref *wf, struct intel_runtime_pm *rpm, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key) + struct intel_wakeref_lockclass *key, + const char *name) { wf->rpm =3D rpm; wf->ops =3D ops; @@ -110,7 +114,7 @@ void __intel_wakeref_init(struct intel_wakeref *wf, "wakeref.work", &key->work, 0); =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) - intel_wakeref_tracker_init(&wf->debug); + ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, name); #endif } =20 diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/in= tel_wakeref.h index 38439deefc5cc..e0cd78fb60761 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -7,17 +7,24 @@ #ifndef INTEL_WAKEREF_H #define INTEL_WAKEREF_H =20 +#include + #include #include #include #include #include #include +#include +#include #include #include #include =20 -#include "intel_wakeref_tracker.h" +typedef unsigned long intel_wakeref_t; + +#define INTEL_REFTRACK_DEAD_COUNT 16 +#define INTEL_REFTRACK_PRINT_LIMIT 16 =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) @@ -45,7 +52,7 @@ struct intel_wakeref { struct delayed_work work; =20 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) - struct intel_wakeref_tracker debug; + struct ref_tracker_dir debug; #endif }; =20 @@ -57,11 +64,12 @@ struct intel_wakeref_lockclass { void __intel_wakeref_init(struct intel_wakeref *wf, struct intel_runtime_pm *rpm, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key); -#define intel_wakeref_init(wf, rpm, ops) do { \ + struct intel_wakeref_lockclass *key, + const char *name); +#define intel_wakeref_init(wf, rpm, ops, name) do { \ static struct intel_wakeref_lockclass __key; \ \ - __intel_wakeref_init((wf), (rpm), (ops), &__key); \ + __intel_wakeref_init((wf), (rpm), (ops), &__key, name); \ } while (0) =20 int __intel_wakeref_get_first(struct intel_wakeref *wf); @@ -266,17 +274,67 @@ __intel_wakeref_defer_park(struct intel_wakeref *wf) */ int intel_wakeref_wait_for_idle(struct intel_wakeref *wf); =20 +#define INTEL_WAKEREF_DEF ((intel_wakeref_t)(-1)) + +static inline intel_wakeref_t intel_ref_tracker_alloc(struct ref_tracker_d= ir *dir) +{ + struct ref_tracker *user =3D NULL; + + ref_tracker_alloc(dir, &user, GFP_NOWAIT); + + return (intel_wakeref_t)user ?: INTEL_WAKEREF_DEF; +} + +static inline void intel_ref_tracker_free(struct ref_tracker_dir *dir, + intel_wakeref_t handle) +{ + struct ref_tracker *user; + + user =3D (handle =3D=3D INTEL_WAKEREF_DEF) ? NULL : (void *)handle; + + ref_tracker_free(dir, &user); +} + +static inline void +intel_wakeref_tracker_show(struct ref_tracker_dir *dir, + struct drm_printer *p) +{ + const size_t buf_size =3D PAGE_SIZE; + char *buf, *sb, *se; + size_t count; + + buf =3D kmalloc(buf_size, GFP_NOWAIT); + if (!buf) + return; + + count =3D ref_tracker_dir_snprint(dir, buf, buf_size); + if (!count) + goto free; + /* printk does not like big buffers, so we split it */ + for (sb =3D buf; *sb; sb =3D se + 1) { + se =3D strchrnul(sb, '\n'); + drm_printf(p, "%.*s", (int)(se - sb + 1), sb); + if (!*se) + break; + } + if (count >=3D buf_size) + drm_printf(p, "\n...dropped %zd extra bytes of leak report.\n", + count + 1 - buf_size); +free: + kfree(buf); +} + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) =20 static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) { - return intel_wakeref_tracker_add(&wf->debug); + return intel_ref_tracker_alloc(&wf->debug); } =20 static inline void intel_wakeref_untrack(struct intel_wakeref *wf, intel_wakeref_t handle) { - intel_wakeref_tracker_remove(&wf->debug, handle); + intel_ref_tracker_free(&wf->debug, handle); } =20 static inline void intel_wakeref_show(struct intel_wakeref *wf, diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.c b/drivers/gpu/drm= /i915/intel_wakeref_tracker.c deleted file mode 100644 index a0bcef13a1085..0000000000000 --- a/drivers/gpu/drm/i915/intel_wakeref_tracker.c +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright =C2=A9 2021 Intel Corporation - */ - -#include -#include -#include -#include - -#include - -#include "intel_wakeref.h" - -#define STACKDEPTH 8 - -static noinline depot_stack_handle_t __save_depot_stack(void) -{ - unsigned long entries[STACKDEPTH]; - unsigned int n; - - n =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); - return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); -} - -static void __print_depot_stack(depot_stack_handle_t stack, - char *buf, int sz, int indent) -{ - unsigned long *entries; - unsigned int nr_entries; - - nr_entries =3D stack_depot_fetch(stack, &entries); - stack_trace_snprint(buf, sz, entries, nr_entries, indent); -} - -static int cmphandle(const void *_a, const void *_b) -{ - const depot_stack_handle_t * const a =3D _a, * const b =3D _b; - - if (*a < *b) - return -1; - else if (*a > *b) - return 1; - else - return 0; -} - -void -__intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, - struct drm_printer *p) -{ - unsigned long i; - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - if (w->last_acquire) { - __print_depot_stack(w->last_acquire, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last acquired:\n%s", buf); - } - - if (w->last_release) { - __print_depot_stack(w->last_release, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last released:\n%s", buf); - } - - drm_printf(p, "Wakeref count: %lu\n", w->count); - - sort(w->owners, w->count, sizeof(*w->owners), cmphandle, NULL); - - for (i =3D 0; i < w->count; i++) { - depot_stack_handle_t stack =3D w->owners[i]; - unsigned long rep; - - rep =3D 1; - while (i + 1 < w->count && w->owners[i + 1] =3D=3D stack) - rep++, i++; - __print_depot_stack(stack, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); - } - - kfree(buf); -} - -void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, - struct drm_printer *p) -{ - struct intel_wakeref_tracker tmp =3D {}; - - do { - unsigned long alloc =3D tmp.count; - depot_stack_handle_t *s; - - spin_lock_irq(&w->lock); - tmp.count =3D w->count; - if (tmp.count <=3D alloc) - memcpy(tmp.owners, w->owners, tmp.count * sizeof(*s)); - tmp.last_acquire =3D w->last_acquire; - tmp.last_release =3D w->last_release; - spin_unlock_irq(&w->lock); - if (tmp.count <=3D alloc) - break; - - s =3D krealloc(tmp.owners, - tmp.count * sizeof(*s), - GFP_NOWAIT | __GFP_NOWARN); - if (!s) - goto out; - - tmp.owners =3D s; - } while (1); - - __intel_wakeref_tracker_show(&tmp, p); - -out: - intel_wakeref_tracker_fini(&tmp); -} - -intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) -{ - depot_stack_handle_t stack, *stacks; - unsigned long flags; - - stack =3D __save_depot_stack(); - if (!stack) - return -1; - - spin_lock_irqsave(&w->lock, flags); - - if (!w->count) - w->last_acquire =3D stack; - - stacks =3D krealloc(w->owners, - (w->count + 1) * sizeof(*stacks), - GFP_NOWAIT | __GFP_NOWARN); - if (stacks) { - stacks[w->count++] =3D stack; - w->owners =3D stacks; - } else { - stack =3D -1; - } - - spin_unlock_irqrestore(&w->lock, flags); - - return stack; -} - -void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, - intel_wakeref_t stack) -{ - unsigned long flags, n; - bool found =3D false; - - if (unlikely(stack =3D=3D -1)) - return; - - spin_lock_irqsave(&w->lock, flags); - for (n =3D w->count; n--; ) { - if (w->owners[n] =3D=3D stack) { - memmove(w->owners + n, - w->owners + n + 1, - (--w->count - n) * sizeof(stack)); - found =3D true; - break; - } - } - spin_unlock_irqrestore(&w->lock, flags); - - if (WARN(!found, - "Unmatched wakeref %x, tracking %lu\n", - stack, w->count)) { - char *buf; - - buf =3D kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - __print_depot_stack(stack, buf, PAGE_SIZE, 2); - pr_err("wakeref %x from\n%s", stack, buf); - - stack =3D READ_ONCE(w->last_release); - if (stack && !w->count) { - __print_depot_stack(stack, buf, PAGE_SIZE, 2); - pr_err("wakeref last released at\n%s", buf); - } - - kfree(buf); - } -} - -struct intel_wakeref_tracker -__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) -{ - struct intel_wakeref_tracker saved; - - lockdep_assert_held(&w->lock); - - saved =3D *w; - - w->owners =3D NULL; - w->count =3D 0; - w->last_release =3D __save_depot_stack(); - - return saved; -} - -void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, - struct drm_printer *p) -{ - struct intel_wakeref_tracker tmp; - - spin_lock_irq(&w->lock); - tmp =3D __intel_wakeref_tracker_reset(w); - spin_unlock_irq(&w->lock); - - if (tmp.count) - __intel_wakeref_tracker_show(&tmp, p); - - intel_wakeref_tracker_fini(&tmp); -} - -void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w) -{ - memset(w, 0, sizeof(*w)); - spin_lock_init(&w->lock); - stack_depot_init(); -} - -void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w) -{ - kfree(w->owners); -} diff --git a/drivers/gpu/drm/i915/intel_wakeref_tracker.h b/drivers/gpu/drm= /i915/intel_wakeref_tracker.h deleted file mode 100644 index 61df68e28c0fb..0000000000000 --- a/drivers/gpu/drm/i915/intel_wakeref_tracker.h +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright =C2=A9 2019 Intel Corporation - */ - -#ifndef INTEL_WAKEREF_TRACKER_H -#define INTEL_WAKEREF_TRACKER_H - -#include -#include -#include - -typedef depot_stack_handle_t intel_wakeref_t; - -struct drm_printer; - -struct intel_wakeref_tracker { - spinlock_t lock; - - depot_stack_handle_t last_acquire; - depot_stack_handle_t last_release; - - depot_stack_handle_t *owners; - unsigned long count; -}; - -#if IS_ENABLED(CONFIG_DRM_I915_TRACK_WAKEREF) - -void intel_wakeref_tracker_init(struct intel_wakeref_tracker *w); -void intel_wakeref_tracker_fini(struct intel_wakeref_tracker *w); - -intel_wakeref_t intel_wakeref_tracker_add(struct intel_wakeref_tracker *w); -void intel_wakeref_tracker_remove(struct intel_wakeref_tracker *w, - intel_wakeref_t handle); - -struct intel_wakeref_tracker -__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w); -void intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w, - struct drm_printer *p); - -void __intel_wakeref_tracker_show(const struct intel_wakeref_tracker *w, - struct drm_printer *p); -void intel_wakeref_tracker_show(struct intel_wakeref_tracker *w, - struct drm_printer *p); - -#else - -static inline void intel_wakeref_tracker_init(struct intel_wakeref_tracker= *w) {} -static inline void intel_wakeref_tracker_fini(struct intel_wakeref_tracker= *w) {} - -static inline intel_wakeref_t -intel_wakeref_tracker_add(struct intel_wakeref_tracker *w) -{ - return -1; -} - -static inline void -intel_wakeref_untrack_remove(struct intel_wakeref_tracker *w, intel_wakere= f_t handle) {} - -static inline struct intel_wakeref_tracker -__intel_wakeref_tracker_reset(struct intel_wakeref_tracker *w) -{ - return (struct intel_wakeref_tracker){}; -} - -static inline void intel_wakeref_tracker_reset(struct intel_wakeref_tracke= r *w, - struct drm_printer *p) -{ -} - -static inline void __intel_wakeref_tracker_show(const struct intel_wakeref= _tracker *w, struct drm_printer *p) {} -static inline void intel_wakeref_tracker_show(struct intel_wakeref_tracker= *w, struct drm_printer *p) {} - -#endif - -#endif /* INTEL_WAKEREF_TRACKER_H */ --=20 2.25.1