Browse Source

Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

Nothing major ready for merging yet, so mostly bug fixes below, in addition to VP3 enablement from Ilia.

* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
  drm/nouveau: fix command submission to use vmalloc for big allocations
  drm/nouveau/bios/therm: handle vbioses with duplicate entries (mostly nva5)
  drm/nouveau: use MSI interrupts
  drm/nv50-/kms: assume analog display connected if load on any pin
  drm/nv50/disp: prevent false output detection on the original nv50
  drm/nouveau/i2c: pass the function pointers in at creation time
  drm/nouveau/therm: survive to suspend/resume cycles
  drm/nouveau/timer: add a way to cancel alarms
  drm/nouveau/timer: restore the time on resume
  drm/nouveau/fan: restore pwm value on resume when in manual/auto mode
  drm/nouveau/therm: Set the correct pwm_mode upon resume
  drm/nouveau: require contiguous bo for framebuffer
  drm/nv50-/disp: use the number of dac, sor, pior rather than hardcoded values
  drm/nouveau: remove duplicate copy of nv44_graph_class
  drm/nouveau/vdec: implement support for VP3 engines
  drm/nouveau/core: get rid of math.h, replace log2i with order_base_2
Dave Airlie 11 years ago
parent
commit
d30645ae18
37 changed files with 323 additions and 145 deletions
  1. 1 2
      drivers/gpu/drm/nouveau/core/core/ramht.c
  2. 35 17
      drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
  3. 10 5
      drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
  4. 17 17
      drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
  5. 1 2
      drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
  6. 3 2
      drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
  7. 1 2
      drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
  8. 1 2
      drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
  9. 3 0
      drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
  10. 32 20
      drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
  11. 32 15
      drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
  12. 0 16
      drivers/gpu/drm/nouveau/core/include/core/math.h
  13. 5 3
      drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
  14. 1 0
      drivers/gpu/drm/nouveau/core/include/subdev/mc.h
  15. 2 0
      drivers/gpu/drm/nouveau/core/include/subdev/timer.h
  16. 3 1
      drivers/gpu/drm/nouveau/core/os.h
  17. 2 1
      drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
  18. 4 6
      drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
  19. 2 0
      drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
  20. 2 2
      drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
  21. 2 2
      drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
  22. 2 2
      drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
  23. 4 4
      drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
  24. 2 2
      drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
  25. 2 8
      drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
  26. 23 1
      drivers/gpu/drm/nouveau/core/subdev/mc/base.c
  27. 2 1
      drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
  28. 16 3
      drivers/gpu/drm/nouveau/core/subdev/therm/base.c
  29. 20 0
      drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
  30. 4 0
      drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
  31. 21 0
      drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
  32. 7 0
      drivers/gpu/drm/nouveau/core/subdev/timer/base.c
  33. 34 1
      drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
  34. 1 0
      drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
  35. 5 0
      drivers/gpu/drm/nouveau/nouveau_display.c
  36. 20 7
      drivers/gpu/drm/nouveau/nouveau_gem.c
  37. 1 1
      drivers/gpu/drm/nouveau/nv50_display.c

+ 1 - 2
drivers/gpu/drm/nouveau/core/core/ramht.c

@@ -22,7 +22,6 @@
 
 #include <core/object.h>
 #include <core/ramht.h>
-#include <core/math.h>
 
 #include <subdev/bar.h>
 
@@ -104,6 +103,6 @@ nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
 	if (ret)
 		return ret;
 
-	ramht->bits = log2i(nv_gpuobj(ramht)->size >> 3);
+	ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
 	return 0;
 }

+ 35 - 17
drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c

@@ -19,16 +19,14 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
  */
 
-#include <core/engctx.h>
-#include <core/class.h>
-
+#include <engine/falcon.h>
 #include <engine/bsp.h>
 
 struct nv98_bsp_priv {
-	struct nouveau_engine base;
+	struct nouveau_falcon base;
 };
 
 /*******************************************************************************
@@ -37,30 +35,48 @@ struct nv98_bsp_priv {
 
 static struct nouveau_oclass
 nv98_bsp_sclass[] = {
+	{ 0x88b1, &nouveau_object_ofuncs },
+	{ 0x85b1, &nouveau_object_ofuncs },
+	{ 0x86b1, &nouveau_object_ofuncs },
 	{},
 };
 
 /*******************************************************************************
- * BSP context
+ * PBSP context
  ******************************************************************************/
 
 static struct nouveau_oclass
 nv98_bsp_cclass = {
 	.handle = NV_ENGCTX(BSP, 0x98),
 	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_engctx_ctor,
-		.dtor = _nouveau_engctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-		.rd32 = _nouveau_engctx_rd32,
-		.wr32 = _nouveau_engctx_wr32,
+		.ctor = _nouveau_falcon_context_ctor,
+		.dtor = _nouveau_falcon_context_dtor,
+		.init = _nouveau_falcon_context_init,
+		.fini = _nouveau_falcon_context_fini,
+		.rd32 = _nouveau_falcon_context_rd32,
+		.wr32 = _nouveau_falcon_context_wr32,
 	},
 };
 
 /*******************************************************************************
- * BSP engine/subdev functions
+ * PBSP engine/subdev functions
  ******************************************************************************/
 
