cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rootnv50.c (10121B)


      1/*
      2 * Copyright 2012 Red Hat Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: Ben Skeggs
     23 */
     24#include "rootnv50.h"
     25#include "channv50.h"
     26#include "dp.h"
     27#include "head.h"
     28#include "ior.h"
     29
     30#include <core/client.h>
     31
     32#include <nvif/class.h>
     33#include <nvif/cl5070.h>
     34#include <nvif/unpack.h>
     35
     36static int
     37nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
     38{
     39	union {
     40		struct nv50_disp_mthd_v0 v0;
     41		struct nv50_disp_mthd_v1 v1;
     42	} *args = data;
     43	struct nv50_disp_root *root = nv50_disp_root(object);
     44	struct nv50_disp *disp = root->disp;
     45	struct nvkm_outp *temp, *outp = NULL;
     46	struct nvkm_head *head;
     47	u16 type, mask = 0;
     48	int hidx, ret = -ENOSYS;
     49
     50	if (mthd != NV50_DISP_MTHD)
     51		return -EINVAL;
     52
     53	nvif_ioctl(object, "disp mthd size %d\n", size);
     54	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
     55		nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
     56			   args->v0.version, args->v0.method, args->v0.head);
     57		mthd = args->v0.method;
     58		hidx = args->v0.head;
     59	} else
     60	if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
     61		nvif_ioctl(object, "disp mthd vers %d mthd %02x "
     62				   "type %04x mask %04x\n",
     63			   args->v1.version, args->v1.method,
     64			   args->v1.hasht, args->v1.hashm);
     65		mthd = args->v1.method;
     66		type = args->v1.hasht;
     67		mask = args->v1.hashm;
     68		hidx = ffs((mask >> 8) & 0x0f) - 1;
     69	} else
     70		return ret;
     71
     72	if (!(head = nvkm_head_find(&disp->base, hidx)))
     73		return -ENXIO;
     74
     75	if (mask) {
     76		list_for_each_entry(temp, &disp->base.outp, head) {
     77			if ((temp->info.hasht         == type) &&
     78			    (temp->info.hashm & mask) == mask) {
     79				outp = temp;
     80				break;
     81			}
     82		}
     83		if (outp == NULL)
     84			return -ENXIO;
     85	}
     86
     87	switch (mthd) {
     88	case NV50_DISP_SCANOUTPOS: {
     89		return nvkm_head_mthd_scanoutpos(object, head, data, size);
     90	}
     91	default:
     92		break;
     93	}
     94
     95	switch (mthd * !!outp) {
     96	case NV50_DISP_MTHD_V1_ACQUIRE: {
     97		union {
     98			struct nv50_disp_acquire_v0 v0;
     99		} *args = data;
    100		int ret = -ENOSYS;
    101		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    102			ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, args->v0.hda);
    103			if (ret == 0) {
    104				args->v0.or = outp->ior->id;
    105				args->v0.link = outp->ior->asy.link;
    106			}
    107		}
    108		return ret;
    109	}
    110		break;
    111	case NV50_DISP_MTHD_V1_RELEASE:
    112		nvkm_outp_release(outp, NVKM_OUTP_USER);
    113		return 0;
    114	case NV50_DISP_MTHD_V1_DAC_LOAD: {
    115		union {
    116			struct nv50_disp_dac_load_v0 v0;
    117		} *args = data;
    118		int ret = -ENOSYS;
    119		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    120			if (args->v0.data & 0xfff00000)
    121				return -EINVAL;
    122			ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV, false);
    123			if (ret)
    124				return ret;
    125			ret = outp->ior->func->sense(outp->ior, args->v0.data);
    126			nvkm_outp_release(outp, NVKM_OUTP_PRIV);
    127			if (ret < 0)
    128				return ret;
    129			args->v0.load = ret;
    130			return 0;
    131		} else
    132			return ret;
    133	}
    134		break;
    135	case NV50_DISP_MTHD_V1_SOR_HDA_ELD: {
    136		union {
    137			struct nv50_disp_sor_hda_eld_v0 v0;
    138		} *args = data;
    139		struct nvkm_ior *ior = outp->ior;
    140		int ret = -ENOSYS;
    141
    142		nvif_ioctl(object, "disp sor hda eld size %d\n", size);
    143		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
    144			nvif_ioctl(object, "disp sor hda eld vers %d\n",
    145				   args->v0.version);
    146			if (size > 0x60)
    147				return -E2BIG;
    148		} else
    149			return ret;
    150
    151		if (!ior->func->hda.hpd)
    152			return -ENODEV;
    153
    154		if (size && args->v0.data[0]) {
    155			if (outp->info.type == DCB_OUTPUT_DP)
    156				ior->func->dp.audio(ior, hidx, true);
    157			ior->func->hda.hpd(ior, hidx, true);
    158			ior->func->hda.eld(ior, hidx, data, size);
    159		} else {
    160			if (outp->info.type == DCB_OUTPUT_DP)
    161				ior->func->dp.audio(ior, hidx, false);
    162			ior->func->hda.hpd(ior, hidx, false);
    163		}
    164
    165		return 0;
    166	}
    167		break;
    168	case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: {
    169		union {
    170			struct nv50_disp_sor_hdmi_pwr_v0 v0;
    171		} *args = data;
    172		u8 *vendor, vendor_size;
    173		u8 *avi, avi_size;
    174		int ret = -ENOSYS;
    175
    176		nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
    177		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
    178			nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
    179					   "max_ac_packet %d rekey %d scdc %d\n",
    180				   args->v0.version, args->v0.state,
    181				   args->v0.max_ac_packet, args->v0.rekey,
    182				   args->v0.scdc);
    183			if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
    184				return -EINVAL;
    185			if ((args->v0.avi_infoframe_length
    186			     + args->v0.vendor_infoframe_length) > size)
    187				return -EINVAL;
    188			else
    189			if ((args->v0.avi_infoframe_length
    190			     + args->v0.vendor_infoframe_length) < size)
    191				return -E2BIG;
    192			avi = data;
    193			avi_size = args->v0.avi_infoframe_length;
    194			vendor = avi + avi_size;
    195			vendor_size = args->v0.vendor_infoframe_length;
    196		} else
    197			return ret;
    198
    199		if (!outp->ior->func->hdmi.ctrl)
    200			return -ENODEV;
    201
    202		outp->ior->func->hdmi.ctrl(outp->ior, hidx, args->v0.state,
    203					   args->v0.max_ac_packet,
    204					   args->v0.rekey, avi, avi_size,
    205					   vendor, vendor_size);
    206
    207		if (outp->ior->func->hdmi.scdc)
    208			outp->ior->func->hdmi.scdc(outp->ior, args->v0.scdc);
    209
    210		return 0;
    211	}
    212		break;
    213	case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
    214		union {
    215			struct nv50_disp_sor_lvds_script_v0 v0;
    216		} *args = data;
    217		int ret = -ENOSYS;
    218		nvif_ioctl(object, "disp sor lvds script size %d\n", size);
    219		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    220			nvif_ioctl(object, "disp sor lvds script "
    221					   "vers %d name %04x\n",
    222				   args->v0.version, args->v0.script);
    223			disp->sor.lvdsconf = args->v0.script;
    224			return 0;
    225		} else
    226			return ret;
    227	}
    228		break;
    229	case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: {
    230		struct nvkm_dp *dp = nvkm_dp(outp);
    231		union {
    232			struct nv50_disp_sor_dp_mst_link_v0 v0;
    233		} *args = data;
    234		int ret = -ENOSYS;
    235		nvif_ioctl(object, "disp sor dp mst link size %d\n", size);
    236		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    237			nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n",
    238				   args->v0.version, args->v0.state);
    239			dp->lt.mst = !!args->v0.state;
    240			return 0;
    241		} else
    242			return ret;
    243	}
    244		break;
    245	case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: {
    246		union {
    247			struct nv50_disp_sor_dp_mst_vcpi_v0 v0;
    248		} *args = data;
    249		int ret = -ENOSYS;
    250		nvif_ioctl(object, "disp sor dp mst vcpi size %d\n", size);
    251		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    252			nvif_ioctl(object, "disp sor dp mst vcpi vers %d "
    253					   "slot %02x/%02x pbn %04x/%04x\n",
    254				   args->v0.version, args->v0.start_slot,
    255				   args->v0.num_slots, args->v0.pbn,
    256				   args->v0.aligned_pbn);
    257			if (!outp->ior->func->dp.vcpi)
    258				return -ENODEV;
    259			outp->ior->func->dp.vcpi(outp->ior, hidx,
    260						 args->v0.start_slot,
    261						 args->v0.num_slots,
    262						 args->v0.pbn,
    263						 args->v0.aligned_pbn);
    264			return 0;
    265		} else
    266			return ret;
    267	}
    268		break;
    269	default:
    270		break;
    271	}
    272
    273	return -EINVAL;
    274}
    275
    276static int
    277nv50_disp_root_child_new_(const struct nvkm_oclass *oclass,
    278			  void *argv, u32 argc, struct nvkm_object **pobject)
    279{
    280	struct nv50_disp *disp = nv50_disp_root(oclass->parent)->disp;
    281	const struct nv50_disp_user *user = oclass->priv;
    282	return user->ctor(oclass, argv, argc, disp, pobject);
    283}
    284
    285static int
    286nv50_disp_root_child_get_(struct nvkm_object *object, int index,
    287			  struct nvkm_oclass *sclass)
    288{
    289	struct nv50_disp_root *root = nv50_disp_root(object);
    290
    291	if (root->func->user[index].ctor) {
    292		sclass->base = root->func->user[index].base;
    293		sclass->priv = root->func->user + index;
    294		sclass->ctor = nv50_disp_root_child_new_;
    295		return 0;
    296	}
    297
    298	return -EINVAL;
    299}
    300
    301static void *
    302nv50_disp_root_dtor_(struct nvkm_object *object)
    303{
    304	struct nv50_disp_root *root = nv50_disp_root(object);
    305	return root;
    306}
    307
    308static const struct nvkm_object_func
    309nv50_disp_root_ = {
    310	.dtor = nv50_disp_root_dtor_,
    311	.mthd = nv50_disp_root_mthd_,
    312	.ntfy = nvkm_disp_ntfy,
    313	.sclass = nv50_disp_root_child_get_,
    314};
    315
    316int
    317nv50_disp_root_new_(const struct nv50_disp_root_func *func,
    318		    struct nvkm_disp *base, const struct nvkm_oclass *oclass,
    319		    void *data, u32 size, struct nvkm_object **pobject)
    320{
    321	struct nv50_disp *disp = nv50_disp(base);
    322	struct nv50_disp_root *root;
    323
    324	if (!(root = kzalloc(sizeof(*root), GFP_KERNEL)))
    325		return -ENOMEM;
    326	*pobject = &root->object;
    327
    328	nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object);
    329	root->func = func;
    330	root->disp = disp;
    331	return 0;
    332}
    333
    334static const struct nv50_disp_root_func
    335nv50_disp_root = {
    336	.user = {
    337		{{0,0,NV50_DISP_CURSOR             }, nv50_disp_curs_new },
    338		{{0,0,NV50_DISP_OVERLAY            }, nv50_disp_oimm_new },
    339		{{0,0,NV50_DISP_BASE_CHANNEL_DMA   }, nv50_disp_base_new },
    340		{{0,0,NV50_DISP_CORE_CHANNEL_DMA   }, nv50_disp_core_new },
    341		{{0,0,NV50_DISP_OVERLAY_CHANNEL_DMA}, nv50_disp_ovly_new },
    342		{}
    343	},
    344};
    345
    346static int
    347nv50_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
    348		   void *data, u32 size, struct nvkm_object **pobject)
    349{
    350	return nv50_disp_root_new_(&nv50_disp_root, disp, oclass,
    351				   data, size, pobject);
    352}
    353
    354const struct nvkm_disp_oclass
    355nv50_disp_root_oclass = {
    356	.base.oclass = NV50_DISP,
    357	.base.minver = -1,
    358	.base.maxver = -1,
    359	.ctor = nv50_disp_root_new,
    360};