xref: /openbmc/linux/drivers/accel/ivpu/ivpu_drv.c (revision 5d7422cf)
135b13763SJacek Lawrynowicz // SPDX-License-Identifier: GPL-2.0-only
235b13763SJacek Lawrynowicz /*
335b13763SJacek Lawrynowicz  * Copyright (C) 2020-2023 Intel Corporation
435b13763SJacek Lawrynowicz  */
535b13763SJacek Lawrynowicz 
635b13763SJacek Lawrynowicz #include <linux/firmware.h>
735b13763SJacek Lawrynowicz #include <linux/module.h>
835b13763SJacek Lawrynowicz #include <linux/pci.h>
935b13763SJacek Lawrynowicz 
1035b13763SJacek Lawrynowicz #include <drm/drm_accel.h>
1135b13763SJacek Lawrynowicz #include <drm/drm_drv.h>
1235b13763SJacek Lawrynowicz #include <drm/drm_file.h>
1335b13763SJacek Lawrynowicz #include <drm/drm_gem.h>
1435b13763SJacek Lawrynowicz #include <drm/drm_ioctl.h>
15647371a6SJacek Lawrynowicz #include <drm/drm_prime.h>
1635b13763SJacek Lawrynowicz 
1735b13763SJacek Lawrynowicz #include "ivpu_drv.h"
18647371a6SJacek Lawrynowicz #include "ivpu_gem.h"
1935b13763SJacek Lawrynowicz #include "ivpu_hw.h"
20*5d7422cfSJacek Lawrynowicz #include "ivpu_ipc.h"
21263b2ba5SJacek Lawrynowicz #include "ivpu_mmu.h"
22263b2ba5SJacek Lawrynowicz #include "ivpu_mmu_context.h"
2335b13763SJacek Lawrynowicz 
2435b13763SJacek Lawrynowicz #ifndef DRIVER_VERSION_STR
2535b13763SJacek Lawrynowicz #define DRIVER_VERSION_STR __stringify(DRM_IVPU_DRIVER_MAJOR) "." \
2635b13763SJacek Lawrynowicz 			   __stringify(DRM_IVPU_DRIVER_MINOR) "."
2735b13763SJacek Lawrynowicz #endif
2835b13763SJacek Lawrynowicz 
2935b13763SJacek Lawrynowicz static const struct drm_driver driver;
3035b13763SJacek Lawrynowicz 
3135b13763SJacek Lawrynowicz int ivpu_dbg_mask;
3235b13763SJacek Lawrynowicz module_param_named(dbg_mask, ivpu_dbg_mask, int, 0644);
3335b13763SJacek Lawrynowicz MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros.");
3435b13763SJacek Lawrynowicz 
3535b13763SJacek Lawrynowicz u8 ivpu_pll_min_ratio;
3635b13763SJacek Lawrynowicz module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644);
3735b13763SJacek Lawrynowicz MODULE_PARM_DESC(pll_min_ratio, "Minimum PLL ratio used to set VPU frequency");
3835b13763SJacek Lawrynowicz 
3935b13763SJacek Lawrynowicz u8 ivpu_pll_max_ratio = U8_MAX;
4035b13763SJacek Lawrynowicz module_param_named(pll_max_ratio, ivpu_pll_max_ratio, byte, 0644);
4135b13763SJacek Lawrynowicz MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set VPU frequency");
4235b13763SJacek Lawrynowicz 
4335b13763SJacek Lawrynowicz struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
4435b13763SJacek Lawrynowicz {
45263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
46263b2ba5SJacek Lawrynowicz 
4735b13763SJacek Lawrynowicz 	kref_get(&file_priv->ref);
48263b2ba5SJacek Lawrynowicz 
49263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, KREF, "file_priv get: ctx %u refcount %u\n",
50263b2ba5SJacek Lawrynowicz 		 file_priv->ctx.id, kref_read(&file_priv->ref));
51263b2ba5SJacek Lawrynowicz 
5235b13763SJacek Lawrynowicz 	return file_priv;
5335b13763SJacek Lawrynowicz }
5435b13763SJacek Lawrynowicz 
55647371a6SJacek Lawrynowicz struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id)
56647371a6SJacek Lawrynowicz {
57647371a6SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv;
58647371a6SJacek Lawrynowicz 
59647371a6SJacek Lawrynowicz 	xa_lock_irq(&vdev->context_xa);
60647371a6SJacek Lawrynowicz 	file_priv = xa_load(&vdev->context_xa, id);
61647371a6SJacek Lawrynowicz 	/* file_priv may still be in context_xa during file_priv_release() */
62647371a6SJacek Lawrynowicz 	if (file_priv && !kref_get_unless_zero(&file_priv->ref))
63647371a6SJacek Lawrynowicz 		file_priv = NULL;
64647371a6SJacek Lawrynowicz 	xa_unlock_irq(&vdev->context_xa);
65647371a6SJacek Lawrynowicz 
66647371a6SJacek Lawrynowicz 	if (file_priv)
67647371a6SJacek Lawrynowicz 		ivpu_dbg(vdev, KREF, "file_priv get by id: ctx %u refcount %u\n",
68647371a6SJacek Lawrynowicz 			 file_priv->ctx.id, kref_read(&file_priv->ref));
69647371a6SJacek Lawrynowicz 
70647371a6SJacek Lawrynowicz 	return file_priv;
71647371a6SJacek Lawrynowicz }
72647371a6SJacek Lawrynowicz 
7335b13763SJacek Lawrynowicz static void file_priv_release(struct kref *ref)
7435b13763SJacek Lawrynowicz {
7535b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
76263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
7735b13763SJacek Lawrynowicz 
78263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id);
79263b2ba5SJacek Lawrynowicz 
80263b2ba5SJacek Lawrynowicz 	ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
81647371a6SJacek Lawrynowicz 	drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv);
8235b13763SJacek Lawrynowicz 	kfree(file_priv);
8335b13763SJacek Lawrynowicz }
8435b13763SJacek Lawrynowicz 
8535b13763SJacek Lawrynowicz void ivpu_file_priv_put(struct ivpu_file_priv **link)
8635b13763SJacek Lawrynowicz {
8735b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = *link;
88263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
8935b13763SJacek Lawrynowicz 
90647371a6SJacek Lawrynowicz 	drm_WARN_ON(&vdev->drm, !file_priv);
9135b13763SJacek Lawrynowicz 
92263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, KREF, "file_priv put: ctx %u refcount %u\n",
93263b2ba5SJacek Lawrynowicz 		 file_priv->ctx.id, kref_read(&file_priv->ref));
94263b2ba5SJacek Lawrynowicz 
9535b13763SJacek Lawrynowicz 	*link = NULL;
9635b13763SJacek Lawrynowicz 	kref_put(&file_priv->ref, file_priv_release);
9735b13763SJacek Lawrynowicz }
9835b13763SJacek Lawrynowicz 
9935b13763SJacek Lawrynowicz static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
10035b13763SJacek Lawrynowicz {
10135b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = file->driver_priv;
10235b13763SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
10335b13763SJacek Lawrynowicz 	struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
10435b13763SJacek Lawrynowicz 	struct drm_ivpu_param *args = data;
10535b13763SJacek Lawrynowicz 	int ret = 0;
10635b13763SJacek Lawrynowicz 
10735b13763SJacek Lawrynowicz 	switch (args->param) {
10835b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_DEVICE_ID:
10935b13763SJacek Lawrynowicz 		args->value = pdev->device;
11035b13763SJacek Lawrynowicz 		break;
11135b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_DEVICE_REVISION:
11235b13763SJacek Lawrynowicz 		args->value = pdev->revision;
11335b13763SJacek Lawrynowicz 		break;
11435b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_PLATFORM_TYPE:
11535b13763SJacek Lawrynowicz 		args->value = vdev->platform;
11635b13763SJacek Lawrynowicz 		break;
11735b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CORE_CLOCK_RATE:
11835b13763SJacek Lawrynowicz 		args->value = ivpu_hw_reg_pll_freq_get(vdev);
11935b13763SJacek Lawrynowicz 		break;
12035b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_NUM_CONTEXTS:
12135b13763SJacek Lawrynowicz 		args->value = ivpu_get_context_count(vdev);
12235b13763SJacek Lawrynowicz 		break;
12335b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
12435b13763SJacek Lawrynowicz 		args->value = vdev->hw->ranges.user_low.start;
12535b13763SJacek Lawrynowicz 		break;
12635b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
12735b13763SJacek Lawrynowicz 		args->value = file_priv->priority;
12835b13763SJacek Lawrynowicz 		break;
129263b2ba5SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_ID:
130263b2ba5SJacek Lawrynowicz 		args->value = file_priv->ctx.id;
131263b2ba5SJacek Lawrynowicz 		break;
13235b13763SJacek Lawrynowicz 	default:
13335b13763SJacek Lawrynowicz 		ret = -EINVAL;
13435b13763SJacek Lawrynowicz 		break;
13535b13763SJacek Lawrynowicz 	}
13635b13763SJacek Lawrynowicz 
13735b13763SJacek Lawrynowicz 	return ret;
13835b13763SJacek Lawrynowicz }
13935b13763SJacek Lawrynowicz 
14035b13763SJacek Lawrynowicz static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
14135b13763SJacek Lawrynowicz {
14235b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = file->driver_priv;
14335b13763SJacek Lawrynowicz 	struct drm_ivpu_param *args = data;
14435b13763SJacek Lawrynowicz 	int ret = 0;
14535b13763SJacek Lawrynowicz 
14635b13763SJacek Lawrynowicz 	switch (args->param) {
14735b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
14835b13763SJacek Lawrynowicz 		if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME)
14935b13763SJacek Lawrynowicz 			file_priv->priority = args->value;
15035b13763SJacek Lawrynowicz 		else
15135b13763SJacek Lawrynowicz 			ret = -EINVAL;
15235b13763SJacek Lawrynowicz 		break;
15335b13763SJacek Lawrynowicz 	default:
15435b13763SJacek Lawrynowicz 		ret = -EINVAL;
15535b13763SJacek Lawrynowicz 	}
15635b13763SJacek Lawrynowicz 
15735b13763SJacek Lawrynowicz 	return ret;
15835b13763SJacek Lawrynowicz }
15935b13763SJacek Lawrynowicz 
16035b13763SJacek Lawrynowicz static int ivpu_open(struct drm_device *dev, struct drm_file *file)
16135b13763SJacek Lawrynowicz {
16235b13763SJacek Lawrynowicz 	struct ivpu_device *vdev = to_ivpu_device(dev);
16335b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv;
164263b2ba5SJacek Lawrynowicz 	u32 ctx_id;
165263b2ba5SJacek Lawrynowicz 	void *old;
166263b2ba5SJacek Lawrynowicz 	int ret;
167263b2ba5SJacek Lawrynowicz 
168263b2ba5SJacek Lawrynowicz 	ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL);
169263b2ba5SJacek Lawrynowicz 	if (ret) {
170263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
171263b2ba5SJacek Lawrynowicz 		return ret;
172263b2ba5SJacek Lawrynowicz 	}
17335b13763SJacek Lawrynowicz 
17435b13763SJacek Lawrynowicz 	file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
175263b2ba5SJacek Lawrynowicz 	if (!file_priv) {
176263b2ba5SJacek Lawrynowicz 		ret = -ENOMEM;
177263b2ba5SJacek Lawrynowicz 		goto err_xa_erase;
178263b2ba5SJacek Lawrynowicz 	}
17935b13763SJacek Lawrynowicz 
18035b13763SJacek Lawrynowicz 	file_priv->vdev = vdev;
18135b13763SJacek Lawrynowicz 	file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
18235b13763SJacek Lawrynowicz 	kref_init(&file_priv->ref);
18335b13763SJacek Lawrynowicz 
184263b2ba5SJacek Lawrynowicz 	ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id);
185263b2ba5SJacek Lawrynowicz 	if (ret)
186263b2ba5SJacek Lawrynowicz 		goto err_free_file_priv;
187263b2ba5SJacek Lawrynowicz 
188263b2ba5SJacek Lawrynowicz 	old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL);
189263b2ba5SJacek Lawrynowicz 	if (xa_is_err(old)) {
190263b2ba5SJacek Lawrynowicz 		ret = xa_err(old);
191263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret);
192263b2ba5SJacek Lawrynowicz 		goto err_ctx_fini;
193263b2ba5SJacek Lawrynowicz 	}
194263b2ba5SJacek Lawrynowicz 
195263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n",
196263b2ba5SJacek Lawrynowicz 		 ctx_id, current->comm, task_pid_nr(current));
197263b2ba5SJacek Lawrynowicz 
19835b13763SJacek Lawrynowicz 	file->driver_priv = file_priv;
19935b13763SJacek Lawrynowicz 	return 0;
200263b2ba5SJacek Lawrynowicz 
201263b2ba5SJacek Lawrynowicz err_ctx_fini:
202263b2ba5SJacek Lawrynowicz 	ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
203263b2ba5SJacek Lawrynowicz err_free_file_priv:
204263b2ba5SJacek Lawrynowicz 	kfree(file_priv);
205263b2ba5SJacek Lawrynowicz err_xa_erase:
206263b2ba5SJacek Lawrynowicz 	xa_erase_irq(&vdev->context_xa, ctx_id);
207263b2ba5SJacek Lawrynowicz 	return ret;
20835b13763SJacek Lawrynowicz }
20935b13763SJacek Lawrynowicz 
21035b13763SJacek Lawrynowicz static void ivpu_postclose(struct drm_device *dev, struct drm_file *file)
21135b13763SJacek Lawrynowicz {
21235b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = file->driver_priv;
213263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = to_ivpu_device(dev);
214263b2ba5SJacek Lawrynowicz 
215263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, FILE, "file_priv close: ctx %u process %s pid %d\n",
216263b2ba5SJacek Lawrynowicz 		 file_priv->ctx.id, current->comm, task_pid_nr(current));
21735b13763SJacek Lawrynowicz 
21835b13763SJacek Lawrynowicz 	ivpu_file_priv_put(&file_priv);
21935b13763SJacek Lawrynowicz }
22035b13763SJacek Lawrynowicz 
22135b13763SJacek Lawrynowicz static const struct drm_ioctl_desc ivpu_drm_ioctls[] = {
22235b13763SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_GET_PARAM, ivpu_get_param_ioctl, 0),
22335b13763SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_SET_PARAM, ivpu_set_param_ioctl, 0),
224647371a6SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_BO_CREATE, ivpu_bo_create_ioctl, 0),
225647371a6SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_BO_INFO, ivpu_bo_info_ioctl, 0),
22635b13763SJacek Lawrynowicz };
22735b13763SJacek Lawrynowicz 
22835b13763SJacek Lawrynowicz int ivpu_shutdown(struct ivpu_device *vdev)
22935b13763SJacek Lawrynowicz {
23035b13763SJacek Lawrynowicz 	int ret;
23135b13763SJacek Lawrynowicz 
23235b13763SJacek Lawrynowicz 	ivpu_hw_irq_disable(vdev);
233*5d7422cfSJacek Lawrynowicz 	ivpu_ipc_disable(vdev);
234263b2ba5SJacek Lawrynowicz 	ivpu_mmu_disable(vdev);
23535b13763SJacek Lawrynowicz 
23635b13763SJacek Lawrynowicz 	ret = ivpu_hw_power_down(vdev);
23735b13763SJacek Lawrynowicz 	if (ret)
23835b13763SJacek Lawrynowicz 		ivpu_warn(vdev, "Failed to power down HW: %d\n", ret);
23935b13763SJacek Lawrynowicz 
24035b13763SJacek Lawrynowicz 	return ret;
24135b13763SJacek Lawrynowicz }
24235b13763SJacek Lawrynowicz 
24335b13763SJacek Lawrynowicz static const struct file_operations ivpu_fops = {
24435b13763SJacek Lawrynowicz 	.owner		= THIS_MODULE,
24535b13763SJacek Lawrynowicz 	.mmap           = drm_gem_mmap,
24635b13763SJacek Lawrynowicz 	DRM_ACCEL_FOPS,
24735b13763SJacek Lawrynowicz };
24835b13763SJacek Lawrynowicz 
24935b13763SJacek Lawrynowicz static const struct drm_driver driver = {
25035b13763SJacek Lawrynowicz 	.driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL,
25135b13763SJacek Lawrynowicz 
25235b13763SJacek Lawrynowicz 	.open = ivpu_open,
25335b13763SJacek Lawrynowicz 	.postclose = ivpu_postclose,
254647371a6SJacek Lawrynowicz 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
255647371a6SJacek Lawrynowicz 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
256647371a6SJacek Lawrynowicz 	.gem_prime_import = ivpu_gem_prime_import,
257647371a6SJacek Lawrynowicz 	.gem_prime_mmap = drm_gem_prime_mmap,
25835b13763SJacek Lawrynowicz 
25935b13763SJacek Lawrynowicz 	.ioctls = ivpu_drm_ioctls,
26035b13763SJacek Lawrynowicz 	.num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls),
26135b13763SJacek Lawrynowicz 	.fops = &ivpu_fops,
26235b13763SJacek Lawrynowicz 
26335b13763SJacek Lawrynowicz 	.name = DRIVER_NAME,
26435b13763SJacek Lawrynowicz 	.desc = DRIVER_DESC,
26535b13763SJacek Lawrynowicz 	.date = DRIVER_DATE,
26635b13763SJacek Lawrynowicz 	.major = DRM_IVPU_DRIVER_MAJOR,
26735b13763SJacek Lawrynowicz 	.minor = DRM_IVPU_DRIVER_MINOR,
26835b13763SJacek Lawrynowicz };
26935b13763SJacek Lawrynowicz 
27035b13763SJacek Lawrynowicz static int ivpu_irq_init(struct ivpu_device *vdev)
27135b13763SJacek Lawrynowicz {
27235b13763SJacek Lawrynowicz 	struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
27335b13763SJacek Lawrynowicz 	int ret;
27435b13763SJacek Lawrynowicz 
27535b13763SJacek Lawrynowicz 	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX);
27635b13763SJacek Lawrynowicz 	if (ret < 0) {
27735b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to allocate a MSI IRQ: %d\n", ret);
27835b13763SJacek Lawrynowicz 		return ret;
27935b13763SJacek Lawrynowicz 	}
28035b13763SJacek Lawrynowicz 
28135b13763SJacek Lawrynowicz 	vdev->irq = pci_irq_vector(pdev, 0);
28235b13763SJacek Lawrynowicz 
28335b13763SJacek Lawrynowicz 	ret = devm_request_irq(vdev->drm.dev, vdev->irq, vdev->hw->ops->irq_handler,
28435b13763SJacek Lawrynowicz 			       IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
28535b13763SJacek Lawrynowicz 	if (ret)
28635b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to request an IRQ %d\n", ret);
28735b13763SJacek Lawrynowicz 
28835b13763SJacek Lawrynowicz 	return ret;
28935b13763SJacek Lawrynowicz }
29035b13763SJacek Lawrynowicz 
29135b13763SJacek Lawrynowicz static int ivpu_pci_init(struct ivpu_device *vdev)
29235b13763SJacek Lawrynowicz {
29335b13763SJacek Lawrynowicz 	struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
29435b13763SJacek Lawrynowicz 	struct resource *bar0 = &pdev->resource[0];
29535b13763SJacek Lawrynowicz 	struct resource *bar4 = &pdev->resource[4];
29635b13763SJacek Lawrynowicz 	int ret;
29735b13763SJacek Lawrynowicz 
29835b13763SJacek Lawrynowicz 	ivpu_dbg(vdev, MISC, "Mapping BAR0 (RegV) %pR\n", bar0);
29935b13763SJacek Lawrynowicz 	vdev->regv = devm_ioremap_resource(vdev->drm.dev, bar0);
30035b13763SJacek Lawrynowicz 	if (IS_ERR(vdev->regv)) {
30135b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to map bar 0: %pe\n", vdev->regv);
30235b13763SJacek Lawrynowicz 		return PTR_ERR(vdev->regv);
30335b13763SJacek Lawrynowicz 	}
30435b13763SJacek Lawrynowicz 
30535b13763SJacek Lawrynowicz 	ivpu_dbg(vdev, MISC, "Mapping BAR4 (RegB) %pR\n", bar4);
30635b13763SJacek Lawrynowicz 	vdev->regb = devm_ioremap_resource(vdev->drm.dev, bar4);
30735b13763SJacek Lawrynowicz 	if (IS_ERR(vdev->regb)) {
30835b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to map bar 4: %pe\n", vdev->regb);
30935b13763SJacek Lawrynowicz 		return PTR_ERR(vdev->regb);
31035b13763SJacek Lawrynowicz 	}
31135b13763SJacek Lawrynowicz 
31235b13763SJacek Lawrynowicz 	ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(38));
31335b13763SJacek Lawrynowicz 	if (ret) {
31435b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to set DMA mask: %d\n", ret);
31535b13763SJacek Lawrynowicz 		return ret;
31635b13763SJacek Lawrynowicz 	}
31735b13763SJacek Lawrynowicz 
31835b13763SJacek Lawrynowicz 	/* Clear any pending errors */
31935b13763SJacek Lawrynowicz 	pcie_capability_clear_word(pdev, PCI_EXP_DEVSTA, 0x3f);
32035b13763SJacek Lawrynowicz 
32135b13763SJacek Lawrynowicz 	ret = pcim_enable_device(pdev);
32235b13763SJacek Lawrynowicz 	if (ret) {
32335b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to enable PCI device: %d\n", ret);
32435b13763SJacek Lawrynowicz 		return ret;
32535b13763SJacek Lawrynowicz 	}
32635b13763SJacek Lawrynowicz 
32735b13763SJacek Lawrynowicz 	pci_set_master(pdev);
32835b13763SJacek Lawrynowicz 
32935b13763SJacek Lawrynowicz 	return 0;
33035b13763SJacek Lawrynowicz }
33135b13763SJacek Lawrynowicz 
33235b13763SJacek Lawrynowicz static int ivpu_dev_init(struct ivpu_device *vdev)
33335b13763SJacek Lawrynowicz {
33435b13763SJacek Lawrynowicz 	int ret;
33535b13763SJacek Lawrynowicz 
33635b13763SJacek Lawrynowicz 	vdev->hw = drmm_kzalloc(&vdev->drm, sizeof(*vdev->hw), GFP_KERNEL);
33735b13763SJacek Lawrynowicz 	if (!vdev->hw)
33835b13763SJacek Lawrynowicz 		return -ENOMEM;
33935b13763SJacek Lawrynowicz 
340263b2ba5SJacek Lawrynowicz 	vdev->mmu = drmm_kzalloc(&vdev->drm, sizeof(*vdev->mmu), GFP_KERNEL);
341263b2ba5SJacek Lawrynowicz 	if (!vdev->mmu)
342263b2ba5SJacek Lawrynowicz 		return -ENOMEM;
343263b2ba5SJacek Lawrynowicz 
344*5d7422cfSJacek Lawrynowicz 	vdev->ipc = drmm_kzalloc(&vdev->drm, sizeof(*vdev->ipc), GFP_KERNEL);
345*5d7422cfSJacek Lawrynowicz 	if (!vdev->ipc)
346*5d7422cfSJacek Lawrynowicz 		return -ENOMEM;
347*5d7422cfSJacek Lawrynowicz 
34835b13763SJacek Lawrynowicz 	vdev->hw->ops = &ivpu_hw_mtl_ops;
34935b13763SJacek Lawrynowicz 	vdev->platform = IVPU_PLATFORM_INVALID;
35035b13763SJacek Lawrynowicz 	vdev->context_xa_limit.min = IVPU_GLOBAL_CONTEXT_MMU_SSID + 1;
35135b13763SJacek Lawrynowicz 	vdev->context_xa_limit.max = IVPU_CONTEXT_LIMIT;
35235b13763SJacek Lawrynowicz 	xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC);
35335b13763SJacek Lawrynowicz 
35435b13763SJacek Lawrynowicz 	ret = ivpu_pci_init(vdev);
35535b13763SJacek Lawrynowicz 	if (ret) {
35635b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize PCI device: %d\n", ret);
35735b13763SJacek Lawrynowicz 		goto err_xa_destroy;
35835b13763SJacek Lawrynowicz 	}
35935b13763SJacek Lawrynowicz 
36035b13763SJacek Lawrynowicz 	ret = ivpu_irq_init(vdev);
36135b13763SJacek Lawrynowicz 	if (ret) {
36235b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize IRQs: %d\n", ret);
36335b13763SJacek Lawrynowicz 		goto err_xa_destroy;
36435b13763SJacek Lawrynowicz 	}
36535b13763SJacek Lawrynowicz 
36635b13763SJacek Lawrynowicz 	/* Init basic HW info based on buttress registers which are accessible before power up */
36735b13763SJacek Lawrynowicz 	ret = ivpu_hw_info_init(vdev);
36835b13763SJacek Lawrynowicz 	if (ret) {
36935b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize HW info: %d\n", ret);
37035b13763SJacek Lawrynowicz 		goto err_xa_destroy;
37135b13763SJacek Lawrynowicz 	}
37235b13763SJacek Lawrynowicz 
37335b13763SJacek Lawrynowicz 	/* Power up early so the rest of init code can access VPU registers */
37435b13763SJacek Lawrynowicz 	ret = ivpu_hw_power_up(vdev);
37535b13763SJacek Lawrynowicz 	if (ret) {
37635b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to power up HW: %d\n", ret);
37735b13763SJacek Lawrynowicz 		goto err_xa_destroy;
37835b13763SJacek Lawrynowicz 	}
37935b13763SJacek Lawrynowicz 
380263b2ba5SJacek Lawrynowicz 	ret = ivpu_mmu_global_context_init(vdev);
381263b2ba5SJacek Lawrynowicz 	if (ret) {
382263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize global MMU context: %d\n", ret);
383263b2ba5SJacek Lawrynowicz 		goto err_power_down;
384263b2ba5SJacek Lawrynowicz 	}
385263b2ba5SJacek Lawrynowicz 
386263b2ba5SJacek Lawrynowicz 	ret = ivpu_mmu_init(vdev);
387263b2ba5SJacek Lawrynowicz 	if (ret) {
388263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize MMU device: %d\n", ret);
389263b2ba5SJacek Lawrynowicz 		goto err_mmu_gctx_fini;
390263b2ba5SJacek Lawrynowicz 	}
391263b2ba5SJacek Lawrynowicz 
392*5d7422cfSJacek Lawrynowicz 	ret = ivpu_ipc_init(vdev);
393*5d7422cfSJacek Lawrynowicz 	if (ret) {
394*5d7422cfSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize IPC: %d\n", ret);
395*5d7422cfSJacek Lawrynowicz 		goto err_mmu_gctx_fini;
396*5d7422cfSJacek Lawrynowicz 	}
397*5d7422cfSJacek Lawrynowicz 
39835b13763SJacek Lawrynowicz 	return 0;
39935b13763SJacek Lawrynowicz 
400263b2ba5SJacek Lawrynowicz err_mmu_gctx_fini:
401263b2ba5SJacek Lawrynowicz 	ivpu_mmu_global_context_fini(vdev);
402263b2ba5SJacek Lawrynowicz err_power_down:
403263b2ba5SJacek Lawrynowicz 	ivpu_hw_power_down(vdev);
40435b13763SJacek Lawrynowicz err_xa_destroy:
40535b13763SJacek Lawrynowicz 	xa_destroy(&vdev->context_xa);
40635b13763SJacek Lawrynowicz 	return ret;
40735b13763SJacek Lawrynowicz }
40835b13763SJacek Lawrynowicz 
40935b13763SJacek Lawrynowicz static void ivpu_dev_fini(struct ivpu_device *vdev)
41035b13763SJacek Lawrynowicz {
41135b13763SJacek Lawrynowicz 	ivpu_shutdown(vdev);
412*5d7422cfSJacek Lawrynowicz 	ivpu_ipc_fini(vdev);
413263b2ba5SJacek Lawrynowicz 	ivpu_mmu_global_context_fini(vdev);
41435b13763SJacek Lawrynowicz 
41535b13763SJacek Lawrynowicz 	drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->context_xa));
41635b13763SJacek Lawrynowicz 	xa_destroy(&vdev->context_xa);
41735b13763SJacek Lawrynowicz }
41835b13763SJacek Lawrynowicz 
41935b13763SJacek Lawrynowicz static struct pci_device_id ivpu_pci_ids[] = {
42035b13763SJacek Lawrynowicz 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
42135b13763SJacek Lawrynowicz 	{ }
42235b13763SJacek Lawrynowicz };
42335b13763SJacek Lawrynowicz MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
42435b13763SJacek Lawrynowicz 
42535b13763SJacek Lawrynowicz static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
42635b13763SJacek Lawrynowicz {
42735b13763SJacek Lawrynowicz 	struct ivpu_device *vdev;
42835b13763SJacek Lawrynowicz 	int ret;
42935b13763SJacek Lawrynowicz 
43035b13763SJacek Lawrynowicz 	vdev = devm_drm_dev_alloc(&pdev->dev, &driver, struct ivpu_device, drm);
43135b13763SJacek Lawrynowicz 	if (IS_ERR(vdev))
43235b13763SJacek Lawrynowicz 		return PTR_ERR(vdev);
43335b13763SJacek Lawrynowicz 
43435b13763SJacek Lawrynowicz 	pci_set_drvdata(pdev, vdev);
43535b13763SJacek Lawrynowicz 
43635b13763SJacek Lawrynowicz 	ret = ivpu_dev_init(vdev);
43735b13763SJacek Lawrynowicz 	if (ret) {
43835b13763SJacek Lawrynowicz 		dev_err(&pdev->dev, "Failed to initialize VPU device: %d\n", ret);
43935b13763SJacek Lawrynowicz 		return ret;
44035b13763SJacek Lawrynowicz 	}
44135b13763SJacek Lawrynowicz 
44235b13763SJacek Lawrynowicz 	ret = drm_dev_register(&vdev->drm, 0);
44335b13763SJacek Lawrynowicz 	if (ret) {
44435b13763SJacek Lawrynowicz 		dev_err(&pdev->dev, "Failed to register DRM device: %d\n", ret);
44535b13763SJacek Lawrynowicz 		ivpu_dev_fini(vdev);
44635b13763SJacek Lawrynowicz 	}
44735b13763SJacek Lawrynowicz 
44835b13763SJacek Lawrynowicz 	return ret;
44935b13763SJacek Lawrynowicz }
45035b13763SJacek Lawrynowicz 
45135b13763SJacek Lawrynowicz static void ivpu_remove(struct pci_dev *pdev)
45235b13763SJacek Lawrynowicz {
45335b13763SJacek Lawrynowicz 	struct ivpu_device *vdev = pci_get_drvdata(pdev);
45435b13763SJacek Lawrynowicz 
45535b13763SJacek Lawrynowicz 	drm_dev_unregister(&vdev->drm);
45635b13763SJacek Lawrynowicz 	ivpu_dev_fini(vdev);
45735b13763SJacek Lawrynowicz }
45835b13763SJacek Lawrynowicz 
45935b13763SJacek Lawrynowicz static struct pci_driver ivpu_pci_driver = {
46035b13763SJacek Lawrynowicz 	.name = KBUILD_MODNAME,
46135b13763SJacek Lawrynowicz 	.id_table = ivpu_pci_ids,
46235b13763SJacek Lawrynowicz 	.probe = ivpu_probe,
46335b13763SJacek Lawrynowicz 	.remove = ivpu_remove,
46435b13763SJacek Lawrynowicz };
46535b13763SJacek Lawrynowicz 
46635b13763SJacek Lawrynowicz module_pci_driver(ivpu_pci_driver);
46735b13763SJacek Lawrynowicz 
46835b13763SJacek Lawrynowicz MODULE_AUTHOR("Intel Corporation");
46935b13763SJacek Lawrynowicz MODULE_DESCRIPTION(DRIVER_DESC);
47035b13763SJacek Lawrynowicz MODULE_LICENSE("GPL and additional rights");
47135b13763SJacek Lawrynowicz MODULE_VERSION(DRIVER_VERSION_STR);
472