+static int
+nv98_bsp_init(struct nouveau_object *object)
+{
+	struct nv98_bsp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nouveau_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x084010, 0x0000ffd2);
+	nv_wr32(priv, 0x08401c, 0x0000fff2);
+	return 0;
+}
+
 static int
 nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	      struct nouveau_oclass *oclass, void *data, u32 size,
@@ -69,7 +85,7 @@ nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	struct nv98_bsp_priv *priv;
 	int ret;
 
-	ret = nouveau_engine_create(parent, engine, oclass, true,
+	ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
 				    "PBSP", "bsp", &priv);
 	*pobject = nv_object(priv);
 	if (ret)
@@ -86,8 +102,10 @@ nv98_bsp_oclass = {
 	.handle = NV_ENGINE(BSP, 0x98),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nv98_bsp_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
+		.dtor = _nouveau_falcon_dtor,
+		.init = nv98_bsp_init,
+		.fini = _nouveau_falcon_fini,
+		.rd32 = _nouveau_falcon_rd32,
+		.wr32 = _nouveau_falcon_wr32,
 	},
 };

+ 10 - 5
drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c

@@ -49,18 +49,23 @@ int
 nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval)
 {
 	const u32 doff = (or * 0x800);
-	int load = -EINVAL;
+
 	nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
 	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+
 	nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
 	mdelay(9);
 	udelay(500);
-	nv_wr32(priv, 0x61a00c + doff, 0x80000000);
-	load = (nv_rd32(priv, 0x61a00c + doff) & 0x38000000) >> 27;
-	nv_wr32(priv, 0x61a00c + doff, 0x00000000);
+	loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000);
+
 	nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
 	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
-	return load;
+
+	nv_debug(priv, "DAC%d sense: 0x%08x\n", or, loadval);
+	if (!(loadval & 0x80000000))
+		return -ETIMEDOUT;
+
+	return (loadval & 0x38000000) >> 27;
 }
 
 int

+ 17 - 17
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c

@@ -628,7 +628,7 @@ nv50_disp_base_init(struct nouveau_object *object)
 	}
 
 	/* ... PIOR caps */
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < priv->pior.nr; i++) {
 		tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
 		nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
 	}
@@ -834,10 +834,11 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
 	u8  ver, hdr, cnt, len;
 	u16 data;
 	u32 ctrl = 0x00000000;
+	u32 reg;
 	int i;
 
 	/* DAC */
-	for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
+	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
 		ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
 
 	/* SOR */
@@ -845,19 +846,18 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
 		if (nv_device(priv)->chipset  < 0x90 ||
 		    nv_device(priv)->chipset == 0x92 ||
 		    nv_device(priv)->chipset == 0xa0) {
-			for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
-				ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
-			i += 4;
+			reg = 0x610b74;
 		} else {
-			for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
-				ctrl = nv_rd32(priv, 0x610798 + (i * 8));
-			i += 4;
+			reg = 0x610798;
 		}
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
+			ctrl = nv_rd32(priv, reg + (i * 8));
+		i += 4;
 	}
 
 	/* PIOR */
 	if (!(ctrl & (1 << head))) {
-		for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
 			ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
 		i += 8;
 	}
@@ -893,10 +893,11 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
 	u8  ver, hdr, cnt, len;
 	u32 ctrl = 0x00000000;
 	u32 data, conf = ~0;
+	u32 reg;
 	int i;
 
 	/* DAC */
-	for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
+	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
 		ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
 
 	/* SOR */
@@ -904,19 +905,18 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
 		if (nv_device(priv)->chipset  < 0x90 ||
 		    nv_device(priv)->chipset == 0x92 ||
 		    nv_device(priv)->chipset == 0xa0) {
-			for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
-				ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
-			i += 4;
+			reg = 0x610b70;
 		} else {
-			for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
-				ctrl = nv_rd32(priv, 0x610794 + (i * 8));
-			i += 4;
+			reg = 0x610794;
 		}
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
+			ctrl = nv_rd32(priv, reg + (i * 8));
+		i += 4;
 	}
 
 	/* PIOR */
 	if (!(ctrl & (1 << head))) {
-		for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
 			ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
 		i += 8;
 	}

+ 1 - 2
drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c

@@ -26,7 +26,6 @@
 #include <core/engctx.h>
 #include <core/ramht.h>
 #include <core/class.h>
-#include <core/math.h>
 
 #include <subdev/timer.h>
 #include <subdev/bar.h>
@@ -278,7 +277,7 @@ nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
 		return ret;
 
 	ioffset = args->ioffset;
-	ilength = log2i(args->ilength / 8);
+	ilength = order_base_2(args->ilength / 8);
 
 	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
 	nv_wo32(base->ramfc, 0x44, 0x01003fff);

+ 3 - 2
drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c

@@ -28,7 +28,6 @@
 #include <core/ramht.h>
 #include <core/event.h>
 #include <core/class.h>
-#include <core/math.h>
 
 #include <subdev/timer.h>
 #include <subdev/bar.h>
