Skip to content

Commit 85e1993

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 54de489 commit 85e1993

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;
@@ -248,31 +252,36 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
248252
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
249253
return -EINVAL;
250254

251-
tbl = dart_get_table(data, iova);
255+
tbl = dart_get_index(data, iova, level);
256+
257+
if (tbl > (1 << data->tbl_bits))
258+
return -ENOMEM;
252259

253260
ptep = data->pgd[tbl];
254-
ptep += dart_get_l1_index(data, iova);
255-
pte = READ_ONCE(*ptep);
261+
while (--level > 1) {
262+
ptep += dart_get_index(data, iova, level);
263+
pte = READ_ONCE(*ptep);
256264

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

263-
pte = dart_install_table(cptep, ptep, 0, data);
264-
if (pte)
265-
iommu_free_pages(cptep, get_order(tblsz));
271+
pte = dart_install_table(cptep, ptep, 0, data);
272+
if (pte)
273+
iommu_free_pages(cptep, get_order(tblsz));
266274

267-
/* L2 table is present (now) */
268-
pte = READ_ONCE(*ptep);
269-
}
275+
/* L2 table is present (now) */
276+
pte = READ_ONCE(*ptep);
277+
}
270278

271-
ptep = iopte_deref(pte, data);
279+
ptep = iopte_deref(pte, data);
280+
}
272281

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

304-
ptep = dart_get_l2(data, iova);
313+
ptep = dart_get_last(data, iova);
305314

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

310-
unmap_idx_start = dart_get_l2_index(data, iova);
319+
unmap_idx_start = dart_get_last_index(data, iova);
311320
ptep += unmap_idx_start;
312321

313322
max_entries = DART_PTES_PER_TABLE(data) - unmap_idx_start;
@@ -338,13 +347,13 @@ static phys_addr_t dart_iova_to_phys(struct io_pgtable_ops *ops,
338347
struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops);
339348
dart_iopte pte, *ptep;
340349

341-
ptep = dart_get_l2(data, iova);
350+
ptep = dart_get_last(data, iova);
342351

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

347-
ptep += dart_get_l2_index(data, iova);
356+
ptep += dart_get_last_index(data, iova);
348357

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

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

369387
va_bits = cfg->ias - pg_shift;
370388

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

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

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

@@ -411,6 +436,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
411436
return NULL;
412437

413438
cfg->apple_dart_cfg.n_ttbrs = 1 << data->tbl_bits;
439+
cfg->apple_dart_cfg.n_levels = data->levels;
414440

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

433-
static void apple_dart_free_pgtable(struct io_pgtable *iop)
459+
static void apple_dart_free_pgtables(struct dart_io_pgtable *data, dart_iopte *ptep, int level)
434460
{
435-
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
461+
dart_iopte *end;
462+
dart_iopte *start = ptep;
436463
int order = get_order(DART_GRANULE(data));
437-
dart_iopte *ptep, *end;
438-
int i;
439464

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

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

447471
if (pte)
448-
iommu_free_pages(iopte_deref(pte, data), order);
472+
apple_dart_free_pgtables(data, iopte_deref(pte, data), level - 1);
449473
}
450-
iommu_free_pages(data->pgd[i], order);
474+
}
475+
iommu_free_pages(start, order);
476+
}
477+
478+
static void apple_dart_free_pgtable(struct io_pgtable *iop)
479+
{
480+
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
481+
int i;
482+
483+
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
484+
apple_dart_free_pgtables(data, data->pgd[i], data->levels - 1);
451485
}
452486

453487
kfree(data);

include/linux/io-pgtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ struct io_pgtable_cfg {
170170
struct {
171171
u64 ttbr[4];
172172
u32 n_ttbrs;
173+
u32 n_levels;
173174
} apple_dart_cfg;
174175
};
175176
};

0 commit comments

Comments
 (0)