History

accel/amdxdna: Add hardware context

The hardware can be shared among multiple user applications. The hardware resources are allocated/freed based on the request from user application via driver IOCTLs. DRM_IOCTL_AMDXDNA_CREATE_HWCTX Allocate tile columns and create a hardware context structure to track the usage and status of the resources. A hardware context ID is returned for XDNA command execution. DRM_IOCTL_AMDXDNA_DESTROY_HWCTX Release hardware context based on its ID. The tile columns belong to this hardware context will be reclaimed. DRM_IOCTL_AMDXDNA_CONFIG_HWCTX Config hardware context. Bind the hardware context to the required resources.

Lizhi Hou committed 1 year ago

Commit be462c91 parent c88d33210 files · +867 −1Browse files

Unified · Split

10 files
  1. drivers/accel/amdxdna/Makefile +2 −0
  2. drivers/accel/amdxdna/aie2_ctx.c +186 −0
  3. drivers/accel/amdxdna/aie2_message.c +90 −0
  4. drivers/accel/amdxdna/aie2_pci.c +43 −0
  5. drivers/accel/amdxdna/aie2_pci.h +13 −0
  6. drivers/accel/amdxdna/amdxdna_ctx.c +219 −0
  7. drivers/accel/amdxdna/amdxdna_ctx.h +39 −0
  8. drivers/accel/amdxdna/amdxdna_pci_drv.c +124 −1
  9. drivers/accel/amdxdna/amdxdna_pci_drv.h +20 −0
  10. include/uapi/drm/amdxdna_accel.h +131 −0
