LCOV - code coverage report
Current view: top level - drivers/gpu/drm/virtio - virtgpu_kms.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 154 0.0 %
Date: 2022-04-01 14:17:54 Functions: 0 8 0.0 %
Branches: 0 56 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2015 Red Hat, Inc.
       3                 :            :  * All Rights Reserved.
       4                 :            :  *
       5                 :            :  * Permission is hereby granted, free of charge, to any person obtaining
       6                 :            :  * a copy of this software and associated documentation files (the
       7                 :            :  * "Software"), to deal in the Software without restriction, including
       8                 :            :  * without limitation the rights to use, copy, modify, merge, publish,
       9                 :            :  * distribute, sublicense, and/or sell copies of the Software, and to
      10                 :            :  * permit persons to whom the Software is furnished to do so, subject to
      11                 :            :  * the following conditions:
      12                 :            :  *
      13                 :            :  * The above copyright notice and this permission notice (including the
      14                 :            :  * next paragraph) shall be included in all copies or substantial
      15                 :            :  * portions of the Software.
      16                 :            :  *
      17                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      18                 :            :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      19                 :            :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      20                 :            :  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
      21                 :            :  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      22                 :            :  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      23                 :            :  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      24                 :            :  */
      25                 :            : 
      26                 :            : #include <linux/virtio.h>
      27                 :            : #include <linux/virtio_config.h>
      28                 :            : 
      29                 :            : #include <drm/drm_file.h>
      30                 :            : 
      31                 :            : #include "virtgpu_drv.h"
      32                 :            : 
      33                 :          0 : static void virtio_gpu_config_changed_work_func(struct work_struct *work)
      34                 :            : {
      35                 :          0 :         struct virtio_gpu_device *vgdev =
      36                 :          0 :                 container_of(work, struct virtio_gpu_device,
      37                 :            :                              config_changed_work);
      38                 :          0 :         u32 events_read, events_clear = 0;
      39                 :            : 
      40                 :            :         /* read the config space */
      41                 :          0 :         virtio_cread(vgdev->vdev, struct virtio_gpu_config,
      42                 :            :                      events_read, &events_read);
      43         [ #  # ]:          0 :         if (events_read & VIRTIO_GPU_EVENT_DISPLAY) {
      44         [ #  # ]:          0 :                 if (vgdev->has_edid)
      45                 :          0 :                         virtio_gpu_cmd_get_edids(vgdev);
      46                 :          0 :                 virtio_gpu_cmd_get_display_info(vgdev);
      47                 :          0 :                 drm_helper_hpd_irq_event(vgdev->ddev);
      48                 :          0 :                 events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
      49                 :            :         }
      50                 :          0 :         virtio_cwrite(vgdev->vdev, struct virtio_gpu_config,
      51                 :            :                       events_clear, &events_clear);
      52                 :          0 : }
      53                 :            : 
      54                 :          0 : static int virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
      55                 :            :                                       uint32_t nlen, const char *name)
      56                 :            : {
      57                 :          0 :         int handle = ida_alloc(&vgdev->ctx_id_ida, GFP_KERNEL);
      58                 :            : 
      59         [ #  # ]:          0 :         if (handle < 0)
      60                 :            :                 return handle;
      61                 :          0 :         handle += 1;
      62                 :          0 :         virtio_gpu_cmd_context_create(vgdev, handle, nlen, name);
      63                 :          0 :         return handle;
      64                 :            : }
      65                 :            : 
      66                 :          0 : static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev,
      67                 :            :                                       uint32_t ctx_id)
      68                 :            : {
      69                 :          0 :         virtio_gpu_cmd_context_destroy(vgdev, ctx_id);
      70                 :          0 :         ida_free(&vgdev->ctx_id_ida, ctx_id - 1);
      71                 :            : }
      72                 :            : 
      73                 :          0 : static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
      74                 :            :                                void (*work_func)(struct work_struct *work))
      75                 :            : {
      76                 :          0 :         spin_lock_init(&vgvq->qlock);
      77                 :          0 :         init_waitqueue_head(&vgvq->ack_queue);
      78                 :          0 :         INIT_WORK(&vgvq->dequeue_work, work_func);
      79                 :            : }
      80                 :            : 
      81                 :          0 : static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev,
      82                 :            :                                    int num_capsets)
      83                 :            : {
      84                 :          0 :         int i, ret;
      85                 :            : 
      86                 :          0 :         vgdev->capsets = kcalloc(num_capsets,
      87                 :            :                                  sizeof(struct virtio_gpu_drv_capset),
      88                 :            :                                  GFP_KERNEL);
      89         [ #  # ]:          0 :         if (!vgdev->capsets) {
      90                 :          0 :                 DRM_ERROR("failed to allocate cap sets\n");
      91                 :          0 :                 return;
      92                 :            :         }
      93         [ #  # ]:          0 :         for (i = 0; i < num_capsets; i++) {
      94                 :          0 :                 virtio_gpu_cmd_get_capset_info(vgdev, i);
      95   [ #  #  #  #  :          0 :                 ret = wait_event_timeout(vgdev->resp_wq,
                   #  # ]
      96                 :            :                                          vgdev->capsets[i].id > 0, 5 * HZ);
      97         [ #  # ]:          0 :                 if (ret == 0) {
      98                 :          0 :                         DRM_ERROR("timed out waiting for cap set %d\n", i);
      99                 :          0 :                         kfree(vgdev->capsets);
     100                 :          0 :                         vgdev->capsets = NULL;
     101                 :          0 :                         return;
     102                 :            :                 }
     103                 :          0 :                 DRM_INFO("cap set %d: id %d, max-version %d, max-size %d\n",
     104                 :            :                          i, vgdev->capsets[i].id,
     105                 :            :                          vgdev->capsets[i].max_version,
     106                 :            :                          vgdev->capsets[i].max_size);
     107                 :            :         }
     108                 :          0 :         vgdev->num_capsets = num_capsets;
     109                 :            : }
     110                 :            : 
     111                 :          0 : int virtio_gpu_init(struct drm_device *dev)
     112                 :            : {
     113                 :          0 :         static vq_callback_t *callbacks[] = {
     114                 :            :                 virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack
     115                 :            :         };
     116                 :          0 :         static const char * const names[] = { "control", "cursor" };
     117                 :            : 
     118                 :          0 :         struct virtio_gpu_device *vgdev;
     119                 :            :         /* this will expand later */
     120                 :          0 :         struct virtqueue *vqs[2];
     121                 :          0 :         u32 num_scanouts, num_capsets;
     122                 :          0 :         int ret;
     123                 :            : 
     124         [ #  # ]:          0 :         if (!virtio_has_feature(dev_to_virtio(dev->dev), VIRTIO_F_VERSION_1))
     125                 :            :                 return -ENODEV;
     126                 :            : 
     127                 :          0 :         vgdev = kzalloc(sizeof(struct virtio_gpu_device), GFP_KERNEL);
     128         [ #  # ]:          0 :         if (!vgdev)
     129                 :            :                 return -ENOMEM;
     130                 :            : 
     131                 :          0 :         vgdev->ddev = dev;
     132                 :          0 :         dev->dev_private = vgdev;
     133                 :          0 :         vgdev->vdev = dev_to_virtio(dev->dev);
     134                 :          0 :         vgdev->dev = dev->dev;
     135                 :            : 
     136                 :          0 :         spin_lock_init(&vgdev->display_info_lock);
     137                 :          0 :         ida_init(&vgdev->ctx_id_ida);
     138                 :          0 :         ida_init(&vgdev->resource_ida);
     139                 :          0 :         init_waitqueue_head(&vgdev->resp_wq);
     140                 :          0 :         virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func);
     141                 :          0 :         virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func);
     142                 :            : 
     143                 :          0 :         vgdev->fence_drv.context = dma_fence_context_alloc(1);
     144                 :          0 :         spin_lock_init(&vgdev->fence_drv.lock);
     145                 :          0 :         INIT_LIST_HEAD(&vgdev->fence_drv.fences);
     146                 :          0 :         INIT_LIST_HEAD(&vgdev->cap_cache);
     147                 :          0 :         INIT_WORK(&vgdev->config_changed_work,
     148                 :            :                   virtio_gpu_config_changed_work_func);
     149                 :            : 
     150                 :          0 :         INIT_WORK(&vgdev->obj_free_work,
     151                 :            :                   virtio_gpu_array_put_free_work);
     152                 :          0 :         INIT_LIST_HEAD(&vgdev->obj_free_list);
     153                 :          0 :         spin_lock_init(&vgdev->obj_free_lock);
     154                 :            : 
     155                 :            : #ifdef __LITTLE_ENDIAN
     156         [ #  # ]:          0 :         if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VIRGL))
     157                 :          0 :                 vgdev->has_virgl_3d = true;
     158                 :            : #endif
     159         [ #  # ]:          0 :         if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) {
     160                 :          0 :                 vgdev->has_edid = true;
     161                 :            :         }
     162                 :            : 
     163   [ #  #  #  # ]:          0 :         DRM_INFO("features: %cvirgl %cedid\n",
     164                 :            :                  vgdev->has_virgl_3d ? '+' : '-',
     165                 :            :                  vgdev->has_edid     ? '+' : '-');
     166                 :            : 
     167                 :          0 :         ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL);
     168         [ #  # ]:          0 :         if (ret) {
     169                 :          0 :                 DRM_ERROR("failed to find virt queues\n");
     170                 :          0 :                 goto err_vqs;
     171                 :            :         }
     172                 :          0 :         vgdev->ctrlq.vq = vqs[0];
     173                 :          0 :         vgdev->cursorq.vq = vqs[1];
     174                 :          0 :         ret = virtio_gpu_alloc_vbufs(vgdev);
     175         [ #  # ]:          0 :         if (ret) {
     176                 :          0 :                 DRM_ERROR("failed to alloc vbufs\n");
     177                 :          0 :                 goto err_vbufs;
     178                 :            :         }
     179                 :            : 
     180                 :            :         /* get display info */
     181                 :          0 :         virtio_cread(vgdev->vdev, struct virtio_gpu_config,
     182                 :            :                      num_scanouts, &num_scanouts);
     183                 :          0 :         vgdev->num_scanouts = min_t(uint32_t, num_scanouts,
     184                 :            :                                     VIRTIO_GPU_MAX_SCANOUTS);
     185         [ #  # ]:          0 :         if (!vgdev->num_scanouts) {
     186                 :          0 :                 DRM_ERROR("num_scanouts is zero\n");
     187                 :          0 :                 ret = -EINVAL;
     188                 :          0 :                 goto err_scanouts;
     189                 :            :         }
     190                 :          0 :         DRM_INFO("number of scanouts: %d\n", num_scanouts);
     191                 :            : 
     192                 :          0 :         virtio_cread(vgdev->vdev, struct virtio_gpu_config,
     193                 :            :                      num_capsets, &num_capsets);
     194                 :          0 :         DRM_INFO("number of cap sets: %d\n", num_capsets);
     195                 :            : 
     196                 :          0 :         virtio_gpu_modeset_init(vgdev);
     197                 :            : 
     198                 :          0 :         virtio_device_ready(vgdev->vdev);
     199                 :          0 :         vgdev->vqs_ready = true;
     200                 :            : 
     201         [ #  # ]:          0 :         if (num_capsets)
     202                 :          0 :                 virtio_gpu_get_capsets(vgdev, num_capsets);
     203         [ #  # ]:          0 :         if (vgdev->has_edid)
     204                 :          0 :                 virtio_gpu_cmd_get_edids(vgdev);
     205                 :          0 :         virtio_gpu_cmd_get_display_info(vgdev);
     206   [ #  #  #  #  :          0 :         wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending,
                   #  # ]
     207                 :            :                            5 * HZ);
     208                 :            :         return 0;
     209                 :            : 
     210                 :            : err_scanouts:
     211                 :          0 :         virtio_gpu_free_vbufs(vgdev);
     212                 :          0 : err_vbufs:
     213                 :          0 :         vgdev->vdev->config->del_vqs(vgdev->vdev);
     214                 :          0 : err_vqs:
     215                 :          0 :         kfree(vgdev);
     216                 :          0 :         return ret;
     217                 :            : }
     218                 :            : 
     219                 :          0 : static void virtio_gpu_cleanup_cap_cache(struct virtio_gpu_device *vgdev)
     220                 :            : {
     221                 :          0 :         struct virtio_gpu_drv_cap_cache *cache_ent, *tmp;
     222                 :            : 
     223         [ #  # ]:          0 :         list_for_each_entry_safe(cache_ent, tmp, &vgdev->cap_cache, head) {
     224                 :          0 :                 kfree(cache_ent->caps_cache);
     225                 :          0 :                 kfree(cache_ent);
     226                 :            :         }
     227                 :          0 : }
     228                 :            : 
     229                 :          0 : void virtio_gpu_deinit(struct drm_device *dev)
     230                 :            : {
     231                 :          0 :         struct virtio_gpu_device *vgdev = dev->dev_private;
     232                 :            : 
     233                 :          0 :         flush_work(&vgdev->obj_free_work);
     234                 :          0 :         vgdev->vqs_ready = false;
     235                 :          0 :         flush_work(&vgdev->ctrlq.dequeue_work);
     236                 :          0 :         flush_work(&vgdev->cursorq.dequeue_work);
     237                 :          0 :         flush_work(&vgdev->config_changed_work);
     238                 :          0 :         vgdev->vdev->config->reset(vgdev->vdev);
     239                 :          0 :         vgdev->vdev->config->del_vqs(vgdev->vdev);
     240                 :            : 
     241                 :          0 :         virtio_gpu_modeset_fini(vgdev);
     242                 :          0 :         virtio_gpu_free_vbufs(vgdev);
     243                 :          0 :         virtio_gpu_cleanup_cap_cache(vgdev);
     244                 :          0 :         kfree(vgdev->capsets);
     245                 :          0 :         kfree(vgdev);
     246                 :          0 : }
     247                 :            : 
     248                 :          0 : int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
     249                 :            : {
     250                 :          0 :         struct virtio_gpu_device *vgdev = dev->dev_private;
     251                 :          0 :         struct virtio_gpu_fpriv *vfpriv;
     252                 :          0 :         int id;
     253                 :          0 :         char dbgname[TASK_COMM_LEN];
     254                 :            : 
     255                 :            :         /* can't create contexts without 3d renderer */
     256         [ #  # ]:          0 :         if (!vgdev->has_virgl_3d)
     257                 :            :                 return 0;
     258                 :            : 
     259                 :            :         /* allocate a virt GPU context for this opener */
     260                 :          0 :         vfpriv = kzalloc(sizeof(*vfpriv), GFP_KERNEL);
     261         [ #  # ]:          0 :         if (!vfpriv)
     262                 :            :                 return -ENOMEM;
     263                 :            : 
     264                 :          0 :         get_task_comm(dbgname, current);
     265                 :          0 :         id = virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname);
     266         [ #  # ]:          0 :         if (id < 0) {
     267                 :          0 :                 kfree(vfpriv);
     268                 :          0 :                 return id;
     269                 :            :         }
     270                 :            : 
     271                 :          0 :         vfpriv->ctx_id = id;
     272                 :          0 :         file->driver_priv = vfpriv;
     273                 :          0 :         return 0;
     274                 :            : }
     275                 :            : 
     276                 :          0 : void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file)
     277                 :            : {
     278                 :          0 :         struct virtio_gpu_device *vgdev = dev->dev_private;
     279                 :          0 :         struct virtio_gpu_fpriv *vfpriv;
     280                 :            : 
     281         [ #  # ]:          0 :         if (!vgdev->has_virgl_3d)
     282                 :            :                 return;
     283                 :            : 
     284                 :          0 :         vfpriv = file->driver_priv;
     285                 :            : 
     286                 :          0 :         virtio_gpu_context_destroy(vgdev, vfpriv->ctx_id);
     287                 :          0 :         kfree(vfpriv);
     288                 :          0 :         file->driver_priv = NULL;
     289                 :            : }

Generated by: LCOV version 1.14