Re: [Nouveau] [PATCH] Add PFIFO and PGRAPH pausing methods

2011-01-12 Thread Francisco Jerez
Martin Peres martin.pe...@free.fr writes:

 Hi,

 I'm still working on getting the reclocking work done right. There are
 several parts I identify:
 - Pausing PFIFO (with its caches), pause PGRAPH and wait for idle
 - Stop some PLL (I guess it is more, physically disconnect them from
 the engines) using the 0xc040 register.
 - reclock memory
 - reclock the other engines
 - Make sure the display doesn't blow up
 Depending on the cards, I have completed all of the steps or none.

 Anyway, pausing PFIFO and PGRAPH works well on all the card I tested
 and so, I would like it to be pushed.
 I have a new theory upon the PLL_SUPERVISOR(0xc040) that I want to
 test. When I'm done with this, I'll put together a patch for it and
 continue on the other steps.

 Please provide me with some feedback on the patch or push it if
 nothing bothers you.

Thanks, some comments inline.

 Martin

 PS: I'm quite busy at the moment, I'll write an in-depth mail when
 I've verified my theories and got proper support on other cards than
 the nv86 ones.

 From f7ad98f4a857dd4b1892712d15f93c13eb0669e3 Mon Sep 17 00:00:00 2001
 From: Martin Peres martin.pe...@ensi-bourges.fr
 Date: Mon, 10 Jan 2011 00:44:05 +0100
 Subject: [PATCH] Pause PFIFO and PGRAPH before reclocking

 Signed-off-by: Martin Peres martin.pe...@ensi-bourges.fr
 ---
  drivers/gpu/drm/nouveau/nouveau_drv.h   |   15 +++
  drivers/gpu/drm/nouveau/nouveau_pm.c|   32 ++-
  drivers/gpu/drm/nouveau/nouveau_reg.h   |3 +
  drivers/gpu/drm/nouveau/nouveau_state.c |   51 +++-
  drivers/gpu/drm/nouveau/nv04_fifo.c |   16 +++
  drivers/gpu/drm/nouveau/nv50_fifo.c |   20 +
  drivers/gpu/drm/nouveau/nv50_graph.c|   66 
 +++
  7 files changed, 200 insertions(+), 3 deletions(-)

 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h 
 b/drivers/gpu/drm/nouveau/nouveau_drv.h
 index 6d749b7..b0c52c7 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
 @@ -359,6 +359,12 @@ struct nouveau_fifo_engine {
   int  (*load_context)(struct nouveau_channel *);
   int  (*unload_context)(struct drm_device *);
   void (*tlb_flush)(struct drm_device *dev);
 +
 + int  (*pause)(struct drm_device *);
 + void  (*unpause)(struct drm_device *);
 +
 + int  (*cache_pause)(struct drm_device *);
 + void  (*cache_unpause)(struct drm_device *);

You could fold fifo-cache_pause() into fifo-pause(). I don't see any
reason to have two separate pairs of callbacks here, they're always
going to be called one after the other.

  };
  
  struct nouveau_pgraph_engine {
 @@ -383,6 +389,9 @@ struct nouveau_pgraph_engine {
   void (*tlb_flush)(struct drm_device *dev);
  
   void (*set_tile_region)(struct drm_device *dev, int i);
 +
 + int  (*pause)(struct drm_device *);
 + void  (*unpause)(struct drm_device *);
  };
  
  struct nouveau_display_engine {
 @@ -1094,6 +1103,8 @@ extern void nv04_fifo_destroy_context(struct 
 nouveau_channel *);
  extern int  nv04_fifo_load_context(struct nouveau_channel *);
  extern int  nv04_fifo_unload_context(struct drm_device *);
  extern void nv04_fifo_isr(struct drm_device *);
 +extern void nv04_fifo_cache_pause(struct drm_device *dev);
 +extern void nv04_fifo_cache_unpause(struct drm_device *dev);
  
  /* nv10_fifo.c */
  extern int  nv10_fifo_init(struct drm_device *);
 @@ -1117,6 +1128,8 @@ extern void nv50_fifo_destroy_context(struct 
 nouveau_channel *);
  extern int  nv50_fifo_load_context(struct nouveau_channel *);
  extern int  nv50_fifo_unload_context(struct drm_device *);
  extern void nv50_fifo_tlb_flush(struct drm_device *dev);
 +extern int  nv50_fifo_pause(struct drm_device *);
 +extern void nv50_fifo_unpause(struct drm_device *);
  
  /* nvc0_fifo.c */
  extern int  nvc0_fifo_init(struct drm_device *);
 @@ -1189,6 +1202,8 @@ extern int  nv50_graph_unload_context(struct drm_device 
 *);
  extern int  nv50_grctx_init(struct nouveau_grctx *);
  extern void nv50_graph_tlb_flush(struct drm_device *dev);
  extern void nv86_graph_tlb_flush(struct drm_device *dev);
 +extern int  nv50_graph_pause(struct drm_device *dev);
 +extern void nv50_graph_unpause(struct drm_device *dev);
  extern struct nouveau_enum nv50_data_error_names[];
  
  /* nvc0_graph.c */
 diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c 
 b/drivers/gpu/drm/nouveau/nouveau_pm.c
 index fb846a3..233deec 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
 @@ -59,6 +59,7 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct 
 nouveau_pm_level *perflvl)
  {
   struct drm_nouveau_private *dev_priv = dev-dev_private;
   struct nouveau_pm_engine *pm = dev_priv-engine.pm;
 + unsigned long flags;
   int ret;
  
   if (perflvl == pm-cur)
 @@ -72,13 +73,42 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct 
 nouveau_pm_level *perflvl)
   }
   }
  
 + /* Do 

[Nouveau] [PATCH] Add PFIFO and PGRAPH pausing methods

2011-01-09 Thread Martin Peres

Hi,

I'm still working on getting the reclocking work done right. There are 
several parts I identify:

- Pausing PFIFO (with its caches), pause PGRAPH and wait for idle
- Stop some PLL (I guess it is more, physically disconnect them from the 
engines) using the 0xc040 register.

- reclock memory
- reclock the other engines
- Make sure the display doesn't blow up
Depending on the cards, I have completed all of the steps or none.

Anyway, pausing PFIFO and PGRAPH works well on all the card I tested and 
so, I would like it to be pushed.
I have a new theory upon the PLL_SUPERVISOR(0xc040) that I want to test. 
When I'm done with this, I'll put together a patch for it and continue 
on the other steps.


Please provide me with some feedback on the patch or push it if nothing 
bothers you.


Martin

PS: I'm quite busy at the moment, I'll write an in-depth mail when I've 
verified my theories and got proper support on other cards than the nv86 
ones.
From f7ad98f4a857dd4b1892712d15f93c13eb0669e3 Mon Sep 17 00:00:00 2001
From: Martin Peres martin.pe...@ensi-bourges.fr
Date: Mon, 10 Jan 2011 00:44:05 +0100
Subject: [PATCH] Pause PFIFO and PGRAPH before reclocking

Signed-off-by: Martin Peres martin.pe...@ensi-bourges.fr
---
 drivers/gpu/drm/nouveau/nouveau_drv.h   |   15 +++
 drivers/gpu/drm/nouveau/nouveau_pm.c|   32 ++-
 drivers/gpu/drm/nouveau/nouveau_reg.h   |3 +
 drivers/gpu/drm/nouveau/nouveau_state.c |   51 +++-
 drivers/gpu/drm/nouveau/nv04_fifo.c |   16 +++
 drivers/gpu/drm/nouveau/nv50_fifo.c |   20 +
 drivers/gpu/drm/nouveau/nv50_graph.c|   66 +++
 7 files changed, 200 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 6d749b7..b0c52c7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -359,6 +359,12 @@ struct nouveau_fifo_engine {
 	int  (*load_context)(struct nouveau_channel *);
 	int  (*unload_context)(struct drm_device *);
 	void (*tlb_flush)(struct drm_device *dev);
+
+	int  (*pause)(struct drm_device *);
+	void  (*unpause)(struct drm_device *);
+
+	int  (*cache_pause)(struct drm_device *);
+	void  (*cache_unpause)(struct drm_device *);
 };
 
 struct nouveau_pgraph_engine {
@@ -383,6 +389,9 @@ struct nouveau_pgraph_engine {
 	void (*tlb_flush)(struct drm_device *dev);
 
 	void (*set_tile_region)(struct drm_device *dev, int i);
+
+	int  (*pause)(struct drm_device *);
+	void  (*unpause)(struct drm_device *);
 };
 
 struct nouveau_display_engine {
@@ -1094,6 +1103,8 @@ extern void nv04_fifo_destroy_context(struct nouveau_channel *);
 extern int  nv04_fifo_load_context(struct nouveau_channel *);
 extern int  nv04_fifo_unload_context(struct drm_device *);
 extern void nv04_fifo_isr(struct drm_device *);
+extern void nv04_fifo_cache_pause(struct drm_device *dev);
+extern void nv04_fifo_cache_unpause(struct drm_device *dev);
 
 /* nv10_fifo.c */
 extern int  nv10_fifo_init(struct drm_device *);