@@ -57,6 +56,7 @@ nv84_fifo_context_attach(struct nouveau_object *parent,
 	case NVDEV_ENGINE_SW   : return 0;
 	case NVDEV_ENGINE_GR   : addr = 0x0020; break;
 	case NVDEV_ENGINE_VP   : addr = 0x0040; break;
+	case NVDEV_ENGINE_PPP  :
 	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
 	case NVDEV_ENGINE_BSP  : addr = 0x0080; break;
 	case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
@@ -92,6 +92,7 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
 	case NVDEV_ENGINE_SW   : return 0;
 	case NVDEV_ENGINE_GR   : engn = 0; addr = 0x0020; break;
 	case NVDEV_ENGINE_VP   : engn = 3; addr = 0x0040; break;
+	case NVDEV_ENGINE_PPP  :
 	case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
 	case NVDEV_ENGINE_BSP  : engn = 5; addr = 0x0080; break;
 	case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
@@ -258,7 +259,7 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
 	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
 
 	ioffset = args->ioffset;
-	ilength = log2i(args->ilength / 8);
+	ilength = order_base_2(args->ilength / 8);
 
 	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
 	nv_wo32(base->ramfc, 0x44, 0x01003fff);

+ 1 - 2
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c

@@ -29,7 +29,6 @@
 #include <core/engctx.h>
 #include <core/event.h>
 #include <core/class.h>
-#include <core/math.h>
 #include <core/enum.h>
 
 #include <subdev/timer.h>
@@ -200,7 +199,7 @@ nvc0_fifo_chan_ctor(struct nouveau_object *parent,
 
 	usermem = chan->base.chid * 0x1000;
 	ioffset = args->ioffset;
-	ilength = log2i(args->ilength / 8);
+	ilength = order_base_2(args->ilength / 8);
 
 	for (i = 0; i < 0x1000; i += 4)
 		nv_wo32(priv->user.mem, usermem + i, 0x00000000);

+ 1 - 2
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c

@@ -29,7 +29,6 @@
 #include <core/engctx.h>
 #include <core/event.h>
 #include <core/class.h>
-#include <core/math.h>
 #include <core/enum.h>
 
 #include <subdev/timer.h>
@@ -240,7 +239,7 @@ nve0_fifo_chan_ctor(struct nouveau_object *parent,
 
 	usermem = chan->base.chid * 0x200;
 	ioffset = args->ioffset;
-	ilength = log2i(args->ilength / 8);
+	ilength = order_base_2(args->ilength / 8);
 
 	for (i = 0; i < 0x200; i += 4)
 		nv_wo32(priv->user.mem, usermem + i, 0x00000000);

+ 3 - 0
drivers/gpu/drm/nouveau/core/engine/graph/nv40.h

@@ -1,6 +1,9 @@
 #ifndef __NV40_GRAPH_H__
 #define __NV40_GRAPH_H__
 
+#include <core/device.h>
+#include <core/gpuobj.h>
+
 /* returns 1 if device is one of the nv4x using the 0x4497 object class,
  * helpful to determine a number of other hardware features
  */

+ 32 - 20
drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c

@@ -19,21 +19,14 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
  */
 
-#include <core/engine.h>
-#include <core/engctx.h>
-#include <core/class.h>
-
+#include <engine/falcon.h>
 #include <engine/ppp.h>
 
 struct nv98_ppp_priv {
-	struct nouveau_engine base;
-};
-
-struct nv98_ppp_chan {
-	struct nouveau_engctx base;
+	struct nouveau_falcon base;
 };
 
 /*******************************************************************************
@@ -42,6 +35,8 @@ struct nv98_ppp_chan {
 
 static struct nouveau_oclass
 nv98_ppp_sclass[] = {
+	{ 0x88b3, &nouveau_object_ofuncs },
+	{ 0x85b3, &nouveau_object_ofuncs },
 	{},
 };
 
@@ -53,12 +48,12 @@ static struct nouveau_oclass
 nv98_ppp_cclass = {
 	.handle = NV_ENGCTX(PPP, 0x98),
 	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_engctx_ctor,
-		.dtor = _nouveau_engctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-		.rd32 = _nouveau_engctx_rd32,
-		.wr32 = _nouveau_engctx_wr32,
+		.ctor = _nouveau_falcon_context_ctor,
+		.dtor = _nouveau_falcon_context_dtor,
+		.init = _nouveau_falcon_context_init,
+		.fini = _nouveau_falcon_context_fini,
+		.rd32 = _nouveau_falcon_context_rd32,
+		.wr32 = _nouveau_falcon_context_wr32,
 	},
 };
 
@@ -66,6 +61,21 @@ nv98_ppp_cclass = {
  * PPPP engine/subdev functions
  ******************************************************************************/
 
+static int
+nv98_ppp_init(struct nouveau_object *object)
+{
+	struct nv98_ppp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nouveau_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x086010, 0x0000ffd2);
+	nv_wr32(priv, 0x08601c, 0x0000fff2);
+	return 0;
+}
+
 static int
 nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	      struct nouveau_oclass *oclass, void *data, u32 size,
@@ -74,7 +84,7 @@ nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	struct nv98_ppp_priv *priv;
 	int ret;
 
-	ret = nouveau_engine_create(parent, engine, oclass, true,
+	ret = nouveau_falcon_create(parent, engine, oclass, 0x086000, true,
 				    "PPPP", "ppp", &priv);
 	*pobject = nv_object(priv);
 	if (ret)
@@ -91,8 +101,10 @@ nv98_ppp_oclass = {
 	.handle = NV_ENGINE(PPP, 0x98),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nv98_ppp_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
+		.dtor = _nouveau_falcon_dtor,
+		.init = nv98_ppp_init,
+		.fini = _nouveau_falcon_fini,
+		.rd32 = _nouveau_falcon_rd32,
+		.wr32 = _nouveau_falcon_wr32,
 	},
 };

+ 32 - 15
drivers/gpu/drm/nouveau/core/engine/vp/nv98.c

@@ -19,16 +19,14 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
  */
 
-#include <core/engctx.h>
-#include <core/class.h>
-
+#include <engine/falcon.h>
 #include <engine/vp.h>
 
 struct nv98_vp_priv {
-	struct nouveau_engine base;
+	struct nouveau_falcon base;
 };
 
 /*******************************************************************************
@@ -37,6 +35,8 @@ struct nv98_vp_priv {
 
 static struct nouveau_oclass
 nv98_vp_sclass[] = {
+	{ 0x88b2, &nouveau_object_ofuncs },
+	{ 0x85b2, &nouveau_object_ofuncs },
 	{},
 };
 
@@ -48,12 +48,12 @@ static struct nouveau_oclass
 nv98_vp_cclass = {
 	.handle = NV_ENGCTX(VP, 0x98),
 	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_engctx_ctor,
-		.dtor = _nouveau_engctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-		.rd32 = _nouveau_engctx_rd32,
-		.wr32 = _nouveau_engctx_wr32,
+		.ctor = _nouveau_falcon_context_ctor,
+		.dtor = _nouveau_falcon_context_dtor,
+		.init = _nouveau_falcon_context_init,
+		.fini = _nouveau_falcon_context_fini,
+		.rd32 = _nouveau_falcon_context_rd32,
+		.wr32 = _nouveau_falcon_context_wr32,
 	},
 };
 
@@ -61,6 +61,21 @@ nv98_vp_cclass = {
  * PVP engine/subdev functions
  ******************************************************************************/
 
+static int
+nv98_vp_init(struct nouveau_object *object)
+{
+	struct nv98_vp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nouveau_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x085010, 0x0000ffd2);
+	nv_wr32(priv, 0x08501c, 0x0000fff2);
+	return 0;
+}
+
 static int
 nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	     struct nouveau_oclass *oclass, void *data, u32 size,
@@ -69,7 +84,7 @@ nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	struct nv98_vp_priv *priv;
 	int ret;
 
-	ret = nouveau_engine_create(parent, engine, oclass, true,
+	ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
 				    "PVP", "vp", &priv);
 	*pobject = nv_object(priv);
 	if (ret)
@@ -86,8 +101,10 @@ nv98_vp_oclass = {
 	.handle = NV_ENGINE(VP, 0x98),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nv98_vp_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
+		.dtor = _nouveau_falcon_dtor,
+		.init = nv98_vp_init,
+		.fini = _nouveau_falcon_fini,
+		.rd32 = _nouveau_falcon_rd32,
+		.wr32 = _nouveau_falcon_wr32,
 	},
 };

