File Index
Files and directories
Sign in
FILE

amdxdna_pci_drv.c

File preview with syntax highlighting.

linux-6.19.14/drivers/accel/amdxdna/amdxdna_pci_drv.c C
  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_accel.h>
  8#include <drm/drm_drv.h>
  9#include <drm/drm_gem.h>
 10#include <drm/drm_gem_shmem_helper.h>
 11#include <drm/drm_ioctl.h>
 12#include <drm/drm_managed.h>
 13#include <drm/gpu_scheduler.h>
 14#include <linux/iommu.h>
 15#include <linux/pci.h>
 16
 17#include "amdxdna_ctx.h"
 18#include "amdxdna_gem.h"
 19#include "amdxdna_pci_drv.h"
 20#include "amdxdna_pm.h"
 21
 22MODULE_FIRMWARE("amdnpu/1502_00/npu.sbin");
 23MODULE_FIRMWARE("amdnpu/17f0_10/npu.sbin");
 24MODULE_FIRMWARE("amdnpu/17f0_11/npu.sbin");
 25MODULE_FIRMWARE("amdnpu/17f0_20/npu.sbin");
 26
 27/*
 28 * 0.0: Initial version
 29 * 0.1: Support getting all hardware contexts by DRM_IOCTL_AMDXDNA_GET_ARRAY
 30 * 0.2: Support getting last error hardware error
 31 * 0.3: Support firmware debug buffer
 32 * 0.4: Support getting resource information
 33 * 0.5: Support getting telemetry data
 34 * 0.6: Support preemption
 35 */
 36#define AMDXDNA_DRIVER_MAJOR		0
 37#define AMDXDNA_DRIVER_MINOR		6
 38
 39/*
 40 * Bind the driver base on (vendor_id, device_id) pair and later use the
 41 * (device_id, rev_id) pair as a key to select the devices. The devices with
 42 * same device_id have very similar interface to host driver.
 43 */
 44static const struct pci_device_id pci_ids[] = {
 45	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1502) },
 46	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f0) },
 47	{0}
 48};
 49
 50MODULE_DEVICE_TABLE(pci, pci_ids);
 51
 52static const struct amdxdna_device_id amdxdna_ids[] = {
 53	{ 0x1502, 0x0,  &dev_npu1_info },
 54	{ 0x17f0, 0x0,  &dev_npu2_info },
 55	{ 0x17f0, 0x10, &dev_npu4_info },
 56	{ 0x17f0, 0x11, &dev_npu5_info },
 57	{ 0x17f0, 0x20, &dev_npu6_info },
 58	{0}
 59};
 60
 61static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
 62{
 63	struct amdxdna_dev *xdna = to_xdna_dev(ddev);
 64	struct amdxdna_client *client;
 65	int ret;
 66
 67	client = kzalloc(sizeof(*client), GFP_KERNEL);
 68	if (!client)
 69		return -ENOMEM;
 70
 71	client->pid = pid_nr(rcu_access_pointer(filp->pid));
 72	client->xdna = xdna;
 73
 74	client->sva = iommu_sva_bind_device(xdna->ddev.dev, current->mm);
 75	if (IS_ERR(client->sva)) {
 76		ret = PTR_ERR(client->sva);
 77		XDNA_ERR(xdna, "SVA bind device failed, ret %d", ret);
 78		goto failed;
 79	}
 80	client->pasid = iommu_sva_get_pasid(client->sva);
 81	if (client->pasid == IOMMU_PASID_INVALID) {
 82		XDNA_ERR(xdna, "SVA get pasid failed");
 83		ret = -ENODEV;
 84		goto unbind_sva;
 85	}
 86	client->mm = current->mm;
 87	mmgrab(client->mm);
 88	init_srcu_struct(&client->hwctx_srcu);
 89	xa_init_flags(&client->hwctx_xa, XA_FLAGS_ALLOC);
 90	mutex_init(&client->mm_lock);
 91
 92	mutex_lock(&xdna->dev_lock);
 93	list_add_tail(&client->node, &xdna->client_list);
 94	mutex_unlock(&xdna->dev_lock);
 95
 96	filp->driver_priv = client;
 97	client->filp = filp;
 98
 99	XDNA_DBG(xdna, "pid %d opened", client->pid);
100	return 0;
101
102unbind_sva:
103	iommu_sva_unbind_device(client->sva);
104failed:
105	kfree(client);
106
107	return ret;
108}
109
110static void amdxdna_drm_close(struct drm_device *ddev, struct drm_file *filp)
111{
112	struct amdxdna_client *client = filp->driver_priv;
113	struct amdxdna_dev *xdna = to_xdna_dev(ddev);
114
115	XDNA_DBG(xdna, "closing pid %d", client->pid);
116
117	xa_destroy(&client->hwctx_xa);
118	cleanup_srcu_struct(&client->hwctx_srcu);
119	mutex_destroy(&client->mm_lock);
120	if (client->dev_heap)
121		drm_gem_object_put(to_gobj(client->dev_heap));
122
123	iommu_sva_unbind_device(client->sva);
124	mmdrop(client->mm);
125
126	XDNA_DBG(xdna, "pid %d closed", client->pid);
127	kfree(client);
128}
129
130static int amdxdna_flush(struct file *f, fl_owner_t id)
131{
132	struct drm_file *filp = f->private_data;
133	struct amdxdna_client *client = filp->driver_priv;
134	struct amdxdna_dev *xdna = client->xdna;
135	int idx;
136
137	XDNA_DBG(xdna, "PID %d flushing...", client->pid);
138	if (!drm_dev_enter(&xdna->ddev, &idx))
139		return 0;
140
141	mutex_lock(&xdna->dev_lock);
142	list_del_init(&client->node);
143	amdxdna_hwctx_remove_all(client);
144	mutex_unlock(&xdna->dev_lock);
145
146	drm_dev_exit(idx);
147	return 0;
148}
149
150static int amdxdna_drm_get_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
151{
152	struct amdxdna_client *client = filp->driver_priv;
153	struct amdxdna_dev *xdna = to_xdna_dev(dev);
154	struct amdxdna_drm_get_info *args = data;
155	int ret;
156
157	if (!xdna->dev_info->ops->get_aie_info)
158		return -EOPNOTSUPP;
159
160	XDNA_DBG(xdna, "Request parameter %u", args->param);
161	mutex_lock(&xdna->dev_lock);
162	ret = xdna->dev_info->ops->get_aie_info(client, args);
163	mutex_unlock(&xdna->dev_lock);
164	return ret;
165}
166
167static int amdxdna_drm_get_array_ioctl(struct drm_device *dev, void *data,
168				       struct drm_file *filp)
169{
170	struct amdxdna_client *client = filp->driver_priv;
171	struct amdxdna_dev *xdna = to_xdna_dev(dev);
172	struct amdxdna_drm_get_array *args = data;
173
174	if (!xdna->dev_info->ops->get_array)
175		return -EOPNOTSUPP;
176
177	if (args->pad || !args->num_element || !args->element_size)
178		return -EINVAL;
179
180	guard(mutex)(&xdna->dev_lock);
181	return xdna->dev_info->ops->get_array(client, args);
182}
183
184static int amdxdna_drm_set_state_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
185{
186	struct amdxdna_client *client = filp->driver_priv;
187	struct amdxdna_dev *xdna = to_xdna_dev(dev);
188	struct amdxdna_drm_set_state *args = data;
189	int ret;
190
191	if (!xdna->dev_info->ops->set_aie_state)
192		return -EOPNOTSUPP;
193
194	XDNA_DBG(xdna, "Request parameter %u", args->param);
195	mutex_lock(&xdna->dev_lock);
196	ret = xdna->dev_info->ops->set_aie_state(client, args);
197	mutex_unlock(&xdna->dev_lock);
198
199	return ret;
200}
201
202static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = {
203	/* Context */
204	DRM_IOCTL_DEF_DRV(AMDXDNA_CREATE_HWCTX, amdxdna_drm_create_hwctx_ioctl, 0),
205	DRM_IOCTL_DEF_DRV(AMDXDNA_DESTROY_HWCTX, amdxdna_drm_destroy_hwctx_ioctl, 0),
206	DRM_IOCTL_DEF_DRV(AMDXDNA_CONFIG_HWCTX, amdxdna_drm_config_hwctx_ioctl, 0),
207	/* BO */
208	DRM_IOCTL_DEF_DRV(AMDXDNA_CREATE_BO, amdxdna_drm_create_bo_ioctl, 0),
209	DRM_IOCTL_DEF_DRV(AMDXDNA_GET_BO_INFO, amdxdna_drm_get_bo_info_ioctl, 0),
210	DRM_IOCTL_DEF_DRV(AMDXDNA_SYNC_BO, amdxdna_drm_sync_bo_ioctl, 0),
211	/* Execution */
212	DRM_IOCTL_DEF_DRV(AMDXDNA_EXEC_CMD, amdxdna_drm_submit_cmd_ioctl, 0),
213	/* AIE hardware */
214	DRM_IOCTL_DEF_DRV(AMDXDNA_GET_INFO, amdxdna_drm_get_info_ioctl, 0),
215	DRM_IOCTL_DEF_DRV(AMDXDNA_GET_ARRAY, amdxdna_drm_get_array_ioctl, 0),
216	DRM_IOCTL_DEF_DRV(AMDXDNA_SET_STATE, amdxdna_drm_set_state_ioctl, DRM_ROOT_ONLY),
217};
218
219static const struct file_operations amdxdna_fops = {
220	.owner		= THIS_MODULE,
221	.open		= accel_open,
222	.release	= drm_release,
223	.flush		= amdxdna_flush,
224	.unlocked_ioctl	= drm_ioctl,
225	.compat_ioctl	= drm_compat_ioctl,
226	.poll		= drm_poll,
227	.read		= drm_read,
228	.llseek		= noop_llseek,
229	.mmap		= drm_gem_mmap,
230	.fop_flags	= FOP_UNSIGNED_OFFSET,
231};
232
233const struct drm_driver amdxdna_drm_drv = {
234	.driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL |
235		DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE,
236	.fops = &amdxdna_fops,
237	.name = "amdxdna_accel_driver",
238	.desc = "AMD XDNA DRM implementation",
239	.major = AMDXDNA_DRIVER_MAJOR,
240	.minor = AMDXDNA_DRIVER_MINOR,
241	.open = amdxdna_drm_open,
242	.postclose = amdxdna_drm_close,
243	.ioctls = amdxdna_drm_ioctls,
244	.num_ioctls = ARRAY_SIZE(amdxdna_drm_ioctls),
245
246	.gem_create_object = amdxdna_gem_create_object_cb,
247	.gem_prime_import = amdxdna_gem_prime_import,
248};
249
250static const struct amdxdna_dev_info *
251amdxdna_get_dev_info(struct pci_dev *pdev)
252{
253	int i;
254
255	for (i = 0; i < ARRAY_SIZE(amdxdna_ids); i++) {
256		if (pdev->device == amdxdna_ids[i].device &&
257		    pdev->revision == amdxdna_ids[i].revision)
258			return amdxdna_ids[i].dev_info;
259	}
260	return NULL;
261}
262
263static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
264{
265	struct device *dev = &pdev->dev;
266	struct amdxdna_dev *xdna;
267	int ret;
268
269	xdna = devm_drm_dev_alloc(dev, &amdxdna_drm_drv, typeof(*xdna), ddev);
270	if (IS_ERR(xdna))
271		return PTR_ERR(xdna);
272
273	xdna->dev_info = amdxdna_get_dev_info(pdev);
274	if (!xdna->dev_info)
275		return -ENODEV;
276
277	drmm_mutex_init(&xdna->ddev, &xdna->dev_lock);
278	init_rwsem(&xdna->notifier_lock);
279	INIT_LIST_HEAD(&xdna->client_list);
280	pci_set_drvdata(pdev, xdna);
281
282	if (IS_ENABLED(CONFIG_LOCKDEP)) {
283		fs_reclaim_acquire(GFP_KERNEL);
284		might_lock(&xdna->notifier_lock);
285		fs_reclaim_release(GFP_KERNEL);
286	}
287
288	xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM);
289	if (!xdna->notifier_wq)
290		return -ENOMEM;
291
292	mutex_lock(&xdna->dev_lock);
293	ret = xdna->dev_info->ops->init(xdna);
294	mutex_unlock(&xdna->dev_lock);
295	if (ret) {
296		XDNA_ERR(xdna, "Hardware init failed, ret %d", ret);
297		goto destroy_notifier_wq;
298	}
299
300	ret = amdxdna_sysfs_init(xdna);
301	if (ret) {
302		XDNA_ERR(xdna, "Create amdxdna attrs failed: %d", ret);
303		goto failed_dev_fini;
304	}
305
306	ret = drm_dev_register(&xdna->ddev, 0);
307	if (ret) {
308		XDNA_ERR(xdna, "DRM register failed, ret %d", ret);
309		goto failed_sysfs_fini;
310	}
311
312	return 0;
313
314failed_sysfs_fini:
315	amdxdna_sysfs_fini(xdna);
316failed_dev_fini:
317	mutex_lock(&xdna->dev_lock);
318	xdna->dev_info->ops->fini(xdna);
319	mutex_unlock(&xdna->dev_lock);
320destroy_notifier_wq:
321	destroy_workqueue(xdna->notifier_wq);
322	return ret;
323}
324
325static void amdxdna_remove(struct pci_dev *pdev)
326{
327	struct amdxdna_dev *xdna = pci_get_drvdata(pdev);
328	struct amdxdna_client *client;
329
330	destroy_workqueue(xdna->notifier_wq);
331
332	drm_dev_unplug(&xdna->ddev);
333	amdxdna_sysfs_fini(xdna);
334
335	mutex_lock(&xdna->dev_lock);
336	client = list_first_entry_or_null(&xdna->client_list,
337					  struct amdxdna_client, node);
338	while (client) {
339		list_del_init(&client->node);
340		amdxdna_hwctx_remove_all(client);
341
342		client = list_first_entry_or_null(&xdna->client_list,
343						  struct amdxdna_client, node);
344	}
345
346	xdna->dev_info->ops->fini(xdna);
347	mutex_unlock(&xdna->dev_lock);
348}
349
350static const struct dev_pm_ops amdxdna_pm_ops = {
351	SYSTEM_SLEEP_PM_OPS(amdxdna_pm_suspend, amdxdna_pm_resume)
352	RUNTIME_PM_OPS(amdxdna_pm_suspend, amdxdna_pm_resume, NULL)
353};
354
355static struct pci_driver amdxdna_pci_driver = {
356	.name = KBUILD_MODNAME,
357	.id_table = pci_ids,
358	.probe = amdxdna_probe,
359	.remove = amdxdna_remove,
360	.driver.pm = &amdxdna_pm_ops,
361};
362
363module_pci_driver(amdxdna_pci_driver);
364
365MODULE_LICENSE("GPL");
366MODULE_AUTHOR("XRT Team <runtimeca39d@amd.com>");
367MODULE_DESCRIPTION("amdxdna driver");
~/ Read-only file preview.