void
nouveau_screen_fini(struct nouveau_screen *screen)
{
	struct pipe_winsys *ws = screen->base.winsys;
	nouveau_channel_free(&screen->channel);
	if (ws)
		ws->destroy(ws);
}
static int
nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
			struct drm_file *file_priv)
{
	struct drm_nouveau_channel_free *cfree = data;
	struct nouveau_channel *chan;

	NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
	NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan);

	nouveau_channel_free(chan);
	return 0;
}
/* cleans up all the fifos from file_priv */
void
nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_engine *engine = &dev_priv->engine;
	int i;

	NV_DEBUG(dev, "clearing FIFO enables from file_priv\n");
	for (i = 0; i < engine->fifo.channels; i++) {
		struct nouveau_channel *chan = dev_priv->fifos[i];

		if (chan && chan->file_priv == file_priv)
			nouveau_channel_free(chan);
	}
}
static int
nouveau_card_init_channel(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *gpuobj;
	int ret;

	ret = nouveau_channel_alloc(dev, &dev_priv->channel,
				    (struct drm_file *)-2,
				    NvDmaFB, NvDmaTT);
	if (ret)
		return ret;

	gpuobj = NULL;
	ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
				     0, nouveau_mem_fb_amount(dev),
				     NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
				     &gpuobj);
	if (ret)
		goto out_err;

	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
				     gpuobj, NULL);
	if (ret)
		goto out_err;

	gpuobj = NULL;
	ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
					  dev_priv->gart_info.aper_size,
					  NV_DMA_ACCESS_RW, &gpuobj, NULL);
	if (ret)
		goto out_err;

	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
				     gpuobj, NULL);
	if (ret)
		goto out_err;

	return 0;
