xref: /openbmc/linux/drivers/gpu/host1x/job.c (revision 47f89c10ddc439638bc0ea51a7f9872e1b7734ce)
1 /*
2  * Tegra host1x Job
3  *
4  * Copyright (c) 2010-2015, NVIDIA Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <linux/dma-mapping.h>
20 #include <linux/err.h>
21 #include <linux/host1x.h>
22 #include <linux/kref.h>
23 #include <linux/module.h>
24 #include <linux/scatterlist.h>
25 #include <linux/slab.h>
26 #include <linux/vmalloc.h>
27 #include <trace/events/host1x.h>
28 
29 #include "channel.h"
30 #include "dev.h"
31 #include "job.h"
32 #include "syncpt.h"
33 
34 struct host1x_job *host1x_job_alloc(struct host1x_channel *ch,
35 				    u32 num_cmdbufs, u32 num_relocs,
36 				    u32 num_waitchks)
37 {
38 	struct host1x_job *job = NULL;
39 	unsigned int num_unpins = num_cmdbufs + num_relocs;
40 	u64 total;
41 	void *mem;
42 
43 	/* Check that we're not going to overflow */
44 	total = sizeof(struct host1x_job) +
45 		(u64)num_relocs * sizeof(struct host1x_reloc) +
46 		(u64)num_unpins * sizeof(struct host1x_job_unpin_data) +
47 		(u64)num_waitchks * sizeof(struct host1x_waitchk) +
48 		(u64)num_cmdbufs * sizeof(struct host1x_job_gather) +
49 		(u64)num_unpins * sizeof(dma_addr_t) +
50 		(u64)num_unpins * sizeof(u32 *);
51 	if (total > ULONG_MAX)
52 		return NULL;
53 
54 	mem = job = kzalloc(total, GFP_KERNEL);
55 	if (!job)
56 		return NULL;
57 
58 	kref_init(&job->ref);
59 	job->channel = ch;
60 
61 	/* Redistribute memory to the structs  */
62 	mem += sizeof(struct host1x_job);
63 	job->relocarray = num_relocs ? mem : NULL;
64 	mem += num_relocs * sizeof(struct host1x_reloc);
65 	job->unpins = num_unpins ? mem : NULL;
66 	mem += num_unpins * sizeof(struct host1x_job_unpin_data);
67 	job->waitchk = num_waitchks ? mem : NULL;
68 	mem += num_waitchks * sizeof(struct host1x_waitchk);
69 	job->gathers = num_cmdbufs ? mem : NULL;
70 	mem += num_cmdbufs * sizeof(struct host1x_job_gather);
71 	job->addr_phys = num_unpins ? mem : NULL;
72 
73 	job->reloc_addr_phys = job->addr_phys;
74 	job->gather_addr_phys = &job->addr_phys[num_relocs];
75 
76 	return job;
77 }
78 EXPORT_SYMBOL(host1x_job_alloc);
79 
80 struct host1x_job *host1x_job_get(struct host1x_job *job)
81 {
82 	kref_get(&job->ref);
83 	return job;
84 }
85 EXPORT_SYMBOL(host1x_job_get);
86 
87 static void job_free(struct kref *ref)
88 {
89 	struct host1x_job *job = container_of(ref, struct host1x_job, ref);
90 
91 	kfree(job);
92 }
93 
94 void host1x_job_put(struct host1x_job *job)
95 {
96 	kref_put(&job->ref, job_free);
97 }
98 EXPORT_SYMBOL(host1x_job_put);
99 
100 void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo,
101 			   u32 words, u32 offset)
102 {
103 	struct host1x_job_gather *cur_gather = &job->gathers[job->num_gathers];
104 
105 	cur_gather->words = words;
106 	cur_gather->bo = bo;
107 	cur_gather->offset = offset;
108 	job->num_gathers++;
109 }
110 EXPORT_SYMBOL(host1x_job_add_gather);
111 
112 /*
113  * NULL an already satisfied WAIT_SYNCPT host method, by patching its
114  * args in the command stream. The method data is changed to reference
115  * a reserved (never given out or incr) HOST1X_SYNCPT_RESERVED syncpt
116  * with a matching threshold value of 0, so is guaranteed to be popped
117  * by the host HW.
118  */
119 static void host1x_syncpt_patch_offset(struct host1x_syncpt *sp,
120 				       struct host1x_bo *h, u32 offset)
121 {
122 	void *patch_addr = NULL;
123 
124 	/* patch the wait */
125 	patch_addr = host1x_bo_kmap(h, offset >> PAGE_SHIFT);
126 	if (patch_addr) {
127 		host1x_syncpt_patch_wait(sp,
128 					 patch_addr + (offset & ~PAGE_MASK));
129 		host1x_bo_kunmap(h, offset >> PAGE_SHIFT, patch_addr);
130 	} else
131 		pr_err("Could not map cmdbuf for wait check\n");
132 }
133 
134 /*
135  * Check driver supplied waitchk structs for syncpt thresholds
136  * that have already been satisfied and NULL the comparison (to
137  * avoid a wrap condition in the HW).
138  */
139 static int do_waitchks(struct host1x_job *job, struct host1x *host,
140 		       struct host1x_job_gather *g)
141 {
142 	struct host1x_bo *patch = g->bo;
143 	int i;
144 
145 	/* compare syncpt vs wait threshold */
146 	for (i = 0; i < job->num_waitchk; i++) {
147 		struct host1x_waitchk *wait = &job->waitchk[i];
148 		struct host1x_syncpt *sp =
149 			host1x_syncpt_get(host, wait->syncpt_id);
150 
151 		/* validate syncpt id */
152 		if (wait->syncpt_id > host1x_syncpt_nb_pts(host))
153 			continue;
154 
155 		/* skip all other gathers */
156 		if (patch != wait->bo)
157 			continue;
158 
159 		trace_host1x_syncpt_wait_check(wait->bo, wait->offset,
160 					       wait->syncpt_id, wait->thresh,
161 					       host1x_syncpt_read_min(sp));
162 
163 		if (host1x_syncpt_is_expired(sp, wait->thresh)) {
164 			dev_dbg(host->dev,
165 				"drop WAIT id %u (%s) thresh 0x%x, min 0x%x\n",
166 				wait->syncpt_id, sp->name, wait->thresh,
167 				host1x_syncpt_read_min(sp));
168 
169 			host1x_syncpt_patch_offset(sp, patch,
170 						   g->offset + wait->offset);
171 		}
172 
173 		wait->bo = NULL;
174 	}
175 
176 	return 0;
177 }
178 
179 static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
180 {
181 	unsigned int i;
182 	int err;
183 
184 	job->num_unpins = 0;
185 
186 	for (i = 0; i < job->num_relocs; i++) {
187 		struct host1x_reloc *reloc = &job->relocarray[i];
188 		struct sg_table *sgt;
189 		dma_addr_t phys_addr;
190 
191 		reloc->target.bo = host1x_bo_get(reloc->target.bo);
192 		if (!reloc->target.bo) {
193 			err = -EINVAL;
194 			goto unpin;
195 		}
196 
197 		phys_addr = host1x_bo_pin(reloc->target.bo, &sgt);
198 		if (!phys_addr) {
199 			err = -EINVAL;
200 			goto unpin;
201 		}
202 
203 		job->addr_phys[job->num_unpins] = phys_addr;
204 		job->unpins[job->num_unpins].bo = reloc->target.bo;
205 		job->unpins[job->num_unpins].sgt = sgt;
206 		job->num_unpins++;
207 	}
208 
209 	for (i = 0; i < job->num_gathers; i++) {
210 		struct host1x_job_gather *g = &job->gathers[i];
211 		size_t gather_size = 0;
212 		struct scatterlist *sg;
213 		struct sg_table *sgt;
214 		dma_addr_t phys_addr;
215 		unsigned long shift;
216 		struct iova *alloc;
217 		unsigned int j;
218 
219 		g->bo = host1x_bo_get(g->bo);
220 		if (!g->bo) {
221 			err = -EINVAL;
222 			goto unpin;
223 		}
224 
225 		phys_addr = host1x_bo_pin(g->bo, &sgt);
226 		if (!phys_addr) {
227 			err = -EINVAL;
228 			goto unpin;
229 		}
230 
231 		if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) {
232 			for_each_sg(sgt->sgl, sg, sgt->nents, j)
233 				gather_size += sg->length;
234 			gather_size = iova_align(&host->iova, gather_size);
235 
236 			shift = iova_shift(&host->iova);
237 			alloc = alloc_iova(&host->iova, gather_size >> shift,
238 					   host->iova_end >> shift, true);
239 			if (!alloc) {
240 				err = -ENOMEM;
241 				goto unpin;
242 			}
243 
244 			err = iommu_map_sg(host->domain,
245 					iova_dma_addr(&host->iova, alloc),
246 					sgt->sgl, sgt->nents, IOMMU_READ);
247 			if (err == 0) {
248 				__free_iova(&host->iova, alloc);
249 				err = -EINVAL;
250 				goto unpin;
251 			}
252 
253 			job->addr_phys[job->num_unpins] =
254 				iova_dma_addr(&host->iova, alloc);
255 			job->unpins[job->num_unpins].size = gather_size;
256 		} else {
257 			job->addr_phys[job->num_unpins] = phys_addr;
258 		}
259 
260 		job->gather_addr_phys[i] = job->addr_phys[job->num_unpins];
261 
262 		job->unpins[job->num_unpins].bo = g->bo;
263 		job->unpins[job->num_unpins].sgt = sgt;
264 		job->num_unpins++;
265 	}
266 
267 	return 0;
268 
269 unpin:
270 	host1x_job_unpin(job);
271 	return err;
272 }
273 
274 static int do_relocs(struct host1x_job *job, struct host1x_job_gather *g)
275 {
276 	int i = 0;
277 	u32 last_page = ~0;
278 	void *cmdbuf_page_addr = NULL;
279 	struct host1x_bo *cmdbuf = g->bo;
280 
281 	/* pin & patch the relocs for one gather */
282 	for (i = 0; i < job->num_relocs; i++) {
283 		struct host1x_reloc *reloc = &job->relocarray[i];
284 		u32 reloc_addr = (job->reloc_addr_phys[i] +
285 				  reloc->target.offset) >> reloc->shift;
286 		u32 *target;
287 
288 		/* skip all other gathers */
289 		if (cmdbuf != reloc->cmdbuf.bo)
290 			continue;
291 
292 		if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) {
293 			target = (u32 *)job->gather_copy_mapped +
294 					reloc->cmdbuf.offset / sizeof(u32) +
295 						g->offset / sizeof(u32);
296 			goto patch_reloc;
297 		}
298 
299 		if (last_page != reloc->cmdbuf.offset >> PAGE_SHIFT) {
300 			if (cmdbuf_page_addr)
301 				host1x_bo_kunmap(cmdbuf, last_page,
302 						 cmdbuf_page_addr);
303 
304 			cmdbuf_page_addr = host1x_bo_kmap(cmdbuf,
305 					reloc->cmdbuf.offset >> PAGE_SHIFT);
306 			last_page = reloc->cmdbuf.offset >> PAGE_SHIFT;
307 
308 			if (unlikely(!cmdbuf_page_addr)) {
309 				pr_err("Could not map cmdbuf for relocation\n");
310 				return -ENOMEM;
311 			}
312 		}
313 
314 		target = cmdbuf_page_addr + (reloc->cmdbuf.offset & ~PAGE_MASK);
315 patch_reloc:
316 		*target = reloc_addr;
317 	}
318 
319 	if (cmdbuf_page_addr)
320 		host1x_bo_kunmap(cmdbuf, last_page, cmdbuf_page_addr);
321 
322 	return 0;
323 }
324 
325 static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
326 			unsigned int offset)
327 {
328 	offset *= sizeof(u32);
329 
330 	if (reloc->cmdbuf.bo != cmdbuf || reloc->cmdbuf.offset != offset)
331 		return false;
332 
333 	return true;
334 }
335 
336 struct host1x_firewall {
337 	struct host1x_job *job;
338 	struct device *dev;
339 
340 	unsigned int num_relocs;
341 	struct host1x_reloc *reloc;
342 
343 	struct host1x_bo *cmdbuf;
344 	unsigned int offset;
345 
346 	u32 words;
347 	u32 class;
348 	u32 reg;
349 	u32 mask;
350 	u32 count;
351 };
352 
353 static int check_register(struct host1x_firewall *fw, unsigned long offset)
354 {
355 	if (fw->job->is_addr_reg(fw->dev, fw->class, offset)) {
356 		if (!fw->num_relocs)
357 			return -EINVAL;
358 
359 		if (!check_reloc(fw->reloc, fw->cmdbuf, fw->offset))
360 			return -EINVAL;
361 
362 		fw->num_relocs--;
363 		fw->reloc++;
364 	}
365 
366 	return 0;
367 }
368 
369 static int check_mask(struct host1x_firewall *fw)
370 {
371 	u32 mask = fw->mask;
372 	u32 reg = fw->reg;
373 	int ret;
374 
375 	while (mask) {
376 		if (fw->words == 0)
377 			return -EINVAL;
378 
379 		if (mask & 1) {
380 			ret = check_register(fw, reg);
381 			if (ret < 0)
382 				return ret;
383 
384 			fw->words--;
385 			fw->offset++;
386 		}
387 		mask >>= 1;
388 		reg++;
389 	}
390 
391 	return 0;
392 }
393 
394 static int check_incr(struct host1x_firewall *fw)
395 {
396 	u32 count = fw->count;
397 	u32 reg = fw->reg;
398 	int ret;
399 
400 	while (count) {
401 		if (fw->words == 0)
402 			return -EINVAL;
403 
404 		ret = check_register(fw, reg);
405 		if (ret < 0)
406 			return ret;
407 
408 		reg++;
409 		fw->words--;
410 		fw->offset++;
411 		count--;
412 	}
413 
414 	return 0;
415 }
416 
417 static int check_nonincr(struct host1x_firewall *fw)
418 {
419 	u32 count = fw->count;
420 	int ret;
421 
422 	while (count) {
423 		if (fw->words == 0)
424 			return -EINVAL;
425 
426 		ret = check_register(fw, fw->reg);
427 		if (ret < 0)
428 			return ret;
429 
430 		fw->words--;
431 		fw->offset++;
432 		count--;
433 	}
434 
435 	return 0;
436 }
437 
438 static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
439 {
440 	u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped +
441 		(g->offset / sizeof(u32));
442 	int err = 0;
443 
444 	if (!fw->job->is_addr_reg)
445 		return 0;
446 
447 	fw->words = g->words;
448 	fw->cmdbuf = g->bo;
449 	fw->offset = 0;
450 
451 	while (fw->words && !err) {
452 		u32 word = cmdbuf_base[fw->offset];
453 		u32 opcode = (word & 0xf0000000) >> 28;
454 
455 		fw->mask = 0;
456 		fw->reg = 0;
457 		fw->count = 0;
458 		fw->words--;
459 		fw->offset++;
460 
461 		switch (opcode) {
462 		case 0:
463 			fw->class = word >> 6 & 0x3ff;
464 			fw->mask = word & 0x3f;
465 			fw->reg = word >> 16 & 0xfff;
466 			err = check_mask(fw);
467 			if (err)
468 				goto out;
469 			break;
470 		case 1:
471 			fw->reg = word >> 16 & 0xfff;
472 			fw->count = word & 0xffff;
473 			err = check_incr(fw);
474 			if (err)
475 				goto out;
476 			break;
477 
478 		case 2:
479 			fw->reg = word >> 16 & 0xfff;
480 			fw->count = word & 0xffff;
481 			err = check_nonincr(fw);
482 			if (err)
483 				goto out;
484 			break;
485 
486 		case 3:
487 			fw->mask = word & 0xffff;
488 			fw->reg = word >> 16 & 0xfff;
489 			err = check_mask(fw);
490 			if (err)
491 				goto out;
492 			break;
493 		case 4:
494 		case 5:
495 		case 14:
496 			break;
497 		default:
498 			err = -EINVAL;
499 			break;
500 		}
501 	}
502 
503 out:
504 	return err;
505 }
506 
507 static inline int copy_gathers(struct host1x_job *job, struct device *dev)
508 {
509 	struct host1x_firewall fw;
510 	size_t size = 0;
511 	size_t offset = 0;
512 	int i;
513 
514 	fw.job = job;
515 	fw.dev = dev;
516 	fw.reloc = job->relocarray;
517 	fw.num_relocs = job->num_relocs;
518 	fw.class = job->class;
519 
520 	for (i = 0; i < job->num_gathers; i++) {
521 		struct host1x_job_gather *g = &job->gathers[i];
522 
523 		size += g->words * sizeof(u32);
524 	}
525 
526 	job->gather_copy_mapped = dma_alloc_wc(dev, size, &job->gather_copy,
527 					       GFP_KERNEL);
528 	if (!job->gather_copy_mapped) {
529 		job->gather_copy_mapped = NULL;
530 		return -ENOMEM;
531 	}
532 
533 	job->gather_copy_size = size;
534 
535 	for (i = 0; i < job->num_gathers; i++) {
536 		struct host1x_job_gather *g = &job->gathers[i];
537 		void *gather;
538 
539 		/* Copy the gather */
540 		gather = host1x_bo_mmap(g->bo);
541 		memcpy(job->gather_copy_mapped + offset, gather + g->offset,
542 		       g->words * sizeof(u32));
543 		host1x_bo_munmap(g->bo, gather);
544 
545 		/* Store the location in the buffer */
546 		g->base = job->gather_copy;
547 		g->offset = offset;
548 
549 		/* Validate the job */
550 		if (validate(&fw, g))
551 			return -EINVAL;
552 
553 		offset += g->words * sizeof(u32);
554 	}
555 
556 	/* No relocs should remain at this point */
557 	if (fw.num_relocs)
558 		return -EINVAL;
559 
560 	return 0;
561 }
562 
563 int host1x_job_pin(struct host1x_job *job, struct device *dev)
564 {
565 	int err;
566 	unsigned int i, j;
567 	struct host1x *host = dev_get_drvdata(dev->parent);
568 	DECLARE_BITMAP(waitchk_mask, host1x_syncpt_nb_pts(host));
569 
570 	bitmap_zero(waitchk_mask, host1x_syncpt_nb_pts(host));
571 	for (i = 0; i < job->num_waitchk; i++) {
572 		u32 syncpt_id = job->waitchk[i].syncpt_id;
573 
574 		if (syncpt_id < host1x_syncpt_nb_pts(host))
575 			set_bit(syncpt_id, waitchk_mask);
576 	}
577 
578 	/* get current syncpt values for waitchk */
579 	for_each_set_bit(i, waitchk_mask, host1x_syncpt_nb_pts(host))
580 		host1x_syncpt_load(host->syncpt + i);
581 
582 	/* pin memory */
583 	err = pin_job(host, job);
584 	if (err)
585 		goto out;
586 
587 	if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) {
588 		err = copy_gathers(job, dev);
589 		if (err)
590 			goto out;
591 	}
592 
593 	/* patch gathers */
594 	for (i = 0; i < job->num_gathers; i++) {
595 		struct host1x_job_gather *g = &job->gathers[i];
596 
597 		/* process each gather mem only once */
598 		if (g->handled)
599 			continue;
600 
601 		/* copy_gathers() sets gathers base if firewall is enabled */
602 		if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
603 			g->base = job->gather_addr_phys[i];
604 
605 		for (j = i + 1; j < job->num_gathers; j++) {
606 			if (job->gathers[j].bo == g->bo) {
607 				job->gathers[j].handled = true;
608 				job->gathers[j].base = g->base;
609 			}
610 		}
611 
612 		err = do_relocs(job, g);
613 		if (err)
614 			break;
615 
616 		err = do_waitchks(job, host, g);
617 		if (err)
618 			break;
619 	}
620 
621 out:
622 	if (err)
623 		host1x_job_unpin(job);
624 	wmb();
625 
626 	return err;
627 }
628 EXPORT_SYMBOL(host1x_job_pin);
629 
630 void host1x_job_unpin(struct host1x_job *job)
631 {
632 	struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
633 	unsigned int i;
634 
635 	for (i = 0; i < job->num_unpins; i++) {
636 		struct host1x_job_unpin_data *unpin = &job->unpins[i];
637 
638 		if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) {
639 			iommu_unmap(host->domain, job->addr_phys[i],
640 				    unpin->size);
641 			free_iova(&host->iova,
642 				iova_pfn(&host->iova, job->addr_phys[i]));
643 		}
644 
645 		host1x_bo_unpin(unpin->bo, unpin->sgt);
646 		host1x_bo_put(unpin->bo);
647 	}
648 
649 	job->num_unpins = 0;
650 
651 	if (job->gather_copy_size)
652 		dma_free_wc(job->channel->dev, job->gather_copy_size,
653 			    job->gather_copy_mapped, job->gather_copy);
654 }
655 EXPORT_SYMBOL(host1x_job_unpin);
656 
657 /*
658  * Debug routine used to dump job entries
659  */
660 void host1x_job_dump(struct device *dev, struct host1x_job *job)
661 {
662 	dev_dbg(dev, "    SYNCPT_ID   %d\n", job->syncpt_id);
663 	dev_dbg(dev, "    SYNCPT_VAL  %d\n", job->syncpt_end);
664 	dev_dbg(dev, "    FIRST_GET   0x%x\n", job->first_get);
665 	dev_dbg(dev, "    TIMEOUT     %d\n", job->timeout);
666 	dev_dbg(dev, "    NUM_SLOTS   %d\n", job->num_slots);
667 	dev_dbg(dev, "    NUM_HANDLES %d\n", job->num_unpins);
668 }
669