Esempio n. 1
0
int
nouveau_card_init(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_engine *engine;
	int ret, e = 0;

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

	/* Initialise internal driver API hooks */
	ret = nouveau_init_engine_ptrs(dev);
	if (ret)
		goto out;
	engine = &dev_priv->engine;
	spin_lock_init(&dev_priv->channels.lock);
	spin_lock_init(&dev_priv->tile.lock);
	spin_lock_init(&dev_priv->context_switch_lock);
	spin_lock_init(&dev_priv->vm_lock);

	/* Make the CRTCs and I2C buses accessible */
	ret = engine->display.early_init(dev);
	if (ret)
		goto out;

	/* Parse BIOS tables / Run init tables if card not POSTed */
	ret = nouveau_bios_init(dev);
	if (ret)
		goto out_display_early;

	/* workaround an odd issue on nvc1 by disabling the device's
	 * nosnoop capability.  hopefully won't cause issues until a
	 * better fix is found - assuming there is one...
	 */
	if (dev_priv->chipset == 0xc1) {
		nv_mask(dev, 0x00088080, 0x00000800, 0x00000000);
	}

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

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

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

	ret = engine->vram.init(dev);
	if (ret)
		goto out_fb;

	/* PGPIO */
	ret = nouveau_gpio_create(dev);
	if (ret)
		goto out_vram;

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

	ret = engine->instmem.init(dev);
	if (ret)
		goto out_gpuobj;

	ret = nouveau_mem_vram_init(dev);
	if (ret)
		goto out_instmem;

	ret = nouveau_mem_gart_init(dev);
	if (ret)
		goto out_ttmvram;

	if (!dev_priv->noaccel) {
		switch (dev_priv->card_type) {
		case NV_04:
			nv04_graph_create(dev);
			break;
		case NV_10:
			nv10_graph_create(dev);
			break;
		case NV_20:
		case NV_30:
			nv20_graph_create(dev);
			break;
		case NV_40:
			nv40_graph_create(dev);
			break;
		case NV_50:
			nv50_graph_create(dev);
			break;
		case NV_C0:
		case NV_D0:
			nvc0_graph_create(dev);
			break;
		default:
			break;
		}

		switch (dev_priv->chipset) {
		case 0x84:
		case 0x86:
		case 0x92:
		case 0x94:
		case 0x96:
		case 0xa0:
			nv84_crypt_create(dev);
			break;
		case 0x98:
		case 0xaa:
		case 0xac:
			nv98_crypt_create(dev);
			break;
		}

		switch (dev_priv->card_type) {
		case NV_50:
			switch (dev_priv->chipset) {
			case 0xa3:
			case 0xa5:
			case 0xa8:
			case 0xaf:
				nva3_copy_create(dev);
				break;
			}
			break;
		case NV_C0:
			nvc0_copy_create(dev, 0);
			nvc0_copy_create(dev, 1);
			break;
		default:
			break;
		}

		if (dev_priv->chipset >= 0xa3 || dev_priv->chipset == 0x98) {
			nv84_bsp_create(dev);
			nv84_vp_create(dev);
			nv98_ppp_create(dev);
		} else
		if (dev_priv->chipset >= 0x84) {
			nv50_mpeg_create(dev);
			nv84_bsp_create(dev);
			nv84_vp_create(dev);
		} else
		if (dev_priv->chipset >= 0x50) {
			nv50_mpeg_create(dev);
		} else
		if (dev_priv->card_type == NV_40 ||
		    dev_priv->chipset == 0x31 ||
		    dev_priv->chipset == 0x34 ||
		    dev_priv->chipset == 0x36) {
			nv31_mpeg_create(dev);
		}

		for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
			if (dev_priv->eng[e]) {
				ret = dev_priv->eng[e]->init(dev, e);
				if (ret)
					goto out_engine;
			}
		}

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

	ret = nouveau_irq_init(dev);
	if (ret)
		goto out_fifo;

	ret = nouveau_display_create(dev);
	if (ret)
		goto out_irq;

	nouveau_backlight_init(dev);
	nouveau_pm_init(dev);

	ret = nouveau_fence_init(dev);
	if (ret)
		goto out_pm;

	if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
		ret = nouveau_card_channel_init(dev);
		if (ret)
			goto out_fence;
	}

	if (dev->mode_config.num_crtc) {
		ret = nouveau_display_init(dev);
		if (ret)
			goto out_chan;

		nouveau_fbcon_init(dev);
	}

	return 0;

