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 #define HOST1X_WAIT_SYNCPT_OFFSET 0x8 35 36 struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, 37 u32 num_cmdbufs, u32 num_relocs) 38 { 39 struct host1x_job *job = NULL; 40 unsigned int num_unpins = num_cmdbufs + num_relocs; 41 u64 total; 42 void *mem; 43 44 /* Check that we're not going to overflow */ 45 total = sizeof(struct host1x_job) + 46 (u64)num_relocs * sizeof(struct host1x_reloc) + 47 (u64)num_unpins * sizeof(struct host1x_job_unpin_data) + 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->relocs = 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->gathers = num_cmdbufs ? mem : NULL; 68 mem += num_cmdbufs * sizeof(struct host1x_job_gather); 69 job->addr_phys = num_unpins ? mem : NULL; 70 71 job->reloc_addr_phys = job->addr_phys; 72 job->gather_addr_phys = &job->addr_phys[num_relocs]; 73 74 return job; 75 } 76 EXPORT_SYMBOL(host1x_job_alloc); 77 78 struct host1x_job *host1x_job_get(struct host1x_job *job) 79 { 80 kref_get(&job->ref); 81 return job; 82 } 83 EXPORT_SYMBOL(host1x_job_get); 84 85 static void job_free(struct kref *ref) 86 { 87 struct host1x_job *job = container_of(ref, struct host1x_job, ref); 88 89 kfree(job); 90 } 91 92 void host1x_job_put(struct host1x_job *job) 93 { 94 kref_put(&job->ref, job_free); 95 } 96 EXPORT_SYMBOL(host1x_job_put); 97 98 void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, 99 unsigned int words, unsigned int offset) 100 { 101 struct host1x_job_gather *gather = &job->gathers[job->num_gathers]; 102 103 gather->words = words; 104 gather->bo = bo; 105 gather->offset = offset; 106 107 job->num_gathers++; 108 } 109 EXPORT_SYMBOL(host1x_job_add_gather); 110 111 static unsigned int pin_job(struct host1x *host, struct host1x_job *job) 112 { 113 unsigned int i; 114 int err; 115 116 job->num_unpins = 0; 117 118 for (i = 0; i < job->num_relocs; i++) { 119 struct host1x_reloc *reloc = &job->relocs[i]; 120 struct sg_table *sgt; 121 dma_addr_t phys_addr; 122 123 reloc->target.bo = host1x_bo_get(reloc->target.bo); 124 if (!reloc->target.bo) { 125 err = -EINVAL; 126 goto unpin; 127 } 128 129 phys_addr = host1x_bo_pin(reloc->target.bo, &sgt); 130 131 job->addr_phys[job->num_unpins] = phys_addr; 132 job->unpins[job->num_unpins].bo = reloc->target.bo; 133 job->unpins[job->num_unpins].sgt = sgt; 134 job->num_unpins++; 135 } 136 137 for (i = 0; i < job->num_gathers; i++) { 138 struct host1x_job_gather *g = &job->gathers[i]; 139 size_t gather_size = 0; 140 struct scatterlist *sg; 141 struct sg_table *sgt; 142 dma_addr_t phys_addr; 143 unsigned long shift; 144 struct iova *alloc; 145 unsigned int j; 146 147 g->bo = host1x_bo_get(g->bo); 148 if (!g->bo) { 149 err = -EINVAL; 150 goto unpin; 151 } 152 153 phys_addr = host1x_bo_pin(g->bo, &sgt); 154 155 if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) { 156 for_each_sg(sgt->sgl, sg, sgt->nents, j) 157 gather_size += sg->length; 158 gather_size = iova_align(&host->iova, gather_size); 159 160 shift = iova_shift(&host->iova); 161 alloc = alloc_iova(&host->iova, gather_size >> shift, 162 host->iova_end >> shift, true); 163 if (!alloc) { 164 err = -ENOMEM; 165 goto unpin; 166 } 167 168 err = iommu_map_sg(host->domain, 169 iova_dma_addr(&host->iova, alloc), 170 sgt->sgl, sgt->nents, IOMMU_READ); 171 if (err == 0) { 172 __free_iova(&host->iova, alloc); 173 err = -EINVAL; 174 goto unpin; 175 } 176 177 job->addr_phys[job->num_unpins] = 178 iova_dma_addr(&host->iova, alloc); 179 job->unpins[job->num_unpins].size = gather_size; 180 } else { 181 job->addr_phys[job->num_unpins] = phys_addr; 182 } 183 184 job->gather_addr_phys[i] = job->addr_phys[job->num_unpins]; 185 186 job->unpins[job->num_unpins].bo = g->bo; 187 job->unpins[job->num_unpins].sgt = sgt; 188 job->num_unpins++; 189 } 190 191 return 0; 192 193 unpin: 194 host1x_job_unpin(job); 195 return err; 196 } 197 198 static int do_relocs(struct host1x_job *job, struct host1x_job_gather *g) 199 { 200 u32 last_page = ~0; 201 void *cmdbuf_page_addr = NULL; 202 struct host1x_bo *cmdbuf = g->bo; 203 unsigned int i; 204 205 /* pin & patch the relocs for one gather */ 206 for (i = 0; i < job->num_relocs; i++) { 207 struct host1x_reloc *reloc = &job->relocs[i]; 208 u32 reloc_addr = (job->reloc_addr_phys[i] + 209 reloc->target.offset) >> reloc->shift; 210 u32 *target; 211 212 /* skip all other gathers */ 213 if (cmdbuf != reloc->cmdbuf.bo) 214 continue; 215 216 if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) { 217 target = (u32 *)job->gather_copy_mapped + 218 reloc->cmdbuf.offset / sizeof(u32) + 219 g->offset / sizeof(u32); 220 goto patch_reloc; 221 } 222 223 if (last_page != reloc->cmdbuf.offset >> PAGE_SHIFT) { 224 if (cmdbuf_page_addr) 225 host1x_bo_kunmap(cmdbuf, last_page, 226 cmdbuf_page_addr); 227 228 cmdbuf_page_addr = host1x_bo_kmap(cmdbuf, 229 reloc->cmdbuf.offset >> PAGE_SHIFT); 230 last_page = reloc->cmdbuf.offset >> PAGE_SHIFT; 231 232 if (unlikely(!cmdbuf_page_addr)) { 233 pr_err("Could not map cmdbuf for relocation\n"); 234 return -ENOMEM; 235 } 236 } 237 238 target = cmdbuf_page_addr + (reloc->cmdbuf.offset & ~PAGE_MASK); 239 patch_reloc: 240 *target = reloc_addr; 241 } 242 243 if (cmdbuf_page_addr) 244 host1x_bo_kunmap(cmdbuf, last_page, cmdbuf_page_addr); 245 246 return 0; 247 } 248 249 static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf, 250 unsigned int offset) 251 { 252 offset *= sizeof(u32); 253 254 if (reloc->cmdbuf.bo != cmdbuf || reloc->cmdbuf.offset != offset) 255 return false; 256 257 /* relocation shift value validation isn't implemented yet */ 258 if (reloc->shift) 259 return false; 260 261 return true; 262 } 263 264 struct host1x_firewall { 265 struct host1x_job *job; 266 struct device *dev; 267 268 unsigned int num_relocs; 269 struct host1x_reloc *reloc; 270 271 struct host1x_bo *cmdbuf; 272 unsigned int offset; 273 274 u32 words; 275 u32 class; 276 u32 reg; 277 u32 mask; 278 u32 count; 279 }; 280 281 static int check_register(struct host1x_firewall *fw, unsigned long offset) 282 { 283 if (!fw->job->is_addr_reg) 284 return 0; 285 286 if (fw->job->is_addr_reg(fw->dev, fw->class, offset)) { 287 if (!fw->num_relocs) 288 return -EINVAL; 289 290 if (!check_reloc(fw->reloc, fw->cmdbuf, fw->offset)) 291 return -EINVAL; 292 293 fw->num_relocs--; 294 fw->reloc++; 295 } 296 297 return 0; 298 } 299 300 static int check_class(struct host1x_firewall *fw, u32 class) 301 { 302 if (!fw->job->is_valid_class) { 303 if (fw->class != class) 304 return -EINVAL; 305 } else { 306 if (!fw->job->is_valid_class(fw->class)) 307 return -EINVAL; 308 } 309 310 return 0; 311 } 312 313 static int check_mask(struct host1x_firewall *fw) 314 { 315 u32 mask = fw->mask; 316 u32 reg = fw->reg; 317 int ret; 318 319 while (mask) { 320 if (fw->words == 0) 321 return -EINVAL; 322 323 if (mask & 1) { 324 ret = check_register(fw, reg); 325 if (ret < 0) 326 return ret; 327 328 fw->words--; 329 fw->offset++; 330 } 331 mask >>= 1; 332 reg++; 333 } 334 335 return 0; 336 } 337 338 static int check_incr(struct host1x_firewall *fw) 339 { 340 u32 count = fw->count; 341 u32 reg = fw->reg; 342 int ret; 343 344 while (count) { 345 if (fw->words == 0) 346 return -EINVAL; 347 348 ret = check_register(fw, reg); 349 if (ret < 0) 350 return ret; 351 352 reg++; 353 fw->words--; 354 fw->offset++; 355 count--; 356 } 357 358 return 0; 359 } 360 361 static int check_nonincr(struct host1x_firewall *fw) 362 { 363 u32 count = fw->count; 364 int ret; 365 366 while (count) { 367 if (fw->words == 0) 368 return -EINVAL; 369 370 ret = check_register(fw, fw->reg); 371 if (ret < 0) 372 return ret; 373 374 fw->words--; 375 fw->offset++; 376 count--; 377 } 378 379 return 0; 380 } 381 382 static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g) 383 { 384 u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped + 385 (g->offset / sizeof(u32)); 386 u32 job_class = fw->class; 387 int err = 0; 388 389 fw->words = g->words; 390 fw->cmdbuf = g->bo; 391 fw->offset = 0; 392 393 while (fw->words && !err) { 394 u32 word = cmdbuf_base[fw->offset]; 395 u32 opcode = (word & 0xf0000000) >> 28; 396 397 fw->mask = 0; 398 fw->reg = 0; 399 fw->count = 0; 400 fw->words--; 401 fw->offset++; 402 403 switch (opcode) { 404 case 0: 405 fw->class = word >> 6 & 0x3ff; 406 fw->mask = word & 0x3f; 407 fw->reg = word >> 16 & 0xfff; 408 err = check_class(fw, job_class); 409 if (!err) 410 err = check_mask(fw); 411 if (err) 412 goto out; 413 break; 414 case 1: 415 fw->reg = word >> 16 & 0xfff; 416 fw->count = word & 0xffff; 417 err = check_incr(fw); 418 if (err) 419 goto out; 420 break; 421 422 case 2: 423 fw->reg = word >> 16 & 0xfff; 424 fw->count = word & 0xffff; 425 err = check_nonincr(fw); 426 if (err) 427 goto out; 428 break; 429 430 case 3: 431 fw->mask = word & 0xffff; 432 fw->reg = word >> 16 & 0xfff; 433 err = check_mask(fw); 434 if (err) 435 goto out; 436 break; 437 case 4: 438 case 14: 439 break; 440 default: 441 err = -EINVAL; 442 break; 443 } 444 } 445 446 out: 447 return err; 448 } 449 450 static inline int copy_gathers(struct host1x_job *job, struct device *dev) 451 { 452 struct host1x_firewall fw; 453 size_t size = 0; 454 size_t offset = 0; 455 unsigned int i; 456 457 fw.job = job; 458 fw.dev = dev; 459 fw.reloc = job->relocs; 460 fw.num_relocs = job->num_relocs; 461 fw.class = job->class; 462 463 for (i = 0; i < job->num_gathers; i++) { 464 struct host1x_job_gather *g = &job->gathers[i]; 465 466 size += g->words * sizeof(u32); 467 } 468 469 /* 470 * Try a non-blocking allocation from a higher priority pools first, 471 * as awaiting for the allocation here is a major performance hit. 472 */ 473 job->gather_copy_mapped = dma_alloc_wc(dev, size, &job->gather_copy, 474 GFP_NOWAIT); 475 476 /* the higher priority allocation failed, try the generic-blocking */ 477 if (!job->gather_copy_mapped) 478 job->gather_copy_mapped = dma_alloc_wc(dev, size, 479 &job->gather_copy, 480 GFP_KERNEL); 481 if (!job->gather_copy_mapped) 482 return -ENOMEM; 483 484 job->gather_copy_size = size; 485 486 for (i = 0; i < job->num_gathers; i++) { 487 struct host1x_job_gather *g = &job->gathers[i]; 488 void *gather; 489 490 /* Copy the gather */ 491 gather = host1x_bo_mmap(g->bo); 492 memcpy(job->gather_copy_mapped + offset, gather + g->offset, 493 g->words * sizeof(u32)); 494 host1x_bo_munmap(g->bo, gather); 495 496 /* Store the location in the buffer */ 497 g->base = job->gather_copy; 498 g->offset = offset; 499 500 /* Validate the job */ 501 if (validate(&fw, g)) 502 return -EINVAL; 503 504 offset += g->words * sizeof(u32); 505 } 506 507 /* No relocs should remain at this point */ 508 if (fw.num_relocs) 509 return -EINVAL; 510 511 return 0; 512 } 513 514 int host1x_job_pin(struct host1x_job *job, struct device *dev) 515 { 516 int err; 517 unsigned int i, j; 518 struct host1x *host = dev_get_drvdata(dev->parent); 519 520 /* pin memory */ 521 err = pin_job(host, job); 522 if (err) 523 goto out; 524 525 if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) { 526 err = copy_gathers(job, dev); 527 if (err) 528 goto out; 529 } 530 531 /* patch gathers */ 532 for (i = 0; i < job->num_gathers; i++) { 533 struct host1x_job_gather *g = &job->gathers[i]; 534 535 /* process each gather mem only once */ 536 if (g->handled) 537 continue; 538 539 /* copy_gathers() sets gathers base if firewall is enabled */ 540 if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) 541 g->base = job->gather_addr_phys[i]; 542 543 for (j = i + 1; j < job->num_gathers; j++) { 544 if (job->gathers[j].bo == g->bo) { 545 job->gathers[j].handled = true; 546 job->gathers[j].base = g->base; 547 } 548 } 549 550 err = do_relocs(job, g); 551 if (err) 552 break; 553 } 554 555 out: 556 if (err) 557 host1x_job_unpin(job); 558 wmb(); 559 560 return err; 561 } 562 EXPORT_SYMBOL(host1x_job_pin); 563 564 void host1x_job_unpin(struct host1x_job *job) 565 { 566 struct host1x *host = dev_get_drvdata(job->channel->dev->parent); 567 unsigned int i; 568 569 for (i = 0; i < job->num_unpins; i++) { 570 struct host1x_job_unpin_data *unpin = &job->unpins[i]; 571 572 if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) { 573 iommu_unmap(host->domain, job->addr_phys[i], 574 unpin->size); 575 free_iova(&host->iova, 576 iova_pfn(&host->iova, job->addr_phys[i])); 577 } 578 579 host1x_bo_unpin(unpin->bo, unpin->sgt); 580 host1x_bo_put(unpin->bo); 581 } 582 583 job->num_unpins = 0; 584 585 if (job->gather_copy_size) 586 dma_free_wc(job->channel->dev, job->gather_copy_size, 587 job->gather_copy_mapped, job->gather_copy); 588 } 589 EXPORT_SYMBOL(host1x_job_unpin); 590 591 /* 592 * Debug routine used to dump job entries 593 */ 594 void host1x_job_dump(struct device *dev, struct host1x_job *job) 595 { 596 dev_dbg(dev, " SYNCPT_ID %d\n", job->syncpt_id); 597 dev_dbg(dev, " SYNCPT_VAL %d\n", job->syncpt_end); 598 dev_dbg(dev, " FIRST_GET 0x%x\n", job->first_get); 599 dev_dbg(dev, " TIMEOUT %d\n", job->timeout); 600 dev_dbg(dev, " NUM_SLOTS %d\n", job->num_slots); 601 dev_dbg(dev, " NUM_HANDLES %d\n", job->num_unpins); 602 } 603