user.c 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright 2012 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: Ben Skeggs
 */
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 <core/parent.h>
30 31
#include <subdev/fb.h>
#include <subdev/instmem.h>
B
Ben Skeggs 已提交
32
#include <subdev/timer.h>
33 34 35 36
#include <engine/disp.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/pm.h>
37 38 39 40 41

#include <nvif/class.h>
#include <nvif/unpack.h>

struct nvkm_udevice {
42
	struct nvkm_object object;
43 44 45 46
	struct nvkm_device *device;
};

static int
47
nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
48
{
49
	struct nvkm_object *object = &udev->object;
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
	struct nvkm_device *device = udev->device;
	struct nvkm_fb *fb = device->fb;
	struct nvkm_instmem *imem = device->imem;
	union {
		struct nv_device_info_v0 v0;
	} *args = data;
	int ret;

	nvif_ioctl(object, "device info size %d\n", size);
	if (nvif_unpack(args->v0, 0, 0, false)) {
		nvif_ioctl(object, "device info vers %d\n", args->v0.version);
	} else
		return ret;

	switch (device->chipset) {
	case 0x01a:
	case 0x01f:
	case 0x04c:
	case 0x04e:
	case 0x063:
	case 0x067:
	case 0x068:
	case 0x0aa:
	case 0x0ac:
	case 0x0af:
		args->v0.platform = NV_DEVICE_INFO_V0_IGP;
		break;
	default:
		if (device->pdev) {
			if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
				args->v0.platform = NV_DEVICE_INFO_V0_AGP;
			else
			if (pci_is_pcie(device->pdev))
				args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
			else
				args->v0.platform = NV_DEVICE_INFO_V0_PCI;
		} else {
			args->v0.platform = NV_DEVICE_INFO_V0_SOC;
		}
		break;
	}

	switch (device->card_type) {
	case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
	case NV_10:
	case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
	case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
	case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
	case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
	case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
	case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
	case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
	case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
	default:
		args->v0.family = 0;
		break;
	}

	args->v0.chipset  = device->chipset;
	args->v0.revision = device->chiprev;
	if (fb && fb->ram)
		args->v0.ram_size = args->v0.ram_user = fb->ram->size;
	else
		args->v0.ram_size = args->v0.ram_user = 0;
	if (imem && args->v0.ram_size > 0)
		args->v0.ram_user = args->v0.ram_user - imem->reserved;

117 118
	strncpy(args->v0.chip, device->chip->name, sizeof(args->v0.chip));
	strncpy(args->v0.name, device->name, sizeof(args->v0.name));
119 120 121
	return 0;
}

B
Ben Skeggs 已提交
122
static int
123
nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size)
B
Ben Skeggs 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
{
	struct nvkm_device *device = udev->device;
	struct nvkm_timer *tmr = device->timer;
	union {
		struct nv_device_time_v0 v0;
	} *args = data;
	int ret;

	if (nvif_unpack(args->v0, 0, 0, false)) {
		args->v0.time = tmr->read(tmr);
	}

	return ret;
}

139 140 141
static int
nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
{
142
	struct nvkm_udevice *udev = nvkm_udevice(object);
143 144
	switch (mthd) {
	case NV_DEVICE_V0_INFO:
145
		return nvkm_udevice_info(udev, data, size);
B
Ben Skeggs 已提交
146
	case NV_DEVICE_V0_TIME:
147
		return nvkm_udevice_time(udev, data, size);
148 149 150 151 152 153
	default:
		break;
	}
	return -EINVAL;
}

154 155
static int
nvkm_udevice_rd08(struct nvkm_object *object, u64 addr, u8 *data)
156
{
157 158 159
	struct nvkm_udevice *udev = nvkm_udevice(object);
	*data = nvkm_rd08(udev->device, addr);
	return 0;
160 161
}

162 163
static int
nvkm_udevice_rd16(struct nvkm_object *object, u64 addr, u16 *data)
164
{
165 166 167
	struct nvkm_udevice *udev = nvkm_udevice(object);
	*data = nvkm_rd16(udev->device, addr);
	return 0;
168 169
}