out_chan:
	nouveau_card_channel_fini(dev);
out_fence:
	nouveau_fence_fini(dev);
out_pm:
	nouveau_pm_fini(dev);
	nouveau_backlight_exit(dev);
	nouveau_display_destroy(dev);
out_irq:
	nouveau_irq_fini(dev);
out_fifo:
	if (!dev_priv->noaccel)
		engine->fifo.takedown(dev);
out_engine:
	if (!dev_priv->noaccel) {
		for (e = e - 1; e >= 0; e--) {
			if (!dev_priv->eng[e])
				continue;
			dev_priv->eng[e]->fini(dev, e, false);
			dev_priv->eng[e]->destroy(dev,e );
		}
	}
	nouveau_mem_gart_fini(dev);
out_ttmvram:
	nouveau_mem_vram_fini(dev);
out_instmem:
	engine->instmem.takedown(dev);
out_gpuobj:
	nouveau_gpuobj_takedown(dev);
out_gpio:
	nouveau_gpio_destroy(dev);
out_vram:
	engine->vram.takedown(dev);
out_fb:
	engine->fb.takedown(dev);
out_timer:
	engine->timer.takedown(dev);
out_mc:
	engine->mc.takedown(dev);
out_bios:
	nouveau_bios_takedown(dev);
out_display_early:
	engine->display.late_takedown(dev);
out:
	vga_client_register(dev->pdev, NULL, NULL, NULL);
	return ret;
}
Esempio n. 2
0
int
nouveau_card_init(struct drm_device *dev)
{
    struct drm_nouveau_private *dev_priv = dev->dev_private;
    struct nouveau_engine *engine;
    int ret;

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

    /* Initialise internal driver API hooks */
    ret = nouveau_init_engine_ptrs(dev);
    if (ret)
        goto out;
    engine = &dev_priv->engine;
    spin_lock_init(&dev_priv->channels.lock);
    spin_lock_init(&dev_priv->tile.lock);
    spin_lock_init(&dev_priv->context_switch_lock);
    spin_lock_init(&dev_priv->vm_lock);

    /* Make the CRTCs and I2C buses accessible */
    ret = engine->display.early_init(dev);
    if (ret)
        goto out;

    /* Parse BIOS tables / Run init tables if card not POSTed */
    ret = nouveau_bios_init(dev);
    if (ret)
        goto out_display_early;

    nouveau_pm_init(dev);

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

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

    ret = engine->instmem.init(dev);
    if (ret)
        goto out_gpuobj;

    ret = nouveau_mem_gart_init(dev);
    if (ret)
        goto out_instmem;

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

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

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

    /* 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;

        /* PCRYPT */
        ret = engine->crypt.init(dev);
        if (ret)
            goto out_graph;

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

    ret = engine->display.create(dev);
    if (ret)
        goto out_fifo;

    ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1);
    if (ret)
        goto out_vblank;

    ret = nouveau_irq_init(dev);
    if (ret)
        goto out_vblank;

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

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

        ret = nouveau_card_init_channel(dev);
        if (ret)
            goto out_fence;
    }

    nouveau_fbcon_init(dev);
    drm_kms_helper_poll_init(dev);
    return 0;

out_fence:
    nouveau_fence_fini(dev);
out_irq:
    nouveau_irq_fini(dev);
out_vblank:
    drm_vblank_cleanup(dev);
    engine->display.destroy(dev);
out_fifo:
    if (!nouveau_noaccel)
        engine->fifo.takedown(dev);
out_crypt:
    if (!nouveau_noaccel)
        engine->crypt.takedown(dev);
out_graph:
    if (!nouveau_noaccel)
        engine->graph.takedown(dev);
out_fb:
    engine->fb.takedown(dev);
out_timer:
    engine->timer.takedown(dev);
out_gpio:
    engine->gpio.takedown(dev);
out_mc:
    engine->mc.takedown(dev);
out_gart:
    nouveau_mem_gart_fini(dev);
out_instmem:
    engine->instmem.takedown(dev);
out_gpuobj:
    nouveau_gpuobj_takedown(dev);
out_vram:
    nouveau_mem_vram_fini(dev);
out_bios:
    nouveau_pm_fini(dev);
    nouveau_bios_takedown(dev);
out_display_early:
    engine->display.late_takedown(dev);
out:
    vga_client_register(dev->pdev, NULL, NULL, NULL);
    return ret;
}
/* 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;
}