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

user.c (11474B)


      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 nvkm_udevice(p) container_of((p), struct nvkm_udevice, object)
     25#include "priv.h"
     26#include "ctrl.h"
     27
     28#include <core/client.h>
     29#include <subdev/fb.h>
     30#include <subdev/instmem.h>
     31#include <subdev/timer.h>
     32
     33#include <nvif/class.h>
     34#include <nvif/cl0080.h>
     35#include <nvif/unpack.h>
     36
     37struct nvkm_udevice {
     38	struct nvkm_object object;
     39	struct nvkm_device *device;
     40};
     41
     42static int
     43nvkm_udevice_info_subdev(struct nvkm_device *device, u64 mthd, u64 *data)
     44{
     45	struct nvkm_subdev *subdev;
     46	enum nvkm_subdev_type type;
     47
     48	switch (mthd & NV_DEVICE_INFO_UNIT) {
     49	case NV_DEVICE_HOST(0): type = NVKM_ENGINE_FIFO; break;
     50	default:
     51		return -EINVAL;
     52	}
     53
     54	subdev = nvkm_device_subdev(device, type, 0);
     55	if (subdev)
     56		return nvkm_subdev_info(subdev, mthd, data);
     57	return -ENODEV;
     58}
     59
     60static void
     61nvkm_udevice_info_v1(struct nvkm_device *device,
     62		     struct nv_device_info_v1_data *args)
     63{
     64	if (args->mthd & NV_DEVICE_INFO_UNIT) {
     65		if (nvkm_udevice_info_subdev(device, args->mthd, &args->data))
     66			args->mthd = NV_DEVICE_INFO_INVALID;
     67		return;
     68	}
     69	args->mthd = NV_DEVICE_INFO_INVALID;
     70}
     71
     72static int
     73nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
     74{
     75	struct nvkm_object *object = &udev->object;
     76	struct nvkm_device *device = udev->device;
     77	struct nvkm_fb *fb = device->fb;
     78	struct nvkm_instmem *imem = device->imem;
     79	union {
     80		struct nv_device_info_v0 v0;
     81		struct nv_device_info_v1 v1;
     82	} *args = data;
     83	int ret = -ENOSYS, i;
     84
     85	nvif_ioctl(object, "device info size %d\n", size);
     86	if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
     87		nvif_ioctl(object, "device info vers %d count %d\n",
     88			   args->v1.version, args->v1.count);
     89		if (args->v1.count * sizeof(args->v1.data[0]) == size) {
     90			for (i = 0; i < args->v1.count; i++)
     91				nvkm_udevice_info_v1(device, &args->v1.data[i]);
     92			return 0;
     93		}
     94		return -EINVAL;
     95	} else
     96	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
     97		nvif_ioctl(object, "device info vers %d\n", args->v0.version);
     98	} else
     99		return ret;
    100
    101	switch (device->chipset) {
    102	case 0x01a:
    103	case 0x01f:
    104	case 0x04c:
    105	case 0x04e:
    106	case 0x063:
    107	case 0x067:
    108	case 0x068:
    109	case 0x0aa:
    110	case 0x0ac:
    111	case 0x0af:
    112		args->v0.platform = NV_DEVICE_INFO_V0_IGP;
    113		break;
    114	default:
    115		switch (device->type) {
    116		case NVKM_DEVICE_PCI:
    117			args->v0.platform = NV_DEVICE_INFO_V0_PCI;
    118			break;
    119		case NVKM_DEVICE_AGP:
    120			args->v0.platform = NV_DEVICE_INFO_V0_AGP;
    121			break;
    122		case NVKM_DEVICE_PCIE:
    123			args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
    124			break;
    125		case NVKM_DEVICE_TEGRA:
    126			args->v0.platform = NV_DEVICE_INFO_V0_SOC;
    127			break;
    128		default:
    129			WARN_ON(1);
    130			break;
    131		}
    132		break;
    133	}
    134
    135	switch (device->card_type) {
    136	case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
    137	case NV_10:
    138	case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
    139	case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
    140	case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
    141	case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
    142	case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
    143	case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
    144	case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
    145	case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
    146	case GP100: args->v0.family = NV_DEVICE_INFO_V0_PASCAL; break;
    147	case GV100: args->v0.family = NV_DEVICE_INFO_V0_VOLTA; break;
    148	case TU100: args->v0.family = NV_DEVICE_INFO_V0_TURING; break;
    149	case GA100: args->v0.family = NV_DEVICE_INFO_V0_AMPERE; break;
    150	default:
    151		args->v0.family = 0;
    152		break;
    153	}
    154
    155	args->v0.chipset  = device->chipset;
    156	args->v0.revision = device->chiprev;
    157	if (fb && fb->ram)
    158		args->v0.ram_size = args->v0.ram_user = fb->ram->size;
    159	else
    160		args->v0.ram_size = args->v0.ram_user = 0;
    161	if (imem && args->v0.ram_size > 0)
    162		args->v0.ram_user = args->v0.ram_user - imem->reserved;
    163
    164	snprintf(args->v0.chip, sizeof(args->v0.chip), "%s", device->chip->name);
    165	snprintf(args->v0.name, sizeof(args->v0.name), "%s", device->name);
    166	return 0;
    167}
    168
    169static int
    170nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size)
    171{
    172	struct nvkm_object *object = &udev->object;
    173	struct nvkm_device *device = udev->device;
    174	union {
    175		struct nv_device_time_v0 v0;
    176	} *args = data;
    177	int ret = -ENOSYS;
    178
    179	nvif_ioctl(object, "device time size %d\n", size);
    180	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    181		nvif_ioctl(object, "device time vers %d\n", args->v0.version);
    182		args->v0.time = nvkm_timer_read(device->timer);
    183	}
    184
    185	return ret;
    186}
    187
    188static int
    189nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
    190{
    191	struct nvkm_udevice *udev = nvkm_udevice(object);
    192	nvif_ioctl(object, "device mthd %08x\n", mthd);
    193	switch (mthd) {
    194	case NV_DEVICE_V0_INFO:
    195		return nvkm_udevice_info(udev, data, size);
    196	case NV_DEVICE_V0_TIME:
    197		return nvkm_udevice_time(udev, data, size);
    198	default:
    199		break;
    200	}
    201	return -EINVAL;
    202}
    203
    204static int
    205nvkm_udevice_rd08(struct nvkm_object *object, u64 addr, u8 *data)
    206{
    207	struct nvkm_udevice *udev = nvkm_udevice(object);
    208	*data = nvkm_rd08(udev->device, addr);
    209	return 0;
    210}
    211
    212static int
    213nvkm_udevice_rd16(struct nvkm_object *object, u64 addr, u16 *data)
    214{
    215	struct nvkm_udevice *udev = nvkm_udevice(object);
    216	*data = nvkm_rd16(udev->device, addr);
    217	return 0;
    218}
    219
    220static int
    221nvkm_udevice_rd32(struct nvkm_object *object, u64 addr, u32 *data)
    222{
    223	struct nvkm_udevice *udev = nvkm_udevice(object);
    224	*data = nvkm_rd32(udev->device, addr);
    225	return 0;
    226}
    227
    228static int
    229nvkm_udevice_wr08(struct nvkm_object *object, u64 addr, u8 data)
    230{
    231	struct nvkm_udevice *udev = nvkm_udevice(object);
    232	nvkm_wr08(udev->device, addr, data);
    233	return 0;
    234}
    235
    236static int
    237nvkm_udevice_wr16(struct nvkm_object *object, u64 addr, u16 data)
    238{
    239	struct nvkm_udevice *udev = nvkm_udevice(object);
    240	nvkm_wr16(udev->device, addr, data);
    241	return 0;
    242}
    243
    244static int
    245nvkm_udevice_wr32(struct nvkm_object *object, u64 addr, u32 data)
    246{
    247	struct nvkm_udevice *udev = nvkm_udevice(object);
    248	nvkm_wr32(udev->device, addr, data);
    249	return 0;
    250}
    251
    252static int
    253nvkm_udevice_map(struct nvkm_object *object, void *argv, u32 argc,
    254		 enum nvkm_object_map *type, u64 *addr, u64 *size)
    255{
    256	struct nvkm_udevice *udev = nvkm_udevice(object);
    257	struct nvkm_device *device = udev->device;
    258	*type = NVKM_OBJECT_MAP_IO;
    259	*addr = device->func->resource_addr(device, 0);
    260	*size = device->func->resource_size(device, 0);
    261	return 0;
    262}
    263
    264static int
    265nvkm_udevice_fini(struct nvkm_object *object, bool suspend)
    266{
    267	struct nvkm_udevice *udev = nvkm_udevice(object);
    268	struct nvkm_device *device = udev->device;
    269	int ret = 0;
    270
    271	mutex_lock(&device->mutex);
    272	if (!--device->refcount) {
    273		ret = nvkm_device_fini(device, suspend);
    274		if (ret && suspend) {
    275			device->refcount++;
    276			goto done;
    277		}
    278	}
    279
    280done:
    281	mutex_unlock(&device->mutex);
    282	return ret;
    283}
    284
    285static int
    286nvkm_udevice_init(struct nvkm_object *object)
    287{
    288	struct nvkm_udevice *udev = nvkm_udevice(object);
    289	struct nvkm_device *device = udev->device;
    290	int ret = 0;
    291
    292	mutex_lock(&device->mutex);
    293	if (!device->refcount++) {
    294		ret = nvkm_device_init(device);
    295		if (ret) {
    296			device->refcount--;
    297			goto done;
    298		}
    299	}
    300
    301done:
    302	mutex_unlock(&device->mutex);
    303	return ret;
    304}
    305
    306static int
    307nvkm_udevice_child_new(const struct nvkm_oclass *oclass,
    308		       void *data, u32 size, struct nvkm_object **pobject)
    309{
    310	struct nvkm_udevice *udev = nvkm_udevice(oclass->parent);
    311	const struct nvkm_device_oclass *sclass = oclass->priv;
    312	return sclass->ctor(udev->device, oclass, data, size, pobject);
    313}
    314
    315static int
    316nvkm_udevice_child_get(struct nvkm_object *object, int index,
    317		       struct nvkm_oclass *oclass)
    318{
    319	struct nvkm_udevice *udev = nvkm_udevice(object);
    320	struct nvkm_device *device = udev->device;
    321	struct nvkm_engine *engine;
    322	u64 mask = (1ULL << NVKM_ENGINE_DMAOBJ) |
    323		   (1ULL << NVKM_ENGINE_FIFO) |
    324		   (1ULL << NVKM_ENGINE_DISP) |
    325		   (1ULL << NVKM_ENGINE_PM);
    326	const struct nvkm_device_oclass *sclass = NULL;
    327	int i;
    328
    329	for (; i = __ffs64(mask), mask && !sclass; mask &= ~(1ULL << i)) {
    330		if (!(engine = nvkm_device_engine(device, i, 0)) ||
    331		    !(engine->func->base.sclass))
    332			continue;
    333		oclass->engine = engine;
    334
    335		index -= engine->func->base.sclass(oclass, index, &sclass);
    336	}
    337
    338	if (!sclass) {
    339		if (index-- == 0)
    340			sclass = &nvkm_control_oclass;
    341		else if (device->mmu && index-- == 0)
    342			sclass = &device->mmu->user;
    343		else if (device->fault && index-- == 0)
    344			sclass = &device->fault->user;
    345		else
    346			return -EINVAL;
    347
    348		oclass->base = sclass->base;
    349	}
    350
    351	oclass->ctor = nvkm_udevice_child_new;
    352	oclass->priv = sclass;
    353	return 0;
    354}
    355
    356static const struct nvkm_object_func
    357nvkm_udevice_super = {
    358	.init = nvkm_udevice_init,
    359	.fini = nvkm_udevice_fini,
    360	.mthd = nvkm_udevice_mthd,
    361	.map = nvkm_udevice_map,
    362	.rd08 = nvkm_udevice_rd08,
    363	.rd16 = nvkm_udevice_rd16,
    364	.rd32 = nvkm_udevice_rd32,
    365	.wr08 = nvkm_udevice_wr08,
    366	.wr16 = nvkm_udevice_wr16,
    367	.wr32 = nvkm_udevice_wr32,
    368	.sclass = nvkm_udevice_child_get,
    369};
    370
    371static const struct nvkm_object_func
    372nvkm_udevice = {
    373	.init = nvkm_udevice_init,
    374	.fini = nvkm_udevice_fini,
    375	.mthd = nvkm_udevice_mthd,
    376	.sclass = nvkm_udevice_child_get,
    377};
    378
    379static int
    380nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size,
    381		 struct nvkm_object **pobject)
    382{
    383	union {
    384		struct nv_device_v0 v0;
    385	} *args = data;
    386	struct nvkm_client *client = oclass->client;
    387	struct nvkm_object *parent = &client->object;
    388	const struct nvkm_object_func *func;
    389	struct nvkm_udevice *udev;
    390	int ret = -ENOSYS;
    391
    392	nvif_ioctl(parent, "create device size %d\n", size);
    393	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
    394		nvif_ioctl(parent, "create device v%d device %016llx\n",
    395			   args->v0.version, args->v0.device);
    396	} else
    397		return ret;
    398
    399	/* give priviledged clients register access */
    400	if (args->v0.priv)
    401		func = &nvkm_udevice_super;
    402	else
    403		func = &nvkm_udevice;
    404
    405	if (!(udev = kzalloc(sizeof(*udev), GFP_KERNEL)))
    406		return -ENOMEM;
    407	nvkm_object_ctor(func, oclass, &udev->object);
    408	*pobject = &udev->object;
    409
    410	/* find the device that matches what the client requested */
    411	if (args->v0.device != ~0)
    412		udev->device = nvkm_device_find(args->v0.device);
    413	else
    414		udev->device = nvkm_device_find(client->device);
    415	if (!udev->device)
    416		return -ENODEV;
    417
    418	return 0;
    419}
    420
    421const struct nvkm_sclass
    422nvkm_udevice_sclass = {
    423	.oclass = NV_DEVICE,
    424	.minver = 0,
    425	.maxver = 0,
    426	.ctor = nvkm_udevice_new,
    427};