Skip to content

Commit 74a0e72

Browse files
marcanjoergroedel
authored andcommitted
iommu/io-pgtable-dart: 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]> Signed-off-by: Janne Grunau <[email protected]> Reviewed-by: Sven Peter <[email protected]> Reviewed-by: Neal Gompa <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 1268890 commit 74a0e72

2 files changed

Lines changed: 87 additions & 53 deletions

File tree

drivers/iommu/io-pgtable-dart.c

Lines changed: 86 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

@@ -156,44 +158,45 @@ static dart_iopte dart_install_table(dart_iopte *table,
156158
return old;
157159
}
158160

159-
static int dart_get_table(struct dart_io_pgtable *data, unsigned long iova)
161+
static int dart_get_index(struct dart_io_pgtable *data, unsigned long iova, int level)
160162
{
161-
return (iova >> (3 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
162-
((1 << data->tbl_bits) - 1);
163+
return (iova >> (level * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
164+
((1 << data->bits_per_level) - 1);
163165
}
164166

165-
static int dart_get_l1_index(struct dart_io_pgtable *data, unsigned long iova)
166-
{
167-
168-
return (iova >> (2 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
169-
((1 << data->bits_per_level) - 1);
170-
}
171-
172-
static int dart_get_l2_index(struct dart_io_pgtable *data, unsigned long iova)
167+
static int dart_get_last_index(struct dart_io_pgtable *data, unsigned long iova)
173168
{
174169

175170
return (iova >> (data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
176171
((1 << data->bits_per_level) - 1);
177172
}
178173

179-
static dart_iopte *dart_get_l2(struct dart_io_pgtable *data, unsigned long iova)
174+
static dart_iopte *dart_get_last(struct dart_io_pgtable *data, unsigned long iova)
180175
{
181176
dart_iopte pte, *ptep;
182-
int tbl = dart_get_table(data, iova);
177+
int level = data->levels;
178+
int tbl = dart_get_index(data, iova, level);
179+
180+
if (tbl > (1 << data->tbl_bits))
181+
return NULL;
183182

184183
ptep = data->pgd[tbl];
185184
if (!ptep)
186185
return NULL;
187186

188-
ptep += dart_get_l1_index(data, iova);
189-
pte = READ_ONCE(*ptep);
187+
while (--level > 1) {
188+
ptep += dart_get_index(data, iova, level);
189+
pte = READ_ONCE(*ptep);
190190

191-
/* Valid entry? */
192-
if (!pte)
193-
return NULL;
191+
/* Valid entry? */
192+
if (!pte)
193+
return NULL;
194194

195-
/* Deref to get level 2 table */
196-
return iopte_deref(pte, data);
195+
/* Deref to get next level table */
196+
ptep = iopte_deref(pte, data);
197+
}
198+
199+
return ptep;
197200
}
198201

199202
static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data,
@@ -230,6 +233,7 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
230233
int ret = 0, tbl, num_entries, max_entries, map_idx_start;
231234
dart_iopte pte, *cptep, *ptep;
232235
dart_iopte prot;
236+
int level = data->levels;
233237

234238
if (WARN_ON(pgsize != cfg->pgsize_bitmap))
235239
return -EINVAL;
@@ -240,31 +244,36 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
240244
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
241245
return -EINVAL;
242246

243-
tbl = dart_get_table(data, iova);
247+
tbl = dart_get_index(data, iova, level);
248+
249+
if (tbl > (1 << data->tbl_bits))
250+
return -ENOMEM;
244251

245252
ptep = data->pgd[tbl];
246-
ptep += dart_get_l1_index(data, iova);
247-
pte = READ_ONCE(*ptep);
253+
while (--level > 1) {
254+
ptep += dart_get_index(data, iova, level);
255+
pte = READ_ONCE(*ptep);
248256

249-
/* no L2 table present */
250-
if (!pte) {
251-
cptep = iommu_alloc_pages_sz(gfp, tblsz);
252-
if (!cptep)
253-
return -ENOMEM;
257+
/* no table present */
258+
if (!pte) {
259+
cptep = iommu_alloc_pages_sz(gfp, tblsz);
260+
if (!cptep)
261+
return -ENOMEM;
254262

255-
pte = dart_install_table(cptep, ptep, 0, data);
256-
if (pte)
257-
iommu_free_pages(cptep);
263+
pte = dart_install_table(cptep, ptep, 0, data);
264+
if (pte)
265+
iommu_free_pages(cptep);
258266

259-
/* L2 table is present (now) */
260-
pte = READ_ONCE(*ptep);
261-
}
267+
/* L2 table is present (now) */
268+
pte = READ_ONCE(*ptep);
269+
}
262270

263-
ptep = iopte_deref(pte, data);
271+
ptep = iopte_deref(pte, data);
272+
}
264273

265274
/* install a leaf entries into L2 table */
266275
prot = dart_prot_to_pte(data, iommu_prot);
267-
map_idx_start = dart_get_l2_index(data, iova);
276+
map_idx_start = dart_get_last_index(data, iova);
268277
max_entries = DART_PTES_PER_TABLE(data) - map_idx_start;
269278
num_entries = min_t(int, pgcount, max_entries);
270279
ptep += map_idx_start;
@@ -293,13 +302,13 @@ static size_t dart_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova,
293302
if (WARN_ON(pgsize != cfg->pgsize_bitmap || !pgcount))
294303
return 0;
295304

296-
ptep = dart_get_l2(data, iova);
305+
ptep = dart_get_last(data, iova);
297306

298307
/* Valid L2 IOPTE pointer? */
299308
if (WARN_ON(!ptep))
300309
return 0;
301310

302-
unmap_idx_start = dart_get_l2_index(data, iova);
311+
unmap_idx_start = dart_get_last_index(data, iova);
303312
ptep += unmap_idx_start;
304313

305314
max_entries = DART_PTES_PER_TABLE(data) - unmap_idx_start;
@@ -330,13 +339,13 @@ static phys_addr_t dart_iova_to_phys(struct io_pgtable_ops *ops,
330339
struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops);
331340
dart_iopte pte, *ptep;
332341

333-
ptep = dart_get_l2(data, iova);
342+
ptep = dart_get_last(data, iova);
334343

335344
/* Valid L2 IOPTE pointer? */
336345
if (!ptep)
337346
return 0;
338347

339-
ptep += dart_get_l2_index(data, iova);
348+
ptep += dart_get_last_index(data, iova);
340349

341350
pte = READ_ONCE(*ptep);
342351
/* Found translation */
@@ -353,21 +362,37 @@ static struct dart_io_pgtable *
353362
dart_alloc_pgtable(struct io_pgtable_cfg *cfg)
354363
{
355364
struct dart_io_pgtable *data;
356-
int tbl_bits, bits_per_level, va_bits, pg_shift;
365+
int levels, max_tbl_bits, tbl_bits, bits_per_level, va_bits, pg_shift;
366+
367+
/*
368+
* Old 4K page DARTs can use up to 4 top-level tables.
369+
* Newer ones only ever use a maximum of 1.
370+
*/
371+
if (cfg->pgsize_bitmap == SZ_4K)
372+
max_tbl_bits = DART_MAX_TABLE_BITS;
373+
else
374+
max_tbl_bits = 0;
357375

358376
pg_shift = __ffs(cfg->pgsize_bitmap);
359377
bits_per_level = pg_shift - ilog2(sizeof(dart_iopte));
360378

361379
va_bits = cfg->ias - pg_shift;
362380

363-
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * DART_LEVELS));
364-
if ((1 << tbl_bits) > DART_MAX_TABLES)
381+
levels = max_t(int, 2, (va_bits - max_tbl_bits + bits_per_level - 1) / bits_per_level);
382+
383+
if (levels > (DART_MAX_LEVELS - 1))
384+
return NULL;
385+
386+
tbl_bits = max_t(int, 0, va_bits - (bits_per_level * levels));
387+
388+
if (tbl_bits > max_tbl_bits)
365389
return NULL;
366390

367391
data = kzalloc(sizeof(*data), GFP_KERNEL);
368392
if (!data)
369393
return NULL;
370394

395+
data->levels = levels + 1; /* Table level counts as one level */
371396
data->tbl_bits = tbl_bits;
372397
data->bits_per_level = bits_per_level;
373398

@@ -403,6 +428,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
403428
return NULL;
404429

405430
cfg->apple_dart_cfg.n_ttbrs = 1 << data->tbl_bits;
431+
cfg->apple_dart_cfg.n_levels = data->levels;
406432

407433
for (i = 0; i < cfg->apple_dart_cfg.n_ttbrs; ++i) {
408434
data->pgd[i] =
@@ -422,24 +448,31 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
422448
return NULL;
423449
}
424450

425-
static void apple_dart_free_pgtable(struct io_pgtable *iop)
451+
static void apple_dart_free_pgtables(struct dart_io_pgtable *data, dart_iopte *ptep, int level)
426452
{
427-
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
428-
dart_iopte *ptep, *end;
429-
int i;
453+
dart_iopte *end;
454+
dart_iopte *start = ptep;
430455

431-
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
432-
ptep = data->pgd[i];
456+
if (level > 1) {
433457
end = (void *)ptep + DART_GRANULE(data);
434458

435459
while (ptep != end) {
436460
dart_iopte pte = *ptep++;
437461

438462
if (pte)
439-
iommu_free_pages(iopte_deref(pte, data));
463+
apple_dart_free_pgtables(data, iopte_deref(pte, data), level - 1);
440464
}
441-
iommu_free_pages(data->pgd[i]);
442465
}
466+
iommu_free_pages(start);
467+
}
468+
469+
static void apple_dart_free_pgtable(struct io_pgtable *iop)
470+
{
471+
struct dart_io_pgtable *data = io_pgtable_to_data(iop);
472+
int i;
473+
474+
for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i)
475+
apple_dart_free_pgtables(data, data->pgd[i], data->levels - 1);
443476

444477
kfree(data);
445478
}

include/linux/io-pgtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ struct io_pgtable_cfg {
180180
struct {
181181
u64 ttbr[4];
182182
u32 n_ttbrs;
183+
u32 n_levels;
183184
} apple_dart_cfg;
184185

185186
struct {

0 commit comments

Comments
 (0)