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