18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Generic page table allocator for IOMMUs.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 ARM Limited
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Will Deacon <will.deacon@arm.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/bug.h>
118c2ecf20Sopenharmony_ci#include <linux/io-pgtable.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic const struct io_pgtable_init_fns *
168c2ecf20Sopenharmony_ciio_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = {
178c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE
188c2ecf20Sopenharmony_ci	[ARM_32_LPAE_S1] = &io_pgtable_arm_32_lpae_s1_init_fns,
198c2ecf20Sopenharmony_ci	[ARM_32_LPAE_S2] = &io_pgtable_arm_32_lpae_s2_init_fns,
208c2ecf20Sopenharmony_ci	[ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns,
218c2ecf20Sopenharmony_ci	[ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns,
228c2ecf20Sopenharmony_ci	[ARM_MALI_LPAE] = &io_pgtable_arm_mali_lpae_init_fns,
238c2ecf20Sopenharmony_ci#endif
248c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S
258c2ecf20Sopenharmony_ci	[ARM_V7S] = &io_pgtable_arm_v7s_init_fns,
268c2ecf20Sopenharmony_ci#endif
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistruct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
308c2ecf20Sopenharmony_ci					    struct io_pgtable_cfg *cfg,
318c2ecf20Sopenharmony_ci					    void *cookie)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	struct io_pgtable *iop;
348c2ecf20Sopenharmony_ci	const struct io_pgtable_init_fns *fns;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (fmt >= IO_PGTABLE_NUM_FMTS)
378c2ecf20Sopenharmony_ci		return NULL;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	fns = io_pgtable_init_table[fmt];
408c2ecf20Sopenharmony_ci	if (!fns)
418c2ecf20Sopenharmony_ci		return NULL;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	iop = fns->alloc(cfg, cookie);
448c2ecf20Sopenharmony_ci	if (!iop)
458c2ecf20Sopenharmony_ci		return NULL;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	iop->fmt	= fmt;
488c2ecf20Sopenharmony_ci	iop->cookie	= cookie;
498c2ecf20Sopenharmony_ci	iop->cfg	= *cfg;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return &iop->ops;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(alloc_io_pgtable_ops);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * It is the IOMMU driver's responsibility to ensure that the page table
578c2ecf20Sopenharmony_ci * is no longer accessible to the walker by this point.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_civoid free_io_pgtable_ops(struct io_pgtable_ops *ops)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct io_pgtable *iop;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (!ops)
648c2ecf20Sopenharmony_ci		return;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	iop = io_pgtable_ops_to_pgtable(ops);
678c2ecf20Sopenharmony_ci	io_pgtable_tlb_flush_all(iop);
688c2ecf20Sopenharmony_ci	io_pgtable_init_table[iop->fmt]->free(iop);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(free_io_pgtable_ops);
71