Commit c4abd317 authored by Ben Skeggs's avatar Ben Skeggs

drm/nv50-/disp: audit and version DAC_LOAD 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 bf0eb898
......@@ -63,9 +63,24 @@ nv50_dac_power(NV50_DISP_MTHD_V1)
}
int
nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval)
nv50_dac_sense(NV50_DISP_MTHD_V1)
{
const u32 doff = (or * 0x800);
union {
struct nv50_disp_dac_load_v0 v0;
} *args = data;
const u32 doff = outp->or * 0x800;
u32 loadval;
int ret;
nv_ioctl(object, "disp dac load size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp dac load vers %d data %08x\n",
args->v0.version, args->v0.data);
if (args->v0.data & 0xfff00000)
return -EINVAL;
loadval = args->v0.data;
} else
return ret;
nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
......@@ -78,35 +93,10 @@ nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval)
nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
nv_debug(priv, "DAC%d sense: 0x%08x\n", or, loadval);
nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval);
if (!(loadval & 0x80000000))
return -ETIMEDOUT;
return (loadval & 0x38000000) >> 27;
}
int
nv50_dac_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
{
struct nv50_disp_priv *priv = (void *)object->engine;
const u8 or = (mthd & NV50_DISP_DAC_MTHD_OR);
u32 *data = args;
int ret;
if (size < sizeof(u32))
return -EINVAL;
switch (mthd & ~0x3f) {
case NV50_DISP_DAC_LOAD:
ret = priv->dac.sense(priv, or, data[0]);
if (ret >= 0) {
data[0] = ret;
ret = 0;
}
break;
default:
BUG_ON(1);
}
return ret;
args->v0.load = (loadval & 0x38000000) >> 27;
return 0;
}
......@@ -901,6 +901,8 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
switch (mthd * !!outp) {
case NV50_DISP_MTHD_V1_DAC_PWR:
return priv->dac.power(object, priv, data, size, head, outp);
case NV50_DISP_MTHD_V1_DAC_LOAD:
return priv->dac.sense(object, priv, data, size, head, outp);
default:
break;
}
......@@ -1031,7 +1033,6 @@ nv50_disp_base_omthds[] = {
{ HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
{ SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
......
......@@ -42,7 +42,7 @@ struct nv50_disp_priv {
struct {
int nr;
int (*power)(NV50_DISP_MTHD_V1);
int (*sense)(struct nv50_disp_priv *, int dac, u32 load);
int (*sense)(NV50_DISP_MTHD_V1);
} dac;
struct {
int nr;
......@@ -65,9 +65,8 @@ int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);
#define DAC_MTHD(n) (n), (n) + 0x03
int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32);
int nv50_dac_power(NV50_DISP_MTHD_V1);
int nv50_dac_sense(struct nv50_disp_priv *, int, u32);
int nv50_dac_sense(NV50_DISP_MTHD_V1);
#define SOR_MTHD(n) (n), (n) + 0x3f
......
......@@ -218,7 +218,6 @@ nv84_disp_base_omthds[] = {
{ SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
......
......@@ -78,7 +78,6 @@ nv94_disp_base_omthds[] = {
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
......
......@@ -51,7 +51,6 @@ nva3_disp_base_omthds[] = {
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
......
......@@ -717,7 +717,6 @@ nvd0_disp_base_omthds[] = {
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
......
......@@ -77,13 +77,6 @@ struct nv04_display_scanoutpos {
#define NV94_DISP_SOR_DP_PWR_STATE_OFF 0x00000000
#define NV94_DISP_SOR_DP_PWR_STATE_ON 0x00000001
#define NV50_DISP_DAC_MTHD 0x00020000
#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000
#define NV50_DISP_DAC_MTHD_OR 0x00000003
#define NV50_DISP_DAC_LOAD 0x00020100
#define NV50_DISP_DAC_LOAD_VALUE 0x00000007
#define NV50_DISP_PIOR_MTHD 0x00030000
#define NV50_DISP_PIOR_MTHD_TYPE 0x0000f000
#define NV50_DISP_PIOR_MTHD_OR 0x00000003
......
......@@ -1590,14 +1590,25 @@ nv50_dac_disconnect(struct drm_encoder *encoder)
static enum drm_connector_status
nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
int ret, or = nouveau_encoder(encoder)->or;
u32 load = nouveau_drm(encoder->dev)->vbios.dactestval;
if (load == 0)
load = 340;
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_dac_load_v0 load;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_DAC_LOAD,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = nv_encoder->dcb->hashm,
};
int ret;
args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval;
if (args.load.data == 0)
args.load.data = 340;
ret = nvif_exec(disp->disp, NV50_DISP_DAC_LOAD + or, &load, sizeof(load));
if (ret || !load)
ret = nvif_mthd(disp->disp, 0, &args, sizeof(args));
if (ret || !args.load.load)
return connector_status_disconnected;
return connector_status_connected;
......
......@@ -333,4 +333,11 @@ struct nv50_disp_dac_pwr_v0 {
__u8 pad05[3];
};
struct nv50_disp_dac_load_v0 {
__u8 version;
__u8 load;
__u16 data;
__u8 pad04[4];
};
#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