void nvc0_default_flush_notify(struct nouveau_channel *chan) { struct nvc0_screen *screen = chan->user_private; if (!screen) return; nouveau_fence_update(&screen->base, TRUE); nouveau_fence_next(&screen->base); }
void nv50_default_kick_notify(struct nouveau_pushbuf *push) { struct nv50_screen *screen = push->user_priv; if (screen) { nouveau_fence_next(&screen->base); nouveau_fence_update(&screen->base, TRUE); if (screen->cur_ctx) screen->cur_ctx->state.flushed = TRUE; } }
void nvc0_default_kick_notify(struct nouveau_pushbuf *push) { struct nvc0_screen *screen = push->user_priv; if (screen) { nouveau_fence_next(&screen->base); nouveau_fence_update(&screen->base, true); if (screen->cur_ctx) screen->cur_ctx->state.flushed = true; NOUVEAU_DRV_STAT(&screen->base, pushbuf_count, 1); } }
void nouveau_channel_idle(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct nouveau_fence *fence = NULL; int ret; nouveau_fence_update(chan); if (chan->fence.sequence != chan->fence.sequence_ack) { ret = nouveau_fence_new(chan, &fence, true); if (!ret) { ret = nouveau_fence_wait(fence, false, false); nouveau_fence_unref(&fence); } if (ret) NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id); } }
static int nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) { struct nouveau_fence_chan *fctx = container_of(notify, typeof(*fctx), notify); unsigned long flags; int ret = NVIF_NOTIFY_KEEP; spin_lock_irqsave(&fctx->lock, flags); if (!list_empty(&fctx->pending)) { struct nouveau_fence *fence; struct nouveau_channel *chan; fence = list_entry(fctx->pending.next, typeof(*fence), head); chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); if (nouveau_fence_update(fence->channel, fctx)) ret = NVIF_NOTIFY_DROP; } spin_unlock_irqrestore(&fctx->lock, flags); return ret; }
/* stops a fifo */ void nouveau_channel_free(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; unsigned long flags; int ret; NV_INFO(dev, "%s: freeing fifo %d\n", __func__, chan->id); nouveau_debugfs_channel_fini(chan); /* Give outstanding push buffers a chance to complete */ spin_lock_irqsave(&chan->fence.lock, flags); nouveau_fence_update(chan); spin_unlock_irqrestore(&chan->fence.lock, flags); if (chan->fence.sequence != chan->fence.sequence_ack) { struct nouveau_fence *fence = NULL; ret = nouveau_fence_new(chan, &fence, true); if (ret == 0) { ret = nouveau_fence_wait(fence, NULL, false, false); nouveau_fence_unref((void *)&fence); } if (ret) NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id); } /* Ensure all outstanding fences are signaled. They should be if the * above attempts at idling were OK, but if we failed this'll tell TTM * we're done with the buffers. */ nouveau_fence_fini(chan); /* Ensure the channel is no longer active on the GPU */ pfifo->reassign(dev, false); pgraph->fifo_access(dev, false); if (pgraph->channel(dev) == chan) pgraph->unload_context(dev); pgraph->destroy_context(chan); pgraph->fifo_access(dev, true); if (pfifo->channel_id(dev) == chan->id) { pfifo->disable(dev); pfifo->unload_context(dev); pfifo->enable(dev); } pfifo->destroy_context(chan); pfifo->reassign(dev, true); /* Release the channel's resources */ nouveau_gpuobj_ref_del(dev, &chan->pushbuf); if (chan->pushbuf_bo) { nouveau_bo_unpin(chan->pushbuf_bo); nouveau_bo_ref(NULL, &chan->pushbuf_bo); } nouveau_gpuobj_channel_takedown(chan); nouveau_notifier_takedown_channel(chan); if (chan->user) iounmap(chan->user); dev_priv->fifos[chan->id] = NULL; dev_priv->fifo_alloc_count--; kfree(chan); }