#include "priv.h"
 
+struct nvc0_bar_priv_vm {
+       struct nouveau_gpuobj *mem;
+       struct nouveau_gpuobj *pgd;
+       struct nouveau_vm *vm;
+};
+
 struct nvc0_bar_priv {
        struct nouveau_bar base;
        spinlock_t lock;
-       struct {
-               struct nouveau_gpuobj *mem;
-               struct nouveau_gpuobj *pgd;
-               struct nouveau_vm *vm;
-       } bar[2];
+       struct nvc0_bar_priv_vm bar[2];
 };
 
 static int
 }
 
 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)
+nvc0_bar_init_vm(struct nvc0_bar_priv *priv, struct nvc0_bar_priv_vm *bar_vm,
+                int bar_nr)
 {
-       struct nouveau_device *device = nv_device(parent);
-       struct nvc0_bar_priv *priv;
-       struct nouveau_gpuobj *mem;
+       struct nouveau_device *device = nv_device(&priv->base);
        struct nouveau_vm *vm;
+       resource_size_t bar_len;
        int ret;
 
-       ret = nouveau_bar_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       /* BAR3 */
        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
-                               &priv->bar[0].mem);
-       mem = priv->bar[0].mem;
+                               &bar_vm->mem);
        if (ret)
                return ret;
 
        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0,
-                               &priv->bar[0].pgd);
+                               &bar_vm->pgd);
        if (ret)
                return ret;
 
-       ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 3), 0, &vm);
+       bar_len = nv_device_resource_len(device, bar_nr);
+
+       ret = nouveau_vm_new(device, 0, bar_len, 0, &vm);
        if (ret)
                return ret;
 
        atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
 
-       ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-                                (nv_device_resource_len(device, 3) >> 12) * 8,
-                                0x1000, NVOBJ_FLAG_ZERO_ALLOC,
-                                &vm->pgt[0].obj[0]);
-       vm->pgt[0].refcount[0] = 1;
-       if (ret)
-               return ret;
+       /*
+        * Bootstrap page table lookup.
+        */
+       if (bar_nr == 3) {
+               ret = nouveau_gpuobj_new(nv_object(priv), NULL,
+                                        (bar_len >> 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);
+       ret = nouveau_vm_ref(vm, &bar_vm->vm, bar_vm->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(nv_device_resource_len(device, 3) - 1));
-       nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 3) - 1));
+       nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr));
+       nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr));
+       nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1));
+       nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1));
 
-       /* BAR1 */
-       ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
-                               &priv->bar[1].mem);
-       mem = priv->bar[1].mem;
-       if (ret)
-               return ret;
+       return 0;
+}
 
-       ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0,
-                               &priv->bar[1].pgd);
-       if (ret)
-               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 nvc0_bar_priv *priv;
+       bool has_bar3 = nv_device_resource_len(device, 3) != 0;
+       int ret;
 
-       ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 1), 0, &vm);
+       ret = nouveau_bar_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+       /* BAR3 */
+       if (has_bar3) {
+               ret = nvc0_bar_init_vm(priv, &priv->bar[0], 3);
+               if (ret)
+                       return ret;
+               priv->base.alloc = nouveau_bar_alloc;
+               priv->base.kmap = nvc0_bar_kmap;
+       }
 
-       ret = nouveau_vm_ref(vm, &priv->bar[1].vm, priv->bar[1].pgd);
-       nouveau_vm_ref(NULL, &vm, NULL);
+       /* BAR1 */
+       ret = nvc0_bar_init_vm(priv, &priv->bar[1], 1);
        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(nv_device_resource_len(device, 1) - 1));
-       nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 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;
        nv_mask(priv, 0x100c80, 0x00000001, 0x00000000);
 
        nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12);
-       nv_wr32(priv, 0x001714, 0xc0000000 | priv->bar[0].mem->addr >> 12);
+       if (priv->bar[0].mem)
+               nv_wr32(priv, 0x001714,
+                       0xc0000000 | priv->bar[0].mem->addr >> 12);
        return 0;
 }