kfd_chardev.c 15.0 KB
Newer Older
O
Oded Gabbay 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/*
 * Copyright 2014 Advanced Micro Devices, 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.
 */

#include <linux/device.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/compat.h>
#include <uapi/linux/kfd_ioctl.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <uapi/asm-generic/mman-common.h>
#include <asm/processor.h>
#include "kfd_priv.h"
37
#include "kfd_device_queue_manager.h"
O
Oded Gabbay 已提交
38 39 40

static long kfd_ioctl(struct file *, unsigned int, unsigned long);
static int kfd_open(struct inode *, struct file *);
41
static int kfd_mmap(struct file *, struct vm_area_struct *);
O
Oded Gabbay 已提交
42 43 44 45 46 47 48 49

static const char kfd_dev_name[] = "kfd";

static const struct file_operations kfd_fops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = kfd_ioctl,
	.compat_ioctl = kfd_ioctl,
	.open = kfd_open,
50
	.mmap = kfd_mmap,
O
Oded Gabbay 已提交
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
};

static int kfd_char_dev_major = -1;
static struct class *kfd_class;
struct device *kfd_device;

int kfd_chardev_init(void)
{
	int err = 0;

	kfd_char_dev_major = register_chrdev(0, kfd_dev_name, &kfd_fops);
	err = kfd_char_dev_major;
	if (err < 0)
		goto err_register_chrdev;

	kfd_class = class_create(THIS_MODULE, kfd_dev_name);
	err = PTR_ERR(kfd_class);
	if (IS_ERR(kfd_class))
		goto err_class_create;

	kfd_device = device_create(kfd_class, NULL,
					MKDEV(kfd_char_dev_major, 0),
					NULL, kfd_dev_name);
	err = PTR_ERR(kfd_device);
	if (IS_ERR(kfd_device))
		goto err_device_create;

	return 0;

err_device_create:
	class_destroy(kfd_class);
err_class_create:
	unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
err_register_chrdev:
	return err;
}

void kfd_chardev_exit(void)
{
	device_destroy(kfd_class, MKDEV(kfd_char_dev_major, 0));
	class_destroy(kfd_class);
	unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
}

struct device *kfd_chardev(void)
{
	return kfd_device;
}


static int kfd_open(struct inode *inode, struct file *filep)
{
103
	struct kfd_process *process;
104
	bool is_32bit_user_mode;
105

O
Oded Gabbay 已提交
106 107 108
	if (iminor(inode) != 0)
		return -ENODEV;

109 110 111 112 113 114 115 116 117 118
	is_32bit_user_mode = is_compat_task();

	if (is_32bit_user_mode == true) {
		dev_warn(kfd_device,
			"Process %d (32-bit) failed to open /dev/kfd\n"
			"32-bit processes are not supported by amdkfd\n",
			current->pid);
		return -EPERM;
	}

119 120 121 122 123 124 125
	process = kfd_create_process(current);
	if (IS_ERR(process))
		return PTR_ERR(process);

	dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n",
		process->pasid, process->is_32bit_user_mode);

O
Oded Gabbay 已提交
126 127 128
	return 0;
}

129 130
static int kfd_ioctl_get_version(struct file *filep, struct kfd_process *p,
					void *data)
O
Oded Gabbay 已提交
131
{
132
	struct kfd_ioctl_get_version_args *args = data;
133 134
	int err = 0;

135 136
	args->major_version = KFD_IOCTL_MAJOR_VERSION;
	args->minor_version = KFD_IOCTL_MINOR_VERSION;
137 138

	return err;
O
Oded Gabbay 已提交
139 140
}

141 142 143 144 145 146 147 148 149 150 151 152 153 154
static int set_queue_properties_from_user(struct queue_properties *q_properties,
				struct kfd_ioctl_create_queue_args *args)
{
	if (args->queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
		pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n");
		return -EINVAL;
	}

	if (args->queue_priority > KFD_MAX_QUEUE_PRIORITY) {
		pr_err("kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY\n");
		return -EINVAL;
	}

