summaryrefslogtreecommitdiff
path: root/drivers/accel
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-03-27 12:45:28 +1000
committerDave Airlie <airlied@redhat.com>2026-03-27 12:45:54 +1000
commitcf2d1b5b0158a42182b50e8c797ba171c995c726 (patch)
treeff4a692455052ea76a2df9a4af8cc53a13c883e8 /drivers/accel
parent72b585da5587f79cb72c89e8a88ae3d2bcbbceb3 (diff)
parent3bce3fdd1ff2ba242f76ab66659fff27207299f1 (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.c8
-rw-r--r--drivers/accel/amdxdna/aie2_message.c40
-rw-r--r--drivers/accel/amdxdna/aie2_pci.c4
-rw-r--r--drivers/accel/amdxdna/amdxdna_ctx.c23
-rw-r--r--drivers/accel/amdxdna/amdxdna_ctx.h15
-rw-r--r--drivers/accel/amdxdna/amdxdna_gem.c508
-rw-r--r--drivers/accel/amdxdna/amdxdna_gem.h37
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox.c2
-rw-r--r--drivers/accel/amdxdna/amdxdna_pci_drv.c8
-rw-r--r--drivers/accel/amdxdna/amdxdna_pci_drv.h4
-rw-r--r--drivers/accel/amdxdna/amdxdna_ubuf.c17
-rw-r--r--drivers/accel/amdxdna/amdxdna_ubuf.h5
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_ */