170 171
static int
nvkm_udevice_rd32(struct nvkm_object *object, u64 addr, u32 *data)
172
{
173 174 175
	struct nvkm_udevice *udev = nvkm_udevice(object);
	*data = nvkm_rd32(udev->device, addr);
	return 0;
176 177
}

178
static int
179 180
nvkm_udevice_wr08(struct nvkm_object *object, u64 addr, u8 data)
{
181
	struct nvkm_udevice *udev = nvkm_udevice(object);
182
	nvkm_wr08(udev->device, addr, data);
183
	return 0;
184 185
}

186
static int
187 188
nvkm_udevice_wr16(struct nvkm_object *object, u64 addr, u16 data)
{
189
	struct nvkm_udevice *udev = nvkm_udevice(object);
190
	nvkm_wr16(udev->device, addr, data);
191
	return 0;
192 193
}

194
static int
195 196
nvkm_udevice_wr32(struct nvkm_object *object, u64 addr, u32 data)
{
197
	struct nvkm_udevice *udev = nvkm_udevice(object);
198
	nvkm_wr32(udev->device, addr, data);
199
	return 0;
200 201 202 203 204
}

static int
nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size)
{
205
	struct nvkm_udevice *udev = nvkm_udevice(object);
206 207 208 209 210 211
	struct nvkm_device *device = udev->device;
	*addr = nv_device_resource_start(device, 0);
	*size = nv_device_resource_len(device, 0);
	return 0;
}

212 213 214
static int
nvkm_udevice_fini(struct nvkm_object *object, bool suspend)
{
215
	struct nvkm_udevice *udev = nvkm_udevice(object);
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
	struct nvkm_device *device = udev->device;
	int ret = 0;

	mutex_lock(&device->mutex);
	if (!--device->refcount) {
		ret = nvkm_device_fini(device, suspend);
		if (ret && suspend) {
			device->refcount++;
			goto done;
		}
	}

done:
	mutex_unlock(&device->mutex);
	return ret;
}

static int
nvkm_udevice_init(struct nvkm_object *object)
{
236
	struct nvkm_udevice *udev = nvkm_udevice(object);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
	struct nvkm_device *device = udev->device;
	int ret = 0;

	mutex_lock(&device->mutex);
	if (!device->refcount++) {
		ret = nvkm_device_init(device);
		if (ret) {
			device->refcount--;
			goto done;
		}
	}

done:
	mutex_unlock(&device->mutex);
	return ret;
}

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
static int
nvkm_udevice_child_old(const struct nvkm_oclass *oclass,
		       void *data, u32 size, struct nvkm_object **pobject)
{
	struct nvkm_object *parent = oclass->parent;
	struct nvkm_engine *engine = oclass->engine;
	struct nvkm_oclass *eclass = (void *)oclass->priv;
	struct nvkm_object *engctx = NULL;
	int ret;

	if (engine->cclass) {
		ret = nvkm_object_old(parent, &engine->subdev.object,
				      engine->cclass, NULL, 0, &engctx);
		if (ret)
			return ret;
	} else {
		nvkm_object_ref(parent, &engctx);
271
	}
272 273 274 275 276 277

	ret = nvkm_object_old(engctx, &engine->subdev.object, eclass,
			      data, size, pobject);
	nvkm_object_ref(NULL, &engctx);
	return ret;
}
278 279

static int
280 281 282 283
nvkm_udevice_child_new(const struct nvkm_oclass *oclass,
		       void *data, u32 size, struct nvkm_object **pobject)
{
	struct nvkm_udevice *udev = nvkm_udevice(oclass->parent);
284 285
	const struct nvkm_device_oclass *sclass = oclass->priv;
	return sclass->ctor(udev->device, oclass, data, size, pobject);
286 287 288 289 290 291 292 293 294 295 296 297 298
}

