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

Reply via email to