out_err:
	nouveau_gpuobj_del(dev, &gpuobj);
	nouveau_channel_free(dev_priv->channel);
	dev_priv->channel = NULL;
	return ret;
}
Example #5
0
static void nouveau_card_takedown(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_engine *engine = &dev_priv->engine;

	NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);

	if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {

		nouveau_backlight_exit(dev);

		if (dev_priv->channel) {
			nouveau_channel_free(dev_priv->channel);
			dev_priv->channel = NULL;
		}

		if (!nouveau_noaccel) {
			engine->fifo.takedown(dev);
			engine->graph.takedown(dev);
		}
		engine->fb.takedown(dev);
		engine->timer.takedown(dev);
		engine->mc.takedown(dev);

		mutex_lock(&dev->struct_mutex);
		ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
		ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
		mutex_unlock(&dev->struct_mutex);
		nouveau_sgdma_takedown(dev);

		nouveau_gpuobj_takedown(dev);
		nouveau_mem_close(dev);
		engine->instmem.takedown(dev);

		if (drm_core_check_feature(dev, DRIVER_MODESET))
			drm_irq_uninstall(dev);

		nouveau_gpuobj_late_takedown(dev);
		nouveau_bios_takedown(dev);

		vga_client_register(dev->pdev, NULL, NULL, NULL);

		dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
	}
}
static int
nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct drm_nouveau_channel_alloc *init = data;
	struct nouveau_channel *chan;
	int ret;

	NOUVEAU_CHECK_INITIALISED_WITH_RETURN;

	if (dev_priv->engine.graph.accel_blocked)
		return -ENODEV;

	if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
		return -EINVAL;

	ret = nouveau_channel_alloc(dev, &chan, file_priv,
				    init->fb_ctxdma_handle,
				    init->tt_ctxdma_handle);
	if (ret)
		return ret;
	init->channel  = chan->id;

	init->subchan[0].handle = NvM2MF;
	if (dev_priv->card_type < NV_50)
		init->subchan[0].grclass = 0x0039;
	else
		init->subchan[0].grclass = 0x5039;
	init->subchan[1].handle = NvSw;
	init->subchan[1].grclass = NV_SW;
	init->nr_subchan = 2;

	/* Named memory object area */
	ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem,
				    &init->notifier_handle);
	if (ret) {
		nouveau_channel_free(chan);
		return ret;
	}

	return 0;
}
Example #7
0
static void nouveau_card_takedown(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_engine *engine = &dev_priv->engine;

	nouveau_backlight_exit(dev);

	if (!engine->graph.accel_blocked) {
		nouveau_fence_fini(dev);
		nouveau_channel_free(dev_priv->channel);
		dev_priv->channel = NULL;
	}

	if (!nouveau_noaccel) {
		engine->fifo.takedown(dev);
		engine->graph.takedown(dev);
	}
	engine->fb.takedown(dev);
	engine->timer.takedown(dev);
	engine->gpio.takedown(dev);
	engine->mc.takedown(dev);
	engine->display.late_takedown(dev);

	mutex_lock(&dev->struct_mutex);
	ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
	ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
	mutex_unlock(&dev->struct_mutex);
	nouveau_mem_gart_fini(dev);

	engine->instmem.takedown(dev);
	nouveau_gpuobj_takedown(dev);
	nouveau_mem_vram_fini(dev);

	drm_irq_uninstall(dev);

	nouveau_pm_fini(dev);
	nouveau_bios_takedown(dev);

	vga_client_register(dev->pdev, NULL, NULL, NULL);
}
/* 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;
}
Example #9
0
int
nouveau_channel_alloc(struct nouveau_device *dev, uint32_t fb_ctxdma,
		      uint32_t tt_ctxdma, int pushbuf_size,
		      struct nouveau_channel **chan)
{
	struct nouveau_device_priv *nvdev = nouveau_device(dev);
	struct nouveau_channel_priv *nvchan;
	unsigned i;
	int ret;

	if (!nvdev || !chan || *chan)
	    return -EINVAL;

	nvchan = calloc(1, sizeof(struct nouveau_channel_priv));
	if (!nvchan)
		return -ENOMEM;
	nvchan->base.device = dev;

	nvchan->drm.fb_ctxdma_handle = fb_ctxdma;
	nvchan->drm.tt_ctxdma_handle = tt_ctxdma;
	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_CHANNEL_ALLOC,
				  &nvchan->drm, sizeof(nvchan->drm));
	if (ret) {
		free(nvchan);
		return ret;
	}

	nvchan->base.id = nvchan->drm.channel;
	if (nouveau_grobj_ref(&nvchan->base, nvchan->drm.fb_ctxdma_handle,
			      &nvchan->base.vram) ||
	    nouveau_grobj_ref(&nvchan->base, nvchan->drm.tt_ctxdma_handle,
		    	      &nvchan->base.gart)) {
		nouveau_channel_free((void *)&nvchan);
		return -EINVAL;
	}

	/* Mark all DRM-assigned subchannels as in-use */
	for (i = 0; i < nvchan->drm.nr_subchan; i++) {
		struct nouveau_grobj_priv *gr = calloc(1, sizeof(*gr));

		gr->base.bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
		gr->base.subc = i;
		gr->base.handle = nvchan->drm.subchan[i].handle;
		gr->base.grclass = nvchan->drm.subchan[i].grclass;
		gr->base.channel = &nvchan->base;

		nvchan->base.subc[i].gr = &gr->base;
	}

	if (dev->chipset < 0xc0) {
		ret = nouveau_bo_wrap(dev, nvchan->drm.notifier_handle,
				      &nvchan->notifier_bo);
		if (!ret)
			ret = nouveau_bo_map(nvchan->notifier_bo,
					     NOUVEAU_BO_RDWR);
		if (ret) {
			nouveau_channel_free((void *)&nvchan);
			return ret;
		}

		ret = nouveau_grobj_alloc(&nvchan->base, 0x00000000, 0x0030,
					  &nvchan->base.nullobj);
		if (ret) {
			nouveau_channel_free((void *)&nvchan);
			return ret;
		}
	}

	ret = nouveau_pushbuf_init(&nvchan->base, pushbuf_size);
	if (ret) {
		nouveau_channel_free((void *)&nvchan);
		return ret;
	}

	*chan = &nvchan->base;
	return 0;
}
Example #10
0
int
nouveau_card_init(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_engine *engine;
	int ret;

	NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);

	if (dev_priv->init_state == NOUVEAU_CARD_INIT_DONE)
		return 0;

	vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
	vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
				       nouveau_switcheroo_can_switch);

	/* Initialise internal driver API hooks */
	ret = nouveau_init_engine_ptrs(dev);
	if (ret)
		goto out;
	engine = &dev_priv->engine;
	dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
	spin_lock_init(&dev_priv->context_switch_lock);

	/* Parse BIOS tables / Run init tables if card not POSTed */
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		ret = nouveau_bios_init(dev);
		if (ret)
			goto out;
	}

	ret = nouveau_mem_detect(dev);
	if (ret)
		goto out_bios;

	ret = nouveau_gpuobj_early_init(dev);
	if (ret)
		goto out_bios;

	/* Initialise instance memory, must happen before mem_init so we
	 * know exactly how much VRAM we're able to use for "normal"
	 * purposes.
	 */
	ret = engine->instmem.init(dev);
	if (ret)
		goto out_gpuobj_early;

	/* Setup the memory manager */
	ret = nouveau_mem_init(dev);
	if (ret)
		goto out_instmem;

	ret = nouveau_gpuobj_init(dev);
	if (ret)
		goto out_mem;

	/* PMC */
	ret = engine->mc.init(dev);
	if (ret)
		goto out_gpuobj;

	/* PTIMER */
	ret = engine->timer.init(dev);
	if (ret)
		goto out_mc;

	/* PFB */
	ret = engine->fb.init(dev);
	if (ret)
		goto out_timer;

	if (nouveau_noaccel)
		engine->graph.accel_blocked = true;
	else {
		/* PGRAPH */
		ret = engine->graph.init(dev);
		if (ret)
			goto out_fb;

		/* PFIFO */
		ret = engine->fifo.init(dev);
		if (ret)
			goto out_graph;
	}

	/* this call irq_preinstall, register irq handler and
	 * call irq_postinstall
	 */
	ret = drm_irq_install(dev);
	if (ret)
		goto out_fifo;

	ret = drm_vblank_init(dev, 0);
	if (ret)
		goto out_irq;

	/* what about PVIDEO/PCRTC/PRAMDAC etc? */

	if (!engine->graph.accel_blocked) {
		ret = nouveau_card_init_channel(dev);
		if (ret)
			goto out_irq;
	}

	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		if (dev_priv->card_type >= NV_50)
			ret = nv50_display_create(dev);
		else
			ret = nv04_display_create(dev);
		if (ret)
			goto out_channel;
	}

	ret = nouveau_backlight_init(dev);
	if (ret)
		NV_ERROR(dev, "Error %d registering backlight\n", ret);

	dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;

	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		nouveau_fbcon_init(dev);
		drm_kms_helper_poll_init(dev);
	}

	return 0;

out_channel:
	if (dev_priv->channel) {
		nouveau_channel_free(dev_priv->channel);
		dev_priv->channel = NULL;
	}
out_irq:
	drm_irq_uninstall(dev);
out_fifo:
	if (!nouveau_noaccel)
		engine->fifo.takedown(dev);
out_graph:
	if (!nouveau_noaccel)
		engine->graph.takedown(dev);
out_fb:
	engine->fb.takedown(dev);
out_timer:
	engine->timer.takedown(dev);
out_mc:
	engine->mc.takedown(dev);
out_gpuobj:
	nouveau_gpuobj_takedown(dev);
out_mem:
	nouveau_sgdma_takedown(dev);
	nouveau_mem_close(dev);
out_instmem:
	engine->instmem.takedown(dev);
out_gpuobj_early:
	nouveau_gpuobj_late_takedown(dev);
out_bios:
	nouveau_bios_takedown(dev);
out:
	vga_client_register(dev->pdev, NULL, NULL, NULL);
	return ret;
}