Home | History | Annotate | Line # | Download | only in qxl
      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