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
This commit is contained in:
Dave Airlie 2013-07-30 16:49:57 +10:00
commit e9e3c8a20b
17 changed files with 80 additions and 57 deletions

View 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) {

View 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) {

View 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:

View 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);

View 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;
}

View 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);

View 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];

View 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

View File

@ -27,17 +27,10 @@
#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);

View 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

View 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);
}

View 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 },
{},
};

View 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);
}
if (*ptr) {
nouveau_vm_unlink(*ptr, pgd);
kref_put(&(*ptr)->refcount, nouveau_vm_del);
}
vm = *ptr;
*ptr = ref;
if (vm) {
nouveau_vm_unlink(vm, pgd);
if (--vm->refcount == 0)
nouveau_vm_del(vm);
}
return 0;
}

View 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);

View File

@ -398,6 +398,7 @@ void
nouveau_fbcon_output_poll_changed(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon)
drm_fb_helper_hotplug_event(&drm->fbcon->helper);
}

View 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);

View 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);
}