diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_channel.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_channel.c | 185 |
1 files changed, 93 insertions, 92 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index a018def..d31d355 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -27,63 +27,40 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" #include "nouveau_dma.h" -#include "nouveau_ramht.h" static int -nouveau_channel_pushbuf_init(struct nouveau_channel *chan) +nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) { - u32 mem = nouveau_vram_pushbuf ? TTM_PL_FLAG_VRAM : TTM_PL_FLAG_TT; struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - int ret; - - /* allocate buffer object */ - ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, &chan->pushbuf_bo); - if (ret) - goto out; - - ret = nouveau_bo_pin(chan->pushbuf_bo, mem); - if (ret) - goto out; - - ret = nouveau_bo_map(chan->pushbuf_bo); - if (ret) - goto out; + struct nouveau_bo *pb = chan->pushbuf_bo; + struct nouveau_gpuobj *pushbuf = NULL; + int ret = 0; - /* create DMA object covering the entire memtype where the push - * buffer resides, userspace can submit its own push buffers from - * anywhere within the same memtype. - */ - chan->pushbuf_base = chan->pushbuf_bo->bo.offset; if (dev_priv->card_type >= NV_50) { - ret = nouveau_bo_vma_add(chan->pushbuf_bo, chan->vm, - &chan->pushbuf_vma); - if (ret) - goto out; - if (dev_priv->card_type < NV_C0) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, (1ULL << 40), NV_MEM_ACCESS_RO, NV_MEM_TARGET_VM, - &chan->pushbuf); + &pushbuf); } - chan->pushbuf_base = chan->pushbuf_vma.offset; + chan->pushbuf_base = pb->bo.offset; } else - if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_TT) { + if (pb->bo.mem.mem_type == TTM_PL_TT) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->gart_info.aper_size, NV_MEM_ACCESS_RO, - NV_MEM_TARGET_GART, - &chan->pushbuf); + NV_MEM_TARGET_GART, &pushbuf); + chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; } else if (dev_priv->card_type != NV_04) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->fb_available_size, NV_MEM_ACCESS_RO, - NV_MEM_TARGET_VRAM, - &chan->pushbuf); + NV_MEM_TARGET_VRAM, &pushbuf); + chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; } else { /* NV04 cmdbuf hack, from original ddx.. not sure of it's * exact reason for existing :) PCI access to cmdbuf in @@ -93,22 +70,47 @@ nouveau_channel_pushbuf_init(struct nouveau_channel *chan) pci_resource_start(dev->pdev, 1), dev_priv->fb_available_size, NV_MEM_ACCESS_RO, - NV_MEM_TARGET_PCI, - &chan->pushbuf); + NV_MEM_TARGET_PCI, &pushbuf); + chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; + } + + nouveau_gpuobj_ref(pushbuf, &chan->pushbuf); + nouveau_gpuobj_ref(NULL, &pushbuf); + return ret; +} + +static struct nouveau_bo * +nouveau_channel_user_pushbuf_alloc(struct drm_device *dev) +{ + struct nouveau_bo *pushbuf = NULL; + int location, ret; + + if (nouveau_vram_pushbuf) + location = TTM_PL_FLAG_VRAM; + else + location = TTM_PL_FLAG_TT; + + ret = nouveau_bo_new(dev, NULL, 65536, 0, location, 0, 0x0000, &pushbuf); + if (ret) { + NV_ERROR(dev, "error allocating DMA push buffer: %d\n", ret); + return NULL; } -out: + ret = nouveau_bo_pin(pushbuf, location); if (ret) { - NV_ERROR(dev, "error initialising pushbuf: %d\n", ret); - nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma); - nouveau_gpuobj_ref(NULL, &chan->pushbuf); - if (chan->pushbuf_bo) { - nouveau_bo_unmap(chan->pushbuf_bo); - nouveau_bo_ref(NULL, &chan->pushbuf_bo); - } + NV_ERROR(dev, "error pinning DMA push buffer: %d\n", ret); + nouveau_bo_ref(NULL, &pushbuf); + return NULL; } - return 0; + ret = nouveau_bo_map(pushbuf); + if (ret) { + nouveau_bo_unpin(pushbuf); + nouveau_bo_ref(NULL, &pushbuf); + return NULL; + } + + return pushbuf; } /* allocates and initializes a fifo for user space consumption */ @@ -119,7 +121,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; - struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); struct nouveau_channel *chan; unsigned long flags; int ret; @@ -160,14 +161,19 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, INIT_LIST_HEAD(&chan->fence.pending); spin_lock_init(&chan->fence.lock); - /* setup channel's memory and vm */ - ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); - if (ret) { - NV_ERROR(dev, "gpuobj %d\n", ret); + /* Allocate DMA push buffer */ + chan->pushbuf_bo = nouveau_channel_user_pushbuf_alloc(dev); + if (!chan->pushbuf_bo) { + ret = -ENOMEM; + NV_ERROR(dev, "pushbuf %d\n", ret); nouveau_channel_put(&chan); return ret; } + nouveau_dma_pre_init(chan); + chan->user_put = 0x40; + chan->user_get = 0x44; + /* Allocate space for per-channel fixed notifier memory */ ret = nouveau_notifier_init_channel(chan); if (ret) { @@ -176,19 +182,21 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return ret; } - /* Allocate DMA push buffer */ - ret = nouveau_channel_pushbuf_init(chan); + /* Setup channel's default objects */ + ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); if (ret) { - NV_ERROR(dev, "pushbuf %d\n", ret); + NV_ERROR(dev, "gpuobj %d\n", ret); nouveau_channel_put(&chan); return ret; } - nouveau_dma_pre_init(chan); - chan->user_put = 0x40; - chan->user_get = 0x44; - if (dev_priv->card_type >= NV_50) - chan->user_get_hi = 0x60; + /* Create a dma object for the push buffer */ + ret = nouveau_channel_pushbuf_ctxdma_init(chan); + if (ret) { + NV_ERROR(dev, "pbctxdma %d\n", ret); + nouveau_channel_put(&chan); + return ret; + } /* disable the fifo caches */ pfifo->reassign(dev, false); @@ -213,11 +221,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, nouveau_debugfs_channel_init(chan); NV_DEBUG(dev, "channel %d initialised\n", chan->id); - if (fpriv) { - spin_lock(&fpriv->lock); - list_add(&chan->list, &fpriv->channels); - spin_unlock(&fpriv->lock); - } *chan_ret = chan; return 0; } @@ -234,23 +237,29 @@ nouveau_channel_get_unlocked(struct nouveau_channel *ref) } struct nouveau_channel * -nouveau_channel_get(struct drm_file *file_priv, int id) +nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id) { - struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan; + unsigned long flags; - spin_lock(&fpriv->lock); - list_for_each_entry(chan, &fpriv->channels, list) { - if (chan->id == id) { - chan = nouveau_channel_get_unlocked(chan); - spin_unlock(&fpriv->lock); - mutex_lock(&chan->mutex); - return chan; - } + if (unlikely(id < 0 || id >= NOUVEAU_MAX_CHANNEL_NR)) + return ERR_PTR(-EINVAL); + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + chan = nouveau_channel_get_unlocked(dev_priv->channels.ptr[id]); + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + + if (unlikely(!chan)) + return ERR_PTR(-EINVAL); + + if (unlikely(file_priv && chan->file_priv != file_priv)) { + nouveau_channel_put_unlocked(&chan); + return ERR_PTR(-EINVAL); } - spin_unlock(&fpriv->lock); - return ERR_PTR(-EINVAL); + mutex_lock(&chan->mutex); + return chan; } void @@ -304,14 +313,12 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) /* destroy any resources the channel owned */ nouveau_gpuobj_ref(NULL, &chan->pushbuf); if (chan->pushbuf_bo) { - nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma); nouveau_bo_unmap(chan->pushbuf_bo); nouveau_bo_unpin(chan->pushbuf_bo); nouveau_bo_ref(NULL, &chan->pushbuf_bo); } - nouveau_ramht_ref(NULL, &chan->ramht, chan); - nouveau_notifier_takedown_channel(chan); nouveau_gpuobj_channel_takedown(chan); + nouveau_notifier_takedown_channel(chan); nouveau_channel_ref(NULL, pchan); } @@ -377,11 +384,10 @@ nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) NV_DEBUG(dev, "clearing FIFO enables from file_priv\n"); for (i = 0; i < engine->fifo.channels; i++) { - chan = nouveau_channel_get(file_priv, i); + chan = nouveau_channel_get(dev, file_priv, i); if (IS_ERR(chan)) continue; - list_del(&chan->list); atomic_dec(&chan->users); nouveau_channel_put(&chan); } @@ -414,17 +420,13 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, return ret; init->channel = chan->id; - if (nouveau_vram_pushbuf == 0) { - if (chan->dma.ib_max) - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | - NOUVEAU_GEM_DOMAIN_GART; - else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; - else - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; - } else { + if (chan->dma.ib_max) + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | + NOUVEAU_GEM_DOMAIN_GART; + else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; - } + else + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; if (dev_priv->card_type < NV_C0) { init->subchan[0].handle = NvM2MF; @@ -458,11 +460,10 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, struct drm_nouveau_channel_free *req = data; struct nouveau_channel *chan; - chan = nouveau_channel_get(file_priv, req->channel); + chan = nouveau_channel_get(dev, file_priv, req->channel); if (IS_ERR(chan)) return PTR_ERR(chan); - list_del(&chan->list); atomic_dec(&chan->users); nouveau_channel_put(&chan); return 0; |