[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