diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-08-10 04:10:26 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-08-10 05:28:07 +1000 |
commit | bf0eb89859439f016a1fab4cdf737c95f36dbb2e (patch) | |
tree | 59709bbd702fe904e63a2237d200162f90d820b4 /drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | |
parent | drm/nv50-/disp: share channel creation between nv50/gf110 impls (diff) | |
download | linux-dev-bf0eb89859439f016a1fab4cdf737c95f36dbb2e.tar.xz linux-dev-bf0eb89859439f016a1fab4cdf737c95f36dbb2e.zip |
drm/nv50-/disp: audit and version DAC_PWR 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/drm/nouveau/core/engine/disp/nv50.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 4f1ed8928c82..00d1e34cb2a6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -23,10 +23,13 @@ */ #include <core/object.h> +#include <core/client.h> #include <core/parent.h> #include <core/handle.h> -#include <core/class.h> #include <core/enum.h> +#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -840,6 +843,72 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, } int +nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + union { + struct nv50_disp_mthd_v0 v0; + struct nv50_disp_mthd_v1 v1; + } *args = data; + struct nv50_disp_priv *priv = (void *)object->engine; + struct nvkm_output *outp = NULL; + struct nvkm_output *temp; + u16 type, mask = 0; + int head, ret; + + if (mthd != NV50_DISP_MTHD) + return -EINVAL; + + 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 + if (nvif_unpack(args->v1, 1, 1, true)) { + nv_ioctl(object, "disp mthd vers %d mthd %02x " + "type %04x mask %04x\n", + args->v1.version, args->v1.method, + args->v1.hasht, args->v1.hashm); + mthd = args->v1.method; + type = args->v1.hasht; + mask = args->v1.hashm; + head = ffs((mask >> 8) & 0x0f) - 1; + } else + return ret; + + if (head < 0 || head >= priv->head.nr) + return -ENXIO; + + if (mask) { + list_for_each_entry(temp, &priv->base.outp, head) { + if ((temp->info.hasht == type) && + (temp->info.hashm & mask) == mask) { + outp = temp; + break; + } + } + if (outp == NULL) + return -ENXIO; + } + + switch (mthd) { + default: + break; + } + + switch (mthd * !!outp) { + case NV50_DISP_MTHD_V1_DAC_PWR: + return priv->dac.power(object, priv, data, size, head, outp); + default: + break; + } + + return -EINVAL; +} + +int nv50_disp_base_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -954,6 +1023,7 @@ nv50_disp_base_ofuncs = { .dtor = nv50_disp_base_dtor, .init = nv50_disp_base_init, .fini = nv50_disp_base_fini, + .mthd = nv50_disp_base_mthd, }; static struct nouveau_omthds @@ -961,7 +1031,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_PWR) , nv50_dac_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 }, |