@@ -1117,6 +1128,8 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
 extern int  nv50_fifo_load_context(struct nouveau_channel *);
 extern int  nv50_fifo_unload_context(struct drm_device *);
 extern void nv50_fifo_tlb_flush(struct drm_device *dev);
+extern int  nv50_fifo_pause(struct drm_device *);
+extern void nv50_fifo_unpause(struct drm_device *);
 
 /* nvc0_fifo.c */
 extern int  nvc0_fifo_init(struct drm_device *);
@@ -1189,6 +1202,8 @@ extern int  nv50_graph_unload_context(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
 extern void nv50_graph_tlb_flush(struct drm_device *dev);
 extern void nv86_graph_tlb_flush(struct drm_device *dev);
+extern int  nv50_graph_pause(struct drm_device *dev);
+extern void nv50_graph_unpause(struct drm_device *dev);
 extern struct nouveau_enum nv50_data_error_names[];
 
 /* nvc0_graph.c */
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index fb846a3..233deec 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -59,6 +59,7 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 {
 	struct drm_nouveau_private *dev_priv = dev-dev_private;
 	struct nouveau_pm_engine *pm = dev_priv-engine.pm;
+	unsigned long flags;
 	int ret;
 
 	if (perflvl == pm-cur)
@@ -72,13 +73,42 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 		}
 	}
 
+	/* Do not allow the card to allocate/destroy a
+	 * new channel while reclocking.
+	 */
+	spin_lock_irqsave(dev_priv-context_switch_lock, flags);
+
+	/* Pause the engines, if possible */
+	if (dev_priv-engine.fifo.pause(dev)) {
+		ret = -EIO;
+		goto out;
+	}
+	dev_priv-engine.fifo.cache_pause(dev);
+	if (dev_priv-engine.graph.pause(dev)) {
+		ret = -EIO;
+		goto out;
+	}
+
 	nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl-core);