summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/panfrost/pan_bo.c83
-rw-r--r--src/gallium/drivers/panfrost/pan_screen.c21
-rw-r--r--src/gallium/drivers/panfrost/pan_screen.h4
3 files changed, 87 insertions, 21 deletions
diff --git a/src/gallium/drivers/panfrost/pan_bo.c b/src/gallium/drivers/panfrost/pan_bo.c
index 37602688d63..aa60620ccdf 100644
--- a/src/gallium/drivers/panfrost/pan_bo.c
+++ b/src/gallium/drivers/panfrost/pan_bo.c
@@ -371,6 +371,11 @@ panfrost_bo_create(struct panfrost_screen *screen, size_t size,
}
pipe_reference_init(&bo->reference, 1);
+
+ pthread_mutex_lock(&screen->active_bos_lock);
+ _mesa_set_add(bo->screen->active_bos, bo);
+ pthread_mutex_unlock(&screen->active_bos_lock);
+
return bo;
}
@@ -390,43 +395,79 @@ panfrost_bo_unreference(struct panfrost_bo *bo)
if (!pipe_reference(&bo->reference, NULL))
return;
- /* When the reference count goes to zero, we need to cleanup */
- panfrost_bo_munmap(bo);
+ struct panfrost_screen *screen = bo->screen;
- /* Rather than freeing the BO now, we'll cache the BO for later
- * allocations if we're allowed to.
+ pthread_mutex_lock(&screen->active_bos_lock);
+ /* Someone might have imported this BO while we were waiting for the
+ * lock, let's make sure it's still not referenced before freeing it.
*/
- if (panfrost_bo_cache_put(bo))
- return;
+ if (!pipe_is_referenced(&bo->reference)) {
+ _mesa_set_remove_key(bo->screen->active_bos, bo);
- panfrost_bo_free(bo);
+ /* When the reference count goes to zero, we need to cleanup */
+ panfrost_bo_munmap(bo);
+
+ /* Rather than freeing the BO now, we'll cache the BO for later
+ * allocations if we're allowed to.
+ */
+ if (!panfrost_bo_cache_put(bo))
+ panfrost_bo_free(bo);
+ }
+ pthread_mutex_unlock(&screen->active_bos_lock);
}
struct panfrost_bo *
panfrost_bo_import(struct panfrost_screen *screen, int fd)
{
- struct panfrost_bo *bo = rzalloc(screen, struct panfrost_bo);
+ struct panfrost_bo *bo, *newbo = rzalloc(screen, struct panfrost_bo);
struct drm_panfrost_get_bo_offset get_bo_offset = {0,};
+ struct set_entry *entry;
ASSERTED int ret;
unsigned gem_handle;
- ret = drmPrimeFDToHandle(screen->fd, fd, &gem_handle);
- assert(!ret);
+ newbo->screen = screen;
- get_bo_offset.handle = gem_handle;
- ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_GET_BO_OFFSET, &get_bo_offset);
+ ret = drmPrimeFDToHandle(screen->fd, fd, &gem_handle);
assert(!ret);
- bo->screen = screen;
- bo->gem_handle = gem_handle;
- bo->gpu = (mali_ptr) get_bo_offset.offset;
- bo->size = lseek(fd, 0, SEEK_END);
- bo->flags |= PAN_BO_DONT_REUSE | PAN_BO_IMPORTED;
- assert(bo->size > 0);
- pipe_reference_init(&bo->reference, 1);
+ newbo->gem_handle = gem_handle;
+
+ pthread_mutex_lock(&screen->active_bos_lock);
+ entry = _mesa_set_search_or_add(screen->active_bos, newbo);
+ assert(entry);
+ bo = (struct panfrost_bo *)entry->key;
+ if (newbo == bo) {
+ get_bo_offset.handle = gem_handle;
+ ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_GET_BO_OFFSET, &get_bo_offset);
+ assert(!ret);
+
+ newbo->gpu = (mali_ptr) get_bo_offset.offset;
+ newbo->size = lseek(fd, 0, SEEK_END);
+ newbo->flags |= PAN_BO_DONT_REUSE | PAN_BO_IMPORTED;
+ assert(newbo->size > 0);
+ pipe_reference_init(&newbo->reference, 1);
+ // TODO map and unmap on demand?
+ panfrost_bo_mmap(newbo);
+ } else {
+ ralloc_free(newbo);
+ /* !pipe_is_referenced(&bo->reference) can happen if the BO
+ * was being released but panfrost_bo_import() acquired the
+ * lock before panfrost_bo_unreference(). In that case, refcnt
+ * is 0 and we can't use panfrost_bo_reference() directly, we
+ * have to re-initialize it with pipe_reference_init().
+ * Note that panfrost_bo_unreference() checks
+ * pipe_is_referenced() value just after acquiring the lock to
+ * make sure the object is not freed if panfrost_bo_import()
+ * acquired it in the meantime.
+ */
+ if (!pipe_is_referenced(&bo->reference))
+ pipe_reference_init(&newbo->reference, 1);
+ else
+ panfrost_bo_reference(bo);
+ assert(bo->cpu);
+ }
+ pthread_mutex_unlock(&screen->active_bos_lock);
- // TODO map and unmap on demand?
- panfrost_bo_mmap(bo);
return bo;
}
diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c
index 4c21bf3efaf..d698e5071f8 100644
--- a/src/gallium/drivers/panfrost/pan_screen.c
+++ b/src/gallium/drivers/panfrost/pan_screen.c
@@ -548,6 +548,7 @@ panfrost_destroy_screen(struct pipe_screen *pscreen)
struct panfrost_screen *screen = pan_screen(pscreen);
panfrost_bo_cache_evict_all(screen);
pthread_mutex_destroy(&screen->bo_cache_lock);
+ pthread_mutex_destroy(&screen->active_bos_lock);
drmFreeVersion(screen->kernel_version);
ralloc_free(screen);
}
@@ -681,6 +682,22 @@ panfrost_query_gpu_version(struct panfrost_screen *screen)
return get_param.value;
}
+static uint32_t
+panfrost_active_bos_hash(const void *key)
+{
+ const struct panfrost_bo *bo = key;
+
+ return _mesa_hash_data(&bo->gem_handle, sizeof(bo->gem_handle));
+}
+
+static bool
+panfrost_active_bos_cmp(const void *keya, const void *keyb)
+{
+ const struct panfrost_bo *a = keya, *b = keyb;
+
+ return a->gem_handle == b->gem_handle;
+}
+
struct pipe_screen *
panfrost_create_screen(int fd, struct renderonly *ro)
{
@@ -733,6 +750,10 @@ panfrost_create_screen(int fd, struct renderonly *ro)
return NULL;
}
+ pthread_mutex_init(&screen->active_bos_lock, NULL);
+ screen->active_bos = _mesa_set_create(screen, panfrost_active_bos_hash,
+ panfrost_active_bos_cmp);
+
pthread_mutex_init(&screen->bo_cache_lock, NULL);
for (unsigned i = 0; i < ARRAY_SIZE(screen->bo_cache); ++i)
list_inithead(&screen->bo_cache[i]);
diff --git a/src/gallium/drivers/panfrost/pan_screen.h b/src/gallium/drivers/panfrost/pan_screen.h
index f09db8011c6..2e613fbe60f 100644
--- a/src/gallium/drivers/panfrost/pan_screen.h
+++ b/src/gallium/drivers/panfrost/pan_screen.h
@@ -35,6 +35,7 @@
#include "renderonly/renderonly.h"
#include "util/u_dynarray.h"
#include "util/bitset.h"
+#include "util/set.h"
#include <panfrost-misc.h>
#include "pan_allocate.h"
@@ -85,6 +86,9 @@ struct panfrost_screen {
struct renderonly *ro;
+ pthread_mutex_t active_bos_lock;
+ struct set *active_bos;
+
pthread_mutex_t bo_cache_lock;
/* The BO cache is a set of buckets with power-of-two sizes ranging