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:
Коммит
e9e3c8a20b
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче