From b84f30e65c2352c6400b9c748b918ca4031f5d4a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 28 Feb 2011 17:20:45 +1000 Subject: [PATCH 1/7] drm/nvc0: remove vm hack forcing large/small pages to not share a PDE Appears to be fixed with commit: "drm/nv50-nvc0: make sure vma is definitely unmapped when destroying bo" Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_vm.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c index 62824c80bcb8..0059e6f58a8b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vm.c +++ b/drivers/gpu/drm/nouveau/nouveau_vm.c @@ -314,18 +314,7 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, vm->spg_shift = 12; vm->lpg_shift = 17; pgt_bits = 27; - - /* Should be 4096 everywhere, this is a hack that's - * currently necessary to avoid an elusive bug that - * causes corruption when mixing small/large pages - */ - if (length < (1ULL << 40)) - block = 4096; - else { - block = (1 << pgt_bits); - if (length < block) - block = length; - } + block = 4096; } else { kfree(vm); return -ENOSYS; From 7fa0cba2b269fa498804a89a0a1d763ea1f65015 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Mon, 7 Mar 2011 12:31:35 +0100 Subject: [PATCH 2/7] drm/nouveau: properly handle pushbuffer check failures When "buffer in list" check does not pass, don't free validation lists - they were not initialized yet. Fixes this oops: [drm] nouveau 0000:02:00.0: push 105 buffer not in list BUG: unable to handle kernel NULL pointer dereference at 000000000000057c IP: [] do_raw_spin_lock+0x14/0x13c PGD 1ac6cb067 PUD 1aaa52067 PMD 0 CPU 0 Modules linked in: nouveau ttm drm_kms_helper snd_hda_codec_realtek snd_hda_intel snd_hda_codec Pid: 6265, comm: OilRush_x86 Not tainted 2.6.38-rc6-nv+ #632 System manufacturer System Product Name/P6T SE RIP: 0010:[] [] do_raw_spin_lock+0x14/0x13c (...) Process OilRush_x86 (pid: 6265, threadinfo ffff8801a6aee000, task ffff8801a26c0000) 0000000000000000 ffff8801ac74c618 0000000000000000 0000000000000578 0000000000000000 ffff8801ac74c618 0000000000000000 ffff8801bd9d0000 [] _raw_spin_lock+0x1e/0x22 [] nouveau_bo_fence+0x2e/0x60 [nouveau] [] validate_fini_list+0x35/0xeb [nouveau] [] validate_fini+0x12/0x31 [nouveau] [] nouveau_gem_ioctl_pushbuf+0xe94/0xf6b [nouveau] [] ? sub_preempt_count+0x9e/0xb2 [] ? _raw_spin_unlock_irqrestore+0x30/0x4d [] ? __wake_up+0x3f/0x48 [] drm_ioctl+0x289/0x361 [] ? sub_preempt_count+0x9e/0xb2 [] ? nouveau_gem_ioctl_pushbuf+0x0/0xf6b [nouveau] [] ? sub_preempt_count+0x9e/0xb2 [] nouveau_compat_ioctl+0x16/0x1c [nouveau] [] compat_sys_ioctl+0x1c8/0x12d7 [] ? trace_hardirqs_off_thunk+0x3a/0x6c [] sysenter_dispatch+0x7/0x30 [] ? trace_hardirqs_on_thunk+0x3a/0x3c RIP [] do_raw_spin_lock+0x14/0x13c RSP ---[ end trace 0014d5d93e6147e1 ]--- Additionally, don't call validate_fini twice in case of validation failure. Signed-off-by: Marcin Slusarz Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 3ce58d2222cb..e8b04f4aed7e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -600,7 +600,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (push[i].bo_index >= req->nr_buffers) { NV_ERROR(dev, "push %d buffer not in list\n", i); ret = -EINVAL; - goto out; + goto out_prevalid; } bo[push[i].bo_index].read_domains |= (1 << 31); @@ -612,7 +612,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (ret) { if (ret != -ERESTARTSYS) NV_ERROR(dev, "validate: %d\n", ret); - goto out; + goto out_prevalid; } /* Apply any relocations that are required */ @@ -705,6 +705,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, out: validate_fini(&op, fence); nouveau_fence_unref(&fence); + +out_prevalid: kfree(bo); kfree(push); From bb9b18a390db4a15cd46bbd7472510feb7d4c168 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 Mar 2011 08:39:43 +1000 Subject: [PATCH 3/7] drm/nouveau: add nouveau_enum_find() util function Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_util.c | 23 +++++-- drivers/gpu/drm/nouveau/nouveau_util.h | 4 ++ drivers/gpu/drm/nouveau/nv50_graph.c | 92 +++++++++++++------------- 3 files changed, 66 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_util.c b/drivers/gpu/drm/nouveau/nouveau_util.c index fbe0fb13bc1e..e51b51503baa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_util.c +++ b/drivers/gpu/drm/nouveau/nouveau_util.c @@ -47,16 +47,25 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value) printk(" (unknown bits 0x%08x)", value); } +const struct nouveau_enum * +nouveau_enum_find(const struct nouveau_enum *en, u32 value) +{ + while (en->name) { + if (en->value == value) + return en; + en++; + } + + return NULL; +} + void nouveau_enum_print(const struct nouveau_enum *en, u32 value) { - while (en->name) { - if (value == en->value) { - printk("%s", en->name); - return; - } - - en++; + en = nouveau_enum_find(en, value); + if (en) { + printk("%s", en->name); + return; } printk("(unknown enum 0x%08x)", value); diff --git a/drivers/gpu/drm/nouveau/nouveau_util.h b/drivers/gpu/drm/nouveau/nouveau_util.h index d9ceaea26f4b..b97719fbb739 100644 --- a/drivers/gpu/drm/nouveau/nouveau_util.h +++ b/drivers/gpu/drm/nouveau/nouveau_util.h @@ -36,10 +36,14 @@ struct nouveau_bitfield { struct nouveau_enum { u32 value; const char *name; + void *data; }; void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value); void nouveau_enum_print(const struct nouveau_enum *, u32 value); +const struct nouveau_enum * +nouveau_enum_find(const struct nouveau_enum *, u32 value); + int nouveau_ratelimit(void); #endif diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index e1267a1f6d10..a8be5184477a 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -550,11 +550,11 @@ nv86_graph_tlb_flush(struct drm_device *dev) static struct nouveau_enum nv50_mp_exec_error_names[] = { - { 3, "STACK_UNDERFLOW" }, - { 4, "QUADON_ACTIVE" }, - { 8, "TIMEOUT" }, - { 0x10, "INVALID_OPCODE" }, - { 0x40, "BREAKPOINT" }, + { 3, "STACK_UNDERFLOW", NULL }, + { 4, "QUADON_ACTIVE", NULL }, + { 8, "TIMEOUT", NULL }, + { 0x10, "INVALID_OPCODE", NULL }, + { 0x40, "BREAKPOINT", NULL }, {} }; @@ -582,47 +582,47 @@ static struct nouveau_bitfield nv50_graph_trap_ccache[] = { /* There must be a *lot* of these. Will take some time to gather them up. */ struct nouveau_enum nv50_data_error_names[] = { - { 0x00000003, "INVALID_QUERY_OR_TEXTURE" }, - { 0x00000004, "INVALID_VALUE" }, - { 0x00000005, "INVALID_ENUM" }, - { 0x00000008, "INVALID_OBJECT" }, - { 0x00000009, "READ_ONLY_OBJECT" }, - { 0x0000000a, "SUPERVISOR_OBJECT" }, - { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT" }, - { 0x0000000c, "INVALID_BITFIELD" }, - { 0x0000000d, "BEGIN_END_ACTIVE" }, - { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT" }, - { 0x0000000f, "VIEWPORT_ID_NEEDS_GP" }, - { 0x00000010, "RT_DOUBLE_BIND" }, - { 0x00000011, "RT_TYPES_MISMATCH" }, - { 0x00000012, "RT_LINEAR_WITH_ZETA" }, - { 0x00000015, "FP_TOO_FEW_REGS" }, - { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH" }, - { 0x00000017, "RT_LINEAR_WITH_MSAA" }, - { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT" }, - { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT" }, - { 0x0000001a, "RT_INVALID_ALIGNMENT" }, - { 0x0000001b, "SAMPLER_OVER_LIMIT" }, - { 0x0000001c, "TEXTURE_OVER_LIMIT" }, - { 0x0000001e, "GP_TOO_MANY_OUTPUTS" }, - { 0x0000001f, "RT_BPP128_WITH_MS8" }, - { 0x00000021, "Z_OUT_OF_BOUNDS" }, - { 0x00000023, "XY_OUT_OF_BOUNDS" }, - { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED" }, - { 0x00000028, "CP_NO_REG_SPACE_STRIPED" }, - { 0x00000029, "CP_NO_REG_SPACE_PACKED" }, - { 0x0000002a, "CP_NOT_ENOUGH_WARPS" }, - { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH" }, - { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS" }, - { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS" }, - { 0x0000002e, "CP_NO_BLOCKDIM_LATCH" }, - { 0x00000031, "ENG2D_FORMAT_MISMATCH" }, - { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP" }, - { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT" }, - { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT" }, - { 0x00000046, "LAYER_ID_NEEDS_GP" }, - { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT" }, - { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT" }, + { 0x00000003, "INVALID_QUERY_OR_TEXTURE", NULL }, + { 0x00000004, "INVALID_VALUE", NULL }, + { 0x00000005, "INVALID_ENUM", NULL }, + { 0x00000008, "INVALID_OBJECT", NULL }, + { 0x00000009, "READ_ONLY_OBJECT", NULL }, + { 0x0000000a, "SUPERVISOR_OBJECT", NULL }, + { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL }, + { 0x0000000c, "INVALID_BITFIELD", NULL }, + { 0x0000000d, "BEGIN_END_ACTIVE", NULL }, + { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL }, + { 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL }, + { 0x00000010, "RT_DOUBLE_BIND", NULL }, + { 0x00000011, "RT_TYPES_MISMATCH", NULL }, + { 0x00000012, "RT_LINEAR_WITH_ZETA", NULL }, + { 0x00000015, "FP_TOO_FEW_REGS", NULL }, + { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL }, + { 0x00000017, "RT_LINEAR_WITH_MSAA", NULL }, + { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL }, + { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL }, + { 0x0000001a, "RT_INVALID_ALIGNMENT", NULL }, + { 0x0000001b, "SAMPLER_OVER_LIMIT", NULL }, + { 0x0000001c, "TEXTURE_OVER_LIMIT", NULL }, + { 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL }, + { 0x0000001f, "RT_BPP128_WITH_MS8", NULL }, + { 0x00000021, "Z_OUT_OF_BOUNDS", NULL }, + { 0x00000023, "XY_OUT_OF_BOUNDS", NULL }, + { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL }, + { 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL }, + { 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL }, + { 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL }, + { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL }, + { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL }, + { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL }, + { 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL }, + { 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL }, + { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL }, + { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL }, + { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL }, + { 0x00000046, "LAYER_ID_NEEDS_GP", NULL }, + { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL }, + { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL }, {} }; From 312d1d5fe9b832899b02c620c143bc7eb5a3bdb1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 Mar 2011 09:50:06 +1000 Subject: [PATCH 4/7] drm/nv50: decode vm faults some more Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fb.c | 148 ++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c index ed411d88451d..705f59743db8 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -114,12 +114,109 @@ nv50_fb_takedown(struct drm_device *dev) nv50_fb_destroy(dev); } +static struct nouveau_enum vm_dispatch_subclients[] = { + { 0x00000000, "GRCTX", NULL }, + { 0x00000001, "NOTIFY", NULL }, + { 0x00000002, "QUERY", NULL }, + { 0x00000003, "COND", NULL }, + { 0x00000004, "M2M_IN", NULL }, + { 0x00000005, "M2M_OUT", NULL }, + { 0x00000006, "M2M_NOTIFY", NULL }, + {} +}; + +static struct nouveau_enum vm_ccache_subclients[] = { + { 0x00000000, "CB", NULL }, + { 0x00000001, "TIC", NULL }, + { 0x00000002, "TSC", NULL }, + {} +}; + +static struct nouveau_enum vm_prop_subclients[] = { + { 0x00000000, "RT0", NULL }, + { 0x00000001, "RT1", NULL }, + { 0x00000002, "RT2", NULL }, + { 0x00000003, "RT3", NULL }, + { 0x00000004, "RT4", NULL }, + { 0x00000005, "RT5", NULL }, + { 0x00000006, "RT6", NULL }, + { 0x00000007, "RT7", NULL }, + { 0x00000008, "ZETA", NULL }, + { 0x00000009, "LOCAL", NULL }, + { 0x0000000a, "GLOBAL", NULL }, + { 0x0000000b, "STACK", NULL }, + { 0x0000000c, "DST2D", NULL }, + {} +}; + +static struct nouveau_enum vm_pfifo_subclients[] = { + { 0x00000000, "PUSHBUF", NULL }, + { 0x00000001, "SEMAPHORE", NULL }, + {} +}; + +static struct nouveau_enum vm_bar_subclients[] = { + { 0x00000000, "FB", NULL }, + { 0x00000001, "IN", NULL }, + {} +}; + +static struct nouveau_enum vm_client[] = { + { 0x00000000, "STRMOUT", NULL }, + { 0x00000003, "DISPATCH", vm_dispatch_subclients }, + { 0x00000004, "PFIFO_WRITE", NULL }, + { 0x00000005, "CCACHE", vm_ccache_subclients }, + { 0x00000006, "PPPP", NULL }, + { 0x00000007, "CLIPID", NULL }, + { 0x00000008, "PFIFO_READ", NULL }, + { 0x00000009, "VFETCH", NULL }, + { 0x0000000a, "TEXTURE", NULL }, + { 0x0000000b, "PROP", vm_prop_subclients }, + { 0x0000000c, "PVP", NULL }, + { 0x0000000d, "PBSP", NULL }, + { 0x0000000e, "PCRYPT", NULL }, + { 0x0000000f, "PCOUNTER", NULL }, + { 0x00000011, "PDAEMON", NULL }, + {} +}; + +static struct nouveau_enum vm_engine[] = { + { 0x00000000, "PGRAPH", NULL }, + { 0x00000001, "PVP", NULL }, + { 0x00000004, "PEEPHOLE", NULL }, + { 0x00000005, "PFIFO", vm_pfifo_subclients }, + { 0x00000006, "BAR", vm_bar_subclients }, + { 0x00000008, "PPPP", NULL }, + { 0x00000009, "PBSP", NULL }, + { 0x0000000a, "PCRYPT", NULL }, + { 0x0000000b, "PCOUNTER", NULL }, + { 0x0000000c, "SEMAPHORE_BG", NULL }, + { 0x0000000d, "PCOPY", NULL }, + { 0x0000000e, "PDAEMON", NULL }, + {} +}; + +static struct nouveau_enum vm_fault[] = { + { 0x00000000, "PT_NOT_PRESENT", NULL }, + { 0x00000001, "PT_TOO_SHORT", NULL }, + { 0x00000002, "PAGE_NOT_PRESENT", NULL }, + { 0x00000003, "PAGE_SYSTEM_ONLY", NULL }, + { 0x00000004, "PAGE_READ_ONLY", NULL }, + { 0x00000006, "NULL_DMAOBJ", NULL }, + { 0x00000007, "WRONG_MEMTYPE", NULL }, + { 0x0000000b, "VRAM_LIMIT", NULL }, + { 0x0000000f, "DMAOBJ_LIMIT", NULL }, + {} +}; + void nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) { struct drm_nouveau_private *dev_priv = dev->dev_private; + const struct nouveau_enum *en, *cl; unsigned long flags; u32 trap[6], idx, chinst; + u8 st0, st1, st2, st3; int i, ch; idx = nv_rd32(dev, 0x100c90); @@ -136,8 +233,8 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) if (!display) return; + /* lookup channel id */ chinst = (trap[2] << 16) | trap[1]; - spin_lock_irqsave(&dev_priv->channels.lock, flags); for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { struct nouveau_channel *chan = dev_priv->channels.ptr[ch]; @@ -150,9 +247,48 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) } spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x " - "channel %d (0x%08x)\n", - name, (trap[5] & 0x100 ? "read" : "write"), - trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, - trap[0], ch, chinst); + /* decode status bits into something more useful */ + if (dev_priv->chipset < 0xa3 || + dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) { + st0 = (trap[0] & 0x0000000f) >> 0; + st1 = (trap[0] & 0x000000f0) >> 4; + st2 = (trap[0] & 0x00000f00) >> 8; + st3 = (trap[0] & 0x0000f000) >> 12; + } else { + st0 = (trap[0] & 0x000000ff) >> 0; + st1 = (trap[0] & 0x0000ff00) >> 8; + st2 = (trap[0] & 0x00ff0000) >> 16; + st3 = (trap[0] & 0xff000000) >> 24; + } + + NV_INFO(dev, "VM: trapped %s at 0x%02x%04x%04x on ch %d [0x%08x] ", + (trap[5] & 0x00000100) ? "read" : "write", + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, ch, chinst); + + en = nouveau_enum_find(vm_engine, st0); + if (en) + printk("%s/", en->name); + else + printk("%02x/", st0); + + cl = nouveau_enum_find(vm_client, st2); + if (cl) + printk("%s/", cl->name); + else + printk("%02x/", st2); + + if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3); + else if (en && en->data) cl = nouveau_enum_find(en->data, st3); + else cl = NULL; + if (cl) + printk("%s", cl->name); + else + printk("%02x", st3); + + printk(" reason: "); + en = nouveau_enum_find(vm_fault, st1); + if (en) + printk("%s\n", en->name); + else + printk("0x%08x\n", st1); } From 6fdb383e81a644a244299d635de5eb30ed401278 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 Mar 2011 09:57:17 +1000 Subject: [PATCH 5/7] drm/nv50: check for vm traps on every gr irq Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 +- drivers/gpu/drm/nouveau/nv04_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv50_fb.c | 2 +- drivers/gpu/drm/nouveau/nv50_graph.c | 3 +-- drivers/gpu/drm/nouveau/nv84_crypt.c | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 00aff226397d..8efefed58c15 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1076,7 +1076,7 @@ extern void nv40_fb_set_tile_region(struct drm_device *dev, int i); /* nv50_fb.c */ extern int nv50_fb_init(struct drm_device *); extern void nv50_fb_takedown(struct drm_device *); -extern void nv50_fb_vm_trap(struct drm_device *, int display, const char *); +extern void nv50_fb_vm_trap(struct drm_device *, int display); /* nvc0_fb.c */ extern int nvc0_fb_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index dfa600c46186..db465a3ee1b2 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -516,7 +516,7 @@ nv04_fifo_isr(struct drm_device *dev) if (dev_priv->card_type == NV_50) { if (status & 0x00000010) { - nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); + nv50_fb_vm_trap(dev, nouveau_ratelimit()); status &= ~0x00000010; nv_wr32(dev, 0x002100, 0x00000010); } diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c index 705f59743db8..bdd2afe29205 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -210,7 +210,7 @@ static struct nouveau_enum vm_fault[] = { }; void -nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) +nv50_fb_vm_trap(struct drm_device *dev, int display) { struct drm_nouveau_private *dev_priv = dev->dev_private; const struct nouveau_enum *en, *cl; diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index a8be5184477a..8675b00caf18 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -702,7 +702,6 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, tps++; switch (type) { case 6: /* texture error... unknown for now */ - nv50_fb_vm_trap(dev, display, name); if (display) { NV_ERROR(dev, "magic set %d:\n", i); for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) @@ -725,7 +724,6 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); - nv50_fb_vm_trap(dev, display, name); /* 2d engine destination */ if (ustatus & 0x00000010) { if (display) { @@ -1068,6 +1066,7 @@ nv50_graph_isr(struct drm_device *dev) NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d " "class 0x%04x mthd 0x%04x data 0x%08x\n", chid, inst, subc, class, mthd, data); + nv50_fb_vm_trap(dev, 1); } } diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c index ec18ae1c3886..fabc7fd30b1d 100644 --- a/drivers/gpu/drm/nouveau/nv84_crypt.c +++ b/drivers/gpu/drm/nouveau/nv84_crypt.c @@ -136,5 +136,5 @@ nv84_crypt_isr(struct drm_device *dev) nv_wr32(dev, 0x102130, stat); nv_wr32(dev, 0x10200c, 0x10); - nv50_fb_vm_trap(dev, show, "PCRYPT"); + nv50_fb_vm_trap(dev, show); } From 459ca7e5283914845d7139905ff58824d2b0cc85 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 Mar 2011 14:47:53 +1000 Subject: [PATCH 6/7] drm/nv40: attempt to reserve just enough vram for all 32 channels This also makes the fact we're giving 512MiB of GART space to all PCIE boards explicit, although the vast majority (if not all) of them will now have a ramin_rsvd_vram larger than 2MiB anyway. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 34 +++++++++++++++++++------ drivers/gpu/drm/nouveau/nouveau_sgdma.c | 3 +-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 63b9040b5f30..02b48d183f4a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -424,14 +424,32 @@ nouveau_mem_vram_init(struct drm_device *dev) } /* reserve space at end of VRAM for PRAMIN */ - if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 || - dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) - dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024); - else - if (dev_priv->card_type >= NV_40) - dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024); - else - dev_priv->ramin_rsvd_vram = (512 * 1024); + if (dev_priv->card_type >= NV_50) { + dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; + } else + if (dev_priv->card_type >= NV_40) { + u32 vs = hweight8((nv_rd32(dev, 0x001540) & 0x0000ff00) >> 8); + u32 rsvd; + + /* estimate grctx size, the magics come from nv40_grctx.c */ + if (dev_priv->chipset == 0x40) rsvd = 0x6aa0 * vs; + else if (dev_priv->chipset < 0x43) rsvd = 0x4f00 * vs; + else if (nv44_graph_class(dev)) rsvd = 0x4980 * vs; + else rsvd = 0x4a40 * vs; + rsvd += 16 * 1024; + rsvd *= dev_priv->engine.fifo.channels; + + /* pciegart table */ + if (drm_pci_device_is_pcie(dev)) + rsvd += 512 * 1024; + + /* object storage */ + rsvd += 512 * 1024; + + dev_priv->ramin_rsvd_vram = round_up(rsvd, 4096); + } else { + dev_priv->ramin_rsvd_vram = 512 * 1024; + } ret = dev_priv->engine.vram.init(dev); if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 1205f0f345b9..a33fe4019286 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -427,8 +427,7 @@ nouveau_sgdma_init(struct drm_device *dev) u32 aper_size, align; int ret; - if (dev_priv->card_type >= NV_50 || - dev_priv->ramin_rsvd_vram >= 2 * 1024 * 1024) + if (dev_priv->card_type >= NV_50 || drm_pci_device_is_pcie(dev)) aper_size = 512 * 1024 * 1024; else aper_size = 64 * 1024 * 1024; From bd35fe5a7930bf83ed56422ea4e4b6471ee6f739 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 9 Mar 2011 14:22:19 +0100 Subject: [PATCH 7/7] drm/nouveau: fix __nouveau_fence_wait performance Commit 21e86c1c8a844bf978f8fc431a59c9f5a578812d ("drm/nouveau: remove cpu_writers lock") turned on lazy waits. Unfortunately __nouveau_fence_wait was not optimized for this case and on HZ=100 kernel wasted up to 10 ms per call. Depending on application, it led to 10-30% FPS regression. Fix it. Signed-off-by: Marcin Slusarz Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_fence.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index a244702bb227..4b9f4493c9f9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -27,6 +27,9 @@ #include "drmP.h" #include "drm.h" +#include +#include + #include "nouveau_drv.h" #include "nouveau_ramht.h" #include "nouveau_dma.h" @@ -229,7 +232,8 @@ int __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) { unsigned long timeout = jiffies + (3 * DRM_HZ); - unsigned long sleep_time = jiffies + 1; + unsigned long sleep_time = NSEC_PER_MSEC / 1000; + ktime_t t; int ret = 0; while (1) { @@ -243,8 +247,13 @@ __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) __set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (lazy && time_after_eq(jiffies, sleep_time)) - schedule_timeout(1); + if (lazy) { + t = ktime_set(0, sleep_time); + schedule_hrtimeout(&t, HRTIMER_MODE_REL); + sleep_time *= 2; + if (sleep_time > NSEC_PER_MSEC) + sleep_time = NSEC_PER_MSEC; + } if (intr && signal_pending(current)) { ret = -ERESTARTSYS;