+ 0 - 16
drivers/gpu/drm/nouveau/core/include/core/math.h

@@ -1,16 +0,0 @@
-#ifndef __NOUVEAU_MATH_H__
-#define __NOUVEAU_MATH_H__
-
-static inline int
-log2i(u64 base)
-{
-	u64 temp = base >> 1;
-	int log2;
-
-	for (log2 = 0; temp; log2++, temp >>= 1) {
-	}
-
-	return (base & (base - 1)) ? log2 + 1: log2;
-}
-
-#endif

+ 5 - 3
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h

@@ -39,8 +39,8 @@ struct nouveau_i2c_func {
 	int  (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
 };
 
-#define nouveau_i2c_port_create(p,e,o,i,a,d)                                   \
-	nouveau_i2c_port_create_((p), (e), (o), (i), (a),                      \
+#define nouveau_i2c_port_create(p,e,o,i,a,f,d)                                 \
+	nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f),                 \
 				 sizeof(**d), (void **)d)
 #define nouveau_i2c_port_destroy(p) ({                                         \
 	struct nouveau_i2c_port *port = (p);                                   \
@@ -53,7 +53,9 @@ struct nouveau_i2c_func {
 
 int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
 			     struct nouveau_oclass *, u8,
-			     const struct i2c_algorithm *, int, void **);
+			     const struct i2c_algorithm *,
+			     const struct nouveau_i2c_func *,
+			     int, void **);
 void _nouveau_i2c_port_dtor(struct nouveau_object *);
 #define _nouveau_i2c_port_init nouveau_object_init
 #define _nouveau_i2c_port_fini nouveau_object_fini

+ 1 - 0
drivers/gpu/drm/nouveau/core/include/subdev/mc.h

@@ -12,6 +12,7 @@ struct nouveau_mc_intr {
 struct nouveau_mc {
 	struct nouveau_subdev base;
 	const struct nouveau_mc_intr *intr_map;
+	bool use_msi;
 };
 
 static inline struct nouveau_mc *

+ 2 - 0
drivers/gpu/drm/nouveau/core/include/subdev/timer.h

@@ -22,6 +22,7 @@ bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
 bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
 bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
 void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *);
+void nouveau_timer_alarm_cancel(void *, struct nouveau_alarm *);
 
 #define NV_WAIT_DEFAULT 2000000000ULL
 #define nv_wait(o,a,m,v)                                                       \
@@ -35,6 +36,7 @@ struct nouveau_timer {
 	struct nouveau_subdev base;
 	u64  (*read)(struct nouveau_timer *);
 	void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *);
+	void (*alarm_cancel)(struct nouveau_timer *, struct nouveau_alarm *);
 };
 
 static inline struct nouveau_timer *

