Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

accel/amdxdna: Allow forcing IOVA-based DMA via module parameter

The amdxdna driver normally performs DMA using userspace virtual address
plus PASID. For debugging and validation purposes, add a module parameter,
force_iova, to force DMA to go through IOMMU IOVA mapping.

When force_iova=1 is set, the driver will allocate and map DMA buffers
using IOVA.

Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
Link: https://patch.msgid.link/20260126193001.1400545-1-lizhi.hou@amd.com

Lizhi Hou ece3e898 d11ac904

+324 -31
+1
drivers/accel/amdxdna/Makefile
··· 11 11 aie2_solver.o \ 12 12 amdxdna_ctx.o \ 13 13 amdxdna_gem.o \ 14 + amdxdna_iommu.o \ 14 15 amdxdna_mailbox.o \ 15 16 amdxdna_mailbox_helper.o \ 16 17 amdxdna_pci_drv.o \
+4 -2
drivers/accel/amdxdna/aie2_ctx.c
··· 68 68 } 69 69 70 70 ret = aie2_map_host_buf(xdna->dev_handle, hwctx->fw_ctx_id, 71 - heap->mem.userptr, heap->mem.size); 71 + amdxdna_obj_dma_addr(hwctx->client, heap), 72 + heap->mem.size); 72 73 if (ret) { 73 74 XDNA_ERR(xdna, "Map host buf failed, ret %d", ret); 74 75 goto out; ··· 638 637 } 639 638 640 639 ret = aie2_map_host_buf(xdna->dev_handle, hwctx->fw_ctx_id, 641 - heap->mem.userptr, heap->mem.size); 640 + amdxdna_obj_dma_addr(hwctx->client, heap), 641 + heap->mem.size); 642 642 if (ret) { 643 643 XDNA_ERR(xdna, "Map host buffer failed, ret %d", ret); 644 644 goto release_resource;
+2 -3
drivers/accel/amdxdna/aie2_error.c
··· 355 355 return -ENOMEM; 356 356 357 357 events->buf = aie2_alloc_msg_buffer(ndev, &total_size, &events->addr); 358 - 359 - if (!events->buf) { 360 - ret = -ENOMEM; 358 + if (IS_ERR(events->buf)) { 359 + ret = PTR_ERR(events->buf); 361 360 goto free_events; 362 361 } 363 362 events->size = total_size;
+23 -7
drivers/accel/amdxdna/aie2_message.c
··· 61 61 *size = max(*size, SZ_8K); 62 62 order = get_order(*size); 63 63 if (order > MAX_PAGE_ORDER) 64 - return NULL; 64 + return ERR_PTR(-EINVAL); 65 65 *size = PAGE_SIZE << order; 66 66 67 + if (amdxdna_iova_on(xdna)) 68 + return amdxdna_iommu_alloc(xdna, *size, dma_addr); 69 + 67 70 return dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, 68 - DMA_FROM_DEVICE, GFP_KERNEL); 71 + DMA_FROM_DEVICE, GFP_KERNEL); 72 + } 73 + 74 + void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size, 75 + void *cpu_addr, dma_addr_t dma_addr) 76 + { 77 + struct amdxdna_dev *xdna = ndev->xdna; 78 + 79 + if (amdxdna_iova_on(xdna)) { 80 + amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr); 81 + return; 82 + } 83 + 84 + dma_free_noncoherent(xdna->ddev.dev, size, cpu_addr, dma_addr, DMA_FROM_DEVICE); 69 85 } 70 86 71 87 int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) ··· 272 256 req.num_col = hwctx->num_col; 273 257 req.num_unused_col = hwctx->num_unused_col; 274 258 req.num_cq_pairs_requested = 1; 275 - req.pasid = hwctx->client->pasid; 259 + req.pasid = amdxdna_pasid_on(hwctx->client) ? hwctx->client->pasid : 0; 276 260 req.context_priority = aie2_get_context_priority(ndev, hwctx); 277 261 278 262 ret = aie2_send_mgmt_msg_wait(ndev, &msg); ··· 396 380 int ret; 397 381 398 382 buff_addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); 399 - if (!buff_addr) 400 - return -ENOMEM; 383 + if (IS_ERR(buff_addr)) 384 + return PTR_ERR(buff_addr); 401 385 402 386 /* Go through each hardware context and mark the AIE columns that are active */ 403 387 list_for_each_entry(client, &xdna->client_list, node) ··· 452 436 return -EINVAL; 453 437 454 438 addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); 455 - if (!addr) 456 - return -ENOMEM; 439 + if (IS_ERR(addr)) 440 + return PTR_ERR(addr); 457 441 458 442 req.buf_addr = dma_addr; 459 443 req.buf_size = buf_sz;
+2 -3
drivers/accel/amdxdna/aie2_pci.h
··· 366 366 int (*notify_cb)(void *, void __iomem *, size_t)); 367 367 void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, 368 368 dma_addr_t *dma_addr); 369 - #define aie2_free_msg_buffer(ndev, size, buff_addr, dma_addr) \ 370 - dma_free_noncoherent((ndev)->xdna->ddev.dev, size, buff_addr, \ 371 - dma_addr, DMA_FROM_DEVICE) 369 + void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size, 370 + void *cpu_addr, dma_addr_t dma_addr); 372 371 373 372 /* aie2_hwctx.c */ 374 373 int aie2_hwctx_init(struct amdxdna_hwctx *hwctx);
+44 -1
drivers/accel/amdxdna/amdxdna_gem.c
··· 474 474 drm_gem_shmem_free(&abo->base); 475 475 } 476 476 477 + static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *filp) 478 + { 479 + struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); 480 + struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 481 + int ret; 482 + 483 + guard(mutex)(&abo->lock); 484 + if (abo->ref) { 485 + abo->ref++; 486 + return 0; 487 + } 488 + 489 + if (amdxdna_iova_on(xdna)) { 490 + ret = amdxdna_iommu_map_bo(xdna, abo); 491 + if (ret) 492 + return ret; 493 + } 494 + abo->ref++; 495 + 496 + return 0; 497 + } 498 + 499 + static void amdxdna_gem_obj_close(struct drm_gem_object *gobj, struct drm_file *filp) 500 + { 501 + struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); 502 + struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 503 + 504 + guard(mutex)(&abo->lock); 505 + abo->ref--; 506 + if (abo->ref) 507 + return; 508 + 509 + if (amdxdna_iova_on(xdna)) 510 + amdxdna_iommu_unmap_bo(xdna, abo); 511 + } 512 + 477 513 static const struct drm_gem_object_funcs amdxdna_gem_dev_obj_funcs = { 478 514 .free = amdxdna_gem_dev_obj_free, 479 515 }; 480 516 481 517 static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = { 482 518 .free = amdxdna_gem_obj_free, 519 + .open = amdxdna_gem_obj_open, 520 + .close = amdxdna_gem_obj_close, 483 521 .print_info = drm_gem_shmem_object_print_info, 484 522 .pin = drm_gem_shmem_object_pin, 485 523 .unpin = drm_gem_shmem_object_unpin, ··· 544 506 545 507 abo->mem.userptr = AMDXDNA_INVALID_ADDR; 546 508 abo->mem.dev_addr = AMDXDNA_INVALID_ADDR; 509 + abo->mem.dma_addr = AMDXDNA_INVALID_ADDR; 547 510 abo->mem.size = size; 548 511 INIT_LIST_HEAD(&abo->mem.umap_list); 549 512 ··· 660 621 abo = to_xdna_obj(gobj); 661 622 abo->attach = attach; 662 623 abo->dma_buf = dma_buf; 624 + abo->type = AMDXDNA_BO_SHMEM; 663 625 664 626 return gobj; 665 627 ··· 945 905 946 906 abo = to_xdna_obj(gobj); 947 907 args->vaddr = abo->mem.userptr; 948 - args->xdna_addr = abo->mem.dev_addr; 908 + if (abo->mem.dev_addr != AMDXDNA_INVALID_ADDR) 909 + args->xdna_addr = abo->mem.dev_addr; 910 + else 911 + args->xdna_addr = abo->mem.dma_addr; 949 912 950 913 if (abo->type != AMDXDNA_BO_DEV) 951 914 args->map_offset = drm_vma_node_offset_addr(&gobj->vma_node);
+10
drivers/accel/amdxdna/amdxdna_gem.h
··· 6 6 #ifndef _AMDXDNA_GEM_H_ 7 7 #define _AMDXDNA_GEM_H_ 8 8 9 + #include <drm/drm_gem_shmem_helper.h> 9 10 #include <linux/hmm.h> 11 + #include <linux/iova.h> 10 12 #include "amdxdna_pci_drv.h" 11 13 12 14 struct amdxdna_umap { ··· 27 25 u64 userptr; 28 26 void *kva; 29 27 u64 dev_addr; 28 + u64 dma_addr; 30 29 size_t size; 31 30 struct page **pages; 32 31 u32 nr_pages; ··· 42 39 bool pinned; 43 40 struct mutex lock; /* Protects: pinned */ 44 41 struct amdxdna_mem mem; 42 + u32 ref; 45 43 46 44 /* Below members is uninitialized when needed */ 47 45 struct drm_mm mm; /* For AMDXDNA_BO_DEV_HEAP */ ··· 70 66 static inline u64 amdxdna_dev_bo_offset(struct amdxdna_gem_obj *abo) 71 67 { 72 68 return abo->mem.dev_addr - abo->client->dev_heap->mem.dev_addr; 69 + } 70 + 71 + static inline u64 amdxdna_obj_dma_addr(struct amdxdna_client *client, 72 + struct amdxdna_gem_obj *abo) 73 + { 74 + return amdxdna_pasid_on(client) ? abo->mem.userptr : abo->mem.dma_addr; 73 75 } 74 76 75 77 void amdxdna_umap_put(struct amdxdna_umap *mapp);
+184
drivers/accel/amdxdna/amdxdna_iommu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2025, Advanced Micro Devices, Inc. 4 + */ 5 + 6 + #include <drm/amdxdna_accel.h> 7 + #include <linux/iommu.h> 8 + #include <linux/iova.h> 9 + 10 + #include "amdxdna_gem.h" 11 + #include "amdxdna_pci_drv.h" 12 + 13 + static bool force_iova; 14 + module_param(force_iova, bool, 0600); 15 + MODULE_PARM_DESC(force_iova, "Force use IOVA (Default false)"); 16 + 17 + static struct iova *amdxdna_iommu_alloc_iova(struct amdxdna_dev *xdna, 18 + size_t size, 19 + dma_addr_t *dma_addr, 20 + bool size_aligned) 21 + { 22 + unsigned long shift, end; 23 + struct iova *iova; 24 + 25 + end = xdna->domain->geometry.aperture_end; 26 + shift = iova_shift(&xdna->iovad); 27 + size = iova_align(&xdna->iovad, size); 28 + 29 + iova = alloc_iova(&xdna->iovad, size >> shift, end >> shift, size_aligned); 30 + if (!iova) 31 + return ERR_PTR(-ENOMEM); 32 + 33 + *dma_addr = iova_dma_addr(&xdna->iovad, iova); 34 + 35 + return iova; 36 + } 37 + 38 + int amdxdna_iommu_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo) 39 + { 40 + struct sg_table *sgt; 41 + dma_addr_t dma_addr; 42 + struct iova *iova; 43 + size_t size; 44 + 45 + if (abo->type != AMDXDNA_BO_DEV_HEAP && abo->type != AMDXDNA_BO_SHMEM) 46 + return 0; 47 + 48 + sgt = drm_gem_shmem_get_pages_sgt(&abo->base); 49 + if (IS_ERR(sgt)) { 50 + XDNA_ERR(xdna, "Get sgt failed, ret %ld", PTR_ERR(sgt)); 51 + return PTR_ERR(sgt); 52 + } 53 + 54 + if (!sgt->orig_nents || !sg_page(sgt->sgl)) { 55 + XDNA_ERR(xdna, "sgl is zero length or not page backed"); 56 + return -EOPNOTSUPP; 57 + } 58 + 59 + iova = amdxdna_iommu_alloc_iova(xdna, abo->mem.size, &dma_addr, 60 + (abo->type == AMDXDNA_BO_DEV_HEAP)); 61 + if (IS_ERR(iova)) { 62 + XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova)); 63 + return PTR_ERR(iova); 64 + } 65 + 66 + size = iommu_map_sgtable(xdna->domain, dma_addr, sgt, 67 + IOMMU_READ | IOMMU_WRITE); 68 + if (size < abo->mem.size) { 69 + __free_iova(&xdna->iovad, iova); 70 + return -ENXIO; 71 + } 72 + 73 + abo->mem.dma_addr = dma_addr; 74 + 75 + return 0; 76 + } 77 + 78 + void amdxdna_iommu_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo) 79 + { 80 + size_t size; 81 + 82 + if (abo->mem.dma_addr == AMDXDNA_INVALID_ADDR) 83 + return; 84 + 85 + size = iova_align(&xdna->iovad, abo->mem.size); 86 + iommu_unmap(xdna->domain, abo->mem.dma_addr, size); 87 + free_iova(&xdna->iovad, iova_pfn(&xdna->iovad, abo->mem.dma_addr)); 88 + abo->mem.dma_addr = AMDXDNA_INVALID_ADDR; 89 + } 90 + 91 + void *amdxdna_iommu_alloc(struct amdxdna_dev *xdna, size_t size, dma_addr_t *dma_addr) 92 + { 93 + struct iova *iova; 94 + void *cpu_addr; 95 + int ret; 96 + 97 + iova = amdxdna_iommu_alloc_iova(xdna, size, dma_addr, true); 98 + if (IS_ERR(iova)) { 99 + XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova)); 100 + return iova; 101 + } 102 + 103 + cpu_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(size)); 104 + if (!cpu_addr) { 105 + ret = -ENOMEM; 106 + goto free_iova; 107 + } 108 + 109 + ret = iommu_map(xdna->domain, *dma_addr, virt_to_phys(cpu_addr), 110 + iova_align(&xdna->iovad, size), 111 + IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); 112 + if (ret) 113 + goto free_iova; 114 + 115 + return cpu_addr; 116 + 117 + free_iova: 118 + __free_iova(&xdna->iovad, iova); 119 + return ERR_PTR(ret); 120 + } 121 + 122 + void amdxdna_iommu_free(struct amdxdna_dev *xdna, size_t size, 123 + void *cpu_addr, dma_addr_t dma_addr) 124 + { 125 + iommu_unmap(xdna->domain, dma_addr, iova_align(&xdna->iovad, size)); 126 + free_iova(&xdna->iovad, iova_pfn(&xdna->iovad, dma_addr)); 127 + free_pages((unsigned long)cpu_addr, get_order(size)); 128 + } 129 + 130 + int amdxdna_iommu_init(struct amdxdna_dev *xdna) 131 + { 132 + unsigned long order; 133 + int ret; 134 + 135 + xdna->group = iommu_group_get(xdna->ddev.dev); 136 + if (!xdna->group || !force_iova) 137 + return 0; 138 + 139 + XDNA_WARN(xdna, "Enabled force_iova mode."); 140 + xdna->domain = iommu_paging_domain_alloc_flags(xdna->ddev.dev, 141 + IOMMU_HWPT_ALLOC_PASID); 142 + if (IS_ERR(xdna->domain)) { 143 + XDNA_ERR(xdna, "Failed to alloc iommu domain"); 144 + ret = PTR_ERR(xdna->domain); 145 + goto put_group; 146 + } 147 + 148 + ret = iova_cache_get(); 149 + if (ret) 150 + goto free_domain; 151 + 152 + order = __ffs(xdna->domain->pgsize_bitmap); 153 + init_iova_domain(&xdna->iovad, 1UL << order, 0); 154 + 155 + ret = iommu_attach_group(xdna->domain, xdna->group); 156 + if (ret) 157 + goto put_iova; 158 + 159 + return 0; 160 + 161 + put_iova: 162 + put_iova_domain(&xdna->iovad); 163 + iova_cache_put(); 164 + free_domain: 165 + iommu_domain_free(xdna->domain); 166 + put_group: 167 + iommu_group_put(xdna->group); 168 + xdna->domain = NULL; 169 + 170 + return ret; 171 + } 172 + 173 + void amdxdna_iommu_fini(struct amdxdna_dev *xdna) 174 + { 175 + if (xdna->domain) { 176 + iommu_detach_group(xdna->domain, xdna->group); 177 + put_iova_domain(&xdna->iovad); 178 + iova_cache_put(); 179 + iommu_domain_free(xdna->domain); 180 + } 181 + 182 + if (xdna->group) 183 + iommu_group_put(xdna->group); 184 + }
+30 -15
drivers/accel/amdxdna/amdxdna_pci_drv.c
··· 73 73 74 74 client->pid = pid_nr(rcu_access_pointer(filp->pid)); 75 75 client->xdna = xdna; 76 + client->pasid = IOMMU_PASID_INVALID; 76 77 77 - client->sva = iommu_sva_bind_device(xdna->ddev.dev, current->mm); 78 - if (IS_ERR(client->sva)) { 79 - ret = PTR_ERR(client->sva); 80 - XDNA_ERR(xdna, "SVA bind device failed, ret %d", ret); 81 - goto failed; 82 - } 83 - client->pasid = iommu_sva_get_pasid(client->sva); 84 - if (client->pasid == IOMMU_PASID_INVALID) { 85 - XDNA_ERR(xdna, "SVA get pasid failed"); 86 - ret = -ENODEV; 87 - goto unbind_sva; 78 + if (!amdxdna_iova_on(xdna)) { 79 + client->sva = iommu_sva_bind_device(xdna->ddev.dev, current->mm); 80 + if (IS_ERR(client->sva)) { 81 + ret = PTR_ERR(client->sva); 82 + XDNA_ERR(xdna, "SVA bind device failed, ret %d", ret); 83 + goto failed; 84 + } 85 + client->pasid = iommu_sva_get_pasid(client->sva); 86 + if (client->pasid == IOMMU_PASID_INVALID) { 87 + XDNA_ERR(xdna, "SVA get pasid failed"); 88 + ret = -ENODEV; 89 + goto unbind_sva; 90 + } 88 91 } 89 92 client->mm = current->mm; 90 93 mmgrab(client->mm); ··· 106 103 return 0; 107 104 108 105 unbind_sva: 109 - iommu_sva_unbind_device(client->sva); 106 + if (!IS_ERR_OR_NULL(client->sva)) 107 + iommu_sva_unbind_device(client->sva); 110 108 failed: 111 109 kfree(client); 112 110 ··· 125 121 if (client->dev_heap) 126 122 drm_gem_object_put(to_gobj(client->dev_heap)); 127 123 128 - iommu_sva_unbind_device(client->sva); 124 + if (!IS_ERR_OR_NULL(client->sva)) 125 + iommu_sva_unbind_device(client->sva); 129 126 mmdrop(client->mm); 130 127 131 128 kfree(client); ··· 287 282 fs_reclaim_release(GFP_KERNEL); 288 283 } 289 284 285 + ret = amdxdna_iommu_init(xdna); 286 + if (ret) 287 + return ret; 288 + 290 289 xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM); 291 - if (!xdna->notifier_wq) 292 - return -ENOMEM; 290 + if (!xdna->notifier_wq) { 291 + ret = -ENOMEM; 292 + goto iommu_fini; 293 + } 293 294 294 295 mutex_lock(&xdna->dev_lock); 295 296 ret = xdna->dev_info->ops->init(xdna); ··· 327 316 mutex_unlock(&xdna->dev_lock); 328 317 destroy_notifier_wq: 329 318 destroy_workqueue(xdna->notifier_wq); 319 + iommu_fini: 320 + amdxdna_iommu_fini(xdna); 330 321 return ret; 331 322 } 332 323 ··· 354 341 355 342 xdna->dev_info->ops->fini(xdna); 356 343 mutex_unlock(&xdna->dev_lock); 344 + 345 + amdxdna_iommu_fini(xdna); 357 346 } 358 347 359 348 static const struct dev_pm_ops amdxdna_pm_ops = {
+24
drivers/accel/amdxdna/amdxdna_pci_drv.h
··· 6 6 #ifndef _AMDXDNA_PCI_DRV_H_ 7 7 #define _AMDXDNA_PCI_DRV_H_ 8 8 9 + #include <drm/amdxdna_accel.h> 9 10 #include <drm/drm_print.h> 11 + #include <linux/iommu.h> 12 + #include <linux/iova.h> 10 13 #include <linux/workqueue.h> 11 14 #include <linux/xarray.h> 12 15 ··· 104 101 struct amdxdna_fw_ver fw_ver; 105 102 struct rw_semaphore notifier_lock; /* for mmu notifier*/ 106 103 struct workqueue_struct *notifier_wq; 104 + 105 + struct iommu_group *group; 106 + struct iommu_domain *domain; 107 + struct iova_domain iovad; 107 108 }; 108 109 109 110 /* ··· 152 145 int amdxdna_sysfs_init(struct amdxdna_dev *xdna); 153 146 void amdxdna_sysfs_fini(struct amdxdna_dev *xdna); 154 147 148 + int amdxdna_iommu_init(struct amdxdna_dev *xdna); 149 + void amdxdna_iommu_fini(struct amdxdna_dev *xdna); 150 + int amdxdna_iommu_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo); 151 + void amdxdna_iommu_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo); 152 + void *amdxdna_iommu_alloc(struct amdxdna_dev *xdna, size_t size, dma_addr_t *dma_addr); 153 + void amdxdna_iommu_free(struct amdxdna_dev *xdna, size_t size, 154 + void *cpu_addr, dma_addr_t dma_addr); 155 + 156 + static inline bool amdxdna_iova_on(struct amdxdna_dev *xdna) 157 + { 158 + return !!xdna->domain; 159 + } 160 + 161 + static inline bool amdxdna_pasid_on(struct amdxdna_client *client) 162 + { 163 + return client->pasid != IOMMU_PASID_INVALID; 164 + } 155 165 #endif /* _AMDXDNA_PCI_DRV_H_ */