Commit e9e3c8a2 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6

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
parents ca089b72 7a7da592
...@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size) ...@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
if (data && data[0]) { if (data && data[0]) {
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[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); nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
} else } else
if (data) { if (data) {
......
...@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size) ...@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
if (data && data[0]) { if (data && data[0]) {
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[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); nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
} else } else
if (data) { if (data) {
......
...@@ -47,14 +47,8 @@ int ...@@ -47,14 +47,8 @@ int
nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; 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 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 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; u32 data;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) ...@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
return -EINVAL; return -EINVAL;
data = *(u32 *)args; data = *(u32 *)args;
if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
return -ENODEV;
switch (mthd & ~0x3f) { switch (mthd & ~0x3f) {
case NV50_DISP_SOR_PWR: case NV50_DISP_SOR_PWR:
......
...@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int int
nv31_mpeg_init(struct nouveau_object *object) nv31_mpeg_init(struct nouveau_object *object)
{ {
struct nouveau_engine *engine = nv_engine(object->engine); struct nouveau_engine *engine = nv_engine(object);
struct nv31_mpeg_priv *priv = (void *)engine; struct nv31_mpeg_priv *priv = (void *)object;
struct nouveau_fb *pfb = nouveau_fb(object); struct nouveau_fb *pfb = nouveau_fb(object);
int ret, i; int ret, i;
...@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object) ...@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object)
/* PMPEG init */ /* PMPEG init */
nv_wr32(priv, 0x00b32c, 0x00000000); nv_wr32(priv, 0x00b32c, 0x00000000);
nv_wr32(priv, 0x00b314, 0x00000100); 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_wr32(priv, 0x00b300, 0x02001ec1);
nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
......
...@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent, ...@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent,
if (ret) if (ret)
return ret; return ret;
nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
return 0; return 0;
} }
......
...@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object) ...@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object)
return ret; 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); &xtensa->gpu_fw);
if (ret) { if (ret) {
release_firmware(fw); release_firmware(fw);
......
...@@ -55,7 +55,7 @@ struct nouveau_vma { ...@@ -55,7 +55,7 @@ struct nouveau_vma {
struct nouveau_vm { struct nouveau_vm {
struct nouveau_vmmgr *vmm; struct nouveau_vmmgr *vmm;
struct nouveau_mm mm; struct nouveau_mm mm;
int refcount; struct kref refcount;
struct list_head pgd_list; struct list_head pgd_list;
atomic_t engref[NVDEV_SUBDEV_NR]; atomic_t engref[NVDEV_SUBDEV_NR];
......
...@@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); ...@@ -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, void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nouveau_fb_tile *); 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]; extern int nv50_fb_memtype[0x80];
#endif #endif
...@@ -27,17 +27,10 @@ ...@@ -27,17 +27,10 @@
#include "priv.h" #include "priv.h"
void 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_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)) { while (!list_empty(&mem->regions)) {
this = list_first_entry(&mem->regions, typeof(*this), rl_entry); 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) ...@@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
} }
nouveau_mm_free(&pfb->tags, &mem->tag); 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); mutex_unlock(&pfb->base.mutex);
kfree(mem); kfree(mem);
......
...@@ -33,11 +33,19 @@ void ...@@ -33,11 +33,19 @@ void
nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
{ {
struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
struct nouveau_mem *mem = *pmem;
if ((*pmem)->tag) *pmem = NULL;
ltcg->tags_free(ltcg, &(*pmem)->tag); 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 int
......
...@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev) ...@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
int i; int i;
intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); 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); intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
hi = (intr0 & 0x0000ffff) | (intr1 << 16); hi = (intr0 & 0x0000ffff) | (intr1 << 16);
...@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev) ...@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
} }
nv_wr32(priv, 0xe054, intr0); nv_wr32(priv, 0xe054, intr0);
if (nv_device(priv)->chipset >= 0x90) if (nv_device(priv)->chipset > 0x92)
nv_wr32(priv, 0xe074, intr1); nv_wr32(priv, 0xe074, intr1);
} }
...@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_gpio_create(parent, engine, oclass, ret = nouveau_gpio_create(parent, engine, oclass,
nv_device(parent)->chipset >= 0x90 ? 32 : 16, nv_device(parent)->chipset > 0x92 ? 32 : 16,
&priv); &priv);
*pobject = nv_object(priv); *pobject = nv_object(priv);
if (ret) if (ret)
...@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object) ...@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object)
/* disable, and ack any pending gpio interrupts */ /* disable, and ack any pending gpio interrupts */
nv_wr32(priv, 0xe050, 0x00000000); nv_wr32(priv, 0xe050, 0x00000000);
nv_wr32(priv, 0xe054, 0xffffffff); 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, 0xe070, 0x00000000);
nv_wr32(priv, 0xe074, 0xffffffff); nv_wr32(priv, 0xe074, 0xffffffff);
} }
...@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend) ...@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv50_gpio_priv *priv = (void *)object; struct nv50_gpio_priv *priv = (void *)object;
nv_wr32(priv, 0xe050, 0x00000000); nv_wr32(priv, 0xe050, 0x00000000);
if (nv_device(priv)->chipset >= 0x90) if (nv_device(priv)->chipset > 0x92)
nv_wr32(priv, 0xe070, 0x00000000); nv_wr32(priv, 0xe070, 0x00000000);
return nouveau_gpio_fini(&priv->base, suspend); return nouveau_gpio_fini(&priv->base, suspend);
} }
......
...@@ -41,7 +41,7 @@ nv50_mc_intr[] = { ...@@ -41,7 +41,7 @@ nv50_mc_intr[] = {
{ 0x04000000, NVDEV_ENGINE_DISP }, { 0x04000000, NVDEV_ENGINE_DISP },
{ 0x10000000, NVDEV_SUBDEV_BUS }, { 0x10000000, NVDEV_SUBDEV_BUS },
{ 0x80000000, NVDEV_ENGINE_SW }, { 0x80000000, NVDEV_ENGINE_SW },
{ 0x0000d101, NVDEV_SUBDEV_FB }, { 0x0002d101, NVDEV_SUBDEV_FB },
{}, {},
}; };
......
...@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, ...@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
INIT_LIST_HEAD(&vm->pgd_list); INIT_LIST_HEAD(&vm->pgd_list);
vm->vmm = vmm; vm->vmm = vmm;
vm->refcount = 1; kref_init(&vm->refcount);
vm->fpde = offset >> (vmm->pgt_bits + 12); vm->fpde = offset >> (vmm->pgt_bits + 12);
vm->lpde = (offset + length - 1) >> (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) ...@@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
} }
static void 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; struct nouveau_vm_pgd *vpgd, *tmp;
list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
...@@ -458,27 +459,19 @@ int ...@@ -458,27 +459,19 @@ int
nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr, nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
struct nouveau_gpuobj *pgd) struct nouveau_gpuobj *pgd)
{ {
struct nouveau_vm *vm; if (ref) {
int ret; int ret = nouveau_vm_link(ref, pgd);
vm = ref;
if (vm) {
ret = nouveau_vm_link(vm, pgd);
if (ret) if (ret)
return ret; return ret;
vm->refcount++; kref_get(&ref->refcount);
} }
vm = *ptr; if (*ptr) {
*ptr = ref; nouveau_vm_unlink(*ptr, pgd);
kref_put(&(*ptr)->refcount, nouveau_vm_del);
if (vm) {
nouveau_vm_unlink(vm, pgd);
if (--vm->refcount == 0)
nouveau_vm_del(vm);
} }
*ptr = ref;
return 0; return 0;
} }
...@@ -198,7 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, ...@@ -198,7 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
size_t acc_size; size_t acc_size;
int ret; int ret;
int type = ttm_bo_type_device; 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) { if (size <= 0 || size > max_size) {
nv_warn(drm, "skipped size %x\n", (u32)size); nv_warn(drm, "skipped size %x\n", (u32)size);
......
...@@ -398,7 +398,8 @@ void ...@@ -398,7 +398,8 @@ void
nouveau_fbcon_output_poll_changed(struct drm_device *dev) nouveau_fbcon_output_poll_changed(struct drm_device *dev)
{ {
struct nouveau_drm *drm = nouveau_drm(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 static int
......
...@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan) ...@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
struct ttm_mem_reg *mem = &priv->bo->bo.mem; struct ttm_mem_reg *mem = &priv->bo->bo.mem;
struct nouveau_object *object; struct nouveau_object *object;
u32 start = mem->start * PAGE_SIZE; u32 start = mem->start * PAGE_SIZE;
u32 limit = mem->start + mem->size - 1; u32 limit = start + mem->size - 1;
int ret = 0; int ret = 0;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
......
...@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan) ...@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
struct nv10_fence_chan *fctx; struct nv10_fence_chan *fctx;
struct ttm_mem_reg *mem = &priv->bo->bo.mem; struct ttm_mem_reg *mem = &priv->bo->bo.mem;
struct nouveau_object *object; struct nouveau_object *object;
u32 start = mem->start * PAGE_SIZE;
u32 limit = start + mem->size - 1;
int ret, i; int ret, i;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
...@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan) ...@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan)
fctx->base.sync = nv17_fence_sync; fctx->base.sync = nv17_fence_sync;
ret = nouveau_object_new(nv_object(chan->cli), chan->handle, ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
NvSema, 0x0002, NvSema, 0x003d,
&(struct nv_dma_class) { &(struct nv_dma_class) {
.flags = NV_DMA_TARGET_VRAM | .flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR, NV_DMA_ACCESS_RDWR,
.start = mem->start * PAGE_SIZE, .start = start,
.limit = mem->size - 1, .limit = limit,
}, sizeof(struct nv_dma_class), }, sizeof(struct nv_dma_class),
&object); &object);
/* dma objects for display sync channel semaphore blocks */ /* dma objects for display sync channel semaphore blocks */
for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) { for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
struct nouveau_bo *bo = nv50_display_crtc_sema(dev, 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, ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
NvEvoSema0 + i, 0x003d, NvEvoSema0 + i, 0x003d,
&(struct nv_dma_class) { &(struct nv_dma_class) {
.flags = NV_DMA_TARGET_VRAM | .flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR, NV_DMA_ACCESS_RDWR,
.start = bo->bo.offset, .start = start,
.limit = bo->bo.offset + 0xfff, .limit = limit,
}, sizeof(struct nv_dma_class), }, sizeof(struct nv_dma_class),
&object); &object);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment