162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2015 Red Hat, Inc. 362306a36Sopenharmony_ci * All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 662306a36Sopenharmony_ci * a copy of this software and associated documentation files (the 762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 962306a36Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to 1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1162306a36Sopenharmony_ci * the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1462306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial 1562306a36Sopenharmony_ci * portions of the Software. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1862306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1962306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 2062306a36Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 2162306a36Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 2262306a36Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2362306a36Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/virtio.h> 2762306a36Sopenharmony_ci#include <linux/virtio_config.h> 2862306a36Sopenharmony_ci#include <linux/virtio_ring.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <drm/drm_file.h> 3162306a36Sopenharmony_ci#include <drm/drm_managed.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "virtgpu_drv.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void virtio_gpu_config_changed_work_func(struct work_struct *work) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct virtio_gpu_device *vgdev = 3862306a36Sopenharmony_ci container_of(work, struct virtio_gpu_device, 3962306a36Sopenharmony_ci config_changed_work); 4062306a36Sopenharmony_ci u32 events_read, events_clear = 0; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* read the config space */ 4362306a36Sopenharmony_ci virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, 4462306a36Sopenharmony_ci events_read, &events_read); 4562306a36Sopenharmony_ci if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { 4662306a36Sopenharmony_ci if (vgdev->num_scanouts) { 4762306a36Sopenharmony_ci if (vgdev->has_edid) 4862306a36Sopenharmony_ci virtio_gpu_cmd_get_edids(vgdev); 4962306a36Sopenharmony_ci virtio_gpu_cmd_get_display_info(vgdev); 5062306a36Sopenharmony_ci virtio_gpu_notify(vgdev); 5162306a36Sopenharmony_ci drm_helper_hpd_irq_event(vgdev->ddev); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci events_clear |= VIRTIO_GPU_EVENT_DISPLAY; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci virtio_cwrite_le(vgdev->vdev, struct virtio_gpu_config, 5662306a36Sopenharmony_ci events_clear, &events_clear); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, 6062306a36Sopenharmony_ci void (*work_func)(struct work_struct *work)) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci spin_lock_init(&vgvq->qlock); 6362306a36Sopenharmony_ci init_waitqueue_head(&vgvq->ack_queue); 6462306a36Sopenharmony_ci INIT_WORK(&vgvq->dequeue_work, work_func); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, 6862306a36Sopenharmony_ci int num_capsets) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int i, ret; 7162306a36Sopenharmony_ci bool invalid_capset_id = false; 7262306a36Sopenharmony_ci struct drm_device *drm = vgdev->ddev; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci vgdev->capsets = drmm_kcalloc(drm, num_capsets, 7562306a36Sopenharmony_ci sizeof(struct virtio_gpu_drv_capset), 7662306a36Sopenharmony_ci GFP_KERNEL); 7762306a36Sopenharmony_ci if (!vgdev->capsets) { 7862306a36Sopenharmony_ci DRM_ERROR("failed to allocate cap sets\n"); 7962306a36Sopenharmony_ci return; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci for (i = 0; i < num_capsets; i++) { 8262306a36Sopenharmony_ci virtio_gpu_cmd_get_capset_info(vgdev, i); 8362306a36Sopenharmony_ci virtio_gpu_notify(vgdev); 8462306a36Sopenharmony_ci ret = wait_event_timeout(vgdev->resp_wq, 8562306a36Sopenharmony_ci vgdev->capsets[i].id > 0, 5 * HZ); 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * Capability ids are defined in the virtio-gpu spec and are 8862306a36Sopenharmony_ci * between 1 to 63, inclusive. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci if (!vgdev->capsets[i].id || 9162306a36Sopenharmony_ci vgdev->capsets[i].id > MAX_CAPSET_ID) 9262306a36Sopenharmony_ci invalid_capset_id = true; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (ret == 0) 9562306a36Sopenharmony_ci DRM_ERROR("timed out waiting for cap set %d\n", i); 9662306a36Sopenharmony_ci else if (invalid_capset_id) 9762306a36Sopenharmony_ci DRM_ERROR("invalid capset id %u", vgdev->capsets[i].id); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (ret == 0 || invalid_capset_id) { 10062306a36Sopenharmony_ci spin_lock(&vgdev->display_info_lock); 10162306a36Sopenharmony_ci drmm_kfree(drm, vgdev->capsets); 10262306a36Sopenharmony_ci vgdev->capsets = NULL; 10362306a36Sopenharmony_ci spin_unlock(&vgdev->display_info_lock); 10462306a36Sopenharmony_ci return; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci vgdev->capset_id_mask |= 1 << vgdev->capsets[i].id; 10862306a36Sopenharmony_ci DRM_INFO("cap set %d: id %d, max-version %d, max-size %d\n", 10962306a36Sopenharmony_ci i, vgdev->capsets[i].id, 11062306a36Sopenharmony_ci vgdev->capsets[i].max_version, 11162306a36Sopenharmony_ci vgdev->capsets[i].max_size); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci vgdev->num_capsets = num_capsets; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciint virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci static vq_callback_t *callbacks[] = { 12062306a36Sopenharmony_ci virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack 12162306a36Sopenharmony_ci }; 12262306a36Sopenharmony_ci static const char * const names[] = { "control", "cursor" }; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci struct virtio_gpu_device *vgdev; 12562306a36Sopenharmony_ci /* this will expand later */ 12662306a36Sopenharmony_ci struct virtqueue *vqs[2]; 12762306a36Sopenharmony_ci u32 num_scanouts, num_capsets; 12862306a36Sopenharmony_ci int ret = 0; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) 13162306a36Sopenharmony_ci return -ENODEV; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci vgdev = drmm_kzalloc(dev, sizeof(struct virtio_gpu_device), GFP_KERNEL); 13462306a36Sopenharmony_ci if (!vgdev) 13562306a36Sopenharmony_ci return -ENOMEM; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci vgdev->ddev = dev; 13862306a36Sopenharmony_ci dev->dev_private = vgdev; 13962306a36Sopenharmony_ci vgdev->vdev = vdev; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci spin_lock_init(&vgdev->display_info_lock); 14262306a36Sopenharmony_ci spin_lock_init(&vgdev->resource_export_lock); 14362306a36Sopenharmony_ci spin_lock_init(&vgdev->host_visible_lock); 14462306a36Sopenharmony_ci ida_init(&vgdev->ctx_id_ida); 14562306a36Sopenharmony_ci ida_init(&vgdev->resource_ida); 14662306a36Sopenharmony_ci init_waitqueue_head(&vgdev->resp_wq); 14762306a36Sopenharmony_ci virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func); 14862306a36Sopenharmony_ci virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci vgdev->fence_drv.context = dma_fence_context_alloc(1); 15162306a36Sopenharmony_ci spin_lock_init(&vgdev->fence_drv.lock); 15262306a36Sopenharmony_ci INIT_LIST_HEAD(&vgdev->fence_drv.fences); 15362306a36Sopenharmony_ci INIT_LIST_HEAD(&vgdev->cap_cache); 15462306a36Sopenharmony_ci INIT_WORK(&vgdev->config_changed_work, 15562306a36Sopenharmony_ci virtio_gpu_config_changed_work_func); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci INIT_WORK(&vgdev->obj_free_work, 15862306a36Sopenharmony_ci virtio_gpu_array_put_free_work); 15962306a36Sopenharmony_ci INIT_LIST_HEAD(&vgdev->obj_free_list); 16062306a36Sopenharmony_ci spin_lock_init(&vgdev->obj_free_lock); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN 16362306a36Sopenharmony_ci if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VIRGL)) 16462306a36Sopenharmony_ci vgdev->has_virgl_3d = true; 16562306a36Sopenharmony_ci#endif 16662306a36Sopenharmony_ci if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) { 16762306a36Sopenharmony_ci vgdev->has_edid = true; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) { 17062306a36Sopenharmony_ci vgdev->has_indirect = true; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_UUID)) { 17362306a36Sopenharmony_ci vgdev->has_resource_assign_uuid = true; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_BLOB)) { 17662306a36Sopenharmony_ci vgdev->has_resource_blob = true; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci if (virtio_get_shm_region(vgdev->vdev, &vgdev->host_visible_region, 17962306a36Sopenharmony_ci VIRTIO_GPU_SHM_ID_HOST_VISIBLE)) { 18062306a36Sopenharmony_ci if (!devm_request_mem_region(&vgdev->vdev->dev, 18162306a36Sopenharmony_ci vgdev->host_visible_region.addr, 18262306a36Sopenharmony_ci vgdev->host_visible_region.len, 18362306a36Sopenharmony_ci dev_name(&vgdev->vdev->dev))) { 18462306a36Sopenharmony_ci DRM_ERROR("Could not reserve host visible region\n"); 18562306a36Sopenharmony_ci ret = -EBUSY; 18662306a36Sopenharmony_ci goto err_vqs; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci DRM_INFO("Host memory window: 0x%lx +0x%lx\n", 19062306a36Sopenharmony_ci (unsigned long)vgdev->host_visible_region.addr, 19162306a36Sopenharmony_ci (unsigned long)vgdev->host_visible_region.len); 19262306a36Sopenharmony_ci vgdev->has_host_visible = true; 19362306a36Sopenharmony_ci drm_mm_init(&vgdev->host_visible_mm, 19462306a36Sopenharmony_ci (unsigned long)vgdev->host_visible_region.addr, 19562306a36Sopenharmony_ci (unsigned long)vgdev->host_visible_region.len); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_CONTEXT_INIT)) { 19862306a36Sopenharmony_ci vgdev->has_context_init = true; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci DRM_INFO("features: %cvirgl %cedid %cresource_blob %chost_visible", 20262306a36Sopenharmony_ci vgdev->has_virgl_3d ? '+' : '-', 20362306a36Sopenharmony_ci vgdev->has_edid ? '+' : '-', 20462306a36Sopenharmony_ci vgdev->has_resource_blob ? '+' : '-', 20562306a36Sopenharmony_ci vgdev->has_host_visible ? '+' : '-'); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci DRM_INFO("features: %ccontext_init\n", 20862306a36Sopenharmony_ci vgdev->has_context_init ? '+' : '-'); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); 21162306a36Sopenharmony_ci if (ret) { 21262306a36Sopenharmony_ci DRM_ERROR("failed to find virt queues\n"); 21362306a36Sopenharmony_ci goto err_vqs; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci vgdev->ctrlq.vq = vqs[0]; 21662306a36Sopenharmony_ci vgdev->cursorq.vq = vqs[1]; 21762306a36Sopenharmony_ci ret = virtio_gpu_alloc_vbufs(vgdev); 21862306a36Sopenharmony_ci if (ret) { 21962306a36Sopenharmony_ci DRM_ERROR("failed to alloc vbufs\n"); 22062306a36Sopenharmony_ci goto err_vbufs; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* get display info */ 22462306a36Sopenharmony_ci virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, 22562306a36Sopenharmony_ci num_scanouts, &num_scanouts); 22662306a36Sopenharmony_ci vgdev->num_scanouts = min_t(uint32_t, num_scanouts, 22762306a36Sopenharmony_ci VIRTIO_GPU_MAX_SCANOUTS); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_DRM_VIRTIO_GPU_KMS) || !vgdev->num_scanouts) { 23062306a36Sopenharmony_ci DRM_INFO("KMS disabled\n"); 23162306a36Sopenharmony_ci vgdev->num_scanouts = 0; 23262306a36Sopenharmony_ci vgdev->has_edid = false; 23362306a36Sopenharmony_ci dev->driver_features &= ~(DRIVER_MODESET | DRIVER_ATOMIC); 23462306a36Sopenharmony_ci } else { 23562306a36Sopenharmony_ci DRM_INFO("number of scanouts: %d\n", num_scanouts); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, 23962306a36Sopenharmony_ci num_capsets, &num_capsets); 24062306a36Sopenharmony_ci DRM_INFO("number of cap sets: %d\n", num_capsets); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci ret = virtio_gpu_modeset_init(vgdev); 24362306a36Sopenharmony_ci if (ret) { 24462306a36Sopenharmony_ci DRM_ERROR("modeset init failed\n"); 24562306a36Sopenharmony_ci goto err_scanouts; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci virtio_device_ready(vgdev->vdev); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (num_capsets) 25162306a36Sopenharmony_ci virtio_gpu_get_capsets(vgdev, num_capsets); 25262306a36Sopenharmony_ci if (vgdev->num_scanouts) { 25362306a36Sopenharmony_ci if (vgdev->has_edid) 25462306a36Sopenharmony_ci virtio_gpu_cmd_get_edids(vgdev); 25562306a36Sopenharmony_ci virtio_gpu_cmd_get_display_info(vgdev); 25662306a36Sopenharmony_ci virtio_gpu_notify(vgdev); 25762306a36Sopenharmony_ci wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, 25862306a36Sopenharmony_ci 5 * HZ); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cierr_scanouts: 26362306a36Sopenharmony_ci virtio_gpu_free_vbufs(vgdev); 26462306a36Sopenharmony_cierr_vbufs: 26562306a36Sopenharmony_ci vgdev->vdev->config->del_vqs(vgdev->vdev); 26662306a36Sopenharmony_cierr_vqs: 26762306a36Sopenharmony_ci dev->dev_private = NULL; 26862306a36Sopenharmony_ci return ret; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void virtio_gpu_cleanup_cap_cache(struct virtio_gpu_device *vgdev) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct virtio_gpu_drv_cap_cache *cache_ent, *tmp; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci list_for_each_entry_safe(cache_ent, tmp, &vgdev->cap_cache, head) { 27662306a36Sopenharmony_ci kfree(cache_ent->caps_cache); 27762306a36Sopenharmony_ci kfree(cache_ent); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_civoid virtio_gpu_deinit(struct drm_device *dev) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct virtio_gpu_device *vgdev = dev->dev_private; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci flush_work(&vgdev->obj_free_work); 28662306a36Sopenharmony_ci flush_work(&vgdev->ctrlq.dequeue_work); 28762306a36Sopenharmony_ci flush_work(&vgdev->cursorq.dequeue_work); 28862306a36Sopenharmony_ci flush_work(&vgdev->config_changed_work); 28962306a36Sopenharmony_ci virtio_reset_device(vgdev->vdev); 29062306a36Sopenharmony_ci vgdev->vdev->config->del_vqs(vgdev->vdev); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_civoid virtio_gpu_release(struct drm_device *dev) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct virtio_gpu_device *vgdev = dev->dev_private; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (!vgdev) 29862306a36Sopenharmony_ci return; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci virtio_gpu_modeset_fini(vgdev); 30162306a36Sopenharmony_ci virtio_gpu_free_vbufs(vgdev); 30262306a36Sopenharmony_ci virtio_gpu_cleanup_cap_cache(vgdev); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (vgdev->has_host_visible) 30562306a36Sopenharmony_ci drm_mm_takedown(&vgdev->host_visible_mm); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciint virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct virtio_gpu_device *vgdev = dev->dev_private; 31162306a36Sopenharmony_ci struct virtio_gpu_fpriv *vfpriv; 31262306a36Sopenharmony_ci int handle; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* can't create contexts without 3d renderer */ 31562306a36Sopenharmony_ci if (!vgdev->has_virgl_3d) 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* allocate a virt GPU context for this opener */ 31962306a36Sopenharmony_ci vfpriv = kzalloc(sizeof(*vfpriv), GFP_KERNEL); 32062306a36Sopenharmony_ci if (!vfpriv) 32162306a36Sopenharmony_ci return -ENOMEM; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci mutex_init(&vfpriv->context_lock); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci handle = ida_alloc(&vgdev->ctx_id_ida, GFP_KERNEL); 32662306a36Sopenharmony_ci if (handle < 0) { 32762306a36Sopenharmony_ci kfree(vfpriv); 32862306a36Sopenharmony_ci return handle; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci vfpriv->ctx_id = handle + 1; 33262306a36Sopenharmony_ci file->driver_priv = vfpriv; 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_civoid virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct virtio_gpu_device *vgdev = dev->dev_private; 33962306a36Sopenharmony_ci struct virtio_gpu_fpriv *vfpriv = file->driver_priv; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!vgdev->has_virgl_3d) 34262306a36Sopenharmony_ci return; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (vfpriv->context_created) { 34562306a36Sopenharmony_ci virtio_gpu_cmd_context_destroy(vgdev, vfpriv->ctx_id); 34662306a36Sopenharmony_ci virtio_gpu_notify(vgdev); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci ida_free(&vgdev->ctx_id_ida, vfpriv->ctx_id - 1); 35062306a36Sopenharmony_ci mutex_destroy(&vfpriv->context_lock); 35162306a36Sopenharmony_ci kfree(vfpriv); 35262306a36Sopenharmony_ci file->driver_priv = NULL; 35362306a36Sopenharmony_ci} 354