Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/amd/display: Fix multi-display support for idle opt workqueue

[Why]
The current implementation for idle optimization support only has a
single work item that gets reshuffled into the system workqueue
whenever we receive an enable or disable event.

We can have mismatched events if the work hasn't been processed or if
we're getting control events from multiple displays at once.

This fixes this issue and also makes the implementation usable for
PSR control - which will be addressed in another patch.

[How]
We need to be able to flush remaining work out on demand for driver stop
and psr disable so create a driver specific workqueue instead of using
the system one. The workqueue will be single threaded to guarantee the
ordering of enable/disable events.

Refactor the queue to allocate the control work and deallocate it
after processing it.

Pass the acrtc directly to make it easier to handle psr enable/disable
in a later patch.

Rename things to indicate that it's not just MALL specific.

Reviewed-by: Roman Li <Roman.Li@amd.com>
Acked-by: Wayne Lin <wayne.lin@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Nicholas Kazlauskas and committed by
Alex Deucher
09a5df6c 58de0ef2

+36 -47
+25 -37
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 1044 1044 } 1045 1045 #endif 1046 1046 #if defined(CONFIG_DRM_AMD_DC_DCN) 1047 - static void event_mall_stutter(struct work_struct *work) 1047 + static void vblank_control_worker(struct work_struct *work) 1048 1048 { 1049 - 1050 - struct vblank_workqueue *vblank_work = container_of(work, struct vblank_workqueue, mall_work); 1049 + struct vblank_control_work *vblank_work = 1050 + container_of(work, struct vblank_control_work, work); 1051 1051 struct amdgpu_display_manager *dm = vblank_work->dm; 1052 1052 1053 1053 mutex_lock(&dm->dc_lock); ··· 1062 1062 DRM_DEBUG_KMS("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0); 1063 1063 1064 1064 mutex_unlock(&dm->dc_lock); 1065 + kfree(vblank_work); 1065 1066 } 1066 1067 1067 - static struct vblank_workqueue *vblank_create_workqueue(struct amdgpu_device *adev, struct dc *dc) 1068 - { 1069 - struct vblank_workqueue *vblank_work; 1070 - 1071 - vblank_work = kzalloc(sizeof(*vblank_work), GFP_KERNEL); 1072 - if (ZERO_OR_NULL_PTR(vblank_work)) { 1073 - kfree(vblank_work); 1074 - return NULL; 1075 - } 1076 - 1077 - INIT_WORK(&vblank_work->mall_work, event_mall_stutter); 1078 - 1079 - return vblank_work; 1080 - } 1081 1068 #endif 1082 1069 static int amdgpu_dm_init(struct amdgpu_device *adev) 1083 1070 { ··· 1207 1220 1208 1221 #if defined(CONFIG_DRM_AMD_DC_DCN) 1209 1222 if (adev->dm.dc->caps.max_links > 0) { 1210 - adev->dm.vblank_workqueue = vblank_create_workqueue(adev, adev->dm.dc); 1211 - 1212 - if (!adev->dm.vblank_workqueue) 1223 + adev->dm.vblank_control_workqueue = 1224 + create_singlethread_workqueue("dm_vblank_control_workqueue"); 1225 + if (!adev->dm.vblank_control_workqueue) 1213 1226 DRM_ERROR("amdgpu: failed to initialize vblank_workqueue.\n"); 1214 - else 1215 - DRM_DEBUG_DRIVER("amdgpu: vblank_workqueue init done %p.\n", adev->dm.vblank_workqueue); 1216 1227 } 1217 1228 #endif 1218 1229 ··· 1283 1298 { 1284 1299 int i; 1285 1300 1301 + #if defined(CONFIG_DRM_AMD_DC_DCN) 1302 + if (adev->dm.vblank_control_workqueue) { 1303 + destroy_workqueue(adev->dm.vblank_control_workqueue); 1304 + adev->dm.vblank_control_workqueue = NULL; 1305 + } 1306 + #endif 1307 + 1286 1308 for (i = 0; i < adev->dm.display_indexes_num; i++) { 1287 1309 drm_encoder_cleanup(&adev->dm.mst_encoders[i].base); 1288 1310 } ··· 1311 1319 1312 1320 if (adev->dm.dc) 1313 1321 dc_deinit_callbacks(adev->dm.dc); 1314 - #endif 1315 - 1316 - #if defined(CONFIG_DRM_AMD_DC_DCN) 1317 - if (adev->dm.vblank_workqueue) { 1318 - adev->dm.vblank_workqueue->dm = NULL; 1319 - kfree(adev->dm.vblank_workqueue); 1320 - adev->dm.vblank_workqueue = NULL; 1321 - } 1322 1322 #endif 1323 1323 1324 1324 dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); ··· 5984 6000 struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); 5985 6001 #if defined(CONFIG_DRM_AMD_DC_DCN) 5986 6002 struct amdgpu_display_manager *dm = &adev->dm; 5987 - unsigned long flags; 6003 + struct vblank_control_work *work; 5988 6004 #endif 5989 6005 int rc = 0; 5990 6006 ··· 6009 6025 return 0; 6010 6026 6011 6027 #if defined(CONFIG_DRM_AMD_DC_DCN) 6012 - spin_lock_irqsave(&dm->vblank_lock, flags); 6013 - dm->vblank_workqueue->dm = dm; 6014 - dm->vblank_workqueue->otg_inst = acrtc->otg_inst; 6015 - dm->vblank_workqueue->enable = enable; 6016 - spin_unlock_irqrestore(&dm->vblank_lock, flags); 6017 - schedule_work(&dm->vblank_workqueue->mall_work); 6028 + work = kzalloc(sizeof(*work), GFP_ATOMIC); 6029 + if (!work) 6030 + return -ENOMEM; 6031 + 6032 + INIT_WORK(&work->work, vblank_control_worker); 6033 + work->dm = dm; 6034 + work->acrtc = acrtc; 6035 + work->enable = enable; 6036 + 6037 + queue_work(dm->vblank_control_workqueue, &work->work); 6018 6038 #endif 6019 6039 6020 6040 return 0;
+11 -10
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
··· 60 60 61 61 /* Forward declarations */ 62 62 struct amdgpu_device; 63 + struct amdgpu_crtc; 63 64 struct drm_device; 64 65 struct dc; 65 66 struct amdgpu_bo; ··· 87 86 }; 88 87 89 88 /** 90 - * struct vblank_workqueue - Works to be executed in a separate thread during vblank 91 - * @mall_work: work for mall stutter 89 + * struct vblank_control_work - Work data for vblank control 90 + * @work: Kernel work data for the work event 92 91 * @dm: amdgpu display manager device 93 - * @otg_inst: otg instance of which vblank is being set 94 - * @enable: true if enable vblank 92 + * @acrtc: amdgpu CRTC instance for which the event has occurred 93 + * @enable: true if enabling vblank 95 94 */ 96 - struct vblank_workqueue { 97 - struct work_struct mall_work; 95 + struct vblank_control_work { 96 + struct work_struct work; 98 97 struct amdgpu_display_manager *dm; 99 - int otg_inst; 98 + struct amdgpu_crtc *acrtc; 100 99 bool enable; 101 100 }; 102 101 ··· 381 380 382 381 #if defined(CONFIG_DRM_AMD_DC_DCN) 383 382 /** 384 - * @vblank_workqueue: 383 + * @vblank_control_workqueue: 385 384 * 386 - * amdgpu workqueue during vblank 385 + * Deferred work for vblank control events. 387 386 */ 388 - struct vblank_workqueue *vblank_workqueue; 387 + struct workqueue_struct *vblank_control_workqueue; 389 388 #endif 390 389 391 390 struct drm_atomic_state *cached_state;