diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-03-27 12:45:28 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-03-27 12:45:54 +1000 |
| commit | cf2d1b5b0158a42182b50e8c797ba171c995c726 (patch) | |
| tree | ff4a692455052ea76a2df9a4af8cc53a13c883e8 /drivers/accel | |
| parent | 72b585da5587f79cb72c89e8a88ae3d2bcbbceb3 (diff) | |
| parent | 3bce3fdd1ff2ba242f76ab66659fff27207299f1 (diff) | |
Merge tag 'drm-misc-next-2026-03-26' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v7.1:
UAPI Changes:
amdxdna:
- support per-BO memory-usage queries
docs:
- Improve UAPI documentation
panthor:
- extend timestamp query with flags
Core Changes:
edid:
- provide enum drm_output_color_format; mass-convert drivers
gem-dma:
- use drm_dev_dma_dev() for DMA mappings
- set VM_DONTDUMP on mmap
mipi-dbi:
- drop simple-display; mass-convert drivers
prime:
- use drm_dev_dma_dev() for DMA mappings
ttm:
- improve handling of gfp_retry_mayfail
Driver Changes:
amdgpu:
- use atomic_create_state for private_obj
amdxdna:
- refactor GEM implementation
- fixes
bridge:
- provide clear-and-put helper for reliable cleanup
- analogix_dp: Use DP helpers for link training
- lontium-lt8713sx: Fix 64-bit division and Kconfig
- samsung-dsim: Use clear-and-put
imagination:
- improve power-off sequence
- support context-reset notification from firmware
komeda:
- support Arm China Linlon D6 plus DT bindings
mediatek:
- use drm_dev_dma_dev() for DMA mappings
panel:
- support Himax HX83121A plus DT bindings
- support JuTouch JT070TM041 plus DT bindings
- support Samsung S6E8FC0 plus DT bindings
- himax-hx83102c: support Samsung S6E8FC0 plus DT bindings; support backlight
- ili9806e: support Rocktech RK050HR345-CT106A plus DT bindings
- simple: support Tianma TM050RDH03 plus DT bindings
panthor:
- support various sources for timestamp queries
- fixes
omapdrm:
- use atomic_create_state for private_obj
rcar-du:
- fix suspend/resume wrt VSP interface
- fix leak of device_link
- clean up
sun4i:
- use drm_dev_dma_dev() for DMA mappings
tegra:
- use atomic_create_state for private_obj
xe:
- send 'none' recovery method for XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260326151812.GA76082@linux.fritz.box
Diffstat (limited to 'drivers/accel')
| -rw-r--r-- | drivers/accel/amdxdna/aie2_ctx.c | 8 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/aie2_message.c | 40 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/aie2_pci.c | 4 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_ctx.c | 23 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_ctx.h | 15 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_gem.c | 508 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_gem.h | 37 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_mailbox.c | 2 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_pci_drv.c | 8 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_pci_drv.h | 4 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_ubuf.c | 17 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_ubuf.h | 5 |
12 files changed, 396 insertions, 275 deletions
diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 1fa8e92d1449..286379d9511d 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -79,7 +79,7 @@ static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hw } ret = aie2_map_host_buf(xdna->dev_handle, hwctx->fw_ctx_id, - amdxdna_obj_dma_addr(hwctx->client, heap), + amdxdna_obj_dma_addr(heap), heap->mem.size); if (ret) { XDNA_ERR(xdna, "Map host buf failed, ret %d", ret); @@ -649,14 +649,14 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx) .size = MAX_CHAIN_CMDBUF_SIZE, }; - abo = amdxdna_drm_alloc_dev_bo(&xdna->ddev, &args, client->filp); + abo = amdxdna_drm_create_dev_bo(&xdna->ddev, &args, client->filp); if (IS_ERR(abo)) { ret = PTR_ERR(abo); goto free_cmd_bufs; } XDNA_DBG(xdna, "Command buf %d addr 0x%llx size 0x%lx", - i, abo->mem.dev_addr, abo->mem.size); + i, amdxdna_gem_dev_addr(abo), abo->mem.size); priv->cmd_buf[i] = abo; } @@ -697,7 +697,7 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx) } ret = aie2_map_host_buf(xdna->dev_handle, hwctx->fw_ctx_id, - amdxdna_obj_dma_addr(hwctx->client, heap), + amdxdna_obj_dma_addr(heap), heap->mem.size); if (ret) { XDNA_ERR(xdna, "Map host buffer failed, ret %d", ret); diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index 4ec591306854..a1c546c3e81c 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -56,6 +56,7 @@ void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, dma_addr_t *dma_addr) { struct amdxdna_dev *xdna = ndev->xdna; + void *vaddr; int order; *size = max(*size, SZ_8K); @@ -67,8 +68,12 @@ void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, if (amdxdna_iova_on(xdna)) return amdxdna_iommu_alloc(xdna, *size, dma_addr); - return dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, + vaddr = dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, DMA_FROM_DEVICE, GFP_KERNEL); + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; } void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size, @@ -548,10 +553,10 @@ int aie2_config_cu(struct amdxdna_hwctx *hwctx, } req.cfgs[i] = FIELD_PREP(AIE2_MSG_CFG_CU_PDI_ADDR, - abo->mem.dev_addr >> shift); + amdxdna_gem_dev_addr(abo) >> shift); req.cfgs[i] |= FIELD_PREP(AIE2_MSG_CFG_CU_FUNC, cu->cu_func); XDNA_DBG(xdna, "CU %d full addr 0x%llx, cfg 0x%x", i, - abo->mem.dev_addr, req.cfgs[i]); + amdxdna_gem_dev_addr(abo), req.cfgs[i]); drm_gem_object_put(gobj); } req.num_cus = hwctx->cus->num_cus; @@ -998,6 +1003,7 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx, struct mailbox_channel *chann = hwctx->priv->mbox_chann; struct amdxdna_client *client = hwctx->client; struct amdxdna_gem_obj *cmd_abo = job->cmd_bo; + void *cmd_buf = amdxdna_gem_vmap(cmdbuf_abo); struct amdxdna_dev *xdna = client->xdna; struct amdxdna_cmd_chain *payload; struct xdna_mailbox_msg msg; @@ -1009,6 +1015,9 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx, u32 op; u32 i; + if (!cmd_buf) + return -ENOMEM; + op = amdxdna_cmd_get_op(cmd_abo); payload = amdxdna_cmd_get_payload(cmd_abo, &payload_len); if (op != ERT_CMD_CHAIN) { @@ -1032,15 +1041,14 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx, u32 boh = (u32)(payload->data[i]); struct amdxdna_gem_obj *abo; - abo = amdxdna_gem_get_obj(client, boh, AMDXDNA_BO_CMD); + abo = amdxdna_gem_get_obj(client, boh, AMDXDNA_BO_SHARE); if (!abo) { XDNA_ERR(xdna, "Failed to find cmd BO %d", boh); return -ENOENT; } size = cmdbuf_abo->mem.size - offset; - ret = aie2_cmdlist_fill_slot(cmdbuf_abo->mem.kva + offset, - abo, &size, &op); + ret = aie2_cmdlist_fill_slot(cmd_buf + offset, abo, &size, &op); amdxdna_gem_put_obj(abo); if (ret) return ret; @@ -1050,16 +1058,16 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx, XDNA_DBG(xdna, "Total %d commands:", ccnt); print_hex_dump_debug("cmdbufs: ", DUMP_PREFIX_OFFSET, 16, 4, - cmdbuf_abo->mem.kva, offset, false); + cmd_buf, offset, false); msg.opcode = EXEC_MSG_OPS(xdna)->get_chain_msg_op(op); if (msg.opcode == MSG_OP_MAX_OPCODE) return -EOPNOTSUPP; /* The offset is the accumulated total size of the cmd buffer */ - EXEC_MSG_OPS(xdna)->init_chain_req(&req, cmdbuf_abo->mem.dev_addr, + EXEC_MSG_OPS(xdna)->init_chain_req(&req, amdxdna_gem_dev_addr(cmdbuf_abo), offset, ccnt); - drm_clflush_virt_range(cmdbuf_abo->mem.kva, offset); + drm_clflush_virt_range(cmd_buf, offset); msg.handle = job; msg.notify_cb = notify_cb; @@ -1084,27 +1092,29 @@ int aie2_cmdlist_single_execbuf(struct amdxdna_hwctx *hwctx, struct mailbox_channel *chann = hwctx->priv->mbox_chann; struct amdxdna_dev *xdna = hwctx->client->xdna; struct amdxdna_gem_obj *cmd_abo = job->cmd_bo; + void *cmd_buf = amdxdna_gem_vmap(cmdbuf_abo); struct xdna_mailbox_msg msg; union exec_chain_req req; u32 op = ERT_INVALID_CMD; size_t size; int ret; + if (!cmd_buf) + return -ENOMEM; + size = cmdbuf_abo->mem.size; - ret = aie2_cmdlist_fill_slot(cmdbuf_abo->mem.kva, cmd_abo, &size, &op); + ret = aie2_cmdlist_fill_slot(cmd_buf, cmd_abo, &size, &op); if (ret) return ret; - print_hex_dump_debug("cmdbuf: ", DUMP_PREFIX_OFFSET, 16, 4, - cmdbuf_abo->mem.kva, size, false); + print_hex_dump_debug("cmdbuf: ", DUMP_PREFIX_OFFSET, 16, 4, cmd_buf, size, false); msg.opcode = EXEC_MSG_OPS(xdna)->get_chain_msg_op(op); if (msg.opcode == MSG_OP_MAX_OPCODE) return -EOPNOTSUPP; - EXEC_MSG_OPS(xdna)->init_chain_req(&req, cmdbuf_abo->mem.dev_addr, - size, 1); - drm_clflush_virt_range(cmdbuf_abo->mem.kva, size); + EXEC_MSG_OPS(xdna)->init_chain_req(&req, amdxdna_gem_dev_addr(cmdbuf_abo), size, 1); + drm_clflush_virt_range(cmd_buf, size); msg.handle = job; msg.notify_cb = notify_cb; diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index 9e39bfe75971..f1ac4e00bd9f 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -865,6 +865,7 @@ static int aie2_hwctx_status_cb(struct amdxdna_hwctx *hwctx, void *arg) tmp->command_submissions = hwctx->priv->seq; tmp->command_completions = hwctx->priv->completed; tmp->pasid = hwctx->client->pasid; + tmp->heap_usage = hwctx->client->heap_usage; tmp->priority = hwctx->qos.priority; tmp->gops = hwctx->qos.gops; tmp->fps = hwctx->qos.fps; @@ -1148,6 +1149,9 @@ static int aie2_get_array(struct amdxdna_client *client, case DRM_AMDXDNA_HW_LAST_ASYNC_ERR: ret = aie2_get_array_async_error(xdna->dev_handle, args); break; + case DRM_AMDXDNA_BO_USAGE: + ret = amdxdna_drm_get_bo_usage(&xdna->ddev, args); + break; default: XDNA_ERR(xdna, "Not supported request parameter %u", args->param); ret = -EOPNOTSUPP; diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c index 2abe27dbd44d..ff6c3e8e5a15 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.c +++ b/drivers/accel/amdxdna/amdxdna_ctx.c @@ -95,9 +95,12 @@ int amdxdna_hwctx_walk(struct amdxdna_client *client, void *arg, void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size) { - struct amdxdna_cmd *cmd = abo->mem.kva; + struct amdxdna_cmd *cmd = amdxdna_gem_vmap(abo); u32 num_masks, count; + if (!cmd) + return NULL; + if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN) num_masks = 0; else @@ -119,10 +122,13 @@ void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size) u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo) { - struct amdxdna_cmd *cmd = abo->mem.kva; + struct amdxdna_cmd *cmd = amdxdna_gem_vmap(abo); u32 num_masks, i; u32 *cu_mask; + if (!cmd) + return INVALID_CU_IDX; + if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN) return INVALID_CU_IDX; @@ -142,19 +148,24 @@ int amdxdna_cmd_set_error(struct amdxdna_gem_obj *abo, void *err_data, size_t size) { struct amdxdna_client *client = job->hwctx->client; - struct amdxdna_cmd *cmd = abo->mem.kva; + struct amdxdna_cmd *cmd = amdxdna_gem_vmap(abo); struct amdxdna_cmd_chain *cc = NULL; + if (!cmd) + return -ENOMEM; + cmd->header &= ~AMDXDNA_CMD_STATE; cmd->header |= FIELD_PREP(AMDXDNA_CMD_STATE, error_state); if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN) { cc = amdxdna_cmd_get_payload(abo, NULL); cc->error_index = (cmd_idx < cc->command_count) ? cmd_idx : 0; - abo = amdxdna_gem_get_obj(client, cc->data[0], AMDXDNA_BO_CMD); + abo = amdxdna_gem_get_obj(client, cc->data[0], AMDXDNA_BO_SHARE); if (!abo) return -EINVAL; - cmd = abo->mem.kva; + cmd = amdxdna_gem_vmap(abo); + if (!cmd) + return -ENOMEM; } memset(cmd->data, 0xff, abo->mem.size - sizeof(*cmd)); @@ -474,7 +485,7 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, job->drv_cmd = drv_cmd; if (cmd_bo_hdl != AMDXDNA_INVALID_BO_HANDLE) { - job->cmd_bo = amdxdna_gem_get_obj(client, cmd_bo_hdl, AMDXDNA_BO_CMD); + job->cmd_bo = amdxdna_gem_get_obj(client, cmd_bo_hdl, AMDXDNA_BO_SHARE); if (!job->cmd_bo) { XDNA_ERR(xdna, "Failed to get cmd bo from %d", cmd_bo_hdl); ret = -EINVAL; diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h index 57db1527a93b..a8557d7e8923 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.h +++ b/drivers/accel/amdxdna/amdxdna_ctx.h @@ -158,7 +158,10 @@ struct amdxdna_sched_job { static inline u32 amdxdna_cmd_get_op(struct amdxdna_gem_obj *abo) { - struct amdxdna_cmd *cmd = abo->mem.kva; + struct amdxdna_cmd *cmd = amdxdna_gem_vmap(abo); + + if (!cmd) + return ERT_INVALID_CMD; return FIELD_GET(AMDXDNA_CMD_OPCODE, cmd->header); } @@ -166,7 +169,10 @@ amdxdna_cmd_get_op(struct amdxdna_gem_obj *abo) static inline void amdxdna_cmd_set_state(struct amdxdna_gem_obj *abo, enum ert_cmd_state s) { - struct amdxdna_cmd *cmd = abo->mem.kva; + struct amdxdna_cmd *cmd = amdxdna_gem_vmap(abo); + + if (!cmd) + return; cmd->header &= ~AMDXDNA_CMD_STATE; cmd->header |= FIELD_PREP(AMDXDNA_CMD_STATE, s); @@ -175,7 +181,10 @@ amdxdna_cmd_set_state(struct amdxdna_gem_obj *abo, enum ert_cmd_state s) static inline enum ert_cmd_state amdxdna_cmd_get_state(struct amdxdna_gem_obj *abo) { - struct amdxdna_cmd *cmd = abo->mem.kva; + struct amdxdna_cmd *cmd = amdxdna_gem_vmap(abo); + + if (!cmd) + return ERT_CMD_STATE_INVALID; return FIELD_GET(AMDXDNA_CMD_STATE, cmd->header); } diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c index d80cf164740c..238ee244d4a6 100644 --- a/drivers/accel/amdxdna/amdxdna_gem.c +++ b/drivers/accel/amdxdna/amdxdna_gem.c @@ -30,7 +30,6 @@ amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo) struct amdxdna_dev *xdna = client->xdna; struct amdxdna_mem *mem = &abo->mem; struct amdxdna_gem_obj *heap; - u64 offset; u32 align; int ret; @@ -42,7 +41,7 @@ amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo) goto unlock_out; } - if (heap->mem.userptr == AMDXDNA_INVALID_ADDR) { + if (amdxdna_gem_uva(heap) == AMDXDNA_INVALID_ADDR) { XDNA_ERR(xdna, "Invalid dev heap userptr"); ret = -EINVAL; goto unlock_out; @@ -64,10 +63,7 @@ amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo) goto unlock_out; } - mem->dev_addr = abo->mm_node.start; - offset = mem->dev_addr - heap->mem.dev_addr; - mem->userptr = heap->mem.userptr + offset; - mem->kva = heap->mem.kva + offset; + client->heap_usage += mem->size; drm_gem_object_get(to_gobj(heap)); @@ -78,25 +74,120 @@ unlock_out: } static void +amdxdna_gem_heap_free(struct amdxdna_gem_obj *abo) +{ + struct amdxdna_client *client = abo->client; + struct amdxdna_gem_obj *heap; + + mutex_lock(&client->mm_lock); + + drm_mm_remove_node(&abo->mm_node); + client->heap_usage -= abo->mem.size; + heap = client->dev_heap; + drm_gem_object_put(to_gobj(heap)); + + mutex_unlock(&client->mm_lock); +} + +static struct amdxdna_gem_obj * +amdxdna_gem_create_obj(struct drm_device *dev, size_t size) +{ + struct amdxdna_gem_obj *abo; + + abo = kzalloc_obj(*abo); + if (!abo) + return ERR_PTR(-ENOMEM); + + abo->pinned = false; + abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE; + mutex_init(&abo->lock); + + abo->mem.dma_addr = AMDXDNA_INVALID_ADDR; + abo->mem.uva = AMDXDNA_INVALID_ADDR; + abo->mem.size = size; + abo->open_ref = 0; + abo->internal = false; + INIT_LIST_HEAD(&abo->mem.umap_list); + + return abo; +} + +static void amdxdna_gem_destroy_obj(struct amdxdna_gem_obj *abo) { mutex_destroy(&abo->lock); kfree(abo); } -static void -amdxdna_gem_heap_free(struct amdxdna_gem_obj *abo) +/* + * Obtains a kernel virtual address on the BO (usually of small size). + * The mapping is established on the first call and stays valid until + * amdxdna_gem_vunmap() is called. + */ +void *amdxdna_gem_vmap(struct amdxdna_gem_obj *abo) { - struct amdxdna_gem_obj *heap; + struct iosys_map map = IOSYS_MAP_INIT_VADDR(NULL); + int ret; - mutex_lock(&abo->client->mm_lock); + if (abo->mem.kva) + return abo->mem.kva; - drm_mm_remove_node(&abo->mm_node); + /* The first call to get the kva, taking slow path. */ + guard(mutex)(&abo->lock); - heap = abo->client->dev_heap; - drm_gem_object_put(to_gobj(heap)); + if (!abo->mem.kva) { + ret = drm_gem_vmap(to_gobj(abo), &map); + if (ret) + XDNA_ERR(abo->client->xdna, "Vmap bo failed, ret %d", ret); + else + abo->mem.kva = map.vaddr; + } + return abo->mem.kva; +} + +/* + * Free mapping established through amdxdna_gem_vmap() + */ +static void amdxdna_gem_vunmap(struct amdxdna_gem_obj *abo) +{ + guard(mutex)(&abo->lock); - mutex_unlock(&abo->client->mm_lock); + if (abo->mem.kva) { + struct iosys_map map = IOSYS_MAP_INIT_VADDR(abo->mem.kva); + + drm_gem_vunmap(to_gobj(abo), &map); + abo->mem.kva = NULL; + } +} + +/* + * Obtain the user virtual address for accessing the BO. + * It can be used for device to access the BO when PASID is enabled. + */ +u64 amdxdna_gem_uva(struct amdxdna_gem_obj *abo) +{ + if (abo->type == AMDXDNA_BO_DEV) { + struct amdxdna_gem_obj *heap = abo->client->dev_heap; + u64 off = amdxdna_dev_bo_offset(abo); + + if (amdxdna_gem_uva(heap) != AMDXDNA_INVALID_ADDR) + return amdxdna_gem_uva(heap) + off; + return AMDXDNA_INVALID_ADDR; + } + + return abo->mem.uva; +} + +/* + * Obtain the address for device to access the BO. + */ +u64 amdxdna_gem_dev_addr(struct amdxdna_gem_obj *abo) +{ + if (abo->type == AMDXDNA_BO_DEV_HEAP) + return abo->client->xdna->dev_info->dev_mem_base; + if (abo->type == AMDXDNA_BO_DEV) + return abo->mm_node.start; + return amdxdna_obj_dma_addr(abo); } static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni, @@ -161,16 +252,19 @@ static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo, static void amdxdna_umap_release(struct kref *ref) { struct amdxdna_umap *mapp = container_of(ref, struct amdxdna_umap, refcnt); + struct amdxdna_gem_obj *abo = mapp->abo; struct vm_area_struct *vma = mapp->vma; struct amdxdna_dev *xdna; mmu_interval_notifier_remove(&mapp->notifier); - if (is_import_bo(mapp->abo) && vma->vm_file && vma->vm_file->f_mapping) + if (is_import_bo(abo) && vma->vm_file && vma->vm_file->f_mapping) mapping_clear_unevictable(vma->vm_file->f_mapping); xdna = to_xdna_dev(to_gobj(mapp->abo)->dev); down_write(&xdna->notifier_lock); list_del(&mapp->node); + if (list_empty(&abo->mem.umap_list)) + abo->mem.uva = AMDXDNA_INVALID_ADDR; up_write(&xdna->notifier_lock); kvfree(mapp->range.hmm_pfns); @@ -232,13 +326,13 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo, mapp->abo = abo; kref_init(&mapp->refcnt); - if (abo->mem.userptr == AMDXDNA_INVALID_ADDR) - abo->mem.userptr = addr; INIT_WORK(&mapp->hmm_unreg_work, amdxdna_hmm_unreg_work); if (is_import_bo(abo) && vma->vm_file && vma->vm_file->f_mapping) mapping_set_unevictable(vma->vm_file->f_mapping); down_write(&xdna->notifier_lock); + if (list_empty(&abo->mem.umap_list)) + abo->mem.uva = addr; list_add_tail(&mapp->node, &abo->mem.umap_list); up_write(&xdna->notifier_lock); @@ -256,10 +350,11 @@ static void amdxdna_gem_dev_obj_free(struct drm_gem_object *gobj) struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); - XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, abo->mem.dev_addr); + XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, amdxdna_gem_dev_addr(abo)); if (abo->pinned) amdxdna_gem_unpin(abo); + amdxdna_gem_vunmap(abo); amdxdna_gem_heap_free(abo); drm_gem_object_release(gobj); amdxdna_gem_destroy_obj(abo); @@ -390,35 +485,6 @@ static const struct dma_buf_ops amdxdna_dmabuf_ops = { .vunmap = drm_gem_dmabuf_vunmap, }; -static int amdxdna_gem_obj_vmap(struct amdxdna_gem_obj *abo, void **vaddr) -{ - struct iosys_map map = IOSYS_MAP_INIT_VADDR(NULL); - int ret; - - if (is_import_bo(abo)) - ret = dma_buf_vmap_unlocked(abo->dma_buf, &map); - else - ret = drm_gem_vmap(to_gobj(abo), &map); - - *vaddr = map.vaddr; - return ret; -} - -static void amdxdna_gem_obj_vunmap(struct amdxdna_gem_obj *abo) -{ - struct iosys_map map; - - if (!abo->mem.kva) - return; - - iosys_map_set_vaddr(&map, abo->mem.kva); - - if (is_import_bo(abo)) - dma_buf_vunmap_unlocked(abo->dma_buf, &map); - else - drm_gem_vunmap(to_gobj(abo), &map); -} - static struct dma_buf *amdxdna_gem_prime_export(struct drm_gem_object *gobj, int flags) { struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); @@ -447,13 +513,55 @@ static void amdxdna_imported_obj_free(struct amdxdna_gem_obj *abo) kfree(abo); } +static inline bool +amdxdna_gem_skip_bo_usage(struct amdxdna_gem_obj *abo) +{ + /* Do not count imported BOs since the buffer is not allocated by us. */ + if (is_import_bo(abo)) + return true; + + /* Already counted as part of HEAP BO */ + if (abo->type == AMDXDNA_BO_DEV) + return true; + + return false; +} + +static void +amdxdna_gem_add_bo_usage(struct amdxdna_gem_obj *abo) +{ + struct amdxdna_client *client = abo->client; + + if (amdxdna_gem_skip_bo_usage(abo)) + return; + + guard(mutex)(&client->mm_lock); + + client->total_bo_usage += abo->mem.size; + if (abo->internal) + client->total_int_bo_usage += abo->mem.size; +} + +static void +amdxdna_gem_del_bo_usage(struct amdxdna_gem_obj *abo) +{ + struct amdxdna_client *client = abo->client; + + if (amdxdna_gem_skip_bo_usage(abo)) + return; + + guard(mutex)(&client->mm_lock); + + client->total_bo_usage -= abo->mem.size; + if (abo->internal) + client->total_int_bo_usage -= abo->mem.size; +} + static void amdxdna_gem_obj_free(struct drm_gem_object *gobj) { struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); - XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, abo->mem.dev_addr); - amdxdna_hmm_unregister(abo, NULL); flush_workqueue(xdna->notifier_wq); @@ -463,15 +571,16 @@ static void amdxdna_gem_obj_free(struct drm_gem_object *gobj) if (abo->type == AMDXDNA_BO_DEV_HEAP) drm_mm_takedown(&abo->mm); - amdxdna_gem_obj_vunmap(abo); + if (amdxdna_iova_on(xdna)) + amdxdna_iommu_unmap_bo(xdna, abo); + + amdxdna_gem_vunmap(abo); mutex_destroy(&abo->lock); - if (is_import_bo(abo)) { + if (is_import_bo(abo)) amdxdna_imported_obj_free(abo); - return; - } - - drm_gem_shmem_free(&abo->base); + else + drm_gem_shmem_free(&abo->base); } static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *filp) @@ -481,37 +590,51 @@ static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *fi int ret; guard(mutex)(&abo->lock); - if (abo->ref) { - abo->ref++; - return 0; - } + abo->open_ref++; + if (abo->open_ref == 1) { + /* Attached to the client when first opened by it. */ + abo->client = filp->driver_priv; + amdxdna_gem_add_bo_usage(abo); + } if (amdxdna_iova_on(xdna)) { ret = amdxdna_iommu_map_bo(xdna, abo); if (ret) return ret; } - abo->ref++; return 0; } static void amdxdna_gem_obj_close(struct drm_gem_object *gobj, struct drm_file *filp) { - struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev); struct amdxdna_gem_obj *abo = to_xdna_obj(gobj); guard(mutex)(&abo->lock); - abo->ref--; - if (abo->ref) - return; + abo->open_ref--; - if (amdxdna_iova_on(xdna)) - amdxdna_iommu_unmap_bo(xdna, abo); + if (abo->open_ref == 0) { + amdxdna_gem_del_bo_usage(abo); + /* Detach from the client when last closed by it. */ + abo->client = NULL; + } +} + +static int amdxdna_gem_dev_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map) +{ + struct amdxdna_gem_obj *abo = to_xdna_obj(obj); + void *base = amdxdna_gem_vmap(abo->client->dev_heap); + u64 offset = amdxdna_dev_bo_offset(abo); + + if (!base) + return -ENOMEM; + iosys_map_set_vaddr(map, base + offset); + return 0; } static const struct drm_gem_object_funcs amdxdna_gem_dev_obj_funcs = { .free = amdxdna_gem_dev_obj_free, + .vmap = amdxdna_gem_dev_obj_vmap, }; static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = { @@ -529,31 +652,9 @@ static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = { .export = amdxdna_gem_prime_export, }; -static struct amdxdna_gem_obj * -amdxdna_gem_create_obj(struct drm_device *dev, size_t size) -{ - struct amdxdna_gem_obj *abo; - - abo = kzalloc_obj(*abo); - if (!abo) - return ERR_PTR(-ENOMEM); - - abo->pinned = false; - abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE; - mutex_init(&abo->lock); - - abo->mem.userptr = AMDXDNA_INVALID_ADDR; - abo->mem.dev_addr = AMDXDNA_INVALID_ADDR; - abo->mem.dma_addr = AMDXDNA_INVALID_ADDR; - abo->mem.size = size; - INIT_LIST_HEAD(&abo->mem.umap_list); - - return abo; -} - /* For drm_driver->gem_create_object callback */ struct drm_gem_object * -amdxdna_gem_create_object_cb(struct drm_device *dev, size_t size) +amdxdna_gem_create_shmem_object_cb(struct drm_device *dev, size_t size) { struct amdxdna_gem_obj *abo; @@ -567,8 +668,9 @@ amdxdna_gem_create_object_cb(struct drm_device *dev, size_t size) } static struct amdxdna_gem_obj * -amdxdna_gem_create_shmem_object(struct drm_device *dev, size_t size) +amdxdna_gem_create_shmem_object(struct drm_device *dev, struct amdxdna_drm_create_bo *args) { + size_t size = args->size; struct drm_gem_shmem_object *shmem = drm_gem_shmem_create(dev, size); if (IS_ERR(shmem)) @@ -582,7 +684,6 @@ static struct amdxdna_gem_obj * amdxdna_gem_create_ubuf_object(struct drm_device *dev, struct amdxdna_drm_create_bo *args) { struct amdxdna_dev *xdna = to_xdna_dev(dev); - enum amdxdna_ubuf_flag flags = 0; struct amdxdna_drm_va_tbl va_tbl; struct drm_gem_object *gobj; struct dma_buf *dma_buf; @@ -593,10 +694,7 @@ amdxdna_gem_create_ubuf_object(struct drm_device *dev, struct amdxdna_drm_create } if (va_tbl.num_entries) { - if (args->type == AMDXDNA_BO_CMD) - flags |= AMDXDNA_UBUF_FLAG_MAP_DMA; - - dma_buf = amdxdna_get_ubuf(dev, flags, va_tbl.num_entries, + dma_buf = amdxdna_get_ubuf(dev, va_tbl.num_entries, u64_to_user_ptr(args->vaddr + sizeof(va_tbl))); } else { dma_buf = dma_buf_get(va_tbl.dmabuf_fd); @@ -616,18 +714,6 @@ amdxdna_gem_create_ubuf_object(struct drm_device *dev, struct amdxdna_drm_create return to_xdna_obj(gobj); } -static struct amdxdna_gem_obj * -amdxdna_gem_create_object(struct drm_device *dev, - struct amdxdna_drm_create_bo *args) -{ - size_t aligned_sz = PAGE_ALIGN(args->size); - - if (args->vaddr) - return amdxdna_gem_create_ubuf_object(dev, args); - - return amdxdna_gem_create_shmem_object(dev, aligned_sz); -} - struct drm_gem_object * amdxdna_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf) { @@ -660,7 +746,8 @@ amdxdna_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf) abo = to_xdna_obj(gobj); abo->attach = attach; abo->dma_buf = dma_buf; - abo->type = AMDXDNA_BO_SHMEM; + abo->type = AMDXDNA_BO_SHARE; + gobj->resv = dma_buf->resv; return gobj; @@ -675,93 +762,101 @@ put_buf: } static struct amdxdna_gem_obj * -amdxdna_drm_alloc_shmem(struct drm_device *dev, - struct amdxdna_drm_create_bo *args, - struct drm_file *filp) +amdxdna_drm_create_share_bo(struct drm_device *dev, + struct amdxdna_drm_create_bo *args, struct drm_file *filp) { - struct amdxdna_client *client = filp->driver_priv; struct amdxdna_gem_obj *abo; - abo = amdxdna_gem_create_object(dev, args); + if (args->vaddr) + abo = amdxdna_gem_create_ubuf_object(dev, args); + else + abo = amdxdna_gem_create_shmem_object(dev, args); if (IS_ERR(abo)) return ERR_CAST(abo); - abo->client = client; - abo->type = AMDXDNA_BO_SHMEM; + if (args->type == AMDXDNA_BO_DEV_HEAP) { + abo->type = AMDXDNA_BO_DEV_HEAP; + abo->internal = true; + } else { + abo->type = AMDXDNA_BO_SHARE; + abo->internal = args->type == AMDXDNA_BO_CMD; + } return abo; } static struct amdxdna_gem_obj * -amdxdna_drm_create_dev_heap(struct drm_device *dev, - struct amdxdna_drm_create_bo *args, - struct drm_file *filp) +amdxdna_drm_create_dev_heap_bo(struct drm_device *dev, + struct amdxdna_drm_create_bo *args, struct drm_file *filp) { struct amdxdna_client *client = filp->driver_priv; struct amdxdna_dev *xdna = to_xdna_dev(dev); struct amdxdna_gem_obj *abo; int ret; - if (args->size > xdna->dev_info->dev_mem_size) { - XDNA_DBG(xdna, "Invalid dev heap size 0x%llx, limit 0x%lx", + WARN_ON(!is_power_of_2(xdna->dev_info->dev_mem_size)); + XDNA_DBG(xdna, "Requested dev heap size 0x%llx", args->size); + if (!args->size || !IS_ALIGNED(args->size, xdna->dev_info->dev_mem_size)) { + XDNA_ERR(xdna, "The dev heap size 0x%llx is not multiple of 0x%lx", args->size, xdna->dev_info->dev_mem_size); return ERR_PTR(-EINVAL); } + /* HEAP BO is a special case of SHARE BO. */ + abo = amdxdna_drm_create_share_bo(dev, args, filp); + if (IS_ERR(abo)) + return ERR_CAST(abo); + + /* Set up heap for this client. */ mutex_lock(&client->mm_lock); + if (client->dev_heap) { XDNA_DBG(client->xdna, "dev heap is already created"); ret = -EBUSY; goto mm_unlock; } - - abo = amdxdna_gem_create_object(dev, args); - if (IS_ERR(abo)) { - ret = PTR_ERR(abo); - goto mm_unlock; - } - - abo->type = AMDXDNA_BO_DEV_HEAP; - abo->client = client; - abo->mem.dev_addr = client->xdna->dev_info->dev_mem_base; - drm_mm_init(&abo->mm, abo->mem.dev_addr, abo->mem.size); - - ret = amdxdna_gem_obj_vmap(abo, &abo->mem.kva); - if (ret) { - XDNA_ERR(xdna, "Vmap heap bo failed, ret %d", ret); - goto release_obj; - } - client->dev_heap = abo; drm_gem_object_get(to_gobj(abo)); + + drm_mm_init(&abo->mm, xdna->dev_info->dev_mem_base, abo->mem.size); + mutex_unlock(&client->mm_lock); return abo; -release_obj: - drm_gem_object_put(to_gobj(abo)); mm_unlock: mutex_unlock(&client->mm_lock); + drm_gem_object_put(to_gobj(abo)); return ERR_PTR(ret); } struct amdxdna_gem_obj * -amdxdna_drm_alloc_dev_bo(struct drm_device *dev, - struct amdxdna_drm_create_bo *args, - struct drm_file *filp) +amdxdna_drm_create_dev_bo(struct drm_device *dev, + struct amdxdna_drm_create_bo *args, struct drm_file *filp) { + size_t aligned_sz = PAGE_ALIGN(args->size); struct amdxdna_client *client = filp->driver_priv; struct amdxdna_dev *xdna = to_xdna_dev(dev); - size_t aligned_sz = PAGE_ALIGN(args->size); struct amdxdna_gem_obj *abo; + struct drm_gem_object *gobj; int ret; - abo = amdxdna_gem_create_obj(&xdna->ddev, aligned_sz); + if (!aligned_sz) { + XDNA_ERR(xdna, "Invalid BO size 0x%llx", args->size); + return ERR_PTR(-EINVAL); + } + + abo = amdxdna_gem_create_obj(dev, aligned_sz); if (IS_ERR(abo)) return abo; - - to_gobj(abo)->funcs = &amdxdna_gem_dev_obj_funcs; + gobj = to_gobj(abo); + gobj->funcs = &amdxdna_gem_dev_obj_funcs; abo->type = AMDXDNA_BO_DEV; + abo->internal = true; + /* + * DEV BOs cannot be alive when client is gone, it's OK to + * always establish the connection. + */ abo->client = client; ret = amdxdna_gem_heap_alloc(abo); @@ -770,31 +865,7 @@ amdxdna_drm_alloc_dev_bo(struct drm_device *dev, amdxdna_gem_destroy_obj(abo); return ERR_PTR(ret); } - - drm_gem_private_object_init(&xdna->ddev, to_gobj(abo), aligned_sz); - - return abo; -} - -static struct amdxdna_gem_obj * -amdxdna_drm_create_cmd_bo(struct drm_device *dev, - struct amdxdna_drm_create_bo *args, - struct drm_file *filp) -{ - struct amdxdna_dev *xdna = to_xdna_dev(dev); - struct amdxdna_gem_obj *abo; - - if (args->size < sizeof(struct amdxdna_cmd)) { - XDNA_DBG(xdna, "Command BO size 0x%llx too small", args->size); - return ERR_PTR(-EINVAL); - } - - abo = amdxdna_gem_create_object(dev, args); - if (IS_ERR(abo)) - return ERR_CAST(abo); - - abo->type = AMDXDNA_BO_CMD; - abo->client = filp->driver_priv; + drm_gem_private_object_init(dev, gobj, aligned_sz); return abo; } @@ -812,17 +883,16 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f XDNA_DBG(xdna, "BO arg type %d vaddr 0x%llx size 0x%llx flags 0x%llx", args->type, args->vaddr, args->size, args->flags); switch (args->type) { - case AMDXDNA_BO_SHMEM: - abo = amdxdna_drm_alloc_shmem(dev, args, filp); + case AMDXDNA_BO_CMD: + fallthrough; + case AMDXDNA_BO_SHARE: + abo = amdxdna_drm_create_share_bo(dev, args, filp); break; case AMDXDNA_BO_DEV_HEAP: - abo = amdxdna_drm_create_dev_heap(dev, args, filp); + abo = amdxdna_drm_create_dev_heap_bo(dev, args, filp); break; case AMDXDNA_BO_DEV: - abo = amdxdna_drm_alloc_dev_bo(dev, args, filp); - break; - case AMDXDNA_BO_CMD: - abo = amdxdna_drm_create_cmd_bo(dev, args, filp); + abo = amdxdna_drm_create_dev_bo(dev, args, filp); break; default: return -EINVAL; @@ -830,7 +900,7 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f if (IS_ERR(abo)) return PTR_ERR(abo); - /* ready to publish object to userspace */ + /* Ready to publish object to userspace and count for BO usage. */ ret = drm_gem_handle_create(filp, to_gobj(abo), &args->handle); if (ret) { XDNA_ERR(xdna, "Create handle failed"); @@ -838,8 +908,8 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f } XDNA_DBG(xdna, "BO hdl %d type %d userptr 0x%llx xdna_addr 0x%llx size 0x%lx", - args->handle, args->type, abo->mem.userptr, - abo->mem.dev_addr, abo->mem.size); + args->handle, args->type, amdxdna_gem_uva(abo), + amdxdna_gem_dev_addr(abo), abo->mem.size); put_obj: /* Dereference object reference. Handle holds it now. */ drm_gem_object_put(to_gobj(abo)); @@ -890,38 +960,19 @@ void amdxdna_gem_unpin(struct amdxdna_gem_obj *abo) struct amdxdna_gem_obj *amdxdna_gem_get_obj(struct amdxdna_client *client, u32 bo_hdl, u8 bo_type) { - struct amdxdna_dev *xdna = client->xdna; struct amdxdna_gem_obj *abo; struct drm_gem_object *gobj; - int ret; gobj = drm_gem_object_lookup(client->filp, bo_hdl); if (!gobj) { - XDNA_DBG(xdna, "Can not find bo %d", bo_hdl); + XDNA_DBG(client->xdna, "Can not find bo %d", bo_hdl); return NULL; } abo = to_xdna_obj(gobj); - if (bo_type != AMDXDNA_BO_INVALID && abo->type != bo_type) - goto put_obj; - - if (bo_type != AMDXDNA_BO_CMD || abo->mem.kva) + if (bo_type == AMDXDNA_BO_INVALID || abo->type == bo_type) return abo; - if (abo->mem.size > SZ_32K) { - XDNA_ERR(xdna, "Cmd bo is too big %ld", abo->mem.size); - goto put_obj; - } - - ret = amdxdna_gem_obj_vmap(abo, &abo->mem.kva); - if (ret) { - XDNA_ERR(xdna, "Vmap cmd bo failed, ret %d", ret); - goto put_obj; - } - - return abo; - -put_obj: drm_gem_object_put(gobj); return NULL; } @@ -944,11 +995,8 @@ int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm } abo = to_xdna_obj(gobj); - args->vaddr = abo->mem.userptr; - if (abo->mem.dev_addr != AMDXDNA_INVALID_ADDR) - args->xdna_addr = abo->mem.dev_addr; - else - args->xdna_addr = abo->mem.dma_addr; + args->vaddr = amdxdna_gem_uva(abo); + args->xdna_addr = amdxdna_gem_dev_addr(abo); if (abo->type != AMDXDNA_BO_DEV) args->map_offset = drm_vma_node_offset_addr(&gobj->vma_node); @@ -993,8 +1041,8 @@ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev, if (is_import_bo(abo)) drm_clflush_sg(abo->base.sgt); - else if (abo->mem.kva) - drm_clflush_virt_range(abo->mem.kva + args->offset, args->size); + else if (amdxdna_gem_vmap(abo)) + drm_clflush_virt_range(amdxdna_gem_vmap(abo) + args->offset, args->size); else if (abo->base.pages) drm_clflush_pages(abo->base.pages, gobj->size >> PAGE_SHIFT); else @@ -1012,3 +1060,43 @@ put_obj: drm_gem_object_put(gobj); return ret; } + +int amdxdna_drm_get_bo_usage(struct drm_device *dev, struct amdxdna_drm_get_array *args) +{ + size_t min_sz = min(args->element_size, sizeof(struct amdxdna_drm_bo_usage)); + char __user *buf = u64_to_user_ptr(args->buffer); + struct amdxdna_dev *xdna = to_xdna_dev(dev); + struct amdxdna_client *tmp_client; + struct amdxdna_drm_bo_usage tmp; + + drm_WARN_ON(dev, !mutex_is_locked(&xdna->dev_lock)); + + if (args->num_element != 1) + return -EINVAL; + + if (copy_from_user(&tmp, buf, min_sz)) + return -EFAULT; + + if (!tmp.pid) + return -EINVAL; + + tmp.total_usage = 0; + tmp.internal_usage = 0; + tmp.heap_usage = 0; + + list_for_each_entry(tmp_client, &xdna->client_list, node) { + if (tmp.pid != tmp_client->pid) + continue; + + mutex_lock(&tmp_client->mm_lock); + tmp.total_usage += tmp_client->total_bo_usage; + tmp.internal_usage += tmp_client->total_int_bo_usage; + tmp.heap_usage += tmp_client->heap_usage; + mutex_unlock(&tmp_client->mm_lock); + } + + if (copy_to_user(buf, &tmp, min_sz)) + return -EFAULT; + + return 0; +} diff --git a/drivers/accel/amdxdna/amdxdna_gem.h b/drivers/accel/amdxdna/amdxdna_gem.h index fbeb622e7cf9..4fc48a1189d2 100644 --- a/drivers/accel/amdxdna/amdxdna_gem.h +++ b/drivers/accel/amdxdna/amdxdna_gem.h @@ -24,15 +24,16 @@ struct amdxdna_umap { }; struct amdxdna_mem { - u64 userptr; void *kva; - u64 dev_addr; u64 dma_addr; size_t size; - struct page **pages; - u32 nr_pages; struct list_head umap_list; bool map_invalid; + /* + * Cache the first mmap uva as PASID addr, which can be accessed by driver + * without taking notifier_lock. + */ + u64 uva; }; struct amdxdna_gem_obj { @@ -40,16 +41,19 @@ struct amdxdna_gem_obj { struct amdxdna_client *client; u8 type; bool pinned; - struct mutex lock; /* Protects: pinned */ + struct mutex lock; /* Protects: pinned, mem.kva, open_ref */ struct amdxdna_mem mem; - u32 ref; + int open_ref; - /* Below members is uninitialized when needed */ + /* Below members are initialized when needed */ struct drm_mm mm; /* For AMDXDNA_BO_DEV_HEAP */ struct drm_mm_node mm_node; /* For AMDXDNA_BO_DEV */ u32 assigned_hwctx; struct dma_buf *dma_buf; struct dma_buf_attachment *attach; + + /* True, if BO is managed by XRT, not application */ + bool internal; }; #define to_gobj(obj) (&(obj)->base.base) @@ -67,27 +71,29 @@ static inline void amdxdna_gem_put_obj(struct amdxdna_gem_obj *abo) drm_gem_object_put(to_gobj(abo)); } +void *amdxdna_gem_vmap(struct amdxdna_gem_obj *abo); +u64 amdxdna_gem_uva(struct amdxdna_gem_obj *abo); +u64 amdxdna_gem_dev_addr(struct amdxdna_gem_obj *abo); + static inline u64 amdxdna_dev_bo_offset(struct amdxdna_gem_obj *abo) { - return abo->mem.dev_addr - abo->client->dev_heap->mem.dev_addr; + return amdxdna_gem_dev_addr(abo) - amdxdna_gem_dev_addr(abo->client->dev_heap); } -static inline u64 amdxdna_obj_dma_addr(struct amdxdna_client *client, - struct amdxdna_gem_obj *abo) +static inline u64 amdxdna_obj_dma_addr(struct amdxdna_gem_obj *abo) { - return amdxdna_pasid_on(client) ? abo->mem.userptr : abo->mem.dma_addr; + return amdxdna_pasid_on(abo->client) ? amdxdna_gem_uva(abo) : abo->mem.dma_addr; } void amdxdna_umap_put(struct amdxdna_umap *mapp); struct drm_gem_object * -amdxdna_gem_create_object_cb(struct drm_device *dev, size_t size); +amdxdna_gem_create_shmem_object_cb(struct drm_device *dev, size_t size); struct drm_gem_object * amdxdna_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf); struct amdxdna_gem_obj * -amdxdna_drm_alloc_dev_bo(struct drm_device *dev, - struct amdxdna_drm_create_bo *args, - struct drm_file *filp); +amdxdna_drm_create_dev_bo(struct drm_device *dev, + struct amdxdna_drm_create_bo *args, struct drm_file *filp); int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo); int amdxdna_gem_pin(struct amdxdna_gem_obj *abo); @@ -96,5 +102,6 @@ void amdxdna_gem_unpin(struct amdxdna_gem_obj *abo); int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int amdxdna_drm_get_bo_usage(struct drm_device *dev, struct amdxdna_drm_get_array *args); #endif /* _AMDXDNA_GEM_H_ */ diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c index 46d844a73a94..e681a090752d 100644 --- a/drivers/accel/amdxdna/amdxdna_mailbox.c +++ b/drivers/accel/amdxdna/amdxdna_mailbox.c @@ -499,7 +499,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann, int ret; if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) { - pr_err("Ring buf size must be power of 2"); + pr_err("Ring buf size must be power of 2\n"); return -EINVAL; } diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index 5143b8c9b92b..b50a7d1f8a11 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -36,9 +36,10 @@ MODULE_FIRMWARE("amdnpu/17f0_11/npu_7.sbin"); * 0.5: Support getting telemetry data * 0.6: Support preemption * 0.7: Support getting power and utilization data + * 0.8: Support BO usage query */ #define AMDXDNA_DRIVER_MAJOR 0 -#define AMDXDNA_DRIVER_MINOR 7 +#define AMDXDNA_DRIVER_MINOR 8 /* * Bind the driver base on (vendor_id, device_id) pair and later use the @@ -120,11 +121,12 @@ static void amdxdna_client_cleanup(struct amdxdna_client *client) amdxdna_hwctx_remove_all(client); xa_destroy(&client->hwctx_xa); cleanup_srcu_struct(&client->hwctx_srcu); - mutex_destroy(&client->mm_lock); if (client->dev_heap) drm_gem_object_put(to_gobj(client->dev_heap)); + mutex_destroy(&client->mm_lock); + if (!IS_ERR_OR_NULL(client->sva)) iommu_sva_unbind_device(client->sva); mmdrop(client->mm); @@ -245,7 +247,7 @@ const struct drm_driver amdxdna_drm_drv = { .ioctls = amdxdna_drm_ioctls, .num_ioctls = ARRAY_SIZE(amdxdna_drm_ioctls), - .gem_create_object = amdxdna_gem_create_object_cb, + .gem_create_object = amdxdna_gem_create_shmem_object_cb, .gem_prime_import = amdxdna_gem_prime_import, }; diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h index e91d14ae5190..0661749917d6 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.h +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h @@ -138,6 +138,10 @@ struct amdxdna_client { struct iommu_sva *sva; int pasid; struct mm_struct *mm; + + size_t heap_usage; + size_t total_bo_usage; + size_t total_int_bo_usage; }; #define amdxdna_for_each_hwctx(client, hwctx_id, entry) \ diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c index fb71d6e3f44d..fb999aa25318 100644 --- a/drivers/accel/amdxdna/amdxdna_ubuf.c +++ b/drivers/accel/amdxdna/amdxdna_ubuf.c @@ -17,7 +17,6 @@ struct amdxdna_ubuf_priv { struct page **pages; u64 nr_pages; - enum amdxdna_ubuf_flag flags; struct mm_struct *mm; }; @@ -37,11 +36,9 @@ static struct sg_table *amdxdna_ubuf_map(struct dma_buf_attachment *attach, if (ret) goto err_free_sg; - if (ubuf->flags & AMDXDNA_UBUF_FLAG_MAP_DMA) { - ret = dma_map_sgtable(attach->dev, sg, direction, 0); - if (ret) - goto err_free_table; - } + ret = dma_map_sgtable(attach->dev, sg, direction, 0); + if (ret) + goto err_free_table; return sg; @@ -56,11 +53,7 @@ static void amdxdna_ubuf_unmap(struct dma_buf_attachment *attach, struct sg_table *sg, enum dma_data_direction direction) { - struct amdxdna_ubuf_priv *ubuf = attach->dmabuf->priv; - - if (ubuf->flags & AMDXDNA_UBUF_FLAG_MAP_DMA) - dma_unmap_sgtable(attach->dev, sg, direction, 0); - + dma_unmap_sgtable(attach->dev, sg, direction, 0); sg_free_table(sg); kfree(sg); } @@ -133,7 +126,6 @@ static const struct dma_buf_ops amdxdna_ubuf_dmabuf_ops = { }; struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, - enum amdxdna_ubuf_flag flags, u32 num_entries, void __user *va_entries) { struct amdxdna_dev *xdna = to_xdna_dev(dev); @@ -152,7 +144,6 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, if (!ubuf) return ERR_PTR(-ENOMEM); - ubuf->flags = flags; ubuf->mm = current->mm; mmgrab(ubuf->mm); diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.h b/drivers/accel/amdxdna/amdxdna_ubuf.h index e5cb3bdb3ec9..8900a6dc4371 100644 --- a/drivers/accel/amdxdna/amdxdna_ubuf.h +++ b/drivers/accel/amdxdna/amdxdna_ubuf.h @@ -8,12 +8,7 @@ #include <drm/drm_device.h> #include <linux/dma-buf.h> -enum amdxdna_ubuf_flag { - AMDXDNA_UBUF_FLAG_MAP_DMA = 1, -}; - struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, - enum amdxdna_ubuf_flag flags, u32 num_entries, void __user *va_entries); #endif /* _AMDXDNA_UBUF_H_ */ |