static int
nvkm_udevice_child_get(struct nvkm_object *object, int index,
		       struct nvkm_oclass *oclass)
{
	struct nvkm_udevice *udev = nvkm_udevice(object);
	struct nvkm_device *device = udev->device;
	struct nvkm_engine *engine;
	u64 mask = (1ULL << NVDEV_ENGINE_DMAOBJ) |
		   (1ULL << NVDEV_ENGINE_FIFO) |
		   (1ULL << NVDEV_ENGINE_DISP) |
		   (1ULL << NVDEV_ENGINE_PM);
299
	const struct nvkm_device_oclass *sclass;
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
	int i;

	for (; i = __ffs64(mask), mask; mask &= ~(1ULL << i)) {
		if ((engine = nvkm_device_engine(device, i))) {
			struct nvkm_oclass *sclass = engine->sclass;
			int c = 0;
			while (sclass && sclass->ofuncs) {
				if (c++ == index) {
					oclass->base.oclass = sclass->handle;
					oclass->base.minver = -2;
					oclass->base.maxver = -2;
					oclass->ctor = nvkm_udevice_child_old;
					oclass->priv = sclass;
					oclass->engine = engine;
					return 0;
				}
				sclass++;
			}
			index -= c;
		}
	}

322 323 324 325
	switch (index) {
	case 0: sclass = &nvkm_control_oclass; break;
	default:
		return -EINVAL;
326 327
	}

328 329 330 331
	oclass->ctor = nvkm_udevice_child_new;
	oclass->base = sclass->base;
	oclass->priv = sclass;
	return 0;
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
}

static const struct nvkm_object_func
nvkm_udevice_super = {
	.init = nvkm_udevice_init,
	.fini = nvkm_udevice_fini,
	.mthd = nvkm_udevice_mthd,
	.map = nvkm_udevice_map,
	.rd08 = nvkm_udevice_rd08,
	.rd16 = nvkm_udevice_rd16,
	.rd32 = nvkm_udevice_rd32,
	.wr08 = nvkm_udevice_wr08,
	.wr16 = nvkm_udevice_wr16,
	.wr32 = nvkm_udevice_wr32,
	.sclass = nvkm_udevice_child_get,
};

static const struct nvkm_object_func
nvkm_udevice = {
	.init = nvkm_udevice_init,
	.fini = nvkm_udevice_fini,
	.mthd = nvkm_udevice_mthd,
	.sclass = nvkm_udevice_child_get,
};

int
nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size,
359 360 361 362 363
		 struct nvkm_object **pobject)
{
	union {
		struct nv_device_v0 v0;
	} *args = data;
364 365 366
	struct nvkm_client *client = oclass->client;
	struct nvkm_object *parent = &client->object;
	const struct nvkm_object_func *func;
367 368 369 370 371 372 373 374 375 376 377 378
	struct nvkm_udevice *udev;
	int ret;

	nvif_ioctl(parent, "create device size %d\n", size);
	if (nvif_unpack(args->v0, 0, 0, false)) {
		nvif_ioctl(parent, "create device v%d device %016llx\n",
			   args->v0.version, args->v0.device);
	} else
		return ret;

	/* give priviledged clients register access */
	if (client->super)
379 380 381
		func = &nvkm_udevice_super;
	else
		func = &nvkm_udevice;
382

383 384 385 386 387 388
	if (!(udev = kzalloc(sizeof(*udev), GFP_KERNEL)))
		return -ENOMEM;
	nvkm_object_ctor(func, oclass, &udev->object);
	*pobject = &udev->object;

	/* find the device that matches what the client requested */
389
	if (args->v0.device != ~0)
390
		udev->device = nvkm_device_find(args->v0.device);
391
	else
392 393
		udev->device = nvkm_device_find(client->device);
	if (!udev->device)
394
		return -ENODEV;
395 396 397 398

	return 0;
}

399 400 401 402 403 404
const struct nvkm_sclass
nvkm_udevice_sclass = {
	.oclass = NV_DEVICE,
	.minver = 0,
	.maxver = 0,
	.ctor = nvkm_udevice_new,
405
};