+ 3 - 1
drivers/gpu/drm/nouveau/core/os.h

@@ -13,11 +13,13 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/delay.h>
 #include <linux/io-mapping.h>
-#include <linux/vmalloc.h>
 #include <linux/acpi.h>
+#include <linux/vmalloc.h>
 #include <linux/dmi.h>
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
+#include <linux/log2.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/unaligned.h>
 

+ 2 - 1
drivers/gpu/drm/nouveau/core/subdev/bios/therm.c

@@ -184,7 +184,8 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios,
 			cur_trip->fan_duty = value;
 			break;
 		case 0x26:
-			fan->pwm_freq = value;
+			if (!fan->pwm_freq)
+				fan->pwm_freq = value;
 			break;
 		case 0x3b:
 			fan->bump_period = value;

+ 4 - 6
drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c

@@ -118,7 +118,8 @@ anx9805_aux_chan_ctor(struct nouveau_object *parent,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &nouveau_i2c_aux_algo, &chan);
+				      &nouveau_i2c_aux_algo, &anx9805_aux_func,
+				      &chan);
 	*pobject = nv_object(chan);
 	if (ret)
 		return ret;
@@ -140,8 +141,6 @@ anx9805_aux_chan_ctor(struct nouveau_object *parent,
 		struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
 		algo->udelay = max(algo->udelay, 40);
 	}
-
-	chan->base.func = &anx9805_aux_func;
 	return 0;
 }
 
@@ -234,7 +233,8 @@ anx9805_ddc_port_ctor(struct nouveau_object *parent,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &anx9805_i2c_algo, &port);
+				      &anx9805_i2c_algo, &anx9805_i2c_func,
+				      &port);
 	*pobject = nv_object(port);
 	if (ret)
 		return ret;
@@ -256,8 +256,6 @@ anx9805_ddc_port_ctor(struct nouveau_object *parent,
 		struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
 		algo->udelay = max(algo->udelay, 40);
 	}
-
-	port->base.func = &anx9805_i2c_func;
 	return 0;
 }
 

+ 2 - 0
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c

@@ -95,6 +95,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
 			 struct nouveau_object *engine,
 			 struct nouveau_oclass *oclass, u8 index,
 			 const struct i2c_algorithm *algo,
+			 const struct nouveau_i2c_func *func,
 			 int size, void **pobject)
 {
 	struct nouveau_device *device = nv_device(parent);
@@ -112,6 +113,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
 	port->adapter.owner = THIS_MODULE;
 	port->adapter.dev.parent = &device->pdev->dev;
 	port->index = index;
+	port->func = func;
 	i2c_set_adapdata(&port->adapter, i2c);
 
 	if ( algo == &nouveau_i2c_bit_algo &&

+ 2 - 2
drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c

@@ -91,12 +91,12 @@ nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &nouveau_i2c_bit_algo, &port);
+				      &nouveau_i2c_bit_algo, &nv04_i2c_func,
+				      &port);
 	*pobject = nv_object(port);
 	if (ret)
 		return ret;
 
-	port->base.func = &nv04_i2c_func;
 	port->drive = info->drive;
 	port->sense = info->sense;
 	return 0;

+ 2 - 2
drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c

@@ -84,12 +84,12 @@ nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &nouveau_i2c_bit_algo, &port);
+				      &nouveau_i2c_bit_algo, &nv4e_i2c_func,
+				      &port);
 	*pobject = nv_object(port);
 	if (ret)
 		return ret;
 
-	port->base.func = &nv4e_i2c_func;
 	port->addr = 0x600800 + info->drive;
 	return 0;
 }

+ 2 - 2
drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c

@@ -85,7 +85,8 @@ nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &nouveau_i2c_bit_algo, &port);
+				      &nouveau_i2c_bit_algo, &nv50_i2c_func,
+				      &port);
 	*pobject = nv_object(port);
 	if (ret)
 		return ret;
@@ -93,7 +94,6 @@ nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	if (info->drive >= nv50_i2c_addr_nr)
 		return -EINVAL;
 
-	port->base.func = &nv50_i2c_func;
 	port->state = 0x00000007;
 	port->addr = nv50_i2c_addr[info->drive];
 	return 0;

+ 4 - 4
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c

@@ -186,7 +186,8 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &nouveau_i2c_bit_algo, &port);
+				      &nouveau_i2c_bit_algo, &nv94_i2c_func,
+				      &port);
 	*pobject = nv_object(port);
 	if (ret)
 		return ret;
@@ -194,7 +195,6 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	if (info->drive >= nv50_i2c_addr_nr)
 		return -EINVAL;
 
-	port->base.func = &nv94_i2c_func;
 	port->state = 7;
 	port->addr = nv50_i2c_addr[info->drive];
 	if (info->share != DCB_I2C_UNUSED) {
@@ -221,12 +221,12 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &nouveau_i2c_aux_algo, &port);
+				      &nouveau_i2c_aux_algo, &nv94_aux_func,
+				      &port);
 	*pobject = nv_object(port);
 	if (ret)
 		return ret;
 
-	port->base.func = &nv94_aux_func;
 	port->addr = info->drive;
 	if (info->share != DCB_I2C_UNUSED) {
 		port->ctrl = 0x00e500 + (info->drive * 0x50);

+ 2 - 2
drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c

@@ -60,12 +60,12 @@ nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	int ret;
 
 	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				     &nouveau_i2c_bit_algo, &port);
