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.
Unified · Split
| @@ -1,11 +1,13 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | ||
| 3 | amdxdna-y := \ | 3 | amdxdna-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 \ |
| @@ -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 | } | ||
| @@ -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 | |||
| 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 | } | ||
| @@ -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 | ||
| 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 | |||
| 213 | static void aie2_hw_stop(struct amdxdna_dev *xdna) | 252 | static 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 | |||
| 453 | const struct amdxdna_dev_ops aie2_ops = { | 493 | const 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 | }; |
| @@ -77,6 +77,7 @@ enum psp_reg_idx { · 76 unmodified lines | |||
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | struct amdxdna_fw_ver; | 79 | struct amdxdna_fw_ver; |
| 80 | struct amdxdna_hwctx; | ||
| 80 | 81 | ||
| 81 | struct psp_config { | 82 | struct 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 | ||
| 121 | struct amdxdna_hwctx_priv { | ||
| 122 | void *mbox_chann; | ||
| 123 | }; | ||
| 124 | |||
| 120 | struct amdxdna_dev_hdl { | 125 | struct 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 | |||
| 189 | int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata); | 194 | int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata); |
| 190 | int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, | 195 | int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev, |
| 191 | struct amdxdna_fw_ver *fw_ver); | 196 | 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 | |||
| 192 | #endif /* _AIE2_PCI_H_ */ | 205 | #endif /* _AIE2_PCI_H_ */ |
| @@ -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 | } | ||
| @@ -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_ */ | ||
| @@ -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 | ||
| 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 | }; | ||
| 37 | 141 | ||
| 38 | const struct drm_driver amdxdna_drm_drv = { | 142 | const 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 | ||
| 46 | static const struct amdxdna_dev_info * | 154 | 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 | |||
| 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 | |||
| 106 | static void amdxdna_remove(struct pci_dev *pdev) | 215 | static 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 | } |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | extern const struct drm_driver amdxdna_drm_drv; | 18 | extern const struct drm_driver amdxdna_drm_drv; |
| 19 | 19 | ||
| 20 | struct amdxdna_dev; | 20 | struct amdxdna_dev; |
| 21 | struct amdxdna_hwctx; | ||
| 21 | 22 | ||
| 22 | /* | 23 | /* |
| 23 | * struct amdxdna_dev_ops - Device hardware operation callbacks | 24 | * struct amdxdna_dev_ops - Device hardware operation callbacks |
| @@ -25,6 +26,9 @@ struct amdxdna_dev; · 1 unmodified line | |||
| 25 | struct amdxdna_dev_ops { | 26 | struct 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 | */ | ||
| 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 | |||
| 76 | /* Add device info below */ | 96 | /* Add device info below */ |
| 77 | extern const struct amdxdna_dev_info dev_npu1_info; | 97 | extern const struct amdxdna_dev_info dev_npu1_info; |
| 78 | extern const struct amdxdna_dev_info dev_npu2_info; | 98 | extern const struct amdxdna_dev_info dev_npu2_info; |
| @@ -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) |
| 12 | extern "C" { | 13 | extern "C" { |
| 13 | #endif | 14 | #endif |
| 14 | 15 | ||
| 16 | #define AMDXDNA_INVALID_CTX_HANDLE 0 | ||
| 17 | |||
| 15 | enum amdxdna_device_type { | 18 | enum 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 | ||
| 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 | |||
| 20 | #if defined(__cplusplus) | 151 | #if defined(__cplusplus) |
| 21 | } /* extern c end */ | 152 | } /* extern c end */ |
| 22 | #endif | 153 | #endif |