Skip to content

Commit 2125afb

Browse files
Sam Protsenkojoergroedel
authored andcommitted
iommu/exynos: Abstract non-common registers on different variants
At the moment the driver supports SysMMU v1..v5 versions. SysMMU v5 has different register layout than SysMMU v1..v3. Instead of checking the version each time before reading/writing the registers, let's create corresponding register structure for each SysMMU version and set the needed structure on init, checking the SysMMU version one single time. This way is faster and more elegant. No behavior changes from the user's point of view, it's only a refactoring patch. Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org> Acked-by: Marek Szyprowski <m.szyprowski@samsung.com> Link: https://lore.kernel.org/r/20220714165550.8884-5-semen.protsenko@linaro.org Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 5f26ad5 commit 2125afb

1 file changed

Lines changed: 60 additions & 40 deletions

File tree

drivers/iommu/exynos-iommu.c

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -148,26 +148,12 @@ static u32 lv2ent_offset(sysmmu_iova_t iova)
148148
#define MAKE_MMU_VER(maj, min) ((((maj) & 0xF) << 7) | ((min) & 0x7F))
149149

150150
/* v1.x - v3.x registers */
151-
#define REG_MMU_FLUSH 0x00C
152-
#define REG_MMU_FLUSH_ENTRY 0x010
153-
#define REG_PT_BASE_ADDR 0x014
154-
#define REG_INT_STATUS 0x018
155-
#define REG_INT_CLEAR 0x01C
156-
157151
#define REG_PAGE_FAULT_ADDR 0x024
158152
#define REG_AW_FAULT_ADDR 0x028
159153
#define REG_AR_FAULT_ADDR 0x02C
160154
#define REG_DEFAULT_SLAVE_ADDR 0x030
161155

162156
/* v5.x registers */
163-
#define REG_V5_PT_BASE_PFN 0x00C
164-
#define REG_V5_MMU_FLUSH_ALL 0x010
165-
#define REG_V5_MMU_FLUSH_ENTRY 0x014
166-
#define REG_V5_MMU_FLUSH_RANGE 0x018
167-
#define REG_V5_MMU_FLUSH_START 0x020
168-
#define REG_V5_MMU_FLUSH_END 0x024
169-
#define REG_V5_INT_STATUS 0x060
170-
#define REG_V5_INT_CLEAR 0x064
171157
#define REG_V5_FAULT_AR_VA 0x070
172158
#define REG_V5_FAULT_AW_VA 0x080
173159

@@ -250,6 +236,21 @@ struct exynos_iommu_domain {
250236
struct iommu_domain domain; /* generic domain data structure */
251237
};
252238

239+
/*
240+
* SysMMU version specific data. Contains offsets for the registers which can
241+
* be found in different SysMMU variants, but have different offset values.
242+
*/
243+
struct sysmmu_variant {
244+
u32 pt_base; /* page table base address (physical) */
245+
u32 flush_all; /* invalidate all TLB entries */
246+
u32 flush_entry; /* invalidate specific TLB entry */
247+
u32 flush_range; /* invalidate TLB entries in specified range */
248+
u32 flush_start; /* start address of range invalidation */
249+
u32 flush_end; /* end address of range invalidation */
250+
u32 int_status; /* interrupt status information */
251+
u32 int_clear; /* clear the interrupt */
252+
};
253+
253254
/*
254255
* This structure hold all data of a single SYSMMU controller, this includes
255256
* hw resources like registers and clocks, pointers and list nodes to connect
@@ -274,6 +275,30 @@ struct sysmmu_drvdata {
274275
unsigned int version; /* our version */
275276

276277
struct iommu_device iommu; /* IOMMU core handle */
278+
const struct sysmmu_variant *variant; /* version specific data */
279+
};
280+
281+
#define SYSMMU_REG(data, reg) ((data)->sfrbase + (data)->variant->reg)
282+
283+
/* SysMMU v1..v3 */
284+
static const struct sysmmu_variant sysmmu_v1_variant = {
285+
.flush_all = 0x0c,
286+
.flush_entry = 0x10,
287+
.pt_base = 0x14,
288+
.int_status = 0x18,
289+
.int_clear = 0x1c,
290+
};
291+
292+
/* SysMMU v5 */
293+
static const struct sysmmu_variant sysmmu_v5_variant = {
294+
.pt_base = 0x0c,
295+
.flush_all = 0x10,
296+
.flush_entry = 0x14,
297+
.flush_range = 0x18,
298+
.flush_start = 0x20,
299+
.flush_end = 0x24,
300+
.int_status = 0x60,
301+
.int_clear = 0x64,
277302
};
278303

279304
static struct exynos_iommu_domain *to_exynos_domain(struct iommu_domain *dom)
@@ -304,44 +329,38 @@ static bool sysmmu_block(struct sysmmu_drvdata *data)
304329

305330
static void __sysmmu_tlb_invalidate(struct sysmmu_drvdata *data)
306331
{
307-
if (MMU_MAJ_VER(data->version) < 5)
308-
writel(0x1, data->sfrbase + REG_MMU_FLUSH);
309-
else
310-
writel(0x1, data->sfrbase + REG_V5_MMU_FLUSH_ALL);
332+
writel(0x1, SYSMMU_REG(data, flush_all));
311333
}
312334

