drm/nvc0: enable protection of system-use-only structures in vm
[deliverable/linux.git] / drivers / gpu / drm / nouveau / nv50_instmem.c
index 08202fd682e4dfb4b375a79ea43f0bfd804dae32..ea0041810ae3a648959f533e3fbefcc17ca508d7 100644 (file)
@@ -131,7 +131,6 @@ nv50_instmem_init(struct drm_device *dev)
        struct nouveau_channel *chan;
        struct nouveau_vm *vm;
        int ret, i;
-       u64 nongart_o;
        u32 tmp;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -152,20 +151,19 @@ nv50_instmem_init(struct drm_device *dev)
 
        /* BAR3 */
        ret = nouveau_vm_new(dev, BAR3_VM_BASE, BAR3_VM_SIZE, BAR3_VM_BASE,
-                            29, 12, 16, &dev_priv->bar3_vm);
+                            &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);
+                                &dev_priv->bar3_vm->pgt[0].obj[0]);
        if (ret)
                goto error;
-       dev_priv->bar3_vm->pgt[0].page_shift = 12;
-       dev_priv->bar3_vm->pgt[0].refcount = 1;
+       dev_priv->bar3_vm->pgt[0].refcount[0] = 1;
 
-       nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj);
+       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)
@@ -183,20 +181,20 @@ nv50_instmem_init(struct drm_device *dev)
        nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12));
        nv_wr32(dev, 0x00170c, 0x80000000 | (priv->bar3_dmaobj->cinst >> 4));
 
-       tmp = nv_ri32(dev, 0);
-       nv_wi32(dev, 0, ~tmp);
-       if (nv_ri32(dev, 0) != ~tmp) {
+       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_wi32(dev, 0, tmp);
-
-       dev_priv->ramin_available = true;
+       nv_wo32(chan->ramin, 0, tmp);
 
        /* BAR1 */
-       ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE,
-                            29, 12, 16, &vm);
+       ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, &vm);
        if (ret)
                goto error;
 
@@ -216,16 +214,11 @@ nv50_instmem_init(struct drm_device *dev)
        for (i = 0; i < 8; i++)
                nv_wr32(dev, 0x1900 + (i*4), 0);
 
-       /* Create shared channel VM, space is reserved for GART mappings at
-        * the beginning of this address space, it's managed separately
-        * because TTM makes life painful
+       /* Create shared channel VM, space is reserved at the beginning
+        * to catch "NULL pointer" references
         */
-       dev_priv->vm_gart_base = 0x0020000000ULL;
-       dev_priv->vm_gart_size = 512 * 1024 * 1024;
-       nongart_o = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
-
-       ret = nouveau_vm_new(dev, 0, (1ULL << 40), nongart_o,
-                            29, 12, 16, &dev_priv->chan_vm);
+       ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL,
+                            &dev_priv->chan_vm);
        if (ret)
                return ret;
 
@@ -263,7 +256,7 @@ nv50_instmem_takedown(struct drm_device *dev)
        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);
+       nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]);
        nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL);
 
        if (dev_priv->ramin_heap.free_stack.next)
@@ -308,6 +301,7 @@ nv50_instmem_resume(struct drm_device *dev)
 
 struct nv50_gpuobj_node {
        struct nouveau_vram *vram;
+       struct nouveau_vma chan_vma;
        u32 align;
 };
 
@@ -316,6 +310,8 @@ int
 nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align)
 {
        struct drm_device *dev = gpuobj->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
        struct nv50_gpuobj_node *node = NULL;
        int ret;
 
@@ -327,15 +323,33 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align)
        size  = (size + 4095) & ~4095;
        align = max(align, (u32)4096);
 
-       ret = nv50_vram_new(dev, size, align, 0, 0, &node->vram);
+       ret = vram->get(dev, size, align, 0, 0, &node->vram);
        if (ret) {
                kfree(node);
                return ret;
        }
 
        gpuobj->vinst = node->vram->offset;
-       gpuobj->size  = size;
-       gpuobj->node  = node;
+
+       if (gpuobj->flags & NVOBJ_FLAG_VM) {
+               u32 flags = NV_MEM_ACCESS_RW;
+               if (!(gpuobj->flags & NVOBJ_FLAG_VM_USER))
+                       flags |= NV_MEM_ACCESS_SYS;
+
+               ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, flags,
+                                    &node->chan_vma);
+               if (ret) {
+                       vram->put(dev, &node->vram);
+                       kfree(node);
+                       return ret;
+               }
+
+               nouveau_vm_map(&node->chan_vma, node->vram);
+               gpuobj->vinst = node->chan_vma.offset;
+       }
+
+       gpuobj->size = size;
+       gpuobj->node = node;
        return 0;
 }
 
@@ -343,12 +357,18 @@ void
 nv50_instmem_put(struct nouveau_gpuobj *gpuobj)
 {
        struct drm_device *dev = gpuobj->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
        struct nv50_gpuobj_node *node;
 
        node = gpuobj->node;
        gpuobj->node = NULL;
 
-       nv50_vram_del(dev, &node->vram);
+       if (node->chan_vma.node) {
+               nouveau_vm_unmap(&node->chan_vma);
+               nouveau_vm_put(&node->chan_vma);
+       }
+       vram->put(dev, &node->vram);
        kfree(node);
 }
 
This page took 0.026707 seconds and 5 git commands to generate.