/* allocates and initializes a fifo for user space consumption */ int nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct drm_file *file_priv, uint32_t vram_handle, uint32_t tt_handle) { 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; struct nouveau_channel *chan; int channel, user; int ret; /* * Alright, here is the full story * Nvidia cards have multiple hw fifo contexts (praise them for that, * no complicated crash-prone context switches) * We allocate a new context for each app and let it write to it * directly (woo, full userspace command submission !) * When there are no more contexts, you lost */ for (channel = 0; channel < pfifo->channels; channel++) { if (dev_priv->fifos[channel] == NULL) break; } /* no more fifos. you lost. */ if (channel == pfifo->channels) return -EINVAL; dev_priv->fifos[channel] = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); if (!dev_priv->fifos[channel]) return -ENOMEM; dev_priv->fifo_alloc_count++; chan = dev_priv->fifos[channel]; INIT_LIST_HEAD(&chan->nvsw.vbl_wait); INIT_LIST_HEAD(&chan->fence.pending); chan->dev = dev; chan->id = channel; chan->file_priv = file_priv; chan->vram_handle = vram_handle; chan->gart_handle = tt_handle; NV_INFO(dev, "Allocating FIFO number %d\n", channel); /* 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_free(chan); return ret; } nouveau_dma_pre_init(chan); /* Locate channel's user control regs */ if (dev_priv->card_type < NV_40) user = NV03_USER(channel); else if (dev_priv->card_type < NV_50) user = NV40_USER(channel); else user = NV50_USER(channel); chan->user = ioremap(pci_resource_start(dev->pdev, 0) + user, PAGE_SIZE); if (!chan->user) { NV_ERROR(dev, "ioremap of regs failed.\n"); nouveau_channel_free(chan); return -ENOMEM; } chan->user_put = 0x40; chan->user_get = 0x44; /* Allocate space for per-channel fixed notifier memory */ ret = nouveau_notifier_init_channel(chan); if (ret) { NV_ERROR(dev, "ntfy %d\n", ret); nouveau_channel_free(chan); return ret; } /* Setup channel's default objects */ ret = nouveau_gpuobj_channel_init(chan, vram_handle, tt_handle); if (ret) { NV_ERROR(dev, "gpuobj %d\n", ret); nouveau_channel_free(chan); return ret; } /* 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_free(chan); return ret; } /* disable the fifo caches */ pfifo->reassign(dev, false); /* Create a graphics context for new channel */ ret = pgraph->create_context(chan); if (ret) { nouveau_channel_free(chan); return ret; } /* Construct inital RAMFC for new channel */ ret = pfifo->create_context(chan); if (ret) { nouveau_channel_free(chan); return ret; } pfifo->reassign(dev, true); ret = nouveau_dma_init(chan); if (!ret) ret = nouveau_fence_init(chan); if (ret) { nouveau_channel_free(chan); return ret; } nouveau_debugfs_channel_init(chan); NV_INFO(dev, "%s: initialised FIFO %d\n", __func__, channel); *chan_ret = chan; return 0; }
/* allocates and initializes a fifo for user space consumption */ int nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct drm_file *file_priv, uint32_t vram_handle, uint32_t gart_handle) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_channel *chan; unsigned long flags; int ret; /* allocate and lock channel structure */ chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) return -ENOMEM; chan->dev = dev; chan->file_priv = file_priv; chan->vram_handle = vram_handle; chan->gart_handle = gart_handle; kref_init(&chan->ref); atomic_set(&chan->users, 1); mutex_init(&chan->mutex); mutex_lock(&chan->mutex); /* allocate hw channel id */ spin_lock_irqsave(&dev_priv->channels.lock, flags); for (chan->id = 0; chan->id < pfifo->channels; chan->id++) { if (!dev_priv->channels.ptr[chan->id]) { nouveau_channel_ref(chan, &dev_priv->channels.ptr[chan->id]); break; } } spin_unlock_irqrestore(&dev_priv->channels.lock, flags); if (chan->id == pfifo->channels) { mutex_unlock(&chan->mutex); kfree(chan); return -ENODEV; } NV_DEBUG(dev, "initialising channel %d\n", chan->id); INIT_LIST_HEAD(&chan->nvsw.vbl_wait); INIT_LIST_HEAD(&chan->nvsw.flip); INIT_LIST_HEAD(&chan->fence.pending); spin_lock_init(&chan->fence.lock); /* 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) { NV_ERROR(dev, "ntfy %d\n", ret); nouveau_channel_put(&chan); return ret; } /* Setup channel's default objects */ ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); if (ret) { NV_ERROR(dev, "gpuobj %d\n", ret); nouveau_channel_put(&chan); return ret; } /* 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); /* Construct inital RAMFC for new channel */ ret = pfifo->create_context(chan); if (ret) { nouveau_channel_put(&chan); return ret; } pfifo->reassign(dev, true); ret = nouveau_dma_init(chan); if (!ret) ret = nouveau_fence_channel_init(chan); if (ret) { nouveau_channel_put(&chan); return ret; } nouveau_debugfs_channel_init(chan); NV_DEBUG(dev, "channel %d initialised\n", chan->id); *chan_ret = chan; return 0; }