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

nv50.c (7972B)


      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 "nv50.h"
     25#include "ram.h"
     26
     27#include <core/client.h>
     28#include <core/enum.h>
     29#include <engine/fifo.h>
     30
     31static int
     32nv50_fb_ram_new(struct nvkm_fb *base, struct nvkm_ram **pram)
     33{
     34	struct nv50_fb *fb = nv50_fb(base);
     35	return fb->func->ram_new(&fb->base, pram);
     36}
     37
     38static const struct nvkm_enum vm_dispatch_subclients[] = {
     39	{ 0x00000000, "GRCTX" },
     40	{ 0x00000001, "NOTIFY" },
     41	{ 0x00000002, "QUERY" },
     42	{ 0x00000003, "COND" },
     43	{ 0x00000004, "M2M_IN" },
     44	{ 0x00000005, "M2M_OUT" },
     45	{ 0x00000006, "M2M_NOTIFY" },
     46	{}
     47};
     48
     49static const struct nvkm_enum vm_ccache_subclients[] = {
     50	{ 0x00000000, "CB" },
     51	{ 0x00000001, "TIC" },
     52	{ 0x00000002, "TSC" },
     53	{}
     54};
     55
     56static const struct nvkm_enum vm_prop_subclients[] = {
     57	{ 0x00000000, "RT0" },
     58	{ 0x00000001, "RT1" },
     59	{ 0x00000002, "RT2" },
     60	{ 0x00000003, "RT3" },
     61	{ 0x00000004, "RT4" },
     62	{ 0x00000005, "RT5" },
     63	{ 0x00000006, "RT6" },
     64	{ 0x00000007, "RT7" },
     65	{ 0x00000008, "ZETA" },
     66	{ 0x00000009, "LOCAL" },
     67	{ 0x0000000a, "GLOBAL" },
     68	{ 0x0000000b, "STACK" },
     69	{ 0x0000000c, "DST2D" },
     70	{}
     71};
     72
     73static const struct nvkm_enum vm_pfifo_subclients[] = {
     74	{ 0x00000000, "PUSHBUF" },
     75	{ 0x00000001, "SEMAPHORE" },
     76	{}
     77};
     78
     79static const struct nvkm_enum vm_bar_subclients[] = {
     80	{ 0x00000000, "FB" },
     81	{ 0x00000001, "IN" },
     82	{}
     83};
     84
     85static const struct nvkm_enum vm_client[] = {
     86	{ 0x00000000, "STRMOUT" },
     87	{ 0x00000003, "DISPATCH", vm_dispatch_subclients },
     88	{ 0x00000004, "PFIFO_WRITE" },
     89	{ 0x00000005, "CCACHE", vm_ccache_subclients },
     90	{ 0x00000006, "PMSPPP" },
     91	{ 0x00000007, "CLIPID" },
     92	{ 0x00000008, "PFIFO_READ" },
     93	{ 0x00000009, "VFETCH" },
     94	{ 0x0000000a, "TEXTURE" },
     95	{ 0x0000000b, "PROP", vm_prop_subclients },
     96	{ 0x0000000c, "PVP" },
     97	{ 0x0000000d, "PBSP" },
     98	{ 0x0000000e, "PCRYPT" },
     99	{ 0x0000000f, "PCOUNTER" },
    100	{ 0x00000011, "PDAEMON" },
    101	{}
    102};
    103
    104static const struct nvkm_enum vm_engine[] = {
    105	{ 0x00000000, "PGRAPH" },
    106	{ 0x00000001, "PVP" },
    107	{ 0x00000004, "PEEPHOLE" },
    108	{ 0x00000005, "PFIFO", vm_pfifo_subclients },
    109	{ 0x00000006, "BAR", vm_bar_subclients },
    110	{ 0x00000008, "PMSPPP" },
    111	{ 0x00000008, "PMPEG" },
    112	{ 0x00000009, "PBSP" },
    113	{ 0x0000000a, "PCRYPT" },
    114	{ 0x0000000b, "PCOUNTER" },
    115	{ 0x0000000c, "SEMAPHORE_BG" },
    116	{ 0x0000000d, "PCE0" },
    117	{ 0x0000000e, "PMU" },
    118	{}
    119};
    120
    121static const struct nvkm_enum vm_fault[] = {
    122	{ 0x00000000, "PT_NOT_PRESENT" },
    123	{ 0x00000001, "PT_TOO_SHORT" },
    124	{ 0x00000002, "PAGE_NOT_PRESENT" },
    125	{ 0x00000003, "PAGE_SYSTEM_ONLY" },
    126	{ 0x00000004, "PAGE_READ_ONLY" },
    127	{ 0x00000006, "NULL_DMAOBJ" },
    128	{ 0x00000007, "WRONG_MEMTYPE" },
    129	{ 0x0000000b, "VRAM_LIMIT" },
    130	{ 0x0000000f, "DMAOBJ_LIMIT" },
    131	{}
    132};
    133
    134static void
    135nv50_fb_intr(struct nvkm_fb *base)
    136{
    137	struct nv50_fb *fb = nv50_fb(base);
    138	struct nvkm_subdev *subdev = &fb->base.subdev;
    139	struct nvkm_device *device = subdev->device;
    140	struct nvkm_fifo *fifo = device->fifo;
    141	struct nvkm_fifo_chan *chan;
    142	const struct nvkm_enum *en, *re, *cl, *sc;
    143	u32 trap[6], idx, inst;
    144	u8 st0, st1, st2, st3;
    145	unsigned long flags;
    146	int i;
    147
    148	idx = nvkm_rd32(device, 0x100c90);
    149	if (!(idx & 0x80000000))
    150		return;
    151	idx &= 0x00ffffff;
    152
    153	for (i = 0; i < 6; i++) {
    154		nvkm_wr32(device, 0x100c90, idx | i << 24);
    155		trap[i] = nvkm_rd32(device, 0x100c94);
    156	}
    157	nvkm_wr32(device, 0x100c90, idx | 0x80000000);
    158
    159	/* decode status bits into something more useful */
    160	if (device->chipset  < 0xa3 ||
    161	    device->chipset == 0xaa || device->chipset == 0xac) {
    162		st0 = (trap[0] & 0x0000000f) >> 0;
    163		st1 = (trap[0] & 0x000000f0) >> 4;
    164		st2 = (trap[0] & 0x00000f00) >> 8;
    165		st3 = (trap[0] & 0x0000f000) >> 12;
    166	} else {
    167		st0 = (trap[0] & 0x000000ff) >> 0;
    168		st1 = (trap[0] & 0x0000ff00) >> 8;
    169		st2 = (trap[0] & 0x00ff0000) >> 16;
    170		st3 = (trap[0] & 0xff000000) >> 24;
    171	}
    172	inst = ((trap[2] << 16) | trap[1]) << 12;
    173
    174	en = nvkm_enum_find(vm_engine, st0);
    175	re = nvkm_enum_find(vm_fault , st1);
    176	cl = nvkm_enum_find(vm_client, st2);
    177	if      (cl && cl->data) sc = nvkm_enum_find(cl->data, st3);
    178	else if (en && en->data) sc = nvkm_enum_find(en->data, st3);
    179	else                     sc = NULL;
    180
    181	chan = nvkm_fifo_chan_inst(fifo, inst, &flags);
    182	nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] "
    183			   "engine %02x [%s] client %02x [%s] "
    184			   "subclient %02x [%s] reason %08x [%s]\n",
    185		   (trap[5] & 0x00000100) ? "read" : "write",
    186		   trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
    187		   chan ? chan->chid : -1, inst,
    188		   chan ? chan->object.client->name : "unknown",
    189		   st0, en ? en->name : "",
    190		   st2, cl ? cl->name : "", st3, sc ? sc->name : "",
    191		   st1, re ? re->name : "");
    192	nvkm_fifo_chan_put(fifo, flags, &chan);
    193}
    194
    195static int
    196nv50_fb_oneinit(struct nvkm_fb *base)
    197{
    198	struct nv50_fb *fb = nv50_fb(base);
    199	struct nvkm_device *device = fb->base.subdev.device;
    200
    201	fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
    202	if (fb->r100c08_page) {
    203		fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
    204					   PAGE_SIZE, DMA_BIDIRECTIONAL);
    205		if (dma_mapping_error(device->dev, fb->r100c08))
    206			return -EFAULT;
    207	}
    208
    209	return 0;
    210}
    211
    212static void
    213nv50_fb_init(struct nvkm_fb *base)
    214{
    215	struct nv50_fb *fb = nv50_fb(base);
    216	struct nvkm_device *device = fb->base.subdev.device;
    217
    218	/* Not a clue what this is exactly.  Without pointing it at a
    219	 * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
    220	 * cause IOMMU "read from address 0" errors (rh#561267)
    221	 */
    222	nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8);
    223
    224	/* This is needed to get meaningful information from 100c90
    225	 * on traps. No idea what these values mean exactly. */
    226	nvkm_wr32(device, 0x100c90, fb->func->trap);
    227}
    228
    229static u32
    230nv50_fb_tags(struct nvkm_fb *base)
    231{
    232	struct nv50_fb *fb = nv50_fb(base);
    233	if (fb->func->tags)
    234		return fb->func->tags(&fb->base);
    235	return 0;
    236}
    237
    238static void *
    239nv50_fb_dtor(struct nvkm_fb *base)
    240{
    241	struct nv50_fb *fb = nv50_fb(base);
    242	struct nvkm_device *device = fb->base.subdev.device;
    243
    244	if (fb->r100c08_page) {
    245		dma_unmap_page(device->dev, fb->r100c08, PAGE_SIZE,
    246			       DMA_BIDIRECTIONAL);
    247		__free_page(fb->r100c08_page);
    248	}
    249
    250	return fb;
    251}
    252
    253static const struct nvkm_fb_func
    254nv50_fb_ = {
    255	.dtor = nv50_fb_dtor,
    256	.tags = nv50_fb_tags,
    257	.oneinit = nv50_fb_oneinit,
    258	.init = nv50_fb_init,
    259	.intr = nv50_fb_intr,
    260	.ram_new = nv50_fb_ram_new,
    261};
    262
    263int
    264nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device,
    265	     enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
    266{
    267	struct nv50_fb *fb;
    268
    269	if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL)))
    270		return -ENOMEM;
    271	nvkm_fb_ctor(&nv50_fb_, device, type, inst, &fb->base);
    272	fb->func = func;
    273	*pfb = &fb->base;
    274	return 0;
    275}
    276
    277static const struct nv50_fb_func
    278nv50_fb = {
    279	.ram_new = nv50_ram_new,
    280	.tags = nv20_fb_tags,
    281	.trap = 0x000707ff,
    282};
    283
    284int
    285nv50_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
    286{
    287	return nv50_fb_new_(&nv50_fb, device, type, inst, pfb);
    288}