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 @@
1# SPDX-License-Identifier: GPL-2.0-only1# SPDX-License-Identifier: GPL-2.0-only
2 2
3amdxdna-y := \3amdxdna-y := \
4 aie2_ctx.o \
4 aie2_message.o \5 aie2_message.o \
5 aie2_pci.o \6 aie2_pci.o \
6 aie2_psp.o \7 aie2_psp.o \
7 aie2_smu.o \8 aie2_smu.o \
8 aie2_solver.o \9 aie2_solver.o \
10 amdxdna_ctx.o \
9 amdxdna_mailbox.o \11 amdxdna_mailbox.o \
10 amdxdna_mailbox_helper.o \12 amdxdna_mailbox_helper.o \
11 amdxdna_pci_drv.o \13 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
17static 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
84static 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
116static 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
126int 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
156free_col_list:
157 kfree(hwctx->col_list);
158free_priv:
159 kfree(priv);
160 return ret;
161}
162
163void 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
172int 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
3 * Copyright (C) 2023-2024, Advanced Micro Devices, Inc.3 * Copyright (C) 2023-2024, Advanced Micro Devices, Inc.
4 */4 */
5 5
6#include <drm/amdxdna_accel.h>
6#include <drm/drm_device.h>7#include <drm/drm_device.h>
7#include <drm/drm_print.h>8#include <drm/drm_print.h>
8#include <linux/errno.h>9#include <linux/errno.h>
10#include <linux/pci.h>
9#include <linux/types.h>11#include <linux/types.h>
10 12
11#include "aie2_msg_priv.h"13#include "aie2_msg_priv.h"
12#include "aie2_pci.h"14#include "aie2_pci.h"
15#include "amdxdna_ctx.h"
13#include "amdxdna_mailbox.h"16#include "amdxdna_mailbox.h"
14#include "amdxdna_mailbox_helper.h"17#include "amdxdna_mailbox_helper.h"
15#include "amdxdna_pci_drv.h"18#include "amdxdna_pci_drv.h"
@@ -192,3 +195,90 @@ int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, · 176 unmodified lines
192 195
193 return 0;196 return 0;
194}197}
198
199int 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
256out_destroy_context:
257 aie2_destroy_context(ndev, hwctx);
258 return ret;
259}
260
261int 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
3 * Copyright (C) 2023-2024, Advanced Micro Devices, Inc.3 * Copyright (C) 2023-2024, Advanced Micro Devices, Inc.
4 */4 */
5 5
6#include <drm/amdxdna_accel.h>
6#include <drm/drm_device.h>7#include <drm/drm_device.h>
7#include <drm/drm_managed.h>8#include <drm/drm_managed.h>
8#include <drm/drm_print.h>9#include <drm/drm_print.h>
@@ -15,6 +16,7 @@ · 6 unmodified lines
15#include "aie2_msg_priv.h"16#include "aie2_msg_priv.h"
16#include "aie2_pci.h"17#include "aie2_pci.h"
17#include "aie2_solver.h"18#include "aie2_solver.h"
19#include "amdxdna_ctx.h"
18#include "amdxdna_mailbox.h"20#include "amdxdna_mailbox.h"
19#include "amdxdna_pci_drv.h"21#include "amdxdna_pci_drv.h"
20 22
@@ -210,6 +212,43 @@ static void aie2_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev) · 189 unmodified lines
210 XDNA_DBG(ndev->xdna, "Firmware suspended");212 XDNA_DBG(ndev->xdna, "Firmware suspended");
211}213}
212 214
215static 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
232static 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
247static struct xrs_action_ops aie2_xrs_actions = {
248 .load = aie2_xrs_load,
249 .unload = aie2_xrs_unload,
250};
251
213static void aie2_hw_stop(struct amdxdna_dev *xdna)252static void aie2_hw_stop(struct amdxdna_dev *xdna)
214{253{
215 struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);254 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
417 xrs_cfg.clk_list.cu_clk_list[2] = 1000;456 xrs_cfg.clk_list.cu_clk_list[2] = 1000;
418 xrs_cfg.sys_eff_factor = 1;457 xrs_cfg.sys_eff_factor = 1;
419 xrs_cfg.ddev = &xdna->ddev;458 xrs_cfg.ddev = &xdna->ddev;
459 xrs_cfg.actions = &aie2_xrs_actions;
420 xrs_cfg.total_col = ndev->total_col;460 xrs_cfg.total_col = ndev->total_col;
421 461
422 xdna->xrs_hdl = xrsm_init(&xrs_cfg);462 xdna->xrs_hdl = xrsm_init(&xrs_cfg);
@@ -453,4 +493,7 @@ static void aie2_fini(struct amdxdna_dev *xdna) · 30 unmodified lines
453const struct amdxdna_dev_ops aie2_ops = {493const struct amdxdna_dev_ops aie2_ops = {
454 .init = aie2_init,494 .init = aie2_init,
455 .fini = aie2_fini,495 .fini = aie2_fini,
496 .hwctx_init = aie2_hwctx_init,
497 .hwctx_fini = aie2_hwctx_fini,
498 .hwctx_config = aie2_hwctx_config,
456};499};
drivers/accel/amdxdna/aie2_pci.h+13−0
@@ -77,6 +77,7 @@ enum psp_reg_idx { · 76 unmodified lines
77};77};
78 78
79struct amdxdna_fw_ver;79struct amdxdna_fw_ver;
80struct amdxdna_hwctx;
80 81
81struct psp_config {82struct psp_config {
82 const void *fw_buf;83 const void *fw_buf;
@@ -117,6 +118,10 @@ struct rt_config { · 34 unmodified lines
117 u32 value;118 u32 value;
118};119};
119 120
121struct amdxdna_hwctx_priv {
122 void *mbox_chann;
123};
124
120struct amdxdna_dev_hdl {125struct amdxdna_dev_hdl {
121 struct amdxdna_dev *xdna;126 struct amdxdna_dev *xdna;
122 const struct amdxdna_dev_priv *priv;127 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
189int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata);194int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata);
190int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev,195int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev,
191 struct amdxdna_fw_ver *fw_ver);196 struct amdxdna_fw_ver *fw_ver);
197int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx);
198int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx);
199
200/* aie2_hwctx.c */
201int aie2_hwctx_init(struct amdxdna_hwctx *hwctx);
202void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx);
203int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size);
204
192#endif /* _AIE2_PCI_H_ */205#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
17static 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 */
35void 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
52int 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
114free_name:
115 kfree(hwctx->name);
116rm_id:
117 mutex_lock(&client->hwctx_lock);
118 idr_remove(&client->hwctx_idr, hwctx->id);
119 mutex_unlock(&client->hwctx_lock);
120free_hwctx:
121 kfree(hwctx);
122exit:
123 drm_dev_exit(idx);
124 return ret;
125}
126
127int 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);
153out:
154 drm_dev_exit(idx);
155 return ret;
156}
157
158int 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
215unlock:
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
9struct 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
34void amdxdna_hwctx_remove_all(struct amdxdna_client *client);
35int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
36int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
37int 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
3 * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.3 * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
4 */4 */
5 5
6#include <drm/amdxdna_accel.h>
6#include <drm/drm_accel.h>7#include <drm/drm_accel.h>
7#include <drm/drm_drv.h>8#include <drm/drm_drv.h>
8#include <drm/drm_gem.h>9#include <drm/drm_gem.h>
9#include <drm/drm_ioctl.h>10#include <drm/drm_ioctl.h>
10#include <drm/drm_managed.h>11#include <drm/drm_managed.h>
12#include <linux/iommu.h>
11#include <linux/pci.h>13#include <linux/pci.h>
12 14
15#include "amdxdna_ctx.h"
13#include "amdxdna_pci_drv.h"16#include "amdxdna_pci_drv.h"
14 17
15/*18/*
@@ -33,7 +36,108 @@ static const struct amdxdna_device_id amdxdna_ids[] = { · 17 unmodified lines
33 {0}36 {0}
34};37};
35 38
36DEFINE_DRM_ACCEL_FOPS(amdxdna_fops);39static 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
77unbind_sva:
78 iommu_sva_unbind_device(client->sva);
79failed:
80 kfree(client);
81
82 return ret;
83}
84
85static 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
101static 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
121static 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
128static 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};
37 141
38const struct drm_driver amdxdna_drm_drv = {142const struct drm_driver amdxdna_drm_drv = {
39 .driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL |143 .driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL |
@@ -41,6 +145,10 @@ const struct drm_driver amdxdna_drm_drv = { · 1 unmodified line
41 .fops = &amdxdna_fops,145 .fops = &amdxdna_fops,
42 .name = "amdxdna_accel_driver",146 .name = "amdxdna_accel_driver",
43 .desc = "AMD XDNA DRM implementation",147 .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),
44};152};
45 153
46static const struct amdxdna_dev_info *154static 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
70 return -ENODEV;178 return -ENODEV;
71 179
72 drmm_mutex_init(&xdna->ddev, &xdna->dev_lock);180 drmm_mutex_init(&xdna->ddev, &xdna->dev_lock);
181 INIT_LIST_HEAD(&xdna->client_list);
73 pci_set_drvdata(pdev, xdna);182 pci_set_drvdata(pdev, xdna);
74 183
75 mutex_lock(&xdna->dev_lock);184 mutex_lock(&xdna->dev_lock);
@@ -106,11 +215,25 @@ failed_dev_fini: · 30 unmodified lines
106static void amdxdna_remove(struct pci_dev *pdev)215static void amdxdna_remove(struct pci_dev *pdev)
107{216{
108 struct amdxdna_dev *xdna = pci_get_drvdata(pdev);217 struct amdxdna_dev *xdna = pci_get_drvdata(pdev);
218 struct amdxdna_client *client;
109 219
110 drm_dev_unplug(&xdna->ddev);220 drm_dev_unplug(&xdna->ddev);
111 amdxdna_sysfs_fini(xdna);221 amdxdna_sysfs_fini(xdna);
112 222
113 mutex_lock(&xdna->dev_lock);223 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
114 xdna->dev_info->ops->fini(xdna);237 xdna->dev_info->ops->fini(xdna);
115 mutex_unlock(&xdna->dev_lock);238 mutex_unlock(&xdna->dev_lock);
116}239}
drivers/accel/amdxdna/amdxdna_pci_drv.h+20−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
18extern const struct drm_driver amdxdna_drm_drv;18extern const struct drm_driver amdxdna_drm_drv;
19 19
20struct amdxdna_dev;20struct amdxdna_dev;
21struct amdxdna_hwctx;
21 22
22/*23/*
23 * struct amdxdna_dev_ops - Device hardware operation callbacks24 * struct amdxdna_dev_ops - Device hardware operation callbacks
@@ -25,6 +26,9 @@ struct amdxdna_dev; · 1 unmodified line
25struct amdxdna_dev_ops {26struct amdxdna_dev_ops {
26 int (*init)(struct amdxdna_dev *xdna);27 int (*init)(struct amdxdna_dev *xdna);
27 void (*fini)(struct amdxdna_dev *xdna);28 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);
28};32};
29 33
30/*34/*
@@ -61,6 +65,7 @@ struct amdxdna_dev { · 30 unmodified lines
61 void *xrs_hdl;65 void *xrs_hdl;
62 66
63 struct mutex dev_lock; /* per device lock */67 struct mutex dev_lock; /* per device lock */
68 struct list_head client_list;
64 struct amdxdna_fw_ver fw_ver;69 struct amdxdna_fw_ver fw_ver;
65};70};
66 71
@@ -73,6 +78,21 @@ struct amdxdna_device_id { · 6 unmodified lines
73 const struct amdxdna_dev_info *dev_info;78 const struct amdxdna_dev_info *dev_info;
74};79};
75 80
81/*
82 * struct amdxdna_client - amdxdna client
83 * A per fd data structure for managing context and other user process stuffs.
84 */
85struct 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
76/* Add device info below */96/* Add device info below */
77extern const struct amdxdna_dev_info dev_npu1_info;97extern const struct amdxdna_dev_info dev_npu1_info;
78extern const struct amdxdna_dev_info dev_npu2_info;98extern const struct amdxdna_dev_info dev_npu2_info;
include/uapi/drm/amdxdna_accel.h+131−0
@@ -6,17 +6,148 @@ · 5 unmodified lines
6#ifndef _UAPI_AMDXDNA_ACCEL_H_6#ifndef _UAPI_AMDXDNA_ACCEL_H_
7#define _UAPI_AMDXDNA_ACCEL_H_7#define _UAPI_AMDXDNA_ACCEL_H_
8 8
9#include <linux/stddef.h>
9#include "drm.h"10#include "drm.h"
10 11
11#if defined(__cplusplus)12#if defined(__cplusplus)
12extern "C" {13extern "C" {
13#endif14#endif
14 15
16#define AMDXDNA_INVALID_CTX_HANDLE 0
17
15enum amdxdna_device_type {18enum amdxdna_device_type {
16 AMDXDNA_DEV_TYPE_UNKNOWN = -1,19 AMDXDNA_DEV_TYPE_UNKNOWN = -1,
17 AMDXDNA_DEV_TYPE_KMQ,20 AMDXDNA_DEV_TYPE_KMQ,
18};21};
19 22
23enum 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 */
40struct 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 */
63struct 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 */
82struct 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 */
93struct 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 */
105struct 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
111enum 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 */
131struct 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
20#if defined(__cplusplus)151#if defined(__cplusplus)
21} /* extern c end */152} /* extern c end */
22#endif153#endif