Path: blob/master/drivers/accel/amdxdna/amdxdna_iommu.c
170891 views
// SPDX-License-Identifier: GPL-2.01/*2* Copyright (C) 2025, Advanced Micro Devices, Inc.3*/45#include <drm/amdxdna_accel.h>6#include <linux/iommu.h>7#include <linux/iova.h>89#include "amdxdna_gem.h"10#include "amdxdna_pci_drv.h"1112static bool force_iova;13module_param(force_iova, bool, 0600);14MODULE_PARM_DESC(force_iova, "Force use IOVA (Default false)");1516static struct iova *amdxdna_iommu_alloc_iova(struct amdxdna_dev *xdna,17size_t size,18dma_addr_t *dma_addr,19bool size_aligned)20{21unsigned long shift, end;22struct iova *iova;2324end = xdna->domain->geometry.aperture_end;25shift = iova_shift(&xdna->iovad);26size = iova_align(&xdna->iovad, size);2728iova = alloc_iova(&xdna->iovad, size >> shift, end >> shift, size_aligned);29if (!iova)30return ERR_PTR(-ENOMEM);3132*dma_addr = iova_dma_addr(&xdna->iovad, iova);3334return iova;35}3637int amdxdna_iommu_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)38{39struct sg_table *sgt;40dma_addr_t dma_addr;41struct iova *iova;42size_t size;4344if (abo->type != AMDXDNA_BO_DEV_HEAP && abo->type != AMDXDNA_BO_SHMEM)45return 0;4647sgt = drm_gem_shmem_get_pages_sgt(&abo->base);48if (IS_ERR(sgt)) {49XDNA_ERR(xdna, "Get sgt failed, ret %ld", PTR_ERR(sgt));50return PTR_ERR(sgt);51}5253if (!sgt->orig_nents || !sg_page(sgt->sgl)) {54XDNA_ERR(xdna, "sgl is zero length or not page backed");55return -EOPNOTSUPP;56}5758iova = amdxdna_iommu_alloc_iova(xdna, abo->mem.size, &dma_addr,59(abo->type == AMDXDNA_BO_DEV_HEAP));60if (IS_ERR(iova)) {61XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova));62return PTR_ERR(iova);63}6465size = iommu_map_sgtable(xdna->domain, dma_addr, sgt,66IOMMU_READ | IOMMU_WRITE);67if (size < abo->mem.size) {68__free_iova(&xdna->iovad, iova);69return -ENXIO;70}7172abo->mem.dma_addr = dma_addr;7374return 0;75}7677void amdxdna_iommu_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)78{79size_t size;8081if (abo->mem.dma_addr == AMDXDNA_INVALID_ADDR)82return;8384size = iova_align(&xdna->iovad, abo->mem.size);85iommu_unmap(xdna->domain, abo->mem.dma_addr, size);86free_iova(&xdna->iovad, iova_pfn(&xdna->iovad, abo->mem.dma_addr));87abo->mem.dma_addr = AMDXDNA_INVALID_ADDR;88}8990void *amdxdna_iommu_alloc(struct amdxdna_dev *xdna, size_t size, dma_addr_t *dma_addr)91{92struct iova *iova;93void *cpu_addr;94int ret;9596iova = amdxdna_iommu_alloc_iova(xdna, size, dma_addr, true);97if (IS_ERR(iova)) {98XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova));99return iova;100}101102cpu_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(size));103if (!cpu_addr) {104ret = -ENOMEM;105goto free_iova;106}107108ret = iommu_map(xdna->domain, *dma_addr, virt_to_phys(cpu_addr),109iova_align(&xdna->iovad, size),110IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);111if (ret)112goto free_iova;113114return cpu_addr;115116free_iova:117__free_iova(&xdna->iovad, iova);118return ERR_PTR(ret);119}120121void amdxdna_iommu_free(struct amdxdna_dev *xdna, size_t size,122void *cpu_addr, dma_addr_t dma_addr)123{124iommu_unmap(xdna->domain, dma_addr, iova_align(&xdna->iovad, size));125free_iova(&xdna->iovad, iova_pfn(&xdna->iovad, dma_addr));126free_pages((unsigned long)cpu_addr, get_order(size));127}128129int amdxdna_iommu_init(struct amdxdna_dev *xdna)130{131unsigned long order;132int ret;133134xdna->group = iommu_group_get(xdna->ddev.dev);135if (!xdna->group || !force_iova)136return 0;137138XDNA_WARN(xdna, "Enabled force_iova mode.");139xdna->domain = iommu_paging_domain_alloc_flags(xdna->ddev.dev,140IOMMU_HWPT_ALLOC_PASID);141if (IS_ERR(xdna->domain)) {142XDNA_ERR(xdna, "Failed to alloc iommu domain");143ret = PTR_ERR(xdna->domain);144goto put_group;145}146147ret = iova_cache_get();148if (ret)149goto free_domain;150151order = __ffs(xdna->domain->pgsize_bitmap);152init_iova_domain(&xdna->iovad, 1UL << order, 0);153154ret = iommu_attach_group(xdna->domain, xdna->group);155if (ret)156goto put_iova;157158return 0;159160put_iova:161put_iova_domain(&xdna->iovad);162iova_cache_put();163free_domain:164iommu_domain_free(xdna->domain);165put_group:166iommu_group_put(xdna->group);167xdna->domain = NULL;168169return ret;170}171172void amdxdna_iommu_fini(struct amdxdna_dev *xdna)173{174if (xdna->domain) {175iommu_detach_group(xdna->domain, xdna->group);176put_iova_domain(&xdna->iovad);177iova_cache_put();178iommu_domain_free(xdna->domain);179}180181if (xdna->group)182iommu_group_put(xdna->group);183}184185186