	if ((args->ring_base_address) &&
155 156 157
		(!access_ok(VERIFY_WRITE,
			(const void __user *) args->ring_base_address,
			sizeof(uint64_t)))) {
158 159 160 161 162 163 164 165 166
		pr_err("kfd: can't access ring base address\n");
		return -EFAULT;
	}

	if (!is_power_of_2(args->ring_size) && (args->ring_size != 0)) {
		pr_err("kfd: ring size must be a power of 2 or 0\n");
		return -EINVAL;
	}

167 168 169
	if (!access_ok(VERIFY_WRITE,
			(const void __user *) args->read_pointer_address,
			sizeof(uint32_t))) {
170 171 172 173
		pr_err("kfd: can't access read pointer\n");
		return -EFAULT;
	}

174 175 176
	if (!access_ok(VERIFY_WRITE,
			(const void __user *) args->write_pointer_address,
			sizeof(uint32_t))) {
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
		pr_err("kfd: can't access write pointer\n");
		return -EFAULT;
	}

	q_properties->is_interop = false;
	q_properties->queue_percent = args->queue_percentage;
	q_properties->priority = args->queue_priority;
	q_properties->queue_address = args->ring_base_address;
	q_properties->queue_size = args->ring_size;
	q_properties->read_ptr = (uint32_t *) args->read_pointer_address;
	q_properties->write_ptr = (uint32_t *) args->write_pointer_address;
	if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE ||
		args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
		q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
	else
		return -ENOTSUPP;

	if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
		q_properties->format = KFD_QUEUE_FORMAT_AQL;
	else
		q_properties->format = KFD_QUEUE_FORMAT_PM4;

	pr_debug("Queue Percentage (%d, %d)\n",
			q_properties->queue_percent, args->queue_percentage);

	pr_debug("Queue Priority (%d, %d)\n",
			q_properties->priority, args->queue_priority);

	pr_debug("Queue Address (0x%llX, 0x%llX)\n",
			q_properties->queue_address, args->ring_base_address);

	pr_debug("Queue Size (0x%llX, %u)\n",
			q_properties->queue_size, args->ring_size);

	pr_debug("Queue r/w Pointers (0x%llX, 0x%llX)\n",
			(uint64_t) q_properties->read_ptr,
			(uint64_t) q_properties->write_ptr);

	pr_debug("Queue Format (%d)\n", q_properties->format);

	return 0;
}

220 221
static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
					void *data)
O
Oded Gabbay 已提交
222
{
223
	struct kfd_ioctl_create_queue_args *args = data;
224 225 226 227 228 229 230 231 232 233
	struct kfd_dev *dev;
	int err = 0;
	unsigned int queue_id;
	struct kfd_process_device *pdd;
	struct queue_properties q_properties;

	memset(&q_properties, 0, sizeof(struct queue_properties));

	pr_debug("kfd: creating queue ioctl\n");

234
	err = set_queue_properties_from_user(&q_properties, args);
235 236 237
	if (err)
		return err;

238
	dev = kfd_device_by_id(args->gpu_id);
239 240 241 242 243 244
	if (dev == NULL)
		return -EINVAL;

	mutex_lock(&p->mutex);

	pdd = kfd_bind_process_to_device(dev, p);
245
	if (IS_ERR(pdd)) {
246
		err = -ESRCH;
247 248 249 250 251 252 253 254 255 256 257 258
		goto err_bind_process;
	}

	pr_debug("kfd: creating queue for PASID %d on GPU 0x%x\n",
			p->pasid,
			dev->id);

	err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, 0,
				KFD_QUEUE_TYPE_COMPUTE, &queue_id);
	if (err != 0)
		goto err_create_queue;

259
	args->queue_id = queue_id;
260 261

	/* Return gpu_id as doorbell offset for mmap usage */
262
	args->doorbell_offset = args->gpu_id << PAGE_SHIFT;
263 264 265

	mutex_unlock(&p->mutex);

