diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bo.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_channel.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.c | 215 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.h | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 3 |
8 files changed, 134 insertions, 158 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 1aa03a83bae..6d66314d16b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -35,6 +35,7 @@ #include "nouveau_dma.h" #include "nouveau_mm.h" #include "nouveau_vm.h" +#include "nouveau_fence.h" #include <linux/log2.h> #include <linux/slab.h> @@ -478,7 +479,7 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, struct nouveau_fence *fence = NULL; int ret; - ret = nouveau_fence_new(chan, &fence, true); + ret = nouveau_fence_new(chan, &fence); if (ret) return ret; @@ -1196,7 +1197,7 @@ nouveau_bo_fence_ref(void *sync_obj) static bool nouveau_bo_fence_signalled(void *sync_obj, void *sync_arg) { - return nouveau_fence_signalled(sync_obj); + return nouveau_fence_done(sync_obj); } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 26c08e9b4a3..694f6325311 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -28,6 +28,7 @@ #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_ramht.h" +#include "nouveau_fence.h" #include "nouveau_software.h" static int @@ -369,7 +370,7 @@ nouveau_channel_idle(struct nouveau_channel *chan) nouveau_fence_update(chan); if (chan->fence.sequence != chan->fence.sequence_ack) { - ret = nouveau_fence_new(chan, &fence, true); + ret = nouveau_fence_new(chan, &fence); if (!ret) { ret = nouveau_fence_wait(fence, false, false); nouveau_fence_unref(&fence); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index a13f2516d52..f9cdc921ef9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -35,6 +35,7 @@ #include "nouveau_connector.h" #include "nouveau_software.h" #include "nouveau_gpio.h" +#include "nouveau_fence.h" #include "nv50_display.h" static void @@ -465,7 +466,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, } FIRE_RING (chan); - ret = nouveau_fence_new(chan, pfence, true); + ret = nouveau_fence_new(chan, pfence); if (ret) goto fail; @@ -486,7 +487,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; struct nouveau_page_flip_state *s; - struct nouveau_channel *chan; + struct nouveau_channel *chan = NULL; struct nouveau_fence *fence; int ret; @@ -509,7 +510,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, new_bo->bo.offset }; /* Choose the channel the flip will be handled in */ - chan = nouveau_fence_channel(new_bo->bo.sync_obj); + fence = new_bo->bo.sync_obj; + if (fence) + chan = nouveau_channel_get_unlocked(fence->channel); if (!chan) chan = nouveau_channel_get_unlocked(dev_priv->channel); mutex_lock(&chan->mutex); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index b17444ae05c..43a46f157de 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1444,26 +1444,12 @@ extern int nouveau_bo_vma_add(struct nouveau_bo *, struct nouveau_vm *, extern void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *); /* nouveau_fence.c */ -struct nouveau_fence; -extern int nouveau_fence_init(struct drm_device *); -extern void nouveau_fence_fini(struct drm_device *); -extern int nouveau_fence_channel_init(struct nouveau_channel *); -extern void nouveau_fence_channel_fini(struct nouveau_channel *); -extern void nouveau_fence_update(struct nouveau_channel *); -extern int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **, - bool emit); -extern int nouveau_fence_emit(struct nouveau_fence *); -extern void nouveau_fence_work(struct nouveau_fence *fence, - void (*work)(void *priv, bool signalled), - void *priv); -struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *); - -extern bool nouveau_fence_signalled(struct nouveau_fence *); -extern int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); -extern void nouveau_fence_unref(struct nouveau_fence **); -extern struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *); -extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *); - +int nouveau_fence_init(struct drm_device *); +void nouveau_fence_fini(struct drm_device *); +int nouveau_fence_channel_init(struct nouveau_channel *); +void nouveau_fence_channel_fini(struct nouveau_channel *); +void nouveau_fence_work(struct nouveau_fence *fence, + void (*work)(void *priv, bool signalled), void *priv); /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, int size, int align, uint32_t domain, uint32_t tile_mode, diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index f26177ac27e..2c10d54fc49 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -32,47 +32,13 @@ #include "nouveau_drv.h" #include "nouveau_ramht.h" +#include "nouveau_fence.h" #include "nouveau_software.h" #include "nouveau_dma.h" #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) #define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17) -struct nouveau_fence { - struct nouveau_channel *channel; - struct kref refcount; - struct list_head entry; - - uint32_t sequence; - bool signalled; - unsigned long timeout; - - void (*work)(void *priv, bool signalled); - void *priv; -}; - -struct nouveau_semaphore { - struct kref ref; - struct drm_device *dev; - struct drm_mm_node *mem; -}; - -static inline struct nouveau_fence * -nouveau_fence(void *sync_obj) -{ - return (struct nouveau_fence *)sync_obj; -} - -static void -nouveau_fence_del(struct kref *ref) -{ - struct nouveau_fence *fence = - container_of(ref, struct nouveau_fence, refcount); - - nouveau_channel_ref(NULL, &fence->channel); - kfree(fence); -} - void nouveau_fence_update(struct nouveau_channel *chan) { @@ -94,16 +60,16 @@ nouveau_fence_update(struct nouveau_channel *chan) chan->fence.sequence_ack = sequence; } - list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { + list_for_each_entry_safe(fence, tmp, &chan->fence.pending, head) { if (fence->sequence > chan->fence.sequence_ack) break; - fence->signalled = true; - list_del(&fence->entry); + fence->channel = NULL; + list_del(&fence->head); if (fence->work) fence->work(fence->priv, true); - kref_put(&fence->refcount, nouveau_fence_del); + nouveau_fence_unref(&fence); } out: @@ -111,37 +77,8 @@ out: } int -nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence, - bool emit) +nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) { - struct nouveau_fence *fence; - int ret = 0; - - fence = kzalloc(sizeof(*fence), GFP_KERNEL); - if (!fence) - return -ENOMEM; - kref_init(&fence->refcount); - nouveau_channel_ref(chan, &fence->channel); - - if (emit) - ret = nouveau_fence_emit(fence); - - if (ret) - nouveau_fence_unref(&fence); - *pfence = fence; - return ret; -} - -struct nouveau_channel * -nouveau_fence_channel(struct nouveau_fence *fence) -{ - return fence ? nouveau_channel_get_unlocked(fence->channel) : NULL; -} - -int -nouveau_fence_emit(struct nouveau_fence *fence) -{ - struct nouveau_channel *chan = fence->channel; struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; @@ -158,10 +95,11 @@ nouveau_fence_emit(struct nouveau_fence *fence) } fence->sequence = ++chan->fence.sequence; + fence->channel = chan; - kref_get(&fence->refcount); + kref_get(&fence->kref); spin_lock(&chan->fence.lock); - list_add_tail(&fence->entry, &chan->fence.pending); + list_add_tail(&fence->head, &chan->fence.pending); spin_unlock(&chan->fence.lock); if (USE_REFCNT(dev)) { @@ -179,50 +117,12 @@ nouveau_fence_emit(struct nouveau_fence *fence) return 0; } -void -nouveau_fence_work(struct nouveau_fence *fence, - void (*work)(void *priv, bool signalled), - void *priv) -{ - BUG_ON(fence->work); - - spin_lock(&fence->channel->fence.lock); - - if (fence->signalled) { - work(priv, true); - } else { - fence->work = work; - fence->priv = priv; - } - - spin_unlock(&fence->channel->fence.lock); -} - -void -nouveau_fence_unref(struct nouveau_fence **pfence) -{ - if (*pfence) - kref_put(&(*pfence)->refcount, nouveau_fence_del); - *pfence = NULL; -} - -struct nouveau_fence * -nouveau_fence_ref(struct nouveau_fence *fence) -{ - kref_get(&fence->refcount); - return fence; -} - bool -nouveau_fence_signalled(struct nouveau_fence *fence) +nouveau_fence_done(struct nouveau_fence *fence) { - struct nouveau_channel *chan = fence->channel; - - if (fence->signalled) - return true; - - nouveau_fence_update(chan); - return fence->signalled; + if (fence->channel) + nouveau_fence_update(fence->channel); + return !fence->channel; } int @@ -232,8 +132,8 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) ktime_t t; int ret = 0; - while (!nouveau_fence_signalled(fence)) { - if (time_after_eq(jiffies, fence->timeout)) { + while (!nouveau_fence_done(fence)) { + if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { ret = -EBUSY; break; } @@ -255,10 +155,71 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) } __set_current_state(TASK_RUNNING); + return ret; +} + +static void +nouveau_fence_del(struct kref *kref) +{ + struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref); + kfree(fence); +} + +void +nouveau_fence_unref(struct nouveau_fence **pfence) +{ + if (*pfence) + kref_put(&(*pfence)->kref, nouveau_fence_del); + *pfence = NULL; +} + +struct nouveau_fence * +nouveau_fence_ref(struct nouveau_fence *fence) +{ + kref_get(&fence->kref); + return fence; +} + +int +nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence) +{ + struct nouveau_fence *fence; + int ret = 0; + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return -ENOMEM; + kref_init(&fence->kref); + + if (chan) { + ret = nouveau_fence_emit(fence, chan); + if (ret) + nouveau_fence_unref(&fence); + } + + *pfence = fence; return ret; } +struct nouveau_semaphore { + struct kref ref; + struct drm_device *dev; + struct drm_mm_node *mem; +}; + +void +nouveau_fence_work(struct nouveau_fence *fence, + void (*work)(void *priv, bool signalled), + void *priv) +{ + if (!fence->channel) { + work(priv, true); + } else { + fence->work = work; + fence->priv = priv; + } +} + static struct nouveau_semaphore * semaphore_alloc(struct drm_device *dev) { @@ -367,7 +328,7 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) } /* Delay semaphore destruction until its work is done */ - ret = nouveau_fence_new(chan, &fence, true); + ret = nouveau_fence_new(chan, &fence); if (ret) return ret; @@ -421,7 +382,7 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) } /* Delay semaphore destruction until its work is done */ - ret = nouveau_fence_new(chan, &fence, true); + ret = nouveau_fence_new(chan, &fence); if (ret) return ret; @@ -435,13 +396,13 @@ int nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *wchan) { - struct nouveau_channel *chan = nouveau_fence_channel(fence); + struct nouveau_channel *chan; struct drm_device *dev = wchan->dev; struct nouveau_semaphore *sema; int ret = 0; - if (likely(!chan || chan == wchan || - nouveau_fence_signalled(fence))) + chan = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL; + if (likely(!chan || chan == wchan || nouveau_fence_done(fence))) goto out; sema = semaphore_alloc(dev); @@ -480,12 +441,6 @@ out: } int -__nouveau_fence_flush(void *sync_obj, void *sync_arg) -{ - return 0; -} - -int nouveau_fence_channel_init(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; @@ -538,14 +493,14 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan) struct nouveau_fence *tmp, *fence; spin_lock(&chan->fence.lock); - list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { - fence->signalled = true; - list_del(&fence->entry); + list_for_each_entry_safe(fence, tmp, &chan->fence.pending, head) { + fence->channel = NULL; + list_del(&fence->head); if (unlikely(fence->work)) fence->work(fence->priv, false); - kref_put(&fence->refcount, nouveau_fence_del); + kref_put(&fence->kref, nouveau_fence_del); } spin_unlock(&chan->fence.lock); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h new file mode 100644 index 00000000000..1337acb0017 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -0,0 +1,28 @@ +#ifndef __NOUVEAU_FENCE_H__ +#define __NOUVEAU_FENCE_H__ + +struct nouveau_fence { + struct list_head head; + struct kref kref; + + struct nouveau_channel *channel; + unsigned long timeout; + u32 sequence; + + void (*work)(void *priv, bool signalled); + void *priv; +}; + +int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **); +struct nouveau_fence * +nouveau_fence_ref(struct nouveau_fence *); +void nouveau_fence_unref(struct nouveau_fence **); + +int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *); +bool nouveau_fence_done(struct nouveau_fence *); +int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); +int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *); +void nouveau_fence_idle(struct nouveau_channel *); +void nouveau_fence_update(struct nouveau_channel *); + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 666dad0717a..996755a8c9a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -30,6 +30,7 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" #include "nouveau_dma.h" +#include "nouveau_fence.h" #define nouveau_gem_pushbuf_sync(chan) 0 @@ -778,7 +779,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } } - ret = nouveau_fence_new(chan, &fence, true); + ret = nouveau_fence_new(chan, &fence); if (ret) { NV_ERROR(dev, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 585dcbeafcd..19352125177 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -39,6 +39,7 @@ #include "nouveau_pm.h" #include "nouveau_mm.h" #include "nouveau_vm.h" +#include "nouveau_fence.h" /* * NV10-NV40 tiling helpers @@ -89,7 +90,7 @@ nv10_mem_get_tile_region(struct drm_device *dev, int i) spin_lock(&dev_priv->tile.lock); if (!tile->used && - (!tile->fence || nouveau_fence_signalled(tile->fence))) + (!tile->fence || nouveau_fence_done(tile->fence))) tile->used = true; else tile = NULL; |