xref: /linux/drivers/accel/amdxdna/aie4_pci.c (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
1c02697cbSDavid Zhang // SPDX-License-Identifier: GPL-2.0
2c02697cbSDavid Zhang /*
3c02697cbSDavid Zhang  * Copyright (C) 2026, Advanced Micro Devices, Inc.
4c02697cbSDavid Zhang  */
5c02697cbSDavid Zhang 
6c02697cbSDavid Zhang #include <drm/amdxdna_accel.h>
7c02697cbSDavid Zhang #include <drm/drm_managed.h>
8c02697cbSDavid Zhang #include <drm/drm_print.h>
9e69ef214SDavid Zhang #include <linux/firmware.h>
10e69ef214SDavid Zhang #include <linux/sizes.h>
11c02697cbSDavid Zhang 
12ce9414d0SDavid Zhang #include "aie.h"
13ce9414d0SDavid Zhang #include "aie4_msg_priv.h"
14c02697cbSDavid Zhang #include "aie4_pci.h"
15ce9414d0SDavid Zhang #include "amdxdna_mailbox.h"
16ce9414d0SDavid Zhang #include "amdxdna_mailbox_helper.h"
17c02697cbSDavid Zhang #include "amdxdna_pci_drv.h"
18c02697cbSDavid Zhang 
19c02697cbSDavid Zhang #define NO_IOHUB		0
20e69ef214SDavid Zhang #define PSP_NOTIFY_INTR		0xD007BE11
21ce9414d0SDavid Zhang #define AIE4_TOTAL_COLUMN	3
22c02697cbSDavid Zhang 
23c02697cbSDavid Zhang /*
24c02697cbSDavid Zhang  * The management mailbox channel is allocated by firmware.
25c02697cbSDavid Zhang  * The related register and ring buffer information is on SRAM BAR.
26c02697cbSDavid Zhang  * This struct is the register layout.
27c02697cbSDavid Zhang  */
28c02697cbSDavid Zhang struct mailbox_info {
29c02697cbSDavid Zhang 	__u32 valid;
30c02697cbSDavid Zhang 	__u32 protocol_major;
31c02697cbSDavid Zhang 	__u32 protocol_minor;
32c02697cbSDavid Zhang 	__u32 x2i_tail_offset;
33c02697cbSDavid Zhang 	__u32 x2i_head_offset;
34c02697cbSDavid Zhang 	__u32 x2i_buffer_addr;
35c02697cbSDavid Zhang 	__u32 x2i_buffer_size;
36c02697cbSDavid Zhang 	__u32 i2x_tail_offset;
37c02697cbSDavid Zhang 	__u32 i2x_head_offset;
38c02697cbSDavid Zhang 	__u32 i2x_buffer_addr;
39c02697cbSDavid Zhang 	__u32 i2x_buffer_size;
40c02697cbSDavid Zhang 	__u32 i2x_msi_idx;
41c02697cbSDavid Zhang 	__u32 reserved[4];
42c02697cbSDavid Zhang };
43c02697cbSDavid Zhang 
44c02697cbSDavid Zhang static int aie4_fw_is_alive(struct amdxdna_dev *xdna)
45c02697cbSDavid Zhang {
46c02697cbSDavid Zhang 	const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
47c02697cbSDavid Zhang 	struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
48c02697cbSDavid Zhang 	u32 __iomem *src;
49c02697cbSDavid Zhang 	u32 fw_is_valid;
50c02697cbSDavid Zhang 	int ret;
51c02697cbSDavid Zhang 
52c02697cbSDavid Zhang 	src = ndev->rbuf_base + npriv->mbox_info_off;
53c02697cbSDavid Zhang 
54c02697cbSDavid Zhang 	ret = readx_poll_timeout(readl, src + offsetof(struct mailbox_info, valid),
55c02697cbSDavid Zhang 				 fw_is_valid, (fw_is_valid == 0x1),
56c02697cbSDavid Zhang 				 AIE_INTERVAL, AIE_TIMEOUT);
57c02697cbSDavid Zhang 	if (ret)
58c02697cbSDavid Zhang 		XDNA_ERR(xdna, "fw_is_valid=%d after %d ms",
59c02697cbSDavid Zhang 			 fw_is_valid, DIV_ROUND_CLOSEST(AIE_TIMEOUT, 1000000));
60c02697cbSDavid Zhang 
61c02697cbSDavid Zhang 	return ret;
62c02697cbSDavid Zhang }
63c02697cbSDavid Zhang 
64c02697cbSDavid Zhang static void aie4_read_mbox_info(struct amdxdna_dev *xdna,
65c02697cbSDavid Zhang 				struct mailbox_info *mbox_info)
66c02697cbSDavid Zhang {
67c02697cbSDavid Zhang 	const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
68c02697cbSDavid Zhang 	struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
69c02697cbSDavid Zhang 	u32 *dst = (u32 *)mbox_info;
70c02697cbSDavid Zhang 	u32 __iomem *src;
71c02697cbSDavid Zhang 	int i;
72c02697cbSDavid Zhang 
73c02697cbSDavid Zhang 	src = ndev->rbuf_base + npriv->mbox_info_off;
74c02697cbSDavid Zhang 
75c02697cbSDavid Zhang 	for (i = 0; i < sizeof(*mbox_info) / sizeof(u32); i++)
76c02697cbSDavid Zhang 		dst[i] = readl(&src[i]);
77c02697cbSDavid Zhang }
78c02697cbSDavid Zhang 
79c02697cbSDavid Zhang static int aie4_mailbox_info(struct amdxdna_dev *xdna,
80c02697cbSDavid Zhang 			     struct mailbox_info *mbox_info)
81c02697cbSDavid Zhang {
82c02697cbSDavid Zhang 	int ret;
83c02697cbSDavid Zhang 
84c02697cbSDavid Zhang 	ret = aie4_fw_is_alive(xdna);
85c02697cbSDavid Zhang 	if (ret)
86c02697cbSDavid Zhang 		return ret;
87c02697cbSDavid Zhang 
88c02697cbSDavid Zhang 	aie4_read_mbox_info(xdna, mbox_info);
89c02697cbSDavid Zhang 
90c02697cbSDavid Zhang 	ret = aie_check_protocol(&xdna->dev_handle->aie,
91c02697cbSDavid Zhang 				 mbox_info->protocol_major,
92c02697cbSDavid Zhang 				 mbox_info->protocol_minor);
93c02697cbSDavid Zhang 	if (ret)
94c02697cbSDavid Zhang 		XDNA_ERR(xdna, "mailbox major.minor %d.%d is not supported",
95c02697cbSDavid Zhang 			 mbox_info->protocol_major, mbox_info->protocol_minor);
96c02697cbSDavid Zhang 
97c02697cbSDavid Zhang 	return ret;
98c02697cbSDavid Zhang }
99c02697cbSDavid Zhang 
100c02697cbSDavid Zhang static void aie4_mailbox_fini(struct amdxdna_dev_hdl *ndev)
101c02697cbSDavid Zhang {
102c02697cbSDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
103c02697cbSDavid Zhang 
104c02697cbSDavid Zhang 	aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann);
105c02697cbSDavid Zhang 	drmm_kfree(&xdna->ddev, ndev->mbox);
106c02697cbSDavid Zhang 	ndev->mbox = NULL;
107c02697cbSDavid Zhang }
108c02697cbSDavid Zhang 
109c02697cbSDavid Zhang static int aie4_irq_init(struct amdxdna_dev *xdna)
110c02697cbSDavid Zhang {
111c02697cbSDavid Zhang 	struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
112c02697cbSDavid Zhang 	int ret, nvec;
113c02697cbSDavid Zhang 
114c02697cbSDavid Zhang 	nvec = pci_msix_vec_count(pdev);
115c02697cbSDavid Zhang 	XDNA_DBG(xdna, "irq vectors:%d", nvec);
116c02697cbSDavid Zhang 	if (nvec <= 0) {
117c02697cbSDavid Zhang 		XDNA_ERR(xdna, "does not get number of interrupt vector");
118c02697cbSDavid Zhang 		return -EINVAL;
119c02697cbSDavid Zhang 	}
120c02697cbSDavid Zhang 
121c02697cbSDavid Zhang 	ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX);
122c02697cbSDavid Zhang 	if (ret < 0) {
123c02697cbSDavid Zhang 		XDNA_ERR(xdna, "failed to alloc irq vector, ret: %d", ret);
124c02697cbSDavid Zhang 		return ret;
125c02697cbSDavid Zhang 	}
126c02697cbSDavid Zhang 
127c02697cbSDavid Zhang 	return 0;
128c02697cbSDavid Zhang }
129c02697cbSDavid Zhang 
130c02697cbSDavid Zhang static int aie4_mailbox_start(struct amdxdna_dev *xdna,
131c02697cbSDavid Zhang 			      struct mailbox_info *mbi)
132c02697cbSDavid Zhang {
133c02697cbSDavid Zhang 	struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
134c02697cbSDavid Zhang 	struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
135c02697cbSDavid Zhang 	const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
136c02697cbSDavid Zhang 	struct xdna_mailbox_chann_res *i2x;
137c02697cbSDavid Zhang 	struct xdna_mailbox_chann_res *x2i;
138c02697cbSDavid Zhang 	int mgmt_mb_irq;
139c02697cbSDavid Zhang 	int ret;
140c02697cbSDavid Zhang 
141c02697cbSDavid Zhang 	struct xdna_mailbox_res mbox_res = {
142c02697cbSDavid Zhang 		.ringbuf_base = ndev->rbuf_base,
143c02697cbSDavid Zhang 		.ringbuf_size = pci_resource_len(pdev, npriv->mbox_rbuf_bar),
144c02697cbSDavid Zhang 		.mbox_base = ndev->mbox_base,
145c02697cbSDavid Zhang 		.mbox_size = pci_resource_len(pdev, npriv->mbox_bar),
146c02697cbSDavid Zhang 		.name = "xdna_aie4_mailbox",
147c02697cbSDavid Zhang 	};
148c02697cbSDavid Zhang 
149c02697cbSDavid Zhang 	i2x = &ndev->aie.mgmt_i2x;
150c02697cbSDavid Zhang 	x2i = &ndev->aie.mgmt_x2i;
151c02697cbSDavid Zhang 
152c02697cbSDavid Zhang 	x2i->mb_head_ptr_reg = mbi->x2i_head_offset;
153c02697cbSDavid Zhang 	x2i->mb_tail_ptr_reg = mbi->x2i_tail_offset;
154c02697cbSDavid Zhang 	x2i->rb_start_addr = mbi->x2i_buffer_addr;
155c02697cbSDavid Zhang 	x2i->rb_size = mbi->x2i_buffer_size;
156c02697cbSDavid Zhang 
157c02697cbSDavid Zhang 	i2x->rb_start_addr = mbi->i2x_buffer_addr;
158c02697cbSDavid Zhang 	i2x->rb_size = mbi->i2x_buffer_size;
159c02697cbSDavid Zhang 	i2x->mb_head_ptr_reg = mbi->i2x_head_offset;
160c02697cbSDavid Zhang 	i2x->mb_tail_ptr_reg = mbi->i2x_tail_offset;
161c02697cbSDavid Zhang 
162c02697cbSDavid Zhang 	ndev->aie.mgmt_chan_idx = mbi->i2x_msi_idx;
163c02697cbSDavid Zhang 	aie_dump_mgmt_chann_debug(&ndev->aie);
164c02697cbSDavid Zhang 
165c02697cbSDavid Zhang 	ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
166c02697cbSDavid Zhang 	if (!ndev->mbox) {
167c02697cbSDavid Zhang 		XDNA_ERR(xdna, "failed to create mailbox device");
168c02697cbSDavid Zhang 		return -ENODEV;
169c02697cbSDavid Zhang 	}
170c02697cbSDavid Zhang 
171c02697cbSDavid Zhang 	ndev->aie.mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
172c02697cbSDavid Zhang 	if (!ndev->aie.mgmt_chann) {
173c02697cbSDavid Zhang 		XDNA_ERR(xdna, "failed to alloc mailbox channel");
174c02697cbSDavid Zhang 		return -ENODEV;
175c02697cbSDavid Zhang 	}
176c02697cbSDavid Zhang 
177c02697cbSDavid Zhang 	mgmt_mb_irq = pci_irq_vector(pdev, ndev->aie.mgmt_chan_idx);
178c02697cbSDavid Zhang 	if (mgmt_mb_irq < 0) {
179c02697cbSDavid Zhang 		XDNA_ERR(xdna, "failed to alloc irq vector, return %d", mgmt_mb_irq);
180c02697cbSDavid Zhang 		ret = mgmt_mb_irq;
181c02697cbSDavid Zhang 		goto free_channel;
182c02697cbSDavid Zhang 	}
183c02697cbSDavid Zhang 
184c02697cbSDavid Zhang 	ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
185c02697cbSDavid Zhang 					 &ndev->aie.mgmt_x2i,
186c02697cbSDavid Zhang 					 &ndev->aie.mgmt_i2x,
187c02697cbSDavid Zhang 					 NO_IOHUB,
188c02697cbSDavid Zhang 					 mgmt_mb_irq);
189c02697cbSDavid Zhang 	if (ret) {
190c02697cbSDavid Zhang 		XDNA_ERR(xdna, "failed to start management mailbox channel");
191c02697cbSDavid Zhang 		ret = -EINVAL;
192c02697cbSDavid Zhang 		goto free_channel;
193c02697cbSDavid Zhang 	}
194c02697cbSDavid Zhang 
195c02697cbSDavid Zhang 	XDNA_DBG(xdna, "Mailbox management channel created");
196c02697cbSDavid Zhang 	return 0;
197c02697cbSDavid Zhang 
198c02697cbSDavid Zhang free_channel:
199c02697cbSDavid Zhang 	xdna_mailbox_free_channel(ndev->aie.mgmt_chann);
200c02697cbSDavid Zhang 	ndev->aie.mgmt_chann = NULL;
201c02697cbSDavid Zhang 	return ret;
202c02697cbSDavid Zhang }
203c02697cbSDavid Zhang 
2047b1a245bSDavid Zhang static int aie4_mailbox_init(struct amdxdna_dev_hdl *ndev)
205c02697cbSDavid Zhang {
2067b1a245bSDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
207c02697cbSDavid Zhang 	struct mailbox_info mbox_info;
208c02697cbSDavid Zhang 	int ret;
209c02697cbSDavid Zhang 
210c02697cbSDavid Zhang 	ret = aie4_mailbox_info(xdna, &mbox_info);
211c02697cbSDavid Zhang 	if (ret)
212c02697cbSDavid Zhang 		return ret;
213c02697cbSDavid Zhang 
214c02697cbSDavid Zhang 	return aie4_mailbox_start(xdna, &mbox_info);
215c02697cbSDavid Zhang }
216c02697cbSDavid Zhang 
2177b1a245bSDavid Zhang static void aie4_fw_stop(struct amdxdna_dev_hdl *ndev)
218c02697cbSDavid Zhang {
219e69ef214SDavid Zhang 	aie_psp_stop(ndev->aie.psp_hdl);
22043c9a66eSDavid Zhang 	aie_smu_fini(ndev->aie.smu_hdl);
221c02697cbSDavid Zhang }
222c02697cbSDavid Zhang 
2237b1a245bSDavid Zhang static int aie4_fw_start(struct amdxdna_dev_hdl *ndev)
224c02697cbSDavid Zhang {
22543c9a66eSDavid Zhang 	int ret;
22643c9a66eSDavid Zhang 
22743c9a66eSDavid Zhang 	ret = aie_smu_init(ndev->aie.smu_hdl);
22843c9a66eSDavid Zhang 	if (ret) {
22943c9a66eSDavid Zhang 		XDNA_ERR(ndev->aie.xdna, "failed to init smu, ret %d", ret);
23043c9a66eSDavid Zhang 		return ret;
23143c9a66eSDavid Zhang 	}
23243c9a66eSDavid Zhang 
23343c9a66eSDavid Zhang 	ret = aie_psp_start(ndev->aie.psp_hdl);
23443c9a66eSDavid Zhang 	if (ret) {
23543c9a66eSDavid Zhang 		XDNA_ERR(ndev->aie.xdna, "failed to start psp, ret %d", ret);
23643c9a66eSDavid Zhang 		aie_smu_fini(ndev->aie.smu_hdl);
23743c9a66eSDavid Zhang 	}
23843c9a66eSDavid Zhang 
23943c9a66eSDavid Zhang 	return ret;
240c02697cbSDavid Zhang }
241c02697cbSDavid Zhang 
242ce9414d0SDavid Zhang static int aie4_partition_init(struct amdxdna_dev_hdl *ndev)
243ce9414d0SDavid Zhang {
244ce9414d0SDavid Zhang 	DECLARE_AIE_MSG(aie4_msg_create_partition, AIE4_MSG_OP_CREATE_PARTITION);
245ce9414d0SDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
246ce9414d0SDavid Zhang 	int ret;
247ce9414d0SDavid Zhang 
248ce9414d0SDavid Zhang 	req.partition_col_start = 0;
249ce9414d0SDavid Zhang 	req.partition_col_count = AIE4_TOTAL_COLUMN;
250ce9414d0SDavid Zhang 	ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
251ce9414d0SDavid Zhang 	if (ret) {
252ce9414d0SDavid Zhang 		XDNA_ERR(xdna, "partition init failed: %d", ret);
253ce9414d0SDavid Zhang 		return ret;
254ce9414d0SDavid Zhang 	}
255ce9414d0SDavid Zhang 
256ce9414d0SDavid Zhang 	ndev->partition_id = resp.partition_id;
257ce9414d0SDavid Zhang 	return 0;
258ce9414d0SDavid Zhang }
259ce9414d0SDavid Zhang 
260ce9414d0SDavid Zhang static void aie4_partition_fini(struct amdxdna_dev_hdl *ndev)
261ce9414d0SDavid Zhang {
262ce9414d0SDavid Zhang 	DECLARE_AIE_MSG(aie4_msg_destroy_partition, AIE4_MSG_OP_DESTROY_PARTITION);
263ce9414d0SDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
264ce9414d0SDavid Zhang 	int ret;
265ce9414d0SDavid Zhang 
266ce9414d0SDavid Zhang 	req.partition_id = ndev->partition_id;
267ce9414d0SDavid Zhang 	ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
268ce9414d0SDavid Zhang 	if (ret)
269ce9414d0SDavid Zhang 		XDNA_ERR(xdna, "partition fini failed: %d", ret);
270ce9414d0SDavid Zhang }
271ce9414d0SDavid Zhang 
2720b087e06SDavid Zhang static int aie4_query(struct amdxdna_dev_hdl *ndev)
2730b087e06SDavid Zhang {
2740b087e06SDavid Zhang 	return aie4_query_aie_metadata(ndev, &ndev->aie.metadata);
2750b087e06SDavid Zhang }
2760b087e06SDavid Zhang 
2777b1a245bSDavid Zhang static int aie4_pf_hw_start(struct amdxdna_dev_hdl *ndev)
278c02697cbSDavid Zhang {
279c02697cbSDavid Zhang 	int ret;
280c02697cbSDavid Zhang 
2817b1a245bSDavid Zhang 	ret = aie4_fw_start(ndev);
282c02697cbSDavid Zhang 	if (ret)
283c02697cbSDavid Zhang 		return ret;
284c02697cbSDavid Zhang 
2857b1a245bSDavid Zhang 	ret = aie4_mailbox_init(ndev);
286c02697cbSDavid Zhang 	if (ret)
2877b1a245bSDavid Zhang 		goto stop_fw;
288c02697cbSDavid Zhang 
289*c0069781SNishad Saraf 	ret = aie4_attach_work_buffer(ndev);
290*c0069781SNishad Saraf 	if (ret)
291*c0069781SNishad Saraf 		goto mbox_fini;
292*c0069781SNishad Saraf 
293c02697cbSDavid Zhang 	return 0;
294c02697cbSDavid Zhang 
295*c0069781SNishad Saraf mbox_fini:
296*c0069781SNishad Saraf 	aie4_mailbox_fini(ndev);
2977b1a245bSDavid Zhang stop_fw:
2987b1a245bSDavid Zhang 	aie4_fw_stop(ndev);
299c02697cbSDavid Zhang 
300c02697cbSDavid Zhang 	return ret;
301c02697cbSDavid Zhang }
302c02697cbSDavid Zhang 
3037b1a245bSDavid Zhang static void aie4_pf_hw_stop(struct amdxdna_dev_hdl *ndev)
304c02697cbSDavid Zhang {
3057b1a245bSDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
306c02697cbSDavid Zhang 
307c02697cbSDavid Zhang 	drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
308c02697cbSDavid Zhang 
3097b1a245bSDavid Zhang 	aie4_suspend_fw(ndev);
310c02697cbSDavid Zhang 	aie4_mailbox_fini(ndev);
3117b1a245bSDavid Zhang 	aie4_fw_stop(ndev);
3127b1a245bSDavid Zhang }
313c02697cbSDavid Zhang 
3147b1a245bSDavid Zhang static int aie4_vf_hw_start(struct amdxdna_dev_hdl *ndev)
3157b1a245bSDavid Zhang {
316ce9414d0SDavid Zhang 	int ret;
317ce9414d0SDavid Zhang 
318ce9414d0SDavid Zhang 	ret = aie4_mailbox_init(ndev);
319ce9414d0SDavid Zhang 	if (ret)
320ce9414d0SDavid Zhang 		return ret;
321ce9414d0SDavid Zhang 
3220b087e06SDavid Zhang 	ret = aie4_query(ndev);
3230b087e06SDavid Zhang 	if (ret)
3240b087e06SDavid Zhang 		goto mailbox_fini;
3250b087e06SDavid Zhang 
326ce9414d0SDavid Zhang 	ret = aie4_partition_init(ndev);
327ce9414d0SDavid Zhang 	if (ret)
328ce9414d0SDavid Zhang 		goto mailbox_fini;
329ce9414d0SDavid Zhang 
330ce9414d0SDavid Zhang 	return 0;
331ce9414d0SDavid Zhang 
332ce9414d0SDavid Zhang mailbox_fini:
333ce9414d0SDavid Zhang 	aie4_mailbox_fini(ndev);
334ce9414d0SDavid Zhang 	return ret;
3357b1a245bSDavid Zhang }
3367b1a245bSDavid Zhang 
3377b1a245bSDavid Zhang static void aie4_vf_hw_stop(struct amdxdna_dev_hdl *ndev)
3387b1a245bSDavid Zhang {
3397b1a245bSDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
3407b1a245bSDavid Zhang 
3417b1a245bSDavid Zhang 	drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
3427b1a245bSDavid Zhang 
343ce9414d0SDavid Zhang 	aie4_partition_fini(ndev);
3447b1a245bSDavid Zhang 	aie4_mailbox_fini(ndev);
345c02697cbSDavid Zhang }
346c02697cbSDavid Zhang 
347e69ef214SDavid Zhang static int aie4_request_firmware(struct amdxdna_dev_hdl *ndev,
348e69ef214SDavid Zhang 				 const struct firmware **npufw,
349e69ef214SDavid Zhang 				 const struct firmware **certfw)
350e69ef214SDavid Zhang {
351e69ef214SDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
352e69ef214SDavid Zhang 	struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
353e69ef214SDavid Zhang 	char fw_name[128];
354e69ef214SDavid Zhang 	int ret;
355e69ef214SDavid Zhang 
356e69ef214SDavid Zhang 	ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s",
357e69ef214SDavid Zhang 		       pdev->device, pdev->revision, ndev->priv->npufw_path);
358e69ef214SDavid Zhang 	if (ret >= sizeof(fw_name)) {
359e69ef214SDavid Zhang 		XDNA_ERR(xdna, "npu firmware path is truncated");
360e69ef214SDavid Zhang 		return -EINVAL;
361e69ef214SDavid Zhang 	}
362e69ef214SDavid Zhang 
363e69ef214SDavid Zhang 	ret = request_firmware(npufw, fw_name, &pdev->dev);
364e69ef214SDavid Zhang 	if (ret) {
365e69ef214SDavid Zhang 		XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret);
366e69ef214SDavid Zhang 		return ret;
367e69ef214SDavid Zhang 	}
368e69ef214SDavid Zhang 
369e69ef214SDavid Zhang 	ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s",
370e69ef214SDavid Zhang 		       pdev->device, pdev->revision, ndev->priv->certfw_path);
371e69ef214SDavid Zhang 	if (ret >= sizeof(fw_name)) {
372e69ef214SDavid Zhang 		XDNA_ERR(xdna, "cert firmware path is truncated");
373e69ef214SDavid Zhang 		ret = -EINVAL;
374e69ef214SDavid Zhang 		goto release_npufw;
375e69ef214SDavid Zhang 	}
376e69ef214SDavid Zhang 
377e69ef214SDavid Zhang 	ret = request_firmware(certfw, fw_name, &pdev->dev);
378e69ef214SDavid Zhang 	if (ret) {
379e69ef214SDavid Zhang 		XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret);
380e69ef214SDavid Zhang 		goto release_npufw;
381e69ef214SDavid Zhang 	}
382e69ef214SDavid Zhang 
383e69ef214SDavid Zhang 	return 0;
384e69ef214SDavid Zhang 
385e69ef214SDavid Zhang release_npufw:
386e69ef214SDavid Zhang 	release_firmware(*npufw);
387e69ef214SDavid Zhang 
388e69ef214SDavid Zhang 	return ret;
389e69ef214SDavid Zhang }
390e69ef214SDavid Zhang 
391e69ef214SDavid Zhang static void aie4_release_firmware(struct amdxdna_dev_hdl *ndev,
392e69ef214SDavid Zhang 				  const struct firmware *npufw,
393e69ef214SDavid Zhang 				  const struct firmware *certfw)
394e69ef214SDavid Zhang {
395e69ef214SDavid Zhang 	release_firmware(certfw);
396e69ef214SDavid Zhang 	release_firmware(npufw);
397e69ef214SDavid Zhang }
398e69ef214SDavid Zhang 
399e69ef214SDavid Zhang static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev,
400e69ef214SDavid Zhang 				 const struct firmware *npufw,
401e69ef214SDavid Zhang 				 const struct firmware *certfw,
402e69ef214SDavid Zhang 				 void __iomem *tbl[PCI_NUM_RESOURCES])
403e69ef214SDavid Zhang {
404e69ef214SDavid Zhang 	struct amdxdna_dev *xdna = ndev->aie.xdna;
405e69ef214SDavid Zhang 	struct psp_config psp_conf;
40643c9a66eSDavid Zhang 	struct smu_config smu_conf;
407e69ef214SDavid Zhang 	int i;
408e69ef214SDavid Zhang 
409e69ef214SDavid Zhang 	psp_conf.fw_size = npufw->size;
410e69ef214SDavid Zhang 	psp_conf.fw_buf = npufw->data;
411e69ef214SDavid Zhang 	psp_conf.certfw_size = certfw->size;
412e69ef214SDavid Zhang 	psp_conf.certfw_buf = certfw->data;
413e69ef214SDavid Zhang 	psp_conf.arg2_mask = ~0;
414e69ef214SDavid Zhang 	psp_conf.notify_val = PSP_NOTIFY_INTR;
415e69ef214SDavid Zhang 	for (i = 0; i < PSP_MAX_REGS; i++)
416e69ef214SDavid Zhang 		psp_conf.psp_regs[i] = tbl[PSP_REG_BAR(ndev, i)] + PSP_REG_OFF(ndev, i);
417e69ef214SDavid Zhang 	ndev->aie.psp_hdl = aiem_psp_create(&xdna->ddev, &psp_conf);
418e69ef214SDavid Zhang 	if (!ndev->aie.psp_hdl) {
419e69ef214SDavid Zhang 		XDNA_ERR(xdna, "failed to create psp");
420e69ef214SDavid Zhang 		return -ENOMEM;
421e69ef214SDavid Zhang 	}
422e69ef214SDavid Zhang 
42343c9a66eSDavid Zhang 	for (i = 0; i < SMU_MAX_REGS; i++)
42443c9a66eSDavid Zhang 		smu_conf.smu_regs[i] = tbl[SMU_REG_BAR(ndev, i)] + SMU_REG_OFF(ndev, i);
42543c9a66eSDavid Zhang 	ndev->aie.smu_hdl = aiem_smu_create(&xdna->ddev, &smu_conf);
42643c9a66eSDavid Zhang 	if (!ndev->aie.smu_hdl) {
42743c9a66eSDavid Zhang 		XDNA_ERR(xdna, "failed to create smu");
42843c9a66eSDavid Zhang 		return -ENOMEM;
42943c9a66eSDavid Zhang 	}
43043c9a66eSDavid Zhang 
431e69ef214SDavid Zhang 	return 0;
432e69ef214SDavid Zhang }
433e69ef214SDavid Zhang 
4347b1a245bSDavid Zhang static int aie4_load_fw(struct amdxdna_dev_hdl *ndev,
4357b1a245bSDavid Zhang 			void __iomem *tbl[PCI_NUM_RESOURCES])
436c02697cbSDavid Zhang {
437e69ef214SDavid Zhang 	const struct firmware *npufw, *certfw;
4387b1a245bSDavid Zhang 	int ret;
4397b1a245bSDavid Zhang 
4407b1a245bSDavid Zhang 	if (!ndev->priv->npufw_path && !ndev->priv->certfw_path)
4417b1a245bSDavid Zhang 		return 0;
4427b1a245bSDavid Zhang 
4437b1a245bSDavid Zhang 	ret = aie4_request_firmware(ndev, &npufw, &certfw);
4447b1a245bSDavid Zhang 	if (ret)
4457b1a245bSDavid Zhang 		return ret;
4467b1a245bSDavid Zhang 
4477b1a245bSDavid Zhang 	ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl);
4487b1a245bSDavid Zhang 	aie4_release_firmware(ndev, npufw, certfw);
4497b1a245bSDavid Zhang 
4507b1a245bSDavid Zhang 	return ret;
4517b1a245bSDavid Zhang }
4527b1a245bSDavid Zhang 
4537b1a245bSDavid Zhang static int aie4m_pcidev_init(struct amdxdna_dev *xdna)
4547b1a245bSDavid Zhang {
4557b1a245bSDavid Zhang 	struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
4567b1a245bSDavid Zhang 	struct amdxdna_dev_hdl *ndev;
4577b1a245bSDavid Zhang 	void __iomem *tbl[PCI_NUM_RESOURCES] = {0};
458c02697cbSDavid Zhang 	unsigned long bars = 0;
459c02697cbSDavid Zhang 	int ret, i;
460c02697cbSDavid Zhang 
4617b1a245bSDavid Zhang 	ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL);
4627b1a245bSDavid Zhang 	if (!ndev)
4637b1a245bSDavid Zhang 		return -ENOMEM;
4647b1a245bSDavid Zhang 
4657b1a245bSDavid Zhang 	ndev->priv = xdna->dev_info->dev_priv;
4667b1a245bSDavid Zhang 	ndev->aie.xdna = xdna;
4677b1a245bSDavid Zhang 	xdna->dev_handle = ndev;
4687b1a245bSDavid Zhang 
46919361279SDavid Zhang 	xa_init_flags(&ndev->cert_comp_xa, XA_FLAGS_ALLOC);
47019361279SDavid Zhang 	mutex_init(&ndev->cert_comp_lock);
47119361279SDavid Zhang 
472c02697cbSDavid Zhang 	/* Enable managed PCI device */
473c02697cbSDavid Zhang 	ret = pcim_enable_device(pdev);
474c02697cbSDavid Zhang 	if (ret) {
475c02697cbSDavid Zhang 		XDNA_ERR(xdna, "pcim enable device failed, ret %d", ret);
476c02697cbSDavid Zhang 		return ret;
477c02697cbSDavid Zhang 	}
478c02697cbSDavid Zhang 
479c02697cbSDavid Zhang 	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
480c02697cbSDavid Zhang 	if (ret) {
481c02697cbSDavid Zhang 		XDNA_ERR(xdna, "failed to set DMA mask to 64:%d", ret);
482c02697cbSDavid Zhang 		return ret;
483c02697cbSDavid Zhang 	}
484c02697cbSDavid Zhang 
485e69ef214SDavid Zhang 	for (i = 0; i < PSP_MAX_REGS; i++)
486e69ef214SDavid Zhang 		set_bit(PSP_REG_BAR(ndev, i), &bars);
48743c9a66eSDavid Zhang 	for (i = 0; i < SMU_MAX_REGS; i++)
48843c9a66eSDavid Zhang 		set_bit(SMU_REG_BAR(ndev, i), &bars);
489c02697cbSDavid Zhang 	set_bit(xdna->dev_info->mbox_bar, &bars);
490c02697cbSDavid Zhang 	set_bit(xdna->dev_info->sram_bar, &bars);
491c02697cbSDavid Zhang 
492c02697cbSDavid Zhang 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
493c02697cbSDavid Zhang 		if (!test_bit(i, &bars))
494c02697cbSDavid Zhang 			continue;
495c02697cbSDavid Zhang 		tbl[i] = pcim_iomap(pdev, i, 0);
496c02697cbSDavid Zhang 		if (!tbl[i]) {
497c02697cbSDavid Zhang 			XDNA_ERR(xdna, "map bar %d failed", i);
498c02697cbSDavid Zhang 			return -ENOMEM;
499c02697cbSDavid Zhang 		}
500c02697cbSDavid Zhang 	}
501c02697cbSDavid Zhang 
502c02697cbSDavid Zhang 	ndev->mbox_base = tbl[xdna->dev_info->mbox_bar];
503c02697cbSDavid Zhang 	ndev->rbuf_base = tbl[xdna->dev_info->sram_bar];
504c02697cbSDavid Zhang 
505c02697cbSDavid Zhang 	pci_set_master(pdev);
506c02697cbSDavid Zhang 
5077b1a245bSDavid Zhang 	ret = aie4_load_fw(ndev, tbl);
508e69ef214SDavid Zhang 	if (ret)
5097b1a245bSDavid Zhang 		return ret;
510e69ef214SDavid Zhang 
511c02697cbSDavid Zhang 	ret = aie4_irq_init(xdna);
512c02697cbSDavid Zhang 	if (ret)
513c02697cbSDavid Zhang 		return ret;
514c02697cbSDavid Zhang 
515d8c33b9cSMax Zhen 	amdxdna_vbnv_init(xdna);
5167b1a245bSDavid Zhang 	XDNA_DBG(xdna, "init finished");
5177b1a245bSDavid Zhang 
518c02697cbSDavid Zhang 	return 0;
519c02697cbSDavid Zhang }
520c02697cbSDavid Zhang 
52191f4da82SDavid Zhang static int aie4_doorbell_mmap(struct amdxdna_client *client, struct vm_area_struct *vma)
52291f4da82SDavid Zhang {
52391f4da82SDavid Zhang 	struct amdxdna_dev *xdna = client->xdna;
52491f4da82SDavid Zhang 	struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
52591f4da82SDavid Zhang 	const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
52691f4da82SDavid Zhang 	phys_addr_t res_start;
52791f4da82SDavid Zhang 	unsigned long pfn;
52891f4da82SDavid Zhang 	int ret;
52991f4da82SDavid Zhang 
53091f4da82SDavid Zhang 	if (!aie4_hwctx_valid_doorbell(client, vma->vm_pgoff)) {
53191f4da82SDavid Zhang 		XDNA_ERR(xdna, "Invalid doorbell page offset 0x%lx", vma->vm_pgoff);
53291f4da82SDavid Zhang 		return -EINVAL;
53391f4da82SDavid Zhang 	}
53491f4da82SDavid Zhang 
53591f4da82SDavid Zhang 	if (vma_pages(vma) != 1) {
53691f4da82SDavid Zhang 		XDNA_ERR(xdna, "can only map one page, got %ld", vma_pages(vma));
53791f4da82SDavid Zhang 		return -EINVAL;
53891f4da82SDavid Zhang 	}
53991f4da82SDavid Zhang 
54091f4da82SDavid Zhang 	res_start = pci_resource_start(pdev, xdna->dev_info->doorbell_bar) + npriv->doorbell_off;
54191f4da82SDavid Zhang 	pfn = PHYS_PFN(res_start) + vma->vm_pgoff;
54291f4da82SDavid Zhang 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
54391f4da82SDavid Zhang 	vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
54491f4da82SDavid Zhang 	ret = io_remap_pfn_range(vma, vma->vm_start,
54591f4da82SDavid Zhang 				 pfn,
54691f4da82SDavid Zhang 				 PAGE_SIZE,
54791f4da82SDavid Zhang 				 vma->vm_page_prot);
54891f4da82SDavid Zhang 
54991f4da82SDavid Zhang 	XDNA_DBG(xdna, "doorbell ret %d", ret);
55091f4da82SDavid Zhang 	return ret;
55191f4da82SDavid Zhang }
55291f4da82SDavid Zhang 
5530b087e06SDavid Zhang static int aie4_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args)
5540b087e06SDavid Zhang {
5550b087e06SDavid Zhang 	struct amdxdna_dev *xdna = client->xdna;
5560b087e06SDavid Zhang 	struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
5570b087e06SDavid Zhang 	int ret;
5580b087e06SDavid Zhang 
5590b087e06SDavid Zhang 	switch (args->param) {
5600b087e06SDavid Zhang 	case DRM_AMDXDNA_QUERY_AIE_METADATA:
5610b087e06SDavid Zhang 		ret = amdxdna_get_metadata(&ndev->aie, client, args);
5620b087e06SDavid Zhang 		break;
5630b087e06SDavid Zhang 	default:
5640b087e06SDavid Zhang 		XDNA_ERR(xdna, "Not supported request parameter %u", args->param);
5650b087e06SDavid Zhang 		ret = -EOPNOTSUPP;
5660b087e06SDavid Zhang 	}
5670b087e06SDavid Zhang 
5680b087e06SDavid Zhang 	XDNA_DBG(xdna, "Got param %d", args->param);
5690b087e06SDavid Zhang 
5700b087e06SDavid Zhang 	return ret;
5710b087e06SDavid Zhang }
5720b087e06SDavid Zhang 
573*c0069781SNishad Saraf static int aie4_alloc_work_buffer(struct amdxdna_dev_hdl *ndev)
574*c0069781SNishad Saraf {
575*c0069781SNishad Saraf 	struct amdxdna_dev *xdna = ndev->aie.xdna;
576*c0069781SNishad Saraf 	u32 buf_size = AIE4_WORK_BUFFER_MIN_SIZE;
577*c0069781SNishad Saraf 
578*c0069781SNishad Saraf 	ndev->work_buf = amdxdna_alloc_msg_buffer(xdna, &buf_size,
579*c0069781SNishad Saraf 						  &ndev->work_buf_addr);
580*c0069781SNishad Saraf 	if (IS_ERR(ndev->work_buf)) {
581*c0069781SNishad Saraf 		int ret = PTR_ERR(ndev->work_buf);
582*c0069781SNishad Saraf 
583*c0069781SNishad Saraf 		XDNA_ERR(xdna, "Failed to alloc work buffer, size 0x%x",
584*c0069781SNishad Saraf 			 AIE4_WORK_BUFFER_MIN_SIZE);
585*c0069781SNishad Saraf 		ndev->work_buf = NULL;
586*c0069781SNishad Saraf 		return ret;
587*c0069781SNishad Saraf 	}
588*c0069781SNishad Saraf 
589*c0069781SNishad Saraf 	ndev->work_buf_size = buf_size;
590*c0069781SNishad Saraf 	XDNA_DBG(xdna, "Work buffer allocated: size 0x%x", buf_size);
591*c0069781SNishad Saraf 
592*c0069781SNishad Saraf 	return 0;
593*c0069781SNishad Saraf }
594*c0069781SNishad Saraf 
595*c0069781SNishad Saraf static void aie4_free_work_buffer(struct amdxdna_dev_hdl *ndev)
596*c0069781SNishad Saraf {
597*c0069781SNishad Saraf 	struct amdxdna_dev *xdna = ndev->aie.xdna;
598*c0069781SNishad Saraf 
599*c0069781SNishad Saraf 	if (!ndev->work_buf)
600*c0069781SNishad Saraf 		return;
601*c0069781SNishad Saraf 
602*c0069781SNishad Saraf 	amdxdna_free_msg_buffer(xdna, ndev->work_buf_size, ndev->work_buf,
603*c0069781SNishad Saraf 				ndev->work_buf_addr);
604*c0069781SNishad Saraf 	ndev->work_buf = NULL;
605*c0069781SNishad Saraf }
606*c0069781SNishad Saraf 
6077b1a245bSDavid Zhang static int aie4_pf_init(struct amdxdna_dev *xdna)
6087b1a245bSDavid Zhang {
6097b1a245bSDavid Zhang 	int ret;
6107b1a245bSDavid Zhang 
6117b1a245bSDavid Zhang 	ret = aie4m_pcidev_init(xdna);
6127b1a245bSDavid Zhang 	if (ret)
6137b1a245bSDavid Zhang 		return ret;
6147b1a245bSDavid Zhang 
615*c0069781SNishad Saraf 	ret = aie4_alloc_work_buffer(xdna->dev_handle);
616*c0069781SNishad Saraf 	if (ret)
617*c0069781SNishad Saraf 		return ret;
618*c0069781SNishad Saraf 
619*c0069781SNishad Saraf 	ret = aie4_pf_hw_start(xdna->dev_handle);
620*c0069781SNishad Saraf 	if (ret)
621*c0069781SNishad Saraf 		goto free_work_buf;
622*c0069781SNishad Saraf 
623*c0069781SNishad Saraf 	return 0;
624*c0069781SNishad Saraf 
625*c0069781SNishad Saraf free_work_buf:
626*c0069781SNishad Saraf 	aie4_free_work_buffer(xdna->dev_handle);
627*c0069781SNishad Saraf 	return ret;
6287b1a245bSDavid Zhang }
6297b1a245bSDavid Zhang 
6307b1a245bSDavid Zhang static int aie4_vf_init(struct amdxdna_dev *xdna)
6317b1a245bSDavid Zhang {
6327b1a245bSDavid Zhang 	int ret;
6337b1a245bSDavid Zhang 
6347b1a245bSDavid Zhang 	ret = aie4m_pcidev_init(xdna);
6357b1a245bSDavid Zhang 	if (ret)
6367b1a245bSDavid Zhang 		return ret;
6377b1a245bSDavid Zhang 
6387b1a245bSDavid Zhang 	return aie4_vf_hw_start(xdna->dev_handle);
6397b1a245bSDavid Zhang }
6407b1a245bSDavid Zhang 
6417b1a245bSDavid Zhang static void aie4_pf_fini(struct amdxdna_dev *xdna)
6427b1a245bSDavid Zhang {
6437b1a245bSDavid Zhang 	aie4_sriov_stop(xdna->dev_handle);
6447b1a245bSDavid Zhang 	aie4_pf_hw_stop(xdna->dev_handle);
645*c0069781SNishad Saraf 	aie4_free_work_buffer(xdna->dev_handle);
6467b1a245bSDavid Zhang }
6477b1a245bSDavid Zhang 
6487b1a245bSDavid Zhang static void aie4_vf_fini(struct amdxdna_dev *xdna)
6497b1a245bSDavid Zhang {
6507b1a245bSDavid Zhang 	aie4_vf_hw_stop(xdna->dev_handle);
6517b1a245bSDavid Zhang }
6527b1a245bSDavid Zhang 
6537b1a245bSDavid Zhang const struct amdxdna_dev_ops aie4_pf_ops = {
6547b1a245bSDavid Zhang 	.init			= aie4_pf_init,
6557b1a245bSDavid Zhang 	.fini			= aie4_pf_fini,
656c02697cbSDavid Zhang 	.sriov_configure        = aie4_sriov_configure,
657c02697cbSDavid Zhang };
6587b1a245bSDavid Zhang 
6597b1a245bSDavid Zhang const struct amdxdna_dev_ops aie4_vf_ops = {
6607b1a245bSDavid Zhang 	.init			= aie4_vf_init,
6617b1a245bSDavid Zhang 	.fini			= aie4_vf_fini,
66219361279SDavid Zhang 	.hwctx_init		= aie4_hwctx_init,
66319361279SDavid Zhang 	.hwctx_fini		= aie4_hwctx_fini,
66491f4da82SDavid Zhang 	.mmap			= aie4_doorbell_mmap,
66591f4da82SDavid Zhang 	.cmd_wait		= aie4_cmd_wait,
6660b087e06SDavid Zhang 	.get_aie_info		= aie4_get_info,
6677b1a245bSDavid Zhang };
668