From c5e624f8437331e1d985b4bb5efe3c4229569550 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 3 May 2013 06:40:37 +1000 Subject: [PATCH 01/10] drm/nouveau: fix build with nv50->nvc0 Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/core/engine/device/nve0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c index 08f7b52d9e0c..a354e409cdff 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c @@ -149,7 +149,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; From 46b47b8a7d9223b12ddcabf1f3fc6e753e2d84a1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 7 May 2013 15:54:13 +1000 Subject: [PATCH 02/10] drm/nouveau/bios: fix thinko in ZM_MASK_ADD opcode Cc: stable@vger.kernel.org Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/subdev/bios/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index c300b5e7b670..c434d398d16f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -1940,8 +1940,8 @@ init_zm_mask_add(struct nvbios_init *init) trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add); init->offset += 13; - data = init_rd32(init, addr) & mask; - data |= ((data + add) & ~mask); + data = init_rd32(init, addr); + data = (data & mask) | ((data + add) & ~mask); init_wr32(init, addr, data); } From 6d5f83834dc2b064b8c1202ea281820286b675a8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 13 May 2013 16:11:12 +1000 Subject: [PATCH 03/10] drm/nvc0/ce: disable ce1 on a number of chipsets The falcon is present, but the rest of the copy engine doesn't appear to be... PUNITS doesn't report disabled (maybe the bits for the copy engines got added later?), so we end up trying to use a non-functional CE1, and bust all sorts of things.. Most notably, suspend/resume.. Cc: stable@vger.kernel.org Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/device/nvc0.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index 955af122c3a6..a36e64e98ef3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -138,7 +138,6 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; break; case 0xce: @@ -225,7 +224,6 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; break; case 0xc8: From 49debbe4540efd08b4e9a1c499dce392a43bf1ed Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 14 May 2013 11:37:18 +1000 Subject: [PATCH 04/10] drm/nvc0/ltcg: fix handling of disabled partitions Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c index e4940fb166e8..7c6194f2e074 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c @@ -29,7 +29,6 @@ struct nvc0_ltcg_priv { struct nouveau_ltcg base; u32 part_nr; - u32 part_mask; u32 subp_nr; struct nouveau_mm tags; u32 num_tags; @@ -105,8 +104,6 @@ nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) /* wait until it's finished with clearing */ for (p = 0; p < priv->part_nr; ++p) { - if (!(priv->part_mask & (1 << p))) - continue; for (i = 0; i < priv->subp_nr; ++i) nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0); } @@ -167,16 +164,20 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, { struct nvc0_ltcg_priv *priv; struct nouveau_fb *pfb = nouveau_fb(parent); - int ret; + u32 parts, mask; + int ret, i; ret = nouveau_ltcg_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->part_nr = nv_rd32(priv, 0x022438); - priv->part_mask = nv_rd32(priv, 0x022554); - + parts = nv_rd32(priv, 0x022438); + mask = nv_rd32(priv, 0x022554); + for (i = 0; i < parts; i++) { + if (!(mask & (1 << i))) + priv->part_nr++; + } priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ From fe6fc096b82eb0e84a0609f6431f7069f6c6c347 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 14 May 2013 12:03:33 +1000 Subject: [PATCH 05/10] drm/nve0/ltcg: poke the partition count into yet another register Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c index 7c6194f2e074..fb794e997fbc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c @@ -118,6 +118,8 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) int ret; nv_wr32(priv, 0x17e8d8, priv->part_nr); + if (nv_device(pfb)->card_type >= NV_E0) + nv_wr32(priv, 0x17e000, priv->part_nr); /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ priv->num_tags = (pfb->ram.size >> 17) / 4; From c2e3259b7b6c89686892e4fbcc56dbcab14f1acf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 May 2013 13:54:50 +1000 Subject: [PATCH 06/10] drm/nve0/fifo: prevent races between clients updating playlists Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 9151919fb831..56192a7242ae 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -94,11 +94,13 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine) u32 match = (engine << 16) | 0x00000001; int i, p; + mutex_lock(&nv_subdev(priv)->mutex); cur = engn->playlist[engn->cur_playlist]; if (unlikely(cur == NULL)) { int ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, 0, &cur); if (ret) { + mutex_unlock(&nv_subdev(priv)->mutex); nv_error(priv, "playlist alloc failed\n"); return; } @@ -122,6 +124,7 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine) nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) nv_error(priv, "playlist %d update timeout\n", engine); + mutex_unlock(&nv_subdev(priv)->mutex); } static int From fadb171902df5c6ba38029a9306c2b0d559987b9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 13 May 2013 10:02:11 +1000 Subject: [PATCH 07/10] drm/nvc0/fifo: prevent races between clients updating playlists Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index 4d4a6b905370..1613193e21e6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -71,6 +71,7 @@ nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) struct nouveau_gpuobj *cur; int i, p; + mutex_lock(&nv_subdev(priv)->mutex); cur = priv->playlist[priv->cur_playlist]; priv->cur_playlist = !priv->cur_playlist; @@ -87,6 +88,7 @@ nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000)) nv_error(priv, "playlist update failed\n"); + mutex_unlock(&nv_subdev(priv)->mutex); } static int From 9426eedb26cfe646a843295ac7f91bf866323f92 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 13 May 2013 11:09:59 +1000 Subject: [PATCH 08/10] drm/nvc0/fifo: prevent CHAN_TABLE_ERROR:CHANNEL_PENDING on fifo fini Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index 1613193e21e6..46dfa68c47bb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -250,9 +250,17 @@ nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend) struct nvc0_fifo_priv *priv = (void *)object->engine; struct nvc0_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; + u32 mask, engine; nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); nvc0_fifo_playlist_update(priv); + mask = nv_rd32(priv, 0x0025a4); + for (engine = 0; mask && engine < 16; engine++) { + if (!(mask & (1 << engine))) + continue; + nv_mask(priv, 0x0025a8 + (engine * 4), 0x00000000, 0x00000000); + mask &= ~(1 << engine); + } nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); return nouveau_fifo_channel_fini(&chan->base, suspend); From b5096566f6e1ee2b88324772f020ae9bc0cfa9a0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 14 May 2013 13:33:56 +1000 Subject: [PATCH 09/10] drm/nv50/fifo: prevent races between clients updating playlists Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c index ddaeb5572903..89bf459d584b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c @@ -47,6 +47,7 @@ nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) struct nouveau_gpuobj *cur; int i, p; + mutex_lock(&nv_subdev(priv)->mutex); cur = priv->playlist[priv->cur_playlist]; priv->cur_playlist = !priv->cur_playlist; @@ -60,6 +61,7 @@ nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) nv_wr32(priv, 0x0032f4, cur->addr >> 12); nv_wr32(priv, 0x0032ec, p); nv_wr32(priv, 0x002500, 0x00000101); + mutex_unlock(&nv_subdev(priv)->mutex); } static int From 81dff21b643f48c14010a97ffc799e1920d751e5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 7 May 2013 08:33:10 +1000 Subject: [PATCH 10/10] drm/nouveau: ensure channels are stopped before saving fences for suspend Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 46c152ff0a80..383f4e6ea9d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -453,18 +453,32 @@ nouveau_do_suspend(struct drm_device *dev) NV_INFO(drm, "evicting buffers...\n"); ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); + NV_INFO(drm, "waiting for kernel channels to go idle...\n"); + if (drm->cechan) { + ret = nouveau_channel_idle(drm->cechan); + if (ret) + return ret; + } + + if (drm->channel) { + ret = nouveau_channel_idle(drm->channel); + if (ret) + return ret; + } + + NV_INFO(drm, "suspending client object trees...\n"); if (drm->fence && nouveau_fence(drm)->suspend) { if (!nouveau_fence(drm)->suspend(drm)) return -ENOMEM; } - NV_INFO(drm, "suspending client object trees...\n"); list_for_each_entry(cli, &drm->clients, head) { ret = nouveau_client_fini(&cli->base, true); if (ret) goto fail_client; } + NV_INFO(drm, "suspending kernel object tree...\n"); ret = nouveau_client_fini(&drm->client.base, true); if (ret) goto fail_client; @@ -514,17 +528,18 @@ nouveau_do_resume(struct drm_device *dev) nouveau_agp_reset(drm); - NV_INFO(drm, "resuming client object trees...\n"); + NV_INFO(drm, "resuming kernel object tree...\n"); nouveau_client_init(&drm->client.base); nouveau_agp_init(drm); + NV_INFO(drm, "resuming client object trees...\n"); + if (drm->fence && nouveau_fence(drm)->resume) + nouveau_fence(drm)->resume(drm); + list_for_each_entry(cli, &drm->clients, head) { nouveau_client_init(&cli->base); } - if (drm->fence && nouveau_fence(drm)->resume) - nouveau_fence(drm)->resume(drm); - nouveau_run_vbios_init(dev); nouveau_pm_resume(dev);