void nvc0_instmem_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; struct nouveau_vm *vm = NULL; nvc0_instmem_suspend(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); nvc0_channel_del(&priv->bar1); nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); nouveau_gpuobj_ref(NULL, &priv->bar1_pgd); nvc0_channel_del(&priv->bar3); nouveau_vm_ref(dev_priv->bar3_vm, &vm, NULL); nouveau_vm_ref(NULL, &vm, priv->bar3_pgd); nouveau_gpuobj_ref(NULL, &priv->bar3_pgd); nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); dev_priv->engine.instmem.priv = NULL; kfree(priv); }
void nouveau_postclose(struct drm_device *dev, struct drm_file *file_priv) { struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); nouveau_vm_ref(NULL, &fpriv->vm, NULL); kfree(fpriv); }
static int nv50_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, struct nouveau_channel **pchan) { struct drm_nouveau_private *dev_priv = dev->dev_private; u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; u32 fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200; struct nouveau_channel *chan; int ret, i; chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) return -ENOMEM; chan->dev = dev; ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); if (ret) { nv50_channel_del(&chan); return ret; } ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size); if (ret) { nv50_channel_del(&chan); return ret; } ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : chan->ramin->pinst + pgd, chan->ramin->vinst + pgd, 0x4000, NVOBJ_FLAG_ZERO_ALLOC, &chan->vm_pd); if (ret) { nv50_channel_del(&chan); return ret; } for (i = 0; i < 0x4000; i += 8) { nv_wo32(chan->vm_pd, i + 0, 0x00000000); nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe); } ret = nouveau_vm_ref(vm, &chan->vm, chan->vm_pd); if (ret) { nv50_channel_del(&chan); return ret; } ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : chan->ramin->pinst + fc, chan->ramin->vinst + fc, 0x100, NVOBJ_FLAG_ZERO_ALLOC, &chan->ramfc); if (ret) { nv50_channel_del(&chan); return ret; } *pchan = chan; return 0; }
static void nv50_bar_dtor(struct nouveau_object *object) { struct nv50_bar_priv *priv = (void *)object; nouveau_gpuobj_ref(NULL, &priv->bar1); nouveau_vm_ref(NULL, &priv->bar1_vm, priv->pgd); nouveau_gpuobj_ref(NULL, &priv->bar3); if (priv->bar3_vm) { nouveau_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]); nouveau_vm_ref(NULL, &priv->bar3_vm, priv->pgd); } nouveau_gpuobj_ref(NULL, &priv->pgd); nouveau_gpuobj_ref(NULL, &priv->pad); nouveau_gpuobj_ref(NULL, &priv->mem); nouveau_bar_destroy(&priv->base); }
static void nouveau_cli_destroy(struct nouveau_cli *cli) { nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL); nvif_client_fini(&cli->base); usif_client_fini(cli); }
static void nouveau_cli_destroy(struct nouveau_cli *cli) { struct nouveau_object *client = nv_object(cli); nouveau_vm_ref(NULL, &cli->base.vm, NULL); nouveau_client_fini(&cli->base, false); atomic_set(&client->refcount, 1); nouveau_object_ref(NULL, &client); }
void nv50_instmem_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; struct nouveau_channel *chan = dev_priv->channels.ptr[0]; int i; NV_DEBUG(dev, "\n"); if (!priv) return; dev_priv->ramin_available = false; nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL); for (i = 0x1700; i <= 0x1710; i += 4) nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); nouveau_gpuobj_ref(NULL, &priv->bar3_dmaobj); nouveau_gpuobj_ref(NULL, &priv->bar1_dmaobj); nouveau_vm_ref(NULL, &dev_priv->bar1_vm, chan->vm_pd); dev_priv->channels.ptr[127] = 0; nv50_channel_del(&dev_priv->channels.ptr[0]); nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); if (drm_mm_initialized(&dev_priv->ramin_heap)) drm_mm_takedown(&dev_priv->ramin_heap); dev_priv->engine.instmem.priv = NULL; kfree(priv); }
static void nvc0_channel_del(struct nouveau_channel **pchan) { struct nouveau_channel *chan; chan = *pchan; *pchan = NULL; if (!chan) return; nouveau_vm_ref(NULL, &chan->vm, NULL); if (chan->ramin_heap.free_stack.next) drm_mm_takedown(&chan->ramin_heap); nouveau_gpuobj_ref(NULL, &chan->ramin); kfree(chan); }
static void nv50_channel_del(struct nouveau_channel **pchan) { struct nouveau_channel *chan; chan = *pchan; *pchan = NULL; if (!chan) return; nouveau_gpuobj_ref(NULL, &chan->ramfc); nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); nouveau_gpuobj_ref(NULL, &chan->vm_pd); if (drm_mm_initialized(&chan->ramin_heap)) drm_mm_takedown(&chan->ramin_heap); nouveau_gpuobj_ref(NULL, &chan->ramin); kfree(chan); }
static int nvc0_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, struct nouveau_channel **pchan, struct nouveau_gpuobj *pgd, u64 vm_size) { struct nouveau_channel *chan; int ret; chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) return -ENOMEM; chan->dev = dev; ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); if (ret) { nvc0_channel_del(&chan); return ret; } ret = drm_mm_init(&chan->ramin_heap, 0x1000, size - 0x1000); if (ret) { nvc0_channel_del(&chan); return ret; } ret = nouveau_vm_ref(vm, &chan->vm, NULL); if (ret) { nvc0_channel_del(&chan); return ret; } nv_wo32(chan->ramin, 0x0200, lower_32_bits(pgd->vinst)); nv_wo32(chan->ramin, 0x0204, upper_32_bits(pgd->vinst)); nv_wo32(chan->ramin, 0x0208, lower_32_bits(vm_size - 1)); nv_wo32(chan->ramin, 0x020c, upper_32_bits(vm_size - 1)); *pchan = chan; return 0; }
int nvc0_instmem_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; struct pci_dev *pdev = dev->pdev; struct nvc0_instmem_priv *priv; struct nouveau_vm *vm = NULL; int ret; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; pinstmem->priv = priv; /* BAR3 VM */ ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 3), 0, &dev_priv->bar3_vm); if (ret) goto error; ret = nouveau_gpuobj_new(dev, NULL, (pci_resource_len(pdev, 3) >> 12) * 8, 0, NVOBJ_FLAG_DONT_MAP | NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->bar3_vm->pgt[0].obj[0]); if (ret) goto error; dev_priv->bar3_vm->pgt[0].refcount[0] = 1; nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, NVOBJ_FLAG_ZERO_ALLOC, &priv->bar3_pgd); if (ret) goto error; ret = nouveau_vm_ref(dev_priv->bar3_vm, &vm, priv->bar3_pgd); if (ret) goto error; nouveau_vm_ref(NULL, &vm, NULL); ret = nvc0_channel_new(dev, 8192, dev_priv->bar3_vm, &priv->bar3, priv->bar3_pgd, pci_resource_len(dev->pdev, 3)); if (ret) goto error; /* BAR1 VM */ ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 1), 0, &vm); if (ret) goto error; ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, NVOBJ_FLAG_ZERO_ALLOC, &priv->bar1_pgd); if (ret) goto error; ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, priv->bar1_pgd); if (ret) goto error; nouveau_vm_ref(NULL, &vm, NULL); ret = nvc0_channel_new(dev, 8192, dev_priv->bar1_vm, &priv->bar1, priv->bar1_pgd, pci_resource_len(dev->pdev, 1)); if (ret) goto error; /* channel vm */ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, &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: nvc0_instmem_takedown(dev); return ret; }
static int nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nouveau_device *device = nv_device(parent); struct pci_dev *pdev = device->pdev; struct nvc0_bar_priv *priv; struct nouveau_gpuobj *mem; struct nouveau_vm *vm; int ret; ret = nouveau_bar_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; /* BAR3 */ ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0, 0, &priv->bar[0].mem); mem = priv->bar[0].mem; if (ret) return ret; ret = nouveau_gpuobj_new(parent, NULL, 0x8000, 0, 0, &priv->bar[0].pgd); if (ret) return ret; ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 3), 0, &vm); if (ret) return ret; ret = nouveau_gpuobj_new(parent, NULL, (pci_resource_len(pdev, 3) >> 12) * 8, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); vm->pgt[0].refcount[0] = 1; if (ret) return ret; ret = nouveau_vm_ref(vm, &priv->bar[0].vm, priv->bar[0].pgd); nouveau_vm_ref(NULL, &vm, NULL); if (ret) return ret; nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[0].pgd->addr)); nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[0].pgd->addr)); nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 3) - 1)); nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 3) - 1)); /* BAR1 */ ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0, 0, &priv->bar[1].mem); mem = priv->bar[1].mem; if (ret) return ret; ret = nouveau_gpuobj_new(parent, NULL, 0x8000, 0, 0, &priv->bar[1].pgd); if (ret) return ret; ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 1), 0, &vm); if (ret) return ret; ret = nouveau_vm_ref(vm, &priv->bar[1].vm, priv->bar[1].pgd); nouveau_vm_ref(NULL, &vm, NULL); if (ret) return ret; nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[1].pgd->addr)); nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[1].pgd->addr)); nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 1) - 1)); nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 1) - 1)); priv->base.alloc = nouveau_bar_alloc; priv->base.kmap = nvc0_bar_kmap; priv->base.umap = nvc0_bar_umap; priv->base.unmap = nvc0_bar_unmap; priv->base.flush = nv84_bar_flush; spin_lock_init(&priv->lock); return 0; }
static int nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nouveau_device *device = nv_device(parent); struct nouveau_object *heap; struct nouveau_vm *vm; struct nv50_bar_priv *priv; u64 start, limit; int ret; ret = nouveau_bar_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x20000, 0, NVOBJ_FLAG_HEAP, &priv->mem); heap = nv_object(priv->mem); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), heap, (device->chipset == 0x50) ? 0x1400 : 0x0200, 0, 0, &priv->pad); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), heap, 0x4000, 0, 0, &priv->pgd); if (ret) return ret; /* BAR3 */ start = 0x0100000000ULL; limit = start + nv_device_resource_len(device, 3); ret = nouveau_vm_new(device, start, limit, start, &vm); if (ret) return ret; atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); ret = nouveau_gpuobj_new(nv_object(priv), heap, ((limit-- - start) >> 12) * 8, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); vm->pgt[0].refcount[0] = 1; if (ret) return ret; ret = nouveau_vm_ref(vm, &priv->bar3_vm, priv->pgd); nouveau_vm_ref(NULL, &vm, NULL); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar3); if (ret) return ret; nv_wo32(priv->bar3, 0x00, 0x7fc00000); nv_wo32(priv->bar3, 0x04, lower_32_bits(limit)); nv_wo32(priv->bar3, 0x08, lower_32_bits(start)); nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 | upper_32_bits(start)); nv_wo32(priv->bar3, 0x10, 0x00000000); nv_wo32(priv->bar3, 0x14, 0x00000000); /* BAR1 */ start = 0x0000000000ULL; limit = start + nv_device_resource_len(device, 1); ret = nouveau_vm_new(device, start, limit--, start, &vm); if (ret) return ret; atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); ret = nouveau_vm_ref(vm, &priv->bar1_vm, priv->pgd); nouveau_vm_ref(NULL, &vm, NULL); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar1); if (ret) return ret; nv_wo32(priv->bar1, 0x00, 0x7fc00000); nv_wo32(priv->bar1, 0x04, lower_32_bits(limit)); nv_wo32(priv->bar1, 0x08, lower_32_bits(start)); nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 | upper_32_bits(start)); nv_wo32(priv->bar1, 0x10, 0x00000000); nv_wo32(priv->bar1, 0x14, 0x00000000); priv->base.alloc = nouveau_bar_alloc; priv->base.kmap = nv50_bar_kmap; priv->base.umap = nv50_bar_umap; priv->base.unmap = nv50_bar_unmap; if (device->chipset == 0x50) priv->base.flush = nv50_bar_flush; else priv->base.flush = nv84_bar_flush; spin_lock_init(&priv->lock); return 0; }
int nv50_instmem_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv; struct nouveau_channel *chan; struct nouveau_vm *vm; int ret, i; u32 tmp; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; dev_priv->engine.instmem.priv = priv; /* */ for (i = 0x1700; i <= 0x1710; i += 4) priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); /* */ ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size); if (ret) { NV_ERROR(dev, "Failed to init RAMIN heap\n"); goto error; } /* */ ret = nouveau_vm_new(dev, BAR3_VM_BASE, BAR3_VM_SIZE, BAR3_VM_BASE, &dev_priv->bar3_vm); if (ret) goto error; ret = nouveau_gpuobj_new(dev, NULL, (BAR3_VM_SIZE >> 12) * 8, 0x1000, NVOBJ_FLAG_DONT_MAP | NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->bar3_vm->pgt[0].obj[0]); if (ret) goto error; dev_priv->bar3_vm->pgt[0].refcount[0] = 1; nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); ret = nv50_channel_new(dev, 128 * 1024, dev_priv->bar3_vm, &chan); if (ret) goto error; dev_priv->channels.ptr[0] = dev_priv->channels.ptr[127] = chan; ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR3_VM_BASE, BAR3_VM_SIZE, NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM, NV_MEM_TYPE_VM, NV_MEM_COMP_VM, &priv->bar3_dmaobj); if (ret) goto error; nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12)); nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12)); nv_wr32(dev, 0x00170c, 0x80000000 | (priv->bar3_dmaobj->cinst >> 4)); dev_priv->engine.instmem.flush(dev); dev_priv->ramin_available = true; tmp = nv_ro32(chan->ramin, 0); nv_wo32(chan->ramin, 0, ~tmp); if (nv_ro32(chan->ramin, 0) != ~tmp) { NV_ERROR(dev, "PRAMIN readback failed\n"); ret = -EIO; goto error; } nv_wo32(chan->ramin, 0, tmp); /* */ ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, &vm); if (ret) goto error; ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, chan->vm_pd); if (ret) goto error; nouveau_vm_ref(NULL, &vm, NULL); ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR1_VM_BASE, BAR1_VM_SIZE, NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM, NV_MEM_TYPE_VM, NV_MEM_COMP_VM, &priv->bar1_dmaobj); if (ret) goto error; nv_wr32(dev, 0x001708, 0x80000000 | (priv->bar1_dmaobj->cinst >> 4)); for (i = 0; i < 8; i++) nv_wr32(dev, 0x1900 + (i*4), 0); /* */ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL, &dev_priv->chan_vm); if (ret) return ret; return 0; error: nv50_instmem_takedown(dev); return ret; }