v3d: Add support for handling OOM signals from the simulator.
authorEric Anholt <eric@anholt.net>
Tue, 2 Apr 2019 23:51:44 +0000 (16:51 -0700)
committerEric Anholt <eric@anholt.net>
Fri, 5 Apr 2019 00:30:35 +0000 (17:30 -0700)
I have v3d allocating enough initial allocation memory that we've been
passing tests without it, but to match kernel behavior more it would be
good to actually exercise the OOM path.

src/gallium/drivers/v3d/v3d_context.h
src/gallium/drivers/v3d/v3d_simulator.c
src/gallium/drivers/v3d/v3dx_simulator.c

index de902ece2050f31d8534e83c38c0d1f6ee2685fe..3b39d18145d23a9efd08de5af92f68d31e4ce869 100644 (file)
@@ -552,6 +552,7 @@ void v3d_query_init(struct pipe_context *pctx);
 
 void v3d_simulator_init(struct v3d_screen *screen);
 void v3d_simulator_destroy(struct v3d_screen *screen);
+uint32_t v3d_simulator_get_spill(uint32_t spill_size);
 int v3d_simulator_ioctl(int fd, unsigned long request, void *arg);
 void v3d_simulator_open_from_handle(int fd, int handle, uint32_t size);
 
index c5ddaa031035c82d8f983009faee9bfb1f2e66a8..6e2d25e9448f3c5d2916dc4b1cb9cde01079fdbd 100644 (file)
@@ -52,6 +52,7 @@
 #include "util/hash_table.h"
 #include "util/ralloc.h"
 #include "util/set.h"
+#include "util/u_dynarray.h"
 #include "util/u_memory.h"
 #include "util/u_mm.h"
 #include "drm-uapi/i915_drm.h"
@@ -63,6 +64,7 @@
 /** Global (across GEM fds) state for the simulator */
 static struct v3d_simulator_state {
         mtx_t mutex;
+        mtx_t submit_lock;
 
         struct v3d_hw *v3d;
         int ver;
@@ -80,6 +82,7 @@ static struct v3d_simulator_state {
         /** Mapping from GEM fd to struct v3d_simulator_file * */
         struct hash_table *fd_map;
 
+        struct util_dynarray bin_oom;
         int refcount;
 } sim_state = {
         .mutex = _MTX_INITIALIZER_NP,
@@ -162,7 +165,7 @@ set_gmp_flags(struct v3d_simulator_file *file,
  * that also contains the drm_gem_cma_object struct.
  */
 static struct v3d_simulator_bo *
-v3d_create_simulator_bo(int fd, int handle, unsigned size)
+v3d_create_simulator_bo(int fd, unsigned size)
 {
         struct v3d_simulator_file *file = v3d_get_simulator_file_for_fd(fd);
         struct v3d_simulator_bo *sim_bo = rzalloc(file,
@@ -170,7 +173,6 @@ v3d_create_simulator_bo(int fd, int handle, unsigned size)
         size = align(size, 4096);
 
         sim_bo->file = file;
-        sim_bo->handle = handle;
 
         mtx_lock(&sim_state.mutex);
         sim_bo->block = u_mmAllocMem(sim_state.heap, size + 4, GMP_ALIGN2, 0);
@@ -187,6 +189,18 @@ v3d_create_simulator_bo(int fd, int handle, unsigned size)
 
         *(uint32_t *)(sim_bo->sim_vaddr + sim_bo->size) = BO_SENTINEL;
 
+        return sim_bo;
+}
+
+static struct v3d_simulator_bo *
+v3d_create_simulator_bo_for_gem(int fd, int handle, unsigned size)
+{
+        struct v3d_simulator_file *file = v3d_get_simulator_file_for_fd(fd);
+        struct v3d_simulator_bo *sim_bo =
+                v3d_create_simulator_bo(fd, size);
+
+        sim_bo->handle = handle;
+
         /* Map the GEM buffer for copy in/out to the simulator.  i915 blocks
          * dumb mmap on render nodes, so use their ioctl directly if we're on
          * one.
@@ -238,6 +252,20 @@ v3d_create_simulator_bo(int fd, int handle, unsigned size)
         return sim_bo;
 }
 
+static int bin_fd;
+
+uint32_t
+v3d_simulator_get_spill(uint32_t spill_size)
+{
+        struct v3d_simulator_bo *sim_bo =
+                v3d_create_simulator_bo(bin_fd, spill_size);
+
+        util_dynarray_append(&sim_state.bin_oom, struct v3d_simulator_bo *,
+                             sim_bo);
+
+        return sim_bo->block->ofs;
+}
+
 static void
 v3d_free_simulator_bo(struct v3d_simulator_bo *sim_bo)
 {
@@ -331,11 +359,21 @@ v3d_simulator_submit_cl_ioctl(int fd, struct drm_v3d_submit_cl *submit)
         if (ret)
                 return ret;
 
+        mtx_lock(&sim_state.submit_lock);
+        bin_fd = fd;
         if (sim_state.ver >= 41)
                 v3d41_simulator_submit_cl_ioctl(sim_state.v3d, submit, file->gmp->ofs);
         else
                 v3d33_simulator_submit_cl_ioctl(sim_state.v3d, submit, file->gmp->ofs);
 
+        util_dynarray_foreach(&sim_state.bin_oom, struct v3d_simulator_bo *,
+                              sim_bo) {
+                v3d_free_simulator_bo(*sim_bo);
+        }
+        util_dynarray_clear(&sim_state.bin_oom);
+
+        mtx_unlock(&sim_state.submit_lock);
+
         ret = v3d_simulator_unpin_bos(file, submit);
         if (ret)
                 return ret;
@@ -352,7 +390,7 @@ v3d_simulator_submit_cl_ioctl(int fd, struct drm_v3d_submit_cl *submit)
  */
 void v3d_simulator_open_from_handle(int fd, int handle, uint32_t size)
 {
-        v3d_create_simulator_bo(fd, handle, size);
+        v3d_create_simulator_bo_for_gem(fd, handle, size);
 }
 
 /**
@@ -391,7 +429,8 @@ v3d_simulator_create_bo_ioctl(int fd, struct drm_v3d_create_bo *args)
 
         if (ret == 0) {
                 struct v3d_simulator_bo *sim_bo =
-                        v3d_create_simulator_bo(fd, args->handle, args->size);
+                        v3d_create_simulator_bo_for_gem(fd, args->handle,
+                                                        args->size);
 
                 args->offset = sim_bo->block->ofs;
         }
@@ -548,6 +587,8 @@ v3d_simulator_init_global(const struct v3d_device_info *devinfo)
                                         _mesa_hash_pointer,
                                         _mesa_key_pointer_equal);
 
+        util_dynarray_init(&sim_state.bin_oom, NULL);
+
         if (sim_state.ver >= 41)
                 v3d41_simulator_init_regs(sim_state.v3d);
         else
@@ -589,6 +630,7 @@ v3d_simulator_destroy(struct v3d_screen *screen)
         mtx_lock(&sim_state.mutex);
         if (!--sim_state.refcount) {
                 _mesa_hash_table_destroy(sim_state.fd_map, NULL);
+                util_dynarray_fini(&sim_state.bin_oom);
                 u_mmDestroy(sim_state.heap);
                 /* No memsetting the struct, because it contains the mutex. */
                 sim_state.mem = NULL;
index e6db838c0de6c1317ddd82bdb76cf55b24583ed2..c14c41f964acdd7b2313d7cb42c5b56305e425e2 100644 (file)
@@ -101,6 +101,21 @@ v3d_invalidate_caches(struct v3d_hw *v3d)
         v3d_invalidate_slices(v3d);
 }
 
+static uint32_t g_gmp_ofs;
+static void
+v3d_reload_gmp(struct v3d_hw *v3d)
+{
+        /* Completely reset the GMP. */
+        V3D_WRITE(V3D_GMP_0_CFG,
+                  V3D_GMP_0_CFG_PROTENABLE_SET);
+        V3D_WRITE(V3D_GMP_0_TABLE_ADDR, g_gmp_ofs);
+        V3D_WRITE(V3D_GMP_0_CLEAR_LOAD, ~0);
+        while (V3D_READ(V3D_GMP_0_STATUS) &
+               V3D_GMP_0_STATUS_CFG_BUSY_SET) {
+                ;
+        }
+}
+
 int
 v3dX(simulator_submit_tfu_ioctl)(struct v3d_hw *v3d,
                                  struct drm_v3d_submit_tfu *args)
@@ -167,6 +182,18 @@ v3d_isr(uint32_t hub_status)
         /* Check the per-core bits */
         if (hub_status & (1 << 0)) {
                 uint32_t core_status = V3D_READ(V3D_CTL_0_INT_STS);
+                V3D_WRITE(V3D_CTL_0_INT_CLR, core_status);
+
+                if (core_status & V3D_CTL_0_INT_STS_INT_OUTOMEM_SET) {
+                        uint32_t size = 256 * 1024;
+                        uint32_t offset = v3d_simulator_get_spill(size);
+
+                        v3d_reload_gmp(v3d);
+
+                        V3D_WRITE(V3D_PTB_0_BPOA, offset);
+                        V3D_WRITE(V3D_PTB_0_BPOS, size);
+                        return;
+                }
 
                 if (core_status & V3D_CTL_0_INT_STS_INT_GMPV_SET) {
                         fprintf(stderr, "GMP violation at 0x%08x\n",
@@ -198,7 +225,8 @@ v3dX(simulator_init_regs)(struct v3d_hw *v3d)
         V3D_WRITE(V3D_CTL_0_MISCCFG, V3D_CTL_1_MISCCFG_OVRTMUOUT_SET);
 #endif
 
-        uint32_t core_interrupts = V3D_CTL_0_INT_STS_INT_GMPV_SET;
+        uint32_t core_interrupts = (V3D_CTL_0_INT_STS_INT_GMPV_SET |
+                                    V3D_CTL_0_INT_STS_INT_OUTOMEM_SET);
         V3D_WRITE(V3D_CTL_0_INT_MSK_SET, ~core_interrupts);
         V3D_WRITE(V3D_CTL_0_INT_MSK_CLR, core_interrupts);
 
@@ -211,15 +239,8 @@ v3dX(simulator_submit_cl_ioctl)(struct v3d_hw *v3d,
                                 struct drm_v3d_submit_cl *submit,
                                 uint32_t gmp_ofs)
 {
-        /* Completely reset the GMP. */
-        V3D_WRITE(V3D_GMP_0_CFG,
-                  V3D_GMP_0_CFG_PROTENABLE_SET);
-        V3D_WRITE(V3D_GMP_0_TABLE_ADDR, gmp_ofs);
-        V3D_WRITE(V3D_GMP_0_CLEAR_LOAD, ~0);
-        while (V3D_READ(V3D_GMP_0_STATUS) &
-               V3D_GMP_0_STATUS_CFG_BUSY_SET) {
-                ;
-        }
+        g_gmp_ofs = gmp_ofs;
+        v3d_reload_gmp(v3d);
 
         v3d_invalidate_caches(v3d);