Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6
authorDave Airlie <airlied@redhat.com>
Tue, 30 Jul 2013 06:49:57 +0000 (16:49 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 30 Jul 2013 06:49:57 +0000 (16:49 +1000)
nouveau fixes a number of regressions and a few user triggerable oops
since -rc1. Along with a few mpeg engine fixes.

* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
  drm/nouveau: fix semaphore dmabuf obj
  drm/nouveau/vm: make vm refcount into a kref
  drm/nv31/mpeg: don't recognize nv3x cards as having nv44 graph class
  drm/nv40/mpeg: write magic value to channel object to make it work
  drm/nouveau: fix size check for cards without vm
  drm/nv50-/disp: remove dcb_outp_match call, and related variables
  drm/nva3-/disp: fix hda eld writing, needs to be padded
  drm/nv31/mpeg: fix mpeg engine initialization
  drm/nv50/mc: include vp in the fb error reporting mask
  drm/nouveau: fix null pointer dereference in poll_changed
  drm/nv50/gpio: post-nv92 cards have 32 interrupt lines
  drm/nvc0/fb: take lock in nvc0_ram_put()
  drm/nouveau/core: xtensa firmware size needs to be 0x40000 no matter what

17 files changed:
drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
drivers/gpu/drm/nouveau/core/engine/xtensa.c
drivers/gpu/drm/nouveau/core/include/subdev/vm.h
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
drivers/gpu/drm/nouveau/core/subdev/vm/base.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nv17_fence.c
drivers/gpu/drm/nouveau/nv50_fence.c

index 373dbcc..a19e7d7 100644 (file)
@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x61c440 + soff, (i << 8));
                nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index dc57e24..7176393 100644 (file)
@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x10ec00 + soff, (i << 8));
                nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index ab1e918..526b752 100644 (file)
@@ -47,14 +47,8 @@ int
 nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
-       struct nouveau_bios *bios = nouveau_bios(priv);
-       const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
        const u8  head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
-       const u8  link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
        const u8    or = (mthd & NV50_DISP_SOR_MTHD_OR);
-       const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
-       struct dcb_output outp;
-       u8  ver, hdr;
        u32 data;
        int ret = -EINVAL;
 
@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
                return -EINVAL;
        data = *(u32 *)args;
 
-       if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
-               return -ENODEV;
 
        switch (mthd & ~0x3f) {
        case NV50_DISP_SOR_PWR:
index 49ecbb8..c190043 100644 (file)
@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 int
 nv31_mpeg_init(struct nouveau_object *object)
 {
-       struct nouveau_engine *engine = nv_engine(object->engine);
-       struct nv31_mpeg_priv *priv = (void *)engine;
+       struct nouveau_engine *engine = nv_engine(object);
+       struct nv31_mpeg_priv *priv = (void *)object;
        struct nouveau_fb *pfb = nouveau_fb(object);
        int ret, i;
 
@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object)
        /* PMPEG init */
        nv_wr32(priv, 0x00b32c, 0x00000000);
        nv_wr32(priv, 0x00b314, 0x00000100);
-       nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031);
+       if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv))
+               nv_wr32(priv, 0x00b220, 0x00000044);
+       else
+               nv_wr32(priv, 0x00b220, 0x00000031);
        nv_wr32(priv, 0x00b300, 0x02001ec1);
        nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
 
index f7c581a..dd61960 100644 (file)
@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
        return 0;
 }
 
index 0639bc5..5f6ede7 100644 (file)
@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object)
                        return ret;
                }
 
-               ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0,
+               if (fw->size > 0x40000) {
+                       nv_warn(xtensa, "firmware %s too large\n", name);
+                       release_firmware(fw);
+                       return -EINVAL;
+               }
+
+               ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
                                         &xtensa->gpu_fw);
                if (ret) {
                        release_firmware(fw);
index f2e87b1..fcf57fa 100644 (file)
@@ -55,7 +55,7 @@ struct nouveau_vma {
 struct nouveau_vm {
        struct nouveau_vmmgr *vmm;
        struct nouveau_mm mm;
-       int refcount;
+       struct kref refcount;
 
        struct list_head pgd_list;
        atomic_t engref[NVDEV_SUBDEV_NR];
index 6c974dd..db9d6dd 100644 (file)
@@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
 void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
                       u32 pitch, u32 flags, struct nouveau_fb_tile *);
 
-void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
 extern int nv50_fb_memtype[0x80];
 
 #endif
index af5aa7e..903baff 100644 (file)
 #include "priv.h"
 
 void
-nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
 {
        struct nouveau_mm_node *this;
-       struct nouveau_mem *mem;
 
-       mem = *pmem;
-       *pmem = NULL;
-       if (unlikely(mem == NULL))
-               return;
-
-       mutex_lock(&pfb->base.mutex);
        while (!list_empty(&mem->regions)) {
                this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
 
@@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
        }
 
        nouveau_mm_free(&pfb->tags, &mem->tag);
+}
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+       struct nouveau_mem *mem = *pmem;
+
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
+
+       mutex_lock(&pfb->base.mutex);
+       __nv50_ram_put(pfb, mem);
        mutex_unlock(&pfb->base.mutex);
 
        kfree(mem);
index 9c3634a..cf97c4d 100644 (file)
@@ -33,11 +33,19 @@ void
 nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
 {
        struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+       struct nouveau_mem *mem = *pmem;
 
-       if ((*pmem)->tag)
-               ltcg->tags_free(ltcg, &(*pmem)->tag);
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
 
-       nv50_ram_put(pfb, pmem);
+       mutex_lock(&pfb->base.mutex);
+       if (mem->tag)
+               ltcg->tags_free(ltcg, &mem->tag);
+       __nv50_ram_put(pfb, mem);
+       mutex_unlock(&pfb->base.mutex);
+
+       kfree(mem);
 }
 
 int
index bf489dc..c4c1d41 100644 (file)
@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        int i;
 
        intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
 
        hi = (intr0 & 0x0000ffff) | (intr1 << 16);
@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        }
 
        nv_wr32(priv, 0xe054, intr0);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe074, intr1);
 }
 
@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int ret;
 
        ret = nouveau_gpio_create(parent, engine, oclass,
-                                 nv_device(parent)->chipset >= 0x90 ? 32 : 16,
+                                 nv_device(parent)->chipset > 0x92 ? 32 : 16,
                                  &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object)
        /* disable, and ack any pending gpio interrupts */
        nv_wr32(priv, 0xe050, 0x00000000);
        nv_wr32(priv, 0xe054, 0xffffffff);
-       if (nv_device(priv)->chipset >= 0x90) {
+       if (nv_device(priv)->chipset > 0x92) {
                nv_wr32(priv, 0xe070, 0x00000000);
                nv_wr32(priv, 0xe074, 0xffffffff);
        }
@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_gpio_priv *priv = (void *)object;
        nv_wr32(priv, 0xe050, 0x00000000);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe070, 0x00000000);
        return nouveau_gpio_fini(&priv->base, suspend);
 }
index 0cb322a..f25fc5f 100644 (file)
@@ -41,7 +41,7 @@ nv50_mc_intr[] = {
        { 0x04000000, NVDEV_ENGINE_DISP },
        { 0x10000000, NVDEV_SUBDEV_BUS },
        { 0x80000000, NVDEV_ENGINE_SW },
-       { 0x0000d101, NVDEV_SUBDEV_FB },
+       { 0x0002d101, NVDEV_SUBDEV_FB },
        {},
 };
 
index 67fcb6c..ef3133e 100644 (file)
@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
 
        INIT_LIST_HEAD(&vm->pgd_list);
        vm->vmm = vmm;
-       vm->refcount = 1;
+       kref_init(&vm->refcount);
        vm->fpde = offset >> (vmm->pgt_bits + 12);
        vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
 
@@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
 }
 
 static void
-nouveau_vm_del(struct nouveau_vm *vm)
+nouveau_vm_del(struct kref *kref)
 {
+       struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
        struct nouveau_vm_pgd *vpgd, *tmp;
 
        list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
@@ -458,27 +459,19 @@ int
 nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
               struct nouveau_gpuobj *pgd)
 {
-       struct nouveau_vm *vm;
-       int ret;
-
-       vm = ref;
-       if (vm) {
-               ret = nouveau_vm_link(vm, pgd);
+       if (ref) {
+               int ret = nouveau_vm_link(ref, pgd);
                if (ret)
                        return ret;
 
-               vm->refcount++;
+               kref_get(&ref->refcount);
        }
 
-       vm = *ptr;
-       *ptr = ref;
-
-       if (vm) {
-               nouveau_vm_unlink(vm, pgd);
-
-               if (--vm->refcount == 0)
-                       nouveau_vm_del(vm);
+       if (*ptr) {
+               nouveau_vm_unlink(*ptr, pgd);
+               kref_put(&(*ptr)->refcount, nouveau_vm_del);
        }
 
+       *ptr = ref;
        return 0;
 }
index 4e7ee5f..af20fba 100644 (file)
@@ -198,7 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
        size_t acc_size;
        int ret;
        int type = ttm_bo_type_device;
-       int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1);
+       int lpg_shift = 12;
+       int max_size;
+
+       if (drm->client.base.vm)
+               lpg_shift = drm->client.base.vm->vmm->lpg_shift;
+       max_size = INT_MAX & ~((1 << lpg_shift) - 1);
 
        if (size <= 0 || size > max_size) {
                nv_warn(drm, "skipped size %x\n", (u32)size);
index 4c1bc06..8f6d63d 100644 (file)
@@ -398,7 +398,8 @@ void
 nouveau_fbcon_output_poll_changed(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       drm_fb_helper_hotplug_event(&drm->fbcon->helper);
+       if (drm->fbcon)
+               drm_fb_helper_hotplug_event(&drm->fbcon->helper);
 }
 
 static int
index 8e47a9b..22aa996 100644 (file)
@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
        u32 start = mem->start * PAGE_SIZE;
-       u32 limit = mem->start + mem->size - 1;
+       u32 limit = start + mem->size - 1;
        int ret = 0;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
index f9701e5..0ee3638 100644 (file)
@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        struct nv10_fence_chan *fctx;
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
+       u32 start = mem->start * PAGE_SIZE;
+       u32 limit = start + mem->size - 1;
        int ret, i;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        fctx->base.sync = nv17_fence_sync;
 
        ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
-                                NvSema, 0x0002,
+                                NvSema, 0x003d,
                                 &(struct nv_dma_class) {
                                        .flags = NV_DMA_TARGET_VRAM |
                                                 NV_DMA_ACCESS_RDWR,
-                                       .start = mem->start * PAGE_SIZE,
-                                       .limit = mem->size - 1,
+                                       .start = start,
+                                       .limit = limit,
                                 }, sizeof(struct nv_dma_class),
                                 &object);
 
        /* dma objects for display sync channel semaphore blocks */
        for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
                struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
+               u32 start = bo->bo.mem.start * PAGE_SIZE;
+               u32 limit = start + bo->bo.mem.size - 1;
 
                ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
                                         NvEvoSema0 + i, 0x003d,
                                         &(struct nv_dma_class) {
                                                .flags = NV_DMA_TARGET_VRAM |
                                                         NV_DMA_ACCESS_RDWR,
-                                               .start = bo->bo.offset,
-                                               .limit = bo->bo.offset + 0xfff,
+                                               .start = start,
+                                               .limit = limit,
                                         }, sizeof(struct nv_dma_class),
                                         &object);
        }