1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. 4 */ 5 6 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ 7 8 #include "msm_disp_snapshot.h" 9 10 static ssize_t __maybe_unused disp_devcoredump_read(char *buffer, loff_t offset, 11 size_t count, void *data, size_t datalen) 12 { 13 struct drm_print_iterator iter; 14 struct drm_printer p; 15 struct msm_disp_state *disp_state; 16 17 disp_state = data; 18 19 iter.data = buffer; 20 iter.offset = 0; 21 iter.start = offset; 22 iter.remain = count; 23 24 p = drm_coredump_printer(&iter); 25 26 msm_disp_state_print(disp_state, &p); 27 28 return count - iter.remain; 29 } 30 31 static void _msm_disp_snapshot_work(struct kthread_work *work) 32 { 33 struct msm_kms *kms = container_of(work, struct msm_kms, dump_work); 34 struct drm_device *drm_dev = kms->dev; 35 struct msm_disp_state *disp_state; 36 struct drm_printer p; 37 38 disp_state = kzalloc(sizeof(struct msm_disp_state), GFP_KERNEL); 39 if (!disp_state) 40 return; 41 42 disp_state->dev = drm_dev->dev; 43 disp_state->drm_dev = drm_dev; 44 45 INIT_LIST_HEAD(&disp_state->blocks); 46 47 /* Serialize dumping here */ 48 mutex_lock(&kms->dump_mutex); 49 50 msm_disp_snapshot_capture_state(disp_state); 51 52 mutex_unlock(&kms->dump_mutex); 53 54 if (MSM_DISP_SNAPSHOT_DUMP_IN_CONSOLE) { 55 p = drm_info_printer(disp_state->drm_dev->dev); 56 msm_disp_state_print(disp_state, &p); 57 } 58 59 /* 60 * If COREDUMP is disabled, the stub will call the free function. 61 * If there is a codedump pending for the device, the dev_coredumpm() 62 * will also free new coredump state. 63 */ 64 dev_coredumpm(disp_state->dev, THIS_MODULE, disp_state, 0, GFP_KERNEL, 65 disp_devcoredump_read, msm_disp_state_free); 66 } 67 68 void msm_disp_snapshot_state(struct drm_device *drm_dev) 69 { 70 struct msm_drm_private *priv; 71 struct msm_kms *kms; 72 73 if (!drm_dev) { 74 DRM_ERROR("invalid params\n"); 75 return; 76 } 77 78 priv = drm_dev->dev_private; 79 kms = priv->kms; 80 81 kthread_queue_work(kms->dump_worker, &kms->dump_work); 82 } 83 84 int msm_disp_snapshot_init(struct drm_device *drm_dev) 85 { 86 struct msm_drm_private *priv; 87 struct msm_kms *kms; 88 89 if (!drm_dev) { 90 DRM_ERROR("invalid params\n"); 91 return -EINVAL; 92 } 93 94 priv = drm_dev->dev_private; 95 kms = priv->kms; 96 97 mutex_init(&kms->dump_mutex); 98 99 kms->dump_worker = kthread_create_worker(0, "%s", "disp_snapshot"); 100 if (IS_ERR(kms->dump_worker)) 101 DRM_ERROR("failed to create disp state task\n"); 102 103 kthread_init_work(&kms->dump_work, _msm_disp_snapshot_work); 104 105 return 0; 106 } 107 108 void msm_disp_snapshot_destroy(struct drm_device *drm_dev) 109 { 110 struct msm_kms *kms; 111 struct msm_drm_private *priv; 112 113 if (!drm_dev) { 114 DRM_ERROR("invalid params\n"); 115 return; 116 } 117 118 priv = drm_dev->dev_private; 119 kms = priv->kms; 120 121 if (kms->dump_worker) 122 kthread_destroy_worker(kms->dump_worker); 123 124 mutex_destroy(&kms->dump_mutex); 125 } 126