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; }
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; }