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

gpfifogf100.c (9209B)


      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 "changf100.h"
     25
     26#include <core/client.h>
     27#include <core/gpuobj.h>
     28#include <subdev/fb.h>
     29#include <subdev/timer.h>
     30
     31#include <nvif/class.h>
     32#include <nvif/cl906f.h>
     33#include <nvif/unpack.h>
     34
     35int
     36gf100_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type,
     37		     struct nvkm_event **pevent)
     38{
     39	switch (type) {
     40	case NV906F_V0_NTFY_NON_STALL_INTERRUPT:
     41		*pevent = &chan->fifo->uevent;
     42		return 0;
     43	case NV906F_V0_NTFY_KILLED:
     44		*pevent = &chan->fifo->kevent;
     45		return 0;
     46	default:
     47		break;
     48	}
     49	return -EINVAL;
     50}
     51
     52static u32
     53gf100_fifo_gpfifo_engine_addr(struct nvkm_engine *engine)
     54{
     55	switch (engine->subdev.type) {
     56	case NVKM_ENGINE_SW    : return 0;
     57	case NVKM_ENGINE_GR    : return 0x0210;
     58	case NVKM_ENGINE_CE    : return 0x0230 + (engine->subdev.inst * 0x10);
     59	case NVKM_ENGINE_MSPDEC: return 0x0250;
     60	case NVKM_ENGINE_MSPPP : return 0x0260;
     61	case NVKM_ENGINE_MSVLD : return 0x0270;
     62	default:
     63		WARN_ON(1);
     64		return 0;
     65	}
     66}
     67
     68static struct gf100_fifo_engn *
     69gf100_fifo_gpfifo_engine(struct gf100_fifo_chan *chan, struct nvkm_engine *engine)
     70{
     71	int engi = chan->base.fifo->func->engine_id(chan->base.fifo, engine);
     72	if (engi >= 0)
     73		return &chan->engn[engi];
     74	return NULL;
     75}
     76
     77static int
     78gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
     79			      struct nvkm_engine *engine, bool suspend)
     80{
     81	const u32 offset = gf100_fifo_gpfifo_engine_addr(engine);
     82	struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
     83	struct nvkm_subdev *subdev = &chan->fifo->base.engine.subdev;
     84	struct nvkm_device *device = subdev->device;
     85	struct nvkm_gpuobj *inst = chan->base.inst;
     86	int ret = 0;
     87
     88	mutex_lock(&chan->fifo->base.mutex);
     89	nvkm_wr32(device, 0x002634, chan->base.chid);
     90	if (nvkm_msec(device, 2000,
     91		if (nvkm_rd32(device, 0x002634) == chan->base.chid)
     92			break;
     93	) < 0) {
     94		nvkm_error(subdev, "channel %d [%s] kick timeout\n",
     95			   chan->base.chid, chan->base.object.client->name);
     96		ret = -ETIMEDOUT;
     97	}
     98	mutex_unlock(&chan->fifo->base.mutex);
     99
    100	if (ret && suspend)
    101		return ret;
    102
    103	if (offset) {
    104		nvkm_kmap(inst);
    105		nvkm_wo32(inst, offset + 0x00, 0x00000000);
    106		nvkm_wo32(inst, offset + 0x04, 0x00000000);
    107		nvkm_done(inst);
    108	}
    109
    110	return ret;
    111}
    112
    113static int
    114gf100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base,
    115			      struct nvkm_engine *engine)
    116{
    117	const u32 offset = gf100_fifo_gpfifo_engine_addr(engine);
    118	struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
    119	struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine);
    120	struct nvkm_gpuobj *inst = chan->base.inst;
    121
    122	if (offset) {
    123		nvkm_kmap(inst);
    124		nvkm_wo32(inst, offset + 0x00, lower_32_bits(engn->vma->addr) | 4);
    125		nvkm_wo32(inst, offset + 0x04, upper_32_bits(engn->vma->addr));
    126		nvkm_done(inst);
    127	}
    128
    129	return 0;
    130}
    131
    132static void
    133gf100_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base,
    134			      struct nvkm_engine *engine)
    135{
    136	struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
    137	struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine);
    138	nvkm_vmm_put(chan->base.vmm, &engn->vma);
    139	nvkm_gpuobj_del(&engn->inst);
    140}
    141
    142static int
    143gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base,
    144			      struct nvkm_engine *engine,
    145			      struct nvkm_object *object)
    146{
    147	struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
    148	struct gf100_fifo_engn *engn = gf100_fifo_gpfifo_engine(chan, engine);
    149	int ret;
    150
    151	if (!gf100_fifo_gpfifo_engine_addr(engine))
    152		return 0;
    153
    154	ret = nvkm_object_bind(object, NULL, 0, &engn->inst);
    155	if (ret)
    156		return ret;
    157
    158	ret = nvkm_vmm_get(chan->base.vmm, 12, engn->inst->size, &engn->vma);
    159	if (ret)
    160		return ret;
    161
    162	return nvkm_memory_map(engn->inst, 0, chan->base.vmm, engn->vma, NULL, 0);
    163}
    164
    165static void
    166gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
    167{
    168	struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
    169	struct gf100_fifo *fifo = chan->fifo;
    170	struct nvkm_device *device = fifo->base.engine.subdev.device;
    171	u32 coff = chan->base.chid * 8;
    172
    173	if (!list_empty(&chan->head) && !chan->killed) {
    174		gf100_fifo_runlist_remove(fifo, chan);
    175		nvkm_mask(device, 0x003004 + coff, 0x00000001, 0x00000000);
    176		gf100_fifo_runlist_commit(fifo);
    177	}
    178
    179	gf100_fifo_intr_engine(fifo);
    180
    181	nvkm_wr32(device, 0x003000 + coff, 0x00000000);
    182}
    183
    184static void
    185gf100_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
    186{
    187	struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
    188	struct gf100_fifo *fifo = chan->fifo;
    189	struct nvkm_device *device = fifo->base.engine.subdev.device;
    190	u32 addr = chan->base.inst->addr >> 12;
    191	u32 coff = chan->base.chid * 8;
    192
    193	nvkm_wr32(device, 0x003000 + coff, 0xc0000000 | addr);
    194
    195	if (list_empty(&chan->head) && !chan->killed) {
    196		gf100_fifo_runlist_insert(fifo, chan);
    197		nvkm_wr32(device, 0x003004 + coff, 0x001f0001);
    198		gf100_fifo_runlist_commit(fifo);
    199	}
    200}
    201
    202static void *
    203gf100_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base)
    204{
    205	return gf100_fifo_chan(base);
    206}
    207
    208static const struct nvkm_fifo_chan_func
    209gf100_fifo_gpfifo_func = {
    210	.dtor = gf100_fifo_gpfifo_dtor,
    211	.init = gf100_fifo_gpfifo_init,
    212	.fini = gf100_fifo_gpfifo_fini,
    213	.ntfy = gf100_fifo_chan_ntfy,
    214	.engine_ctor = gf100_fifo_gpfifo_engine_ctor,
    215	.engine_dtor = gf100_fifo_gpfifo_engine_dtor,
    216	.engine_init = gf100_fifo_gpfifo_engine_init,
    217	.engine_fini = gf100_fifo_gpfifo_engine_fini,
    218};
    219
    220static int
    221gf100_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
    222		      void *data, u32 size, struct nvkm_object **pobject)
    223{
    224	union {
    225		struct fermi_channel_gpfifo_v0 v0;
    226	} *args = data;
    227	struct gf100_fifo *fifo = gf100_fifo(base);
    228	struct nvkm_object *parent = oclass->parent;
    229	struct gf100_fifo_chan *chan;
    230	u64 usermem, ioffset, ilength;
    231	int ret = -ENOSYS, i;
    232
    233	nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
    234	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    235		nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
    236				   "ioffset %016llx ilength %08x\n",
    237			   args->v0.version, args->v0.vmm, args->v0.ioffset,
    238			   args->v0.ilength);
    239		if (!args->v0.vmm)
    240			return -EINVAL;
    241	} else
    242		return ret;
    243
    244	/* allocate channel */
    245	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
    246		return -ENOMEM;
    247	*pobject = &chan->base.object;
    248	chan->fifo = fifo;
    249	INIT_LIST_HEAD(&chan->head);
    250
    251	ret = nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func, &fifo->base,
    252				  0x1000, 0x1000, true, args->v0.vmm, 0,
    253				  BIT(GF100_FIFO_ENGN_GR) |
    254				  BIT(GF100_FIFO_ENGN_MSPDEC) |
    255				  BIT(GF100_FIFO_ENGN_MSPPP) |
    256				  BIT(GF100_FIFO_ENGN_MSVLD) |
    257				  BIT(GF100_FIFO_ENGN_CE0) |
    258				  BIT(GF100_FIFO_ENGN_CE1) |
    259				  BIT(GF100_FIFO_ENGN_SW),
    260				  1, fifo->user.bar->addr, 0x1000,
    261				  oclass, &chan->base);
    262	if (ret)
    263		return ret;
    264
    265	args->v0.chid = chan->base.chid;
    266
    267	/* clear channel control registers */
    268
    269	usermem = chan->base.chid * 0x1000;
    270	ioffset = args->v0.ioffset;
    271	ilength = order_base_2(args->v0.ilength / 8);
    272
    273	nvkm_kmap(fifo->user.mem);
    274	for (i = 0; i < 0x1000; i += 4)
    275		nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000);
    276	nvkm_done(fifo->user.mem);
    277	usermem = nvkm_memory_addr(fifo->user.mem) + usermem;
    278
    279	/* RAMFC */
    280	nvkm_kmap(chan->base.inst);
    281	nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem));
    282	nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem));
    283	nvkm_wo32(chan->base.inst, 0x10, 0x0000face);
    284	nvkm_wo32(chan->base.inst, 0x30, 0xfffff902);
    285	nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset));
    286	nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) |
    287					 (ilength << 16));
    288	nvkm_wo32(chan->base.inst, 0x54, 0x00000002);
    289	nvkm_wo32(chan->base.inst, 0x84, 0x20400000);
    290	nvkm_wo32(chan->base.inst, 0x94, 0x30000001);
    291	nvkm_wo32(chan->base.inst, 0x9c, 0x00000100);
    292	nvkm_wo32(chan->base.inst, 0xa4, 0x1f1f1f1f);
    293	nvkm_wo32(chan->base.inst, 0xa8, 0x1f1f1f1f);
    294	nvkm_wo32(chan->base.inst, 0xac, 0x0000001f);
    295	nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000);
    296	nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */
    297	nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */
    298	nvkm_done(chan->base.inst);
    299	return 0;
    300}
    301
    302const struct nvkm_fifo_chan_oclass
    303gf100_fifo_gpfifo_oclass = {
    304	.base.oclass = FERMI_CHANNEL_GPFIFO,
    305	.base.minver = 0,
    306	.base.maxver = 0,
    307	.ctor = gf100_fifo_gpfifo_new,
    308};