Skip to content

Commit 5624289

Browse files
marcanjannau
authored andcommitted
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 <marcan@marcan.st>
1 parent 8e7f20b commit 5624289

2 files changed

Lines changed: 88 additions & 53 deletions

File tree

drivers/iommu/io-pgtable-dart.c

Lines changed: 87 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@
2727

2828
#define DART1_MAX_ADDR_BITS 36
2929

30-
#define DART_MAX_TABLES 4
31-
#define DART_LEVELS 2
30+
#define DART_MAX_TABLE_BITS 2
31+
#define DART_MAX_TABLES BIT(DART_MAX_TABLE_BITS)
32+
#define DART_MAX_LEVELS 4 /* Includes TTBR level */
3233

3334
/* Struct accessors */
3435
#define io_pgtable_to_data(x) \
@@ -68,6 +69,7 @@
6869
struct dart_io_pgtable {
6970
struct io_pgtable iop;
7071

72+
int levels;
7173
int tbl_bits;
7274
int bits_per_level;
7375

@@ -165,44 +167,45 @@ static dart_iopte dart_install_table(dart_iopte *table,
165167
return old;
166168
}
167169

168-
static int dart_get_table(struct dart_io_pgtable *data, unsigned long iova)
170+
static int dart_get_index(struct dart_io_pgtable *data, unsigned long iova, int level)
169171
{
170-
return (iova >> (3 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
171-
((1 << data->tbl_bits) - 1);
172+
return (iova >> (level * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
173+
((1 << data->bits_per_level) - 1);
172174
}
173175

174-
static int dart_get_l1_index(struct dart_io_pgtable *data, unsigned long iova)
175-
{
176-
177-
return (iova >> (2 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
178-
((1 << data->bits_per_level) - 1);
179-
}
180-
181-
static int dart_get_l2_index(struct dart_io_pgtable *data, unsigned long iova)
176+
static int dart_get_last_index(struct dart_io_pgtable *data, unsigned long iova)
182177
{
183178

184179
return (iova >> (data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
185180
((1 << data->bits_per_level) - 1);
186181
}
187182

188-
static dart_iopte *dart_get_l2(struct dart_io_pgtable *data, unsigned long iova)
183+
static dart_iopte *dart_get_last(struct dart_io_pgtable *data, unsigned long iova)
189184
{
190185
dart_iopte pte, *ptep;
191-
int tbl = dart_get_table(data, iova);
186+
int level = data->levels;
187+
int tbl = dart_get_index(data, iova, level);
188+
189+
if (tbl > (1 << data->tbl_bits))
190+
return NULL;
192191

193192
ptep = data->pgd[tbl];
194193
if (!ptep)
195194
return NULL;
196195

197-
ptep += dart_get_l1_index(data, iova);
198-
pte = READ_ONCE(*ptep);
196+
while (--level > 1) {
197+
ptep += dart_get_index(data, iova, level);
198+
pte = READ_ONCE(*ptep);
199199

200-
/* Valid entry? */
201-
if (!pte)
202-
return NULL;
200+
/* Valid entry? */
201+
if (!pte)
202+
return NULL;
203203

204-
/* Deref to get level 2 table */
205-
return iopte_deref(pte, data);
204+
/* Deref to get next level table */
205+
ptep = iopte_deref(pte, data);
206+
}
207+
208+
return ptep;
206209
}
207210

208211
static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data,
@@ -238,6 +241,7 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
238241
int ret = 0, tbl, num_entries, max_entries, map_idx_start;
239242
dart_iopte pte, *cptep, *ptep;
240243
dart_iopte prot;
244+
int level = data->levels;
241245

242246
if (WARN_ON(pgsize != cfg->pgsize_bitmap))
243247
return -EINVAL;
@@ -249,31 +253,36 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
249253
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
250254
return 0;
251255

252-
tbl = dart_get_table(data, iova);
256+
tbl = dart_get_index(data, iova, level);
257+
258+
if (tbl > (1 << data->tbl_bits))
259+
return -ENOMEM;
253260

254261
ptep = data->pgd[tbl];
255-
ptep += dart_get_l1_index(data, iova);
256-
pte = READ_ONCE(*ptep);
262+
while (--level > 1) {
263+
ptep += dart_get_index(data, iova, level);
264+
pte = READ_ONCE(*ptep);
257265

258-
/* no L2 table present */
259-
if (!pte) {
260-
cptep = __dart_alloc_pages(tblsz, gfp);
261-
if (!cptep)
262-
return -ENOMEM;
266+
/* no table present */
267+
if (!pte) {
268+
cptep = __dart_alloc_pages(tblsz, gfp);
269+
if (!cptep)
270+
return -ENOMEM;
263271

264-
pte = dart_install_table(cptep, ptep, 0, data);
265-
if (pte)
266-
iommu_free_pages(cptep, get_order(tblsz));
272+
pte = dart_install_table(cptep, ptep, 0, data);
273+
if (pte)
274+
iommu_free_pages(cptep, get_order(tblsz));
267275

268-
/* L2 table is present (now) */
269-
pte = READ_ONCE(*ptep);
270-
}
276+
/* L2 table is present (now) */
277+
pte = READ_ONCE(*ptep);
278+
}
271279

272-
ptep = iopte_deref(pte, data);
280+
ptep = iopte_deref(pte, data);
281+
}
273282

274283
/* install a leaf entries into L2 table */
275284
prot = dart_prot_to_pte(data, iommu_prot);
276-
map_idx_start = dart_get_l2_index(data, iova);
285+
map_idx_start = dart_get_last_index(data, iova);
277286
max_entries = DART_PTES_PER_TABLE(data) - map_idx_start;
278287
num_entries = min_t(int, pgcount, max_entries);
279288
ptep += map_idx_start;
@@ -302,13 +311,13 @@ static size_t dart_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova,
302311
if (WARN_ON(pgsize != cfg->pgsize_bitmap || !pgcount))
303312
return 0;
304313

305-
ptep = dart_get_l2(data, iova);
314+
ptep = dart_get_last(data, iova);
306315

307316
/* Valid L2 IOPTE pointer? */
308317
if (WARN_ON(!ptep))
309318
return 0;
310319

311-
unmap_idx_start = dart_get_l2_index(data, iova);
320+
unmap_idx_start = dart_get_last_index(data, iova);
312321
ptep += unmap_idx_start;
313322

314323
max_entries = DART_PTES_PER_TABLE(data) - unmap_idx_start;
@@ -339,13 +348,13 @@ static phys_addr_t dart_iova_to_phys(struct io_pgtable_ops *ops,
339348
struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops);
340349
dart_iopte pte, *ptep;
341350

342-
ptep = dart_get_l2(data, iova);
351+
ptep = dart_get_last(data, iova);
343352

344353
/* Valid L2 IOPTE pointer? */
345354
if (!ptep)
346355
return 0;
347356

348-
ptep += dart_get_l2_index(data, iova);
357+
ptep += dart_get_last_index(data, iova);
349358

350359
pte = READ_ONCE(*ptep);
351360
/* Found translation */
@@ -362,21 +371,37 @@ static struct dart_io_pgtable *
362371
dart_alloc_pgtable(struct io_pgtable_cfg *cfg)
363372
{
364373
struct dart_io_pgtable *data;
365-
int tbl_bits, bits_per_level, va_bits, pg_shift;
374+
int levels, max_tbl_bits, tbl_bits, bits_per_level, va_bits, pg_shift;
375+
376+
/*
377+
* Old 4K page DARTs can use up to 4 top-level tables.
378+
* Newer ones only ever use a maximum of 1.
379+
*/
380+
if (cfg->pgsize_bitmap == SZ_4K)
381+
max_tbl_bits = DART_MAX_TABLE_BITS;
382+
else
383+
max_tbl_bits = 0;
366384

367385
pg_shift = __ffs(cfg->pgsize_bitmap);
368386
bits_per_level = pg_shift - ilog2(sizeof(dart_iopte));
369387

370388
va_bits = cfg->ias - pg_shift;
371389

372-
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * DART_LEVELS));
373-
if ((1 << tbl_bits) > DART_MAX_TABLES)
390+
levels = max_t(int, 2, (va_bits - max_tbl_bits + bits_per_level - 1) / bits_per_level);
391+
392+
if (levels > (DART_MAX_LEVELS - 1))
393+
return NULL;
394+
395+
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * levels));
396+
397+
if (tbl_bits > max_tbl_bits)
374398
return NULL;
375399

376400
data = kzalloc(sizeof(*data), GFP_KERNEL);
377401
if (!data)
378402
return NULL;
379403

404+
data->levels = levels + 1; /* Table level counts as one level */
380405
data->tbl_bits = tbl_bits;
381406
data->bits_per_level = bits_per_level;
382407

@@ -412,6 +437,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
412437
return NULL;
413438

414439
cfg->apple_dart_cfg.n_ttbrs = 1 << data->tbl_bits;
440+
cfg->apple_dart_cfg.n_levels = data->levels;
415441

416442
for (i = 0; i < cfg->apple_dart_cfg.n_ttbrs; ++i) {
417443
data->pgd[i] = __dart_alloc_pages(DART_GRANULE(data), GFP_KERNEL);
@@ -431,24 +457,32 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
431457
return NULL;
432458
}
433459

434-
static void apple_dart_free_pgtable(struct io_pgtable *iop)
460+
static void apple_dart_free_pgtables(struct dart_io_pgtable *data, dart_iopte *ptep, int level)
435461
{
436-
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
462+
dart_iopte *end;
463+
dart_iopte *start = ptep;
437464
int order = get_order(DART_GRANULE(data));
438-
dart_iopte *ptep, *end;
439-
int i;
440465

441-
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
442-
ptep = data->pgd[i];
466+
if (level > 1) {
443467
end = (void *)ptep + DART_GRANULE(data);
444468

445469
while (ptep != end) {
446470
dart_iopte pte = *ptep++;
447471

448472
if (pte)
449-
iommu_free_pages(iopte_deref(pte, data), order);
473+
apple_dart_free_pgtables(data, iopte_deref(pte, data), level - 1);
450474
}
451-
iommu_free_pages(data->pgd[i], order);
475+
}
476+
iommu_free_pages(start, order);
477+
}
478+
479+
static void apple_dart_free_pgtable(struct io_pgtable *iop)
480+
{
481+
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
482+
int i;
483+
484+
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
485+
apple_dart_free_pgtables(data, data->pgd[i], data->levels - 1);
452486
}
453487

454488
kfree(data);

include/linux/io-pgtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ struct io_pgtable_cfg {
167167
struct {
168168
u64 ttbr[4];
169169
u32 n_ttbrs;
170+
u32 n_levels;
170171
} apple_dart_cfg;
171172
};
172173
};

0 commit comments

Comments
 (0)