job.c (14228B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Tegra host1x Job 4 * 5 * Copyright (c) 2010-2015, NVIDIA Corporation. 6 */ 7 8#include <linux/dma-mapping.h> 9#include <linux/err.h> 10#include <linux/host1x.h> 11#include <linux/iommu.h> 12#include <linux/kref.h> 13#include <linux/module.h> 14#include <linux/scatterlist.h> 15#include <linux/slab.h> 16#include <linux/vmalloc.h> 17#include <trace/events/host1x.h> 18 19#include "channel.h" 20#include "dev.h" 21#include "job.h" 22#include "syncpt.h" 23 24#define HOST1X_WAIT_SYNCPT_OFFSET 0x8 25 26struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, 27 u32 num_cmdbufs, u32 num_relocs, 28 bool skip_firewall) 29{ 30 struct host1x_job *job = NULL; 31 unsigned int num_unpins = num_relocs; 32 bool enable_firewall; 33 u64 total; 34 void *mem; 35 36 enable_firewall = IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && !skip_firewall; 37 38 if (!enable_firewall) 39 num_unpins += num_cmdbufs; 40 41 /* Check that we're not going to overflow */ 42 total = sizeof(struct host1x_job) + 43 (u64)num_relocs * sizeof(struct host1x_reloc) + 44 (u64)num_unpins * sizeof(struct host1x_job_unpin_data) + 45 (u64)num_cmdbufs * sizeof(struct host1x_job_cmd) + 46 (u64)num_unpins * sizeof(dma_addr_t) + 47 (u64)num_unpins * sizeof(u32 *); 48 if (total > ULONG_MAX) 49 return NULL; 50 51 mem = job = kzalloc(total, GFP_KERNEL); 52 if (!job) 53 return NULL; 54 55 job->enable_firewall = enable_firewall; 56 57 kref_init(&job->ref); 58 job->channel = ch; 59 60 /* Redistribute memory to the structs */ 61 mem += sizeof(struct host1x_job); 62 job->relocs = num_relocs ? mem : NULL; 63 mem += num_relocs * sizeof(struct host1x_reloc); 64 job->unpins = num_unpins ? mem : NULL; 65 mem += num_unpins * sizeof(struct host1x_job_unpin_data); 66 job->cmds = num_cmdbufs ? mem : NULL; 67 mem += num_cmdbufs * sizeof(struct host1x_job_cmd); 68 job->addr_phys = num_unpins ? mem : NULL; 69 70 job->reloc_addr_phys = job->addr_phys; 71 job->gather_addr_phys = &job->addr_phys[num_relocs]; 72 73 return job; 74} 75EXPORT_SYMBOL(host1x_job_alloc); 76 77struct host1x_job *host1x_job_get(struct host1x_job *job) 78{ 79 kref_get(&job->ref); 80 return job; 81} 82EXPORT_SYMBOL(host1x_job_get); 83 84static void job_free(struct kref *ref) 85{ 86 struct host1x_job *job = container_of(ref, struct host1x_job, ref); 87 88 if (job->release) 89 job->release(job); 90 91 if (job->waiter) 92 host1x_intr_put_ref(job->syncpt->host, job->syncpt->id, 93 job->waiter, false); 94 95 if (job->syncpt) 96 host1x_syncpt_put(job->syncpt); 97 98 kfree(job); 99} 100 101void host1x_job_put(struct host1x_job *job) 102{ 103 kref_put(&job->ref, job_free); 104} 105EXPORT_SYMBOL(host1x_job_put); 106 107void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, 108 unsigned int words, unsigned int offset) 109{ 110 struct host1x_job_gather *gather = &job->cmds[job->num_cmds].gather; 111 112 gather->words = words; 113 gather->bo = bo; 114 gather->offset = offset; 115 116 job->num_cmds++; 117} 118EXPORT_SYMBOL(host1x_job_add_gather); 119 120void host1x_job_add_wait(struct host1x_job *job, u32 id, u32 thresh, 121 bool relative, u32 next_class) 122{ 123 struct host1x_job_cmd *cmd = &job->cmds[job->num_cmds]; 124 125 cmd->is_wait = true; 126 cmd->wait.id = id; 127 cmd->wait.threshold = thresh; 128 cmd->wait.next_class = next_class; 129 cmd->wait.relative = relative; 130 131 job->num_cmds++; 132} 133EXPORT_SYMBOL(host1x_job_add_wait); 134 135static unsigned int pin_job(struct host1x *host, struct host1x_job *job) 136{ 137 unsigned long mask = HOST1X_RELOC_READ | HOST1X_RELOC_WRITE; 138 struct host1x_client *client = job->client; 139 struct device *dev = client->dev; 140 struct host1x_job_gather *g; 141 unsigned int i; 142 int err; 143 144 job->num_unpins = 0; 145 146 for (i = 0; i < job->num_relocs; i++) { 147 struct host1x_reloc *reloc = &job->relocs[i]; 148 enum dma_data_direction direction; 149 struct host1x_bo_mapping *map; 150 struct host1x_bo *bo; 151 152 reloc->target.bo = host1x_bo_get(reloc->target.bo); 153 if (!reloc->target.bo) { 154 err = -EINVAL; 155 goto unpin; 156 } 157 158 bo = reloc->target.bo; 159 160 switch (reloc->flags & mask) { 161 case HOST1X_RELOC_READ: 162 direction = DMA_TO_DEVICE; 163 break; 164 165 case HOST1X_RELOC_WRITE: 166 direction = DMA_FROM_DEVICE; 167 break; 168 169 case HOST1X_RELOC_READ | HOST1X_RELOC_WRITE: 170 direction = DMA_BIDIRECTIONAL; 171 break; 172 173 default: 174 err = -EINVAL; 175 goto unpin; 176 } 177 178 map = host1x_bo_pin(dev, bo, direction, NULL); 179 if (IS_ERR(map)) { 180 err = PTR_ERR(map); 181 goto unpin; 182 } 183 184 /* 185 * host1x clients are generally not able to do scatter-gather themselves, so fail 186 * if the buffer is discontiguous and we fail to map its SG table to a single 187 * contiguous chunk of I/O virtual memory. 188 */ 189 if (map->chunks > 1) { 190 err = -EINVAL; 191 goto unpin; 192 } 193 194 job->addr_phys[job->num_unpins] = map->phys; 195 job->unpins[job->num_unpins].map = map; 196 job->num_unpins++; 197 } 198 199 /* 200 * We will copy gathers BO content later, so there is no need to 201 * hold and pin them. 202 */ 203 if (job->enable_firewall) 204 return 0; 205 206 for (i = 0; i < job->num_cmds; i++) { 207 struct host1x_bo_mapping *map; 208 size_t gather_size = 0; 209 struct scatterlist *sg; 210 unsigned long shift; 211 struct iova *alloc; 212 unsigned int j; 213 214 if (job->cmds[i].is_wait) 215 continue; 216 217 g = &job->cmds[i].gather; 218 219 g->bo = host1x_bo_get(g->bo); 220 if (!g->bo) { 221 err = -EINVAL; 222 goto unpin; 223 } 224 225 map = host1x_bo_pin(host->dev, g->bo, DMA_TO_DEVICE, NULL); 226 if (IS_ERR(map)) { 227 err = PTR_ERR(map); 228 goto unpin; 229 } 230 231 if (host->domain) { 232 for_each_sgtable_sg(map->sgt, sg, j) 233 gather_size += sg->length; 234 235 gather_size = iova_align(&host->iova, gather_size); 236 237 shift = iova_shift(&host->iova); 238 alloc = alloc_iova(&host->iova, gather_size >> shift, 239 host->iova_end >> shift, true); 240 if (!alloc) { 241 err = -ENOMEM; 242 goto put; 243 } 244 245 err = iommu_map_sgtable(host->domain, iova_dma_addr(&host->iova, alloc), 246 map->sgt, IOMMU_READ); 247 if (err == 0) { 248 __free_iova(&host->iova, alloc); 249 err = -EINVAL; 250 goto put; 251 } 252 253 map->phys = iova_dma_addr(&host->iova, alloc); 254 map->size = gather_size; 255 } 256 257 job->addr_phys[job->num_unpins] = map->phys; 258 job->unpins[job->num_unpins].map = map; 259 job->num_unpins++; 260 261 job->gather_addr_phys[i] = map->phys; 262 } 263 264 return 0; 265 266put: 267 host1x_bo_put(g->bo); 268unpin: 269 host1x_job_unpin(job); 270 return err; 271} 272 273static int do_relocs(struct host1x_job *job, struct host1x_job_gather *g) 274{ 275 void *cmdbuf_addr = NULL; 276 struct host1x_bo *cmdbuf = g->bo; 277 unsigned int i; 278 279 /* pin & patch the relocs for one gather */ 280 for (i = 0; i < job->num_relocs; i++) { 281 struct host1x_reloc *reloc = &job->relocs[i]; 282 u32 reloc_addr = (job->reloc_addr_phys[i] + 283 reloc->target.offset) >> reloc->shift; 284 u32 *target; 285 286 /* skip all other gathers */ 287 if (cmdbuf != reloc->cmdbuf.bo) 288 continue; 289 290 if (job->enable_firewall) { 291 target = (u32 *)job->gather_copy_mapped + 292 reloc->cmdbuf.offset / sizeof(u32) + 293 g->offset / sizeof(u32); 294 goto patch_reloc; 295 } 296 297 if (!cmdbuf_addr) { 298 cmdbuf_addr = host1x_bo_mmap(cmdbuf); 299 300 if (unlikely(!cmdbuf_addr)) { 301 pr_err("Could not map cmdbuf for relocation\n"); 302 return -ENOMEM; 303 } 304 } 305 306 target = cmdbuf_addr + reloc->cmdbuf.offset; 307patch_reloc: 308 *target = reloc_addr; 309 } 310 311 if (cmdbuf_addr) 312 host1x_bo_munmap(cmdbuf, cmdbuf_addr); 313 314 return 0; 315} 316 317static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf, 318 unsigned int offset) 319{ 320 offset *= sizeof(u32); 321 322 if (reloc->cmdbuf.bo != cmdbuf || reloc->cmdbuf.offset != offset) 323 return false; 324 325 /* relocation shift value validation isn't implemented yet */ 326 if (reloc->shift) 327 return false; 328 329 return true; 330} 331 332struct host1x_firewall { 333 struct host1x_job *job; 334 struct device *dev; 335 336 unsigned int num_relocs; 337 struct host1x_reloc *reloc; 338 339 struct host1x_bo *cmdbuf; 340 unsigned int offset; 341 342 u32 words; 343 u32 class; 344 u32 reg; 345 u32 mask; 346 u32 count; 347}; 348 349static int check_register(struct host1x_firewall *fw, unsigned long offset) 350{ 351 if (!fw->job->is_addr_reg) 352 return 0; 353 354 if (fw->job->is_addr_reg(fw->dev, fw->class, offset)) { 355 if (!fw->num_relocs) 356 return -EINVAL; 357 358 if (!check_reloc(fw->reloc, fw->cmdbuf, fw->offset)) 359 return -EINVAL; 360 361 fw->num_relocs--; 362 fw->reloc++; 363 } 364 365 return 0; 366} 367 368static int check_class(struct host1x_firewall *fw, u32 class) 369{ 370 if (!fw->job->is_valid_class) { 371 if (fw->class != class) 372 return -EINVAL; 373 } else { 374 if (!fw->job->is_valid_class(fw->class)) 375 return -EINVAL; 376 } 377 378 return 0; 379} 380 381static int check_mask(struct host1x_firewall *fw) 382{ 383 u32 mask = fw->mask; 384 u32 reg = fw->reg; 385 int ret; 386 387 while (mask) { 388 if (fw->words == 0) 389 return -EINVAL; 390 391 if (mask & 1) { 392 ret = check_register(fw, reg); 393 if (ret < 0) 394 return ret; 395 396 fw->words--; 397 fw->offset++; 398 } 399 mask >>= 1; 400 reg++; 401 } 402 403 return 0; 404} 405 406static int check_incr(struct host1x_firewall *fw) 407{ 408 u32 count = fw->count; 409 u32 reg = fw->reg; 410 int ret; 411 412 while (count) { 413 if (fw->words == 0) 414 return -EINVAL; 415 416 ret = check_register(fw, reg); 417 if (ret < 0) 418 return ret; 419 420 reg++; 421 fw->words--; 422 fw->offset++; 423 count--; 424 } 425 426 return 0; 427} 428 429static int check_nonincr(struct host1x_firewall *fw) 430{ 431 u32 count = fw->count; 432 int ret; 433 434 while (count) { 435 if (fw->words == 0) 436 return -EINVAL; 437 438 ret = check_register(fw, fw->reg); 439 if (ret < 0) 440 return ret; 441 442 fw->words--; 443 fw->offset++; 444 count--; 445 } 446 447 return 0; 448} 449 450static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g) 451{ 452 u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped + 453 (g->offset / sizeof(u32)); 454 u32 job_class = fw->class; 455 int err = 0; 456 457 fw->words = g->words; 458 fw->cmdbuf = g->bo; 459 fw->offset = 0; 460 461 while (fw->words && !err) { 462 u32 word = cmdbuf_base[fw->offset]; 463 u32 opcode = (word & 0xf0000000) >> 28; 464 465 fw->mask = 0; 466 fw->reg = 0; 467 fw->count = 0; 468 fw->words--; 469 fw->offset++; 470 471 switch (opcode) { 472 case 0: 473 fw->class = word >> 6 & 0x3ff; 474 fw->mask = word & 0x3f; 475 fw->reg = word >> 16 & 0xfff; 476 err = check_class(fw, job_class); 477 if (!err) 478 err = check_mask(fw); 479 if (err) 480 goto out; 481 break; 482 case 1: 483 fw->reg = word >> 16 & 0xfff; 484 fw->count = word & 0xffff; 485 err = check_incr(fw); 486 if (err) 487 goto out; 488 break; 489 490 case 2: 491 fw->reg = word >> 16 & 0xfff; 492 fw->count = word & 0xffff; 493 err = check_nonincr(fw); 494 if (err) 495 goto out; 496 break; 497 498 case 3: 499 fw->mask = word & 0xffff; 500 fw->reg = word >> 16 & 0xfff; 501 err = check_mask(fw); 502 if (err) 503 goto out; 504 break; 505 case 4: 506 case 14: 507 break; 508 default: 509 err = -EINVAL; 510 break; 511 } 512 } 513 514out: 515 return err; 516} 517 518static inline int copy_gathers(struct device *host, struct host1x_job *job, 519 struct device *dev) 520{ 521 struct host1x_firewall fw; 522 size_t size = 0; 523 size_t offset = 0; 524 unsigned int i; 525 526 fw.job = job; 527 fw.dev = dev; 528 fw.reloc = job->relocs; 529 fw.num_relocs = job->num_relocs; 530 fw.class = job->class; 531 532 for (i = 0; i < job->num_cmds; i++) { 533 struct host1x_job_gather *g; 534 535 if (job->cmds[i].is_wait) 536 continue; 537 538 g = &job->cmds[i].gather; 539 540 size += g->words * sizeof(u32); 541 } 542 543 /* 544 * Try a non-blocking allocation from a higher priority pools first, 545 * as awaiting for the allocation here is a major performance hit. 546 */ 547 job->gather_copy_mapped = dma_alloc_wc(host, size, &job->gather_copy, 548 GFP_NOWAIT); 549 550 /* the higher priority allocation failed, try the generic-blocking */ 551 if (!job->gather_copy_mapped) 552 job->gather_copy_mapped = dma_alloc_wc(host, size, 553 &job->gather_copy, 554 GFP_KERNEL); 555 if (!job->gather_copy_mapped) 556 return -ENOMEM; 557 558 job->gather_copy_size = size; 559 560 for (i = 0; i < job->num_cmds; i++) { 561 struct host1x_job_gather *g; 562 void *gather; 563 564 if (job->cmds[i].is_wait) 565 continue; 566 g = &job->cmds[i].gather; 567 568 /* Copy the gather */ 569 gather = host1x_bo_mmap(g->bo); 570 memcpy(job->gather_copy_mapped + offset, gather + g->offset, 571 g->words * sizeof(u32)); 572 host1x_bo_munmap(g->bo, gather); 573 574 /* Store the location in the buffer */ 575 g->base = job->gather_copy; 576 g->offset = offset; 577 578 /* Validate the job */ 579 if (validate(&fw, g)) 580 return -EINVAL; 581 582 offset += g->words * sizeof(u32); 583 } 584 585 /* No relocs should remain at this point */ 586 if (fw.num_relocs) 587 return -EINVAL; 588 589 return 0; 590} 591 592int host1x_job_pin(struct host1x_job *job, struct device *dev) 593{ 594 int err; 595 unsigned int i, j; 596 struct host1x *host = dev_get_drvdata(dev->parent); 597 598 /* pin memory */ 599 err = pin_job(host, job); 600 if (err) 601 goto out; 602 603 if (job->enable_firewall) { 604 err = copy_gathers(host->dev, job, dev); 605 if (err) 606 goto out; 607 } 608 609 /* patch gathers */ 610 for (i = 0; i < job->num_cmds; i++) { 611 struct host1x_job_gather *g; 612 613 if (job->cmds[i].is_wait) 614 continue; 615 g = &job->cmds[i].gather; 616 617 /* process each gather mem only once */ 618 if (g->handled) 619 continue; 620 621 /* copy_gathers() sets gathers base if firewall is enabled */ 622 if (!job->enable_firewall) 623 g->base = job->gather_addr_phys[i]; 624 625 for (j = i + 1; j < job->num_cmds; j++) { 626 if (!job->cmds[j].is_wait && 627 job->cmds[j].gather.bo == g->bo) { 628 job->cmds[j].gather.handled = true; 629 job->cmds[j].gather.base = g->base; 630 } 631 } 632 633 err = do_relocs(job, g); 634 if (err) 635 break; 636 } 637 638out: 639 if (err) 640 host1x_job_unpin(job); 641 wmb(); 642 643 return err; 644} 645EXPORT_SYMBOL(host1x_job_pin); 646 647void host1x_job_unpin(struct host1x_job *job) 648{ 649 struct host1x *host = dev_get_drvdata(job->channel->dev->parent); 650 unsigned int i; 651 652 for (i = 0; i < job->num_unpins; i++) { 653 struct host1x_bo_mapping *map = job->unpins[i].map; 654 struct host1x_bo *bo = map->bo; 655 656 if (!job->enable_firewall && map->size && host->domain) { 657 iommu_unmap(host->domain, job->addr_phys[i], map->size); 658 free_iova(&host->iova, iova_pfn(&host->iova, job->addr_phys[i])); 659 } 660 661 host1x_bo_unpin(map); 662 host1x_bo_put(bo); 663 } 664 665 job->num_unpins = 0; 666 667 if (job->gather_copy_size) 668 dma_free_wc(host->dev, job->gather_copy_size, 669 job->gather_copy_mapped, job->gather_copy); 670} 671EXPORT_SYMBOL(host1x_job_unpin); 672 673/* 674 * Debug routine used to dump job entries 675 */ 676void host1x_job_dump(struct device *dev, struct host1x_job *job) 677{ 678 dev_dbg(dev, " SYNCPT_ID %d\n", job->syncpt->id); 679 dev_dbg(dev, " SYNCPT_VAL %d\n", job->syncpt_end); 680 dev_dbg(dev, " FIRST_GET 0x%x\n", job->first_get); 681 dev_dbg(dev, " TIMEOUT %d\n", job->timeout); 682 dev_dbg(dev, " NUM_SLOTS %d\n", job->num_slots); 683 dev_dbg(dev, " NUM_HANDLES %d\n", job->num_unpins); 684}