aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2011-07-25 05:15:18 -0400
committerDave Airlie <airlied@redhat.com>2011-07-25 05:15:18 -0400
commit603f2e6d378948bf5e5ac04d98673761362a3b79 (patch)
treef511db8fe180b36e451ca6689c52ef5085612806 /drivers/gpu
parente55b9422e186d208f162f056ee28b6eb6b9b81a9 (diff)
parent9962cc6eba013607d6199b723afca23301df7b47 (diff)
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-core-next
* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: drm/nouveau/gr: disable fifo access and idle before suspend ctx unload drm/nouveau: pass flag to engine fini() method on suspend drm/nouveau: replace nv04_graph_fifo_access() use with direct reg bashing drm/nv40/gr: rewrite/split context takedown functions drm/nouveau: detect disabled device in irq handler and return IRQ_NONE drm/nouveau: ignore connector type when deciding digital/analog on DVI-I drm/nouveau: Add a quirk for Gigabyte NX86T drm/nouveau: do not leak in nv20_graph_create drm/nv50/dp: fix hack to work for macbooks booted via EFI
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c34
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c22
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c13
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c112
-rw-r--r--drivers/gpu/drm/nouveau/nv40_mpeg.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c9
-rw-r--r--drivers/gpu/drm/nouveau/nv50_mpeg.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv84_crypt.c2
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_copy.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c2
18 files changed, 98 insertions, 147 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 1aa73d3957e1..b311faba34f8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -5966,6 +5966,12 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx)
5966 if (cte->type == DCB_CONNECTOR_HDMI_1) 5966 if (cte->type == DCB_CONNECTOR_HDMI_1)
5967 cte->type = DCB_CONNECTOR_DVI_I; 5967 cte->type = DCB_CONNECTOR_DVI_I;
5968 } 5968 }
5969
5970 /* Gigabyte GV-NX86T512H */
5971 if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
5972 if (cte->type == DCB_CONNECTOR_HDMI_1)
5973 cte->type = DCB_CONNECTOR_DVI_I;
5974 }
5969} 5975}
5970 5976
5971static const u8 hpd_gpio[16] = { 5977static const u8 hpd_gpio[16] = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 1595d0b6e815..939d4df07777 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -40,7 +40,7 @@
40static void nouveau_connector_hotplug(void *, int); 40static void nouveau_connector_hotplug(void *, int);
41 41
42static struct nouveau_encoder * 42static struct nouveau_encoder *
43find_encoder_by_type(struct drm_connector *connector, int type) 43find_encoder(struct drm_connector *connector, int type)
44{ 44{
45 struct drm_device *dev = connector->dev; 45 struct drm_device *dev = connector->dev;
46 struct nouveau_encoder *nv_encoder; 46 struct nouveau_encoder *nv_encoder;
@@ -170,8 +170,8 @@ nouveau_connector_of_detect(struct drm_connector *connector)
170 struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev); 170 struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
171 171
172 if (!dn || 172 if (!dn ||
173 !((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) || 173 !((nv_encoder = find_encoder(connector, OUTPUT_TMDS)) ||
174 (nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG)))) 174 (nv_encoder = find_encoder(connector, OUTPUT_ANALOG))))
175 return NULL; 175 return NULL;
176 176
177 for_each_child_of_node(dn, cn) { 177 for_each_child_of_node(dn, cn) {
@@ -233,6 +233,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
233 struct drm_device *dev = connector->dev; 233 struct drm_device *dev = connector->dev;
234 struct nouveau_connector *nv_connector = nouveau_connector(connector); 234 struct nouveau_connector *nv_connector = nouveau_connector(connector);
235 struct nouveau_encoder *nv_encoder = NULL; 235 struct nouveau_encoder *nv_encoder = NULL;
236 struct nouveau_encoder *nv_partner;
236 struct nouveau_i2c_chan *i2c; 237 struct nouveau_i2c_chan *i2c;
237 int type; 238 int type;
238 239
@@ -266,19 +267,22 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
266 * same i2c channel so the value returned from ddc_detect 267 * same i2c channel so the value returned from ddc_detect
267 * isn't necessarily correct. 268 * isn't necessarily correct.
268 */ 269 */
269 if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) { 270 nv_partner = NULL;
271 if (nv_encoder->dcb->type == OUTPUT_TMDS)
272 nv_partner = find_encoder(connector, OUTPUT_ANALOG);
273 if (nv_encoder->dcb->type == OUTPUT_ANALOG)
274 nv_partner = find_encoder(connector, OUTPUT_TMDS);
275
276 if (nv_partner && ((nv_encoder->dcb->type == OUTPUT_ANALOG &&
277 nv_partner->dcb->type == OUTPUT_TMDS) ||
278 (nv_encoder->dcb->type == OUTPUT_TMDS &&
279 nv_partner->dcb->type == OUTPUT_ANALOG))) {
270 if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL) 280 if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
271 type = OUTPUT_TMDS; 281 type = OUTPUT_TMDS;
272 else 282 else
273 type = OUTPUT_ANALOG; 283 type = OUTPUT_ANALOG;
274 284
275 nv_encoder = find_encoder_by_type(connector, type); 285 nv_encoder = find_encoder(connector, type);
276 if (!nv_encoder) {
277 NV_ERROR(dev, "Detected %d encoder on %s, "
278 "but no object!\n", type,
279 drm_get_connector_name(connector));
280 return connector_status_disconnected;
281 }
282 } 286 }
283 287
284 nouveau_connector_set_encoder(connector, nv_encoder); 288 nouveau_connector_set_encoder(connector, nv_encoder);
@@ -292,9 +296,9 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
292 } 296 }
293 297
294detect_analog: 298detect_analog:
295 nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); 299 nv_encoder = find_encoder(connector, OUTPUT_ANALOG);
296 if (!nv_encoder && !nouveau_tv_disable) 300 if (!nv_encoder && !nouveau_tv_disable)
297 nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); 301 nv_encoder = find_encoder(connector, OUTPUT_TV);
298 if (nv_encoder && force) { 302 if (nv_encoder && force) {
299 struct drm_encoder *encoder = to_drm_encoder(nv_encoder); 303 struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
300 struct drm_encoder_helper_funcs *helper = 304 struct drm_encoder_helper_funcs *helper =
@@ -327,7 +331,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
327 nv_connector->edid = NULL; 331 nv_connector->edid = NULL;
328 } 332 }
329 333
330 nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); 334 nv_encoder = find_encoder(connector, OUTPUT_LVDS);
331 if (!nv_encoder) 335 if (!nv_encoder)
332 return connector_status_disconnected; 336 return connector_status_disconnected;
333 337
@@ -405,7 +409,7 @@ nouveau_connector_force(struct drm_connector *connector)
405 } else 409 } else
406 type = OUTPUT_ANY; 410 type = OUTPUT_ANY;
407 411
408 nv_encoder = find_encoder_by_type(connector, type); 412 nv_encoder = find_encoder(connector, type);
409 if (!nv_encoder) { 413 if (!nv_encoder) {
410 NV_ERROR(connector->dev, "can't find encoder to force %s on!\n", 414 NV_ERROR(connector->dev, "can't find encoder to force %s on!\n",
411 drm_get_connector_name(connector)); 415 drm_get_connector_name(connector));
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 8256370e5938..b30ddd8d2e2a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -214,10 +214,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
214 pfifo->unload_context(dev); 214 pfifo->unload_context(dev);
215 215
216 for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) { 216 for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
217 if (dev_priv->eng[e]) { 217 if (!dev_priv->eng[e])
218 ret = dev_priv->eng[e]->fini(dev, e); 218 continue;
219 if (ret) 219
220 goto out_abort; 220 ret = dev_priv->eng[e]->fini(dev, e, true);
221 if (ret) {
222 NV_ERROR(dev, "... engine %d failed: %d\n", i, ret);
223 goto out_abort;
221 } 224 }
222 } 225 }
223 226
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 72bfc143eb47..d7d51deb34b6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -312,7 +312,7 @@ struct nouveau_channel {
312struct nouveau_exec_engine { 312struct nouveau_exec_engine {
313 void (*destroy)(struct drm_device *, int engine); 313 void (*destroy)(struct drm_device *, int engine);
314 int (*init)(struct drm_device *, int engine); 314 int (*init)(struct drm_device *, int engine);
315 int (*fini)(struct drm_device *, int engine); 315 int (*fini)(struct drm_device *, int engine, bool suspend);
316 int (*context_new)(struct nouveau_channel *, int engine); 316 int (*context_new)(struct nouveau_channel *, int engine);
317 void (*context_del)(struct nouveau_channel *, int engine); 317 void (*context_del)(struct nouveau_channel *, int engine);
318 int (*object_new)(struct nouveau_channel *, int engine, 318 int (*object_new)(struct nouveau_channel *, int engine,
@@ -1142,7 +1142,6 @@ extern int nvc0_fifo_unload_context(struct drm_device *);
1142 1142
1143/* nv04_graph.c */ 1143/* nv04_graph.c */
1144extern int nv04_graph_create(struct drm_device *); 1144extern int nv04_graph_create(struct drm_device *);
1145extern void nv04_graph_fifo_access(struct drm_device *, bool);
1146extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16); 1145extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
1147extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan, 1146extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
1148 u32 class, u32 mthd, u32 data); 1147 u32 class, u32 mthd, u32 data);
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 2ba7265bc967..868c7fd74854 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -79,7 +79,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
79 int i; 79 int i;
80 80
81 stat = nv_rd32(dev, NV03_PMC_INTR_0); 81 stat = nv_rd32(dev, NV03_PMC_INTR_0);
82 if (!stat) 82 if (stat == 0 || stat == ~0)
83 return IRQ_NONE; 83 return IRQ_NONE;
84 84
85 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 85 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index fa1e63210040..10656e430b44 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -694,7 +694,7 @@ out_engine:
694 for (e = e - 1; e >= 0; e--) { 694 for (e = e - 1; e >= 0; e--) {
695 if (!dev_priv->eng[e]) 695 if (!dev_priv->eng[e])
696 continue; 696 continue;
697 dev_priv->eng[e]->fini(dev, e); 697 dev_priv->eng[e]->fini(dev, e, false);
698 dev_priv->eng[e]->destroy(dev,e ); 698 dev_priv->eng[e]->destroy(dev,e );
699 } 699 }
700 } 700 }
@@ -746,7 +746,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
746 engine->fifo.takedown(dev); 746 engine->fifo.takedown(dev);
747 for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) { 747 for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
748 if (dev_priv->eng[e]) { 748 if (dev_priv->eng[e]) {
749 dev_priv->eng[e]->fini(dev, e); 749 dev_priv->eng[e]->fini(dev, e, false);
750 dev_priv->eng[e]->destroy(dev,e ); 750 dev_priv->eng[e]->destroy(dev,e );
751 } 751 }
752 } 752 }
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index 3626ee7db3ba..dbdea8ed3925 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -450,13 +450,13 @@ nv04_graph_context_del(struct nouveau_channel *chan, int engine)
450 unsigned long flags; 450 unsigned long flags;
451 451
452 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 452 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
453 nv04_graph_fifo_access(dev, false); 453 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
454 454
455 /* Unload the context if it's the currently active one */ 455 /* Unload the context if it's the currently active one */
456 if (nv04_graph_channel(dev) == chan) 456 if (nv04_graph_channel(dev) == chan)
457 nv04_graph_unload_context(dev); 457 nv04_graph_unload_context(dev);
458 458
459 nv04_graph_fifo_access(dev, true); 459 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
460 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 460 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
461 461
462 /* Free the context resources */ 462 /* Free the context resources */
@@ -538,24 +538,18 @@ nv04_graph_init(struct drm_device *dev, int engine)
538} 538}
539 539
540static int 540static int
541nv04_graph_fini(struct drm_device *dev, int engine) 541nv04_graph_fini(struct drm_device *dev, int engine, bool suspend)
542{ 542{
543 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
544 if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
545 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
546 return -EBUSY;
547 }
543 nv04_graph_unload_context(dev); 548 nv04_graph_unload_context(dev);
544 nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); 549 nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
545 return 0; 550 return 0;
546} 551}
547 552
548void
549nv04_graph_fifo_access(struct drm_device *dev, bool enabled)
550{
551 if (enabled)
552 nv_wr32(dev, NV04_PGRAPH_FIFO,
553 nv_rd32(dev, NV04_PGRAPH_FIFO) | 1);
554 else
555 nv_wr32(dev, NV04_PGRAPH_FIFO,
556 nv_rd32(dev, NV04_PGRAPH_FIFO) & ~1);
557}
558
559static int 553static int
560nv04_graph_mthd_set_ref(struct nouveau_channel *chan, 554nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
561 u32 class, u32 mthd, u32 data) 555 u32 class, u32 mthd, u32 data)
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index 0930c6cb88e0..7255e4a4d3f3 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -708,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
708 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c); 708 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
709 nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst); 709 nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
710 nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); 710 nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
711 nv04_graph_fifo_access(dev, true); 711 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
712 nv04_graph_fifo_access(dev, false); 712 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
713 713
714 /* Restore the FIFO state */ 714 /* Restore the FIFO state */
715 for (i = 0; i < ARRAY_SIZE(fifo); i++) 715 for (i = 0; i < ARRAY_SIZE(fifo); i++)
@@ -879,13 +879,13 @@ nv10_graph_context_del(struct nouveau_channel *chan, int engine)
879 unsigned long flags; 879 unsigned long flags;
880 880
881 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 881 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
882 nv04_graph_fifo_access(dev, false); 882 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
883 883
884 /* Unload the context if it's the currently active one */ 884 /* Unload the context if it's the currently active one */
885 if (nv10_graph_channel(dev) == chan) 885 if (nv10_graph_channel(dev) == chan)
886 nv10_graph_unload_context(dev); 886 nv10_graph_unload_context(dev);
887 887
888 nv04_graph_fifo_access(dev, true); 888 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
889 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 889 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
890 890
891 /* Free the context resources */ 891 /* Free the context resources */
@@ -957,8 +957,13 @@ nv10_graph_init(struct drm_device *dev, int engine)
957} 957}
958 958
959static int 959static int
960nv10_graph_fini(struct drm_device *dev, int engine) 960nv10_graph_fini(struct drm_device *dev, int engine, bool suspend)
961{ 961{
962 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
963 if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
964 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
965 return -EBUSY;
966 }
962 nv10_graph_unload_context(dev); 967 nv10_graph_unload_context(dev);
963 nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); 968 nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
964 return 0; 969 return 0;
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index affc7d7dd029..183e37512ef9 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -454,13 +454,13 @@ nv20_graph_context_del(struct nouveau_channel *chan, int engine)
454 unsigned long flags; 454 unsigned long flags;
455 455
456 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 456 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
457 nv04_graph_fifo_access(dev, false); 457 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
458 458
459 /* Unload the context if it's the currently active one */ 459 /* Unload the context if it's the currently active one */
460 if (nv10_graph_channel(dev) == chan) 460 if (nv10_graph_channel(dev) == chan)
461 nv20_graph_unload_context(dev); 461 nv20_graph_unload_context(dev);
462 462
463 nv04_graph_fifo_access(dev, true); 463 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
464 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 464 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
465 465
466 /* Free the context resources */ 466 /* Free the context resources */
@@ -654,8 +654,13 @@ nv30_graph_init(struct drm_device *dev, int engine)
654} 654}
655 655
656int 656int
657nv20_graph_fini(struct drm_device *dev, int engine) 657nv20_graph_fini(struct drm_device *dev, int engine, bool suspend)
658{ 658{
659 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
660 if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
661 nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
662 return -EBUSY;
663 }
659 nv20_graph_unload_context(dev); 664 nv20_graph_unload_context(dev);
660 nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); 665 nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
661 return 0; 666 return 0;
@@ -753,6 +758,7 @@ nv20_graph_create(struct drm_device *dev)
753 break; 758 break;
754 default: 759 default:
755 NV_ERROR(dev, "PGRAPH: unknown chipset\n"); 760 NV_ERROR(dev, "PGRAPH: unknown chipset\n");
761 kfree(pgraph);
756 return 0; 762 return 0;
757 } 763 }
758 } else { 764 } else {
@@ -774,6 +780,7 @@ nv20_graph_create(struct drm_device *dev)
774 break; 780 break;
775 default: 781 default:
776 NV_ERROR(dev, "PGRAPH: unknown chipset\n"); 782 NV_ERROR(dev, "PGRAPH: unknown chipset\n");
783 kfree(pgraph);
777 return 0; 784 return 0;
778 } 785 }
779 } 786 }
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 5beb01b8ace1..ba14a93d8afa 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -35,89 +35,6 @@ struct nv40_graph_engine {
35 u32 grctx_size; 35 u32 grctx_size;
36}; 36};
37 37
38static struct nouveau_channel *
39nv40_graph_channel(struct drm_device *dev)
40{
41 struct drm_nouveau_private *dev_priv = dev->dev_private;
42 struct nouveau_gpuobj *grctx;
43 uint32_t inst;
44 int i;
45
46 inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
47 if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
48 return NULL;
49 inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
50
51 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
52 if (!dev_priv->channels.ptr[i])
53 continue;
54
55 grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
56 if (grctx && grctx->pinst == inst)
57 return dev_priv->channels.ptr[i];
58 }
59
60 return NULL;
61}
62
63static int
64nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
65{
66 uint32_t old_cp, tv = 1000, tmp;
67 int i;
68
69 old_cp = nv_rd32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER);
70 nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
71
72 tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0310);
73 tmp |= save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE :
74 NV40_PGRAPH_CTXCTL_0310_XFER_LOAD;
75 nv_wr32(dev, NV40_PGRAPH_CTXCTL_0310, tmp);
76
77 tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0304);
78 tmp |= NV40_PGRAPH_CTXCTL_0304_XFER_CTX;
79 nv_wr32(dev, NV40_PGRAPH_CTXCTL_0304, tmp);
80
81 nouveau_wait_for_idle(dev);
82
83 for (i = 0; i < tv; i++) {
84 if (nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C) == 0)
85 break;
86 }
87
88 nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp);
89
90 if (i == tv) {
91 uint32_t ucstat = nv_rd32(dev, NV40_PGRAPH_CTXCTL_UCODE_STAT);
92 NV_ERROR(dev, "Failed: Instance=0x%08x Save=%d\n", inst, save);
93 NV_ERROR(dev, "IP: 0x%02x, Opcode: 0x%08x\n",
94 ucstat >> NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT,
95 ucstat & NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK);
96 NV_ERROR(dev, "0x40030C = 0x%08x\n",
97 nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C));
98 return -EBUSY;
99 }
100
101 return 0;
102}
103
104static int
105nv40_graph_unload_context(struct drm_device *dev)
106{
107 uint32_t inst;
108 int ret;
109
110 inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
111 if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
112 return 0;
113 inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
114
115 ret = nv40_graph_transfer_context(dev, inst, 1);
116
117 nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
118 return ret;
119}
120
121static int 38static int
122nv40_graph_context_new(struct nouveau_channel *chan, int engine) 39nv40_graph_context_new(struct nouveau_channel *chan, int engine)
123{ 40{
@@ -163,16 +80,16 @@ nv40_graph_context_del(struct nouveau_channel *chan, int engine)
163 struct nouveau_gpuobj *grctx = chan->engctx[engine]; 80 struct nouveau_gpuobj *grctx = chan->engctx[engine];
164 struct drm_device *dev = chan->dev; 81 struct drm_device *dev = chan->dev;
165 struct drm_nouveau_private *dev_priv = dev->dev_private; 82 struct drm_nouveau_private *dev_priv = dev->dev_private;
83 u32 inst = 0x01000000 | (grctx->pinst >> 4);
166 unsigned long flags; 84 unsigned long flags;
167 85
168 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 86 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
169 nv04_graph_fifo_access(dev, false); 87 nv_mask(dev, 0x400720, 0x00000000, 0x00000001);
170 88 if (nv_rd32(dev, 0x40032c) == inst)
171 /* Unload the context if it's the currently active one */ 89 nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
172 if (nv40_graph_channel(dev) == chan) 90 if (nv_rd32(dev, 0x400330) == inst)
173 nv40_graph_unload_context(dev); 91 nv_mask(dev, 0x400330, 0x01000000, 0x00000000);
174 92 nv_mask(dev, 0x400720, 0x00000001, 0x00000001);
175 nv04_graph_fifo_access(dev, true);
176 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 93 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
177 94
178 /* Free the context resources */ 95 /* Free the context resources */
@@ -429,9 +346,20 @@ nv40_graph_init(struct drm_device *dev, int engine)
429} 346}
430 347
431static int 348static int
432nv40_graph_fini(struct drm_device *dev, int engine) 349nv40_graph_fini(struct drm_device *dev, int engine, bool suspend)
433{ 350{
434 nv40_graph_unload_context(dev); 351 u32 inst = nv_rd32(dev, 0x40032c);
352 if (inst & 0x01000000) {
353 nv_wr32(dev, 0x400720, 0x00000000);
354 nv_wr32(dev, 0x400784, inst);
355 nv_mask(dev, 0x400310, 0x00000020, 0x00000020);
356 nv_mask(dev, 0x400304, 0x00000001, 0x00000001);
357 if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) {
358 u32 insn = nv_rd32(dev, 0x400308);
359 NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn);
360 }
361 nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
362 }
435 return 0; 363 return 0;
436} 364}
437 365
diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
index 6d2af292a2e3..ad03a0e1fc7d 100644
--- a/drivers/gpu/drm/nouveau/nv40_mpeg.c
+++ b/drivers/gpu/drm/nouveau/nv40_mpeg.c
@@ -137,7 +137,7 @@ nv40_mpeg_init(struct drm_device *dev, int engine)
137} 137}
138 138
139static int 139static int
140nv40_mpeg_fini(struct drm_device *dev, int engine) 140nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
141{ 141{
142 /*XXX: context save? */ 142 /*XXX: context save? */
143 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); 143 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index e25cbb46789a..d27dcf0790de 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -125,7 +125,6 @@ static void
125nv50_graph_init_reset(struct drm_device *dev) 125nv50_graph_init_reset(struct drm_device *dev)
126{ 126{
127 uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21); 127 uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21);
128
129 NV_DEBUG(dev, "\n"); 128 NV_DEBUG(dev, "\n");
130 129
131 nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e); 130 nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e);
@@ -255,9 +254,13 @@ nv50_graph_init(struct drm_device *dev, int engine)
255} 254}
256 255
257static int 256static int
258nv50_graph_fini(struct drm_device *dev, int engine) 257nv50_graph_fini(struct drm_device *dev, int engine, bool suspend)
259{ 258{
260 NV_DEBUG(dev, "\n"); 259 nv_mask(dev, 0x400500, 0x00010001, 0x00000000);
260 if (!nv_wait(dev, 0x400700, ~0, 0) && suspend) {
261 nv_mask(dev, 0x400500, 0x00010001, 0x00010001);
262 return -EBUSY;
263 }
261 nv50_graph_unload_context(dev); 264 nv50_graph_unload_context(dev);
262 nv_wr32(dev, 0x40013c, 0x00000000); 265 nv_wr32(dev, 0x40013c, 0x00000000);
263 return 0; 266 return 0;
diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
index 1dc5913f78c5..b57a2d180ad2 100644
--- a/drivers/gpu/drm/nouveau/nv50_mpeg.c
+++ b/drivers/gpu/drm/nouveau/nv50_mpeg.c
@@ -160,7 +160,7 @@ nv50_mpeg_init(struct drm_device *dev, int engine)
160} 160}
161 161
162static int 162static int
163nv50_mpeg_fini(struct drm_device *dev, int engine) 163nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
164{ 164{
165 /*XXX: context save for s/r */ 165 /*XXX: context save for s/r */
166 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); 166 nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index c25c59386420..ffe8b483b7b0 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -318,6 +318,8 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
318 uint32_t tmp; 318 uint32_t tmp;
319 319
320 tmp = nv_rd32(dev, 0x61c700 + (or * 0x800)); 320 tmp = nv_rd32(dev, 0x61c700 + (or * 0x800));
321 if (!tmp)
322 tmp = nv_rd32(dev, 0x610798 + (or * 8));
321 323
322 switch ((tmp & 0x00000f00) >> 8) { 324 switch ((tmp & 0x00000f00) >> 8) {
323 case 8: 325 case 8:
diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c
index 75b809a51748..edece9c616eb 100644
--- a/drivers/gpu/drm/nouveau/nv84_crypt.c
+++ b/drivers/gpu/drm/nouveau/nv84_crypt.c
@@ -138,7 +138,7 @@ nv84_crypt_isr(struct drm_device *dev)
138} 138}
139 139
140static int 140static int
141nv84_crypt_fini(struct drm_device *dev, int engine) 141nv84_crypt_fini(struct drm_device *dev, int engine, bool suspend)
142{ 142{
143 nv_wr32(dev, 0x102140, 0x00000000); 143 nv_wr32(dev, 0x102140, 0x00000000);
144 return 0; 144 return 0;
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
index b86820a61220..8f356d58e409 100644
--- a/drivers/gpu/drm/nouveau/nva3_copy.c
+++ b/drivers/gpu/drm/nouveau/nva3_copy.c
@@ -140,7 +140,7 @@ nva3_copy_init(struct drm_device *dev, int engine)
140} 140}
141 141
142static int 142static int
143nva3_copy_fini(struct drm_device *dev, int engine) 143nva3_copy_fini(struct drm_device *dev, int engine, bool suspend)
144{ 144{
145 nv_mask(dev, 0x104048, 0x00000003, 0x00000000); 145 nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
146 146
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.c b/drivers/gpu/drm/nouveau/nvc0_copy.c
index 5ebcd74244db..dddf006f6d88 100644
--- a/drivers/gpu/drm/nouveau/nvc0_copy.c
+++ b/drivers/gpu/drm/nouveau/nvc0_copy.c
@@ -127,7 +127,7 @@ nvc0_copy_init(struct drm_device *dev, int engine)
127} 127}
128 128
129static int 129static int
130nvc0_copy_fini(struct drm_device *dev, int engine) 130nvc0_copy_fini(struct drm_device *dev, int engine, bool suspend)
131{ 131{
132 struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); 132 struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
133 133
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 3a97431996c5..5b2f6f420468 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -304,7 +304,7 @@ nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
304} 304}
305 305
306static int 306static int
307nvc0_graph_fini(struct drm_device *dev, int engine) 307nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend)
308{ 308{
309 return 0; 309 return 0;
310} 310}