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