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