Skip to content

Commit

Permalink
Implement asynchronous free() call
Browse files Browse the repository at this point in the history
which can be called from any context where fast taskqueue are available.
Use it in i915_sw_fence code to fix #9.
  • Loading branch information
wulf7 committed Nov 14, 2020
1 parent 84d9c2e commit a1cee43
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions drivers/gpu/drm/i915/i915_sw_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
#include <linux/irq_work.h>
#include <linux/dma-resv.h>

#ifndef __linux__
#include <sys/param.h> /* __FreeBSD_version */
#include <linux/llist.h>
#endif

#include "i915_sw_fence.h"
#include "i915_selftest.h"

Expand All @@ -21,6 +26,21 @@ enum {
DEBUG_FENCE_NOTIFY,
};

#if defined(__FreeBSD__) && __FreeBSD_version > 1300127
static void linux_kfree_async(void *);
/*
* Critical section-friendly version of kfree().
* Requires knowledge of the allocation size at build time.
*/
#define KFREE(addr) do { \
BUILD_BUG_ON(sizeof(*(addr)) < sizeof(struct llist_node)); \
if (curthread->td_critnest != 0) \
linux_kfree_async(addr); \
else \
kfree(addr); \
} while (0);
#endif

static void *i915_sw_fence_debug_hint(void *addr)
{
return (void *)(((struct i915_sw_fence *)addr)->flags & I915_SW_FENCE_MASK);
Expand Down Expand Up @@ -384,7 +404,11 @@ static void dma_i915_sw_fence_wake(struct dma_fence *dma,

i915_sw_fence_set_error_once(cb->fence, dma->error);
i915_sw_fence_complete(cb->fence);
#if defined(__FreeBSD__) && __FreeBSD_version > 1300127
KFREE(cb);
#else
kfree(cb);
#endif
}

static void timer_i915_sw_fence_wake(struct timer_list *t)
Expand Down Expand Up @@ -589,6 +613,27 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
#endif

#if defined(__FreeBSD__) && __FreeBSD_version > 1300127
static struct llist_head linux_kfree_async_list = LLIST_HEAD_INIT();

static void
linux_kfree_async_fn(struct irq_work *irqw)
{
struct llist_node *freed;

while((freed = llist_del_first(&linux_kfree_async_list)) != NULL)
kfree(freed);
}
static DEFINE_IRQ_WORK(linux_kfree_async_work, linux_kfree_async_fn);

static void
linux_kfree_async(void *addr)
{
if (addr == NULL)
return;
llist_add(addr, &linux_kfree_async_list);
irq_work_queue(&linux_kfree_async_work);
}

static void
irq_work_ctx_init_fn(struct irq_work *irqw)
{
Expand Down

0 comments on commit a1cee43

Please sign in to comment.