Commit 4952b4d3 authored by Ben Skeggs's avatar Ben Skeggs

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 67cb49c4
...@@ -45,7 +45,7 @@ gm107_disp_sclass[] = { ...@@ -45,7 +45,7 @@ gm107_disp_sclass[] = {
static struct nouveau_oclass static struct nouveau_oclass
gm107_disp_base_oclass[] = { gm107_disp_base_oclass[] = {
{ GM107_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, { GM107_DISP_CLASS, &nvd0_disp_base_ofuncs },
{} {}
}; };
...@@ -99,4 +99,5 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { ...@@ -99,4 +99,5 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -24,60 +24,100 @@ ...@@ -24,60 +24,100 @@
#include "priv.h" #include "priv.h"
#include <core/client.h>
#include <core/event.h> #include <core/event.h>
#include <core/class.h> #include <core/class.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
struct nv04_disp_priv { struct nv04_disp_priv {
struct nouveau_disp base; struct nouveau_disp base;
}; };
static int static int
nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd, nv04_disp_scanoutpos(struct nouveau_object *object, struct nv04_disp_priv *priv,
void *data, u32 size) void *data, u32 size, int head)
{ {
struct nv04_disp_priv *priv = (void *)object->engine; const u32 hoff = head * 0x2000;
struct nv04_display_scanoutpos *args = data; union {
const int head = (mthd & NV04_DISP_MTHD_HEAD); struct nv04_disp_scanoutpos_v0 v0;
} *args = data;
u32 line; u32 line;
int ret;
nv_ioctl(object, "disp scanoutpos size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
args->v0.vblanke = args->v0.vtotal - 1;
args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
args->v0.hblanke = args->v0.htotal - 1;
/*
* If output is vga instead of digital then vtotal/htotal is
* invalid so we have to give up and trigger the timestamping
* fallback in the drm core.
*/
if (!args->v0.vtotal || !args->v0.htotal)
return -ENOTSUPP;
args->v0.time[0] = ktime_to_ns(ktime_get());
line = nv_rd32(priv, 0x600868 + hoff);
args->v0.time[1] = ktime_to_ns(ktime_get());
args->v0.hline = (line & 0xffff0000) >> 16;
args->v0.vline = (line & 0x0000ffff);
} else
return ret;
if (size < sizeof(*args))
return -EINVAL;
args->vblanks = nv_rd32(priv, 0x680800 + (head * 0x2000)) & 0xffff;
args->vtotal = nv_rd32(priv, 0x680804 + (head * 0x2000)) & 0xffff;
args->vblanke = args->vtotal - 1;
args->hblanks = nv_rd32(priv, 0x680820 + (head * 0x2000)) & 0xffff;
args->htotal = nv_rd32(priv, 0x680824 + (head * 0x2000)) & 0xffff;
args->hblanke = args->htotal - 1;
/*
* If output is vga instead of digital then vtotal/htotal is invalid
* so we have to give up and trigger the timestamping fallback in the
* drm core.
*/
if (!args->vtotal || !args->htotal)
return -ENOTSUPP;
args->time[0] = ktime_to_ns(ktime_get());
line = nv_rd32(priv, 0x600868 + (head * 0x2000));
args->time[1] = ktime_to_ns(ktime_get());
args->hline = (line & 0xffff0000) >> 16;
args->vline = (line & 0x0000ffff);
return 0; return 0;
} }
#define HEAD_MTHD(n) (n), (n) + 0x01 static int
nv04_disp_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
{
union {
struct nv04_disp_mthd_v0 v0;
} *args = data;
struct nv04_disp_priv *priv = (void *)object->engine;
int head, ret;
nv_ioctl(object, "disp mthd size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
args->v0.version, args->v0.method, args->v0.head);
mthd = args->v0.method;
head = args->v0.head;
} else
return ret;
if (head < 0 || head >= 2)
return -ENXIO;
switch (mthd) {
case NV04_DISP_SCANOUTPOS:
return nv04_disp_scanoutpos(object, priv, data, size, head);
default:
break;
}
return -EINVAL;
}
static struct nouveau_omthds static struct nouveau_ofuncs
nv04_disp_omthds[] = { nv04_disp_ofuncs = {
{ HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos }, .ctor = _nouveau_object_ctor,
{} .dtor = nouveau_object_destroy,
.init = nouveau_object_init,
.fini = nouveau_object_fini,
.mthd = nv04_disp_mthd,
}; };
static struct nouveau_oclass static struct nouveau_oclass
nv04_disp_sclass[] = { nv04_disp_sclass[] = {
{ NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds }, { NV04_DISP_CLASS, &nv04_disp_ofuncs },
{}, {},
}; };
......
...@@ -814,31 +814,34 @@ nv50_disp_curs_ofuncs = { ...@@ -814,31 +814,34 @@ nv50_disp_curs_ofuncs = {
******************************************************************************/ ******************************************************************************/
int int
nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
void *data, u32 size)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
struct nv04_display_scanoutpos *args = data; const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
const int head = (mthd & NV50_DISP_MTHD_HEAD); const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540));
u32 blanke, blanks, total; union {
struct nv04_disp_scanoutpos_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "disp scanoutpos size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
args->v0.vblanke = (blanke & 0xffff0000) >> 16;
args->v0.hblanke = (blanke & 0x0000ffff);
args->v0.vblanks = (blanks & 0xffff0000) >> 16;
args->v0.hblanks = (blanks & 0x0000ffff);
args->v0.vtotal = ( total & 0xffff0000) >> 16;
args->v0.htotal = ( total & 0x0000ffff);
args->v0.time[0] = ktime_to_ns(ktime_get());
args->v0.vline = /* vline read locks hline */
nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
args->v0.time[1] = ktime_to_ns(ktime_get());
args->v0.hline =
nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
} else
return ret;
if (size < sizeof(*args) || head >= priv->head.nr)
return -EINVAL;
blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
total = nv_rd32(priv, 0x610afc + (head * 0x540));
args->vblanke = (blanke & 0xffff0000) >> 16;
args->hblanke = (blanke & 0x0000ffff);
args->vblanks = (blanks & 0xffff0000) >> 16;
args->hblanks = (blanks & 0x0000ffff);
args->vtotal = ( total & 0xffff0000) >> 16;
args->htotal = ( total & 0x0000ffff);
args->time[0] = ktime_to_ns(ktime_get());
args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
return 0; return 0;
} }
...@@ -846,6 +849,7 @@ int ...@@ -846,6 +849,7 @@ int
nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd, nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
void *data, u32 size) void *data, u32 size)
{ {
const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
union { union {
struct nv50_disp_mthd_v0 v0; struct nv50_disp_mthd_v0 v0;
struct nv50_disp_mthd_v1 v1; struct nv50_disp_mthd_v1 v1;
...@@ -894,6 +898,8 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd, ...@@ -894,6 +898,8 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
} }
switch (mthd) { switch (mthd) {
case NV50_DISP_SCANOUTPOS:
return impl->head.scanoutpos(object, priv, data, size, head);
default: default:
break; break;
} }
...@@ -1081,15 +1087,9 @@ nv50_disp_base_ofuncs = { ...@@ -1081,15 +1087,9 @@ nv50_disp_base_ofuncs = {
.mthd = nv50_disp_base_mthd, .mthd = nv50_disp_base_mthd,
}; };
static struct nouveau_omthds
nv50_disp_base_omthds[] = {
{ HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
{},
};
static struct nouveau_oclass static struct nouveau_oclass
nv50_disp_base_oclass[] = { nv50_disp_base_oclass[] = {
{ NV50_DISP_CLASS, &nv50_disp_base_ofuncs, nv50_disp_base_omthds }, { NV50_DISP_CLASS, &nv50_disp_base_ofuncs },
{} {}
}; };
...@@ -1859,4 +1859,5 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { ...@@ -1859,4 +1859,5 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nv50_disp_sync_mthd_chan, .mthd.base = &nv50_disp_sync_mthd_chan,
.mthd.ovly = &nv50_disp_ovly_mthd_chan, .mthd.ovly = &nv50_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -14,16 +14,6 @@ ...@@ -14,16 +14,6 @@
#include "outp.h" #include "outp.h"
#include "outpdp.h" #include "outpdp.h"
struct nv50_disp_impl {
struct nouveau_disp_impl base;
struct {
const struct nv50_disp_mthd_chan *core;
const struct nv50_disp_mthd_chan *base;
const struct nv50_disp_mthd_chan *ovly;
int prev;
} mthd;
};
#define NV50_DISP_MTHD_ struct nouveau_object *object, \ #define NV50_DISP_MTHD_ struct nouveau_object *object, \
struct nv50_disp_priv *priv, void *data, u32 size struct nv50_disp_priv *priv, void *data, u32 size
#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head #define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
...@@ -58,18 +48,27 @@ struct nv50_disp_priv { ...@@ -58,18 +48,27 @@ struct nv50_disp_priv {
} pior; } pior;
}; };
#define HEAD_MTHD(n) (n), (n) + 0x03 struct nv50_disp_impl {
struct nouveau_disp_impl base;
struct {
const struct nv50_disp_mthd_chan *core;
const struct nv50_disp_mthd_chan *base;
const struct nv50_disp_mthd_chan *ovly;
int prev;
} mthd;
struct {
int (*scanoutpos)(NV50_DISP_MTHD_V0);
} head;
};
int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32); int nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32); int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);
#define DAC_MTHD(n) (n), (n) + 0x03 int nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
int nv50_dac_power(NV50_DISP_MTHD_V1); int nv50_dac_power(NV50_DISP_MTHD_V1);
int nv50_dac_sense(NV50_DISP_MTHD_V1); int nv50_dac_sense(NV50_DISP_MTHD_V1);
#define SOR_MTHD(n) (n), (n) + 0x3f
int nva3_hda_eld(NV50_DISP_MTHD_V1); int nva3_hda_eld(NV50_DISP_MTHD_V1);
int nvd0_hda_eld(NV50_DISP_MTHD_V1); int nvd0_hda_eld(NV50_DISP_MTHD_V1);
...@@ -97,8 +96,6 @@ int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, ...@@ -97,8 +96,6 @@ int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
struct dcb_output *); struct dcb_output *);
#define PIOR_MTHD(n) (n), (n) + 0x03
int nv50_pior_power(NV50_DISP_MTHD_V1); int nv50_pior_power(NV50_DISP_MTHD_V1);
struct nv50_disp_base { struct nv50_disp_base {
...@@ -203,7 +200,6 @@ extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac; ...@@ -203,7 +200,6 @@ extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head; extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head;
extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan; extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan;
extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan; extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
extern struct nouveau_omthds nv84_disp_base_omthds[];
extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan;
...@@ -217,7 +213,6 @@ extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs; ...@@ -217,7 +213,6 @@ extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan; extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan;
extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs; extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs; extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
extern struct nouveau_omthds nvd0_disp_base_omthds[];
extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
extern struct nouveau_oclass nvd0_disp_cclass; extern struct nouveau_oclass nvd0_disp_cclass;
void nvd0_disp_intr_supervisor(struct work_struct *); void nvd0_disp_intr_supervisor(struct work_struct *);
......
...@@ -212,15 +212,9 @@ nv84_disp_sclass[] = { ...@@ -212,15 +212,9 @@ nv84_disp_sclass[] = {
{} {}
}; };
struct nouveau_omthds
nv84_disp_base_omthds[] = {
{ HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
{},
};
static struct nouveau_oclass static struct nouveau_oclass
nv84_disp_base_oclass[] = { nv84_disp_base_oclass[] = {
{ NV84_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds }, { NV84_DISP_CLASS, &nv50_disp_base_ofuncs },
{} {}
}; };
...@@ -274,4 +268,5 @@ nv84_disp_oclass = &(struct nv50_disp_impl) { ...@@ -274,4 +268,5 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -71,15 +71,9 @@ nv94_disp_sclass[] = { ...@@ -71,15 +71,9 @@ nv94_disp_sclass[] = {
{} {}
}; };
static struct nouveau_omthds
nv94_disp_base_omthds[] = {
{ HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
{},
};
static struct nouveau_oclass static struct nouveau_oclass
nv94_disp_base_oclass[] = { nv94_disp_base_oclass[] = {
{ NV94_DISP_CLASS, &nv50_disp_base_ofuncs, nv94_disp_base_omthds }, { NV94_DISP_CLASS, &nv50_disp_base_ofuncs },
{} {}
}; };
...@@ -140,4 +134,5 @@ nv94_disp_oclass = &(struct nv50_disp_impl) { ...@@ -140,4 +134,5 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -90,7 +90,7 @@ nva0_disp_sclass[] = { ...@@ -90,7 +90,7 @@ nva0_disp_sclass[] = {
static struct nouveau_oclass static struct nouveau_oclass
nva0_disp_base_oclass[] = { nva0_disp_base_oclass[] = {
{ NVA0_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds }, { NVA0_DISP_CLASS, &nv50_disp_base_ofuncs },
{} {}
}; };
...@@ -144,4 +144,5 @@ nva0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -144,4 +144,5 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nva0_disp_ovly_mthd_chan, .mthd.ovly = &nva0_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -43,15 +43,9 @@ nva3_disp_sclass[] = { ...@@ -43,15 +43,9 @@ nva3_disp_sclass[] = {
{} {}
}; };
static struct nouveau_omthds
nva3_disp_base_omthds[] = {
{ HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
{},
};
static struct nouveau_oclass static struct nouveau_oclass
nva3_disp_base_oclass[] = { nva3_disp_base_oclass[] = {
{ NVA3_DISP_CLASS, &nv50_disp_base_ofuncs, nva3_disp_base_omthds }, { NVA3_DISP_CLASS, &nv50_disp_base_ofuncs },
{} {}
}; };
...@@ -106,4 +100,5 @@ nva3_disp_oclass = &(struct nv50_disp_impl) { ...@@ -106,4 +100,5 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -23,9 +23,12 @@ ...@@ -23,9 +23,12 @@
*/ */
#include <core/object.h> #include <core/object.h>
#include <core/client.h>
#include <core/parent.h> #include <core/parent.h>
#include <core/handle.h> #include <core/handle.h>
#include <core/class.h> #include <core/class.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <engine/disp.h> #include <engine/disp.h>
...@@ -589,33 +592,35 @@ nvd0_disp_curs_ofuncs = { ...@@ -589,33 +592,35 @@ nvd0_disp_curs_ofuncs = {
* Base display object * Base display object
******************************************************************************/ ******************************************************************************/
static int int
nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
void *data, u32 size)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300));
struct nv04_display_scanoutpos *args = data; const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
const int head = (mthd & NV50_DISP_MTHD_HEAD); const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
u32 blanke, blanks, total; union {
struct nv04_disp_scanoutpos_v0 v0;
if (size < sizeof(*args) || head >= priv->head.nr) } *args = data;
return -EINVAL; int ret;
total = nv_rd32(priv, 0x640414 + (head * 0x300)); nv_ioctl(object, "disp scanoutpos size %d\n", size);
blanke = nv_rd32(priv, 0x64041c + (head * 0x300)); if (nvif_unpack(args->v0, 0, 0, false)) {
blanks = nv_rd32(priv, 0x640420 + (head * 0x300)); nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
args->v0.vblanke = (blanke & 0xffff0000) >> 16;
args->vblanke = (blanke & 0xffff0000) >> 16; args->v0.hblanke = (blanke & 0x0000ffff);
args->hblanke = (blanke & 0x0000ffff); args->v0.vblanks = (blanks & 0xffff0000) >> 16;
args->vblanks = (blanks & 0xffff0000) >> 16; args->v0.hblanks = (blanks & 0x0000ffff);
args->hblanks = (blanks & 0x0000ffff); args->v0.vtotal = ( total & 0xffff0000) >> 16;
args->vtotal = ( total & 0xffff0000) >> 16; args->v0.htotal = ( total & 0x0000ffff);
args->htotal = ( total & 0x0000ffff); args->v0.time[0] = ktime_to_ns(ktime_get());
args->v0.vline = /* vline read locks hline */
args->time[0] = ktime_to_ns(ktime_get()); nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; args->v0.time[1] = ktime_to_ns(ktime_get());
args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */ args->v0.hline =
args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
} else
return ret;
return 0; return 0;
} }
...@@ -709,15 +714,9 @@ nvd0_disp_base_ofuncs = { ...@@ -709,15 +714,9 @@ nvd0_disp_base_ofuncs = {
.mthd = nv50_disp_base_mthd, .mthd = nv50_disp_base_mthd,
}; };
struct nouveau_omthds
nvd0_disp_base_omthds[] = {
{ HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nvd0_disp_base_scanoutpos },
{},
};
static struct nouveau_oclass static struct nouveau_oclass
nvd0_disp_base_oclass[] = { nvd0_disp_base_oclass[] = {
{ NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs },
{} {}
}; };
...@@ -1242,4 +1241,5 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -1242,4 +1241,5 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nvd0_disp_ovly_mthd_chan, .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -210,7 +210,7 @@ nve0_disp_sclass[] = { ...@@ -210,7 +210,7 @@ nve0_disp_sclass[] = {
static struct nouveau_oclass static struct nouveau_oclass
nve0_disp_base_oclass[] = { nve0_disp_base_oclass[] = {
{ NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs },
{} {}
}; };
...@@ -264,4 +264,5 @@ nve0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -264,4 +264,5 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -45,7 +45,7 @@ nvf0_disp_sclass[] = { ...@@ -45,7 +45,7 @@ nvf0_disp_sclass[] = {
static struct nouveau_oclass static struct nouveau_oclass
nvf0_disp_base_oclass[] = { nvf0_disp_base_oclass[] = {
{ NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs },
{} {}
}; };
...@@ -99,4 +99,5 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -99,4 +99,5 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos,
}.base.base; }.base.base;
...@@ -8,26 +8,9 @@ ...@@ -8,26 +8,9 @@
#define NV04_DISP_CLASS 0x00000046 #define NV04_DISP_CLASS 0x00000046
#define NV04_DISP_MTHD 0x00000000
#define NV04_DISP_MTHD_HEAD 0x00000001
#define NV04_DISP_SCANOUTPOS 0x00000000
struct nv04_display_class { struct nv04_display_class {
}; };
struct nv04_display_scanoutpos {
s64 time[2];
u32 vblanks;
u32 vblanke;
u32 vtotal;
u32 vline;
u32 hblanks;
u32 hblanke;
u32 htotal;
u32 hline;
};
/* 5070: NV50_DISP /* 5070: NV50_DISP
* 8270: NV84_DISP * 8270: NV84_DISP
* 8370: NVA0_DISP * 8370: NVA0_DISP
...@@ -49,10 +32,6 @@ struct nv04_display_scanoutpos { ...@@ -49,10 +32,6 @@ struct nv04_display_scanoutpos {
#define NVF0_DISP_CLASS 0x00009270 #define NVF0_DISP_CLASS 0x00009270
#define GM107_DISP_CLASS 0x00009470 #define GM107_DISP_CLASS 0x00009470
#define NV50_DISP_MTHD_HEAD 0x00000003
#define NV50_DISP_SCANOUTPOS 0x00000000
struct nv50_display_class { struct nv50_display_class {
}; };
......
...@@ -95,17 +95,22 @@ int ...@@ -95,17 +95,22 @@ int
nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime) ktime_t *stime, ktime_t *etime)
{ {
const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index; struct {
struct nv04_disp_mthd_v0 base;
struct nv04_disp_scanoutpos_v0 scan;
} args = {
.base.method = NV04_DISP_SCANOUTPOS,
.base.head = nouveau_crtc(crtc)->index,
};
struct nouveau_display *disp = nouveau_display(crtc->dev); struct nouveau_display *disp = nouveau_display(crtc->dev);
struct nv04_display_scanoutpos args;
int ret, retry = 1; int ret, retry = 1;
do { do {
ret = nvif_exec(&disp->disp, mthd, &args, sizeof(args)); ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args));
if (ret != 0) if (ret != 0)
return 0; return 0;
if (args.vline) { if (args.scan.vline) {
ret |= DRM_SCANOUTPOS_ACCURATE; ret |= DRM_SCANOUTPOS_ACCURATE;
ret |= DRM_SCANOUTPOS_VALID; ret |= DRM_SCANOUTPOS_VALID;
break; break;
...@@ -114,10 +119,11 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, ...@@ -114,10 +119,11 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
if (retry) ndelay(crtc->linedur_ns); if (retry) ndelay(crtc->linedur_ns);
} while (retry--); } while (retry--);
*hpos = args.hline; *hpos = args.scan.hline;
*vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline); *vpos = calc(args.scan.vblanks, args.scan.vblanke,
if (stime) *stime = ns_to_ktime(args.time[0]); args.scan.vtotal, args.scan.vline);
if (etime) *etime = ns_to_ktime(args.time[1]); if (stime) *stime = ns_to_ktime(args.scan.time[0]);
if (etime) *etime = ns_to_ktime(args.scan.time[1]);
if (*vpos < 0) if (*vpos < 0)
ret |= DRM_SCANOUTPOS_INVBL; ret |= DRM_SCANOUTPOS_INVBL;
......
...@@ -294,6 +294,28 @@ struct kepler_channel_gpfifo_a_v0 { ...@@ -294,6 +294,28 @@ struct kepler_channel_gpfifo_a_v0 {
* legacy display * legacy display
******************************************************************************/ ******************************************************************************/
struct nv04_disp_mthd_v0 {
__u8 version;
#define NV04_DISP_SCANOUTPOS 0x00
__u8 method;
__u8 head;
__u8 pad03[5];
};
struct nv04_disp_scanoutpos_v0 {
__u8 version;
__u8 pad01[7];
__s64 time[2];
__u16 vblanks;
__u16 vblanke;
__u16 vtotal;
__u16 vline;
__u16 hblanks;
__u16 hblanke;
__u16 htotal;
__u16 hline;
};
/******************************************************************************* /*******************************************************************************
* display * display
...@@ -303,6 +325,7 @@ struct kepler_channel_gpfifo_a_v0 { ...@@ -303,6 +325,7 @@ struct kepler_channel_gpfifo_a_v0 {
struct nv50_disp_mthd_v0 { struct nv50_disp_mthd_v0 {
__u8 version; __u8 version;
#define NV50_DISP_SCANOUTPOS 0x00
__u8 method; __u8 method;
__u8 head; __u8 head;
__u8 pad03[5]; __u8 pad03[5];
......
...@@ -71,6 +71,5 @@ void nvif_object_unmap(struct nvif_object *); ...@@ -71,6 +71,5 @@ void nvif_object_unmap(struct nvif_object *);
/*XXX*/ /*XXX*/
#include <core/object.h> #include <core/object.h>
#define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv) #define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv)
#define nvif_exec(a,b,c,d) nv_exec(nvkm_object(a), (b), (c), (d))
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment