1 1.2 riastrad /* $NetBSD: qxl_cmd.c,v 1.3 2021/12/18 23:45:42 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2013 Red Hat Inc. 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice shall be included in 14 1.1 riastrad * all copies or substantial portions of the Software. 15 1.1 riastrad * 16 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 1.1 riastrad * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 1.1 riastrad * OTHER DEALINGS IN THE SOFTWARE. 23 1.1 riastrad * 24 1.1 riastrad * Authors: Dave Airlie 25 1.1 riastrad * Alon Levy 26 1.1 riastrad */ 27 1.1 riastrad 28 1.1 riastrad /* QXL cmd/ring handling */ 29 1.1 riastrad 30 1.2 riastrad #include <sys/cdefs.h> 31 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: qxl_cmd.c,v 1.3 2021/12/18 23:45:42 riastradh Exp $"); 32 1.2 riastrad 33 1.3 riastrad #include <linux/delay.h> 34 1.3 riastrad 35 1.3 riastrad #include <drm/drm_util.h> 36 1.3 riastrad 37 1.1 riastrad #include "qxl_drv.h" 38 1.1 riastrad #include "qxl_object.h" 39 1.1 riastrad 40 1.1 riastrad static int qxl_reap_surface_id(struct qxl_device *qdev, int max_to_reap); 41 1.1 riastrad 42 1.1 riastrad struct ring { 43 1.1 riastrad struct qxl_ring_header header; 44 1.1 riastrad uint8_t elements[0]; 45 1.1 riastrad }; 46 1.1 riastrad 47 1.1 riastrad struct qxl_ring { 48 1.1 riastrad struct ring *ring; 49 1.1 riastrad int element_size; 50 1.1 riastrad int n_elements; 51 1.1 riastrad int prod_notify; 52 1.1 riastrad wait_queue_head_t *push_event; 53 1.1 riastrad spinlock_t lock; 54 1.1 riastrad }; 55 1.1 riastrad 56 1.1 riastrad void qxl_ring_free(struct qxl_ring *ring) 57 1.1 riastrad { 58 1.1 riastrad kfree(ring); 59 1.1 riastrad } 60 1.1 riastrad 61 1.1 riastrad void qxl_ring_init_hdr(struct qxl_ring *ring) 62 1.1 riastrad { 63 1.1 riastrad ring->ring->header.notify_on_prod = ring->n_elements; 64 1.1 riastrad } 65 1.1 riastrad 66 1.1 riastrad struct qxl_ring * 67 1.1 riastrad qxl_ring_create(struct qxl_ring_header *header, 68 1.1 riastrad int element_size, 69 1.1 riastrad int n_elements, 70 1.1 riastrad int prod_notify, 71 1.1 riastrad bool set_prod_notify, 72 1.1 riastrad wait_queue_head_t *push_event) 73 1.1 riastrad { 74 1.1 riastrad struct qxl_ring *ring; 75 1.1 riastrad 76 1.1 riastrad ring = kmalloc(sizeof(*ring), GFP_KERNEL); 77 1.1 riastrad if (!ring) 78 1.1 riastrad return NULL; 79 1.1 riastrad 80 1.1 riastrad ring->ring = (struct ring *)header; 81 1.1 riastrad ring->element_size = element_size; 82 1.1 riastrad ring->n_elements = n_elements; 83 1.1 riastrad ring->prod_notify = prod_notify; 84 1.1 riastrad ring->push_event = push_event; 85 1.1 riastrad if (set_prod_notify) 86 1.1 riastrad qxl_ring_init_hdr(ring); 87 1.1 riastrad spin_lock_init(&ring->lock); 88 1.1 riastrad return ring; 89 1.1 riastrad } 90 1.1 riastrad 91 1.1 riastrad static int qxl_check_header(struct qxl_ring *ring) 92 1.1 riastrad { 93 1.1 riastrad int ret; 94 1.1 riastrad struct qxl_ring_header *header = &(ring->ring->header); 95 1.1 riastrad unsigned long flags; 96 1.3 riastrad 97 1.1 riastrad spin_lock_irqsave(&ring->lock, flags); 98 1.1 riastrad ret = header->prod - header->cons < header->num_items; 99 1.1 riastrad if (ret == 0) 100 1.1 riastrad header->notify_on_cons = header->cons + 1; 101 1.1 riastrad spin_unlock_irqrestore(&ring->lock, flags); 102 1.1 riastrad return ret; 103 1.1 riastrad } 104 1.1 riastrad 105 1.1 riastrad int qxl_check_idle(struct qxl_ring *ring) 106 1.1 riastrad { 107 1.1 riastrad int ret; 108 1.1 riastrad struct qxl_ring_header *header = &(ring->ring->header); 109 1.1 riastrad unsigned long flags; 110 1.3 riastrad 111 1.1 riastrad spin_lock_irqsave(&ring->lock, flags); 112 1.1 riastrad ret = header->prod == header->cons; 113 1.1 riastrad spin_unlock_irqrestore(&ring->lock, flags); 114 1.1 riastrad return ret; 115 1.1 riastrad } 116 1.1 riastrad 117 1.1 riastrad int qxl_ring_push(struct qxl_ring *ring, 118 1.1 riastrad const void *new_elt, bool interruptible) 119 1.1 riastrad { 120 1.1 riastrad struct qxl_ring_header *header = &(ring->ring->header); 121 1.1 riastrad uint8_t *elt; 122 1.1 riastrad int idx, ret; 123 1.1 riastrad unsigned long flags; 124 1.3 riastrad 125 1.1 riastrad spin_lock_irqsave(&ring->lock, flags); 126 1.1 riastrad if (header->prod - header->cons == header->num_items) { 127 1.1 riastrad header->notify_on_cons = header->cons + 1; 128 1.1 riastrad mb(); 129 1.1 riastrad spin_unlock_irqrestore(&ring->lock, flags); 130 1.1 riastrad if (!drm_can_sleep()) { 131 1.1 riastrad while (!qxl_check_header(ring)) 132 1.1 riastrad udelay(1); 133 1.1 riastrad } else { 134 1.1 riastrad if (interruptible) { 135 1.1 riastrad ret = wait_event_interruptible(*ring->push_event, 136 1.1 riastrad qxl_check_header(ring)); 137 1.1 riastrad if (ret) 138 1.1 riastrad return ret; 139 1.1 riastrad } else { 140 1.1 riastrad wait_event(*ring->push_event, 141 1.1 riastrad qxl_check_header(ring)); 142 1.1 riastrad } 143 1.1 riastrad 144 1.1 riastrad } 145 1.1 riastrad spin_lock_irqsave(&ring->lock, flags); 146 1.1 riastrad } 147 1.1 riastrad 148 1.1 riastrad idx = header->prod & (ring->n_elements - 1); 149 1.1 riastrad elt = ring->ring->elements + idx * ring->element_size; 150 1.1 riastrad 151 1.1 riastrad memcpy((void *)elt, new_elt, ring->element_size); 152 1.1 riastrad 153 1.1 riastrad header->prod++; 154 1.1 riastrad 155 1.1 riastrad mb(); 156 1.1 riastrad 157 1.1 riastrad if (header->prod == header->notify_on_prod) 158 1.1 riastrad outb(0, ring->prod_notify); 159 1.1 riastrad 160 1.1 riastrad spin_unlock_irqrestore(&ring->lock, flags); 161 1.1 riastrad return 0; 162 1.1 riastrad } 163 1.1 riastrad 164 1.1 riastrad static bool qxl_ring_pop(struct qxl_ring *ring, 165 1.1 riastrad void *element) 166 1.1 riastrad { 167 1.1 riastrad volatile struct qxl_ring_header *header = &(ring->ring->header); 168 1.1 riastrad volatile uint8_t *ring_elt; 169 1.1 riastrad int idx; 170 1.1 riastrad unsigned long flags; 171 1.3 riastrad 172 1.1 riastrad spin_lock_irqsave(&ring->lock, flags); 173 1.1 riastrad if (header->cons == header->prod) { 174 1.1 riastrad header->notify_on_prod = header->cons + 1; 175 1.1 riastrad spin_unlock_irqrestore(&ring->lock, flags); 176 1.1 riastrad return false; 177 1.1 riastrad } 178 1.1 riastrad 179 1.1 riastrad idx = header->cons & (ring->n_elements - 1); 180 1.1 riastrad ring_elt = ring->ring->elements + idx * ring->element_size; 181 1.1 riastrad 182 1.1 riastrad memcpy(element, (void *)ring_elt, ring->element_size); 183 1.1 riastrad 184 1.1 riastrad header->cons++; 185 1.1 riastrad 186 1.1 riastrad spin_unlock_irqrestore(&ring->lock, flags); 187 1.1 riastrad return true; 188 1.1 riastrad } 189 1.1 riastrad 190 1.1 riastrad int 191 1.1 riastrad qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *release, 192 1.1 riastrad uint32_t type, bool interruptible) 193 1.1 riastrad { 194 1.1 riastrad struct qxl_command cmd; 195 1.1 riastrad 196 1.1 riastrad cmd.type = type; 197 1.3 riastrad cmd.data = qxl_bo_physical_address(qdev, release->release_bo, release->release_offset); 198 1.1 riastrad 199 1.1 riastrad return qxl_ring_push(qdev->command_ring, &cmd, interruptible); 200 1.1 riastrad } 201 1.1 riastrad 202 1.1 riastrad int 203 1.1 riastrad qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *release, 204 1.1 riastrad uint32_t type, bool interruptible) 205 1.1 riastrad { 206 1.1 riastrad struct qxl_command cmd; 207 1.1 riastrad 208 1.1 riastrad cmd.type = type; 209 1.3 riastrad cmd.data = qxl_bo_physical_address(qdev, release->release_bo, release->release_offset); 210 1.1 riastrad 211 1.1 riastrad return qxl_ring_push(qdev->cursor_ring, &cmd, interruptible); 212 1.1 riastrad } 213 1.1 riastrad 214 1.1 riastrad bool qxl_queue_garbage_collect(struct qxl_device *qdev, bool flush) 215 1.1 riastrad { 216 1.1 riastrad if (!qxl_check_idle(qdev->release_ring)) { 217 1.3 riastrad schedule_work(&qdev->gc_work); 218 1.1 riastrad if (flush) 219 1.1 riastrad flush_work(&qdev->gc_work); 220 1.1 riastrad return true; 221 1.1 riastrad } 222 1.1 riastrad return false; 223 1.1 riastrad } 224 1.1 riastrad 225 1.1 riastrad int qxl_garbage_collect(struct qxl_device *qdev) 226 1.1 riastrad { 227 1.1 riastrad struct qxl_release *release; 228 1.1 riastrad uint64_t id, next_id; 229 1.1 riastrad int i = 0; 230 1.1 riastrad union qxl_release_info *info; 231 1.1 riastrad 232 1.1 riastrad while (qxl_ring_pop(qdev->release_ring, &id)) { 233 1.3 riastrad DRM_DEBUG_DRIVER("popped %lld\n", id); 234 1.1 riastrad while (id) { 235 1.1 riastrad release = qxl_release_from_id_locked(qdev, id); 236 1.1 riastrad if (release == NULL) 237 1.1 riastrad break; 238 1.1 riastrad 239 1.1 riastrad info = qxl_release_map(qdev, release); 240 1.1 riastrad next_id = info->next; 241 1.1 riastrad qxl_release_unmap(qdev, release, info); 242 1.1 riastrad 243 1.3 riastrad DRM_DEBUG_DRIVER("popped %lld, next %lld\n", id, 244 1.3 riastrad next_id); 245 1.1 riastrad 246 1.1 riastrad switch (release->type) { 247 1.1 riastrad case QXL_RELEASE_DRAWABLE: 248 1.1 riastrad case QXL_RELEASE_SURFACE_CMD: 249 1.1 riastrad case QXL_RELEASE_CURSOR_CMD: 250 1.1 riastrad break; 251 1.1 riastrad default: 252 1.1 riastrad DRM_ERROR("unexpected release type\n"); 253 1.1 riastrad break; 254 1.1 riastrad } 255 1.1 riastrad id = next_id; 256 1.1 riastrad 257 1.1 riastrad qxl_release_free(qdev, release); 258 1.1 riastrad ++i; 259 1.1 riastrad } 260 1.1 riastrad } 261 1.1 riastrad 262 1.3 riastrad DRM_DEBUG_DRIVER("%d\n", i); 263 1.1 riastrad 264 1.1 riastrad return i; 265 1.1 riastrad } 266 1.1 riastrad 267 1.1 riastrad int qxl_alloc_bo_reserved(struct qxl_device *qdev, 268 1.1 riastrad struct qxl_release *release, 269 1.1 riastrad unsigned long size, 270 1.1 riastrad struct qxl_bo **_bo) 271 1.1 riastrad { 272 1.1 riastrad struct qxl_bo *bo; 273 1.1 riastrad int ret; 274 1.1 riastrad 275 1.1 riastrad ret = qxl_bo_create(qdev, size, false /* not kernel - device */, 276 1.1 riastrad false, QXL_GEM_DOMAIN_VRAM, NULL, &bo); 277 1.1 riastrad if (ret) { 278 1.1 riastrad DRM_ERROR("failed to allocate VRAM BO\n"); 279 1.1 riastrad return ret; 280 1.1 riastrad } 281 1.1 riastrad ret = qxl_release_list_add(release, bo); 282 1.1 riastrad if (ret) 283 1.1 riastrad goto out_unref; 284 1.1 riastrad 285 1.1 riastrad *_bo = bo; 286 1.1 riastrad return 0; 287 1.1 riastrad out_unref: 288 1.1 riastrad qxl_bo_unref(&bo); 289 1.1 riastrad return ret; 290 1.1 riastrad } 291 1.1 riastrad 292 1.1 riastrad static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, bool intr) 293 1.1 riastrad { 294 1.1 riastrad int irq_num; 295 1.1 riastrad long addr = qdev->io_base + port; 296 1.1 riastrad int ret; 297 1.1 riastrad 298 1.1 riastrad mutex_lock(&qdev->async_io_mutex); 299 1.1 riastrad irq_num = atomic_read(&qdev->irq_received_io_cmd); 300 1.1 riastrad if (qdev->last_sent_io_cmd > irq_num) { 301 1.1 riastrad if (intr) 302 1.1 riastrad ret = wait_event_interruptible_timeout(qdev->io_cmd_event, 303 1.1 riastrad atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); 304 1.1 riastrad else 305 1.1 riastrad ret = wait_event_timeout(qdev->io_cmd_event, 306 1.1 riastrad atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); 307 1.1 riastrad /* 0 is timeout, just bail the "hw" has gone away */ 308 1.1 riastrad if (ret <= 0) 309 1.1 riastrad goto out; 310 1.1 riastrad irq_num = atomic_read(&qdev->irq_received_io_cmd); 311 1.1 riastrad } 312 1.1 riastrad outb(val, addr); 313 1.1 riastrad qdev->last_sent_io_cmd = irq_num + 1; 314 1.1 riastrad if (intr) 315 1.1 riastrad ret = wait_event_interruptible_timeout(qdev->io_cmd_event, 316 1.1 riastrad atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); 317 1.1 riastrad else 318 1.1 riastrad ret = wait_event_timeout(qdev->io_cmd_event, 319 1.1 riastrad atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); 320 1.1 riastrad out: 321 1.1 riastrad if (ret > 0) 322 1.1 riastrad ret = 0; 323 1.1 riastrad mutex_unlock(&qdev->async_io_mutex); 324 1.1 riastrad return ret; 325 1.1 riastrad } 326 1.1 riastrad 327 1.1 riastrad static void wait_for_io_cmd(struct qxl_device *qdev, uint8_t val, long port) 328 1.1 riastrad { 329 1.1 riastrad int ret; 330 1.1 riastrad 331 1.1 riastrad restart: 332 1.1 riastrad ret = wait_for_io_cmd_user(qdev, val, port, false); 333 1.1 riastrad if (ret == -ERESTARTSYS) 334 1.1 riastrad goto restart; 335 1.1 riastrad } 336 1.1 riastrad 337 1.1 riastrad int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf, 338 1.1 riastrad const struct qxl_rect *area) 339 1.1 riastrad { 340 1.1 riastrad int surface_id; 341 1.1 riastrad uint32_t surface_width, surface_height; 342 1.1 riastrad int ret; 343 1.1 riastrad 344 1.1 riastrad if (!surf->hw_surf_alloc) 345 1.1 riastrad DRM_ERROR("got io update area with no hw surface\n"); 346 1.1 riastrad 347 1.1 riastrad if (surf->is_primary) 348 1.1 riastrad surface_id = 0; 349 1.1 riastrad else 350 1.1 riastrad surface_id = surf->surface_id; 351 1.1 riastrad surface_width = surf->surf.width; 352 1.1 riastrad surface_height = surf->surf.height; 353 1.1 riastrad 354 1.1 riastrad if (area->left < 0 || area->top < 0 || 355 1.3 riastrad area->right > surface_width || area->bottom > surface_height) 356 1.1 riastrad return -EINVAL; 357 1.3 riastrad 358 1.1 riastrad mutex_lock(&qdev->update_area_mutex); 359 1.1 riastrad qdev->ram_header->update_area = *area; 360 1.1 riastrad qdev->ram_header->update_surface = surface_id; 361 1.1 riastrad ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC, true); 362 1.1 riastrad mutex_unlock(&qdev->update_area_mutex); 363 1.1 riastrad return ret; 364 1.1 riastrad } 365 1.1 riastrad 366 1.1 riastrad void qxl_io_notify_oom(struct qxl_device *qdev) 367 1.1 riastrad { 368 1.1 riastrad outb(0, qdev->io_base + QXL_IO_NOTIFY_OOM); 369 1.1 riastrad } 370 1.1 riastrad 371 1.1 riastrad void qxl_io_flush_release(struct qxl_device *qdev) 372 1.1 riastrad { 373 1.1 riastrad outb(0, qdev->io_base + QXL_IO_FLUSH_RELEASE); 374 1.1 riastrad } 375 1.1 riastrad 376 1.1 riastrad void qxl_io_flush_surfaces(struct qxl_device *qdev) 377 1.1 riastrad { 378 1.1 riastrad wait_for_io_cmd(qdev, 0, QXL_IO_FLUSH_SURFACES_ASYNC); 379 1.1 riastrad } 380 1.1 riastrad 381 1.1 riastrad void qxl_io_destroy_primary(struct qxl_device *qdev) 382 1.1 riastrad { 383 1.1 riastrad wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); 384 1.3 riastrad qdev->primary_bo->is_primary = false; 385 1.3 riastrad drm_gem_object_put_unlocked(&qdev->primary_bo->tbo.base); 386 1.3 riastrad qdev->primary_bo = NULL; 387 1.1 riastrad } 388 1.1 riastrad 389 1.3 riastrad void qxl_io_create_primary(struct qxl_device *qdev, struct qxl_bo *bo) 390 1.1 riastrad { 391 1.1 riastrad struct qxl_surface_create *create; 392 1.1 riastrad 393 1.3 riastrad if (WARN_ON(qdev->primary_bo)) 394 1.3 riastrad return; 395 1.3 riastrad 396 1.3 riastrad DRM_DEBUG_DRIVER("qdev %p, ram_header %p\n", qdev, qdev->ram_header); 397 1.1 riastrad create = &qdev->ram_header->create_surface; 398 1.1 riastrad create->format = bo->surf.format; 399 1.1 riastrad create->width = bo->surf.width; 400 1.1 riastrad create->height = bo->surf.height; 401 1.1 riastrad create->stride = bo->surf.stride; 402 1.3 riastrad create->mem = qxl_bo_physical_address(qdev, bo, 0); 403 1.1 riastrad 404 1.3 riastrad DRM_DEBUG_DRIVER("mem = %llx, from %p\n", create->mem, bo->kptr); 405 1.1 riastrad 406 1.1 riastrad create->flags = QXL_SURF_FLAG_KEEP_DATA; 407 1.1 riastrad create->type = QXL_SURF_TYPE_PRIMARY; 408 1.1 riastrad 409 1.1 riastrad wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC); 410 1.3 riastrad qdev->primary_bo = bo; 411 1.3 riastrad qdev->primary_bo->is_primary = true; 412 1.3 riastrad drm_gem_object_get(&qdev->primary_bo->tbo.base); 413 1.1 riastrad } 414 1.1 riastrad 415 1.1 riastrad void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id) 416 1.1 riastrad { 417 1.3 riastrad DRM_DEBUG_DRIVER("qxl_memslot_add %d\n", id); 418 1.1 riastrad wait_for_io_cmd(qdev, id, QXL_IO_MEMSLOT_ADD_ASYNC); 419 1.1 riastrad } 420 1.1 riastrad 421 1.1 riastrad void qxl_io_reset(struct qxl_device *qdev) 422 1.1 riastrad { 423 1.1 riastrad outb(0, qdev->io_base + QXL_IO_RESET); 424 1.1 riastrad } 425 1.1 riastrad 426 1.1 riastrad void qxl_io_monitors_config(struct qxl_device *qdev) 427 1.1 riastrad { 428 1.1 riastrad wait_for_io_cmd(qdev, 0, QXL_IO_MONITORS_CONFIG_ASYNC); 429 1.1 riastrad } 430 1.1 riastrad 431 1.1 riastrad int qxl_surface_id_alloc(struct qxl_device *qdev, 432 1.1 riastrad struct qxl_bo *surf) 433 1.1 riastrad { 434 1.1 riastrad uint32_t handle; 435 1.1 riastrad int idr_ret; 436 1.1 riastrad int count = 0; 437 1.1 riastrad again: 438 1.1 riastrad idr_preload(GFP_ATOMIC); 439 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 440 1.1 riastrad idr_ret = idr_alloc(&qdev->surf_id_idr, NULL, 1, 0, GFP_NOWAIT); 441 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 442 1.1 riastrad idr_preload_end(); 443 1.1 riastrad if (idr_ret < 0) 444 1.1 riastrad return idr_ret; 445 1.1 riastrad handle = idr_ret; 446 1.1 riastrad 447 1.1 riastrad if (handle >= qdev->rom->n_surfaces) { 448 1.1 riastrad count++; 449 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 450 1.1 riastrad idr_remove(&qdev->surf_id_idr, handle); 451 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 452 1.1 riastrad qxl_reap_surface_id(qdev, 2); 453 1.1 riastrad goto again; 454 1.1 riastrad } 455 1.1 riastrad surf->surface_id = handle; 456 1.1 riastrad 457 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 458 1.1 riastrad qdev->last_alloced_surf_id = handle; 459 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 460 1.1 riastrad return 0; 461 1.1 riastrad } 462 1.1 riastrad 463 1.1 riastrad void qxl_surface_id_dealloc(struct qxl_device *qdev, 464 1.1 riastrad uint32_t surface_id) 465 1.1 riastrad { 466 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 467 1.1 riastrad idr_remove(&qdev->surf_id_idr, surface_id); 468 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 469 1.1 riastrad } 470 1.1 riastrad 471 1.1 riastrad int qxl_hw_surface_alloc(struct qxl_device *qdev, 472 1.3 riastrad struct qxl_bo *surf) 473 1.1 riastrad { 474 1.1 riastrad struct qxl_surface_cmd *cmd; 475 1.1 riastrad struct qxl_release *release; 476 1.1 riastrad int ret; 477 1.1 riastrad 478 1.1 riastrad if (surf->hw_surf_alloc) 479 1.1 riastrad return 0; 480 1.1 riastrad 481 1.1 riastrad ret = qxl_alloc_surface_release_reserved(qdev, QXL_SURFACE_CMD_CREATE, 482 1.1 riastrad NULL, 483 1.1 riastrad &release); 484 1.1 riastrad if (ret) 485 1.1 riastrad return ret; 486 1.1 riastrad 487 1.1 riastrad ret = qxl_release_reserve_list(release, true); 488 1.1 riastrad if (ret) 489 1.1 riastrad return ret; 490 1.1 riastrad 491 1.1 riastrad cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release); 492 1.1 riastrad cmd->type = QXL_SURFACE_CMD_CREATE; 493 1.2 riastrad cmd->flags = QXL_SURF_FLAG_KEEP_DATA; 494 1.1 riastrad cmd->u.surface_create.format = surf->surf.format; 495 1.1 riastrad cmd->u.surface_create.width = surf->surf.width; 496 1.1 riastrad cmd->u.surface_create.height = surf->surf.height; 497 1.1 riastrad cmd->u.surface_create.stride = surf->surf.stride; 498 1.3 riastrad cmd->u.surface_create.data = qxl_bo_physical_address(qdev, surf, 0); 499 1.1 riastrad cmd->surface_id = surf->surface_id; 500 1.1 riastrad qxl_release_unmap(qdev, release, &cmd->release_info); 501 1.1 riastrad 502 1.1 riastrad surf->surf_create = release; 503 1.1 riastrad 504 1.1 riastrad /* no need to add a release to the fence for this surface bo, 505 1.1 riastrad since it is only released when we ask to destroy the surface 506 1.1 riastrad and it would never signal otherwise */ 507 1.1 riastrad qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); 508 1.1 riastrad qxl_release_fence_buffer_objects(release); 509 1.1 riastrad 510 1.1 riastrad surf->hw_surf_alloc = true; 511 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 512 1.1 riastrad idr_replace(&qdev->surf_id_idr, surf, surf->surface_id); 513 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 514 1.1 riastrad return 0; 515 1.1 riastrad } 516 1.1 riastrad 517 1.1 riastrad int qxl_hw_surface_dealloc(struct qxl_device *qdev, 518 1.1 riastrad struct qxl_bo *surf) 519 1.1 riastrad { 520 1.1 riastrad struct qxl_surface_cmd *cmd; 521 1.1 riastrad struct qxl_release *release; 522 1.1 riastrad int ret; 523 1.1 riastrad int id; 524 1.1 riastrad 525 1.1 riastrad if (!surf->hw_surf_alloc) 526 1.1 riastrad return 0; 527 1.1 riastrad 528 1.1 riastrad ret = qxl_alloc_surface_release_reserved(qdev, QXL_SURFACE_CMD_DESTROY, 529 1.1 riastrad surf->surf_create, 530 1.1 riastrad &release); 531 1.1 riastrad if (ret) 532 1.1 riastrad return ret; 533 1.1 riastrad 534 1.1 riastrad surf->surf_create = NULL; 535 1.1 riastrad /* remove the surface from the idr, but not the surface id yet */ 536 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 537 1.1 riastrad idr_replace(&qdev->surf_id_idr, NULL, surf->surface_id); 538 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 539 1.1 riastrad surf->hw_surf_alloc = false; 540 1.1 riastrad 541 1.1 riastrad id = surf->surface_id; 542 1.1 riastrad surf->surface_id = 0; 543 1.1 riastrad 544 1.1 riastrad release->surface_release_id = id; 545 1.1 riastrad cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release); 546 1.1 riastrad cmd->type = QXL_SURFACE_CMD_DESTROY; 547 1.1 riastrad cmd->surface_id = id; 548 1.1 riastrad qxl_release_unmap(qdev, release, &cmd->release_info); 549 1.1 riastrad 550 1.1 riastrad qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); 551 1.1 riastrad 552 1.1 riastrad qxl_release_fence_buffer_objects(release); 553 1.1 riastrad 554 1.1 riastrad return 0; 555 1.1 riastrad } 556 1.1 riastrad 557 1.3 riastrad static int qxl_update_surface(struct qxl_device *qdev, struct qxl_bo *surf) 558 1.1 riastrad { 559 1.1 riastrad struct qxl_rect rect; 560 1.1 riastrad int ret; 561 1.1 riastrad 562 1.1 riastrad /* if we are evicting, we need to make sure the surface is up 563 1.1 riastrad to date */ 564 1.1 riastrad rect.left = 0; 565 1.1 riastrad rect.right = surf->surf.width; 566 1.1 riastrad rect.top = 0; 567 1.1 riastrad rect.bottom = surf->surf.height; 568 1.1 riastrad retry: 569 1.1 riastrad ret = qxl_io_update_area(qdev, surf, &rect); 570 1.1 riastrad if (ret == -ERESTARTSYS) 571 1.1 riastrad goto retry; 572 1.1 riastrad return ret; 573 1.1 riastrad } 574 1.1 riastrad 575 1.1 riastrad static void qxl_surface_evict_locked(struct qxl_device *qdev, struct qxl_bo *surf, bool do_update_area) 576 1.1 riastrad { 577 1.1 riastrad /* no need to update area if we are just freeing the surface normally */ 578 1.1 riastrad if (do_update_area) 579 1.1 riastrad qxl_update_surface(qdev, surf); 580 1.1 riastrad 581 1.1 riastrad /* nuke the surface id at the hw */ 582 1.1 riastrad qxl_hw_surface_dealloc(qdev, surf); 583 1.1 riastrad } 584 1.1 riastrad 585 1.1 riastrad void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool do_update_area) 586 1.1 riastrad { 587 1.1 riastrad mutex_lock(&qdev->surf_evict_mutex); 588 1.1 riastrad qxl_surface_evict_locked(qdev, surf, do_update_area); 589 1.1 riastrad mutex_unlock(&qdev->surf_evict_mutex); 590 1.1 riastrad } 591 1.1 riastrad 592 1.1 riastrad static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stall) 593 1.1 riastrad { 594 1.1 riastrad int ret; 595 1.1 riastrad 596 1.1 riastrad ret = qxl_bo_reserve(surf, false); 597 1.2 riastrad if (ret) 598 1.2 riastrad return ret; 599 1.1 riastrad 600 1.1 riastrad if (stall) 601 1.1 riastrad mutex_unlock(&qdev->surf_evict_mutex); 602 1.1 riastrad 603 1.3 riastrad ret = ttm_bo_wait(&surf->tbo, true, !stall); 604 1.1 riastrad 605 1.1 riastrad if (stall) 606 1.1 riastrad mutex_lock(&qdev->surf_evict_mutex); 607 1.2 riastrad if (ret) { 608 1.1 riastrad qxl_bo_unreserve(surf); 609 1.2 riastrad return ret; 610 1.1 riastrad } 611 1.1 riastrad 612 1.1 riastrad qxl_surface_evict_locked(qdev, surf, true); 613 1.1 riastrad qxl_bo_unreserve(surf); 614 1.1 riastrad return 0; 615 1.1 riastrad } 616 1.1 riastrad 617 1.1 riastrad static int qxl_reap_surface_id(struct qxl_device *qdev, int max_to_reap) 618 1.1 riastrad { 619 1.1 riastrad int num_reaped = 0; 620 1.1 riastrad int i, ret; 621 1.1 riastrad bool stall = false; 622 1.1 riastrad int start = 0; 623 1.1 riastrad 624 1.1 riastrad mutex_lock(&qdev->surf_evict_mutex); 625 1.1 riastrad again: 626 1.1 riastrad 627 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 628 1.1 riastrad start = qdev->last_alloced_surf_id + 1; 629 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 630 1.1 riastrad 631 1.1 riastrad for (i = start; i < start + qdev->rom->n_surfaces; i++) { 632 1.1 riastrad void *objptr; 633 1.1 riastrad int surfid = i % qdev->rom->n_surfaces; 634 1.1 riastrad 635 1.1 riastrad /* this avoids the case where the objects is in the 636 1.1 riastrad idr but has been evicted half way - its makes 637 1.1 riastrad the idr lookup atomic with the eviction */ 638 1.1 riastrad spin_lock(&qdev->surf_id_idr_lock); 639 1.1 riastrad objptr = idr_find(&qdev->surf_id_idr, surfid); 640 1.1 riastrad spin_unlock(&qdev->surf_id_idr_lock); 641 1.1 riastrad 642 1.1 riastrad if (!objptr) 643 1.1 riastrad continue; 644 1.1 riastrad 645 1.1 riastrad ret = qxl_reap_surf(qdev, objptr, stall); 646 1.1 riastrad if (ret == 0) 647 1.1 riastrad num_reaped++; 648 1.1 riastrad if (num_reaped >= max_to_reap) 649 1.1 riastrad break; 650 1.1 riastrad } 651 1.1 riastrad if (num_reaped == 0 && stall == false) { 652 1.1 riastrad stall = true; 653 1.1 riastrad goto again; 654 1.1 riastrad } 655 1.1 riastrad 656 1.1 riastrad mutex_unlock(&qdev->surf_evict_mutex); 657 1.1 riastrad if (num_reaped) { 658 1.1 riastrad usleep_range(500, 1000); 659 1.1 riastrad qxl_queue_garbage_collect(qdev, true); 660 1.1 riastrad } 661 1.1 riastrad 662 1.1 riastrad return 0; 663 1.1 riastrad } 664