313335
static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
314336
sysmmu_iova_t iova, unsigned int num_inv)
315337
{
316338
unsigned int i;
317339

318-
if (MMU_MAJ_VER(data->version) < 5) {
340+
if (MMU_MAJ_VER(data->version) < 5 || num_inv == 1) {
319341
for (i = 0; i < num_inv; i++) {
320342
writel((iova & SPAGE_MASK) | 1,
321-
data->sfrbase + REG_MMU_FLUSH_ENTRY);
343+
SYSMMU_REG(data, flush_entry));
322344
iova += SPAGE_SIZE;
323345
}
324346
} else {
325-
if (num_inv == 1) {
326-
writel((iova & SPAGE_MASK) | 1,
327-
data->sfrbase + REG_V5_MMU_FLUSH_ENTRY);
328-
} else {
329-
writel((iova & SPAGE_MASK),
330-
data->sfrbase + REG_V5_MMU_FLUSH_START);
331-
writel((iova & SPAGE_MASK) + (num_inv - 1) * SPAGE_SIZE,
332-
data->sfrbase + REG_V5_MMU_FLUSH_END);
333-
writel(1, data->sfrbase + REG_V5_MMU_FLUSH_RANGE);
334-
}
347+
writel(iova & SPAGE_MASK, SYSMMU_REG(data, flush_start));
348+
writel((iova & SPAGE_MASK) + (num_inv - 1) * SPAGE_SIZE,
349+
SYSMMU_REG(data, flush_end));
350+
writel(0x1, SYSMMU_REG(data, flush_range));
335351
}
336352
}
337353

338354
static void __sysmmu_set_ptbase(struct sysmmu_drvdata *data, phys_addr_t pgd)
339355
{
356+
u32 pt_base;
357+
340358
if (MMU_MAJ_VER(data->version) < 5)
341-
writel(pgd, data->sfrbase + REG_PT_BASE_ADDR);
359+
pt_base = pgd;
342360
else
343-
writel(pgd >> SPAGE_ORDER, data->sfrbase + REG_V5_PT_BASE_PFN);
361+
pt_base = pgd >> SPAGE_ORDER;
344362

363+
writel(pt_base, SYSMMU_REG(data, pt_base));
345364
__sysmmu_tlb_invalidate(data);
346365
}
347366

@@ -378,6 +397,11 @@ static void __sysmmu_get_version(struct sysmmu_drvdata *data)
378397
dev_dbg(data->sysmmu, "hardware version: %d.%d\n",
379398
MMU_MAJ_VER(data->version), MMU_MIN_VER(data->version));
380399

400+
if (MMU_MAJ_VER(data->version) < 5)
401+
data->variant = &sysmmu_v1_variant;
402+
else
403+
data->variant = &sysmmu_v5_variant;
404+
381405
__sysmmu_disable_clocks(data);
382406
}
383407

@@ -405,19 +429,14 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
405429
const struct sysmmu_fault_info *finfo;
406430
unsigned int i, n, itype;
407431
sysmmu_iova_t fault_addr;
408-
unsigned short reg_status, reg_clear;
409432
int ret = -ENOSYS;
410433

411434
WARN_ON(!data->active);
412435

413436
if (MMU_MAJ_VER(data->version) < 5) {
414-
reg_status = REG_INT_STATUS;
415-
reg_clear = REG_INT_CLEAR;
416437
finfo = sysmmu_faults;
417438
n = ARRAY_SIZE(sysmmu_faults);
418439
} else {
419-
reg_status = REG_V5_INT_STATUS;
420-
reg_clear = REG_V5_INT_CLEAR;
421440
finfo = sysmmu_v5_faults;
422441
n = ARRAY_SIZE(sysmmu_v5_faults);
423442
}
@@ -426,7 +445,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
426445

427446
clk_enable(data->clk_master);
428447

429-
itype = __ffs(readl(data->sfrbase + reg_status));
448+
itype = __ffs(readl(SYSMMU_REG(data, int_status)));
430449
for (i = 0; i < n; i++, finfo++)
431450
if (finfo->bit == itype)
432451
break;
@@ -443,7 +462,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
443462
/* fault is not recovered by fault handler */
444463
BUG_ON(ret != 0);
445464

446-
writel(1 << itype, data->sfrbase + reg_clear);
465+
writel(1 << itype, SYSMMU_REG(data, int_clear));
447466

448467
sysmmu_unblock(data);
449468

@@ -622,6 +641,8 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
622641
data->sysmmu = dev;
623642
spin_lock_init(&data->lock);
624643

644+
__sysmmu_get_version(data);
645+
625646
ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
626647
dev_name(data->sysmmu));
627648
if (ret)
@@ -633,7 +654,6 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
633654

634655
platform_set_drvdata(pdev, data);
635656

636-
__sysmmu_get_version(data);
637657
if (PG_ENT_SHIFT < 0) {
638658
if (MMU_MAJ_VER(data->version) < 5) {
639659
PG_ENT_SHIFT = SYSMMU_PG_ENT_SHIFT;

0 commit comments

Comments
 (0)