+				      &nouveau_i2c_bit_algo, &nvd0_i2c_func,
+				      &port);
 	*pobject = nv_object(port);
 	if (ret)
 		return ret;
 
-	port->base.func = &nvd0_i2c_func;
 	port->state = 0x00000007;
 	port->addr = 0x00d014 + (info->drive * 0x20);
 	if (info->share != DCB_I2C_UNUSED) {

+ 2 - 8
drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c

@@ -22,15 +22,9 @@
  * Authors: Ben Skeggs
  */
 
-#include "nv04.h"
+#include <engine/graph/nv40.h>
 
-static inline int
-nv44_graph_class(struct nv04_instmem_priv *priv)
-{
-	if ((nv_device(priv)->chipset & 0xf0) == 0x60)
-		return 1;
-	return !(0x0baf & (1 << (nv_device(priv)->chipset & 0x0f)));
-}
+#include "nv04.h"
 
 static int
 nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,

+ 23 - 1
drivers/gpu/drm/nouveau/core/subdev/mc/base.c

@@ -23,7 +23,7 @@
  */
 
 #include <subdev/mc.h>
-#include <linux/pm_runtime.h>
+#include <core/option.h>
 
 static irqreturn_t
 nouveau_mc_intr(int irq, void *arg)
@@ -47,6 +47,9 @@ nouveau_mc_intr(int irq, void *arg)
 		map++;
 	}
 
+	if (pmc->use_msi)
+		nv_wr08(pmc->base.base.parent, 0x00088068, 0xff);
+
 	if (intr) {
 		nv_error(pmc, "unknown intr 0x%08x\n", stat);
 	}
@@ -81,6 +84,8 @@ _nouveau_mc_dtor(struct nouveau_object *object)
 	struct nouveau_device *device = nv_device(object);
 	struct nouveau_mc *pmc = (void *)object;
 	free_irq(device->pdev->irq, pmc);
+	if (pmc->use_msi)
+		pci_disable_msi(device->pdev);
 	nouveau_subdev_destroy(&pmc->base);
 }
 
@@ -102,6 +107,23 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
 
 	pmc->intr_map = intr_map;
 
+	switch (device->pdev->device & 0x0ff0) {
+	case 0x00f0: /* BR02? */
+	case 0x02e0: /* BR02? */
+		pmc->use_msi = false;
+		break;
+	default:
+		pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", true);
+		if (pmc->use_msi) {
+			pmc->use_msi = pci_enable_msi(device->pdev) == 0;
+			if (pmc->use_msi) {
+				nv_info(pmc, "MSI interrupts enabled\n");
+				nv_wr08(device, 0x00088068, 0xff);
+			}
+		}
+		break;
+	}
+
 	ret = request_irq(device->pdev->irq, nouveau_mc_intr,
 			  IRQF_SHARED, "nouveau", pmc);
 	if (ret < 0)

+ 2 - 1
drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c

@@ -35,6 +35,7 @@ nv98_mc_intr[] = {
 	{ 0x00001000, NVDEV_ENGINE_GR },
 	{ 0x00004000, NVDEV_ENGINE_CRYPT },	/* NV84:NVA3 */
 	{ 0x00008000, NVDEV_ENGINE_BSP },
+	{ 0x00020000, NVDEV_ENGINE_VP },
 	{ 0x00080000, NVDEV_SUBDEV_THERM },	/* NVA3:NVC0 */
 	{ 0x00100000, NVDEV_SUBDEV_TIMER },
 	{ 0x00200000, NVDEV_SUBDEV_GPIO },
@@ -42,7 +43,7 @@ nv98_mc_intr[] = {
 	{ 0x04000000, NVDEV_ENGINE_DISP },
 	{ 0x10000000, NVDEV_SUBDEV_BUS },
 	{ 0x80000000, NVDEV_ENGINE_SW },
-	{ 0x0040d101, NVDEV_SUBDEV_FB },
+	{ 0x0042d101, NVDEV_SUBDEV_FB },
 	{},
 };
 

+ 16 - 3
drivers/gpu/drm/nouveau/core/subdev/therm/base.c

@@ -95,12 +95,14 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
 	int duty;
 
 	spin_lock_irqsave(&priv->lock, flags);
+	nv_debug(therm, "FAN speed check\n");
 	if (mode < 0)
 		mode = priv->mode;
 	priv->mode = mode;
 
 	switch (mode) {
 	case NOUVEAU_THERM_CTRL_MANUAL:
+		ptimer->alarm_cancel(ptimer, &priv->alarm);
 		duty = nouveau_therm_fan_get(therm);
 		if (duty < 0)
 			duty = 100;
@@ -113,6 +115,7 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
 		break;
 	case NOUVEAU_THERM_CTRL_NONE:
 	default:
+		ptimer->alarm_cancel(ptimer, &priv->alarm);
 		goto done;
 	}
 
@@ -122,6 +125,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
 done:
 	if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO))
 		ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
+	else if (!list_empty(&priv->alarm.head))
+		nv_debug(therm, "therm fan alarm list is not empty\n");
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
@@ -267,9 +272,15 @@ _nouveau_therm_init(struct nouveau_object *object)
 	if (ret)
 		return ret;
 
