DF-4732 / fix.diff
--- a/sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -115,7 +115,10 @@ struct amdgpu_display_manager { struct common_irq_params vblank_params[DC_IRQ_SOURCE_VBLANK6 - DC_IRQ_SOURCE_VBLANK1 + 1]; - /* this spin lock synchronizes access to 'irq_handler_list_table' */ - spinlock_t irq_handler_list_table_lock; + /* + * This spin lock synchronizes access to 'irq_handler_list_table'. + * It is a true DragonFly spinlock: it is acquired from the GPU + * interrupt dispatch path (amdgpu_dm_irq_immediate_work / + * amdgpu_dm_irq_schedule_work), where sleeping (lockmgr) is illegal. + */ + struct spinlock irq_handler_list_table_lock; struct backlight_device *backlight_dev; --- a/sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -50,10 +50,18 @@ struct amdgpu_dm_irq_handler_data { enum dc_irq_source irq_source; }; +/* + * The table lock is taken from the GPU ISR dispatch path (see + * amdgpu_dm_irq_handler below), which runs in serialized interrupt-thread + * context via request_irq()->bus_setup_intr(). The Linux shim's + * spin_lock_irqsave() maps to a *sleepable* lockmgr acquisition, which may + * not be performed from an ithread. Use a true DragonFly spinlock wrapped + * in a critical section instead (equivalent to upstream's irqsave spinlock). + */ #define DM_IRQ_TABLE_LOCK(adev, flags) \ - spin_lock_irqsave(&adev->dm.irq_handler_list_table_lock, flags) + do { \ + crit_enter(); \ + spin_lock(&adev->dm.irq_handler_list_table_lock); \ + (void)(flags); \ + } while (0) #define DM_IRQ_TABLE_UNLOCK(adev, flags) \ - spin_unlock_irqrestore(&adev->dm.irq_handler_list_table_lock, flags) + do { \ + spin_unlock(&adev->dm.irq_handler_list_table_lock); \ + crit_exit(); \ + } while (0) @@ -303,8 +311,7 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev) DRM_DEBUG_KMS("DM_IRQ\n"); - lockinit(&adev->dm.irq_handler_list_table_lock, "agdmihltl", 0, LK_CANRECURSE); + spin_init(&adev->dm.irq_handler_list_table_lock, "agdmihltl"); for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) { /* low context handler list init */ |