aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/core/core/mm.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/xtensa.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mc.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/vm.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c12
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c14
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c34
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/base.c27
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c58
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv17_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv40_pm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fence.c14
31 files changed, 177 insertions, 104 deletions
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
index d8291724dbd4..7a4e0891c5f8 100644
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ b/drivers/gpu/drm/nouveau/core/core/mm.c
@@ -98,6 +98,8 @@ nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
98 u32 splitoff; 98 u32 splitoff;
99 u32 s, e; 99 u32 s, e;
100 100
101 BUG_ON(!type);
102
101 list_for_each_entry(this, &mm->free, fl_entry) { 103 list_for_each_entry(this, &mm->free, fl_entry) {
102 e = this->offset + this->length; 104 e = this->offset + this->length;
103 s = this->offset; 105 s = this->offset;
@@ -162,6 +164,8 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
162 struct nouveau_mm_node *prev, *this, *next; 164 struct nouveau_mm_node *prev, *this, *next;
163 u32 mask = align - 1; 165 u32 mask = align - 1;
164 166
167 BUG_ON(!type);
168
165 list_for_each_entry_reverse(this, &mm->free, fl_entry) { 169 list_for_each_entry_reverse(this, &mm->free, fl_entry) {
166 u32 e = this->offset + this->length; 170 u32 e = this->offset + this->length;
167 u32 s = this->offset; 171 u32 s = this->offset;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
index 373dbcc523b2..a19e7d79b847 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
36 if (data && data[0]) { 36 if (data && data[0]) {
37 for (i = 0; i < size; i++) 37 for (i = 0; i < size; i++)
38 nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]); 38 nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]);
39 for (; i < 0x60; i++)
40 nv_wr32(priv, 0x61c440 + soff, (i << 8));
39 nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003); 41 nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
40 } else 42 } else
41 if (data) { 43 if (data) {
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
index dc57e24fc1df..717639386ced 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
41 if (data && data[0]) { 41 if (data && data[0]) {
42 for (i = 0; i < size; i++) 42 for (i = 0; i < size; i++)
43 nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]); 43 nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]);
44 for (; i < 0x60; i++)
45 nv_wr32(priv, 0x10ec00 + soff, (i << 8));
44 nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003); 46 nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
45 } else 47 } else
46 if (data) { 48 if (data) {
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
index ab1e918469a8..526b75242899 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
@@ -47,14 +47,8 @@ int
47nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) 47nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
48{ 48{
49 struct nv50_disp_priv *priv = (void *)object->engine; 49 struct nv50_disp_priv *priv = (void *)object->engine;
50 struct nouveau_bios *bios = nouveau_bios(priv);
51 const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
52 const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3; 50 const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
53 const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
54 const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR); 51 const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR);
55 const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
56 struct dcb_output outp;
57 u8 ver, hdr;
58 u32 data; 52 u32 data;
59 int ret = -EINVAL; 53 int ret = -EINVAL;
60 54
@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
62 return -EINVAL; 56 return -EINVAL;
63 data = *(u32 *)args; 57 data = *(u32 *)args;
64 58
65 if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
66 return -ENODEV;
67 59
68 switch (mthd & ~0x3f) { 60 switch (mthd & ~0x3f) {
69 case NV50_DISP_SOR_PWR: 61 case NV50_DISP_SOR_PWR:
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
index 49ecbb859b25..c19004301309 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
265int 265int
266nv31_mpeg_init(struct nouveau_object *object) 266nv31_mpeg_init(struct nouveau_object *object)
267{ 267{
268 struct nouveau_engine *engine = nv_engine(object->engine); 268 struct nouveau_engine *engine = nv_engine(object);
269 struct nv31_mpeg_priv *priv = (void *)engine; 269 struct nv31_mpeg_priv *priv = (void *)object;
270 struct nouveau_fb *pfb = nouveau_fb(object); 270 struct nouveau_fb *pfb = nouveau_fb(object);
271 int ret, i; 271 int ret, i;
272 272
@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object)
284 /* PMPEG init */ 284 /* PMPEG init */
285 nv_wr32(priv, 0x00b32c, 0x00000000); 285 nv_wr32(priv, 0x00b32c, 0x00000000);
286 nv_wr32(priv, 0x00b314, 0x00000100); 286 nv_wr32(priv, 0x00b314, 0x00000100);
287 nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031); 287 if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv))
288 nv_wr32(priv, 0x00b220, 0x00000044);
289 else
290 nv_wr32(priv, 0x00b220, 0x00000031);
288 nv_wr32(priv, 0x00b300, 0x02001ec1); 291 nv_wr32(priv, 0x00b300, 0x02001ec1);
289 nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); 292 nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
290 293
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
index f7c581ad1991..dd6196072e9c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent,
61 if (ret) 61 if (ret)
62 return ret; 62 return ret;
63 63
64 nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
64 return 0; 65 return 0;
65} 66}
66 67
diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
index 0639bc59d0a5..5f6ede7c4892 100644
--- a/drivers/gpu/drm/nouveau/core/engine/xtensa.c
+++ b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object)
118 return ret; 118 return ret;
119 } 119 }
120 120
121 ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0, 121 if (fw->size > 0x40000) {
122 nv_warn(xtensa, "firmware %s too large\n", name);
123 release_firmware(fw);
124 return -EINVAL;
125 }
126
127 ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
122 &xtensa->gpu_fw); 128 &xtensa->gpu_fw);
123 if (ret) { 129 if (ret) {
124 release_firmware(fw); 130 release_firmware(fw);
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
index d5502267c30f..9d2cd2006250 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
@@ -20,8 +20,8 @@ nouveau_mc(void *obj)
20 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC]; 20 return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC];
21} 21}
22 22
23#define nouveau_mc_create(p,e,o,d) \ 23#define nouveau_mc_create(p,e,o,m,d) \
24 nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d) 24 nouveau_mc_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
25#define nouveau_mc_destroy(p) ({ \ 25#define nouveau_mc_destroy(p) ({ \
26 struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \ 26 struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \
27}) 27})
@@ -33,7 +33,8 @@ nouveau_mc(void *obj)
33}) 33})
34 34
35int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *, 35int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *,
36 struct nouveau_oclass *, int, void **); 36 struct nouveau_oclass *, const struct nouveau_mc_intr *,
37 int, void **);
37void _nouveau_mc_dtor(struct nouveau_object *); 38void _nouveau_mc_dtor(struct nouveau_object *);
38int _nouveau_mc_init(struct nouveau_object *); 39int _nouveau_mc_init(struct nouveau_object *);
39int _nouveau_mc_fini(struct nouveau_object *, bool); 40int _nouveau_mc_fini(struct nouveau_object *, bool);
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
index f2e87b105666..fcf57fa309bf 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
@@ -55,7 +55,7 @@ struct nouveau_vma {
55struct nouveau_vm { 55struct nouveau_vm {
56 struct nouveau_vmmgr *vmm; 56 struct nouveau_vmmgr *vmm;
57 struct nouveau_mm mm; 57 struct nouveau_mm mm;
58 int refcount; 58 struct kref refcount;
59 59
60 struct list_head pgd_list; 60 struct list_head pgd_list;
61 atomic_t engref[NVDEV_SUBDEV_NR]; 61 atomic_t engref[NVDEV_SUBDEV_NR];
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
index 6c974dd83e8b..db9d6ddde52c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
@@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
81void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, 81void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
82 u32 pitch, u32 flags, struct nouveau_fb_tile *); 82 u32 pitch, u32 flags, struct nouveau_fb_tile *);
83 83
84void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **); 84void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
85extern int nv50_fb_memtype[0x80]; 85extern int nv50_fb_memtype[0x80];
86 86
87#endif 87#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
index 19e3a9a63a02..ab7ef0ac9e34 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
@@ -40,15 +40,15 @@ nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
40 return ret; 40 return ret;
41 41
42 switch (pfb914 & 0x00000003) { 42 switch (pfb914 & 0x00000003) {
43 case 0x00000000: pfb->ram->type = NV_MEM_TYPE_DDR1; break; 43 case 0x00000000: ram->type = NV_MEM_TYPE_DDR1; break;
44 case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break; 44 case 0x00000001: ram->type = NV_MEM_TYPE_DDR2; break;
45 case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break; 45 case 0x00000002: ram->type = NV_MEM_TYPE_GDDR3; break;
46 case 0x00000003: break; 46 case 0x00000003: break;
47 } 47 }
48 48
49 pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; 49 ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
50 pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; 50 ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
51 pfb->ram->tags = nv_rd32(pfb, 0x100320); 51 ram->tags = nv_rd32(pfb, 0x100320);
52 return 0; 52 return 0;
53} 53}
54 54
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
index 7192aa6e5577..63a6aab86028 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
@@ -38,8 +38,8 @@ nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
38 if (ret) 38 if (ret)
39 return ret; 39 return ret;
40 40
41 pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; 41 ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
42 pfb->ram->type = NV_MEM_TYPE_STOLEN; 42 ram->type = NV_MEM_TYPE_STOLEN;
43 return 0; 43 return 0;
44} 44}
45 45
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
index af5aa7ee8ad9..903baff77fdd 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
@@ -27,17 +27,10 @@
27#include "priv.h" 27#include "priv.h"
28 28
29void 29void
30nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) 30__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
31{ 31{
32 struct nouveau_mm_node *this; 32 struct nouveau_mm_node *this;
33 struct nouveau_mem *mem;
34 33
35 mem = *pmem;
36 *pmem = NULL;
37 if (unlikely(mem == NULL))
38 return;
39
40 mutex_lock(&pfb->base.mutex);
41 while (!list_empty(&mem->regions)) { 34 while (!list_empty(&mem->regions)) {
42 this = list_first_entry(&mem->regions, typeof(*this), rl_entry); 35 this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
43 36
@@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
46 } 39 }
47 40
48 nouveau_mm_free(&pfb->tags, &mem->tag); 41 nouveau_mm_free(&pfb->tags, &mem->tag);
42}
43
44void
45nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
46{
47 struct nouveau_mem *mem = *pmem;
48
49 *pmem = NULL;
50 if (unlikely(mem == NULL))
51 return;
52
53 mutex_lock(&pfb->base.mutex);
54 __nv50_ram_put(pfb, mem);
49 mutex_unlock(&pfb->base.mutex); 55 mutex_unlock(&pfb->base.mutex);
50 56
51 kfree(mem); 57 kfree(mem);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
index 9c3634acbb9d..cf97c4de4a6b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
@@ -33,11 +33,19 @@ void
33nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) 33nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
34{ 34{
35 struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); 35 struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
36 struct nouveau_mem *mem = *pmem;
36 37
37 if ((*pmem)->tag) 38 *pmem = NULL;
38 ltcg->tags_free(ltcg, &(*pmem)->tag); 39 if (unlikely(mem == NULL))
40 return;
39 41
40 nv50_ram_put(pfb, pmem); 42 mutex_lock(&pfb->base.mutex);
43 if (mem->tag)
44 ltcg->tags_free(ltcg, &mem->tag);
45 __nv50_ram_put(pfb, mem);
46 mutex_unlock(&pfb->base.mutex);
47
48 kfree(mem);
41} 49}
42 50
43int 51int
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
index bf489dcf46e2..c4c1d415e7fe 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
103 int i; 103 int i;
104 104
105 intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); 105 intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
106 if (nv_device(priv)->chipset >= 0x90) 106 if (nv_device(priv)->chipset > 0x92)
107 intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070); 107 intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
108 108
109 hi = (intr0 & 0x0000ffff) | (intr1 << 16); 109 hi = (intr0 & 0x0000ffff) | (intr1 << 16);
@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
115 } 115 }
116 116
117 nv_wr32(priv, 0xe054, intr0); 117 nv_wr32(priv, 0xe054, intr0);
118 if (nv_device(priv)->chipset >= 0x90) 118 if (nv_device(priv)->chipset > 0x92)
119 nv_wr32(priv, 0xe074, intr1); 119 nv_wr32(priv, 0xe074, intr1);
120} 120}
121 121
@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
146 int ret; 146 int ret;
147 147
148 ret = nouveau_gpio_create(parent, engine, oclass, 148 ret = nouveau_gpio_create(parent, engine, oclass,
149 nv_device(parent)->chipset >= 0x90 ? 32 : 16, 149 nv_device(parent)->chipset > 0x92 ? 32 : 16,
150 &priv); 150 &priv);
151 *pobject = nv_object(priv); 151 *pobject = nv_object(priv);
152 if (ret) 152 if (ret)
@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object)
182 /* disable, and ack any pending gpio interrupts */ 182 /* disable, and ack any pending gpio interrupts */
183 nv_wr32(priv, 0xe050, 0x00000000); 183 nv_wr32(priv, 0xe050, 0x00000000);
184 nv_wr32(priv, 0xe054, 0xffffffff); 184 nv_wr32(priv, 0xe054, 0xffffffff);
185 if (nv_device(priv)->chipset >= 0x90) { 185 if (nv_device(priv)->chipset > 0x92) {
186 nv_wr32(priv, 0xe070, 0x00000000); 186 nv_wr32(priv, 0xe070, 0x00000000);
187 nv_wr32(priv, 0xe074, 0xffffffff); 187 nv_wr32(priv, 0xe074, 0xffffffff);
188 } 188 }
@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend)
195{ 195{
196 struct nv50_gpio_priv *priv = (void *)object; 196 struct nv50_gpio_priv *priv = (void *)object;
197 nv_wr32(priv, 0xe050, 0x00000000); 197 nv_wr32(priv, 0xe050, 0x00000000);
198 if (nv_device(priv)->chipset >= 0x90) 198 if (nv_device(priv)->chipset > 0x92)
199 nv_wr32(priv, 0xe070, 0x00000000); 199 nv_wr32(priv, 0xe070, 0x00000000);
200 return nouveau_gpio_fini(&priv->base, suspend); 200 return nouveau_gpio_fini(&priv->base, suspend);
201} 201}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
index bcca883018f4..cce65cc56514 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
@@ -30,8 +30,9 @@ struct nvc0_ltcg_priv {
30 struct nouveau_ltcg base; 30 struct nouveau_ltcg base;
31 u32 part_nr; 31 u32 part_nr;
32 u32 subp_nr; 32 u32 subp_nr;
33 struct nouveau_mm tags;
34 u32 num_tags; 33 u32 num_tags;
34 u32 tag_base;
35 struct nouveau_mm tags;
35 struct nouveau_mm_node *tag_ram; 36 struct nouveau_mm_node *tag_ram;
36}; 37};
37 38
@@ -117,10 +118,6 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
117 u32 tag_size, tag_margin, tag_align; 118 u32 tag_size, tag_margin, tag_align;
118 int ret; 119 int ret;
119 120
120 nv_wr32(priv, 0x17e8d8, priv->part_nr);
121 if (nv_device(pfb)->card_type >= NV_E0)
122 nv_wr32(priv, 0x17e000, priv->part_nr);
123
124 /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ 121 /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
125 priv->num_tags = (pfb->ram->size >> 17) / 4; 122 priv->num_tags = (pfb->ram->size >> 17) / 4;
126 if (priv->num_tags > (1 << 17)) 123 if (priv->num_tags > (1 << 17))
@@ -142,7 +139,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
142 tag_size += tag_align; 139 tag_size += tag_align;
143 tag_size = (tag_size + 0xfff) >> 12; /* round up */ 140 tag_size = (tag_size + 0xfff) >> 12; /* round up */
144 141
145 ret = nouveau_mm_tail(&pfb->vram, 0, tag_size, tag_size, 1, 142 ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1,
146 &priv->tag_ram); 143 &priv->tag_ram);
147 if (ret) { 144 if (ret) {
148 priv->num_tags = 0; 145 priv->num_tags = 0;
@@ -152,7 +149,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
152 tag_base += tag_align - 1; 149 tag_base += tag_align - 1;
153 ret = do_div(tag_base, tag_align); 150 ret = do_div(tag_base, tag_align);
154 151
155 nv_wr32(priv, 0x17e8d4, tag_base); 152 priv->tag_base = tag_base;
156 } 153 }
157 ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1); 154 ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);
158 155
@@ -182,8 +179,6 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
182 } 179 }
183 priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; 180 priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28;
184 181
185 nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
186
187 ret = nvc0_ltcg_init_tag_ram(pfb, priv); 182 ret = nvc0_ltcg_init_tag_ram(pfb, priv);
188 if (ret) 183 if (ret)
189 return ret; 184 return ret;
@@ -209,13 +204,32 @@ nvc0_ltcg_dtor(struct nouveau_object *object)
209 nouveau_ltcg_destroy(ltcg); 204 nouveau_ltcg_destroy(ltcg);
210} 205}
211 206
207static int
208nvc0_ltcg_init(struct nouveau_object *object)
209{
210 struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
211 struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
212 int ret;
213
214 ret = nouveau_ltcg_init(ltcg);
215 if (ret)
216 return ret;
217
218 nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
219 nv_wr32(priv, 0x17e8d8, priv->part_nr);
220 if (nv_device(ltcg)->card_type >= NV_E0)
221 nv_wr32(priv, 0x17e000, priv->part_nr);
222 nv_wr32(priv, 0x17e8d4, priv->tag_base);
223 return 0;
224}
225
212struct nouveau_oclass 226struct nouveau_oclass
213nvc0_ltcg_oclass = { 227nvc0_ltcg_oclass = {
214 .handle = NV_SUBDEV(LTCG, 0xc0), 228 .handle = NV_SUBDEV(LTCG, 0xc0),
215 .ofuncs = &(struct nouveau_ofuncs) { 229 .ofuncs = &(struct nouveau_ofuncs) {
216 .ctor = nvc0_ltcg_ctor, 230 .ctor = nvc0_ltcg_ctor,
217 .dtor = nvc0_ltcg_dtor, 231 .dtor = nvc0_ltcg_dtor,
218 .init = _nouveau_ltcg_init, 232 .init = nvc0_ltcg_init,
219 .fini = _nouveau_ltcg_fini, 233 .fini = _nouveau_ltcg_fini,
220 }, 234 },
221}; 235};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
index 2e7c5fd3de3d..20f9a538746e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
@@ -86,7 +86,9 @@ _nouveau_mc_dtor(struct nouveau_object *object)
86 86
87int 87int
88nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, 88nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
89 struct nouveau_oclass *oclass, int length, void **pobject) 89 struct nouveau_oclass *oclass,
90 const struct nouveau_mc_intr *intr_map,
91 int length, void **pobject)
90{ 92{
91 struct nouveau_device *device = nv_device(parent); 93 struct nouveau_device *device = nv_device(parent);
92 struct nouveau_mc *pmc; 94 struct nouveau_mc *pmc;
@@ -98,6 +100,8 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
98 if (ret) 100 if (ret)
99 return ret; 101 return ret;
100 102
103 pmc->intr_map = intr_map;
104
101 ret = request_irq(device->pdev->irq, nouveau_mc_intr, 105 ret = request_irq(device->pdev->irq, nouveau_mc_intr,
102 IRQF_SHARED, "nouveau", pmc); 106 IRQF_SHARED, "nouveau", pmc);
103 if (ret < 0) 107 if (ret < 0)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
index 8c769715227b..64aa4edb0d9d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
@@ -50,12 +50,11 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
50 struct nv04_mc_priv *priv; 50 struct nv04_mc_priv *priv;
51 int ret; 51 int ret;
52 52
53 ret = nouveau_mc_create(parent, engine, oclass, &priv); 53 ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
54 *pobject = nv_object(priv); 54 *pobject = nv_object(priv);
55 if (ret) 55 if (ret)
56 return ret; 56 return ret;
57 57
58 priv->base.intr_map = nv04_mc_intr;
59 return 0; 58 return 0;
60} 59}
61 60
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
index 51919371810f..d9891782bf28 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
@@ -36,12 +36,11 @@ nv44_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
36 struct nv44_mc_priv *priv; 36 struct nv44_mc_priv *priv;
37 int ret; 37 int ret;
38 38
39 ret = nouveau_mc_create(parent, engine, oclass, &priv); 39 ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
40 *pobject = nv_object(priv); 40 *pobject = nv_object(priv);
41 if (ret) 41 if (ret)
42 return ret; 42 return ret;
43 43
44 priv->base.intr_map = nv04_mc_intr;
45 return 0; 44 return 0;
46} 45}
47 46
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
index 0cb322a5e72c..2b1afe225db8 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
@@ -41,7 +41,7 @@ nv50_mc_intr[] = {
41 { 0x04000000, NVDEV_ENGINE_DISP }, 41 { 0x04000000, NVDEV_ENGINE_DISP },
42 { 0x10000000, NVDEV_SUBDEV_BUS }, 42 { 0x10000000, NVDEV_SUBDEV_BUS },
43 { 0x80000000, NVDEV_ENGINE_SW }, 43 { 0x80000000, NVDEV_ENGINE_SW },
44 { 0x0000d101, NVDEV_SUBDEV_FB }, 44 { 0x0002d101, NVDEV_SUBDEV_FB },
45 {}, 45 {},
46}; 46};
47 47
@@ -53,12 +53,11 @@ nv50_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
53 struct nv50_mc_priv *priv; 53 struct nv50_mc_priv *priv;
54 int ret; 54 int ret;
55 55
56 ret = nouveau_mc_create(parent, engine, oclass, &priv); 56 ret = nouveau_mc_create(parent, engine, oclass, nv50_mc_intr, &priv);
57 *pobject = nv_object(priv); 57 *pobject = nv_object(priv);
58 if (ret) 58 if (ret)
59 return ret; 59 return ret;
60 60
61 priv->base.intr_map = nv50_mc_intr;
62 return 0; 61 return 0;
63} 62}
64 63
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
index e82fd21b5041..0d57b4d3e001 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
@@ -54,12 +54,11 @@ nv98_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
54 struct nv98_mc_priv *priv; 54 struct nv98_mc_priv *priv;
55 int ret; 55 int ret;
56 56
57 ret = nouveau_mc_create(parent, engine, oclass, &priv); 57 ret = nouveau_mc_create(parent, engine, oclass, nv98_mc_intr, &priv);
58 *pobject = nv_object(priv); 58 *pobject = nv_object(priv);
59 if (ret) 59 if (ret)
60 return ret; 60 return ret;
61 61
62 priv->base.intr_map = nv98_mc_intr;
63 return 0; 62 return 0;
64} 63}
65 64
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
index c5da3babbc62..104175c5a2dd 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
@@ -57,12 +57,11 @@ nvc0_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
57 struct nvc0_mc_priv *priv; 57 struct nvc0_mc_priv *priv;
58 int ret; 58 int ret;
59 59
60 ret = nouveau_mc_create(parent, engine, oclass, &priv); 60 ret = nouveau_mc_create(parent, engine, oclass, nvc0_mc_intr, &priv);
61 *pobject = nv_object(priv); 61 *pobject = nv_object(priv);
62 if (ret) 62 if (ret)
63 return ret; 63 return ret;
64 64
65 priv->base.intr_map = nvc0_mc_intr;
66 return 0; 65 return 0;
67} 66}
68 67
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
index 67fcb6c852ac..ef3133e7575c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
361 361
362 INIT_LIST_HEAD(&vm->pgd_list); 362 INIT_LIST_HEAD(&vm->pgd_list);
363 vm->vmm = vmm; 363 vm->vmm = vmm;
364 vm->refcount = 1; 364 kref_init(&vm->refcount);
365 vm->fpde = offset >> (vmm->pgt_bits + 12); 365 vm->fpde = offset >> (vmm->pgt_bits + 12);
366 vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12); 366 vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
367 367
@@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
441} 441}
442 442
443static void 443static void
444nouveau_vm_del(struct nouveau_vm *vm) 444nouveau_vm_del(struct kref *kref)
445{ 445{
446 struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
446 struct nouveau_vm_pgd *vpgd, *tmp; 447 struct nouveau_vm_pgd *vpgd, *tmp;
447 448
448 list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { 449 list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
@@ -458,27 +459,19 @@ int
458nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr, 459nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
459 struct nouveau_gpuobj *pgd) 460 struct nouveau_gpuobj *pgd)
460{ 461{
461 struct nouveau_vm *vm; 462 if (ref) {
462 int ret; 463 int ret = nouveau_vm_link(ref, pgd);
463
464 vm = ref;
465 if (vm) {
466 ret = nouveau_vm_link(vm, pgd);
467 if (ret) 464 if (ret)
468 return ret; 465 return ret;
469 466
470 vm->refcount++; 467 kref_get(&ref->refcount);
471 } 468 }
472 469
473 vm = *ptr; 470 if (*ptr) {
474 *ptr = ref; 471 nouveau_vm_unlink(*ptr, pgd);
475 472 kref_put(&(*ptr)->refcount, nouveau_vm_del);
476 if (vm) {
477 nouveau_vm_unlink(vm, pgd);
478
479 if (--vm->refcount == 0)
480 nouveau_vm_del(vm);
481 } 473 }
482 474
475 *ptr = ref;
483 return 0; 476 return 0;
484} 477}
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 6413552df21c..d4fbf11360fe 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -607,6 +607,24 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
607 regp->ramdac_a34 = 0x1; 607 regp->ramdac_a34 = 0x1;
608} 608}
609 609
610static int
611nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
612{
613 struct nv04_display *disp = nv04_display(crtc->dev);
614 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
615 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
616 int ret;
617
618 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
619 if (ret == 0) {
620 if (disp->image[nv_crtc->index])
621 nouveau_bo_unpin(disp->image[nv_crtc->index]);
622 nouveau_bo_ref(nvfb->nvbo, &disp->image[nv_crtc->index]);
623 }
624
625 return ret;
626}
627
610/** 628/**
611 * Sets up registers for the given mode/adjusted_mode pair. 629 * Sets up registers for the given mode/adjusted_mode pair.
612 * 630 *
@@ -623,10 +641,15 @@ nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
623 struct drm_device *dev = crtc->dev; 641 struct drm_device *dev = crtc->dev;
624 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 642 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
625 struct nouveau_drm *drm = nouveau_drm(dev); 643 struct nouveau_drm *drm = nouveau_drm(dev);
644 int ret;
626 645
627 NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index); 646 NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index);
628 drm_mode_debug_printmodeline(adjusted_mode); 647 drm_mode_debug_printmodeline(adjusted_mode);
629 648
649 ret = nv_crtc_swap_fbs(crtc, old_fb);
650 if (ret)
651 return ret;
652
630 /* unlock must come after turning off FP_TG_CONTROL in output_prepare */ 653 /* unlock must come after turning off FP_TG_CONTROL in output_prepare */
631 nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1); 654 nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1);
632 655
@@ -723,6 +746,7 @@ static void nv_crtc_commit(struct drm_crtc *crtc)
723 746
724static void nv_crtc_destroy(struct drm_crtc *crtc) 747static void nv_crtc_destroy(struct drm_crtc *crtc)
725{ 748{
749 struct nv04_display *disp = nv04_display(crtc->dev);
726 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 750 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
727 751
728 if (!nv_crtc) 752 if (!nv_crtc)
@@ -730,6 +754,10 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
730 754
731 drm_crtc_cleanup(crtc); 755 drm_crtc_cleanup(crtc);
732 756
757 if (disp->image[nv_crtc->index])
758 nouveau_bo_unpin(disp->image[nv_crtc->index]);
759 nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
760
733 nouveau_bo_unmap(nv_crtc->cursor.nvbo); 761 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
734 nouveau_bo_unpin(nv_crtc->cursor.nvbo); 762 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
735 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); 763 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
@@ -755,6 +783,16 @@ nv_crtc_gamma_load(struct drm_crtc *crtc)
755} 783}
756 784
757static void 785static void
786nv_crtc_disable(struct drm_crtc *crtc)
787{
788 struct nv04_display *disp = nv04_display(crtc->dev);
789 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
790 if (disp->image[nv_crtc->index])
791 nouveau_bo_unpin(disp->image[nv_crtc->index]);
792 nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
793}
794
795static void
758nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, 796nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
759 uint32_t size) 797 uint32_t size)
760{ 798{
@@ -792,7 +830,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
792 struct drm_framebuffer *drm_fb; 830 struct drm_framebuffer *drm_fb;
793 struct nouveau_framebuffer *fb; 831 struct nouveau_framebuffer *fb;
794 int arb_burst, arb_lwm; 832 int arb_burst, arb_lwm;
795 int ret;
796 833
797 NV_DEBUG(drm, "index %d\n", nv_crtc->index); 834 NV_DEBUG(drm, "index %d\n", nv_crtc->index);
798 835
@@ -802,10 +839,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
802 return 0; 839 return 0;
803 } 840 }
804 841
805
806 /* If atomic, we want to switch to the fb we were passed, so 842 /* If atomic, we want to switch to the fb we were passed, so
807 * now we update pointers to do that. (We don't pin; just 843 * now we update pointers to do that.
808 * assume we're already pinned and update the base address.)
809 */ 844 */
810 if (atomic) { 845 if (atomic) {
811 drm_fb = passed_fb; 846 drm_fb = passed_fb;
@@ -813,17 +848,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
813 } else { 848 } else {
814 drm_fb = crtc->fb; 849 drm_fb = crtc->fb;
815 fb = nouveau_framebuffer(crtc->fb); 850 fb = nouveau_framebuffer(crtc->fb);
816 /* If not atomic, we can go ahead and pin, and unpin the
817 * old fb we were passed.
818 */
819 ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
820 if (ret)
821 return ret;
822
823 if (passed_fb) {
824 struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
825 nouveau_bo_unpin(ofb->nvbo);
826 }
827 } 851 }
828 852
829 nv_crtc->fb.offset = fb->nvbo->bo.offset; 853 nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -878,6 +902,9 @@ static int
878nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 902nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
879 struct drm_framebuffer *old_fb) 903 struct drm_framebuffer *old_fb)
880{ 904{
905 int ret = nv_crtc_swap_fbs(crtc, old_fb);
906 if (ret)
907 return ret;
881 return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false); 908 return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
882} 909}
883 910
@@ -1074,6 +1101,7 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
1074 .mode_set_base = nv04_crtc_mode_set_base, 1101 .mode_set_base = nv04_crtc_mode_set_base,
1075 .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic, 1102 .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
1076 .load_lut = nv_crtc_gamma_load, 1103 .load_lut = nv_crtc_gamma_load,
1104 .disable = nv_crtc_disable,
1077}; 1105};
1078 1106
1079int 1107int
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index a0a031dad13f..9928187f0a7d 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -81,6 +81,7 @@ struct nv04_display {
81 uint32_t saved_vga_font[4][16384]; 81 uint32_t saved_vga_font[4][16384];
82 uint32_t dac_users[4]; 82 uint32_t dac_users[4];
83 struct nouveau_object *core; 83 struct nouveau_object *core;
84 struct nouveau_bo *image[2];
84}; 85};
85 86
86static inline struct nv04_display * 87static inline struct nv04_display *
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index e4444bacd0b2..755c38d06271 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -198,7 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
198 size_t acc_size; 198 size_t acc_size;
199 int ret; 199 int ret;
200 int type = ttm_bo_type_device; 200 int type = ttm_bo_type_device;
201 int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1); 201 int lpg_shift = 12;
202 int max_size;
203
204 if (drm->client.base.vm)
205 lpg_shift = drm->client.base.vm->vmm->lpg_shift;
206 max_size = INT_MAX & ~((1 << lpg_shift) - 1);
202 207
203 if (size <= 0 || size > max_size) { 208 if (size <= 0 || size > max_size) {
204 nv_warn(drm, "skipped size %x\n", (u32)size); 209 nv_warn(drm, "skipped size %x\n", (u32)size);
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 44202bf7b819..77ffded68837 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -580,6 +580,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
580 ret = nv50_display_flip_next(crtc, fb, chan, 0); 580 ret = nv50_display_flip_next(crtc, fb, chan, 0);
581 if (ret) 581 if (ret)
582 goto fail_unreserve; 582 goto fail_unreserve;
583 } else {
584 struct nv04_display *dispnv04 = nv04_display(dev);
585 nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]);
583 } 586 }
584 587
585 ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); 588 ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 4c1bc061fae2..8f6d63d7edd3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -398,7 +398,8 @@ void
398nouveau_fbcon_output_poll_changed(struct drm_device *dev) 398nouveau_fbcon_output_poll_changed(struct drm_device *dev)
399{ 399{
400 struct nouveau_drm *drm = nouveau_drm(dev); 400 struct nouveau_drm *drm = nouveau_drm(dev);
401 drm_fb_helper_hotplug_event(&drm->fbcon->helper); 401 if (drm->fbcon)
402 drm_fb_helper_hotplug_event(&drm->fbcon->helper);
402} 403}
403 404
404static int 405static int
diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c
index 8e47a9bae8c3..22aa9963ea6f 100644
--- a/drivers/gpu/drm/nouveau/nv17_fence.c
+++ b/drivers/gpu/drm/nouveau/nv17_fence.c
@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
76 struct ttm_mem_reg *mem = &priv->bo->bo.mem; 76 struct ttm_mem_reg *mem = &priv->bo->bo.mem;
77 struct nouveau_object *object; 77 struct nouveau_object *object;
78 u32 start = mem->start * PAGE_SIZE; 78 u32 start = mem->start * PAGE_SIZE;
79 u32 limit = mem->start + mem->size - 1; 79 u32 limit = start + mem->size - 1;
80 int ret = 0; 80 int ret = 0;
81 81
82 fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); 82 fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
index 3af5bcd0b203..625f80d53dc2 100644
--- a/drivers/gpu/drm/nouveau/nv40_pm.c
+++ b/drivers/gpu/drm/nouveau/nv40_pm.c
@@ -131,7 +131,7 @@ nv40_calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll,
131 if (clk < pll->vco1.max_freq) 131 if (clk < pll->vco1.max_freq)
132 pll->vco2.max_freq = 0; 132 pll->vco2.max_freq = 0;
133 133
134 pclk->pll_calc(pclk, pll, clk, &coef); 134 ret = pclk->pll_calc(pclk, pll, clk, &coef);
135 if (ret == 0) 135 if (ret == 0)
136 return -ERANGE; 136 return -ERANGE;
137 137
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c
index f9701e567db8..0ee363840035 100644
--- a/drivers/gpu/drm/nouveau/nv50_fence.c
+++ b/drivers/gpu/drm/nouveau/nv50_fence.c
@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
39 struct nv10_fence_chan *fctx; 39 struct nv10_fence_chan *fctx;
40 struct ttm_mem_reg *mem = &priv->bo->bo.mem; 40 struct ttm_mem_reg *mem = &priv->bo->bo.mem;
41 struct nouveau_object *object; 41 struct nouveau_object *object;
42 u32 start = mem->start * PAGE_SIZE;
43 u32 limit = start + mem->size - 1;
42 int ret, i; 44 int ret, i;
43 45
44 fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); 46 fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan)
51 fctx->base.sync = nv17_fence_sync; 53 fctx->base.sync = nv17_fence_sync;
52 54
53 ret = nouveau_object_new(nv_object(chan->cli), chan->handle, 55 ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
54 NvSema, 0x0002, 56 NvSema, 0x003d,
55 &(struct nv_dma_class) { 57 &(struct nv_dma_class) {
56 .flags = NV_DMA_TARGET_VRAM | 58 .flags = NV_DMA_TARGET_VRAM |
57 NV_DMA_ACCESS_RDWR, 59 NV_DMA_ACCESS_RDWR,
58 .start = mem->start * PAGE_SIZE, 60 .start = start,
59 .limit = mem->size - 1, 61 .limit = limit,
60 }, sizeof(struct nv_dma_class), 62 }, sizeof(struct nv_dma_class),
61 &object); 63 &object);
62 64
63 /* dma objects for display sync channel semaphore blocks */ 65 /* dma objects for display sync channel semaphore blocks */
64 for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) { 66 for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
65 struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i); 67 struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
68 u32 start = bo->bo.mem.start * PAGE_SIZE;
69 u32 limit = start + bo->bo.mem.size - 1;
66 70
67 ret = nouveau_object_new(nv_object(chan->cli), chan->handle, 71 ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
68 NvEvoSema0 + i, 0x003d, 72 NvEvoSema0 + i, 0x003d,
69 &(struct nv_dma_class) { 73 &(struct nv_dma_class) {
70 .flags = NV_DMA_TARGET_VRAM | 74 .flags = NV_DMA_TARGET_VRAM |
71 NV_DMA_ACCESS_RDWR, 75 NV_DMA_ACCESS_RDWR,
72 .start = bo->bo.offset, 76 .start = start,
73 .limit = bo->bo.offset + 0xfff, 77 .limit = limit,
74 }, sizeof(struct nv_dma_class), 78 }, sizeof(struct nv_dma_class),
75 &object); 79 &object);
76 } 80 }