-	if (priv->suspend >= 0)
-		nouveau_therm_fan_mode(therm, priv->mode);
-	priv->sensor.program_alarms(therm);
+	if (priv->suspend >= 0) {
+		/* restore the pwm value only when on manual or auto mode */
+		if (priv->suspend > 0)
+			nouveau_therm_fan_set(therm, true, priv->fan->percent);
+
+		nouveau_therm_fan_mode(therm, priv->suspend);
+	}
+	nouveau_therm_sensor_init(therm);
+	nouveau_therm_fan_init(therm);
 	return 0;
 }
 
@@ -279,6 +290,8 @@ _nouveau_therm_fini(struct nouveau_object *object, bool suspend)
 	struct nouveau_therm *therm = (void *)object;
 	struct nouveau_therm_priv *priv = (void *)therm;
 
+	nouveau_therm_fan_fini(therm, suspend);
+	nouveau_therm_sensor_fini(therm, suspend);
 	if (suspend) {
 		priv->suspend = priv->mode;
 		priv->mode = NOUVEAU_THERM_CTRL_NONE;

+ 20 - 0
drivers/gpu/drm/nouveau/core/subdev/therm/fan.c

@@ -203,6 +203,23 @@ nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
 		priv->fan->bios.min_duty = priv->fan->bios.max_duty;
 }
 
+int
+nouveau_therm_fan_init(struct nouveau_therm *therm)
+{
+	return 0;
+}
+
+int
+nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend)
+{
+	struct nouveau_therm_priv *priv = (void *)therm;
+	struct nouveau_timer *ptimer = nouveau_timer(therm);
+
+	if (suspend)
+		ptimer->alarm_cancel(ptimer, &priv->fan->alarm);
+	return 0;
+}
+
 int
 nouveau_therm_fan_ctor(struct nouveau_therm *therm)
 {
@@ -234,6 +251,9 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm)
 
 	nv_info(therm, "FAN control: %s\n", priv->fan->type);
 
+	/* read the current speed, it is useful when resuming */
+	priv->fan->percent = nouveau_therm_fan_get(therm);
+
 	/* attempt to detect a tachometer connection */
 	ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach);
 	if (ret)

+ 4 - 0
drivers/gpu/drm/nouveau/core/subdev/therm/priv.h

@@ -113,6 +113,8 @@ void nouveau_therm_ic_ctor(struct nouveau_therm *therm);
 int nouveau_therm_sensor_ctor(struct nouveau_therm *therm);
 
 int nouveau_therm_fan_ctor(struct nouveau_therm *therm);
+int nouveau_therm_fan_init(struct nouveau_therm *therm);
+int nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend);
 int nouveau_therm_fan_get(struct nouveau_therm *therm);
 int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent);
 int nouveau_therm_fan_user_get(struct nouveau_therm *therm);
@@ -122,6 +124,8 @@ int nouveau_therm_fan_sense(struct nouveau_therm *therm);
 
 int nouveau_therm_preinit(struct nouveau_therm *);
 
+int nouveau_therm_sensor_init(struct nouveau_therm *therm);
+int nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend);
 void nouveau_therm_sensor_preinit(struct nouveau_therm *);
 void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
 					     enum nouveau_therm_thrs thrs,

+ 21 - 0
drivers/gpu/drm/nouveau/core/subdev/therm/temp.c

@@ -180,6 +180,8 @@ alarm_timer_callback(struct nouveau_alarm *alarm)
 
 	spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
 
+	nv_debug(therm, "polling the internal temperature\n");
+
 	nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
 					     NOUVEAU_THERM_THRS_FANBOOST);
 
@@ -216,6 +218,25 @@ nouveau_therm_program_alarms_polling(struct nouveau_therm *therm)
 	alarm_timer_callback(&priv->sensor.therm_poll_alarm);
 }
 
+int
+nouveau_therm_sensor_init(struct nouveau_therm *therm)
+{
+	struct nouveau_therm_priv *priv = (void *)therm;
+	priv->sensor.program_alarms(therm);
+	return 0;
+}
+
+int
+nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend)
+{
+	struct nouveau_therm_priv *priv = (void *)therm;
+	struct nouveau_timer *ptimer = nouveau_timer(therm);
+
+	if (suspend)
+		ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm);
+	return 0;
+}
+
 void
 nouveau_therm_sensor_preinit(struct nouveau_therm *therm)
 {

+ 7 - 0
drivers/gpu/drm/nouveau/core/subdev/timer/base.c

@@ -85,3 +85,10 @@ nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm)
 	struct nouveau_timer *ptimer = nouveau_timer(obj);
 	ptimer->alarm(ptimer, nsec, alarm);
 }
+
+void
+nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm)
+{
+	struct nouveau_timer *ptimer = nouveau_timer(obj);
+	ptimer->alarm_cancel(ptimer, alarm);
+}

+ 34 - 1
drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c

@@ -36,6 +36,7 @@ struct nv04_timer_priv {
 	struct nouveau_timer base;
 	struct list_head alarms;
 	spinlock_t lock;
+	u64 suspend_time;
 };
 
 static u64
@@ -112,6 +113,25 @@ nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time,
 	nv04_timer_alarm_trigger(ptimer);
 }
 
