summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared-core/nouveau_drv.h2
-rw-r--r--shared-core/nouveau_state.c8
-rw-r--r--shared-core/nv04_timer.c21
3 files changed, 31 insertions, 0 deletions
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index f68304c9..9e11f9b7 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -157,6 +157,7 @@ struct nouveau_engine_func {
struct {
int (*init)(struct drm_device *dev);
+ uint64_t (*read)(struct drm_device *dev);
void (*takedown)(struct drm_device *dev);
} timer;
@@ -469,6 +470,7 @@ extern void nv50_mc_takedown(struct drm_device *dev);
/* nv04_timer.c */
extern int nv04_timer_init(struct drm_device *dev);
+extern uint64_t nv04_timer_read(struct drm_device *dev);
extern void nv04_timer_takedown(struct drm_device *dev);
extern long nouveau_compat_ioctl(struct file *filp, unsigned int cmd,
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index 4e3b39dd..5b67aea1 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -88,6 +88,8 @@ static int nouveau_init_card_mappings(struct drm_device *dev)
static int nouveau_stub_init(struct drm_device *dev) { return 0; }
static void nouveau_stub_takedown(struct drm_device *dev) {}
+static uint64_t nouveau_stub_timer_read(struct drm_device *dev) { return 0; }
+
static int nouveau_init_engine_ptrs(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -104,6 +106,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
+ engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv04_fb_init;
engine->fb.takedown = nv04_fb_takedown;
@@ -130,6 +133,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
+ engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv10_fb_init;
engine->fb.takedown = nv10_fb_takedown;
@@ -156,6 +160,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
+ engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv10_fb_init;
engine->fb.takedown = nv10_fb_takedown;
@@ -182,6 +187,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
+ engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv10_fb_init;
engine->fb.takedown = nv10_fb_takedown;
@@ -208,6 +214,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->mc.init = nv40_mc_init;
engine->mc.takedown = nv40_mc_takedown;
engine->timer.init = nv04_timer_init;
+ engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv40_fb_init;
engine->fb.takedown = nv40_fb_takedown;
@@ -235,6 +242,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->mc.init = nv50_mc_init;
engine->mc.takedown = nv50_mc_takedown;
engine->timer.init = nouveau_stub_init;
+ engine->timer.read = nouveau_stub_timer_read;
engine->timer.takedown = nouveau_stub_takedown;
engine->fb.init = nouveau_stub_init;
engine->fb.takedown = nouveau_stub_takedown;
diff --git a/shared-core/nv04_timer.c b/shared-core/nv04_timer.c
index efe78da7..08a27f4f 100644
--- a/shared-core/nv04_timer.c
+++ b/shared-core/nv04_timer.c
@@ -17,6 +17,27 @@ nv04_timer_init(struct drm_device *dev)
return 0;
}
+uint64_t
+nv04_timer_read(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t low;
+ /* From kmmio dumps on nv28 this looks like how the blob does this.
+ * It reads the high dword twice, before and after.
+ * The only explanation seems to be that the 64-bit timer counter
+ * advances between high and low dword reads and may corrupt the
+ * result. Not confirmed.
+ */
+ uint32_t high2 = NV_READ(NV04_PTIMER_TIME_1);
+ uint32_t high1;
+ do {
+ high1 = high2;
+ low = NV_READ(NV04_PTIMER_TIME_0);
+ high2 = NV_READ(NV04_PTIMER_TIME_1);
+ } while(high1 != high2);
+ return (((uint64_t)high2) << 32) | (uint64_t)low;
+}
+
void
nv04_timer_takedown(struct drm_device *dev)
{