[Spice-devel] [spice-protocol PATCH 10/46] qxlhw: move handle_oom, data_alloc, data_free from qxl_driver

Alon Levy alevy at redhat.com
Tue Apr 10 04:50:06 PDT 2012


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



More information about the Spice-devel mailing list