nouveau: NV3X PGRAPH engtab functions
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index c7872c3..a4a3764 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -292,9 +292,12 @@
 extern int nv20_graph_context_create(drm_device_t *dev, int channel);
 
 /* nv30_graph.c */
-extern int nv30_graph_init(drm_device_t *dev);
+extern int  nv30_graph_init(drm_device_t *dev);
 extern void nv30_graph_takedown(drm_device_t *dev);
-extern int nv30_graph_context_create(drm_device_t *dev, int channel);
+extern int  nv30_graph_create_context(drm_device_t *, int channel);
+extern void nv30_graph_destroy_context(drm_device_t *, int channel);
+extern int  nv30_graph_load_context(drm_device_t *, int channel);
+extern int  nv30_graph_save_context(drm_device_t *, int channel);
 
 /* nv40_graph.c */
 extern int  nv40_graph_init(drm_device_t *);
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index 0a88364..1ef5a42 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -306,13 +306,6 @@
 				return ret;
 			}
 			break;
-		case NV_30:
-			ret = nv30_graph_context_create(dev, channel);
-			if (ret) {
-				nouveau_fifo_free(dev, channel);
-				return ret;
-			}
-			break;
 		default:
 			if (!engine->graph.create_context) {
 				DRM_ERROR("graph.create_context == NULL\n");
@@ -388,8 +381,6 @@
 	drm_nouveau_private_t *dev_priv = dev->dev_private;
 	nouveau_engine_func_t *engine = &dev_priv->Engine;
 	struct nouveau_fifo *chan = &dev_priv->fifos[channel];
-	int i;
-	int ctx_size = nouveau_fifo_ctx_size(dev);
 
 	chan->used = 0;
 	DRM_INFO("%s: freeing fifo %d\n", __func__, channel);
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index 55d10b8..a997b07 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -143,6 +143,10 @@
 		engine->fb.takedown	= nv10_fb_takedown;
 		engine->graph.init	= nv30_graph_init;
 		engine->graph.takedown	= nv30_graph_takedown;
+		engine->graph.create_context	= nv30_graph_create_context;
+		engine->graph.destroy_context	= nv30_graph_destroy_context;
+		engine->graph.load_context	= nv30_graph_load_context;
+		engine->graph.save_context	= nv30_graph_save_context;
 		engine->fifo.init	= nouveau_fifo_init;
 		engine->fifo.takedown	= nouveau_stub_takedown;
 		engine->fifo.create_context	= nv10_fifo_create_context;
diff --git a/shared-core/nv30_graph.c b/shared-core/nv30_graph.c
index f4faadd..9f064a0 100644
--- a/shared-core/nv30_graph.c
+++ b/shared-core/nv30_graph.c
@@ -100,7 +100,7 @@
 }
 
 
-int nv30_graph_context_create(drm_device_t *dev, int channel)
+int nv30_graph_create_context(drm_device_t *dev, int channel)
 {
 	drm_nouveau_private_t *dev_priv =
 		(drm_nouveau_private_t *)dev->dev_private;
@@ -132,6 +132,70 @@
 	return 0;
 }
 
+void nv30_graph_destroy_context(drm_device_t *dev, int channel)
+{
+	drm_nouveau_private_t *dev_priv =
+		(drm_nouveau_private_t *)dev->dev_private;
+	struct nouveau_fifo *chan = &dev_priv->fifos[channel];
+
+	if (chan->ramin_grctx) {
+		nouveau_instmem_free(dev, chan->ramin_grctx);
+		chan->ramin_grctx = NULL;
+	}
+
+	INSTANCE_WR(dev_priv->ctx_table, channel, 0);
+}
+
+static int
+nouveau_graph_wait_idle(drm_device_t *dev)
+{
+	drm_nouveau_private_t *dev_priv = dev->dev_private;
+	int tv = 1000;
+
+	while (tv--) {
+		if (NV_READ(0x400700) == 0)
+			break;
+	}
+
+	if (NV_READ(0x400700)) {
+		DRM_ERROR("timeout!\n");
+		return DRM_ERR(EBUSY);
+	}
+	return 0;
+}
+
+int nv30_graph_load_context(drm_device_t *dev, int channel)
+{
+	drm_nouveau_private_t *dev_priv = dev->dev_private;
+	struct nouveau_fifo *chan = &dev_priv->fifos[channel];
+	uint32_t inst;
+
+	if (!chan->ramin_grctx)
+		return DRM_ERR(EINVAL);
+	inst = nouveau_chip_instance_get(dev, chan->ramin_grctx);
+
+	NV_WRITE(0x400784, inst);
+	NV_WRITE(0x400788, 1);
+
+	return nouveau_graph_wait_idle(dev);
+}
+
+int nv30_graph_save_context(drm_device_t *dev, int channel)
+{
+	drm_nouveau_private_t *dev_priv = dev->dev_private;
+	struct nouveau_fifo *chan = &dev_priv->fifos[channel];
+	uint32_t inst;
+
+	if (!chan->ramin_grctx)
+		return DRM_ERR(EINVAL);
+	inst = nouveau_chip_instance_get(dev, chan->ramin_grctx);
+
+	NV_WRITE(0x400784, inst);
+	NV_WRITE(0x400788, 2);
+
+	return nouveau_graph_wait_idle(dev);
+}
+
 int nv30_graph_init(drm_device_t *dev)
 {
 	drm_nouveau_private_t *dev_priv =