From 5de8037ab466d397df17ff72382c33a908f42f6c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 8 Jun 2011 18:17:41 +1000 Subject: [PATCH] drm/nvc0: enable per-client address spaces Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 74 +++++++++++++++--------- drivers/gpu/drm/nouveau/nouveau_state.c | 7 ++- drivers/gpu/drm/nouveau/nvc0_instmem.c | 14 +---- 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 115827133bb7..542b451c81f1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -690,6 +690,50 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) return 0; } +static int +nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) +{ + struct drm_device *dev = chan->dev; + struct nouveau_gpuobj *pgd = NULL; + struct nouveau_vm_pgd *vpgd; + int ret, i; + + ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0, &chan->ramin); + if (ret) + return ret; + + /* create page directory for this vm if none currently exists, + * will be destroyed automagically when last reference to the + * vm is removed + */ + if (list_empty(&vm->pgd_list)) { + ret = nouveau_gpuobj_new(dev, NULL, 65536, 0x1000, 0, &pgd); + if (ret) + return ret; + } + nouveau_vm_ref(vm, &chan->vm, pgd); + nouveau_gpuobj_ref(NULL, &pgd); + + /* point channel at vm's page directory */ + vpgd = list_first_entry(&vm->pgd_list, struct nouveau_vm_pgd, head); + nv_wo32(chan->ramin, 0x0200, lower_32_bits(vpgd->obj->vinst)); + nv_wo32(chan->ramin, 0x0204, upper_32_bits(vpgd->obj->vinst)); + nv_wo32(chan->ramin, 0x0208, 0xffffffff); + nv_wo32(chan->ramin, 0x020c, 0x000000ff); + + /* map display semaphore buffers into channel's vm */ + for (i = 0; i < 2; i++) { + struct nv50_display_crtc *dispc = &nv50_display(dev)->crtc[i]; + + ret = nouveau_bo_vma_add(dispc->sem.bo, chan->vm, + &chan->dispc_vma[i]); + if (ret) + return ret; + } + + return 0; +} + int nouveau_gpuobj_channel_init(struct nouveau_channel *chan, uint32_t vram_h, uint32_t tt_h) @@ -702,34 +746,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, int ret, i; NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); - if (dev_priv->card_type == NV_C0) { - struct nouveau_vm_pgd *vpgd; - - ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0, - &chan->ramin); - if (ret) - return ret; - - nouveau_vm_ref(vm, &chan->vm, NULL); - - vpgd = list_first_entry(&vm->pgd_list, struct nouveau_vm_pgd, head); - nv_wo32(chan->ramin, 0x0200, lower_32_bits(vpgd->obj->vinst)); - nv_wo32(chan->ramin, 0x0204, upper_32_bits(vpgd->obj->vinst)); - nv_wo32(chan->ramin, 0x0208, 0xffffffff); - nv_wo32(chan->ramin, 0x020c, 0x000000ff); - - for (i = 0; i < 2; i++) { - struct nv50_display_crtc *dispc = - &nv50_display(dev)->crtc[i]; - - ret = nouveau_bo_vma_add(dispc->sem.bo, chan->vm, - &chan->dispc_vma[i]); - if (ret) - return ret; - } - - return 0; - } + if (dev_priv->card_type == NV_C0) + return nvc0_gpuobj_channel_init(chan, vm); /* Allocate a chunk of memory for per-channel object storage */ ret = nouveau_gpuobj_channel_init_pramin(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 91cc2a64d8e0..50507e7e3f58 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -787,7 +787,12 @@ nouveau_open(struct drm_device *dev, struct drm_file *file_priv) } } else if (dev_priv->card_type >= NV_C0) { - nouveau_vm_ref(dev_priv->chan_vm, &fpriv->vm, NULL); + ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, + &fpriv->vm); + if (ret) { + kfree(fpriv); + return ret; + } } file_priv->driver_priv = fpriv; diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 82357d2df1f4..b701c439c92e 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -32,7 +32,6 @@ struct nvc0_instmem_priv { struct nouveau_channel *bar1; struct nouveau_gpuobj *bar3_pgd; struct nouveau_channel *bar3; - struct nouveau_gpuobj *chan_pgd; }; int @@ -181,17 +180,11 @@ nvc0_instmem_init(struct drm_device *dev) goto error; /* channel vm */ - ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, &vm); + ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, + &dev_priv->chan_vm); if (ret) goto error; - ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 0, &priv->chan_pgd); - if (ret) - goto error; - - nouveau_vm_ref(vm, &dev_priv->chan_vm, priv->chan_pgd); - nouveau_vm_ref(NULL, &vm, NULL); - nvc0_instmem_resume(dev); return 0; error: @@ -211,8 +204,7 @@ nvc0_instmem_takedown(struct drm_device *dev) nv_wr32(dev, 0x1704, 0x00000000); nv_wr32(dev, 0x1714, 0x00000000); - nouveau_vm_ref(NULL, &dev_priv->chan_vm, priv->chan_pgd); - nouveau_gpuobj_ref(NULL, &priv->chan_pgd); + nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL); nvc0_channel_del(&priv->bar1); nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd);