Skip to content

Commit 50080ef

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 7b9aae0 commit 50080ef

2 files changed

Lines changed: 90 additions & 59 deletions

File tree

drivers/iommu/io-pgtable-dart.c

Lines changed: 89 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@
2626

2727
#define DART1_MAX_ADDR_BITS 36
2828

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

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

71+
int levels;
7072
int tbl_bits;
7173
int bits_per_level;
7274

@@ -169,44 +171,45 @@ static dart_iopte dart_install_table(dart_iopte *table,
169171
return old;
170172
}
171173

172-
static int dart_get_table(struct dart_io_pgtable *data, unsigned long iova)
174+
static int dart_get_index(struct dart_io_pgtable *data, unsigned long iova, int level)
173175
{
174-
return (iova >> (3 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
175-
((1 << data->tbl_bits) - 1);
176+
return (iova >> (level * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
177+
((1 << data->bits_per_level) - 1);
176178
}
177179

178-
static int dart_get_l1_index(struct dart_io_pgtable *data, unsigned long iova)
179-
{
180-
181-
return (iova >> (2 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
182-
((1 << data->bits_per_level) - 1);
183-
}
184-
185-
static int dart_get_l2_index(struct dart_io_pgtable *data, unsigned long iova)
180+
static int dart_get_last_index(struct dart_io_pgtable *data, unsigned long iova)
186181
{
187182

188183
return (iova >> (data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
189184
((1 << data->bits_per_level) - 1);
190185
}
191186

192-
static dart_iopte *dart_get_l2(struct dart_io_pgtable *data, unsigned long iova)
187+
static dart_iopte *dart_get_last(struct dart_io_pgtable *data, unsigned long iova)
193188
{
194189
dart_iopte pte, *ptep;
195-
int tbl = dart_get_table(data, iova);
190+
int level = data->levels;
191+
int tbl = dart_get_index(data, iova, level);
192+
193+
if (tbl > (1 << data->tbl_bits))
194+
return NULL;
196195

197196
ptep = data->pgd[tbl];
198197
if (!ptep)
199198
return NULL;
200199

201-
ptep += dart_get_l1_index(data, iova);
202-
pte = READ_ONCE(*ptep);
200+
while (--level > 1) {
201+
ptep += dart_get_index(data, iova, level);
202+
pte = READ_ONCE(*ptep);
203203

204-
/* Valid entry? */
205-
if (!pte)
206-
return NULL;
204+
/* Valid entry? */
205+
if (!pte)
206+
return NULL;
207+
208+
/* Deref to get next level table */
209+
ptep = iopte_deref(pte, data);
210+
}
207211

208-
/* Deref to get level 2 table */
209-
return iopte_deref(pte, data);
212+
return ptep;
210213
}
211214

212215
static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data,
@@ -242,6 +245,7 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
242245
int ret = 0, tbl, num_entries, max_entries, map_idx_start;
243246
dart_iopte pte, *cptep, *ptep;
244247
dart_iopte prot;
248+
int level = data->levels;
245249

246250
if (WARN_ON(pgsize != cfg->pgsize_bitmap))
247251
return -EINVAL;
@@ -253,31 +257,36 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
253257
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
254258
return 0;
255259

256-
tbl = dart_get_table(data, iova);
260+
tbl = dart_get_index(data, iova, level);
261+
262+
if (tbl > (1 << data->tbl_bits))
263+
return -ENOMEM;
257264

258265
ptep = data->pgd[tbl];
259-
ptep += dart_get_l1_index(data, iova);
260-
pte = READ_ONCE(*ptep);
266+
while (--level > 1) {
267+
ptep += dart_get_index(data, iova, level);
268+
pte = READ_ONCE(*ptep);
261269

262-
/* no L2 table present */
263-
if (!pte) {
264-
cptep = __dart_alloc_pages(tblsz, gfp);
265-
if (!cptep)
266-
return -ENOMEM;
270+
/* no table present */
271+
if (!pte) {
272+
cptep = __dart_alloc_pages(tblsz, gfp);
273+
if (!cptep)
274+
return -ENOMEM;
267275

268-
pte = dart_install_table(cptep, ptep, 0, data);
269-
if (pte)
270-
free_pages((unsigned long)cptep, get_order(tblsz));
276+
pte = dart_install_table(cptep, ptep, 0, data);
277+
if (pte)
278+
free_pages((unsigned long)cptep, get_order(tblsz));
271279

272-
/* L2 table is present (now) */
273-
pte = READ_ONCE(*ptep);
274-
}
280+
/* L2 table is present (now) */
281+
pte = READ_ONCE(*ptep);
282+
}
275283

276-
ptep = iopte_deref(pte, data);
284+
ptep = iopte_deref(pte, data);
285+
}
277286

278287
/* install a leaf entries into L2 table */
279288
prot = dart_prot_to_pte(data, iommu_prot);
280-
map_idx_start = dart_get_l2_index(data, iova);
289+
map_idx_start = dart_get_last_index(data, iova);
281290
max_entries = DART_PTES_PER_TABLE(data) - map_idx_start;
282291
num_entries = min_t(int, pgcount, max_entries);
283292
ptep += map_idx_start;
@@ -306,13 +315,13 @@ static size_t dart_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova,
306315
if (WARN_ON(pgsize != cfg->pgsize_bitmap || !pgcount))
307316
return 0;
308317

309-
ptep = dart_get_l2(data, iova);
318+
ptep = dart_get_last(data, iova);
310319

311320
/* Valid L2 IOPTE pointer? */
312321
if (WARN_ON(!ptep))
313322
return 0;
314323

315-
unmap_idx_start = dart_get_l2_index(data, iova);
324+
unmap_idx_start = dart_get_last_index(data, iova);
316325
ptep += unmap_idx_start;
317326

318327
max_entries = DART_PTES_PER_TABLE(data) - unmap_idx_start;
@@ -343,13 +352,13 @@ static phys_addr_t dart_iova_to_phys(struct io_pgtable_ops *ops,
343352
struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops);
344353
dart_iopte pte, *ptep;
345354

346-
ptep = dart_get_l2(data, iova);
355+
ptep = dart_get_last(data, iova);
347356

348357
/* Valid L2 IOPTE pointer? */
349358
if (!ptep)
350359
return 0;
351360

352-
ptep += dart_get_l2_index(data, iova);
361+
ptep += dart_get_last_index(data, iova);
353362

354363
pte = READ_ONCE(*ptep);
355364
/* Found translation */
@@ -366,21 +375,37 @@ static struct dart_io_pgtable *
366375
dart_alloc_pgtable(struct io_pgtable_cfg *cfg)
367376
{
368377
struct dart_io_pgtable *data;
369-
int tbl_bits, bits_per_level, va_bits, pg_shift;
378+
int levels, max_tbl_bits, tbl_bits, bits_per_level, va_bits, pg_shift;
379+
380+
/*
381+
* Old 4K page DARTs can use up to 4 top-level tables.
382+
* Newer ones only ever use a maximum of 1.
383+
*/
384+
if (cfg->pgsize_bitmap == SZ_4K)
385+
max_tbl_bits = DART_MAX_TABLE_BITS;
386+
else
387+
max_tbl_bits = 0;
370388

371389
pg_shift = __ffs(cfg->pgsize_bitmap);
372390
bits_per_level = pg_shift - ilog2(sizeof(dart_iopte));
373391

374392
va_bits = cfg->ias - pg_shift;
375393

376-
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * DART_LEVELS));
377-
if ((1 << tbl_bits) > DART_MAX_TABLES)
394+
levels = max_t(int, 2, (va_bits - max_tbl_bits + bits_per_level - 1) / bits_per_level);
395+
396+
if (levels > (DART_MAX_LEVELS - 1))
397+
return NULL;
398+
399+
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * levels));
400+
401+
if (tbl_bits > max_tbl_bits)
378402
return NULL;
379403

380404
data = kzalloc(sizeof(*data), GFP_KERNEL);
381405
if (!data)
382406
return NULL;
383407

408+
data->levels = levels + 1; /* Table level counts as one level */
384409
data->tbl_bits = tbl_bits;
385410
data->bits_per_level = bits_per_level;
386411

@@ -416,6 +441,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
416441
return NULL;
417442

418443
cfg->apple_dart_cfg.n_ttbrs = 1 << data->tbl_bits;
444+
cfg->apple_dart_cfg.n_levels = data->levels;
419445

420446
for (i = 0; i < cfg->apple_dart_cfg.n_ttbrs; ++i) {
421447
data->pgd[i] = __dart_alloc_pages(DART_GRANULE(data), GFP_KERNEL);
@@ -434,28 +460,32 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
434460
return NULL;
435461
}
436462

437-
static void apple_dart_free_pgtable(struct io_pgtable *iop)
463+
static void apple_dart_free_pgtables(struct dart_io_pgtable *data, dart_iopte *ptep, int level)
438464
{
439-
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
440-
dart_iopte *ptep, *end;
441-
int i;
465+
dart_iopte *end;
442466

443-
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
444-
ptep = data->pgd[i];
467+
if (level > 1) {
445468
end = (void *)ptep + DART_GRANULE(data);
446469

447470
while (ptep != end) {
448471
dart_iopte pte = *ptep++;
449472

450-
if (pte) {
451-
unsigned long page =
452-
(unsigned long)iopte_deref(pte, data);
453-
454-
free_pages(page, get_order(DART_GRANULE(data)));
455-
}
473+
if (pte)
474+
apple_dart_free_pgtables(data, iopte_deref(pte, data), level - 1);
456475
}
457-
free_pages((unsigned long)data->pgd[i],
458-
get_order(DART_GRANULE(data)));
476+
}
477+
free_pages((unsigned long)ptep, get_order(DART_GRANULE(data)));
478+
}
479+
480+
static void apple_dart_free_pgtable(struct io_pgtable *iop)
481+
{
482+
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
483+
dart_iopte *ptep;
484+
int i;
485+
486+
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
487+
ptep = data->pgd[i];
488+
apple_dart_free_pgtables(data, data->pgd[i], data->levels - 1);
459489
}
460490

461491
kfree(data);

include/linux/io-pgtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ struct io_pgtable_cfg {
143143
struct {
144144
u64 ttbr[4];
145145
u32 n_ttbrs;
146+
u32 n_levels;
146147
} apple_dart_cfg;
147148
};
148149
};

0 commit comments

Comments
 (0)