266
	pr_debug("kfd: queue id %d was created successfully\n", args->queue_id);
267 268

	pr_debug("ring buffer address == 0x%016llX\n",
269
			args->ring_base_address);
270 271

	pr_debug("read ptr address    == 0x%016llX\n",
272
			args->read_pointer_address);
273 274

	pr_debug("write ptr address   == 0x%016llX\n",
275
			args->write_pointer_address);
276 277 278 279 280 281 282

	return 0;

err_create_queue:
err_bind_process:
	mutex_unlock(&p->mutex);
	return err;
O
Oded Gabbay 已提交
283 284 285
}

static int kfd_ioctl_destroy_queue(struct file *filp, struct kfd_process *p,
286
					void *data)
O
Oded Gabbay 已提交
287
{
288
	int retval;
289
	struct kfd_ioctl_destroy_queue_args *args = data;
290 291

	pr_debug("kfd: destroying queue id %d for PASID %d\n",
292
				args->queue_id,
293 294 295 296
				p->pasid);

	mutex_lock(&p->mutex);

297
	retval = pqm_destroy_queue(&p->pqm, args->queue_id);
298 299 300

	mutex_unlock(&p->mutex);
	return retval;
O
Oded Gabbay 已提交
301 302 303
}

static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p,
304
					void *data)
O
Oded Gabbay 已提交
305
{
306
	int retval;
307
	struct kfd_ioctl_update_queue_args *args = data;
308 309
	struct queue_properties properties;

310
	if (args->queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
311 312 313 314
		pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n");
		return -EINVAL;
	}

315
	if (args->queue_priority > KFD_MAX_QUEUE_PRIORITY) {
316 317 318 319
		pr_err("kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY\n");
		return -EINVAL;
	}

320
	if ((args->ring_base_address) &&
321
		(!access_ok(VERIFY_WRITE,
322
			(const void __user *) args->ring_base_address,
323
			sizeof(uint64_t)))) {
324 325 326 327
		pr_err("kfd: can't access ring base address\n");
		return -EFAULT;
	}

328
	if (!is_power_of_2(args->ring_size) && (args->ring_size != 0)) {
329 330 331 332
		pr_err("kfd: ring size must be a power of 2 or 0\n");
		return -EINVAL;
	}

333 334 335 336
	properties.queue_address = args->ring_base_address;
	properties.queue_size = args->ring_size;
	properties.queue_percent = args->queue_percentage;
	properties.priority = args->queue_priority;
337 338

	pr_debug("kfd: updating queue id %d for PASID %d\n",
339
			args->queue_id, p->pasid);
340 341 342

	mutex_lock(&p->mutex);

343
	retval = pqm_update_queue(&p->pqm, args->queue_id, &properties);
344 345 346 347

	mutex_unlock(&p->mutex);

	return retval;
O
Oded Gabbay 已提交
348 349
}

350 351
static int kfd_ioctl_set_memory_policy(struct file *filep,
					struct kfd_process *p, void *data)
O
Oded Gabbay 已提交
352
{
353
	struct kfd_ioctl_set_memory_policy_args *args = data;
354 355 356 357 358
	struct kfd_dev *dev;
	int err = 0;
	struct kfd_process_device *pdd;
	enum cache_policy default_policy, alternate_policy;

359 360
	if (args->default_policy != KFD_IOC_CACHE_POLICY_COHERENT
	    && args->default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
361 362 363
		return -EINVAL;
	}

364 365
	if (args->alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
	    && args->alternate_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
366 367 368
		return -EINVAL;
	}

369
	dev = kfd_device_by_id(args->gpu_id);
370 371 372 373 374 375
	if (dev == NULL)
		return -EINVAL;

	mutex_lock(&p->mutex);

	pdd = kfd_bind_process_to_device(dev, p);
376
	if (IS_ERR(pdd)) {
377
		err = -ESRCH;
378 379 380
		goto out;
	}

381
	default_policy = (args->default_policy == KFD_IOC_CACHE_POLICY_COHERENT)
382 383 384
			 ? cache_policy_coherent : cache_policy_noncoherent;

	alternate_policy =
385
		(args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
386 387 388 389 390 391
		   ? cache_policy_coherent : cache_policy_noncoherent;

	if (!dev->dqm->set_cache_memory_policy(dev->dqm,
				&pdd->qpd,
				default_policy,
				alternate_policy,
392 393
				(void __user *)args->alternate_aperture_base,
				args->alternate_aperture_size))
394 395 396 397 398 399
		err = -EINVAL;

out:
	mutex_unlock(&p->mutex);

	return err;
O
Oded Gabbay 已提交
400 401
}

402 403
static int kfd_ioctl_get_clock_counters(struct file *filep,
				struct kfd_process *p, void *data)
O
Oded Gabbay 已提交
404
{
405
	struct kfd_ioctl_get_clock_counters_args *args = data;
406 407 408
	struct kfd_dev *dev;
	struct timespec time;

409
	dev = kfd_device_by_id(args->gpu_id);
410 411 412 413
	if (dev == NULL)
		return -EINVAL;

	/* Reading GPU clock counter from KGD */
414
	args->gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
415 416 417

	/* No access to rdtsc. Using raw monotonic time */
	getrawmonotonic(&time);
418
	args->cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
419 420

	get_monotonic_boottime(&time);
421
	args->system_clock_counter = (uint64_t)timespec_to_ns(&time);
422 423

	/* Since the counter is in nano-seconds we use 1GHz frequency */
424
	args->system_clock_freq = 1000000000;
425 426

	return 0;
O
Oded Gabbay 已提交
427 428 429 430
}


static int kfd_ioctl_get_process_apertures(struct file *filp,
431
				struct kfd_process *p, void *data)
O
Oded Gabbay 已提交
432
{
433
	struct kfd_ioctl_get_process_apertures_args *args = data;
434 435 436 437 438
	struct kfd_process_device_apertures *pAperture;
	struct kfd_process_device *pdd;

	dev_dbg(kfd_device, "get apertures for PASID %d", p->pasid);

439
	args->num_of_nodes = 0;
440 441 442 443 444 445 446 447

	mutex_lock(&p->mutex);

	/*if the process-device list isn't empty*/
	if (kfd_has_process_device_data(p)) {
		/* Run over all pdd of the process */
		pdd = kfd_get_first_process_device_data(p);
		do {
448 449
			pAperture =
				&args->process_apertures[args->num_of_nodes];
450 451 452 453 454 455 456 457 458
			pAperture->gpu_id = pdd->dev->id;
			pAperture->lds_base = pdd->lds_base;
			pAperture->lds_limit = pdd->lds_limit;
			pAperture->gpuvm_base = pdd->gpuvm_base;
			pAperture->gpuvm_limit = pdd->gpuvm_limit;
			pAperture->scratch_base = pdd->scratch_base;
			pAperture->scratch_limit = pdd->scratch_limit;

			dev_dbg(kfd_device,
459
				"node id %u\n", args->num_of_nodes);
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
			dev_dbg(kfd_device,
				"gpu id %u\n", pdd->dev->id);
			dev_dbg(kfd_device,
				"lds_base %llX\n", pdd->lds_base);
			dev_dbg(kfd_device,
				"lds_limit %llX\n", pdd->lds_limit);
			dev_dbg(kfd_device,
				"gpuvm_base %llX\n", pdd->gpuvm_base);
			dev_dbg(kfd_device,
				"gpuvm_limit %llX\n", pdd->gpuvm_limit);
			dev_dbg(kfd_device,
				"scratch_base %llX\n", pdd->scratch_base);
			dev_dbg(kfd_device,
				"scratch_limit %llX\n", pdd->scratch_limit);

475
			args->num_of_nodes++;
476
		} while ((pdd = kfd_get_next_process_device_data(p, pdd)) != NULL &&
477
				(args->num_of_nodes < NUM_OF_SUPPORTED_GPUS));
478 479 480 481 482
	}

	mutex_unlock(&p->mutex);

	return 0;
O
Oded Gabbay 已提交
483 484 485 486 487
}

static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
	struct kfd_process *process;
488 489 490 491
	char stack_kdata[128];
	char *kdata = NULL;
	unsigned int usize, asize;
	int retcode = -EINVAL;
O
Oded Gabbay 已提交
492 493 494 495 496

	dev_dbg(kfd_device,
		"ioctl cmd 0x%x (#%d), arg 0x%lx\n",
		cmd, _IOC_NR(cmd), arg);

497 498 499
	process = kfd_get_process(current);
	if (IS_ERR(process))
		return PTR_ERR(process);
O
Oded Gabbay 已提交
500

501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
	if (cmd & (IOC_IN | IOC_OUT)) {
		if (asize <= sizeof(stack_kdata)) {
			kdata = stack_kdata;
		} else {
			kdata = kmalloc(asize, GFP_KERNEL);
			if (!kdata) {
				retcode = -ENOMEM;
				goto err_i1;
			}
		}
		if (asize > usize)
			memset(kdata + usize, 0, asize - usize);
	}

	if (cmd & IOC_IN) {
		if (copy_from_user(kdata, (void __user *)arg, usize) != 0) {
			retcode = -EFAULT;
			goto err_i1;
		}
	} else if (cmd & IOC_OUT) {
		memset(kdata, 0, usize);
	}


O
Oded Gabbay 已提交
525 526
	switch (cmd) {
	case KFD_IOC_GET_VERSION:
527
		retcode = kfd_ioctl_get_version(filep, process, kdata);
O
Oded Gabbay 已提交
528 529
		break;
	case KFD_IOC_CREATE_QUEUE:
530 531
		retcode = kfd_ioctl_create_queue(filep, process,
						kdata);
O
Oded Gabbay 已提交
532 533 534
		break;

	case KFD_IOC_DESTROY_QUEUE:
535 536
		retcode = kfd_ioctl_destroy_queue(filep, process,
						kdata);
O
Oded Gabbay 已提交
537 538 539
		break;

	case KFD_IOC_SET_MEMORY_POLICY:
540 541
		retcode = kfd_ioctl_set_memory_policy(filep, process,
						kdata);
O
Oded Gabbay 已提交
542 543 544
		break;

	case KFD_IOC_GET_CLOCK_COUNTERS:
545 546
		retcode = kfd_ioctl_get_clock_counters(filep, process,
						kdata);
O
Oded Gabbay 已提交
547 548 549
		break;

	case KFD_IOC_GET_PROCESS_APERTURES:
550 551
		retcode = kfd_ioctl_get_process_apertures(filep, process,
						kdata);
O
Oded Gabbay 已提交
552 553 554
		break;

	case KFD_IOC_UPDATE_QUEUE:
555 556
		retcode = kfd_ioctl_update_queue(filep, process,
						kdata);
O
Oded Gabbay 已提交
557 558 559
		break;

	default:
560
		dev_dbg(kfd_device,
O
Oded Gabbay 已提交
561 562
			"unknown ioctl cmd 0x%x, arg 0x%lx)\n",
			cmd, arg);
563
		retcode = -EINVAL;
O
Oded Gabbay 已提交
564 565 566
		break;
	}

567 568 569
	if (cmd & IOC_OUT)
		if (copy_to_user((void __user *)arg, kdata, usize) != 0)
			retcode = -EFAULT;
O
Oded Gabbay 已提交
570

571 572 573 574 575 576 577 578
err_i1:
	if (kdata != stack_kdata)
		kfree(kdata);

	if (retcode)
		dev_dbg(kfd_device, "ret = %d\n", retcode);

	return retcode;
O
Oded Gabbay 已提交
579
}
580 581 582 583 584 585 586 587 588 589 590

static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
{
	struct kfd_process *process;

	process = kfd_get_process(current);
	if (IS_ERR(process))
		return PTR_ERR(process);

	return kfd_doorbell_mmap(process, vma);
}