Now that we can correctly extract top-level indices without relying on the remaining upper bits being zero, the only remaining impediments to using a given table for TTBR1 are the address validation on map/unmap and the awkward TCR translation granule format. Add a quirk so that we can do the right thing at those points.
Unified · Split
| @@ -104,6 +104,10 @@ · 103 unmodified lines | ||
| 104 | 104 | #define ARM_LPAE_TCR_TG0_64K 1 |
| 105 | 105 | #define ARM_LPAE_TCR_TG0_16K 2 |
| 106 | 106 | |
| 107 | +#define ARM_LPAE_TCR_TG1_16K 1 | |
| 108 | +#define ARM_LPAE_TCR_TG1_4K 2 | |
| 109 | +#define ARM_LPAE_TCR_TG1_64K 3 | |
| 110 | + | |
| 107 | 111 | #define ARM_LPAE_TCR_SH_NS 0 |
| 108 | 112 | #define ARM_LPAE_TCR_SH_OS 2 |
| 109 | 113 | #define ARM_LPAE_TCR_SH_IS 3 |
| @@ -464,6 +468,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, · 354 unmodified lines | ||
| 464 | 468 | arm_lpae_iopte *ptep = data->pgd; |
| 465 | 469 | int ret, lvl = data->start_level; |
| 466 | 470 | arm_lpae_iopte prot; |
| 471 | + long iaext = (long)iova >> cfg->ias; | |
| 467 | 472 | |
| 468 | 473 | /* If no access, then nothing to do */ |
| 469 | 474 | if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) |
| @@ -472,7 +477,9 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, · 2 unmodified lines | ||
| 472 | 477 | if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size)) |
| 473 | 478 | return -EINVAL; |
| 474 | 479 | |
| 475 | − if (WARN_ON(iova >> data->iop.cfg.ias || paddr >> data->iop.cfg.oas)) | |
| 480 | + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) | |
| 481 | + iaext = ~iaext; | |
| 482 | + if (WARN_ON(iaext || paddr >> cfg->oas)) | |
| 476 | 483 | return -ERANGE; |
| 477 | 484 | |
| 478 | 485 | prot = arm_lpae_prot_to_pte(data, iommu_prot); |
| @@ -638,11 +645,14 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, · 159 unmodified lines | ||
| 638 | 645 | struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); |
| 639 | 646 | struct io_pgtable_cfg *cfg = &data->iop.cfg; |
| 640 | 647 | arm_lpae_iopte *ptep = data->pgd; |
| 648 | + long iaext = (long)iova >> cfg->ias; | |
| 641 | 649 | |
| 642 | 650 | if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size)) |
| 643 | 651 | return 0; |
| 644 | 652 | |
| 645 | − if (WARN_ON(iova >> data->iop.cfg.ias)) | |
| 653 | + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) | |
| 654 | + iaext = ~iaext; | |
| 655 | + if (WARN_ON(iaext)) | |
| 646 | 656 | return 0; |
| 647 | 657 | |
| 648 | 658 | return __arm_lpae_unmap(data, gather, iova, size, data->start_level, ptep); |
| @@ -778,9 +788,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) · 129 unmodified lines | ||
| 778 | 788 | u64 reg; |
| 779 | 789 | struct arm_lpae_io_pgtable *data; |
| 780 | 790 | typeof(&cfg->arm_lpae_s1_cfg.tcr) tcr = &cfg->arm_lpae_s1_cfg.tcr; |
| 791 | + bool tg1; | |
| 781 | 792 | |
| 782 | 793 | if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | |
| 783 | − IO_PGTABLE_QUIRK_NON_STRICT)) | |
| 794 | + IO_PGTABLE_QUIRK_NON_STRICT | | |
| 795 | + IO_PGTABLE_QUIRK_ARM_TTBR1)) | |
| 784 | 796 | return NULL; |
| 785 | 797 | |
| 786 | 798 | data = arm_lpae_alloc_pgtable(cfg); |
| @@ -798,15 +810,16 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) · 11 unmodified lines | ||
| 798 | 810 | tcr->orgn = ARM_LPAE_TCR_RGN_NC; |
| 799 | 811 | } |
| 800 | 812 | |
| 813 | + tg1 = cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1; | |
| 801 | 814 | switch (ARM_LPAE_GRANULE(data)) { |
| 802 | 815 | case SZ_4K: |
| 803 | − tcr->tg = ARM_LPAE_TCR_TG0_4K; | |
| 816 | + tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_4K : ARM_LPAE_TCR_TG0_4K; | |
| 804 | 817 | break; |
| 805 | 818 | case SZ_16K: |
| 806 | − tcr->tg = ARM_LPAE_TCR_TG0_16K; | |
| 819 | + tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_16K : ARM_LPAE_TCR_TG0_16K; | |
| 807 | 820 | break; |
| 808 | 821 | case SZ_64K: |
| 809 | − tcr->tg = ARM_LPAE_TCR_TG0_64K; | |
| 822 | + tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_64K : ARM_LPAE_TCR_TG0_64K; | |
| 810 | 823 | break; |
| 811 | 824 | } |
| 812 | 825 | |
| @@ -83,12 +83,16 @@ struct io_pgtable_cfg { · 82 unmodified lines | ||
| 83 | 83 | * IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs |
| 84 | 84 | * on unmap, for DMA domains using the flush queue mechanism for |
| 85 | 85 | * delayed invalidation. |
| 86 | + * | |
| 87 | + * IO_PGTABLE_QUIRK_ARM_TTBR1: (ARM LPAE format) Configure the table | |
| 88 | + * for use in the upper half of a split address space. | |
| 86 | 89 | */ |
| 87 | 90 | #define IO_PGTABLE_QUIRK_ARM_NS BIT(0) |
| 88 | 91 | #define IO_PGTABLE_QUIRK_NO_PERMS BIT(1) |
| 89 | 92 | #define IO_PGTABLE_QUIRK_TLBI_ON_MAP BIT(2) |
| 90 | 93 | #define IO_PGTABLE_QUIRK_ARM_MTK_EXT BIT(3) |
| 91 | 94 | #define IO_PGTABLE_QUIRK_NON_STRICT BIT(4) |
| 95 | + #define IO_PGTABLE_QUIRK_ARM_TTBR1 BIT(5) | |
| 92 | 96 | unsigned long quirks; |
| 93 | 97 | unsigned long pgsize_bitmap; |
| 94 | 98 | unsigned int ias; |