Skip to content

Commit dcf43a4

Browse files
committed
iommu: io-pgtable: Add 4-level page table support
DARTs on t602x SoCs are of the t8110 variant but have an IAS of 42, which means optional support for an extra page table level. Refactor the PTE management to support an arbitrary level count, and then calculate how many levels we need for any given configuration. Signed-off-by: Hector Martin <[email protected]>
1 parent e8284ec commit dcf43a4

2 files changed

Lines changed: 91 additions & 60 deletions

File tree

drivers/iommu/io-pgtable-dart.c

Lines changed: 90 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030

3131
#define DART1_MAX_ADDR_BITS 36
3232

33-
#define DART_MAX_TABLES 4
34-
#define DART_LEVELS 2
33+
#define DART_MAX_TABLE_BITS 2
34+
#define DART_MAX_TABLES BIT(DART_MAX_TABLE_BITS)
35+
#define DART_MAX_LEVELS 4 /* Includes TTBR level */
3536

3637
/* Struct accessors */
3738
#define io_pgtable_to_data(x) \
@@ -71,6 +72,7 @@
7172
struct dart_io_pgtable {
7273
struct io_pgtable iop;
7374

75+
int levels;
7476
int tbl_bits;
7577
int bits_per_level;
7678

@@ -173,44 +175,45 @@ static dart_iopte dart_install_table(dart_iopte *table,
173175
return old;
174176
}
175177

176-
static int dart_get_table(struct dart_io_pgtable *data, unsigned long iova)
178+
static int dart_get_index(struct dart_io_pgtable *data, unsigned long iova, int level)
177179
{
178-
return (iova >> (3 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
179-
((1 << data->tbl_bits) - 1);
180+
return (iova >> (level * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
181+
((1 << data->bits_per_level) - 1);
180182
}
181183

182-
static int dart_get_l1_index(struct dart_io_pgtable *data, unsigned long iova)
183-
{
184-
185-
return (iova >> (2 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
186-
((1 << data->bits_per_level) - 1);
187-
}
188-
189-
static int dart_get_l2_index(struct dart_io_pgtable *data, unsigned long iova)
184+
static int dart_get_last_index(struct dart_io_pgtable *data, unsigned long iova)
190185
{
191186

192187
return (iova >> (data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
193188
((1 << data->bits_per_level) - 1);
194189
}
195190

196-
static dart_iopte *dart_get_l2(struct dart_io_pgtable *data, unsigned long iova)
191+
static dart_iopte *dart_get_last(struct dart_io_pgtable *data, unsigned long iova)
197192
{
198193
dart_iopte pte, *ptep;
199-
int tbl = dart_get_table(data, iova);
194+
int level = data->levels;
195+
int tbl = dart_get_index(data, iova, level);
196+
197+
if (tbl > (1 << data->tbl_bits))
198+
return NULL;
200199

201200
ptep = data->pgd[tbl];
202201
if (!ptep)
203202
return NULL;
204203

205-
ptep += dart_get_l1_index(data, iova);
206-
pte = READ_ONCE(*ptep);
204+
while (--level > 1) {
205+
ptep += dart_get_index(data, iova, level);
206+
pte = READ_ONCE(*ptep);
207207

208-
/* Valid entry? */
209-
if (!pte)
210-
return NULL;
208+
/* Valid entry? */
209+
if (!pte)
210+
return NULL;
211+
212+
/* Deref to get next level table */
213+
ptep = iopte_deref(pte, data);
214+
}
211215

212-
/* Deref to get level 2 table */
213-
return iopte_deref(pte, data);
216+
return ptep;
214217
}
215218

216219
static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data,
@@ -246,6 +249,7 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
246249
int ret = 0, tbl, num_entries, max_entries, map_idx_start;
247250
dart_iopte pte, *cptep, *ptep;
248251
dart_iopte prot;
252+
int level = data->levels;
249253

250254
if (WARN_ON(pgsize != cfg->pgsize_bitmap))
251255
return -EINVAL;
@@ -257,31 +261,36 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
257261
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
258262
return 0;
259263

260-
tbl = dart_get_table(data, iova);
264+
tbl = dart_get_index(data, iova, level);
265+
266+
if (tbl > (1 << data->tbl_bits))
267+
return -ENOMEM;
261268

262269
ptep = data->pgd[tbl];
263-
ptep += dart_get_l1_index(data, iova);
264-
pte = READ_ONCE(*ptep);
270+
while (--level > 1) {
271+
ptep += dart_get_index(data, iova, level);
272+
pte = READ_ONCE(*ptep);
265273

266-
/* no L2 table present */
267-
if (!pte) {
268-
cptep = __dart_alloc_pages(tblsz, gfp);
269-
if (!cptep)
270-
return -ENOMEM;
274+
/* no table present */
275+
if (!pte) {
276+
cptep = __dart_alloc_pages(tblsz, gfp);
277+
if (!cptep)
278+
return -ENOMEM;
271279

272-
pte = dart_install_table(cptep, ptep, 0, data);
273-
if (pte)
274-
free_pages((unsigned long)cptep, get_order(tblsz));
280+
pte = dart_install_table(cptep, ptep, 0, data);
281+
if (pte)
282+
free_pages((unsigned long)cptep, get_order(tblsz));
275283

276-
/* L2 table is present (now) */
277-
pte = READ_ONCE(*ptep);
278-
}
284+
/* L2 table is present (now) */
285+
pte = READ_ONCE(*ptep);
286+
}
279287

280-
ptep = iopte_deref(pte, data);
288+
ptep = iopte_deref(pte, data);
289+
}
281290

282291
/* install a leaf entries into L2 table */
283292
prot = dart_prot_to_pte(data, iommu_prot);
284-
map_idx_start = dart_get_l2_index(data, iova);
293+
map_idx_start = dart_get_last_index(data, iova);
285294
max_entries = DART_PTES_PER_TABLE(data) - map_idx_start;
286295
num_entries = min_t(int, pgcount, max_entries);
287296
ptep += map_idx_start;
@@ -310,13 +319,13 @@ static size_t dart_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova,
310319
if (WARN_ON(pgsize != cfg->pgsize_bitmap || !pgcount))
311320
return 0;
312321

313-
ptep = dart_get_l2(data, iova);
322+
ptep = dart_get_last(data, iova);
314323

315324
/* Valid L2 IOPTE pointer? */
316325
if (WARN_ON(!ptep))
317326
return 0;
318327

319-
unmap_idx_start = dart_get_l2_index(data, iova);
328+
unmap_idx_start = dart_get_last_index(data, iova);
320329
ptep += unmap_idx_start;
321330

322331
max_entries = DART_PTES_PER_TABLE(data) - unmap_idx_start;
@@ -347,13 +356,13 @@ static phys_addr_t dart_iova_to_phys(struct io_pgtable_ops *ops,
347356
struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops);
348357
dart_iopte pte, *ptep;
349358

350-
ptep = dart_get_l2(data, iova);
359+
ptep = dart_get_last(data, iova);
351360

352361
/* Valid L2 IOPTE pointer? */
353362
if (!ptep)
354363
return 0;
355364

356-
ptep += dart_get_l2_index(data, iova);
365+
ptep += dart_get_last_index(data, iova);
357366

358367
pte = READ_ONCE(*ptep);
359368
/* Found translation */
@@ -396,21 +405,37 @@ static struct dart_io_pgtable *
396405
dart_alloc_pgtable(struct io_pgtable_cfg *cfg)
397406
{
398407
struct dart_io_pgtable *data;
399-
int tbl_bits, bits_per_level, va_bits, pg_shift;
408+
int levels, max_tbl_bits, tbl_bits, bits_per_level, va_bits, pg_shift;
409+
410+
/*
411+
* Old 4K page DARTs can use up to 4 top-level tables.
412+
* Newer ones only ever use a maximum of 1.
413+
*/
414+
if (cfg->pgsize_bitmap == SZ_4K)
415+
max_tbl_bits = DART_MAX_TABLE_BITS;
416+
else
417+
max_tbl_bits = 0;
400418

401419
pg_shift = __ffs(cfg->pgsize_bitmap);
402420
bits_per_level = pg_shift - ilog2(sizeof(dart_iopte));
403421

404422
va_bits = cfg->ias - pg_shift;
405423

406-
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * DART_LEVELS));
407-
if ((1 << tbl_bits) > DART_MAX_TABLES)
424+
levels = max_t(int, 2, (va_bits - max_tbl_bits + bits_per_level - 1) / bits_per_level);
425+
426+
if (levels > (DART_MAX_LEVELS - 1))
427+
return NULL;
428+
429+
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * levels));
430+
431+
if (tbl_bits > max_tbl_bits)
408432
return NULL;
409433

410434
data = kzalloc(sizeof(*data), GFP_KERNEL);
411435
if (!data)
412436
return NULL;
413437

438+
data->levels = levels + 1; /* Table level counts as one level */
414439
data->tbl_bits = tbl_bits;
415440
data->bits_per_level = bits_per_level;
416441

@@ -446,6 +471,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
446471
return NULL;
447472

448473
cfg->apple_dart_cfg.n_ttbrs = 1 << data->tbl_bits;
474+
cfg->apple_dart_cfg.n_levels = data->levels;
449475

450476
/* Locked DARTs can not modify the TTBR registers. Allocate first a shadow
451477
* page table so locked DARTs (disp0, dcp, dcpext*) can map their reserved
@@ -481,11 +507,28 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
481507
return NULL;
482508
}
483509

510+
static void apple_dart_free_pgtables(struct dart_io_pgtable *data, dart_iopte *ptep, int level)
511+
{
512+
dart_iopte *end;
513+
514+
if (level > 1) {
515+
end = (void *)ptep + DART_GRANULE(data);
516+
517+
while (ptep != end) {
518+
dart_iopte pte = *ptep++;
519+
520+
if (pte)
521+
apple_dart_free_pgtables(data, iopte_deref(pte, data), level - 1);
522+
}
523+
}
524+
free_pages((unsigned long)ptep, get_order(DART_GRANULE(data)));
525+
}
526+
484527
static void apple_dart_free_pgtable(struct io_pgtable *iop)
485528
{
486529
struct io_pgtable_cfg *cfg = &iop->cfg;
487530
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
488-
dart_iopte *ptep, *end;
531+
dart_iopte *ptep;
489532
int i;
490533

491534
if (cfg->quirks & IO_PGTABLE_QUIRK_APPLE_LOCKED) {
@@ -495,20 +538,7 @@ static void apple_dart_free_pgtable(struct io_pgtable *iop)
495538

496539
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
497540
ptep = data->pgd[i];
498-
end = (void *)ptep + DART_GRANULE(data);
499-
500-
while (ptep != end) {
501-
dart_iopte pte = *ptep++;
502-
503-
if (pte) {
504-
unsigned long page =
505-
(unsigned long)iopte_deref(pte, data);
506-
507-
free_pages(page, get_order(DART_GRANULE(data)));
508-
}
509-
}
510-
free_pages((unsigned long)data->pgd[i],
511-
get_order(DART_GRANULE(data)));
541+
apple_dart_free_pgtables(data, data->pgd[i], data->levels - 1);
512542
}
513543

514544
kfree(data);

include/linux/io-pgtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ struct io_pgtable_cfg {
147147
struct {
148148
u64 ttbr[4];
149149
u32 n_ttbrs;
150+
u32 n_levels;
150151
} apple_dart_cfg;
151152
};
152153
};

0 commit comments

Comments
 (0)