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

nv44.c (6205B)


      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#define nv44_mpeg(p) container_of((p), struct nv44_mpeg, engine)
     25#include "priv.h"
     26
     27#include <core/client.h>
     28#include <core/gpuobj.h>
     29#include <engine/fifo.h>
     30
     31#include <nvif/class.h>
     32
     33struct nv44_mpeg {
     34	struct nvkm_engine engine;
     35	struct list_head chan;
     36};
     37
     38/*******************************************************************************
     39 * PMPEG context
     40 ******************************************************************************/
     41#define nv44_mpeg_chan(p) container_of((p), struct nv44_mpeg_chan, object)
     42
     43struct nv44_mpeg_chan {
     44	struct nvkm_object object;
     45	struct nv44_mpeg *mpeg;
     46	struct nvkm_fifo_chan *fifo;
     47	struct list_head head;
     48	u32 inst;
     49};
     50
     51static int
     52nv44_mpeg_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent,
     53		    int align, struct nvkm_gpuobj **pgpuobj)
     54{
     55	struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object);
     56	int ret = nvkm_gpuobj_new(chan->object.engine->subdev.device, 264 * 4,
     57				  align, true, parent, pgpuobj);
     58	if (ret == 0) {
     59		chan->inst = (*pgpuobj)->addr;
     60		nvkm_kmap(*pgpuobj);
     61		nvkm_wo32(*pgpuobj, 0x78, 0x02001ec1);
     62		nvkm_done(*pgpuobj);
     63	}
     64	return ret;
     65}
     66
     67static int
     68nv44_mpeg_chan_fini(struct nvkm_object *object, bool suspend)
     69{
     70
     71	struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object);
     72	struct nv44_mpeg *mpeg = chan->mpeg;
     73	struct nvkm_device *device = mpeg->engine.subdev.device;
     74	u32 inst = 0x80000000 | (chan->inst >> 4);
     75
     76	nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000);
     77	if (nvkm_rd32(device, 0x00b318) == inst)
     78		nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000);
     79	nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001);
     80	return 0;
     81}
     82
     83static void *
     84nv44_mpeg_chan_dtor(struct nvkm_object *object)
     85{
     86	struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object);
     87	struct nv44_mpeg *mpeg = chan->mpeg;
     88	unsigned long flags;
     89	spin_lock_irqsave(&mpeg->engine.lock, flags);
     90	list_del(&chan->head);
     91	spin_unlock_irqrestore(&mpeg->engine.lock, flags);
     92	return chan;
     93}
     94
     95static const struct nvkm_object_func
     96nv44_mpeg_chan = {
     97	.dtor = nv44_mpeg_chan_dtor,
     98	.fini = nv44_mpeg_chan_fini,
     99	.bind = nv44_mpeg_chan_bind,
    100};
    101
    102static int
    103nv44_mpeg_chan_new(struct nvkm_fifo_chan *fifoch,
    104		   const struct nvkm_oclass *oclass,
    105		   struct nvkm_object **pobject)
    106{
    107	struct nv44_mpeg *mpeg = nv44_mpeg(oclass->engine);
    108	struct nv44_mpeg_chan *chan;
    109	unsigned long flags;
    110
    111	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
    112		return -ENOMEM;
    113	nvkm_object_ctor(&nv44_mpeg_chan, oclass, &chan->object);
    114	chan->mpeg = mpeg;
    115	chan->fifo = fifoch;
    116	*pobject = &chan->object;
    117
    118	spin_lock_irqsave(&mpeg->engine.lock, flags);
    119	list_add(&chan->head, &mpeg->chan);
    120	spin_unlock_irqrestore(&mpeg->engine.lock, flags);
    121	return 0;
    122}
    123
    124/*******************************************************************************
    125 * PMPEG engine/subdev functions
    126 ******************************************************************************/
    127
    128static bool
    129nv44_mpeg_mthd(struct nvkm_device *device, u32 mthd, u32 data)
    130{
    131	switch (mthd) {
    132	case 0x190:
    133	case 0x1a0:
    134	case 0x1b0:
    135		return nv40_mpeg_mthd_dma(device, mthd, data);
    136	default:
    137		break;
    138	}
    139	return false;
    140}
    141
    142static void
    143nv44_mpeg_intr(struct nvkm_engine *engine)
    144{
    145	struct nv44_mpeg *mpeg = nv44_mpeg(engine);
    146	struct nvkm_subdev *subdev = &mpeg->engine.subdev;
    147	struct nvkm_device *device = subdev->device;
    148	struct nv44_mpeg_chan *temp, *chan = NULL;
    149	unsigned long flags;
    150	u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff;
    151	u32 stat = nvkm_rd32(device, 0x00b100);
    152	u32 type = nvkm_rd32(device, 0x00b230);
    153	u32 mthd = nvkm_rd32(device, 0x00b234);
    154	u32 data = nvkm_rd32(device, 0x00b238);
    155	u32 show = stat;
    156
    157	spin_lock_irqsave(&mpeg->engine.lock, flags);
    158	list_for_each_entry(temp, &mpeg->chan, head) {
    159		if (temp->inst >> 4 == inst) {
    160			chan = temp;
    161			list_del(&chan->head);
    162			list_add(&chan->head, &mpeg->chan);
    163			break;
    164		}
    165	}
    166
    167	if (stat & 0x01000000) {
    168		/* happens on initial binding of the object */
    169		if (type == 0x00000020 && mthd == 0x0000) {
    170			nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000);
    171			show &= ~0x01000000;
    172		}
    173
    174		if (type == 0x00000010) {
    175			if (nv44_mpeg_mthd(subdev->device, mthd, data))
    176				show &= ~0x01000000;
    177		}
    178	}
    179
    180	nvkm_wr32(device, 0x00b100, stat);
    181	nvkm_wr32(device, 0x00b230, 0x00000001);
    182
    183	if (show) {
    184		nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n",
    185			   chan ? chan->fifo->chid : -1, inst << 4,
    186			   chan ? chan->object.client->name : "unknown",
    187			   stat, type, mthd, data);
    188	}
    189
    190	spin_unlock_irqrestore(&mpeg->engine.lock, flags);
    191}
    192
    193static const struct nvkm_engine_func
    194nv44_mpeg = {
    195	.init = nv31_mpeg_init,
    196	.intr = nv44_mpeg_intr,
    197	.tile = nv31_mpeg_tile,
    198	.fifo.cclass = nv44_mpeg_chan_new,
    199	.sclass = {
    200		{ -1, -1, NV31_MPEG, &nv31_mpeg_object },
    201		{}
    202	}
    203};
    204
    205int
    206nv44_mpeg_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
    207	      struct nvkm_engine **pmpeg)
    208{
    209	struct nv44_mpeg *mpeg;
    210
    211	if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL)))
    212		return -ENOMEM;
    213	INIT_LIST_HEAD(&mpeg->chan);
    214	*pmpeg = &mpeg->engine;
    215
    216	return nvkm_engine_ctor(&nv44_mpeg, device, type, inst, true, &mpeg->engine);
    217}