drivers/accel/amdxdna/Makefile+2−0
@@ -1,11 +1,13 @@
11 # SPDX-License-Identifier: GPL-2.0-only
22
33 amdxdna-y := \
4+ aie2_ctx.o \
45 aie2_message.o \
56 aie2_pci.o \
67 aie2_psp.o \
78 aie2_smu.o \
89 aie2_solver.o \
10+ amdxdna_ctx.o \
911 amdxdna_mailbox.o \
1012 amdxdna_mailbox_helper.o \
1113 amdxdna_pci_drv.o \
drivers/accel/amdxdna/aie2_ctx.c+186−0
@@ -0,0 +1,186 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/*
3+ * Copyright (C) 2024, Advanced Micro Devices, Inc.
4+ */
5+
6+#include <drm/amdxdna_accel.h>
7+#include <drm/drm_device.h>
8+#include <drm/drm_print.h>
9+#include <linux/types.h>
10+
11+#include "aie2_pci.h"
12+#include "aie2_solver.h"
13+#include "amdxdna_ctx.h"
14+#include "amdxdna_mailbox.h"
15+#include "amdxdna_pci_drv.h"
16+
17+static int aie2_hwctx_col_list(struct amdxdna_hwctx *hwctx)
18+{
19+ struct amdxdna_dev *xdna = hwctx->client->xdna;
20+ struct amdxdna_dev_hdl *ndev;
21+ int start, end, first, last;
22+ u32 width = 1, entries = 0;
23+ int i;
24+
25+ if (!hwctx->num_tiles) {
26+ XDNA_ERR(xdna, "Number of tiles is zero");
27+ return -EINVAL;
28+ }
29+
30+ ndev = xdna->dev_handle;
31+ if (unlikely(!ndev->metadata.core.row_count)) {
32+ XDNA_WARN(xdna, "Core tile row count is zero");
33+ return -EINVAL;
34+ }
35+
36+ hwctx->num_col = hwctx->num_tiles / ndev->metadata.core.row_count;
37+ if (!hwctx->num_col || hwctx->num_col > ndev->total_col) {
38+ XDNA_ERR(xdna, "Invalid num_col %d", hwctx->num_col);
39+ return -EINVAL;
40+ }
41+
42+ if (ndev->priv->col_align == COL_ALIGN_NATURE)
43+ width = hwctx->num_col;
44+
45+ /*
46+ * In range [start, end], find out columns that is multiple of width.
47+ * 'first' is the first column,
48+ * 'last' is the last column,
49+ * 'entries' is the total number of columns.
50+ */
51+ start = xdna->dev_info->first_col;
52+ end = ndev->total_col - hwctx->num_col;
53+ if (start > 0 && end == 0) {
54+ XDNA_DBG(xdna, "Force start from col 0");
55+ start = 0;
56+ }
57+ first = start + (width - start % width) % width;
58+ last = end - end % width;
59+ if (last >= first)
60+ entries = (last - first) / width + 1;
61+ XDNA_DBG(xdna, "start %d end %d first %d last %d",
62+ start, end, first, last);
63+
64+ if (unlikely(!entries)) {
65+ XDNA_ERR(xdna, "Start %d end %d width %d",
66+ start, end, width);
67+ return -EINVAL;
68+ }
69+
70+ hwctx->col_list = kmalloc_array(entries, sizeof(*hwctx->col_list), GFP_KERNEL);
71+ if (!hwctx->col_list)
72+ return -ENOMEM;
73+
74+ hwctx->col_list_len = entries;
75+ hwctx->col_list[0] = first;
76+ for (i = 1; i < entries; i++)
77+ hwctx->col_list[i] = hwctx->col_list[i - 1] + width;
78+
79+ print_hex_dump_debug("col_list: ", DUMP_PREFIX_OFFSET, 16, 4, hwctx->col_list,
80+ entries * sizeof(*hwctx->col_list), false);
81+ return 0;
82+}
83+
84+static int aie2_alloc_resource(struct amdxdna_hwctx *hwctx)
85+{
86+ struct amdxdna_dev *xdna = hwctx->client->xdna;
87+ struct alloc_requests *xrs_req;
88+ int ret;
89+
90+ xrs_req = kzalloc(sizeof(*xrs_req), GFP_KERNEL);
91+ if (!xrs_req)
92+ return -ENOMEM;
93+
94+ xrs_req->cdo.start_cols = hwctx->col_list;
95+ xrs_req->cdo.cols_len = hwctx->col_list_len;
96+ xrs_req->cdo.ncols = hwctx->num_col;
97+ xrs_req->cdo.qos_cap.opc = hwctx->max_opc;
98+
99+ xrs_req->rqos.gops = hwctx->qos.gops;
100+ xrs_req->rqos.fps = hwctx->qos.fps;
101+ xrs_req->rqos.dma_bw = hwctx->qos.dma_bandwidth;
102+ xrs_req->rqos.latency = hwctx->qos.latency;
103+ xrs_req->rqos.exec_time = hwctx->qos.frame_exec_time;
104+ xrs_req->rqos.priority = hwctx->qos.priority;
105+
106+ xrs_req->rid = (uintptr_t)hwctx;
107+
108+ ret = xrs_allocate_resource(xdna->xrs_hdl, xrs_req, hwctx);
109+ if (ret)
110+ XDNA_ERR(xdna, "Allocate AIE resource failed, ret %d", ret);
111+
112+ kfree(xrs_req);
113+ return ret;
114+}
115+
116+static void aie2_release_resource(struct amdxdna_hwctx *hwctx)
117+{
118+ struct amdxdna_dev *xdna = hwctx->client->xdna;
119+ int ret;
120+
121+ ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx);
122+ if (ret)
123+ XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret);
124+}
125+
126+int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
127+{
128+ struct amdxdna_client *client = hwctx->client;
129+ struct amdxdna_dev *xdna = client->xdna;
130+ struct amdxdna_hwctx_priv *priv;
131+ int ret;
132+
133+ priv = kzalloc(sizeof(*hwctx->priv), GFP_KERNEL);
134+ if (!priv)
135+ return -ENOMEM;
136+ hwctx->priv = priv;
137+
138+ ret = aie2_hwctx_col_list(hwctx);
139+ if (ret) {
140+ XDNA_ERR(xdna, "Create col list failed, ret %d", ret);
141+ goto free_priv;
142+ }
143+
144+ ret = aie2_alloc_resource(hwctx);
145+ if (ret) {
146+ XDNA_ERR(xdna, "Alloc hw resource failed, ret %d", ret);
147+ goto free_col_list;
148+ }
149+
150+ hwctx->status = HWCTX_STAT_INIT;
151+
152+ XDNA_DBG(xdna, "hwctx %s init completed", hwctx->name);
153+
154+ return 0;
155+
156+free_col_list:
157+ kfree(hwctx->col_list);
158+free_priv:
159+ kfree(priv);
160+ return ret;
161+}
162+
163+void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx)
164+{
165+ aie2_release_resource(hwctx);
166+
167+ kfree(hwctx->col_list);
168+ kfree(hwctx->priv);
169+ kfree(hwctx->cus);
170+}
171+
172+int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size)
173+{
174+ struct amdxdna_dev *xdna = hwctx->client->xdna;
175+
176+ drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
177+ switch (type) {
178+ case DRM_AMDXDNA_HWCTX_CONFIG_CU:
179+ case DRM_AMDXDNA_HWCTX_ASSIGN_DBG_BUF:
180+ case DRM_AMDXDNA_HWCTX_REMOVE_DBG_BUF:
181+ return -EOPNOTSUPP;
182+ default:
183+ XDNA_DBG(xdna, "Not supported type %d", type);
184+ return -EOPNOTSUPP;
185+ }
186+}
drivers/accel/amdxdna/aie2_message.c+90−0
@@ -3,13 +3,16 @@ · 2 unmodified lines
33 * Copyright (C) 2023-2024, Advanced Micro Devices, Inc.
44 */
55
6+#include <drm/amdxdna_accel.h>
67 #include <drm/drm_device.h>
78 #include <drm/drm_print.h>
89 #include <linux/errno.h>
10+#include <linux/pci.h>
911 #include <linux/types.h>
1012
1113 #include "aie2_msg_priv.h"
1214 #include "aie2_pci.h"
15+#include "amdxdna_ctx.h"
1316 #include "amdxdna_mailbox.h"
1417 #include "amdxdna_mailbox_helper.h"
1518 #include "amdxdna_pci_drv.h"
@@ -192,3 +195,90 @@ int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, · 176 unmodified lines
192195
193196 return 0;
194197 }
198+
199+int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx)
200+{
201+ DECLARE_AIE2_MSG(create_ctx, MSG_OP_CREATE_CONTEXT);
202+ struct amdxdna_dev *xdna = ndev->xdna;
203+ struct xdna_mailbox_chann_res x2i;
204+ struct xdna_mailbox_chann_res i2x;
205+ struct cq_pair *cq_pair;
206+ u32 intr_reg;
207+ int ret;
208+
209+ req.aie_type = 1;
210+ req.start_col = hwctx->start_col;
211+ req.num_col = hwctx->num_col;
212+ req.num_cq_pairs_requested = 1;
213+ req.pasid = hwctx->client->pasid;
214+ req.context_priority = 2;
215+
216+ ret = aie2_send_mgmt_msg_wait(ndev, &msg);
217+ if (ret)
218+ return ret;
219+
220+ hwctx->fw_ctx_id = resp.context_id;
221+ WARN_ONCE(hwctx->fw_ctx_id == -1, "Unexpected context id");
222+
223+ cq_pair = &resp.cq_pair[0];
224+ x2i.mb_head_ptr_reg = AIE2_MBOX_OFF(ndev, cq_pair->x2i_q.head_addr);
225+ x2i.mb_tail_ptr_reg = AIE2_MBOX_OFF(ndev, cq_pair->x2i_q.tail_addr);
226+ x2i.rb_start_addr = AIE2_SRAM_OFF(ndev, cq_pair->x2i_q.buf_addr);
227+ x2i.rb_size = cq_pair->x2i_q.buf_size;
228+
229+ i2x.mb_head_ptr_reg = AIE2_MBOX_OFF(ndev, cq_pair->i2x_q.head_addr);
230+ i2x.mb_tail_ptr_reg = AIE2_MBOX_OFF(ndev, cq_pair->i2x_q.tail_addr);
231+ i2x.rb_start_addr = AIE2_SRAM_OFF(ndev, cq_pair->i2x_q.buf_addr);
232+ i2x.rb_size = cq_pair->i2x_q.buf_size;
233+
234+ ret = pci_irq_vector(to_pci_dev(xdna->ddev.dev), resp.msix_id);
235+ if (ret == -EINVAL) {
236+ XDNA_ERR(xdna, "not able to create channel");
237+ goto out_destroy_context;
238+ }
239+
240+ intr_reg = i2x.mb_head_ptr_reg + 4;
241+ hwctx->priv->mbox_chann = xdna_mailbox_create_channel(ndev->mbox, &x2i, &i2x,
242+ intr_reg, ret);
243+ if (!hwctx->priv->mbox_chann) {
244+ XDNA_ERR(xdna, "not able to create channel");
245+ ret = -EINVAL;
246+ goto out_destroy_context;
247+ }
248+
249+ XDNA_DBG(xdna, "%s mailbox channel irq: %d, msix_id: %d",
250+ hwctx->name, ret, resp.msix_id);
251+ XDNA_DBG(xdna, "%s created fw ctx %d pasid %d", hwctx->name,
252+ hwctx->fw_ctx_id, hwctx->client->pasid);
253+
254+ return 0;
255+
256+out_destroy_context:
257+ aie2_destroy_context(ndev, hwctx);
258+ return ret;
259+}
260+
261+int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx)
262+{
263+ DECLARE_AIE2_MSG(destroy_ctx, MSG_OP_DESTROY_CONTEXT);
264+ struct amdxdna_dev *xdna = ndev->xdna;
265+ int ret;
266+
267+ if (hwctx->fw_ctx_id == -1)
268+ return 0;
269+
270+ xdna_mailbox_stop_channel(hwctx->priv->mbox_chann);
271+
272+ req.context_id = hwctx->fw_ctx_id;
273+ ret = aie2_send_mgmt_msg_wait(ndev, &msg);
274+ if (ret)
275+ XDNA_WARN(xdna, "%s destroy context failed, ret %d", hwctx->name, ret);
276+
277+ xdna_mailbox_destroy_channel(hwctx->priv->mbox_chann);
278+ XDNA_DBG(xdna, "%s destroyed fw ctx %d", hwctx->name,
279+ hwctx->fw_ctx_id);
280+ hwctx->priv->mbox_chann = NULL;
281+ hwctx->fw_ctx_id = -1;
282+
283+ return ret;
284+}
drivers/accel/amdxdna/aie2_pci.c+43−0
@@ -3,6 +3,7 @@ · 2 unmodified lines
33 * Copyright (C) 2023-2024, Advanced Micro Devices, Inc.
44 */
55
6+#include <drm/amdxdna_accel.h>
67 #include <drm/drm_device.h>
78 #include <drm/drm_managed.h>
89 #include <drm/drm_print.h>
@@ -15,6 +16,7 @@ · 6 unmodified lines
1516 #include "aie2_msg_priv.h"
1617 #include "aie2_pci.h"
1718 #include "aie2_solver.h"
19+#include "amdxdna_ctx.h"
1820 #include "amdxdna_mailbox.h"
1921 #include "amdxdna_pci_drv.h"
2022
@@ -210,6 +212,43 @@ static void aie2_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev) · 189 unmodified lines
210212 XDNA_DBG(ndev->xdna, "Firmware suspended");
211213 }
212214
215+static int aie2_xrs_load(void *cb_arg, struct xrs_action_load *action)
216+{
217+ struct amdxdna_hwctx *hwctx = cb_arg;
218+ struct amdxdna_dev *xdna;
219+ int ret;
220+
221+ xdna = hwctx->client->xdna;
222+
223+ hwctx->start_col = action->part.start_col;
224+ hwctx->num_col = action->part.ncols;
225+ ret = aie2_create_context(xdna->dev_handle, hwctx);
226+ if (ret)
227+ XDNA_ERR(xdna, "create context failed, ret %d", ret);
228+
229+ return ret;
230+}
231+
232+static int aie2_xrs_unload(void *cb_arg)
233+{
234+ struct amdxdna_hwctx *hwctx = cb_arg;
235+ struct amdxdna_dev *xdna;
236+ int ret;
237+
238+ xdna = hwctx->client->xdna;
239+
240+ ret = aie2_destroy_context(xdna->dev_handle, hwctx);
241+ if (ret)
242+ XDNA_ERR(xdna, "destroy context failed, ret %d", ret);
243+
244+ return ret;
245+}
246+
247+static struct xrs_action_ops aie2_xrs_actions = {
248+ .load = aie2_xrs_load,
249+ .unload = aie2_xrs_unload,
250+};
251+
213252 static void aie2_hw_stop(struct amdxdna_dev *xdna)
214253 {
215254 struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
@@ -417,6 +456,7 @@ static int aie2_init(struct amdxdna_dev *xdna) · 201 unmodified lines
417456 xrs_cfg.clk_list.cu_clk_list[2] = 1000;
418457 xrs_cfg.sys_eff_factor = 1;
419458 xrs_cfg.ddev = &xdna->ddev;
459+ xrs_cfg.actions = &aie2_xrs_actions;
420460 xrs_cfg.total_col = ndev->total_col;
421461
422462 xdna->xrs_hdl = xrsm_init(&xrs_cfg);
@@ -453,4 +493,7 @@ static void aie2_fini(struct amdxdna_dev *xdna) · 30 unmodified lines
453493 const struct amdxdna_dev_ops aie2_ops = {
454494 .init = aie2_init,
455495 .fini = aie2_fini,
496+ .hwctx_init = aie2_hwctx_init,
497+ .hwctx_fini = aie2_hwctx_fini,
498+ .hwctx_config = aie2_hwctx_config,
456499 };
drivers/accel/amdxdna/aie2_pci.h+13−0
@@ -77,6 +77,7 @@ enum psp_reg_idx { · 76 unmodified lines
7777 };
7878
7979 struct amdxdna_fw_ver;
80+struct amdxdna_hwctx;
8081
8182 struct psp_config {
8283 const void *fw_buf;
@@ -117,6 +118,10 @@ struct rt_config { · 34 unmodified lines
117118 u32 value;
118119 };
119120
121+struct amdxdna_hwctx_priv {
122+ void *mbox_chann;
123+};
124+
120125 struct amdxdna_dev_hdl {
121126 struct amdxdna_dev *xdna;
122127 const struct amdxdna_dev_priv *priv;
@@ -189,4 +194,12 @@ int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *ver · 66 unmodified lines
189194 int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata);
190195 int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev,
191196 struct amdxdna_fw_ver *fw_ver);
197+int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx);
198+int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx);
199+
200+/* aie2_hwctx.c */
201+int aie2_hwctx_init(struct amdxdna_hwctx *hwctx);
202+void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx);
203+int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size);
204+
192205 #endif /* _AIE2_PCI_H_ */
drivers/accel/amdxdna/amdxdna_ctx.c+219−0
@@ -0,0 +1,219 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/*
3+ * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
4+ */
5+
6+#include <drm/amdxdna_accel.h>
7+#include <drm/drm_device.h>
8+#include <drm/drm_drv.h>
9+#include <drm/drm_file.h>
10+#include <drm/drm_print.h>
11+
12+#include "amdxdna_ctx.h"
13+#include "amdxdna_pci_drv.h"
14+
15+#define MAX_HWCTX_ID 255
16+
17+static void amdxdna_hwctx_destroy(struct amdxdna_hwctx *hwctx)
18+{
19+ struct amdxdna_dev *xdna = hwctx->client->xdna;
20+
21+ /* At this point, user is not able to submit new commands */
22+ mutex_lock(&xdna->dev_lock);
23+ xdna->dev_info->ops->hwctx_fini(hwctx);
24+ mutex_unlock(&xdna->dev_lock);
25+
26+ kfree(hwctx->name);
27+ kfree(hwctx);
28+}
29+
30+/*
31+ * This should be called in close() and remove(). DO NOT call in other syscalls.
32+ * This guarantee that when hwctx and resources will be released, if user
33+ * doesn't call amdxdna_drm_destroy_hwctx_ioctl.
34+ */
35+void amdxdna_hwctx_remove_all(struct amdxdna_client *client)
36+{
37+ struct amdxdna_hwctx *hwctx;
38+ int next = 0;
39+
40+ mutex_lock(&client->hwctx_lock);
41+ idr_for_each_entry_continue(&client->hwctx_idr, hwctx, next) {
42+ XDNA_DBG(client->xdna, "PID %d close HW context %d",
43+ client->pid, hwctx->id);
44+ idr_remove(&client->hwctx_idr, hwctx->id);
45+ mutex_unlock(&client->hwctx_lock);
46+ amdxdna_hwctx_destroy(hwctx);
47+ mutex_lock(&client->hwctx_lock);
48+ }
49+ mutex_unlock(&client->hwctx_lock);
50+}
51+
52+int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
53+{
54+ struct amdxdna_client *client = filp->driver_priv;
55+ struct amdxdna_drm_create_hwctx *args = data;
56+ struct amdxdna_dev *xdna = to_xdna_dev(dev);
57+ struct amdxdna_hwctx *hwctx;
58+ int ret, idx;
59+
60+ if (args->ext || args->ext_flags)
61+ return -EINVAL;
62+
63+ if (!drm_dev_enter(dev, &idx))
64+ return -ENODEV;
65+
66+ hwctx = kzalloc(sizeof(*hwctx), GFP_KERNEL);
67+ if (!hwctx) {
68+ ret = -ENOMEM;
69+ goto exit;
70+ }
71+
72+ if (copy_from_user(&hwctx->qos, u64_to_user_ptr(args->qos_p), sizeof(hwctx->qos))) {
73+ XDNA_ERR(xdna, "Access QoS info failed");
74+ ret = -EFAULT;
75+ goto free_hwctx;
76+ }
77+
78+ hwctx->client = client;
79+ hwctx->fw_ctx_id = -1;
80+ hwctx->num_tiles = args->num_tiles;
81+ hwctx->mem_size = args->mem_size;
82+ hwctx->max_opc = args->max_opc;
83+ mutex_lock(&client->hwctx_lock);
84+ ret = idr_alloc_cyclic(&client->hwctx_idr, hwctx, 0, MAX_HWCTX_ID, GFP_KERNEL);
85+ if (ret < 0) {
86+ mutex_unlock(&client->hwctx_lock);
87+ XDNA_ERR(xdna, "Allocate hwctx ID failed, ret %d", ret);
88+ goto free_hwctx;
89+ }
90+ hwctx->id = ret;
91+ mutex_unlock(&client->hwctx_lock);
92+
93+ hwctx->name = kasprintf(GFP_KERNEL, "hwctx.%d.%d", client->pid, hwctx->id);
94+ if (!hwctx->name) {
95+ ret = -ENOMEM;
96+ goto rm_id;
97+ }
98+
99+ mutex_lock(&xdna->dev_lock);
100+ ret = xdna->dev_info->ops->hwctx_init(hwctx);
101+ if (ret) {
102+ mutex_unlock(&xdna->dev_lock);
103+ XDNA_ERR(xdna, "Init hwctx failed, ret %d", ret);
104+ goto free_name;
105+ }
106+ args->handle = hwctx->id;
107+ args->syncobj_handle = hwctx->syncobj_hdl;
108+ mutex_unlock(&xdna->dev_lock);
109+
110+ XDNA_DBG(xdna, "PID %d create HW context %d, ret %d", client->pid, args->handle, ret);
111+ drm_dev_exit(idx);
112+ return 0;
113+
114+free_name:
115+ kfree(hwctx->name);
116+rm_id:
117+ mutex_lock(&client->hwctx_lock);
118+ idr_remove(&client->hwctx_idr, hwctx->id);
119+ mutex_unlock(&client->hwctx_lock);
120+free_hwctx:
121+ kfree(hwctx);
122+exit:
123+ drm_dev_exit(idx);
124+ return ret;
125+}
126+
127+int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
128+{
129+ struct amdxdna_client *client = filp->driver_priv;
130+ struct amdxdna_drm_destroy_hwctx *args = data;
131+ struct amdxdna_dev *xdna = to_xdna_dev(dev);
132+ struct amdxdna_hwctx *hwctx;
133+ int ret = 0, idx;
134+
135+ if (!drm_dev_enter(dev, &idx))
136+ return -ENODEV;
137+
138+ mutex_lock(&client->hwctx_lock);
139+ hwctx = idr_find(&client->hwctx_idr, args->handle);
140+ if (!hwctx) {
141+ mutex_unlock(&client->hwctx_lock);
142+ ret = -EINVAL;
143+ XDNA_DBG(xdna, "PID %d HW context %d not exist",
144+ client->pid, args->handle);
145+ goto out;
146+ }
147+ idr_remove(&client->hwctx_idr, hwctx->id);
148+ mutex_unlock(&client->hwctx_lock);
149+
150+ amdxdna_hwctx_destroy(hwctx);
151+
152+ XDNA_DBG(xdna, "PID %d destroyed HW context %d", client->pid, args->handle);
153+out:
154+ drm_dev_exit(idx);
155+ return ret;
156+}
157+
158+int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
159+{
160+ struct amdxdna_client *client = filp->driver_priv;
161+ struct amdxdna_drm_config_hwctx *args = data;
162+ struct amdxdna_dev *xdna = to_xdna_dev(dev);
163+ struct amdxdna_hwctx *hwctx;
164+ u32 buf_size;
165+ void *buf;
166+ u64 val;
167+ int ret;
168+
169+ if (!xdna->dev_info->ops->hwctx_config)
170+ return -EOPNOTSUPP;
171+
172+ val = args->param_val;
173+ buf_size = args->param_val_size;
174+
175+ switch (args->param_type) {
176+ case DRM_AMDXDNA_HWCTX_CONFIG_CU:
177+ /* For those types that param_val is pointer */
178+ if (buf_size > PAGE_SIZE) {
179+ XDNA_ERR(xdna, "Config CU param buffer too large");
180+ return -E2BIG;
181+ }
182+
183+ /* Hwctx needs to keep buf */
184+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
185+ if (!buf)
186+ return -ENOMEM;
187+
188+ if (copy_from_user(buf, u64_to_user_ptr(val), buf_size)) {
189+ kfree(buf);
190+ return -EFAULT;
191+ }
192+
193+ break;
194+ case DRM_AMDXDNA_HWCTX_ASSIGN_DBG_BUF:
195+ case DRM_AMDXDNA_HWCTX_REMOVE_DBG_BUF:
196+ /* For those types that param_val is a value */
197+ buf = NULL;
198+ buf_size = 0;
199+ break;
200+ default:
201+ XDNA_DBG(xdna, "Unknown HW context config type %d", args->param_type);
202+ return -EINVAL;
203+ }
204+
205+ mutex_lock(&xdna->dev_lock);
206+ hwctx = idr_find(&client->hwctx_idr, args->handle);
207+ if (!hwctx) {
208+ XDNA_DBG(xdna, "PID %d failed to get hwctx %d", client->pid, args->handle);
209+ ret = -EINVAL;
210+ goto unlock;
211+ }
212+
213+ ret = xdna->dev_info->ops->hwctx_config(hwctx, args->param_type, val, buf, buf_size);
214+
215+unlock:
216+ mutex_unlock(&xdna->dev_lock);
217+ kfree(buf);
218+ return ret;
219+}
drivers/accel/amdxdna/amdxdna_ctx.h+39−0
@@ -0,0 +1,39 @@
1+/* SPDX-License-Identifier: GPL-2.0 */
2+/*
3+ * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
4+ */
5+
6+#ifndef _AMDXDNA_CTX_H_
7+#define _AMDXDNA_CTX_H_
8+
9+struct amdxdna_hwctx {
10+ struct amdxdna_client *client;
11+ struct amdxdna_hwctx_priv *priv;
12+ char *name;
13+
14+ u32 id;
15+ u32 max_opc;
16+ u32 num_tiles;
17+ u32 mem_size;
18+ u32 fw_ctx_id;
19+ u32 col_list_len;
20+ u32 *col_list;
21+ u32 start_col;
22+ u32 num_col;
23+#define HWCTX_STAT_INIT 0
24+#define HWCTX_STAT_READY 1
25+#define HWCTX_STAT_STOP 2
26+ u32 status;
27+ u32 old_status;
28+
29+ struct amdxdna_qos_info qos;
30+ struct amdxdna_hwctx_param_config_cu *cus;
31+ u32 syncobj_hdl;
32+};
33+
34+void amdxdna_hwctx_remove_all(struct amdxdna_client *client);
35+int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
36+int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
37+int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
38+
39+#endif /* _AMDXDNA_CTX_H_ */
drivers/accel/amdxdna/amdxdna_pci_drv.c+124−1
@@ -3,13 +3,16 @@ · 2 unmodified lines
33 * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
44 */
55
6+#include <drm/amdxdna_accel.h>
67 #include <drm/drm_accel.h>
78 #include <drm/drm_drv.h>
89 #include <drm/drm_gem.h>
910 #include <drm/drm_ioctl.h>
1011 #include <drm/drm_managed.h>
12+#include <linux/iommu.h>
1113 #include <linux/pci.h>
1214
15+#include "amdxdna_ctx.h"
1316 #include "amdxdna_pci_drv.h"
1417
1518 /*
@@ -33,7 +36,108 @@ static const struct amdxdna_device_id amdxdna_ids[] = { · 17 unmodified lines
3336 {0}
3437 };
3538
36−DEFINE_DRM_ACCEL_FOPS(amdxdna_fops);
39+static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
40+{
41+ struct amdxdna_dev *xdna = to_xdna_dev(ddev);
42+ struct amdxdna_client *client;
43+ int ret;
44+
45+ client = kzalloc(sizeof(*client), GFP_KERNEL);
46+ if (!client)
47+ return -ENOMEM;
48+
49+ client->pid = pid_nr(filp->pid);
50+ client->xdna = xdna;
51+
52+ client->sva = iommu_sva_bind_device(xdna->ddev.dev, current->mm);
53+ if (IS_ERR(client->sva)) {
54+ ret = PTR_ERR(client->sva);
55+ XDNA_ERR(xdna, "SVA bind device failed, ret %d", ret);
56+ goto failed;
57+ }
58+ client->pasid = iommu_sva_get_pasid(client->sva);
59+ if (client->pasid == IOMMU_PASID_INVALID) {
60+ XDNA_ERR(xdna, "SVA get pasid failed");
61+ ret = -ENODEV;
62+ goto unbind_sva;
63+ }
64+ mutex_init(&client->hwctx_lock);
65+ idr_init_base(&client->hwctx_idr, AMDXDNA_INVALID_CTX_HANDLE + 1);
66+
67+ mutex_lock(&xdna->dev_lock);
68+ list_add_tail(&client->node, &xdna->client_list);
69+ mutex_unlock(&xdna->dev_lock);
70+
71+ filp->driver_priv = client;
72+ client->filp = filp;
73+
74+ XDNA_DBG(xdna, "pid %d opened", client->pid);
75+ return 0;
76+
77+unbind_sva:
78+ iommu_sva_unbind_device(client->sva);
79+failed:
80+ kfree(client);
81+
82+ return ret;
83+}
84+
85+static void amdxdna_drm_close(struct drm_device *ddev, struct drm_file *filp)
86+{
87+ struct amdxdna_client *client = filp->driver_priv;
88+ struct amdxdna_dev *xdna = to_xdna_dev(ddev);
89+
90+ XDNA_DBG(xdna, "closing pid %d", client->pid);
91+
92+ idr_destroy(&client->hwctx_idr);
93+ mutex_destroy(&client->hwctx_lock);
94+
95+ iommu_sva_unbind_device(client->sva);
96+
97+ XDNA_DBG(xdna, "pid %d closed", client->pid);
98+ kfree(client);
99+}
100+
101+static int amdxdna_flush(struct file *f, fl_owner_t id)
102+{
103+ struct drm_file *filp = f->private_data;
104+ struct amdxdna_client *client = filp->driver_priv;
105+ struct amdxdna_dev *xdna = client->xdna;
106+ int idx;
107+
108+ XDNA_DBG(xdna, "PID %d flushing...", client->pid);
109+ if (!drm_dev_enter(&xdna->ddev, &idx))
110+ return 0;
111+
112+ mutex_lock(&xdna->dev_lock);
113+ list_del_init(&client->node);
114+ mutex_unlock(&xdna->dev_lock);
115+ amdxdna_hwctx_remove_all(client);
116+
117+ drm_dev_exit(idx);
118+ return 0;
119+}
120+
121+static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = {
122+ /* Context */
123+ DRM_IOCTL_DEF_DRV(AMDXDNA_CREATE_HWCTX, amdxdna_drm_create_hwctx_ioctl, 0),
124+ DRM_IOCTL_DEF_DRV(AMDXDNA_DESTROY_HWCTX, amdxdna_drm_destroy_hwctx_ioctl, 0),
125+ DRM_IOCTL_DEF_DRV(AMDXDNA_CONFIG_HWCTX, amdxdna_drm_config_hwctx_ioctl, 0),
126+};
127+
128+static const struct file_operations amdxdna_fops = {
129+ .owner = THIS_MODULE,
130+ .open = accel_open,
131+ .release = drm_release,
132+ .flush = amdxdna_flush,
133+ .unlocked_ioctl = drm_ioctl,
134+ .compat_ioctl = drm_compat_ioctl,
135+ .poll = drm_poll,
136+ .read = drm_read,
137+ .llseek = noop_llseek,
138+ .mmap = drm_gem_mmap,
139+ .fop_flags = FOP_UNSIGNED_OFFSET,
140+};
37141
38142 const struct drm_driver amdxdna_drm_drv = {
39143 .driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL |
@@ -41,6 +145,10 @@ const struct drm_driver amdxdna_drm_drv = { · 1 unmodified line
41145 .fops = &amdxdna_fops,
42146 .name = "amdxdna_accel_driver",
43147 .desc = "AMD XDNA DRM implementation",
148+ .open = amdxdna_drm_open,
149+ .postclose = amdxdna_drm_close,
150+ .ioctls = amdxdna_drm_ioctls,
151+ .num_ioctls = ARRAY_SIZE(amdxdna_drm_ioctls),
44152 };
45153
46154 static const struct amdxdna_dev_info *
@@ -70,6 +178,7 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 23 unmodified lines
70178 return -ENODEV;
71179
72180 drmm_mutex_init(&xdna->ddev, &xdna->dev_lock);
181+ INIT_LIST_HEAD(&xdna->client_list);
73182 pci_set_drvdata(pdev, xdna);
74183
75184 mutex_lock(&xdna->dev_lock);
@@ -106,11 +215,25 @@ failed_dev_fini: · 30 unmodified lines
106215 static void amdxdna_remove(struct pci_dev *pdev)
107216 {
108217 struct amdxdna_dev *xdna = pci_get_drvdata(pdev);
218+ struct amdxdna_client *client;
109219
110220 drm_dev_unplug(&xdna->ddev);
111221 amdxdna_sysfs_fini(xdna);
112222
113223 mutex_lock(&xdna->dev_lock);
224+ client = list_first_entry_or_null(&xdna->client_list,
225+ struct amdxdna_client, node);
226+ while (client) {
227+ list_del_init(&client->node);
228+ mutex_unlock(&xdna->dev_lock);
229+
230+ amdxdna_hwctx_remove_all(client);
231+
232+ mutex_lock(&xdna->dev_lock);
233+ client = list_first_entry_or_null(&xdna->client_list,
234+ struct amdxdna_client, node);
235+ }
236+
114237 xdna->dev_info->ops->fini(xdna);
115238 mutex_unlock(&xdna->dev_lock);
116239 }
drivers/accel/amdxdna/amdxdna_pci_drv.h+20−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
1818 extern const struct drm_driver amdxdna_drm_drv;
1919
2020 struct amdxdna_dev;
21+struct amdxdna_hwctx;
2122
2223 /*
2324 * struct amdxdna_dev_ops - Device hardware operation callbacks
@@ -25,6 +26,9 @@ struct amdxdna_dev; · 1 unmodified line
2526 struct amdxdna_dev_ops {
2627 int (*init)(struct amdxdna_dev *xdna);
2728 void (*fini)(struct amdxdna_dev *xdna);
29+ int (*hwctx_init)(struct amdxdna_hwctx *hwctx);
30+ void (*hwctx_fini)(struct amdxdna_hwctx *hwctx);
31+ int (*hwctx_config)(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size);
2832 };
2933
3034 /*
@@ -61,6 +65,7 @@ struct amdxdna_dev { · 30 unmodified lines
6165 void *xrs_hdl;
6266
6367 struct mutex dev_lock; /* per device lock */
68+ struct list_head client_list;
6469 struct amdxdna_fw_ver fw_ver;
6570 };
6671
@@ -73,6 +78,21 @@ struct amdxdna_device_id { · 6 unmodified lines
7378 const struct amdxdna_dev_info *dev_info;
7479 };
7580
81+/*
82+ * struct amdxdna_client - amdxdna client
83+ * A per fd data structure for managing context and other user process stuffs.
84+ */
85+struct amdxdna_client {
86+ struct list_head node;
87+ pid_t pid;
88+ struct mutex hwctx_lock; /* protect hwctx */
89+ struct idr hwctx_idr;
90+ struct amdxdna_dev *xdna;
91+ struct drm_file *filp;
92+ struct iommu_sva *sva;
93+ int pasid;
94+};
95+
7696 /* Add device info below */
7797 extern const struct amdxdna_dev_info dev_npu1_info;
7898 extern const struct amdxdna_dev_info dev_npu2_info;
include/uapi/drm/amdxdna_accel.h+131−0
@@ -6,17 +6,148 @@ · 5 unmodified lines
66 #ifndef _UAPI_AMDXDNA_ACCEL_H_
77 #define _UAPI_AMDXDNA_ACCEL_H_
88
9+#include <linux/stddef.h>
910 #include "drm.h"
1011
1112 #if defined(__cplusplus)
1213 extern "C" {
1314 #endif
1415
16+#define AMDXDNA_INVALID_CTX_HANDLE 0
17+
1518 enum amdxdna_device_type {
1619 AMDXDNA_DEV_TYPE_UNKNOWN = -1,
1720 AMDXDNA_DEV_TYPE_KMQ,
1821 };
1922
23+enum amdxdna_drm_ioctl_id {
24+ DRM_AMDXDNA_CREATE_HWCTX,
25+ DRM_AMDXDNA_DESTROY_HWCTX,
26+ DRM_AMDXDNA_CONFIG_HWCTX,
27+};
28+
29+/**
30+ * struct qos_info - QoS information for driver.
31+ * @gops: Giga operations per second.
32+ * @fps: Frames per second.
33+ * @dma_bandwidth: DMA bandwidtha.
34+ * @latency: Frame response latency.
35+ * @frame_exec_time: Frame execution time.
36+ * @priority: Request priority.
37+ *
38+ * User program can provide QoS hints to driver.
39+ */
40+struct amdxdna_qos_info {
41+ __u32 gops;
42+ __u32 fps;
43+ __u32 dma_bandwidth;
44+ __u32 latency;
45+ __u32 frame_exec_time;
46+ __u32 priority;
47+};
48+
49+/**
50+ * struct amdxdna_drm_create_hwctx - Create hardware context.
51+ * @ext: MBZ.
52+ * @ext_flags: MBZ.
53+ * @qos_p: Address of QoS info.
54+ * @umq_bo: BO handle for user mode queue(UMQ).
55+ * @log_buf_bo: BO handle for log buffer.
56+ * @max_opc: Maximum operations per cycle.
57+ * @num_tiles: Number of AIE tiles.
58+ * @mem_size: Size of AIE tile memory.
59+ * @umq_doorbell: Returned offset of doorbell associated with UMQ.
60+ * @handle: Returned hardware context handle.
61+ * @syncobj_handle: Returned syncobj handle for command completion.
62+ */
63+struct amdxdna_drm_create_hwctx {
64+ __u64 ext;
65+ __u64 ext_flags;
66+ __u64 qos_p;
67+ __u32 umq_bo;
68+ __u32 log_buf_bo;
69+ __u32 max_opc;
70+ __u32 num_tiles;
71+ __u32 mem_size;
72+ __u32 umq_doorbell;
73+ __u32 handle;
74+ __u32 syncobj_handle;
75+};
76+
77+/**
78+ * struct amdxdna_drm_destroy_hwctx - Destroy hardware context.
79+ * @handle: Hardware context handle.
80+ * @pad: Structure padding.
81+ */
82+struct amdxdna_drm_destroy_hwctx {
83+ __u32 handle;
84+ __u32 pad;
85+};
86+
87+/**
88+ * struct amdxdna_cu_config - configuration for one CU
89+ * @cu_bo: CU configuration buffer bo handle.
90+ * @cu_func: Function of a CU.
91+ * @pad: Structure padding.
92+ */
93+struct amdxdna_cu_config {
94+ __u32 cu_bo;
95+ __u8 cu_func;
96+ __u8 pad[3];
97+};
98+
99+/**
100+ * struct amdxdna_hwctx_param_config_cu - configuration for CUs in hardware context
101+ * @num_cus: Number of CUs to configure.
102+ * @pad: Structure padding.
103+ * @cu_configs: Array of CU configurations of struct amdxdna_cu_config.
104+ */
105+struct amdxdna_hwctx_param_config_cu {
106+ __u16 num_cus;
107+ __u16 pad[3];
108+ struct amdxdna_cu_config cu_configs[] __counted_by(num_cus);
109+};
110+
111+enum amdxdna_drm_config_hwctx_param {
112+ DRM_AMDXDNA_HWCTX_CONFIG_CU,
113+ DRM_AMDXDNA_HWCTX_ASSIGN_DBG_BUF,
114+ DRM_AMDXDNA_HWCTX_REMOVE_DBG_BUF,
115+ DRM_AMDXDNA_HWCTX_CONFIG_NUM
116+};
117+
118+/**
119+ * struct amdxdna_drm_config_hwctx - Configure hardware context.
120+ * @handle: hardware context handle.
121+ * @param_type: Value in enum amdxdna_drm_config_hwctx_param. Specifies the
122+ * structure passed in via param_val.
123+ * @param_val: A structure specified by the param_type struct member.
124+ * @param_val_size: Size of the parameter buffer pointed to by the param_val.
125+ * If param_val is not a pointer, driver can ignore this.
126+ * @pad: Structure padding.
127+ *
128+ * Note: if the param_val is a pointer pointing to a buffer, the maximum size
129+ * of the buffer is 4KiB(PAGE_SIZE).
130+ */
131+struct amdxdna_drm_config_hwctx {
132+ __u32 handle;
133+ __u32 param_type;
134+ __u64 param_val;
135+ __u32 param_val_size;
136+ __u32 pad;
137+};
138+
139+#define DRM_IOCTL_AMDXDNA_CREATE_HWCTX \
140+ DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDXDNA_CREATE_HWCTX, \
141+ struct amdxdna_drm_create_hwctx)
142+
143+#define DRM_IOCTL_AMDXDNA_DESTROY_HWCTX \
144+ DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDXDNA_DESTROY_HWCTX, \
145+ struct amdxdna_drm_destroy_hwctx)
146+
147+#define DRM_IOCTL_AMDXDNA_CONFIG_HWCTX \
148+ DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDXDNA_CONFIG_HWCTX, \
149+ struct amdxdna_drm_config_hwctx)
150+
20151 #if defined(__cplusplus)
21152 } /* extern c end */
22153 #endif