Skip to content

Commit 891eae8

Browse files
alyssarosenzweigmarcan
authored andcommitted
iommu: io-pgtable: Add locked DART quirk
Apple DARTs can be locked by the bootloader. In particular, we cannot change the TTBR address for these DARTs. However, we may take over the existing allocated page. We clear the existing page table. Important mappings will be restored by reserved regions. Add a quirk for this case and handle it. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Co-developed-by: Janne Grunau <j@jannau.net> Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 1d060f8 commit 891eae8

3 files changed

Lines changed: 56 additions & 2 deletions

File tree

drivers/iommu/apple-dart.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,29 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
596596
.iommu_dev = dart->dev,
597597
};
598598

599+
if (dart->locked) {
600+
unsigned long *sidmap;
601+
int sid;
602+
phys_addr_t phys;
603+
u32 ttbr;
604+
605+
/* Locked DARTs can only have a single stream bound */
606+
sidmap = cfg->stream_maps[0].sidmap;
607+
sid = find_first_bit(sidmap, dart->num_streams);
608+
609+
WARN_ON((sid < 0) || bitmap_weight(sidmap, dart->num_streams) > 1);
610+
ttbr = readl(dart->regs + DART_TTBR(dart, sid, 0));
611+
612+
WARN_ON(!(ttbr & dart->hw->ttbr_valid));
613+
ttbr &= ~dart->hw->ttbr_valid;
614+
if (dart->hw->ttbr_addr_field_shift)
615+
ttbr >>= dart->hw->ttbr_addr_field_shift;
616+
617+
phys = ((phys_addr_t) ttbr) << dart->hw->ttbr_shift;
618+
pgtbl_cfg.apple_dart_cfg.ttbr[0] = phys;
619+
pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_APPLE_LOCKED;
620+
}
621+
599622
dart_domain->pgtbl_ops =
600623
alloc_io_pgtable_ops(dart->hw->fmt, &pgtbl_cfg, domain);
601624
if (!dart_domain->pgtbl_ops) {

drivers/iommu/io-pgtable-dart.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/atomic.h>
1717
#include <linux/bitfield.h>
1818
#include <linux/bitops.h>
19+
#include <linux/io.h>
1920
#include <linux/io-pgtable.h>
2021
#include <linux/kernel.h>
2122
#include <linux/sizes.h>
@@ -417,29 +418,55 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
417418

418419
cfg->apple_dart_cfg.n_ttbrs = 1 << data->tbl_bits;
419420

421+
/* Locked DARTs can not modify the TTBR registers. The known locked
422+
* DARTs (dcp, dcpext0) use just a single TTBR so we do not have to
423+
* worry whether the pages are consecutive.
424+
*/
425+
if (cfg->quirks & IO_PGTABLE_QUIRK_APPLE_LOCKED) {
426+
size_t size = cfg->pgsize_bitmap;
427+
if (cfg->apple_dart_cfg.n_ttbrs > 1)
428+
goto out_free_data;
429+
430+
data->pgd[0] = devm_memremap(cfg->iommu_dev,
431+
cfg->apple_dart_cfg.ttbr[0],
432+
size, MEMREMAP_WB);
433+
if (!data->pgd[0])
434+
goto out_free_data;
435+
/* start with an empty table */
436+
memset(data->pgd[0], 0, size);
437+
return &data->iop;
438+
}
439+
420440
for (i = 0; i < cfg->apple_dart_cfg.n_ttbrs; ++i) {
421441
data->pgd[i] = __dart_alloc_pages(DART_GRANULE(data), GFP_KERNEL);
422442
if (!data->pgd[i])
423-
goto out_free_data;
443+
goto out_free_pages;
424444
cfg->apple_dart_cfg.ttbr[i] = virt_to_phys(data->pgd[i]);
425445
}
426446

427447
return &data->iop;
428448

429-
out_free_data:
449+
out_free_pages:
430450
while (--i >= 0)
431451
free_pages((unsigned long)data->pgd[i],
432452
get_order(DART_GRANULE(data)));
453+
out_free_data:
433454
kfree(data);
434455
return NULL;
435456
}
436457

437458
static void apple_dart_free_pgtable(struct io_pgtable *iop)
438459
{
460+
struct io_pgtable_cfg *cfg = &iop->cfg;
439461
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
440462
dart_iopte *ptep, *end;
441463
int i;
442464

465+
if (cfg->quirks & IO_PGTABLE_QUIRK_APPLE_LOCKED) {
466+
kfree(data);
467+
return;
468+
}
469+
443470
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
444471
ptep = data->pgd[i];
445472
end = (void *)ptep + DART_GRANULE(data);

include/linux/io-pgtable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,17 @@ struct io_pgtable_cfg {
8585
*
8686
* IO_PGTABLE_QUIRK_ARM_OUTER_WBWA: Override the outer-cacheability
8787
* attributes set in the TCR for a non-coherent page-table walker.
88+
*
89+
* IO_PGTABLE_QUIRK_APPLE_LOCKED: Cannot modify the TTBR pointer, must
90+
* inherit mappings from the bootloader.
8891
*/
8992
#define IO_PGTABLE_QUIRK_ARM_NS BIT(0)
9093
#define IO_PGTABLE_QUIRK_NO_PERMS BIT(1)
9194
#define IO_PGTABLE_QUIRK_ARM_MTK_EXT BIT(3)
9295
#define IO_PGTABLE_QUIRK_ARM_MTK_TTBR_EXT BIT(4)
9396
#define IO_PGTABLE_QUIRK_ARM_TTBR1 BIT(5)
9497
#define IO_PGTABLE_QUIRK_ARM_OUTER_WBWA BIT(6)
98+
#define IO_PGTABLE_QUIRK_APPLE_LOCKED BIT(7)
9599
unsigned long quirks;
96100
unsigned long pgsize_bitmap;
97101
unsigned int ias;

0 commit comments

Comments
 (0)