1/*
2 * Copyright 2009 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <stdarg.h>
28#include <errno.h>
29#include <time.h>
30#include <unistd.h>
31
32#include "qxl.h"
33#include "mspace.h"
34
35#include "qxl_surface.h"
36#ifdef DEBUG_QXL_MEM
37#include <valgrind/memcheck.h>
38#endif
39
40#define QXL_BO_DATA 1
41#define QXL_BO_SURF 2
42#define QXL_BO_CMD 4
43#define QXL_BO_SURF_PRIMARY 8
44
45#define QXL_BO_FLAG_FAIL 1
46
47
48struct qxl_mem
49{
50    mspace	space;
51    void *	base;
52    unsigned long n_bytes;
53#ifdef DEBUG_QXL_MEM
54    size_t used_initial;
55    int unverifiable;
56    int missing;
57#endif
58};
59
60#ifdef DEBUG_QXL_MEM
61void
62qxl_mem_unverifiable(struct qxl_mem *mem)
63{
64    mem->unverifiable = 1;
65}
66#endif
67
68static void __attribute__ ((format (gnu_printf, 2, 3)))
69errout (void *data, const char *format, ...)
70{
71    va_list va;
72
73    va_start (va, format);
74
75    VErrorF (format, va);
76
77    va_end (va);
78}
79
80static void __attribute__ ((__noreturn__))
81qxl_mspace_abort_func (void *user_data)
82{
83    abort ();
84}
85
86void
87qxl_mem_init(void)
88{
89    mspace_set_print_func (errout);
90    mspace_set_abort_func (qxl_mspace_abort_func);
91}
92
93struct qxl_mem *
94qxl_mem_create       (void                   *base,
95		      unsigned long           n_bytes)
96{
97    struct qxl_mem *mem;
98
99    mem = calloc (sizeof (*mem), 1);
100    if (!mem)
101	goto out;
102
103    ErrorF ("memory space from %p to %p\n", base, (char *)base + n_bytes);
104
105
106    mem->space = create_mspace_with_base (base, n_bytes, 0, NULL);
107
108    mem->base = base;
109    mem->n_bytes = n_bytes;
110
111#ifdef DEBUG_QXL_MEM
112    {
113        size_t used;
114
115        mspace_malloc_stats_return(mem->space, NULL, NULL, &used);
116        mem->used_initial = used;
117        mem->unverifiable = 0;
118        mem->missing = 0;
119    }
120#endif
121
122out:
123    return mem;
124
125}
126
127void
128qxl_mem_dump_stats   (struct qxl_mem         *mem,
129		      const char             *header)
130{
131    ErrorF ("%s\n", header);
132
133    mspace_malloc_stats (mem->space);
134}
135
136static void *
137qxl_alloc            (struct qxl_mem         *mem,
138		      unsigned long           n_bytes,
139		      const char             *name)
140{
141    void *addr = mspace_malloc (mem->space, n_bytes);
142
143#ifdef DEBUG_QXL_MEM
144    VALGRIND_MALLOCLIKE_BLOCK(addr, n_bytes, 0, 0);
145#ifdef DEBUG_QXL_MEM_VERBOSE
146    fprintf(stderr, "alloc %p: %ld (%s)\n", addr, n_bytes, name);
147#endif
148#endif
149    return addr;
150}
151
152static void
153qxl_free             (struct qxl_mem         *mem,
154		      void                   *d,
155		      const char *            name)
156{
157#if 0
158    ErrorF ("%p <= free %s\n", d, name);
159#endif
160    mspace_free (mem->space, d);
161#ifdef DEBUG_QXL_MEM
162#ifdef DEBUG_QXL_MEM_VERBOSE
163    fprintf(stderr, "free  %p %s\n", d, name);
164#endif
165    VALGRIND_FREELIKE_BLOCK(d, 0);
166#endif
167}
168
169void
170qxl_mem_free_all     (struct qxl_mem         *mem)
171{
172#ifdef DEBUG_QXL_MEM
173    size_t maxfp, fp, used;
174
175    if (mem->space)
176    {
177        mspace_malloc_stats_return(mem->space, &maxfp, &fp, &used);
178        mem->missing = used - mem->used_initial;
179        ErrorF ("untracked %zd bytes (%s)", used - mem->used_initial,
180            mem->unverifiable ? "marked unverifiable" : "oops");
181    }
182#endif
183    mem->space = create_mspace_with_base (mem->base, mem->n_bytes, 0, NULL);
184}
185
186static uint8_t
187setup_slot (qxl_screen_t *qxl, uint8_t slot_index_offset,
188            unsigned long start_phys_addr, unsigned long end_phys_addr,
189            uint64_t start_virt_addr, uint64_t end_virt_addr)
190{
191    uint64_t       high_bits;
192    qxl_memslot_t *slot;
193    uint8_t        slot_index;
194    struct QXLRam *ram_header;
195
196    ram_header = (void *)((unsigned long)qxl->ram + (unsigned long)qxl->rom->ram_header_offset);
197
198    slot_index = qxl->rom->slots_start + slot_index_offset;
199    slot = &qxl->mem_slots[slot_index];
200    slot->start_phys_addr = start_phys_addr;
201    slot->end_phys_addr = end_phys_addr;
202    slot->start_virt_addr = start_virt_addr;
203    slot->end_virt_addr = end_virt_addr;
204
205    ram_header->mem_slot.mem_start = slot->start_phys_addr;
206    ram_header->mem_slot.mem_end = slot->end_phys_addr;
207
208    qxl_io_memslot_add (qxl, slot_index);
209
210    slot->generation = qxl->rom->slot_generation;
211
212    high_bits = slot_index << qxl->slot_gen_bits;
213    high_bits |= slot->generation;
214    high_bits <<= (64 - (qxl->slot_gen_bits + qxl->slot_id_bits));
215    slot->high_bits = high_bits;
216
217    return slot_index;
218}
219
220void
221qxl_reset_and_create_mem_slots (qxl_screen_t *qxl)
222{
223    ioport_write (qxl, QXL_IO_RESET, 0);
224    qxl->device_primary = QXL_DEVICE_PRIMARY_NONE;
225    /* Mem slots */
226    ErrorF ("slots start: %d, slots end: %d\n",
227            qxl->rom->slots_start,
228            qxl->rom->slots_end);
229
230    /* Main slot */
231    qxl->n_mem_slots = qxl->rom->slots_end;
232    qxl->slot_gen_bits = qxl->rom->slot_gen_bits;
233    qxl->slot_id_bits = qxl->rom->slot_id_bits;
234    qxl->va_slot_mask = (~(uint64_t)0) >> (qxl->slot_id_bits + qxl->slot_gen_bits);
235
236    qxl->mem_slots = xnfalloc (qxl->n_mem_slots * sizeof (qxl_memslot_t));
237
238#ifdef XSPICE
239    qxl->main_mem_slot = qxl->vram_mem_slot = setup_slot (qxl, 0, 0, ~0, 0, ~0);
240#else /* QXL */
241    qxl->main_mem_slot = setup_slot (qxl, 0,
242                                     (unsigned long)qxl->ram_physical,
243                                     (unsigned long)qxl->ram_physical + qxl->surface0_size +
244                                     (unsigned long)qxl->rom->num_pages * getpagesize (),
245                                     (uint64_t)(uintptr_t)qxl->ram,
246                                     (uint64_t)(uintptr_t)qxl->ram + qxl->surface0_size +
247                                     (unsigned long)qxl->rom->num_pages * getpagesize ()
248	);
249    qxl->vram_mem_slot = setup_slot (qxl, 1,
250                                     (unsigned long)qxl->vram_physical,
251                                     (unsigned long)qxl->vram_physical + (unsigned long)qxl->vram_size,
252                                     (uint64_t)(uintptr_t)qxl->vram,
253                                     (uint64_t)(uintptr_t)qxl->vram + (uint64_t)qxl->vram_size);
254#endif
255
256    qxl_allocate_monitors_config(qxl);
257}
258
259void
260qxl_mark_mem_unverifiable (qxl_screen_t *qxl)
261{
262    qxl_mem_unverifiable (qxl->mem);
263    qxl_mem_unverifiable (qxl->surf_mem);
264}
265
266
267static uint64_t
268qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
269{
270    /* We assume that there the two low bits of a pointer are
271     * available. If the low one is set, then the command in
272     * question is a cursor command
273     */
274#define POINTER_MASK ((1 << 2) - 1)
275
276    struct qxl_bo *info_bo = (struct qxl_bo *)u64_to_pointer(id & ~POINTER_MASK);
277    union QXLReleaseInfo *info = qxl->bo_funcs->bo_map(info_bo);
278    struct QXLCursorCmd *cmd = (struct QXLCursorCmd *)info;
279    struct QXLDrawable *drawable = (struct QXLDrawable *)info;
280    struct QXLSurfaceCmd *surface_cmd = (struct QXLSurfaceCmd *)info;
281    int is_cursor = FALSE;
282    int is_surface = FALSE;
283    int is_drawable = FALSE;
284    struct qxl_bo *to_free;
285
286    if ((id & POINTER_MASK) == 1)
287	is_cursor = TRUE;
288    else if ((id & POINTER_MASK) == 2)
289	is_surface = TRUE;
290    else
291	is_drawable = TRUE;
292
293    if (is_cursor && cmd->type == QXL_CURSOR_SET)
294    {
295	to_free = qxl_ums_lookup_phy_addr(qxl, cmd->u.set.shape);
296	qxl->bo_funcs->bo_decref (qxl, to_free);
297    }
298    else if (is_drawable && drawable->type == QXL_DRAW_COPY)
299    {
300	struct QXLImage *image;
301
302	to_free = qxl_ums_lookup_phy_addr(qxl, drawable->u.copy.src_bitmap);
303	image = qxl->bo_funcs->bo_map(to_free);
304
305	if (image->descriptor.type == SPICE_IMAGE_TYPE_SURFACE)
306	{
307	    qxl_surface_unref (qxl->surface_cache, image->surface_image.surface_id);
308	    qxl_surface_cache_sanity_check (qxl->surface_cache);
309	    qxl->bo_funcs->bo_unmap(to_free);
310	    qxl->bo_funcs->bo_decref (qxl, to_free);
311	}
312	else
313	{
314	    qxl->bo_funcs->bo_unmap(to_free);
315	    qxl_image_destroy (qxl, to_free);
316	}
317    }
318    else if (is_drawable && drawable->type == QXL_DRAW_COMPOSITE)
319    {
320	struct qxl_bo *bo;
321	struct QXLComposite *composite = &drawable->u.composite;
322
323	/* Source */
324	bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.src);
325	qxl->bo_funcs->bo_decref (qxl, bo);
326
327	if (composite->src_transform)
328	{
329	    bo = qxl_ums_lookup_phy_addr(qxl, composite->src_transform);
330	    qxl->bo_funcs->bo_decref (qxl, bo);
331	}
332
333	/* Mask */
334	if (drawable->u.composite.mask)
335	{
336	    if (drawable->u.composite.mask_transform)
337	    {
338		bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.mask_transform);
339		qxl->bo_funcs->bo_decref (qxl, bo);
340	    }
341	    bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.mask);
342	    qxl->bo_funcs->bo_decref (qxl, bo);
343	}
344    }
345    else if (is_surface && surface_cmd->type == QXL_SURFACE_CMD_DESTROY)
346    {
347	qxl_surface_recycle (qxl->surface_cache, surface_cmd->surface_id);
348	qxl_surface_cache_sanity_check (qxl->surface_cache);
349    }
350
351    id = info->next;
352
353    qxl->bo_funcs->bo_unmap(info_bo);
354    qxl->bo_funcs->bo_decref(qxl, info_bo);
355
356    return id;
357}
358
359int
360qxl_garbage_collect (qxl_screen_t *qxl)
361{
362    uint64_t id;
363    int      i = 0;
364
365    while (qxl_ring_pop (qxl->release_ring, &id))
366    {
367	while (id)
368	{
369	    id = qxl_garbage_collect_internal (qxl, id);
370
371	    i++;
372	}
373    }
374
375    return i;
376}
377
378static void
379qxl_usleep (int useconds)
380{
381    struct timespec t;
382
383    t.tv_sec = useconds / 1000000;
384    t.tv_nsec = (useconds - (t.tv_sec * 1000000)) * 1000;
385
386    errno = 0;
387    while (nanosleep (&t, &t) == -1 && errno == EINTR)
388	;
389}
390
391int
392qxl_handle_oom (qxl_screen_t *qxl)
393{
394    qxl_io_notify_oom (qxl);
395
396#if 0
397    ErrorF (".");
398    qxl_usleep (10000);
399#endif
400
401    if (!(qxl_garbage_collect (qxl)))
402	qxl_usleep (10000);
403
404    return qxl_garbage_collect (qxl);
405}
406
407static void *
408qxl_allocnf (qxl_screen_t *qxl, unsigned long size, const char *name)
409{
410    void *result;
411    int n_attempts = 0;
412
413#if 0
414    static int nth_oom = 1;
415#endif
416
417    qxl_garbage_collect (qxl);
418
419    while (!(result = qxl_alloc (qxl->mem, size, name)))
420    {
421#if 0
422	ErrorF ("eliminated memory (%d)\n", nth_oom++);
423#endif
424	if (!qxl_garbage_collect (qxl))
425	{
426	    if (qxl_handle_oom (qxl))
427	    {
428		n_attempts = 0;
429	    }
430	    else if (++n_attempts == 1000)
431	    {
432		ErrorF ("Out of memory allocating %ld bytes\n", size);
433		qxl_mem_dump_stats (qxl->mem, "Out of mem - stats\n");
434		fprintf (stderr, "Out of memory\n");
435		exit (1);
436	    }
437	}
438    }
439
440    return result;
441}
442
443struct qxl_ums_bo {
444    void *virt_addr;
445    const char *name;
446    int type;
447    uint32_t size;
448    void *internal_virt_addr;
449    int refcnt;
450    qxl_screen_t *qxl;
451    xorg_list_t bos;
452};
453
454static struct qxl_bo *qxl_bo_alloc_internal(qxl_screen_t *qxl, int type, int flags, unsigned long size, const char *name)
455{
456    struct qxl_ums_bo *bo;
457    struct qxl_mem *mptr;
458
459    bo = calloc(1, sizeof(struct qxl_ums_bo));
460    if (!bo)
461	return NULL;
462
463    bo->size = size;
464    bo->name = name;
465    bo->type = type;
466    bo->qxl = qxl;
467    bo->refcnt = 1;
468    if (type == QXL_BO_SURF)
469	mptr = qxl->surf_mem;
470    else
471	mptr = qxl->mem;
472
473    if (flags & QXL_BO_FLAG_FAIL) {
474	bo->internal_virt_addr = qxl_alloc(mptr, size, name);
475	if (!bo->internal_virt_addr) {
476	    free(bo);
477	    return NULL;
478	}
479    } else
480	bo->internal_virt_addr = qxl_allocnf(qxl, size, name);
481
482    if (type != QXL_BO_SURF) {
483	xorg_list_add(&bo->bos, &qxl->ums_bos);
484    }
485    return (struct qxl_bo *)bo;
486}
487
488static struct qxl_bo *qxl_bo_alloc(qxl_screen_t *qxl, unsigned long size, const char *name)
489{
490    return qxl_bo_alloc_internal(qxl, QXL_BO_DATA, 0, size, name);
491}
492
493static struct qxl_bo *qxl_cmd_alloc(qxl_screen_t *qxl, unsigned long size, const char *name)
494{
495    return qxl_bo_alloc_internal(qxl, QXL_BO_CMD, 0, size, name);
496}
497
498static void *qxl_bo_map(struct qxl_bo *_bo)
499{
500    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
501    if (bo->virt_addr)
502	ErrorF("recursive map %p\n", bo);
503    bo->virt_addr = bo->internal_virt_addr;
504    return bo->virt_addr;
505}
506
507static void qxl_bo_unmap(struct qxl_bo *_bo)
508{
509    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
510    if (!bo->virt_addr)
511	ErrorF("unbalanced unmap %p\n", bo);
512    bo->virt_addr = NULL;
513}
514
515static void qxl_bo_output_bo_reloc(qxl_screen_t *qxl, uint32_t dst_offset,
516				struct qxl_bo *_dst_bo,
517				struct qxl_bo *_src_bo)
518{
519    struct qxl_ums_bo *src_bo = (struct qxl_ums_bo *)_src_bo;
520    struct qxl_ums_bo *dst_bo = (struct qxl_ums_bo *)_dst_bo;
521    uint8_t slot_id;
522    uint64_t value;
523
524    /* take a reference on the bo */
525    src_bo->refcnt++;
526
527    slot_id = src_bo->type == QXL_BO_SURF ? qxl->vram_mem_slot : qxl->main_mem_slot;
528    value = physical_address(qxl, src_bo->internal_virt_addr, slot_id);
529
530    *(uint64_t *)((char *)dst_bo->internal_virt_addr + dst_offset) = value;
531}
532
533static void qxl_bo_output_cmd_reloc(qxl_screen_t *qxl, QXLCommand *command,
534				    struct qxl_bo *_src_bo)
535{
536    struct qxl_ums_bo *src_bo = (struct qxl_ums_bo *)_src_bo;
537    uint64_t value;
538    uint8_t slot_id;
539
540    src_bo->refcnt++;
541
542    slot_id = src_bo->type == QXL_BO_SURF ? qxl->vram_mem_slot : qxl->main_mem_slot;
543    value = physical_address(qxl, src_bo->internal_virt_addr, slot_id);
544
545    command->data = value;
546}
547
548struct qxl_bo *qxl_ums_lookup_phy_addr(qxl_screen_t *qxl, uint64_t phy_addr)
549{
550    struct qxl_ums_bo *bo, *found = NULL;
551    uint8_t slot_id;
552    void *virt_addr;
553
554    slot_id = qxl->main_mem_slot;
555    virt_addr = (void *)virtual_address(qxl, u64_to_pointer(phy_addr), slot_id);
556
557    xorg_list_for_each_entry(bo, &qxl->ums_bos, bos) {
558	if (bo->internal_virt_addr == virt_addr && bo->type == QXL_BO_DATA) {
559	    found = bo;
560	    break;
561	}
562    }
563    return (struct qxl_bo *)found;
564}
565
566static void qxl_bo_incref(qxl_screen_t *qxl, struct qxl_bo *_bo)
567{
568    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
569    bo->refcnt++;
570}
571
572static void qxl_bo_decref(qxl_screen_t *qxl, struct qxl_bo *_bo)
573{
574    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
575    struct qxl_mem *mptr;
576
577    bo->refcnt--;
578
579    if (bo->refcnt > 0)
580	return;
581
582    if (bo->type == QXL_BO_SURF_PRIMARY)
583        goto out_free;
584
585    if (bo->type == QXL_BO_SURF)
586	mptr = qxl->surf_mem;
587    else
588	mptr = qxl->mem;
589
590    qxl_free(mptr, bo->internal_virt_addr, bo->name);
591    if (bo->type != QXL_BO_SURF)
592	xorg_list_del(&bo->bos);
593out_free:
594    free(bo);
595}
596
597static void qxl_bo_write_command(qxl_screen_t *qxl, uint32_t cmd_type, struct qxl_bo *bo)
598{
599    struct QXLCommand cmd;
600
601    /* When someone runs "init 3", the device will be
602     * switched into VGA mode and there is nothing we
603     * can do about it. We get no notification.
604     *
605     * However, if commands are submitted when the device
606     * is in VGA mode, they will be queued up, and then
607     * the next time a mode set set, an assertion in the
608     * device will take down the entire virtual machine.
609     *
610     * For surface commands this is not relevant, we send
611     * them regardless.
612     */
613
614    if (!qxl->pScrn->vtSema && cmd_type != QXL_CMD_SURFACE)
615	return;
616
617    cmd.type = cmd_type;
618    qxl_bo_output_cmd_reloc(qxl, &cmd, bo);
619
620    if (cmd_type == QXL_CMD_CURSOR)
621	qxl_ring_push (qxl->cursor_ring, &cmd);
622    else
623	qxl_ring_push (qxl->command_ring, &cmd);
624
625    qxl_bo_decref(qxl, bo);
626}
627
628static void qxl_bo_update_area(qxl_surface_t *surf, int x1, int y1, int x2, int y2)
629{
630    struct QXLRam *ram_header = get_ram_header(surf->qxl);
631
632    ram_header->update_area.top = y1;
633    ram_header->update_area.bottom = y2;
634    ram_header->update_area.left = x1;
635    ram_header->update_area.right = x2;
636
637    ram_header->update_surface = surf->id;
638
639    qxl_update_area(surf->qxl);
640}
641
642/* create a fake bo for the primary */
643static struct qxl_bo *qxl_bo_create_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height, int32_t stride, uint32_t format)
644{
645    struct qxl_ums_bo *bo;
646    struct QXLRam *ram_header =
647	(void *)((unsigned long)qxl->ram + qxl->rom->ram_header_offset);
648
649    struct QXLSurfaceCreate *create = &(ram_header->create_surface);
650
651    create->width = width;
652    create->height = height;
653    create->stride = - stride;
654    create->format = format;
655    create->position = 0; /* What is this? The Windows driver doesn't use it */
656    create->flags = 0;
657    create->type = QXL_SURF_TYPE_PRIMARY;
658    create->mem = physical_address (qxl, qxl->ram, qxl->main_mem_slot);
659
660    qxl_io_create_primary(qxl);
661
662    bo = calloc(1, sizeof(struct qxl_ums_bo));
663    if (!bo)
664        return NULL;
665
666    bo->size = stride * height;
667    bo->name = "primary";
668    bo->type = QXL_BO_SURF_PRIMARY;
669    bo->qxl = qxl;
670    bo->refcnt = 1;
671    bo->internal_virt_addr = (uint8_t *)qxl->ram + stride * (height - 1);
672
673    qxl->primary_bo = (struct qxl_bo *)bo;
674    return (struct qxl_bo *)bo;
675}
676
677static void qxl_bo_destroy_primary(qxl_screen_t *qxl, struct qxl_bo *bo)
678{
679    free(bo);
680    qxl->primary_bo = NULL;
681
682    qxl_io_destroy_primary (qxl);
683}
684
685static void qxl_bo_output_surf_reloc(qxl_screen_t *qxl, uint32_t dst_offset,
686				     struct qxl_bo *_dst_bo, qxl_surface_t *surf)
687{
688    struct qxl_ums_bo *dst_bo = (struct qxl_ums_bo *)_dst_bo;
689
690    *(uint32_t *)((char *)dst_bo->internal_virt_addr + dst_offset) = surf->id;
691}
692
693static struct qxl_bo_funcs qxl_ums_bo_funcs = {
694    qxl_bo_alloc,
695    qxl_cmd_alloc,
696    qxl_bo_map,
697    qxl_bo_unmap,
698    qxl_bo_decref,
699    qxl_bo_incref,
700    qxl_bo_output_bo_reloc,
701    qxl_bo_write_command,
702    qxl_bo_update_area,
703    qxl_bo_create_primary,
704    qxl_bo_destroy_primary,
705    qxl_surface_create,
706    qxl_surface_kill,
707    qxl_bo_output_surf_reloc,
708};
709
710void qxl_ums_setup_funcs(qxl_screen_t *qxl)
711{
712    qxl->bo_funcs = &qxl_ums_bo_funcs;
713}
714
715struct qxl_bo *qxl_ums_surf_mem_alloc(qxl_screen_t *qxl, uint32_t size)
716{
717    struct qxl_bo *bo;
718    bo = qxl_bo_alloc_internal (qxl, QXL_BO_SURF, QXL_BO_FLAG_FAIL, size, "surface memory");
719    return bo;
720}
721