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