| .. | .. |
|---|
| 25 | 25 | |
|---|
| 26 | 26 | #include <linux/virtio.h> |
|---|
| 27 | 27 | #include <linux/virtio_config.h> |
|---|
| 28 | | -#include <drm/drmP.h> |
|---|
| 28 | +#include <linux/virtio_ring.h> |
|---|
| 29 | + |
|---|
| 30 | +#include <drm/drm_file.h> |
|---|
| 31 | + |
|---|
| 29 | 32 | #include "virtgpu_drv.h" |
|---|
| 30 | 33 | |
|---|
| 31 | 34 | static void virtio_gpu_config_changed_work_func(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 36 | 39 | u32 events_read, events_clear = 0; |
|---|
| 37 | 40 | |
|---|
| 38 | 41 | /* read the config space */ |
|---|
| 39 | | - virtio_cread(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 40 | | - events_read, &events_read); |
|---|
| 42 | + virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 43 | + events_read, &events_read); |
|---|
| 41 | 44 | if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { |
|---|
| 42 | 45 | if (vgdev->has_edid) |
|---|
| 43 | 46 | virtio_gpu_cmd_get_edids(vgdev); |
|---|
| 44 | 47 | virtio_gpu_cmd_get_display_info(vgdev); |
|---|
| 48 | + virtio_gpu_notify(vgdev); |
|---|
| 45 | 49 | drm_helper_hpd_irq_event(vgdev->ddev); |
|---|
| 46 | 50 | events_clear |= VIRTIO_GPU_EVENT_DISPLAY; |
|---|
| 47 | 51 | } |
|---|
| 48 | | - virtio_cwrite(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 49 | | - events_clear, &events_clear); |
|---|
| 50 | | -} |
|---|
| 51 | | - |
|---|
| 52 | | -static int virtio_gpu_context_create(struct virtio_gpu_device *vgdev, |
|---|
| 53 | | - uint32_t nlen, const char *name) |
|---|
| 54 | | -{ |
|---|
| 55 | | - int handle = ida_alloc(&vgdev->ctx_id_ida, GFP_KERNEL); |
|---|
| 56 | | - |
|---|
| 57 | | - if (handle < 0) |
|---|
| 58 | | - return handle; |
|---|
| 59 | | - handle += 1; |
|---|
| 60 | | - virtio_gpu_cmd_context_create(vgdev, handle, nlen, name); |
|---|
| 61 | | - return handle; |
|---|
| 62 | | -} |
|---|
| 63 | | - |
|---|
| 64 | | -static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev, |
|---|
| 65 | | - uint32_t ctx_id) |
|---|
| 66 | | -{ |
|---|
| 67 | | - virtio_gpu_cmd_context_destroy(vgdev, ctx_id); |
|---|
| 68 | | - ida_free(&vgdev->ctx_id_ida, ctx_id - 1); |
|---|
| 52 | + virtio_cwrite_le(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 53 | + events_clear, &events_clear); |
|---|
| 69 | 54 | } |
|---|
| 70 | 55 | |
|---|
| 71 | 56 | static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, |
|---|
| .. | .. |
|---|
| 90 | 75 | } |
|---|
| 91 | 76 | for (i = 0; i < num_capsets; i++) { |
|---|
| 92 | 77 | virtio_gpu_cmd_get_capset_info(vgdev, i); |
|---|
| 78 | + virtio_gpu_notify(vgdev); |
|---|
| 93 | 79 | ret = wait_event_timeout(vgdev->resp_wq, |
|---|
| 94 | 80 | vgdev->capsets[i].id > 0, 5 * HZ); |
|---|
| 95 | 81 | if (ret == 0) { |
|---|
| .. | .. |
|---|
| 119 | 105 | /* this will expand later */ |
|---|
| 120 | 106 | struct virtqueue *vqs[2]; |
|---|
| 121 | 107 | u32 num_scanouts, num_capsets; |
|---|
| 122 | | - int ret; |
|---|
| 108 | + int ret = 0; |
|---|
| 123 | 109 | |
|---|
| 124 | 110 | if (!virtio_has_feature(dev_to_virtio(dev->dev), VIRTIO_F_VERSION_1)) |
|---|
| 125 | 111 | return -ENODEV; |
|---|
| .. | .. |
|---|
| 134 | 120 | vgdev->dev = dev->dev; |
|---|
| 135 | 121 | |
|---|
| 136 | 122 | spin_lock_init(&vgdev->display_info_lock); |
|---|
| 123 | + spin_lock_init(&vgdev->resource_export_lock); |
|---|
| 137 | 124 | ida_init(&vgdev->ctx_id_ida); |
|---|
| 138 | 125 | ida_init(&vgdev->resource_ida); |
|---|
| 139 | 126 | init_waitqueue_head(&vgdev->resp_wq); |
|---|
| .. | .. |
|---|
| 147 | 134 | INIT_WORK(&vgdev->config_changed_work, |
|---|
| 148 | 135 | virtio_gpu_config_changed_work_func); |
|---|
| 149 | 136 | |
|---|
| 137 | + INIT_WORK(&vgdev->obj_free_work, |
|---|
| 138 | + virtio_gpu_array_put_free_work); |
|---|
| 139 | + INIT_LIST_HEAD(&vgdev->obj_free_list); |
|---|
| 140 | + spin_lock_init(&vgdev->obj_free_lock); |
|---|
| 141 | + |
|---|
| 150 | 142 | #ifdef __LITTLE_ENDIAN |
|---|
| 151 | 143 | if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VIRGL)) |
|---|
| 152 | 144 | vgdev->has_virgl_3d = true; |
|---|
| 153 | | - DRM_INFO("virgl 3d acceleration %s\n", |
|---|
| 154 | | - vgdev->has_virgl_3d ? "enabled" : "not supported by host"); |
|---|
| 155 | | -#else |
|---|
| 156 | | - DRM_INFO("virgl 3d acceleration not supported by guest\n"); |
|---|
| 157 | 145 | #endif |
|---|
| 158 | 146 | if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) { |
|---|
| 159 | 147 | vgdev->has_edid = true; |
|---|
| 160 | | - DRM_INFO("EDID support available.\n"); |
|---|
| 161 | 148 | } |
|---|
| 149 | + if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) { |
|---|
| 150 | + vgdev->has_indirect = true; |
|---|
| 151 | + } |
|---|
| 152 | + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_UUID)) { |
|---|
| 153 | + vgdev->has_resource_assign_uuid = true; |
|---|
| 154 | + } |
|---|
| 155 | + |
|---|
| 156 | + DRM_INFO("features: %cvirgl %cedid\n", |
|---|
| 157 | + vgdev->has_virgl_3d ? '+' : '-', |
|---|
| 158 | + vgdev->has_edid ? '+' : '-'); |
|---|
| 162 | 159 | |
|---|
| 163 | 160 | ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); |
|---|
| 164 | 161 | if (ret) { |
|---|
| .. | .. |
|---|
| 173 | 170 | goto err_vbufs; |
|---|
| 174 | 171 | } |
|---|
| 175 | 172 | |
|---|
| 176 | | - ret = virtio_gpu_ttm_init(vgdev); |
|---|
| 177 | | - if (ret) { |
|---|
| 178 | | - DRM_ERROR("failed to init ttm %d\n", ret); |
|---|
| 179 | | - goto err_ttm; |
|---|
| 180 | | - } |
|---|
| 181 | | - |
|---|
| 182 | 173 | /* get display info */ |
|---|
| 183 | | - virtio_cread(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 184 | | - num_scanouts, &num_scanouts); |
|---|
| 174 | + virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 175 | + num_scanouts, &num_scanouts); |
|---|
| 185 | 176 | vgdev->num_scanouts = min_t(uint32_t, num_scanouts, |
|---|
| 186 | 177 | VIRTIO_GPU_MAX_SCANOUTS); |
|---|
| 187 | 178 | if (!vgdev->num_scanouts) { |
|---|
| .. | .. |
|---|
| 191 | 182 | } |
|---|
| 192 | 183 | DRM_INFO("number of scanouts: %d\n", num_scanouts); |
|---|
| 193 | 184 | |
|---|
| 194 | | - virtio_cread(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 195 | | - num_capsets, &num_capsets); |
|---|
| 185 | + virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, |
|---|
| 186 | + num_capsets, &num_capsets); |
|---|
| 196 | 187 | DRM_INFO("number of cap sets: %d\n", num_capsets); |
|---|
| 197 | 188 | |
|---|
| 198 | | - virtio_gpu_modeset_init(vgdev); |
|---|
| 189 | + ret = virtio_gpu_modeset_init(vgdev); |
|---|
| 190 | + if (ret) { |
|---|
| 191 | + DRM_ERROR("modeset init failed\n"); |
|---|
| 192 | + goto err_scanouts; |
|---|
| 193 | + } |
|---|
| 199 | 194 | |
|---|
| 200 | 195 | virtio_device_ready(vgdev->vdev); |
|---|
| 201 | | - vgdev->vqs_ready = true; |
|---|
| 202 | 196 | |
|---|
| 203 | 197 | if (num_capsets) |
|---|
| 204 | 198 | virtio_gpu_get_capsets(vgdev, num_capsets); |
|---|
| 205 | 199 | if (vgdev->has_edid) |
|---|
| 206 | 200 | virtio_gpu_cmd_get_edids(vgdev); |
|---|
| 207 | 201 | virtio_gpu_cmd_get_display_info(vgdev); |
|---|
| 202 | + virtio_gpu_notify(vgdev); |
|---|
| 208 | 203 | wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, |
|---|
| 209 | 204 | 5 * HZ); |
|---|
| 210 | 205 | return 0; |
|---|
| 211 | 206 | |
|---|
| 212 | 207 | err_scanouts: |
|---|
| 213 | | - virtio_gpu_ttm_fini(vgdev); |
|---|
| 214 | | -err_ttm: |
|---|
| 215 | 208 | virtio_gpu_free_vbufs(vgdev); |
|---|
| 216 | 209 | err_vbufs: |
|---|
| 217 | 210 | vgdev->vdev->config->del_vqs(vgdev->vdev); |
|---|
| .. | .. |
|---|
| 235 | 228 | { |
|---|
| 236 | 229 | struct virtio_gpu_device *vgdev = dev->dev_private; |
|---|
| 237 | 230 | |
|---|
| 238 | | - vgdev->vqs_ready = false; |
|---|
| 231 | + flush_work(&vgdev->obj_free_work); |
|---|
| 239 | 232 | flush_work(&vgdev->ctrlq.dequeue_work); |
|---|
| 240 | 233 | flush_work(&vgdev->cursorq.dequeue_work); |
|---|
| 241 | 234 | flush_work(&vgdev->config_changed_work); |
|---|
| 242 | 235 | vgdev->vdev->config->reset(vgdev->vdev); |
|---|
| 243 | 236 | vgdev->vdev->config->del_vqs(vgdev->vdev); |
|---|
| 237 | +} |
|---|
| 238 | + |
|---|
| 239 | +void virtio_gpu_release(struct drm_device *dev) |
|---|
| 240 | +{ |
|---|
| 241 | + struct virtio_gpu_device *vgdev = dev->dev_private; |
|---|
| 244 | 242 | |
|---|
| 245 | 243 | virtio_gpu_modeset_fini(vgdev); |
|---|
| 246 | | - virtio_gpu_ttm_fini(vgdev); |
|---|
| 247 | 244 | virtio_gpu_free_vbufs(vgdev); |
|---|
| 248 | 245 | virtio_gpu_cleanup_cap_cache(vgdev); |
|---|
| 249 | 246 | kfree(vgdev->capsets); |
|---|
| .. | .. |
|---|
| 254 | 251 | { |
|---|
| 255 | 252 | struct virtio_gpu_device *vgdev = dev->dev_private; |
|---|
| 256 | 253 | struct virtio_gpu_fpriv *vfpriv; |
|---|
| 257 | | - int id; |
|---|
| 258 | | - char dbgname[TASK_COMM_LEN]; |
|---|
| 254 | + int handle; |
|---|
| 259 | 255 | |
|---|
| 260 | 256 | /* can't create contexts without 3d renderer */ |
|---|
| 261 | 257 | if (!vgdev->has_virgl_3d) |
|---|
| .. | .. |
|---|
| 266 | 262 | if (!vfpriv) |
|---|
| 267 | 263 | return -ENOMEM; |
|---|
| 268 | 264 | |
|---|
| 269 | | - get_task_comm(dbgname, current); |
|---|
| 270 | | - id = virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname); |
|---|
| 271 | | - if (id < 0) { |
|---|
| 265 | + mutex_init(&vfpriv->context_lock); |
|---|
| 266 | + |
|---|
| 267 | + handle = ida_alloc(&vgdev->ctx_id_ida, GFP_KERNEL); |
|---|
| 268 | + if (handle < 0) { |
|---|
| 272 | 269 | kfree(vfpriv); |
|---|
| 273 | | - return id; |
|---|
| 270 | + return handle; |
|---|
| 274 | 271 | } |
|---|
| 275 | 272 | |
|---|
| 276 | | - vfpriv->ctx_id = id; |
|---|
| 273 | + vfpriv->ctx_id = handle + 1; |
|---|
| 277 | 274 | file->driver_priv = vfpriv; |
|---|
| 278 | 275 | return 0; |
|---|
| 279 | 276 | } |
|---|
| .. | .. |
|---|
| 281 | 278 | void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file) |
|---|
| 282 | 279 | { |
|---|
| 283 | 280 | struct virtio_gpu_device *vgdev = dev->dev_private; |
|---|
| 284 | | - struct virtio_gpu_fpriv *vfpriv; |
|---|
| 281 | + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; |
|---|
| 285 | 282 | |
|---|
| 286 | 283 | if (!vgdev->has_virgl_3d) |
|---|
| 287 | 284 | return; |
|---|
| 288 | 285 | |
|---|
| 289 | | - vfpriv = file->driver_priv; |
|---|
| 286 | + if (vfpriv->context_created) { |
|---|
| 287 | + virtio_gpu_cmd_context_destroy(vgdev, vfpriv->ctx_id); |
|---|
| 288 | + virtio_gpu_notify(vgdev); |
|---|
| 289 | + } |
|---|
| 290 | 290 | |
|---|
| 291 | | - virtio_gpu_context_destroy(vgdev, vfpriv->ctx_id); |
|---|
| 291 | + ida_free(&vgdev->ctx_id_ida, vfpriv->ctx_id - 1); |
|---|
| 292 | + mutex_destroy(&vfpriv->context_lock); |
|---|
| 292 | 293 | kfree(vfpriv); |
|---|
| 293 | 294 | file->driver_priv = NULL; |
|---|
| 294 | 295 | } |
|---|