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: Add per-process BO memory usage query support

Add support for querying per-process buffer object (BO) memory
usage through the amdxdna GET_ARRAY UAPI.

Introduce a new query type, DRM_AMDXDNA_BO_USAGE, along with
struct amdxdna_drm_bo_usage to report BO memory usage statistics,
including heap, total, and internal usage.

Track BO memory usage on a per-client basis by maintaining counters
in GEM open/close and heap allocation/free paths. This ensures the
reported statistics reflect the current memory footprint of each
process.

Wire the new query into the GET_ARRAY implementation to expose
the usage information to userspace.

Link: https://github.com/amd/xdna-driver/commit/0546f2aaadbdacf1c3556410ecd71622044cd916
Signed-off-by: Max Zhen <max.zhen@amd.com>
Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
Link: https://patch.msgid.link/20260324163159.2425461-1-lizhi.hou@amd.com

authored by

Max Zhen and committed by
Lizhi Hou
1f513a3e e6fbe345

+177 -13
+4
drivers/accel/amdxdna/aie2_pci.c
··· 865 865 tmp->command_submissions = hwctx->priv->seq; 866 866 tmp->command_completions = hwctx->priv->completed; 867 867 tmp->pasid = hwctx->client->pasid; 868 + tmp->heap_usage = hwctx->client->heap_usage; 868 869 tmp->priority = hwctx->qos.priority; 869 870 tmp->gops = hwctx->qos.gops; 870 871 tmp->fps = hwctx->qos.fps; ··· 1148 1147 break; 1149 1148 case DRM_AMDXDNA_HW_LAST_ASYNC_ERR: 1150 1149 ret = aie2_get_array_async_error(xdna->dev_handle, args); 1150 + break; 1151 + case DRM_AMDXDNA_BO_USAGE: 1152 + ret = amdxdna_drm_get_bo_usage(&xdna->ddev, args); 1151 1153 break; 1152 1154 default: 1153 1155 XDNA_ERR(xdna, "Not supported request parameter %u", args->param);
+124 -10
drivers/accel/amdxdna/amdxdna_gem.c
··· 63 63 goto unlock_out; 64 64 } 65 65 66 + client->heap_usage += mem->size; 67 + 66 68 drm_gem_object_get(to_gobj(heap)); 67 69 68 70 unlock_out: ··· 76 74 static void 77 75 amdxdna_gem_heap_free(struct amdxdna_gem_obj *abo) 78 76 { 77 + struct amdxdna_client *client = abo->client; 79 78 struct amdxdna_gem_obj *heap; 80 79 81 - mutex_lock(&abo->client->mm_lock); 80 + mutex_lock(&client->mm_lock); 82 81 83 82 drm_mm_remove_node(&abo->mm_node); 84 - 85 - heap = abo->client->dev_heap; 83 + client->heap_usage -= abo->mem.size; 84 + heap = client->dev_heap; 86 85 drm_gem_object_put(to_gobj(heap)); 87 86 88 - mutex_unlock(&abo->client->mm_lock); 87 + mutex_unlock(&client->mm_lock); 89 88 } 90 89 91 90 static struct amdxdna_gem_obj * ··· 105 102 abo->mem.dma_addr = AMDXDNA_INVALID_ADDR; 106 103 abo->mem.uva = AMDXDNA_INVALID_ADDR; 107 104 abo->mem.size = size; 105 + abo->open_ref = 0; 106 + abo->internal = false; 108 107 INIT_LIST_HEAD(&abo->mem.umap_list); 109 108 110 109 return abo; ··· 513 508 kfree(abo); 514 509 } 515 510 511 + static inline bool 512 + amdxdna_gem_skip_bo_usage(struct amdxdna_gem_obj *abo) 513 + { 514 + /* Do not count imported BOs since the buffer is not allocated by us. */ 515 + if (is_import_bo(abo)) 516 + return true; 517 + 518 + /* Already counted as part of HEAP BO */ 519 + if (abo->type == AMDXDNA_BO_DEV) 520 + return true; 521 + 522 + return false; 523 + } 524 + 525 + static void 526 + amdxdna_gem_add_bo_usage(struct amdxdna_gem_obj *abo) 527 + { 528 + struct amdxdna_client *client = abo->client; 529 + 530 + if (amdxdna_gem_skip_bo_usage(abo)) 531 + return; 532 + 533 + guard(mutex)(&client->mm_lock); 534 + 535 + client->total_bo_usage += abo->mem.size; 536 + if (abo->internal) 537 + client->total_int_bo_usage += abo->mem.size; 538 + } 539 + 540 + static void 541 + amdxdna_gem_del_bo_usage(struct amdxdna_gem_obj *abo) 542 + { 543 + struct amdxdna_client *client = abo->client; 544 + 545 + if (amdxdna_gem_skip_bo_usage(abo)) 546 + return; 547 + 548 + guard(mutex)(&client->mm_lock); 549 + 550 + client->total_bo_usage -= abo->mem.size; 551 + if (abo->internal) 552 + client->total_int_bo_usage -= abo->mem.size; 553 + } 554 + 516 555 static void amdxdna_gem_obj_free(struct drm_gem_object *gobj) 517 556 { 518 557 struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); 519 558 struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 520 - 521 - XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, amdxdna_gem_dev_addr(abo)); 522 559 523 560 amdxdna_hmm_unregister(abo, NULL); 524 561 flush_workqueue(xdna->notifier_wq); ··· 590 543 int ret; 591 544 592 545 guard(mutex)(&abo->lock); 546 + abo->open_ref++; 593 547 594 - if (!abo->client) 548 + if (abo->open_ref == 1) { 549 + /* Attached to the client when first opened by it. */ 595 550 abo->client = filp->driver_priv; 551 + amdxdna_gem_add_bo_usage(abo); 552 + } 596 553 if (amdxdna_iova_on(xdna)) { 597 554 ret = amdxdna_iommu_map_bo(xdna, abo); 598 555 if (ret) ··· 604 553 } 605 554 606 555 return 0; 556 + } 557 + 558 + static void amdxdna_gem_obj_close(struct drm_gem_object *gobj, struct drm_file *filp) 559 + { 560 + struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); 561 + 562 + guard(mutex)(&abo->lock); 563 + abo->open_ref--; 564 + 565 + if (abo->open_ref == 0) { 566 + amdxdna_gem_del_bo_usage(abo); 567 + /* Detach from the client when last closed by it. */ 568 + abo->client = NULL; 569 + } 607 570 } 608 571 609 572 static int amdxdna_gem_dev_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map) ··· 640 575 static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = { 641 576 .free = amdxdna_gem_obj_free, 642 577 .open = amdxdna_gem_obj_open, 578 + .close = amdxdna_gem_obj_close, 643 579 .print_info = drm_gem_shmem_object_print_info, 644 580 .pin = drm_gem_shmem_object_pin, 645 581 .unpin = drm_gem_shmem_object_unpin, ··· 774 708 if (IS_ERR(abo)) 775 709 return ERR_CAST(abo); 776 710 777 - if (args->type == AMDXDNA_BO_DEV_HEAP) 711 + if (args->type == AMDXDNA_BO_DEV_HEAP) { 778 712 abo->type = AMDXDNA_BO_DEV_HEAP; 779 - else 713 + abo->internal = true; 714 + } else { 780 715 abo->type = AMDXDNA_BO_SHARE; 716 + abo->internal = args->type == AMDXDNA_BO_CMD; 717 + } 781 718 782 719 return abo; 783 720 } ··· 852 783 gobj = to_gobj(abo); 853 784 gobj->funcs = &amdxdna_gem_dev_obj_funcs; 854 785 abo->type = AMDXDNA_BO_DEV; 786 + abo->internal = true; 787 + /* 788 + * DEV BOs cannot be alive when client is gone, it's OK to 789 + * always establish the connection. 790 + */ 855 791 abo->client = client; 856 792 857 793 ret = amdxdna_gem_heap_alloc(abo); ··· 900 826 if (IS_ERR(abo)) 901 827 return PTR_ERR(abo); 902 828 903 - /* ready to publish object to userspace */ 829 + /* Ready to publish object to userspace and count for BO usage. */ 904 830 ret = drm_gem_handle_create(filp, to_gobj(abo), &args->handle); 905 831 if (ret) { 906 832 XDNA_ERR(xdna, "Create handle failed"); ··· 1059 985 put_obj: 1060 986 drm_gem_object_put(gobj); 1061 987 return ret; 988 + } 989 + 990 + int amdxdna_drm_get_bo_usage(struct drm_device *dev, struct amdxdna_drm_get_array *args) 991 + { 992 + size_t min_sz = min(args->element_size, sizeof(struct amdxdna_drm_bo_usage)); 993 + char __user *buf = u64_to_user_ptr(args->buffer); 994 + struct amdxdna_dev *xdna = to_xdna_dev(dev); 995 + struct amdxdna_client *tmp_client; 996 + struct amdxdna_drm_bo_usage tmp; 997 + 998 + drm_WARN_ON(dev, !mutex_is_locked(&xdna->dev_lock)); 999 + 1000 + if (args->num_element != 1) 1001 + return -EINVAL; 1002 + 1003 + if (copy_from_user(&tmp, buf, min_sz)) 1004 + return -EFAULT; 1005 + 1006 + if (!tmp.pid) 1007 + return -EINVAL; 1008 + 1009 + tmp.total_usage = 0; 1010 + tmp.internal_usage = 0; 1011 + tmp.heap_usage = 0; 1012 + 1013 + list_for_each_entry(tmp_client, &xdna->client_list, node) { 1014 + if (tmp.pid != tmp_client->pid) 1015 + continue; 1016 + 1017 + mutex_lock(&tmp_client->mm_lock); 1018 + tmp.total_usage += tmp_client->total_bo_usage; 1019 + tmp.internal_usage += tmp_client->total_int_bo_usage; 1020 + tmp.heap_usage += tmp_client->heap_usage; 1021 + mutex_unlock(&tmp_client->mm_lock); 1022 + } 1023 + 1024 + if (copy_to_user(buf, &tmp, min_sz)) 1025 + return -EFAULT; 1026 + 1027 + return 0; 1062 1028 }
+6 -1
drivers/accel/amdxdna/amdxdna_gem.h
··· 41 41 struct amdxdna_client *client; 42 42 u8 type; 43 43 bool pinned; 44 - struct mutex lock; /* Protects: pinned, mem.kva */ 44 + struct mutex lock; /* Protects: pinned, mem.kva, open_ref */ 45 45 struct amdxdna_mem mem; 46 + int open_ref; 46 47 47 48 /* Below members are initialized when needed */ 48 49 struct drm_mm mm; /* For AMDXDNA_BO_DEV_HEAP */ ··· 51 50 u32 assigned_hwctx; 52 51 struct dma_buf *dma_buf; 53 52 struct dma_buf_attachment *attach; 53 + 54 + /* True, if BO is managed by XRT, not application */ 55 + bool internal; 54 56 }; 55 57 56 58 #define to_gobj(obj) (&(obj)->base.base) ··· 102 98 int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); 103 99 int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); 104 100 int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); 101 + int amdxdna_drm_get_bo_usage(struct drm_device *dev, struct amdxdna_drm_get_array *args); 105 102 106 103 #endif /* _AMDXDNA_GEM_H_ */
+4 -2
drivers/accel/amdxdna/amdxdna_pci_drv.c
··· 36 36 * 0.5: Support getting telemetry data 37 37 * 0.6: Support preemption 38 38 * 0.7: Support getting power and utilization data 39 + * 0.8: Support BO usage query 39 40 */ 40 41 #define AMDXDNA_DRIVER_MAJOR 0 41 - #define AMDXDNA_DRIVER_MINOR 7 42 + #define AMDXDNA_DRIVER_MINOR 8 42 43 43 44 /* 44 45 * Bind the driver base on (vendor_id, device_id) pair and later use the ··· 121 120 amdxdna_hwctx_remove_all(client); 122 121 xa_destroy(&client->hwctx_xa); 123 122 cleanup_srcu_struct(&client->hwctx_srcu); 124 - mutex_destroy(&client->mm_lock); 125 123 126 124 if (client->dev_heap) 127 125 drm_gem_object_put(to_gobj(client->dev_heap)); 126 + 127 + mutex_destroy(&client->mm_lock); 128 128 129 129 if (!IS_ERR_OR_NULL(client->sva)) 130 130 iommu_sva_unbind_device(client->sva);
+4
drivers/accel/amdxdna/amdxdna_pci_drv.h
··· 138 138 struct iommu_sva *sva; 139 139 int pasid; 140 140 struct mm_struct *mm; 141 + 142 + size_t heap_usage; 143 + size_t total_bo_usage; 144 + size_t total_int_bo_usage; 141 145 }; 142 146 143 147 #define amdxdna_for_each_hwctx(client, hwctx_id, entry) \
+35
include/uapi/drm/amdxdna_accel.h
··· 591 591 __u64 ex_err_code; 592 592 }; 593 593 594 + /** 595 + * struct amdxdna_drm_bo_usage - all types of BO usage 596 + * BOs managed by XRT/SHIM/driver is counted as internal. 597 + * Others are counted as external which are managed by applications. 598 + * 599 + * Among all types of BOs: 600 + * AMDXDNA_BO_DEV_HEAP - is counted for internal. 601 + * AMDXDNA_BO_SHARE - is counted for external. 602 + * AMDXDNA_BO_CMD - is counted for internal. 603 + * AMDXDNA_BO_DEV - is counted by heap_usage only, not internal 604 + * or external. It does not add to the total memory 605 + * footprint since its mem comes from heap which is 606 + * already counted as internal. 607 + */ 608 + struct amdxdna_drm_bo_usage { 609 + /** @pid: The ID of the process to query from. */ 610 + __s64 pid; 611 + /** @total_usage: Total BO size used by process. */ 612 + __u64 total_usage; 613 + /** @internal_usage: Total internal BO size used by process. */ 614 + __u64 internal_usage; 615 + /** @heap_usage: Total device BO size used by process. */ 616 + __u64 heap_usage; 617 + }; 618 + 619 + /* 620 + * Supported params in struct amdxdna_drm_get_array 621 + */ 594 622 #define DRM_AMDXDNA_HW_CONTEXT_ALL 0 595 623 #define DRM_AMDXDNA_HW_LAST_ASYNC_ERR 2 624 + #define DRM_AMDXDNA_BO_USAGE 6 596 625 597 626 /** 598 627 * struct amdxdna_drm_get_array - Get information array. ··· 634 605 * 635 606 * %DRM_AMDXDNA_HW_CONTEXT_ALL: 636 607 * Returns all created hardware contexts. 608 + * 609 + * %DRM_AMDXDNA_HW_LAST_ASYNC_ERR: 610 + * Returns last async error. 611 + * 612 + * %DRM_AMDXDNA_BO_USAGE: 613 + * Returns usage of heap/internal/external BOs. 637 614 */ 638 615 __u32 param; 639 616 /**