+static void
+nv04_timer_alarm_cancel(struct nouveau_timer *ptimer,
+			struct nouveau_alarm *alarm)
+{
+	struct nv04_timer_priv *priv = (void *)ptimer;
+	unsigned long flags;
+
+	/* avoid deleting an entry while the alarm intr is running */
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* delete the alarm from the list */
+	list_del(&alarm->head);
+
+	/* reset the head so as list_empty returns 1 */
+	INIT_LIST_HEAD(&alarm->head);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
 static void
 nv04_timer_intr(struct nouveau_subdev *subdev)
 {
@@ -146,6 +166,8 @@ nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	priv->base.base.intr = nv04_timer_intr;
 	priv->base.read = nv04_timer_read;
 	priv->base.alarm = nv04_timer_alarm;
+	priv->base.alarm_cancel = nv04_timer_alarm_cancel;
+	priv->suspend_time = 0;
 
 	INIT_LIST_HEAD(&priv->alarms);
 	spin_lock_init(&priv->lock);
@@ -164,7 +186,7 @@ nv04_timer_init(struct nouveau_object *object)
 {
 	struct nouveau_device *device = nv_device(object);
 	struct nv04_timer_priv *priv = (void *)object;
-	u32 m = 1, f, n, d;
+	u32 m = 1, f, n, d, lo, hi;
 	int ret;
 
 	ret = nouveau_timer_init(&priv->base);
@@ -221,16 +243,25 @@ nv04_timer_init(struct nouveau_object *object)
 		d >>= 1;
 	}
 
+	/* restore the time before suspend */
+	lo = priv->suspend_time;
+	hi = (priv->suspend_time >> 32);
+
 	nv_debug(priv, "input frequency : %dHz\n", f);
 	nv_debug(priv, "input multiplier: %d\n", m);
 	nv_debug(priv, "numerator       : 0x%08x\n", n);
 	nv_debug(priv, "denominator     : 0x%08x\n", d);
 	nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
+	nv_debug(priv, "time low        : 0x%08x\n", lo);
+	nv_debug(priv, "time high       : 0x%08x\n", hi);
 
 	nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
 	nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
 	nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
 	nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+	nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
+	nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
+
 	return 0;
 }
 
@@ -238,6 +269,8 @@ static int
 nv04_timer_fini(struct nouveau_object *object, bool suspend)
 {
 	struct nv04_timer_priv *priv = (void *)object;
+	if (suspend)
+		priv->suspend_time = nv04_timer_read(&priv->base);
 	nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
 	return nouveau_timer_fini(&priv->base, suspend);
 }

+ 1 - 0
drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c

@@ -174,6 +174,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
 		case NVDEV_ENGINE_GR   : vme = 0x00; break;
 		case NVDEV_ENGINE_VP   : vme = 0x01; break;
 		case NVDEV_SUBDEV_BAR  : vme = 0x06; break;
+		case NVDEV_ENGINE_PPP  :
 		case NVDEV_ENGINE_MPEG : vme = 0x08; break;
 		case NVDEV_ENGINE_BSP  : vme = 0x09; break;
 		case NVDEV_ENGINE_CRYPT: vme = 0x0a; break;

+ 5 - 0
drivers/gpu/drm/nouveau/nouveau_display.c

@@ -107,6 +107,11 @@ nouveau_framebuffer_init(struct drm_device *dev,
 			 return -EINVAL;
 		}
 
+		if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
+			NV_ERROR(drm, "framebuffer requires contiguous bo\n");
+			return -EINVAL;
+		}
+
 		if (nv_device(drm->device)->chipset == 0x50)
 			nv_fb->r_format |= (tile_flags << 8);
 

+ 20 - 7
drivers/gpu/drm/nouveau/nouveau_gem.c

@@ -579,18 +579,31 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
 	return 0;
 }
 
+static inline void
+u_free(void *addr)
+{
+	if (!is_vmalloc_addr(addr))
+		kfree(addr);
+	else
+		vfree(addr);
+}
+
 static inline void *
 u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
 {
 	void *mem;
 	void __user *userptr = (void __force __user *)(uintptr_t)user;
 
-	mem = kmalloc(nmemb * size, GFP_KERNEL);
+	size *= nmemb;
+
+	mem = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
+	if (!mem)
+		mem = vmalloc(size);
 	if (!mem)
 		return ERR_PTR(-ENOMEM);
 
-	if (DRM_COPY_FROM_USER(mem, userptr, nmemb * size)) {
-		kfree(mem);
+	if (DRM_COPY_FROM_USER(mem, userptr, size)) {
+		u_free(mem);
 		return ERR_PTR(-EFAULT);
 	}
 
@@ -676,7 +689,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
 		nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data);
 	}
 
-	kfree(reloc);
+	u_free(reloc);
 	return ret;
 }
 
@@ -738,7 +751,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
 
 	bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
 	if (IS_ERR(bo)) {
-		kfree(push);
+		u_free(push);
 		return nouveau_abi16_put(abi16, PTR_ERR(bo));
 	}
 
@@ -849,8 +862,8 @@ out:
 	nouveau_fence_unref(&fence);
 
 out_prevalid:
-	kfree(bo);
-	kfree(push);
+	u_free(bo);
+	u_free(push);
 
 out_next:
 	if (chan->dma.ib_max) {

+ 1 - 1
drivers/gpu/drm/nouveau/nv50_display.c

@@ -1583,7 +1583,7 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
 		load = 340;
 
 	ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load));
-	if (ret || load != 7)
+	if (ret || !load)
 		return connector_status_disconnected;
 
 	return connector_status_connected;