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

channv50.c (10120B)


      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 "channv50.h"
     25#include "rootnv50.h"
     26
     27#include <core/client.h>
     28#include <core/notify.h>
     29#include <core/oproxy.h>
     30#include <core/ramht.h>
     31#include <engine/dma.h>
     32
     33#include <nvif/cl507d.h>
     34#include <nvif/event.h>
     35#include <nvif/unpack.h>
     36
     37static void
     38nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c,
     39		    const struct nv50_disp_mthd_list *list, int inst)
     40{
     41	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
     42	struct nvkm_device *device = subdev->device;
     43	int i;
     44
     45	for (i = 0; list->data[i].mthd; i++) {
     46		if (list->data[i].addr) {
     47			u32 next = nvkm_rd32(device, list->data[i].addr + base + 0);
     48			u32 prev = nvkm_rd32(device, list->data[i].addr + base + c);
     49			u32 mthd = list->data[i].mthd + (list->mthd * inst);
     50			const char *name = list->data[i].name;
     51			char mods[16];
     52
     53			if (prev != next)
     54				snprintf(mods, sizeof(mods), "-> %08x", next);
     55			else
     56				snprintf(mods, sizeof(mods), "%13c", ' ');
     57
     58			nvkm_printk_(subdev, debug, info,
     59				     "\t%04x: %08x %s%s%s\n",
     60				     mthd, prev, mods, name ? " // " : "",
     61				     name ? name : "");
     62		}
     63	}
     64}
     65
     66void
     67nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug)
     68{
     69	struct nv50_disp *disp = chan->disp;
     70	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
     71	const struct nv50_disp_chan_mthd *mthd = chan->mthd;
     72	const struct nv50_disp_mthd_list *list;
     73	int i, j;
     74
     75	if (debug > subdev->debug)
     76		return;
     77	if (!mthd)
     78		return;
     79
     80	for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) {
     81		u32 base = chan->head * mthd->addr;
     82		for (j = 0; j < mthd->data[i].nr; j++, base += list->addr) {
     83			const char *cname = mthd->name;
     84			const char *sname = "";
     85			char cname_[16], sname_[16];
     86
     87			if (mthd->addr) {
     88				snprintf(cname_, sizeof(cname_), "%s %d",
     89					 mthd->name, chan->chid.user);
     90				cname = cname_;
     91			}
     92
     93			if (mthd->data[i].nr > 1) {
     94				snprintf(sname_, sizeof(sname_), " - %s %d",
     95					 mthd->data[i].name, j);
     96				sname = sname_;
     97			}
     98
     99			nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname);
    100			nv50_disp_mthd_list(disp, debug, base, mthd->prev,
    101					    list, j);
    102		}
    103	}
    104}
    105
    106static void
    107nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
    108{
    109	struct nv50_disp *disp = container_of(event, typeof(*disp), uevent);
    110	struct nvkm_device *device = disp->base.engine.subdev.device;
    111	nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000000 << index);
    112	nvkm_wr32(device, 0x610020, 0x00000001 << index);
    113}
    114
    115static void
    116nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
    117{
    118	struct nv50_disp *disp = container_of(event, typeof(*disp), uevent);
    119	struct nvkm_device *device = disp->base.engine.subdev.device;
    120	nvkm_wr32(device, 0x610020, 0x00000001 << index);
    121	nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000001 << index);
    122}
    123
    124void
    125nv50_disp_chan_uevent_send(struct nv50_disp *disp, int chid)
    126{
    127	struct nvif_notify_uevent_rep {
    128	} rep;
    129
    130	nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep));
    131}
    132
    133int
    134nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
    135			   struct nvkm_notify *notify)
    136{
    137	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    138	union {
    139		struct nvif_notify_uevent_req none;
    140	} *args = data;
    141	int ret = -ENOSYS;
    142
    143	if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
    144		notify->size  = sizeof(struct nvif_notify_uevent_rep);
    145		notify->types = 1;
    146		notify->index = chan->chid.user;
    147		return 0;
    148	}
    149
    150	return ret;
    151}
    152
    153const struct nvkm_event_func
    154nv50_disp_chan_uevent = {
    155	.ctor = nv50_disp_chan_uevent_ctor,
    156	.init = nv50_disp_chan_uevent_init,
    157	.fini = nv50_disp_chan_uevent_fini,
    158};
    159
    160u64
    161nv50_disp_chan_user(struct nv50_disp_chan *chan, u64 *psize)
    162{
    163	*psize = 0x1000;
    164	return 0x640000 + (chan->chid.user * 0x1000);
    165}
    166
    167void
    168nv50_disp_chan_intr(struct nv50_disp_chan *chan, bool en)
    169{
    170	struct nvkm_device *device = chan->disp->base.engine.subdev.device;
    171	const u32 mask = 0x00010001 << chan->chid.user;
    172	const u32 data = en ? 0x00010000 << chan->chid.user : 0x00000000;
    173	nvkm_mask(device, 0x610028, mask, data);
    174}
    175
    176static int
    177nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
    178{
    179	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    180	struct nvkm_device *device = chan->disp->base.engine.subdev.device;
    181	u64 size, base = chan->func->user(chan, &size);
    182	*data = nvkm_rd32(device, base + addr);
    183	return 0;
    184}
    185
    186static int
    187nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
    188{
    189	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    190	struct nvkm_device *device = chan->disp->base.engine.subdev.device;
    191	u64 size, base = chan->func->user(chan, &size);
    192	nvkm_wr32(device, base + addr, data);
    193	return 0;
    194}
    195
    196static int
    197nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type,
    198		    struct nvkm_event **pevent)
    199{
    200	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    201	struct nv50_disp *disp = chan->disp;
    202	switch (type) {
    203	case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
    204		*pevent = &disp->uevent;
    205		return 0;
    206	default:
    207		break;
    208	}
    209	return -EINVAL;
    210}
    211
    212static int
    213nv50_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc,
    214		   enum nvkm_object_map *type, u64 *addr, u64 *size)
    215{
    216	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    217	struct nvkm_device *device = chan->disp->base.engine.subdev.device;
    218	const u64 base = device->func->resource_addr(device, 0);
    219	*type = NVKM_OBJECT_MAP_IO;
    220	*addr = base + chan->func->user(chan, size);
    221	return 0;
    222}
    223
    224struct nv50_disp_chan_object {
    225	struct nvkm_oproxy oproxy;
    226	struct nv50_disp *disp;
    227	int hash;
    228};
    229
    230static void
    231nv50_disp_chan_child_del_(struct nvkm_oproxy *base)
    232{
    233	struct nv50_disp_chan_object *object =
    234		container_of(base, typeof(*object), oproxy);
    235	nvkm_ramht_remove(object->disp->ramht, object->hash);
    236}
    237
    238static const struct nvkm_oproxy_func
    239nv50_disp_chan_child_func_ = {
    240	.dtor[0] = nv50_disp_chan_child_del_,
    241};
    242
    243static int
    244nv50_disp_chan_child_new(const struct nvkm_oclass *oclass,
    245			 void *argv, u32 argc, struct nvkm_object **pobject)
    246{
    247	struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent);
    248	struct nv50_disp *disp = chan->disp;
    249	struct nvkm_device *device = disp->base.engine.subdev.device;
    250	const struct nvkm_device_oclass *sclass = oclass->priv;
    251	struct nv50_disp_chan_object *object;
    252	int ret;
    253
    254	if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
    255		return -ENOMEM;
    256	nvkm_oproxy_ctor(&nv50_disp_chan_child_func_, oclass, &object->oproxy);
    257	object->disp = disp;
    258	*pobject = &object->oproxy.base;
    259
    260	ret = sclass->ctor(device, oclass, argv, argc, &object->oproxy.object);
    261	if (ret)
    262		return ret;
    263
    264	object->hash = chan->func->bind(chan, object->oproxy.object,
    265					      oclass->handle);
    266	if (object->hash < 0)
    267		return object->hash;
    268
    269	return 0;
    270}
    271
    272static int
    273nv50_disp_chan_child_get(struct nvkm_object *object, int index,
    274			 struct nvkm_oclass *sclass)
    275{
    276	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    277	struct nvkm_device *device = chan->disp->base.engine.subdev.device;
    278	const struct nvkm_device_oclass *oclass = NULL;
    279
    280	if (chan->func->bind)
    281		sclass->engine = nvkm_device_engine(device, NVKM_ENGINE_DMAOBJ, 0);
    282	else
    283		sclass->engine = NULL;
    284
    285	if (sclass->engine && sclass->engine->func->base.sclass) {
    286		sclass->engine->func->base.sclass(sclass, index, &oclass);
    287		if (oclass) {
    288			sclass->ctor = nv50_disp_chan_child_new,
    289			sclass->priv = oclass;
    290			return 0;
    291		}
    292	}
    293
    294	return -EINVAL;
    295}
    296
    297static int
    298nv50_disp_chan_fini(struct nvkm_object *object, bool suspend)
    299{
    300	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    301	chan->func->fini(chan);
    302	chan->func->intr(chan, false);
    303	return 0;
    304}
    305
    306static int
    307nv50_disp_chan_init(struct nvkm_object *object)
    308{
    309	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    310	chan->func->intr(chan, true);
    311	return chan->func->init(chan);
    312}
    313
    314static void *
    315nv50_disp_chan_dtor(struct nvkm_object *object)
    316{
    317	struct nv50_disp_chan *chan = nv50_disp_chan(object);
    318	struct nv50_disp *disp = chan->disp;
    319	if (chan->chid.user >= 0)
    320		disp->chan[chan->chid.user] = NULL;
    321	nvkm_memory_unref(&chan->memory);
    322	return chan;
    323}
    324
    325static const struct nvkm_object_func
    326nv50_disp_chan = {
    327	.dtor = nv50_disp_chan_dtor,
    328	.init = nv50_disp_chan_init,
    329	.fini = nv50_disp_chan_fini,
    330	.rd32 = nv50_disp_chan_rd32,
    331	.wr32 = nv50_disp_chan_wr32,
    332	.ntfy = nv50_disp_chan_ntfy,
    333	.map = nv50_disp_chan_map,
    334	.sclass = nv50_disp_chan_child_get,
    335};
    336
    337int
    338nv50_disp_chan_new_(const struct nv50_disp_chan_func *func,
    339		    const struct nv50_disp_chan_mthd *mthd,
    340		    struct nv50_disp *disp, int ctrl, int user, int head,
    341		    const struct nvkm_oclass *oclass,
    342		    struct nvkm_object **pobject)
    343{
    344	struct nv50_disp_chan *chan;
    345
    346	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
    347		return -ENOMEM;
    348	*pobject = &chan->object;
    349
    350	nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object);
    351	chan->func = func;
    352	chan->mthd = mthd;
    353	chan->disp = disp;
    354	chan->chid.ctrl = ctrl;
    355	chan->chid.user = user;
    356	chan->head = head;
    357
    358	if (disp->chan[chan->chid.user]) {
    359		chan->chid.user = -1;
    360		return -EBUSY;
    361	}
    362	disp->chan[chan->chid.user] = chan;
    363	return 0;
    364}