data_alloc and data_free unused yet. --- src/qxl_driver.c | 32 +--------- src/qxl_mem.h | 1 - src/qxl_surface.c | 4 +- src/qxlhw.c | 12 ++++ src/qxlhw.h | 12 ++++ src/qxlhw_pci.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 211 insertions(+), 34 deletions(-)
diff --git a/src/qxl_driver.c b/src/qxl_driver.c index a4c5912..0db9221 100644 --- a/src/qxl_driver.c +++ b/src/qxl_driver.c @@ -235,36 +235,6 @@ qxl_garbage_collect (qxl_screen_t *qxl) return i; } -static void -qxl_usleep (int useconds) -{ - struct timespec t; - - t.tv_sec = useconds / 1000000; - t.tv_nsec = (useconds - (t.tv_sec * 1000000)) * 1000; - - errno = 0; - while (nanosleep (&t, &t) == -1 && errno == EINTR) - ; - -} - -int -qxl_handle_oom (qxl_screen_t *qxl) -{ - qxl_notify_oom(qxl); - -#if 0 - ErrorF ("."); - qxl_usleep (10000); -#endif - - if (!(qxl_garbage_collect (qxl))) - qxl_usleep (10000); - - return qxl_garbage_collect (qxl); -} - void * qxl_allocnf (qxl_screen_t *qxl, unsigned long size) { @@ -294,7 +264,7 @@ qxl_allocnf (qxl_screen_t *qxl, unsigned long size) if (!qxl_garbage_collect (qxl)) { - if (qxl_handle_oom (qxl)) + if (qxlhw_handle_oom (qxl->hw)) { n_attempts = 0; } diff --git a/src/qxl_mem.h b/src/qxl_mem.h index 7645373..bb40992 100644 --- a/src/qxl_mem.h +++ b/src/qxl_mem.h @@ -16,6 +16,5 @@ void *qxl_alloc (struct qxl_mem *mem, void qxl_free (struct qxl_mem *mem, void *d); void qxl_mem_free_all (struct qxl_mem *mem); -int qxl_handle_oom (qxl_screen_t *qxl); #endif // QXL_MEM_H diff --git a/src/qxl_surface.c b/src/qxl_surface.c index 2ae7124..8052998 100644 --- a/src/qxl_surface.c +++ b/src/qxl_surface.c @@ -562,7 +562,7 @@ retry2: ErrorF ("- OOM at %d %d %d\n", width, height, bpp); print_cache_info (cache); - if (qxl_handle_oom (qxl)) + if (qxlhw_handle_oom (qxl->hw)) { while (qxl_garbage_collect (qxl)) ; @@ -579,7 +579,7 @@ retry: surface = surface_get_from_free_list (cache); if (!surface) { - if (!qxl_handle_oom (qxl)) + if (!qxlhw_handle_oom (qxl->hw)) { ErrorF (" Out of surfaces\n"); qxl_free (qxl->surf_mem, address); diff --git a/src/qxlhw.c b/src/qxlhw.c index 42ca0db..d412c83 100644 --- a/src/qxlhw.c +++ b/src/qxlhw.c @@ -48,7 +48,19 @@ void qxlhw_unmap_memory(struct qxlhw *base, int scrnIndex) base->unmap_memory(base, scrnIndex); } +void *qxlhw_data_alloc(struct qxlhw *base, unsigned long size) +{ + return base->data_alloc(base, size); +} + void qxlhw_update_area(struct qxlhw *base, int surface_id, struct QXLRect rect) { base->update_area(base, surface_id, rect); } + +/* tried to avoid this. but qxl_surface.c wants to check when failing to find + * a surface in the free list, which it populates using qxl_surface_alloc (should) */ +Bool qxlhw_handle_oom(struct qxlhw *base) +{ + return base->handle_oom(base); +} diff --git a/src/qxlhw.h b/src/qxlhw.h index 67e7edd..34023d0 100644 --- a/src/qxlhw.h +++ b/src/qxlhw.h @@ -17,7 +17,13 @@ struct qxlhw { void (*unmap_memory)(struct qxlhw *base, int scrnIndex); /* memory handling callbacks */ + void *(*data_alloc)(struct qxlhw *base, unsigned long size); + void (*data_free)(struct qxlhw *base, void *p); void (*update_area)(struct qxlhw *base, int surface_id, struct QXLRect rect); + /* tried to avoid this. but qxl_surface.c wants to check when failing to + * find a surface in the free list, which it populates using + * qxl_surface_alloc (should) */ + Bool (*handle_oom)(struct qxlhw *base); }; void qxlhw_init(struct qxlhw *base, qxl_screen_t *qxl); @@ -39,4 +45,10 @@ void qxlhw_restore_state(struct qxlhw *base, ScrnInfoPtr pScrn); Bool qxlhw_map_memory(struct qxlhw *base, int scrnIndex); void qxlhw_unmap_memory(struct qxlhw *base, int scrnIndex); +/* memory translation, relocations. */ +void *qxlhw_data_alloc(struct qxlhw *base, unsigned long size); +void qxlhw_data_free(struct qxlhw *base, void *p); + +Bool qxlhw_handle_oom(struct qxlhw *base); + #endif // QXLHW_H diff --git a/src/qxlhw_pci.c b/src/qxlhw_pci.c index d6a0b63..1caf778 100644 --- a/src/qxlhw_pci.c +++ b/src/qxlhw_pci.c @@ -1,6 +1,8 @@ /* vim: set ts=8 : */ #include <unistd.h> +#include <errno.h> +#include <time.h> #include "qxl_ring.h" #include "qxl_mem.h" @@ -54,6 +56,28 @@ struct qxlhw_pci { #endif /* XSPICE */ }; +static void qxlhw_pci_update_area(struct qxlhw *base, int surface_id, struct QXLRect rect); + +static inline uint64_t +qxlhw_physical_address (struct qxlhw_pci *hw, void *virtual, uint8_t slot_id) +{ + qxl_memslot_t *p_slot = &(hw->mem_slots[slot_id]); + + return p_slot->high_bits | ((unsigned long)virtual - p_slot->start_virt_addr); +} + +static inline void * +qxlhw_virtual_address (struct qxlhw_pci *hw, void *physical, uint8_t slot_id) +{ + qxl_memslot_t *p_slot = &(hw->mem_slots[slot_id]); + unsigned long virt; + + virt = ((unsigned long)physical) & hw->va_slot_mask; + virt += p_slot->start_virt_addr; + + return (void *)virt; +} + struct QXLRam * qxlhw_pci_get_ram_header (struct qxlhw *base) { @@ -103,6 +127,150 @@ static void qxlhw_pci_memslot_add(struct qxlhw_pci *hw, uint8_t id) #endif } +static void qxlhw_pci_notify_oom(struct qxlhw_pci *hw) +{ + qxlhw_pci_ioport_write(hw, QXL_IO_NOTIFY_OOM, 0); +} + +static int +qxlhw_pci_flush_release_ring (struct qxlhw_pci *hw) +{ + uint64_t id; + int i = 0; + qxl_screen_t *qxl = hw->base.qxl; + + while (qxl_ring_pop (hw->release_ring, &id)) + { + while (id) + { + /* We assume that there the two low bits of a pointer are + * available. If the low one is set, then the command in + * question is a cursor command + */ +#define POINTER_MASK ((1 << 2) - 1) + + union QXLReleaseInfo *info = u64_to_pointer (id & ~POINTER_MASK); + struct QXLCursorCmd *cmd = (struct QXLCursorCmd *)info; + struct QXLDrawable *drawable = (struct QXLDrawable *)info; + struct QXLSurfaceCmd *surface_cmd = (struct QXLSurfaceCmd *)info; + int is_cursor = FALSE; + int is_surface = FALSE; + int is_drawable = FALSE; + + if ((id & POINTER_MASK) == 1) + is_cursor = TRUE; + else if ((id & POINTER_MASK) == 2) + is_surface = TRUE; + else + is_drawable = TRUE; + + if (is_cursor && cmd->type == QXL_CURSOR_SET) + { + struct QXLCursor *cursor = (void *)qxlhw_virtual_address ( + hw, u64_to_pointer (cmd->u.set.shape), hw->main_mem_slot); + + qxl_free (hw->mem, cursor); + } + else if (is_drawable && drawable->type == QXL_DRAW_COPY) + { + struct QXLImage *image = qxlhw_virtual_address ( + hw, u64_to_pointer (drawable->u.copy.src_bitmap), hw->main_mem_slot); + + if (image->descriptor.type == SPICE_IMAGE_TYPE_SURFACE) + { + qxl_surface_unref (qxl->surface_cache, image->surface_image.surface_id); + qxl_surface_cache_sanity_check (qxl->surface_cache); + qxl_free (hw->mem, image); + } + else + { + qxl_image_destroy (qxl, image); + } + } + else if (is_surface && surface_cmd->type == QXL_SURFACE_CMD_DESTROY) + { + qxl_surface_recycle (qxl->surface_cache, surface_cmd->surface_id); + qxl_surface_cache_sanity_check (qxl->surface_cache); + } + + id = info->next; + + qxl_free (hw->mem, info); + + ++i; + } + } + + return i; +} + +static void +qxl_usleep (int useconds) +{ + struct timespec t; + + t.tv_sec = useconds / 1000000; + t.tv_nsec = (useconds - (t.tv_sec * 1000000)) * 1000; + + errno = 0; + while (nanosleep (&t, &t) == -1 && errno == EINTR) + ; + +} + +static int +qxlhw_pci_handle_oom (struct qxlhw_pci *hw) +{ + qxlhw_pci_notify_oom(hw); + + if (!(qxlhw_pci_flush_release_ring (hw))) + qxl_usleep (10000); + + return qxlhw_pci_flush_release_ring (hw); +} + +static void * +qxlhw_pci_allocnf (struct qxlhw_pci *hw, struct qxl_mem *mem, unsigned long size) +{ + void *result; + int n_attempts = 0; + QXLRect rect; + qxl_screen_t *qxl = hw->base.qxl; + + qxlhw_pci_flush_release_ring (hw); + + while (!(result = qxl_alloc (mem, size))) + { + /* Rather than go out of memory, we simply tell the + * device to dump everything + */ + rect.top = 0; + rect.bottom = qxl->virtual_y; + rect.left = 0; + rect.right = qxl->virtual_x; + + qxlhw_pci_update_area(&hw->base, 0, rect); + + if (!qxlhw_pci_flush_release_ring (hw)) + { + if (qxlhw_pci_handle_oom (hw)) + { + n_attempts = 0; + } + else if (++n_attempts == 1000) + { + ErrorF ("Out of memory allocating %ld bytes\n", size); + qxl_mem_dump_stats (hw->mem, "Out of mem - stats\n"); + + fprintf (stderr, "Out of memory\n"); + exit (1); + } + } + } + + return result; +} + #ifdef XSPICE static void unmap_memory_helper(struct qxlhw_pci *hw, int scrnIndex) @@ -389,6 +557,20 @@ static void qxlhw_pci_restore_state(struct qxlhw *base, ScrnInfoPtr pScrn) #endif } +static void *qxlhw_pci_data_alloc(struct qxlhw *base, unsigned long size) +{ + struct qxlhw_pci *hw = (struct qxlhw_pci *)base; + + return qxlhw_pci_allocnf(hw, hw->mem, size); +} + +static void qxlhw_pci_data_free(struct qxlhw *base, void *p) +{ + struct qxlhw_pci *hw = (struct qxlhw_pci *)base; + + qxl_free (hw->mem, p); +} + static void qxlhw_pci_update_area(struct qxlhw *base, int surface_id, struct QXLRect rect) { struct qxlhw_pci *hw = (struct qxlhw_pci *)base; @@ -424,6 +606,8 @@ struct qxlhw *create_qxlhw_pci(qxl_screen_t *qxl, ScrnInfoPtr pScrn) base->restore_state = qxlhw_pci_restore_state; base->map_memory = qxlhw_pci_map_memory; base->unmap_memory = qxlhw_pci_unmap_memory; + base->data_alloc = qxlhw_pci_data_alloc; + base->data_free = qxlhw_pci_data_free; base->update_area = qxlhw_pci_update_area; return base; } -- 1.7.9.3 _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel