diff options
author | Dave Airlie <airlied@redhat.com> | 2013-05-19 23:31:36 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-05-19 23:31:36 -0400 |
commit | b7cb1c50c828adaee95e8ada0e55918686245992 (patch) | |
tree | 88694170f862f156e6f4a38b8fa207dba9200d45 | |
parent | e9ced8e040ebe40e9953db90acbe7d0b58702ebb (diff) | |
parent | 81dff21b643f48c14010a97ffc799e1920d751e5 (diff) |
Merge branch 'drm-nouveau-fixes-3.10' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
Fixes some s/r problem with copy engines and ZCULL issues and playlist issues
* 'drm-nouveau-fixes-3.10' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
drm/nouveau: ensure channels are stopped before saving fences for suspend
drm/nv50/fifo: prevent races between clients updating playlists
drm/nvc0/fifo: prevent CHAN_TABLE_ERROR:CHANNEL_PENDING on fifo fini
drm/nvc0/fifo: prevent races between clients updating playlists
drm/nve0/fifo: prevent races between clients updating playlists
drm/nve0/ltcg: poke the partition count into yet another register
drm/nvc0/ltcg: fix handling of disabled partitions
drm/nvc0/ce: disable ce1 on a number of chipsets
drm/nouveau/bios: fix thinko in ZM_MASK_ADD opcode
drm/nouveau: fix build with nv50->nvc0
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/device/nvc0.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/bios/init.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 25 |
7 files changed, 47 insertions, 16 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) | |||
138 | device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; | 138 | device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; |
139 | device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; | 139 | device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; |
140 | device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; | 140 | device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; |
141 | device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; | ||
142 | device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; | 141 | device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; |
143 | break; | 142 | break; |
144 | case 0xce: | 143 | case 0xce: |
@@ -225,7 +224,6 @@ nvc0_identify(struct nouveau_device *device) | |||
225 | device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; | 224 | device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; |
226 | device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; | 225 | device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; |
227 | device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; | 226 | device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; |
228 | device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; | ||
229 | device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; | 227 | device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; |
230 | break; | 228 | break; |
231 | case 0xc8: | 229 | case 0xc8: |
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) | |||
47 | struct nouveau_gpuobj *cur; | 47 | struct nouveau_gpuobj *cur; |
48 | int i, p; | 48 | int i, p; |
49 | 49 | ||
50 | mutex_lock(&nv_subdev(priv)->mutex); | ||
50 | cur = priv->playlist[priv->cur_playlist]; | 51 | cur = priv->playlist[priv->cur_playlist]; |
51 | priv->cur_playlist = !priv->cur_playlist; | 52 | priv->cur_playlist = !priv->cur_playlist; |
52 | 53 | ||
@@ -60,6 +61,7 @@ nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) | |||
60 | nv_wr32(priv, 0x0032f4, cur->addr >> 12); | 61 | nv_wr32(priv, 0x0032f4, cur->addr >> 12); |
61 | nv_wr32(priv, 0x0032ec, p); | 62 | nv_wr32(priv, 0x0032ec, p); |
62 | nv_wr32(priv, 0x002500, 0x00000101); | 63 | nv_wr32(priv, 0x002500, 0x00000101); |
64 | mutex_unlock(&nv_subdev(priv)->mutex); | ||
63 | } | 65 | } |
64 | 66 | ||
65 | static int | 67 | static int |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index 4d4a6b905370..46dfa68c47bb 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) | |||
71 | struct nouveau_gpuobj *cur; | 71 | struct nouveau_gpuobj *cur; |
72 | int i, p; | 72 | int i, p; |
73 | 73 | ||
74 | mutex_lock(&nv_subdev(priv)->mutex); | ||
74 | cur = priv->playlist[priv->cur_playlist]; | 75 | cur = priv->playlist[priv->cur_playlist]; |
75 | priv->cur_playlist = !priv->cur_playlist; | 76 | priv->cur_playlist = !priv->cur_playlist; |
76 | 77 | ||
@@ -87,6 +88,7 @@ nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) | |||
87 | nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); | 88 | nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); |
88 | if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000)) | 89 | if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000)) |
89 | nv_error(priv, "playlist update failed\n"); | 90 | nv_error(priv, "playlist update failed\n"); |
91 | mutex_unlock(&nv_subdev(priv)->mutex); | ||
90 | } | 92 | } |
91 | 93 | ||
92 | static int | 94 | static int |
@@ -248,9 +250,17 @@ nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend) | |||
248 | struct nvc0_fifo_priv *priv = (void *)object->engine; | 250 | struct nvc0_fifo_priv *priv = (void *)object->engine; |
249 | struct nvc0_fifo_chan *chan = (void *)object; | 251 | struct nvc0_fifo_chan *chan = (void *)object; |
250 | u32 chid = chan->base.chid; | 252 | u32 chid = chan->base.chid; |
253 | u32 mask, engine; | ||
251 | 254 | ||
252 | nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); | 255 | nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); |
253 | nvc0_fifo_playlist_update(priv); | 256 | nvc0_fifo_playlist_update(priv); |
257 | mask = nv_rd32(priv, 0x0025a4); | ||
258 | for (engine = 0; mask && engine < 16; engine++) { | ||
259 | if (!(mask & (1 << engine))) | ||
260 | continue; | ||
261 | nv_mask(priv, 0x0025a8 + (engine * 4), 0x00000000, 0x00000000); | ||
262 | mask &= ~(1 << engine); | ||
263 | } | ||
254 | nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); | 264 | nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); |
255 | 265 | ||
256 | return nouveau_fifo_channel_fini(&chan->base, suspend); | 266 | return nouveau_fifo_channel_fini(&chan->base, suspend); |
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) | |||
94 | u32 match = (engine << 16) | 0x00000001; | 94 | u32 match = (engine << 16) | 0x00000001; |
95 | int i, p; | 95 | int i, p; |
96 | 96 | ||
97 | mutex_lock(&nv_subdev(priv)->mutex); | ||
97 | cur = engn->playlist[engn->cur_playlist]; | 98 | cur = engn->playlist[engn->cur_playlist]; |
98 | if (unlikely(cur == NULL)) { | 99 | if (unlikely(cur == NULL)) { |
99 | int ret = nouveau_gpuobj_new(nv_object(priv), NULL, | 100 | int ret = nouveau_gpuobj_new(nv_object(priv), NULL, |
100 | 0x8000, 0x1000, 0, &cur); | 101 | 0x8000, 0x1000, 0, &cur); |
101 | if (ret) { | 102 | if (ret) { |
103 | mutex_unlock(&nv_subdev(priv)->mutex); | ||
102 | nv_error(priv, "playlist alloc failed\n"); | 104 | nv_error(priv, "playlist alloc failed\n"); |
103 | return; | 105 | return; |
104 | } | 106 | } |
@@ -122,6 +124,7 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine) | |||
122 | nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); | 124 | nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); |
123 | if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) | 125 | if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) |
124 | nv_error(priv, "playlist %d update timeout\n", engine); | 126 | nv_error(priv, "playlist %d update timeout\n", engine); |
127 | mutex_unlock(&nv_subdev(priv)->mutex); | ||
125 | } | 128 | } |
126 | 129 | ||
127 | static int | 130 | static int |
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) | |||
1940 | trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add); | 1940 | trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add); |
1941 | init->offset += 13; | 1941 | init->offset += 13; |
1942 | 1942 | ||
1943 | data = init_rd32(init, addr) & mask; | 1943 | data = init_rd32(init, addr); |
1944 | data |= ((data + add) & ~mask); | 1944 | data = (data & mask) | ((data + add) & ~mask); |
1945 | init_wr32(init, addr, data); | 1945 | init_wr32(init, addr, data); |
1946 | } | 1946 | } |
1947 | 1947 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c index e4940fb166e8..fb794e997fbc 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 @@ | |||
29 | struct nvc0_ltcg_priv { | 29 | struct nvc0_ltcg_priv { |
30 | struct nouveau_ltcg base; | 30 | struct nouveau_ltcg base; |
31 | u32 part_nr; | 31 | u32 part_nr; |
32 | u32 part_mask; | ||
33 | u32 subp_nr; | 32 | u32 subp_nr; |
34 | struct nouveau_mm tags; | 33 | struct nouveau_mm tags; |
35 | u32 num_tags; | 34 | u32 num_tags; |
@@ -105,8 +104,6 @@ nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) | |||
105 | 104 | ||
106 | /* wait until it's finished with clearing */ | 105 | /* wait until it's finished with clearing */ |
107 | for (p = 0; p < priv->part_nr; ++p) { | 106 | for (p = 0; p < priv->part_nr; ++p) { |
108 | if (!(priv->part_mask & (1 << p))) | ||
109 | continue; | ||
110 | for (i = 0; i < priv->subp_nr; ++i) | 107 | for (i = 0; i < priv->subp_nr; ++i) |
111 | nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0); | 108 | nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0); |
112 | } | 109 | } |
@@ -121,6 +118,8 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) | |||
121 | int ret; | 118 | int ret; |
122 | 119 | ||
123 | nv_wr32(priv, 0x17e8d8, priv->part_nr); | 120 | nv_wr32(priv, 0x17e8d8, priv->part_nr); |
121 | if (nv_device(pfb)->card_type >= NV_E0) | ||
122 | nv_wr32(priv, 0x17e000, priv->part_nr); | ||
124 | 123 | ||
125 | /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ | 124 | /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ |
126 | priv->num_tags = (pfb->ram.size >> 17) / 4; | 125 | priv->num_tags = (pfb->ram.size >> 17) / 4; |
@@ -167,16 +166,20 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
167 | { | 166 | { |
168 | struct nvc0_ltcg_priv *priv; | 167 | struct nvc0_ltcg_priv *priv; |
169 | struct nouveau_fb *pfb = nouveau_fb(parent); | 168 | struct nouveau_fb *pfb = nouveau_fb(parent); |
170 | int ret; | 169 | u32 parts, mask; |
170 | int ret, i; | ||
171 | 171 | ||
172 | ret = nouveau_ltcg_create(parent, engine, oclass, &priv); | 172 | ret = nouveau_ltcg_create(parent, engine, oclass, &priv); |
173 | *pobject = nv_object(priv); | 173 | *pobject = nv_object(priv); |
174 | if (ret) | 174 | if (ret) |
175 | return ret; | 175 | return ret; |
176 | 176 | ||
177 | priv->part_nr = nv_rd32(priv, 0x022438); | 177 | parts = nv_rd32(priv, 0x022438); |
178 | priv->part_mask = nv_rd32(priv, 0x022554); | 178 | mask = nv_rd32(priv, 0x022554); |
179 | 179 | for (i = 0; i < parts; i++) { | |
180 | if (!(mask & (1 << i))) | ||
181 | priv->part_nr++; | ||
182 | } | ||
180 | priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; | 183 | priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; |
181 | 184 | ||
182 | nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ | 185 | nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ |
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) | |||
453 | NV_INFO(drm, "evicting buffers...\n"); | 453 | NV_INFO(drm, "evicting buffers...\n"); |
454 | ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); | 454 | ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); |
455 | 455 | ||
456 | NV_INFO(drm, "waiting for kernel channels to go idle...\n"); | ||
457 | if (drm->cechan) { | ||
458 | ret = nouveau_channel_idle(drm->cechan); | ||
459 | if (ret) | ||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | if (drm->channel) { | ||
464 | ret = nouveau_channel_idle(drm->channel); | ||
465 | if (ret) | ||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | NV_INFO(drm, "suspending client object trees...\n"); | ||
456 | if (drm->fence && nouveau_fence(drm)->suspend) { | 470 | if (drm->fence && nouveau_fence(drm)->suspend) { |
457 | if (!nouveau_fence(drm)->suspend(drm)) | 471 | if (!nouveau_fence(drm)->suspend(drm)) |
458 | return -ENOMEM; | 472 | return -ENOMEM; |
459 | } | 473 | } |
460 | 474 | ||
461 | NV_INFO(drm, "suspending client object trees...\n"); | ||
462 | list_for_each_entry(cli, &drm->clients, head) { | 475 | list_for_each_entry(cli, &drm->clients, head) { |
463 | ret = nouveau_client_fini(&cli->base, true); | 476 | ret = nouveau_client_fini(&cli->base, true); |
464 | if (ret) | 477 | if (ret) |
465 | goto fail_client; | 478 | goto fail_client; |
466 | } | 479 | } |
467 | 480 | ||
481 | NV_INFO(drm, "suspending kernel object tree...\n"); | ||
468 | ret = nouveau_client_fini(&drm->client.base, true); | 482 | ret = nouveau_client_fini(&drm->client.base, true); |
469 | if (ret) | 483 | if (ret) |
470 | goto fail_client; | 484 | goto fail_client; |
@@ -514,17 +528,18 @@ nouveau_do_resume(struct drm_device *dev) | |||
514 | 528 | ||
515 | nouveau_agp_reset(drm); | 529 | nouveau_agp_reset(drm); |
516 | 530 | ||
517 | NV_INFO(drm, "resuming client object trees...\n"); | 531 | NV_INFO(drm, "resuming kernel object tree...\n"); |
518 | nouveau_client_init(&drm->client.base); | 532 | nouveau_client_init(&drm->client.base); |
519 | nouveau_agp_init(drm); | 533 | nouveau_agp_init(drm); |
520 | 534 | ||
535 | NV_INFO(drm, "resuming client object trees...\n"); | ||
536 | if (drm->fence && nouveau_fence(drm)->resume) | ||
537 | nouveau_fence(drm)->resume(drm); | ||
538 | |||
521 | list_for_each_entry(cli, &drm->clients, head) { | 539 | list_for_each_entry(cli, &drm->clients, head) { |
522 | nouveau_client_init(&cli->base); | 540 | nouveau_client_init(&cli->base); |
523 | } | 541 | } |
524 | 542 | ||
525 | if (drm->fence && nouveau_fence(drm)->resume) | ||
526 | nouveau_fence(drm)->resume(drm); | ||
527 | |||
528 | nouveau_run_vbios_init(dev); | 543 | nouveau_run_vbios_init(dev); |
529 | nouveau_pm_resume(dev); | 544 | nouveau_pm_resume(dev); |
530 | 545 | ||