|
33 | 33 | #include <linux/types.h> |
34 | 34 |
|
35 | 35 | #include "dma-iommu.h" |
| 36 | +#include "io-pgtable-dart.h" |
36 | 37 |
|
37 | 38 | #define DART_MAX_STREAMS 256 |
38 | 39 | #define DART_MAX_TTBR 4 |
@@ -557,17 +558,55 @@ apple_dart_setup_translation(struct apple_dart_domain *domain, |
557 | 558 | struct io_pgtable_cfg *pgtbl_cfg = |
558 | 559 | &io_pgtable_ops_to_pgtable(domain->pgtbl_ops)->cfg; |
559 | 560 |
|
560 | | - for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i) |
561 | | - apple_dart_hw_set_ttbr(stream_map, i, |
562 | | - pgtbl_cfg->apple_dart_cfg.ttbr[i]); |
563 | | - for (; i < stream_map->dart->hw->ttbr_count; ++i) |
564 | | - apple_dart_hw_clear_ttbr(stream_map, i); |
| 561 | + /* Locked DARTs are set up by the bootloader. */ |
| 562 | + if (!stream_map->dart->locked) { |
| 563 | + for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i) |
| 564 | + apple_dart_hw_set_ttbr(stream_map, i, |
| 565 | + pgtbl_cfg->apple_dart_cfg.ttbr[i]); |
| 566 | + for (; i < stream_map->dart->hw->ttbr_count; ++i) |
| 567 | + apple_dart_hw_clear_ttbr(stream_map, i); |
565 | 568 |
|
566 | | - apple_dart_hw_enable_translation(stream_map); |
| 569 | + apple_dart_hw_enable_translation(stream_map); |
| 570 | + } |
567 | 571 | stream_map->dart->hw->invalidate_tlb(stream_map); |
568 | 572 | } |
569 | 573 |
|
| 574 | +static int apple_dart_setup_resv_locked(struct iommu_domain *domain, |
| 575 | + struct device *dev, size_t pgsize) |
| 576 | +{ |
| 577 | + struct iommu_resv_region *region; |
| 578 | + LIST_HEAD(resv_regions); |
| 579 | + int ret = 0; |
| 580 | + |
| 581 | + of_iommu_get_resv_regions(dev, &resv_regions); |
| 582 | + list_for_each_entry(region, &resv_regions, list) { |
| 583 | + size_t mapped = 0; |
| 584 | + |
| 585 | + /* Only map translated reserved regions */ |
| 586 | + if (region->type != IOMMU_RESV_TRANSLATED) |
| 587 | + continue; |
| 588 | + |
| 589 | + while (mapped < region->length) { |
| 590 | + phys_addr_t paddr = region->start + mapped; |
| 591 | + unsigned long iova = region->dva + mapped; |
| 592 | + size_t length = region->length - mapped; |
| 593 | + size_t pgcount = length / pgsize; |
| 594 | + |
| 595 | + ret = apple_dart_map_pages(domain, iova, |
| 596 | + paddr, pgsize, pgcount, |
| 597 | + region->prot, GFP_KERNEL, &mapped); |
| 598 | + |
| 599 | + if (ret) |
| 600 | + goto end_put; |
| 601 | + } |
| 602 | + } |
| 603 | +end_put: |
| 604 | + iommu_put_resv_regions(dev, &resv_regions); |
| 605 | + return ret; |
| 606 | +} |
| 607 | + |
570 | 608 | static int apple_dart_finalize_domain(struct iommu_domain *domain, |
| 609 | + struct device *dev, |
571 | 610 | struct apple_dart_master_cfg *cfg) |
572 | 611 | { |
573 | 612 | struct apple_dart_domain *dart_domain = to_dart_domain(domain); |
@@ -633,6 +672,11 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain, |
633 | 672 |
|
634 | 673 | dart_domain->finalized = true; |
635 | 674 |
|
| 675 | + if (dart->locked) { |
| 676 | + /* TODO: error handling */ |
| 677 | + ret = apple_dart_setup_resv_locked(domain, dev, dart->pgsize); |
| 678 | + io_pgtable_dart_setup_locked(dart_domain->pgtbl_ops); |
| 679 | + } |
636 | 680 | done: |
637 | 681 | mutex_unlock(&dart_domain->init_lock); |
638 | 682 | return ret; |
@@ -689,7 +733,7 @@ static int apple_dart_attach_dev(struct iommu_domain *domain, |
689 | 733 | if (dart0->locked && domain->type != IOMMU_DOMAIN_DMA) |
690 | 734 | return -EINVAL; |
691 | 735 |
|
692 | | - ret = apple_dart_finalize_domain(domain, cfg); |
| 736 | + ret = apple_dart_finalize_domain(domain, dev, cfg); |
693 | 737 | if (ret) |
694 | 738 | return ret; |
695 | 739 |
|
|
0 commit comments