aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-08-09 14:10:27 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-08-09 15:28:10 -0400
commit4952b4d339033c2019bbd00f28f422b6fc340408 (patch)
tree10b610a3ca4d2b7e60e6795fc33e784e809bf2e8 /drivers/gpu
parent67cb49c45feba4141ed4b962855249d30302cd7d (diff)
drm/nouveau/disp: audit and version SCANOUTPOS method
The full object interfaces are about to be exposed to userspace, so we need to check for any security-related issues and version the structs to make it easier to handle any changes we may need in the future. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/gm107.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv04.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c61
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.h33
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv84.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv94.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva3.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c66
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/class.h21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c22
-rw-r--r--drivers/gpu/drm/nouveau/nvif/class.h23
-rw-r--r--drivers/gpu/drm/nouveau/nvif/object.h1
15 files changed, 204 insertions, 172 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
index f93d76e040fe..6a25f38d7fbf 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
@@ -45,7 +45,7 @@ gm107_disp_sclass[] = {
45 45
46static struct nouveau_oclass 46static struct nouveau_oclass
47gm107_disp_base_oclass[] = { 47gm107_disp_base_oclass[] = {
48 { GM107_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, 48 { GM107_DISP_CLASS, &nvd0_disp_base_ofuncs },
49 {} 49 {}
50}; 50};
51 51
@@ -99,4 +99,5 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
99 .mthd.base = &nvd0_disp_sync_mthd_chan, 99 .mthd.base = &nvd0_disp_sync_mthd_chan,
100 .mthd.ovly = &nve0_disp_ovly_mthd_chan, 100 .mthd.ovly = &nve0_disp_ovly_mthd_chan,
101 .mthd.prev = -0x020000, 101 .mthd.prev = -0x020000,
102 .head.scanoutpos = nvd0_disp_base_scanoutpos,
102}.base.base; 103}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
index f1f3bd15a5c0..6dba53df35fc 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
@@ -24,60 +24,100 @@
24 24
25#include "priv.h" 25#include "priv.h"
26 26
27#include <core/client.h>
27#include <core/event.h> 28#include <core/event.h>
28#include <core/class.h> 29#include <core/class.h>
30#include <nvif/unpack.h>
31#include <nvif/class.h>
29 32
30struct nv04_disp_priv { 33struct nv04_disp_priv {
31 struct nouveau_disp base; 34 struct nouveau_disp base;
32}; 35};
33 36
34static int 37static int
35nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd, 38nv04_disp_scanoutpos(struct nouveau_object *object, struct nv04_disp_priv *priv,
36 void *data, u32 size) 39 void *data, u32 size, int head)
37{ 40{
38 struct nv04_disp_priv *priv = (void *)object->engine; 41 const u32 hoff = head * 0x2000;
39 struct nv04_display_scanoutpos *args = data; 42 union {
40 const int head = (mthd & NV04_DISP_MTHD_HEAD); 43 struct nv04_disp_scanoutpos_v0 v0;
44 } *args = data;
41 u32 line; 45 u32 line;
46 int ret;
47
48 nv_ioctl(object, "disp scanoutpos size %d\n", size);
49 if (nvif_unpack(args->v0, 0, 0, false)) {
50 nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
51 args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
52 args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
53 args->v0.vblanke = args->v0.vtotal - 1;
54
55 args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
56 args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
57 args->v0.hblanke = args->v0.htotal - 1;
58
59 /*
60 * If output is vga instead of digital then vtotal/htotal is
61 * invalid so we have to give up and trigger the timestamping
62 * fallback in the drm core.
63 */
64 if (!args->v0.vtotal || !args->v0.htotal)
65 return -ENOTSUPP;
66
67 args->v0.time[0] = ktime_to_ns(ktime_get());
68 line = nv_rd32(priv, 0x600868 + hoff);
69 args->v0.time[1] = ktime_to_ns(ktime_get());
70 args->v0.hline = (line & 0xffff0000) >> 16;
71 args->v0.vline = (line & 0x0000ffff);
72 } else
73 return ret;
42 74
43 if (size < sizeof(*args))
44 return -EINVAL;
45
46 args->vblanks = nv_rd32(priv, 0x680800 + (head * 0x2000)) & 0xffff;
47 args->vtotal = nv_rd32(priv, 0x680804 + (head * 0x2000)) & 0xffff;
48 args->vblanke = args->vtotal - 1;
49
50 args->hblanks = nv_rd32(priv, 0x680820 + (head * 0x2000)) & 0xffff;
51 args->htotal = nv_rd32(priv, 0x680824 + (head * 0x2000)) & 0xffff;
52 args->hblanke = args->htotal - 1;
53
54 /*
55 * If output is vga instead of digital then vtotal/htotal is invalid
56 * so we have to give up and trigger the timestamping fallback in the
57 * drm core.
58 */
59 if (!args->vtotal || !args->htotal)
60 return -ENOTSUPP;
61
62 args->time[0] = ktime_to_ns(ktime_get());
63 line = nv_rd32(priv, 0x600868 + (head * 0x2000));
64 args->time[1] = ktime_to_ns(ktime_get());
65 args->hline = (line & 0xffff0000) >> 16;
66 args->vline = (line & 0x0000ffff);
67 return 0; 75 return 0;
68} 76}
69 77
70#define HEAD_MTHD(n) (n), (n) + 0x01 78static int
79nv04_disp_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
80{
81 union {
82 struct nv04_disp_mthd_v0 v0;
83 } *args = data;
84 struct nv04_disp_priv *priv = (void *)object->engine;
85 int head, ret;
86
87 nv_ioctl(object, "disp mthd size %d\n", size);
88 if (nvif_unpack(args->v0, 0, 0, true)) {
89 nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
90 args->v0.version, args->v0.method, args->v0.head);
91 mthd = args->v0.method;
92 head = args->v0.head;
93 } else
94 return ret;
95
96 if (head < 0 || head >= 2)
97 return -ENXIO;
98
99 switch (mthd) {
100 case NV04_DISP_SCANOUTPOS:
101 return nv04_disp_scanoutpos(object, priv, data, size, head);
102 default:
103 break;
104 }
105
106 return -EINVAL;
107}
71 108
72static struct nouveau_omthds 109static struct nouveau_ofuncs
73nv04_disp_omthds[] = { 110nv04_disp_ofuncs = {
74 { HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos }, 111 .ctor = _nouveau_object_ctor,
75 {} 112 .dtor = nouveau_object_destroy,
113 .init = nouveau_object_init,
114 .fini = nouveau_object_fini,
115 .mthd = nv04_disp_mthd,
76}; 116};
77 117
78static struct nouveau_oclass 118static struct nouveau_oclass
79nv04_disp_sclass[] = { 119nv04_disp_sclass[] = {
80 { NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds }, 120 { NV04_DISP_CLASS, &nv04_disp_ofuncs },
81 {}, 121 {},
82}; 122};
83 123
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index d83d3efe8253..7e60c11d7d36 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -814,31 +814,34 @@ nv50_disp_curs_ofuncs = {
814 ******************************************************************************/ 814 ******************************************************************************/
815 815
816int 816int
817nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, 817nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
818 void *data, u32 size)
819{ 818{
820 struct nv50_disp_priv *priv = (void *)object->engine; 819 const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
821 struct nv04_display_scanoutpos *args = data; 820 const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
822 const int head = (mthd & NV50_DISP_MTHD_HEAD); 821 const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540));
823 u32 blanke, blanks, total; 822 union {
823 struct nv04_disp_scanoutpos_v0 v0;
824 } *args = data;
825 int ret;
826
827 nv_ioctl(object, "disp scanoutpos size %d\n", size);
828 if (nvif_unpack(args->v0, 0, 0, false)) {
829 nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
830 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
831 args->v0.hblanke = (blanke & 0x0000ffff);
832 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
833 args->v0.hblanks = (blanks & 0x0000ffff);
834 args->v0.vtotal = ( total & 0xffff0000) >> 16;
835 args->v0.htotal = ( total & 0x0000ffff);
836 args->v0.time[0] = ktime_to_ns(ktime_get());
837 args->v0.vline = /* vline read locks hline */
838 nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
839 args->v0.time[1] = ktime_to_ns(ktime_get());
840 args->v0.hline =
841 nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
842 } else
843 return ret;
824 844
825 if (size < sizeof(*args) || head >= priv->head.nr)
826 return -EINVAL;
827 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
828 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
829 total = nv_rd32(priv, 0x610afc + (head * 0x540));
830
831 args->vblanke = (blanke & 0xffff0000) >> 16;
832 args->hblanke = (blanke & 0x0000ffff);
833 args->vblanks = (blanks & 0xffff0000) >> 16;
834 args->hblanks = (blanks & 0x0000ffff);
835 args->vtotal = ( total & 0xffff0000) >> 16;
836 args->htotal = ( total & 0x0000ffff);
837
838 args->time[0] = ktime_to_ns(ktime_get());
839 args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
840 args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
841 args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
842 return 0; 845 return 0;
843} 846}
844 847
@@ -846,6 +849,7 @@ int
846nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd, 849nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
847 void *data, u32 size) 850 void *data, u32 size)
848{ 851{
852 const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
849 union { 853 union {
850 struct nv50_disp_mthd_v0 v0; 854 struct nv50_disp_mthd_v0 v0;
851 struct nv50_disp_mthd_v1 v1; 855 struct nv50_disp_mthd_v1 v1;
@@ -894,6 +898,8 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
894 } 898 }
895 899
896 switch (mthd) { 900 switch (mthd) {
901 case NV50_DISP_SCANOUTPOS:
902 return impl->head.scanoutpos(object, priv, data, size, head);
897 default: 903 default:
898 break; 904 break;
899 } 905 }
@@ -1081,15 +1087,9 @@ nv50_disp_base_ofuncs = {
1081 .mthd = nv50_disp_base_mthd, 1087 .mthd = nv50_disp_base_mthd,
1082}; 1088};
1083 1089
1084static struct nouveau_omthds
1085nv50_disp_base_omthds[] = {
1086 { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
1087 {},
1088};
1089
1090static struct nouveau_oclass 1090static struct nouveau_oclass
1091nv50_disp_base_oclass[] = { 1091nv50_disp_base_oclass[] = {
1092 { NV50_DISP_CLASS, &nv50_disp_base_ofuncs, nv50_disp_base_omthds }, 1092 { NV50_DISP_CLASS, &nv50_disp_base_ofuncs },
1093 {} 1093 {}
1094}; 1094};
1095 1095
@@ -1859,4 +1859,5 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
1859 .mthd.base = &nv50_disp_sync_mthd_chan, 1859 .mthd.base = &nv50_disp_sync_mthd_chan,
1860 .mthd.ovly = &nv50_disp_ovly_mthd_chan, 1860 .mthd.ovly = &nv50_disp_ovly_mthd_chan,
1861 .mthd.prev = 0x000004, 1861 .mthd.prev = 0x000004,
1862 .head.scanoutpos = nv50_disp_base_scanoutpos,
1862}.base.base; 1863}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
index 62a38b5f0024..81bf80fd8dcd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
@@ -14,16 +14,6 @@
14#include "outp.h" 14#include "outp.h"
15#include "outpdp.h" 15#include "outpdp.h"
16 16
17struct nv50_disp_impl {
18 struct nouveau_disp_impl base;
19 struct {
20 const struct nv50_disp_mthd_chan *core;
21 const struct nv50_disp_mthd_chan *base;
22 const struct nv50_disp_mthd_chan *ovly;
23 int prev;
24 } mthd;
25};
26
27#define NV50_DISP_MTHD_ struct nouveau_object *object, \ 17#define NV50_DISP_MTHD_ struct nouveau_object *object, \
28 struct nv50_disp_priv *priv, void *data, u32 size 18 struct nv50_disp_priv *priv, void *data, u32 size
29#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head 19#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
@@ -58,18 +48,27 @@ struct nv50_disp_priv {
58 } pior; 48 } pior;
59}; 49};
60 50
61#define HEAD_MTHD(n) (n), (n) + 0x03 51struct nv50_disp_impl {
52 struct nouveau_disp_impl base;
53 struct {
54 const struct nv50_disp_mthd_chan *core;
55 const struct nv50_disp_mthd_chan *base;
56 const struct nv50_disp_mthd_chan *ovly;
57 int prev;
58 } mthd;
59 struct {
60 int (*scanoutpos)(NV50_DISP_MTHD_V0);
61 } head;
62};
62 63
63int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32); 64int nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
64int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32); 65int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);
65 66
66#define DAC_MTHD(n) (n), (n) + 0x03 67int nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
67 68
68int nv50_dac_power(NV50_DISP_MTHD_V1); 69int nv50_dac_power(NV50_DISP_MTHD_V1);
69int nv50_dac_sense(NV50_DISP_MTHD_V1); 70int nv50_dac_sense(NV50_DISP_MTHD_V1);
70 71
71#define SOR_MTHD(n) (n), (n) + 0x3f
72
73int nva3_hda_eld(NV50_DISP_MTHD_V1); 72int nva3_hda_eld(NV50_DISP_MTHD_V1);
74int nvd0_hda_eld(NV50_DISP_MTHD_V1); 73int nvd0_hda_eld(NV50_DISP_MTHD_V1);
75 74
@@ -97,8 +96,6 @@ int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
97int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, 96int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
98 struct dcb_output *); 97 struct dcb_output *);
99 98
100#define PIOR_MTHD(n) (n), (n) + 0x03
101
102int nv50_pior_power(NV50_DISP_MTHD_V1); 99int nv50_pior_power(NV50_DISP_MTHD_V1);
103 100
104struct nv50_disp_base { 101struct nv50_disp_base {
@@ -203,7 +200,6 @@ extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
203extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head; 200extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head;
204extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan; 201extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan;
205extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan; 202extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
206extern struct nouveau_omthds nv84_disp_base_omthds[];
207 203
208extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan; 204extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan;
209 205
@@ -217,7 +213,6 @@ extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
217extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan; 213extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan;
218extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs; 214extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
219extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs; 215extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
220extern struct nouveau_omthds nvd0_disp_base_omthds[];
221extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; 216extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
222extern struct nouveau_oclass nvd0_disp_cclass; 217extern struct nouveau_oclass nvd0_disp_cclass;
223void nvd0_disp_intr_supervisor(struct work_struct *); 218void nvd0_disp_intr_supervisor(struct work_struct *);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
index c0012d8a450a..8746644d9ded 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
@@ -212,15 +212,9 @@ nv84_disp_sclass[] = {
212 {} 212 {}
213}; 213};
214 214
215struct nouveau_omthds
216nv84_disp_base_omthds[] = {
217 { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
218 {},
219};
220
221static struct nouveau_oclass 215static struct nouveau_oclass
222nv84_disp_base_oclass[] = { 216nv84_disp_base_oclass[] = {
223 { NV84_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds }, 217 { NV84_DISP_CLASS, &nv50_disp_base_ofuncs },
224 {} 218 {}
225}; 219};
226 220
@@ -274,4 +268,5 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
274 .mthd.base = &nv84_disp_sync_mthd_chan, 268 .mthd.base = &nv84_disp_sync_mthd_chan,
275 .mthd.ovly = &nv84_disp_ovly_mthd_chan, 269 .mthd.ovly = &nv84_disp_ovly_mthd_chan,
276 .mthd.prev = 0x000004, 270 .mthd.prev = 0x000004,
271 .head.scanoutpos = nv50_disp_base_scanoutpos,
277}.base.base; 272}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
index 192c8085a1dc..11cd16abcee2 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
@@ -71,15 +71,9 @@ nv94_disp_sclass[] = {
71 {} 71 {}
72}; 72};
73 73
74static struct nouveau_omthds
75nv94_disp_base_omthds[] = {
76 { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
77 {},
78};
79
80static struct nouveau_oclass 74static struct nouveau_oclass
81nv94_disp_base_oclass[] = { 75nv94_disp_base_oclass[] = {
82 { NV94_DISP_CLASS, &nv50_disp_base_ofuncs, nv94_disp_base_omthds }, 76 { NV94_DISP_CLASS, &nv50_disp_base_ofuncs },
83 {} 77 {}
84}; 78};
85 79
@@ -140,4 +134,5 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
140 .mthd.base = &nv84_disp_sync_mthd_chan, 134 .mthd.base = &nv84_disp_sync_mthd_chan,
141 .mthd.ovly = &nv84_disp_ovly_mthd_chan, 135 .mthd.ovly = &nv84_disp_ovly_mthd_chan,
142 .mthd.prev = 0x000004, 136 .mthd.prev = 0x000004,
137 .head.scanoutpos = nv50_disp_base_scanoutpos,
143}.base.base; 138}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
index bfd5cf14b0e4..381957586f03 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
@@ -90,7 +90,7 @@ nva0_disp_sclass[] = {
90 90
91static struct nouveau_oclass 91static struct nouveau_oclass
92nva0_disp_base_oclass[] = { 92nva0_disp_base_oclass[] = {
93 { NVA0_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds }, 93 { NVA0_DISP_CLASS, &nv50_disp_base_ofuncs },
94 {} 94 {}
95}; 95};
96 96
@@ -144,4 +144,5 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
144 .mthd.base = &nv84_disp_sync_mthd_chan, 144 .mthd.base = &nv84_disp_sync_mthd_chan,
145 .mthd.ovly = &nva0_disp_ovly_mthd_chan, 145 .mthd.ovly = &nva0_disp_ovly_mthd_chan,
146 .mthd.prev = 0x000004, 146 .mthd.prev = 0x000004,
147 .head.scanoutpos = nv50_disp_base_scanoutpos,
147}.base.base; 148}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
index 38a79a0e358f..25df6b93c93a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
@@ -43,15 +43,9 @@ nva3_disp_sclass[] = {
43 {} 43 {}
44}; 44};
45 45
46static struct nouveau_omthds
47nva3_disp_base_omthds[] = {
48 { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
49 {},
50};
51
52static struct nouveau_oclass 46static struct nouveau_oclass
53nva3_disp_base_oclass[] = { 47nva3_disp_base_oclass[] = {
54 { NVA3_DISP_CLASS, &nv50_disp_base_ofuncs, nva3_disp_base_omthds }, 48 { NVA3_DISP_CLASS, &nv50_disp_base_ofuncs },
55 {} 49 {}
56}; 50};
57 51
@@ -106,4 +100,5 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
106 .mthd.base = &nv84_disp_sync_mthd_chan, 100 .mthd.base = &nv84_disp_sync_mthd_chan,
107 .mthd.ovly = &nv84_disp_ovly_mthd_chan, 101 .mthd.ovly = &nv84_disp_ovly_mthd_chan,
108 .mthd.prev = 0x000004, 102 .mthd.prev = 0x000004,
103 .head.scanoutpos = nv50_disp_base_scanoutpos,
109}.base.base; 104}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 5aa44eca8056..deddd05e7c76 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -23,9 +23,12 @@
23 */ 23 */
24 24
25#include <core/object.h> 25#include <core/object.h>
26#include <core/client.h>
26#include <core/parent.h> 27#include <core/parent.h>
27#include <core/handle.h> 28#include <core/handle.h>
28#include <core/class.h> 29#include <core/class.h>
30#include <nvif/unpack.h>
31#include <nvif/class.h>
29 32
30#include <engine/disp.h> 33#include <engine/disp.h>
31 34
@@ -589,33 +592,35 @@ nvd0_disp_curs_ofuncs = {
589 * Base display object 592 * Base display object
590 ******************************************************************************/ 593 ******************************************************************************/
591 594
592static int 595int
593nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, 596nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
594 void *data, u32 size)
595{ 597{
596 struct nv50_disp_priv *priv = (void *)object->engine; 598 const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300));
597 struct nv04_display_scanoutpos *args = data; 599 const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
598 const int head = (mthd & NV50_DISP_MTHD_HEAD); 600 const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
599 u32 blanke, blanks, total; 601 union {
600 602 struct nv04_disp_scanoutpos_v0 v0;
601 if (size < sizeof(*args) || head >= priv->head.nr) 603 } *args = data;
602 return -EINVAL; 604 int ret;
603 605
604 total = nv_rd32(priv, 0x640414 + (head * 0x300)); 606 nv_ioctl(object, "disp scanoutpos size %d\n", size);
605 blanke = nv_rd32(priv, 0x64041c + (head * 0x300)); 607 if (nvif_unpack(args->v0, 0, 0, false)) {
606 blanks = nv_rd32(priv, 0x640420 + (head * 0x300)); 608 nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
607 609 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
608 args->vblanke = (blanke & 0xffff0000) >> 16; 610 args->v0.hblanke = (blanke & 0x0000ffff);
609 args->hblanke = (blanke & 0x0000ffff); 611 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
610 args->vblanks = (blanks & 0xffff0000) >> 16; 612 args->v0.hblanks = (blanks & 0x0000ffff);
611 args->hblanks = (blanks & 0x0000ffff); 613 args->v0.vtotal = ( total & 0xffff0000) >> 16;
612 args->vtotal = ( total & 0xffff0000) >> 16; 614 args->v0.htotal = ( total & 0x0000ffff);
613 args->htotal = ( total & 0x0000ffff); 615 args->v0.time[0] = ktime_to_ns(ktime_get());
614 616 args->v0.vline = /* vline read locks hline */
615 args->time[0] = ktime_to_ns(ktime_get()); 617 nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
616 args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; 618 args->v0.time[1] = ktime_to_ns(ktime_get());
617 args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */ 619 args->v0.hline =
618 args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; 620 nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
621 } else
622 return ret;
623
619 return 0; 624 return 0;
620} 625}
621 626
@@ -709,15 +714,9 @@ nvd0_disp_base_ofuncs = {
709 .mthd = nv50_disp_base_mthd, 714 .mthd = nv50_disp_base_mthd,
710}; 715};
711 716
712struct nouveau_omthds
713nvd0_disp_base_omthds[] = {
714 { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nvd0_disp_base_scanoutpos },
715 {},
716};
717
718static struct nouveau_oclass 717static struct nouveau_oclass
719nvd0_disp_base_oclass[] = { 718nvd0_disp_base_oclass[] = {
720 { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, 719 { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs },
721 {} 720 {}
722}; 721};
723 722
@@ -1242,4 +1241,5 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
1242 .mthd.base = &nvd0_disp_sync_mthd_chan, 1241 .mthd.base = &nvd0_disp_sync_mthd_chan,
1243 .mthd.ovly = &nvd0_disp_ovly_mthd_chan, 1242 .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
1244 .mthd.prev = -0x020000, 1243 .mthd.prev = -0x020000,
1244 .head.scanoutpos = nvd0_disp_base_scanoutpos,
1245}.base.base; 1245}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
index 49ab742faae9..58b0ac101f16 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
@@ -210,7 +210,7 @@ nve0_disp_sclass[] = {
210 210
211static struct nouveau_oclass 211static struct nouveau_oclass
212nve0_disp_base_oclass[] = { 212nve0_disp_base_oclass[] = {
213 { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, 213 { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs },
214 {} 214 {}
215}; 215};
216 216
@@ -264,4 +264,5 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
264 .mthd.base = &nvd0_disp_sync_mthd_chan, 264 .mthd.base = &nvd0_disp_sync_mthd_chan,
265 .mthd.ovly = &nve0_disp_ovly_mthd_chan, 265 .mthd.ovly = &nve0_disp_ovly_mthd_chan,
266 .mthd.prev = -0x020000, 266 .mthd.prev = -0x020000,
267 .head.scanoutpos = nvd0_disp_base_scanoutpos,
267}.base.base; 268}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
index 448dc912d0ce..b6b01463eb6c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
@@ -45,7 +45,7 @@ nvf0_disp_sclass[] = {
45 45
46static struct nouveau_oclass 46static struct nouveau_oclass
47nvf0_disp_base_oclass[] = { 47nvf0_disp_base_oclass[] = {
48 { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, 48 { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs },
49 {} 49 {}
50}; 50};
51 51
@@ -99,4 +99,5 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
99 .mthd.base = &nvd0_disp_sync_mthd_chan, 99 .mthd.base = &nvd0_disp_sync_mthd_chan,
100 .mthd.ovly = &nve0_disp_ovly_mthd_chan, 100 .mthd.ovly = &nve0_disp_ovly_mthd_chan,
101 .mthd.prev = -0x020000, 101 .mthd.prev = -0x020000,
102 .head.scanoutpos = nvd0_disp_base_scanoutpos,
102}.base.base; 103}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
index 9f8066d252f0..24b85a9ac657 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -8,26 +8,9 @@
8 8
9#define NV04_DISP_CLASS 0x00000046 9#define NV04_DISP_CLASS 0x00000046
10 10
11#define NV04_DISP_MTHD 0x00000000
12#define NV04_DISP_MTHD_HEAD 0x00000001
13
14#define NV04_DISP_SCANOUTPOS 0x00000000
15
16struct nv04_display_class { 11struct nv04_display_class {
17}; 12};
18 13
19struct nv04_display_scanoutpos {
20 s64 time[2];
21 u32 vblanks;
22 u32 vblanke;
23 u32 vtotal;
24 u32 vline;
25 u32 hblanks;
26 u32 hblanke;
27 u32 htotal;
28 u32 hline;
29};
30
31/* 5070: NV50_DISP 14/* 5070: NV50_DISP
32 * 8270: NV84_DISP 15 * 8270: NV84_DISP
33 * 8370: NVA0_DISP 16 * 8370: NVA0_DISP
@@ -49,10 +32,6 @@ struct nv04_display_scanoutpos {
49#define NVF0_DISP_CLASS 0x00009270 32#define NVF0_DISP_CLASS 0x00009270
50#define GM107_DISP_CLASS 0x00009470 33#define GM107_DISP_CLASS 0x00009470
51 34
52#define NV50_DISP_MTHD_HEAD 0x00000003
53
54#define NV50_DISP_SCANOUTPOS 0x00000000
55
56struct nv50_display_class { 35struct nv50_display_class {
57}; 36};
58 37
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index ffea6c4f9b30..f00e56c79ac4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -95,17 +95,22 @@ int
95nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, 95nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
96 ktime_t *stime, ktime_t *etime) 96 ktime_t *stime, ktime_t *etime)
97{ 97{
98 const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index; 98 struct {
99 struct nv04_disp_mthd_v0 base;
100 struct nv04_disp_scanoutpos_v0 scan;
101 } args = {
102 .base.method = NV04_DISP_SCANOUTPOS,
103 .base.head = nouveau_crtc(crtc)->index,
104 };
99 struct nouveau_display *disp = nouveau_display(crtc->dev); 105 struct nouveau_display *disp = nouveau_display(crtc->dev);
100 struct nv04_display_scanoutpos args;
101 int ret, retry = 1; 106 int ret, retry = 1;
102 107
103 do { 108 do {
104 ret = nvif_exec(&disp->disp, mthd, &args, sizeof(args)); 109 ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args));
105 if (ret != 0) 110 if (ret != 0)
106 return 0; 111 return 0;
107 112
108 if (args.vline) { 113 if (args.scan.vline) {
109 ret |= DRM_SCANOUTPOS_ACCURATE; 114 ret |= DRM_SCANOUTPOS_ACCURATE;
110 ret |= DRM_SCANOUTPOS_VALID; 115 ret |= DRM_SCANOUTPOS_VALID;
111 break; 116 break;
@@ -114,10 +119,11 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
114 if (retry) ndelay(crtc->linedur_ns); 119 if (retry) ndelay(crtc->linedur_ns);
115 } while (retry--); 120 } while (retry--);
116 121
117 *hpos = args.hline; 122 *hpos = args.scan.hline;
118 *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline); 123 *vpos = calc(args.scan.vblanks, args.scan.vblanke,
119 if (stime) *stime = ns_to_ktime(args.time[0]); 124 args.scan.vtotal, args.scan.vline);
120 if (etime) *etime = ns_to_ktime(args.time[1]); 125 if (stime) *stime = ns_to_ktime(args.scan.time[0]);
126 if (etime) *etime = ns_to_ktime(args.scan.time[1]);
121 127
122 if (*vpos < 0) 128 if (*vpos < 0)
123 ret |= DRM_SCANOUTPOS_INVBL; 129 ret |= DRM_SCANOUTPOS_INVBL;
diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h
index f869f94d41c1..b0998e7a5396 100644
--- a/drivers/gpu/drm/nouveau/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/nvif/class.h
@@ -294,6 +294,28 @@ struct kepler_channel_gpfifo_a_v0 {
294 * legacy display 294 * legacy display
295 ******************************************************************************/ 295 ******************************************************************************/
296 296
297struct nv04_disp_mthd_v0 {
298 __u8 version;
299#define NV04_DISP_SCANOUTPOS 0x00
300 __u8 method;
301 __u8 head;
302 __u8 pad03[5];
303};
304
305struct nv04_disp_scanoutpos_v0 {
306 __u8 version;
307 __u8 pad01[7];
308 __s64 time[2];
309 __u16 vblanks;
310 __u16 vblanke;
311 __u16 vtotal;
312 __u16 vline;
313 __u16 hblanks;
314 __u16 hblanke;
315 __u16 htotal;
316 __u16 hline;
317};
318
297 319
298/******************************************************************************* 320/*******************************************************************************
299 * display 321 * display
@@ -303,6 +325,7 @@ struct kepler_channel_gpfifo_a_v0 {
303 325
304struct nv50_disp_mthd_v0 { 326struct nv50_disp_mthd_v0 {
305 __u8 version; 327 __u8 version;
328#define NV50_DISP_SCANOUTPOS 0x00
306 __u8 method; 329 __u8 method;
307 __u8 head; 330 __u8 head;
308 __u8 pad03[5]; 331 __u8 pad03[5];
diff --git a/drivers/gpu/drm/nouveau/nvif/object.h b/drivers/gpu/drm/nouveau/nvif/object.h
index a5d82814a9b0..fac3a3bbec44 100644
--- a/drivers/gpu/drm/nouveau/nvif/object.h
+++ b/drivers/gpu/drm/nouveau/nvif/object.h
@@ -71,6 +71,5 @@ void nvif_object_unmap(struct nvif_object *);
71/*XXX*/ 71/*XXX*/
72#include <core/object.h> 72#include <core/object.h>
73#define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv) 73#define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv)
74#define nvif_exec(a,b,c,d) nv_exec(nvkm_object(a), (b), (c), (d))
75 74
76#endif 75#endif