linux/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c
<<
>>
Prefs
   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
  10static 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
  31struct msm_disp_state *
  32msm_disp_snapshot_state_sync(struct msm_kms *kms)
  33{
  34        struct drm_device *drm_dev = kms->dev;
  35        struct msm_disp_state *disp_state;
  36
  37        WARN_ON(!mutex_is_locked(&kms->dump_mutex));
  38
  39        disp_state = kzalloc(sizeof(struct msm_disp_state), GFP_KERNEL);
  40        if (!disp_state)
  41                return ERR_PTR(-ENOMEM);
  42
  43        disp_state->dev = drm_dev->dev;
  44        disp_state->drm_dev = drm_dev;
  45
  46        INIT_LIST_HEAD(&disp_state->blocks);
  47
  48        msm_disp_snapshot_capture_state(disp_state);
  49
  50        return disp_state;
  51}
  52
  53static void _msm_disp_snapshot_work(struct kthread_work *work)
  54{
  55        struct msm_kms *kms = container_of(work, struct msm_kms, dump_work);
  56        struct msm_disp_state *disp_state;
  57        struct drm_printer p;
  58
  59        /* Serialize dumping here */
  60        mutex_lock(&kms->dump_mutex);
  61        disp_state = msm_disp_snapshot_state_sync(kms);
  62        mutex_unlock(&kms->dump_mutex);
  63
  64        if (IS_ERR(disp_state))
  65                return;
  66
  67        if (MSM_DISP_SNAPSHOT_DUMP_IN_CONSOLE) {
  68                p = drm_info_printer(disp_state->drm_dev->dev);
  69                msm_disp_state_print(disp_state, &p);
  70        }
  71
  72        /*
  73         * If COREDUMP is disabled, the stub will call the free function.
  74         * If there is a codedump pending for the device, the dev_coredumpm()
  75         * will also free new coredump state.
  76         */
  77        dev_coredumpm(disp_state->dev, THIS_MODULE, disp_state, 0, GFP_KERNEL,
  78                        disp_devcoredump_read, msm_disp_state_free);
  79}
  80
  81void msm_disp_snapshot_state(struct drm_device *drm_dev)
  82{
  83        struct msm_drm_private *priv;
  84        struct msm_kms *kms;
  85
  86        if (!drm_dev) {
  87                DRM_ERROR("invalid params\n");
  88                return;
  89        }
  90
  91        priv = drm_dev->dev_private;
  92        kms = priv->kms;
  93
  94        kthread_queue_work(kms->dump_worker, &kms->dump_work);
  95}
  96
  97int msm_disp_snapshot_init(struct drm_device *drm_dev)
  98{
  99        struct msm_drm_private *priv;
 100        struct msm_kms *kms;
 101
 102        if (!drm_dev) {
 103                DRM_ERROR("invalid params\n");
 104                return -EINVAL;
 105        }
 106
 107        priv = drm_dev->dev_private;
 108        kms = priv->kms;
 109
 110        mutex_init(&kms->dump_mutex);
 111
 112        kms->dump_worker = kthread_create_worker(0, "%s", "disp_snapshot");
 113        if (IS_ERR(kms->dump_worker))
 114                DRM_ERROR("failed to create disp state task\n");
 115
 116        kthread_init_work(&kms->dump_work, _msm_disp_snapshot_work);
 117
 118        return 0;
 119}
 120
 121void msm_disp_snapshot_destroy(struct drm_device *drm_dev)
 122{
 123        struct msm_kms *kms;
 124        struct msm_drm_private *priv;
 125
 126        if (!drm_dev) {
 127                DRM_ERROR("invalid params\n");
 128                return;
 129        }
 130
 131        priv = drm_dev->dev_private;
 132        kms = priv->kms;
 133
 134        if (kms->dump_worker)
 135                kthread_destroy_worker(kms->dump_worker);
 136
 137        mutex_destroy(&kms->dump_mutex);
 138}
 139