drm/xe: Fix potential deadlock in __fini_dbm
authorMichal Wajdeczko <michal.wajdeczko@intel.com>
Thu, 11 Jan 2024 18:56:03 +0000 (19:56 +0100)
committerMichal Wajdeczko <michal.wajdeczko@intel.com>
Fri, 12 Jan 2024 10:53:05 +0000 (11:53 +0100)
If Doorbell Manager is in unclean state during fini phase, for
debug purposes we try to print it's state, but we missed the fact
that we are already holding a lock so the xe_guc_db_mgr_print()
will deadlock since it also attempts to grab the same lock.

Fixes: 587c73343ac7 ("drm/xe: Introduce GuC Doorbells Manager")
Cc: Piotr Piórkowski <piotr.piorkowski@intel.com>
Reviewed-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Link: https://lore.kernel.org/r/20240111185603.673-1-michal.wajdeczko@intel.com
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
drivers/gpu/drm/xe/xe_guc_db_mgr.c

index c1c04575d82d92f3e973016ab385fcb42672c0b9..8d9a0287df6b9b4d047e532c2bdb9891270ac8a8 100644 (file)
@@ -46,6 +46,8 @@ static struct xe_device *dbm_to_xe(struct xe_guc_db_mgr *dbm)
 #define dbm_assert(_dbm, _cond)                xe_gt_assert(dbm_to_gt(_dbm), _cond)
 #define dbm_mutex(_dbm)                        (&dbm_to_guc(_dbm)->submission_state.lock)
 
+static void dbm_print_locked(struct xe_guc_db_mgr *dbm, struct drm_printer *p, int indent);
+
 static void __fini_dbm(struct drm_device *drm, void *arg)
 {
        struct xe_guc_db_mgr *dbm = arg;
@@ -59,7 +61,7 @@ static void __fini_dbm(struct drm_device *drm, void *arg)
 
                xe_gt_err(dbm_to_gt(dbm), "GuC doorbells manager unclean (%u/%u)\n",
                          weight, dbm->count);
-               xe_guc_db_mgr_print(dbm, &p, 1);
+               dbm_print_locked(dbm, &p, 1);
        }
 
        bitmap_free(dbm->bitmap);
@@ -219,14 +221,7 @@ void xe_guc_db_mgr_release_range(struct xe_guc_db_mgr *dbm,
        mutex_unlock(dbm_mutex(dbm));
 }
 
-/**
- * xe_guc_db_mgr_print() - Print status of GuC Doorbells Manager.
- * @dbm: the &xe_guc_db_mgr to print
- * @p: the &drm_printer to print to
- * @indent: tab indentation level
- */
-void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm,
-                        struct drm_printer *p, int indent)
+static void dbm_print_locked(struct xe_guc_db_mgr *dbm, struct drm_printer *p, int indent)
 {
        unsigned int rs, re;
        unsigned int total;
@@ -235,8 +230,6 @@ void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm,
        if (!dbm->bitmap)
                return;
 
-       mutex_lock(dbm_mutex(dbm));
-
        total = 0;
        for_each_clear_bitrange(rs, re, dbm->bitmap, dbm->count) {
                drm_printf_indent(p, indent, "available range: %u..%u (%u)\n",
@@ -252,7 +245,19 @@ void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm,
                total += re - rs;
        }
        drm_printf_indent(p, indent, "reserved total: %u\n", total);
+}
 
+/**
+ * xe_guc_db_mgr_print() - Print status of GuC Doorbells Manager.
+ * @dbm: the &xe_guc_db_mgr to print
+ * @p: the &drm_printer to print to
+ * @indent: tab indentation level
+ */
+void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm,
+                        struct drm_printer *p, int indent)
+{
+       mutex_lock(dbm_mutex(dbm));
+       dbm_print_locked(dbm, p, indent);
        mutex_unlock(dbm_mutex(dbm));
 }