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

nouveau_chan.c (15971B)


      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 <nvif/push006c.h>
     25
     26#include <nvif/class.h>
     27#include <nvif/cl0002.h>
     28#include <nvif/cl006b.h>
     29#include <nvif/cl506f.h>
     30#include <nvif/cl906f.h>
     31#include <nvif/cla06f.h>
     32#include <nvif/clc36f.h>
     33#include <nvif/ioctl.h>
     34
     35#include "nouveau_drv.h"
     36#include "nouveau_dma.h"
     37#include "nouveau_bo.h"
     38#include "nouveau_chan.h"
     39#include "nouveau_fence.h"
     40#include "nouveau_abi16.h"
     41#include "nouveau_vmm.h"
     42#include "nouveau_svm.h"
     43
     44MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM");
     45int nouveau_vram_pushbuf;
     46module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
     47
     48static int
     49nouveau_channel_killed(struct nvif_notify *ntfy)
     50{
     51	struct nouveau_channel *chan = container_of(ntfy, typeof(*chan), kill);
     52	struct nouveau_cli *cli = (void *)chan->user.client;
     53	NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid);
     54	atomic_set(&chan->killed, 1);
     55	if (chan->fence)
     56		nouveau_fence_context_kill(chan->fence, -ENODEV);
     57	return NVIF_NOTIFY_DROP;
     58}
     59
     60int
     61nouveau_channel_idle(struct nouveau_channel *chan)
     62{
     63	if (likely(chan && chan->fence && !atomic_read(&chan->killed))) {
     64		struct nouveau_cli *cli = (void *)chan->user.client;
     65		struct nouveau_fence *fence = NULL;
     66		int ret;
     67
     68		ret = nouveau_fence_new(chan, false, &fence);
     69		if (!ret) {
     70			ret = nouveau_fence_wait(fence, false, false);
     71			nouveau_fence_unref(&fence);
     72		}
     73
     74		if (ret) {
     75			NV_PRINTK(err, cli, "failed to idle channel %d [%s]\n",
     76				  chan->chid, nvxx_client(&cli->base)->name);
     77			return ret;
     78		}
     79	}
     80	return 0;
     81}
     82
     83void
     84nouveau_channel_del(struct nouveau_channel **pchan)
     85{
     86	struct nouveau_channel *chan = *pchan;
     87	if (chan) {
     88		struct nouveau_cli *cli = (void *)chan->user.client;
     89
     90		if (chan->fence)
     91			nouveau_fence(chan->drm)->context_del(chan);
     92
     93		if (cli)
     94			nouveau_svmm_part(chan->vmm->svmm, chan->inst);
     95
     96		nvif_object_dtor(&chan->nvsw);
     97		nvif_object_dtor(&chan->gart);
     98		nvif_object_dtor(&chan->vram);
     99		nvif_notify_dtor(&chan->kill);
    100		nvif_object_dtor(&chan->user);
    101		nvif_object_dtor(&chan->push.ctxdma);
    102		nouveau_vma_del(&chan->push.vma);
    103		nouveau_bo_unmap(chan->push.buffer);
    104		if (chan->push.buffer && chan->push.buffer->bo.pin_count)
    105			nouveau_bo_unpin(chan->push.buffer);
    106		nouveau_bo_ref(NULL, &chan->push.buffer);
    107		kfree(chan);
    108	}
    109	*pchan = NULL;
    110}
    111
    112static void
    113nouveau_channel_kick(struct nvif_push *push)
    114{
    115	struct nouveau_channel *chan = container_of(push, typeof(*chan), chan._push);
    116	chan->dma.cur = chan->dma.cur + (chan->chan._push.cur - chan->chan._push.bgn);
    117	FIRE_RING(chan);
    118	chan->chan._push.bgn = chan->chan._push.cur;
    119}
    120
    121static int
    122nouveau_channel_wait(struct nvif_push *push, u32 size)
    123{
    124	struct nouveau_channel *chan = container_of(push, typeof(*chan), chan._push);
    125	int ret;
    126	chan->dma.cur = chan->dma.cur + (chan->chan._push.cur - chan->chan._push.bgn);
    127	ret = RING_SPACE(chan, size);
    128	if (ret == 0) {
    129		chan->chan._push.bgn = chan->chan._push.mem.object.map.ptr;
    130		chan->chan._push.bgn = chan->chan._push.bgn + chan->dma.cur;
    131		chan->chan._push.cur = chan->chan._push.bgn;
    132		chan->chan._push.end = chan->chan._push.bgn + size;
    133	}
    134	return ret;
    135}
    136
    137static int
    138nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
    139		     u32 size, struct nouveau_channel **pchan)
    140{
    141	struct nouveau_cli *cli = (void *)device->object.client;
    142	struct nv_dma_v0 args = {};
    143	struct nouveau_channel *chan;
    144	u32 target;
    145	int ret;
    146
    147	chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL);
    148	if (!chan)
    149		return -ENOMEM;
    150
    151	chan->device = device;
    152	chan->drm = drm;
    153	chan->vmm = cli->svm.cli ? &cli->svm : &cli->vmm;
    154	atomic_set(&chan->killed, 0);
    155
    156	/* allocate memory for dma push buffer */
    157	target = NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT;
    158	if (nouveau_vram_pushbuf)
    159		target = NOUVEAU_GEM_DOMAIN_VRAM;
    160
    161	ret = nouveau_bo_new(cli, size, 0, target, 0, 0, NULL, NULL,
    162			    &chan->push.buffer);
    163	if (ret == 0) {
    164		ret = nouveau_bo_pin(chan->push.buffer, target, false);
    165		if (ret == 0)
    166			ret = nouveau_bo_map(chan->push.buffer);
    167	}
    168
    169	if (ret) {
    170		nouveau_channel_del(pchan);
    171		return ret;
    172	}
    173
    174	chan->chan._push.mem.object.parent = cli->base.object.parent;
    175	chan->chan._push.mem.object.client = &cli->base;
    176	chan->chan._push.mem.object.name = "chanPush";
    177	chan->chan._push.mem.object.map.ptr = chan->push.buffer->kmap.virtual;
    178	chan->chan._push.wait = nouveau_channel_wait;
    179	chan->chan._push.kick = nouveau_channel_kick;
    180	chan->chan.push = &chan->chan._push;
    181
    182	/* create dma object covering the *entire* memory space that the
    183	 * pushbuf lives in, this is because the GEM code requires that
    184	 * we be able to call out to other (indirect) push buffers
    185	 */
    186	chan->push.addr = chan->push.buffer->offset;
    187
    188	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
    189		ret = nouveau_vma_new(chan->push.buffer, chan->vmm,
    190				      &chan->push.vma);
    191		if (ret) {
    192			nouveau_channel_del(pchan);
    193			return ret;
    194		}
    195
    196		chan->push.addr = chan->push.vma->addr;
    197
    198		if (device->info.family >= NV_DEVICE_INFO_V0_FERMI)
    199			return 0;
    200
    201		args.target = NV_DMA_V0_TARGET_VM;
    202		args.access = NV_DMA_V0_ACCESS_VM;
    203		args.start = 0;
    204		args.limit = chan->vmm->vmm.limit - 1;
    205	} else
    206	if (chan->push.buffer->bo.resource->mem_type == TTM_PL_VRAM) {
    207		if (device->info.family == NV_DEVICE_INFO_V0_TNT) {
    208			/* nv04 vram pushbuf hack, retarget to its location in
    209			 * the framebuffer bar rather than direct vram access..
    210			 * nfi why this exists, it came from the -nv ddx.
    211			 */
    212			args.target = NV_DMA_V0_TARGET_PCI;
    213			args.access = NV_DMA_V0_ACCESS_RDWR;
    214			args.start = nvxx_device(device)->func->
    215				resource_addr(nvxx_device(device), 1);
    216			args.limit = args.start + device->info.ram_user - 1;
    217		} else {
    218			args.target = NV_DMA_V0_TARGET_VRAM;
    219			args.access = NV_DMA_V0_ACCESS_RDWR;
    220			args.start = 0;
    221			args.limit = device->info.ram_user - 1;
    222		}
    223	} else {
    224		if (chan->drm->agp.bridge) {
    225			args.target = NV_DMA_V0_TARGET_AGP;
    226			args.access = NV_DMA_V0_ACCESS_RDWR;
    227			args.start = chan->drm->agp.base;
    228			args.limit = chan->drm->agp.base +
    229				     chan->drm->agp.size - 1;
    230		} else {
    231			args.target = NV_DMA_V0_TARGET_VM;
    232			args.access = NV_DMA_V0_ACCESS_RDWR;
    233			args.start = 0;
    234			args.limit = chan->vmm->vmm.limit - 1;
    235		}
    236	}
    237
    238	ret = nvif_object_ctor(&device->object, "abi16PushCtxDma", 0,
    239			       NV_DMA_FROM_MEMORY, &args, sizeof(args),
    240			       &chan->push.ctxdma);
    241	if (ret) {
    242		nouveau_channel_del(pchan);
    243		return ret;
    244	}
    245
    246	return 0;
    247}
    248
    249static int
    250nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
    251		    u64 runlist, bool priv, struct nouveau_channel **pchan)
    252{
    253	static const u16 oclasses[] = { AMPERE_CHANNEL_GPFIFO_B,
    254					TURING_CHANNEL_GPFIFO_A,
    255					VOLTA_CHANNEL_GPFIFO_A,
    256					PASCAL_CHANNEL_GPFIFO_A,
    257					MAXWELL_CHANNEL_GPFIFO_A,
    258					KEPLER_CHANNEL_GPFIFO_B,
    259					KEPLER_CHANNEL_GPFIFO_A,
    260					FERMI_CHANNEL_GPFIFO,
    261					G82_CHANNEL_GPFIFO,
    262					NV50_CHANNEL_GPFIFO,
    263					0 };
    264	const u16 *oclass = oclasses;
    265	union {
    266		struct nv50_channel_gpfifo_v0 nv50;
    267		struct fermi_channel_gpfifo_v0 fermi;
    268		struct kepler_channel_gpfifo_a_v0 kepler;
    269		struct volta_channel_gpfifo_a_v0 volta;
    270	} args;
    271	struct nouveau_channel *chan;
    272	u32 size;
    273	int ret;
    274
    275	/* allocate dma push buffer */
    276	ret = nouveau_channel_prep(drm, device, 0x12000, &chan);
    277	*pchan = chan;
    278	if (ret)
    279		return ret;
    280
    281	/* create channel object */
    282	do {
    283		if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) {
    284			args.volta.version = 0;
    285			args.volta.ilength = 0x02000;
    286			args.volta.ioffset = 0x10000 + chan->push.addr;
    287			args.volta.runlist = runlist;
    288			args.volta.vmm = nvif_handle(&chan->vmm->vmm.object);
    289			args.volta.priv = priv;
    290			size = sizeof(args.volta);
    291		} else
    292		if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
    293			args.kepler.version = 0;
    294			args.kepler.ilength = 0x02000;
    295			args.kepler.ioffset = 0x10000 + chan->push.addr;
    296			args.kepler.runlist = runlist;
    297			args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object);
    298			args.kepler.priv = priv;
    299			size = sizeof(args.kepler);
    300		} else
    301		if (oclass[0] >= FERMI_CHANNEL_GPFIFO) {
    302			args.fermi.version = 0;
    303			args.fermi.ilength = 0x02000;
    304			args.fermi.ioffset = 0x10000 + chan->push.addr;
    305			args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object);
    306			size = sizeof(args.fermi);
    307		} else {
    308			args.nv50.version = 0;
    309			args.nv50.ilength = 0x02000;
    310			args.nv50.ioffset = 0x10000 + chan->push.addr;
    311			args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma);
    312			args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object);
    313			size = sizeof(args.nv50);
    314		}
    315
    316		ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
    317				       *oclass++, &args, size, &chan->user);
    318		if (ret == 0) {
    319			if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) {
    320				chan->chid = args.volta.chid;
    321				chan->inst = args.volta.inst;
    322				chan->token = args.volta.token;
    323			} else
    324			if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) {
    325				chan->chid = args.kepler.chid;
    326				chan->inst = args.kepler.inst;
    327			} else
    328			if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
    329				chan->chid = args.fermi.chid;
    330			} else {
    331				chan->chid = args.nv50.chid;
    332			}
    333			return ret;
    334		}
    335	} while (*oclass);
    336
    337	nouveau_channel_del(pchan);
    338	return ret;
    339}
    340
    341static int
    342nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
    343		    struct nouveau_channel **pchan)
    344{
    345	static const u16 oclasses[] = { NV40_CHANNEL_DMA,
    346					NV17_CHANNEL_DMA,
    347					NV10_CHANNEL_DMA,
    348					NV03_CHANNEL_DMA,
    349					0 };
    350	const u16 *oclass = oclasses;
    351	struct nv03_channel_dma_v0 args;
    352	struct nouveau_channel *chan;
    353	int ret;
    354
    355	/* allocate dma push buffer */
    356	ret = nouveau_channel_prep(drm, device, 0x10000, &chan);
    357	*pchan = chan;
    358	if (ret)
    359		return ret;
    360
    361	/* create channel object */
    362	args.version = 0;
    363	args.pushbuf = nvif_handle(&chan->push.ctxdma);
    364	args.offset = chan->push.addr;
    365
    366	do {
    367		ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
    368				       *oclass++, &args, sizeof(args),
    369				       &chan->user);
    370		if (ret == 0) {
    371			chan->chid = args.chid;
    372			return ret;
    373		}
    374	} while (ret && *oclass);
    375
    376	nouveau_channel_del(pchan);
    377	return ret;
    378}
    379
    380static int
    381nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
    382{
    383	struct nvif_device *device = chan->device;
    384	struct nouveau_drm *drm = chan->drm;
    385	struct nv_dma_v0 args = {};
    386	int ret, i;
    387
    388	nvif_object_map(&chan->user, NULL, 0);
    389
    390	if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO &&
    391	    chan->user.oclass < AMPERE_CHANNEL_GPFIFO_B) {
    392		ret = nvif_notify_ctor(&chan->user, "abi16ChanKilled",
    393				       nouveau_channel_killed,
    394				       true, NV906F_V0_NTFY_KILLED,
    395				       NULL, 0, 0, &chan->kill);
    396		if (ret == 0)
    397			ret = nvif_notify_get(&chan->kill);
    398		if (ret) {
    399			NV_ERROR(drm, "Failed to request channel kill "
    400				      "notification: %d\n", ret);
    401			return ret;
    402		}
    403	}
    404
    405	/* allocate dma objects to cover all allowed vram, and gart */
    406	if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
    407		if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
    408			args.target = NV_DMA_V0_TARGET_VM;
    409			args.access = NV_DMA_V0_ACCESS_VM;
    410			args.start = 0;
    411			args.limit = chan->vmm->vmm.limit - 1;
    412		} else {
    413			args.target = NV_DMA_V0_TARGET_VRAM;
    414			args.access = NV_DMA_V0_ACCESS_RDWR;
    415			args.start = 0;
    416			args.limit = device->info.ram_user - 1;
    417		}
    418
    419		ret = nvif_object_ctor(&chan->user, "abi16ChanVramCtxDma", vram,
    420				       NV_DMA_IN_MEMORY, &args, sizeof(args),
    421				       &chan->vram);
    422		if (ret)
    423			return ret;
    424
    425		if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
    426			args.target = NV_DMA_V0_TARGET_VM;
    427			args.access = NV_DMA_V0_ACCESS_VM;
    428			args.start = 0;
    429			args.limit = chan->vmm->vmm.limit - 1;
    430		} else
    431		if (chan->drm->agp.bridge) {
    432			args.target = NV_DMA_V0_TARGET_AGP;
    433			args.access = NV_DMA_V0_ACCESS_RDWR;
    434			args.start = chan->drm->agp.base;
    435			args.limit = chan->drm->agp.base +
    436				     chan->drm->agp.size - 1;
    437		} else {
    438			args.target = NV_DMA_V0_TARGET_VM;
    439			args.access = NV_DMA_V0_ACCESS_RDWR;
    440			args.start = 0;
    441			args.limit = chan->vmm->vmm.limit - 1;
    442		}
    443
    444		ret = nvif_object_ctor(&chan->user, "abi16ChanGartCtxDma", gart,
    445				       NV_DMA_IN_MEMORY, &args, sizeof(args),
    446				       &chan->gart);
    447		if (ret)
    448			return ret;
    449	}
    450
    451	/* initialise dma tracking parameters */
    452	switch (chan->user.oclass & 0x00ff) {
    453	case 0x006b:
    454	case 0x006e:
    455		chan->user_put = 0x40;
    456		chan->user_get = 0x44;
    457		chan->dma.max = (0x10000 / 4) - 2;
    458		break;
    459	default:
    460		chan->user_put = 0x40;
    461		chan->user_get = 0x44;
    462		chan->user_get_hi = 0x60;
    463		chan->dma.ib_base =  0x10000 / 4;
    464		chan->dma.ib_max  = (0x02000 / 8) - 1;
    465		chan->dma.ib_put  = 0;
    466		chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
    467		chan->dma.max = chan->dma.ib_base;
    468		break;
    469	}
    470
    471	chan->dma.put = 0;
    472	chan->dma.cur = chan->dma.put;
    473	chan->dma.free = chan->dma.max - chan->dma.cur;
    474
    475	ret = PUSH_WAIT(chan->chan.push, NOUVEAU_DMA_SKIPS);
    476	if (ret)
    477		return ret;
    478
    479	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
    480		PUSH_DATA(chan->chan.push, 0x00000000);
    481
    482	/* allocate software object class (used for fences on <= nv05) */
    483	if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
    484		ret = nvif_object_ctor(&chan->user, "abi16NvswFence", 0x006e,
    485				       NVIF_CLASS_SW_NV04,
    486				       NULL, 0, &chan->nvsw);
    487		if (ret)
    488			return ret;
    489
    490		ret = PUSH_WAIT(chan->chan.push, 2);
    491		if (ret)
    492			return ret;
    493
    494		PUSH_NVSQ(chan->chan.push, NV_SW, 0x0000, chan->nvsw.handle);
    495		PUSH_KICK(chan->chan.push);
    496	}
    497
    498	/* initialise synchronisation */
    499	return nouveau_fence(chan->drm)->context_new(chan);
    500}
    501
    502int
    503nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
    504		    u32 arg0, u32 arg1, bool priv,
    505		    struct nouveau_channel **pchan)
    506{
    507	struct nouveau_cli *cli = (void *)device->object.client;
    508	int ret;
    509
    510	/* hack until fencenv50 is fixed, and agp access relaxed */
    511	ret = nouveau_channel_ind(drm, device, arg0, priv, pchan);
    512	if (ret) {
    513		NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret);
    514		ret = nouveau_channel_dma(drm, device, pchan);
    515		if (ret) {
    516			NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret);
    517			return ret;
    518		}
    519	}
    520
    521	ret = nouveau_channel_init(*pchan, arg0, arg1);
    522	if (ret) {
    523		NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret);
    524		nouveau_channel_del(pchan);
    525		return ret;
    526	}
    527
    528	ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst);
    529	if (ret)
    530		nouveau_channel_del(pchan);
    531
    532	return ret;
    533}
    534
    535int
    536nouveau_channels_init(struct nouveau_drm *drm)
    537{
    538	struct {
    539		struct nv_device_info_v1 m;
    540		struct {
    541			struct nv_device_info_v1_data channels;
    542		} v;
    543	} args = {
    544		.m.version = 1,
    545		.m.count = sizeof(args.v) / sizeof(args.v.channels),
    546		.v.channels.mthd = NV_DEVICE_HOST_CHANNELS,
    547	};
    548	struct nvif_object *device = &drm->client.device.object;
    549	int ret;
    550
    551	ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
    552	if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
    553		return -ENODEV;
    554
    555	drm->chan.nr = args.v.channels.data;
    556	drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr);
    557	return 0;
    558}