xref: /openbmc/linux/drivers/accel/ivpu/ivpu_drv.c (revision 3ff6edbc)
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_file.h>
1235b13763SJacek Lawrynowicz #include <drm/drm_gem.h>
1335b13763SJacek Lawrynowicz #include <drm/drm_ioctl.h>
14647371a6SJacek Lawrynowicz #include <drm/drm_prime.h>
1535b13763SJacek Lawrynowicz 
1602d5b0aaSJacek Lawrynowicz #include "vpu_boot_api.h"
1735b13763SJacek Lawrynowicz #include "ivpu_drv.h"
1802d5b0aaSJacek Lawrynowicz #include "ivpu_fw.h"
19647371a6SJacek Lawrynowicz #include "ivpu_gem.h"
2035b13763SJacek Lawrynowicz #include "ivpu_hw.h"
215d7422cfSJacek Lawrynowicz #include "ivpu_ipc.h"
22cd727221SJacek Lawrynowicz #include "ivpu_job.h"
2302d5b0aaSJacek Lawrynowicz #include "ivpu_jsm_msg.h"
24263b2ba5SJacek Lawrynowicz #include "ivpu_mmu.h"
25263b2ba5SJacek Lawrynowicz #include "ivpu_mmu_context.h"
26852be13fSJacek Lawrynowicz #include "ivpu_pm.h"
2735b13763SJacek Lawrynowicz 
2835b13763SJacek Lawrynowicz #ifndef DRIVER_VERSION_STR
2935b13763SJacek Lawrynowicz #define DRIVER_VERSION_STR __stringify(DRM_IVPU_DRIVER_MAJOR) "." \
3035b13763SJacek Lawrynowicz 			   __stringify(DRM_IVPU_DRIVER_MINOR) "."
3135b13763SJacek Lawrynowicz #endif
3235b13763SJacek Lawrynowicz 
3335b13763SJacek Lawrynowicz static const struct drm_driver driver;
3435b13763SJacek Lawrynowicz 
35cd727221SJacek Lawrynowicz static struct lock_class_key submitted_jobs_xa_lock_class_key;
36cd727221SJacek Lawrynowicz 
3735b13763SJacek Lawrynowicz int ivpu_dbg_mask;
3835b13763SJacek Lawrynowicz module_param_named(dbg_mask, ivpu_dbg_mask, int, 0644);
3935b13763SJacek Lawrynowicz MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros.");
4035b13763SJacek Lawrynowicz 
4102d5b0aaSJacek Lawrynowicz int ivpu_test_mode;
4202d5b0aaSJacek Lawrynowicz module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644);
4302d5b0aaSJacek Lawrynowicz MODULE_PARM_DESC(test_mode, "Test mode: 0 - normal operation, 1 - fw unit test, 2 - null hw");
4402d5b0aaSJacek Lawrynowicz 
4535b13763SJacek Lawrynowicz u8 ivpu_pll_min_ratio;
4635b13763SJacek Lawrynowicz module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644);
4735b13763SJacek Lawrynowicz MODULE_PARM_DESC(pll_min_ratio, "Minimum PLL ratio used to set VPU frequency");
4835b13763SJacek Lawrynowicz 
4935b13763SJacek Lawrynowicz u8 ivpu_pll_max_ratio = U8_MAX;
5035b13763SJacek Lawrynowicz module_param_named(pll_max_ratio, ivpu_pll_max_ratio, byte, 0644);
5135b13763SJacek Lawrynowicz MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set VPU frequency");
5235b13763SJacek Lawrynowicz 
5335b13763SJacek Lawrynowicz struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
5435b13763SJacek Lawrynowicz {
55263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
56263b2ba5SJacek Lawrynowicz 
5735b13763SJacek Lawrynowicz 	kref_get(&file_priv->ref);
58263b2ba5SJacek Lawrynowicz 
59263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, KREF, "file_priv get: ctx %u refcount %u\n",
60263b2ba5SJacek Lawrynowicz 		 file_priv->ctx.id, kref_read(&file_priv->ref));
61263b2ba5SJacek Lawrynowicz 
6235b13763SJacek Lawrynowicz 	return file_priv;
6335b13763SJacek Lawrynowicz }
6435b13763SJacek Lawrynowicz 
65647371a6SJacek Lawrynowicz struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id)
66647371a6SJacek Lawrynowicz {
67647371a6SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv;
68647371a6SJacek Lawrynowicz 
69647371a6SJacek Lawrynowicz 	xa_lock_irq(&vdev->context_xa);
70647371a6SJacek Lawrynowicz 	file_priv = xa_load(&vdev->context_xa, id);
71647371a6SJacek Lawrynowicz 	/* file_priv may still be in context_xa during file_priv_release() */
72647371a6SJacek Lawrynowicz 	if (file_priv && !kref_get_unless_zero(&file_priv->ref))
73647371a6SJacek Lawrynowicz 		file_priv = NULL;
74647371a6SJacek Lawrynowicz 	xa_unlock_irq(&vdev->context_xa);
75647371a6SJacek Lawrynowicz 
76647371a6SJacek Lawrynowicz 	if (file_priv)
77647371a6SJacek Lawrynowicz 		ivpu_dbg(vdev, KREF, "file_priv get by id: ctx %u refcount %u\n",
78647371a6SJacek Lawrynowicz 			 file_priv->ctx.id, kref_read(&file_priv->ref));
79647371a6SJacek Lawrynowicz 
80647371a6SJacek Lawrynowicz 	return file_priv;
81647371a6SJacek Lawrynowicz }
82647371a6SJacek Lawrynowicz 
8335b13763SJacek Lawrynowicz static void file_priv_release(struct kref *ref)
8435b13763SJacek Lawrynowicz {
8535b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
86263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
8735b13763SJacek Lawrynowicz 
88263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id);
89263b2ba5SJacek Lawrynowicz 
90cd727221SJacek Lawrynowicz 	ivpu_cmdq_release_all(file_priv);
91cd727221SJacek Lawrynowicz 	ivpu_bo_remove_all_bos_from_context(&file_priv->ctx);
92dffaa98cSAndrzej Kacprowski 	ivpu_jsm_context_release(vdev, file_priv->ctx.id);
93263b2ba5SJacek Lawrynowicz 	ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
94647371a6SJacek Lawrynowicz 	drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv);
95cd727221SJacek Lawrynowicz 	mutex_destroy(&file_priv->lock);
9635b13763SJacek Lawrynowicz 	kfree(file_priv);
9735b13763SJacek Lawrynowicz }
9835b13763SJacek Lawrynowicz 
9935b13763SJacek Lawrynowicz void ivpu_file_priv_put(struct ivpu_file_priv **link)
10035b13763SJacek Lawrynowicz {
10135b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = *link;
102263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
10335b13763SJacek Lawrynowicz 
104647371a6SJacek Lawrynowicz 	drm_WARN_ON(&vdev->drm, !file_priv);
10535b13763SJacek Lawrynowicz 
106263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, KREF, "file_priv put: ctx %u refcount %u\n",
107263b2ba5SJacek Lawrynowicz 		 file_priv->ctx.id, kref_read(&file_priv->ref));
108263b2ba5SJacek Lawrynowicz 
10935b13763SJacek Lawrynowicz 	*link = NULL;
11035b13763SJacek Lawrynowicz 	kref_put(&file_priv->ref, file_priv_release);
11135b13763SJacek Lawrynowicz }
11235b13763SJacek Lawrynowicz 
11335b13763SJacek Lawrynowicz static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
11435b13763SJacek Lawrynowicz {
11535b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = file->driver_priv;
11635b13763SJacek Lawrynowicz 	struct ivpu_device *vdev = file_priv->vdev;
11735b13763SJacek Lawrynowicz 	struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
11835b13763SJacek Lawrynowicz 	struct drm_ivpu_param *args = data;
11935b13763SJacek Lawrynowicz 	int ret = 0;
1204522ad76SStanislaw Gruszka 	int idx;
1214522ad76SStanislaw Gruszka 
1224522ad76SStanislaw Gruszka 	if (!drm_dev_enter(dev, &idx))
1234522ad76SStanislaw Gruszka 		return -ENODEV;
12435b13763SJacek Lawrynowicz 
12535b13763SJacek Lawrynowicz 	switch (args->param) {
12635b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_DEVICE_ID:
12735b13763SJacek Lawrynowicz 		args->value = pdev->device;
12835b13763SJacek Lawrynowicz 		break;
12935b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_DEVICE_REVISION:
13035b13763SJacek Lawrynowicz 		args->value = pdev->revision;
13135b13763SJacek Lawrynowicz 		break;
13235b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_PLATFORM_TYPE:
13335b13763SJacek Lawrynowicz 		args->value = vdev->platform;
13435b13763SJacek Lawrynowicz 		break;
13535b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CORE_CLOCK_RATE:
13635b13763SJacek Lawrynowicz 		args->value = ivpu_hw_reg_pll_freq_get(vdev);
13735b13763SJacek Lawrynowicz 		break;
13835b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_NUM_CONTEXTS:
13935b13763SJacek Lawrynowicz 		args->value = ivpu_get_context_count(vdev);
14035b13763SJacek Lawrynowicz 		break;
14135b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
14235b13763SJacek Lawrynowicz 		args->value = vdev->hw->ranges.user_low.start;
14335b13763SJacek Lawrynowicz 		break;
14435b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
14535b13763SJacek Lawrynowicz 		args->value = file_priv->priority;
14635b13763SJacek Lawrynowicz 		break;
147263b2ba5SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_ID:
148263b2ba5SJacek Lawrynowicz 		args->value = file_priv->ctx.id;
149263b2ba5SJacek Lawrynowicz 		break;
15002d5b0aaSJacek Lawrynowicz 	case DRM_IVPU_PARAM_FW_API_VERSION:
15102d5b0aaSJacek Lawrynowicz 		if (args->index < VPU_FW_API_VER_NUM) {
15202d5b0aaSJacek Lawrynowicz 			struct vpu_firmware_header *fw_hdr;
15302d5b0aaSJacek Lawrynowicz 
15402d5b0aaSJacek Lawrynowicz 			fw_hdr = (struct vpu_firmware_header *)vdev->fw->file->data;
15502d5b0aaSJacek Lawrynowicz 			args->value = fw_hdr->api_version[args->index];
15602d5b0aaSJacek Lawrynowicz 		} else {
15702d5b0aaSJacek Lawrynowicz 			ret = -EINVAL;
15802d5b0aaSJacek Lawrynowicz 		}
15902d5b0aaSJacek Lawrynowicz 		break;
16002d5b0aaSJacek Lawrynowicz 	case DRM_IVPU_PARAM_ENGINE_HEARTBEAT:
16102d5b0aaSJacek Lawrynowicz 		ret = ivpu_jsm_get_heartbeat(vdev, args->index, &args->value);
16202d5b0aaSJacek Lawrynowicz 		break;
16302d5b0aaSJacek Lawrynowicz 	case DRM_IVPU_PARAM_UNIQUE_INFERENCE_ID:
16402d5b0aaSJacek Lawrynowicz 		args->value = (u64)atomic64_inc_return(&vdev->unique_id_counter);
16502d5b0aaSJacek Lawrynowicz 		break;
16602d5b0aaSJacek Lawrynowicz 	case DRM_IVPU_PARAM_TILE_CONFIG:
16702d5b0aaSJacek Lawrynowicz 		args->value = vdev->hw->tile_fuse;
16802d5b0aaSJacek Lawrynowicz 		break;
16902d5b0aaSJacek Lawrynowicz 	case DRM_IVPU_PARAM_SKU:
17002d5b0aaSJacek Lawrynowicz 		args->value = vdev->hw->sku;
17102d5b0aaSJacek Lawrynowicz 		break;
17235b13763SJacek Lawrynowicz 	default:
17335b13763SJacek Lawrynowicz 		ret = -EINVAL;
17435b13763SJacek Lawrynowicz 		break;
17535b13763SJacek Lawrynowicz 	}
17635b13763SJacek Lawrynowicz 
1774522ad76SStanislaw Gruszka 	drm_dev_exit(idx);
17835b13763SJacek Lawrynowicz 	return ret;
17935b13763SJacek Lawrynowicz }
18035b13763SJacek Lawrynowicz 
18135b13763SJacek Lawrynowicz static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
18235b13763SJacek Lawrynowicz {
18335b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = file->driver_priv;
18435b13763SJacek Lawrynowicz 	struct drm_ivpu_param *args = data;
18535b13763SJacek Lawrynowicz 	int ret = 0;
18635b13763SJacek Lawrynowicz 
18735b13763SJacek Lawrynowicz 	switch (args->param) {
18835b13763SJacek Lawrynowicz 	case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
18935b13763SJacek Lawrynowicz 		if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME)
19035b13763SJacek Lawrynowicz 			file_priv->priority = args->value;
19135b13763SJacek Lawrynowicz 		else
19235b13763SJacek Lawrynowicz 			ret = -EINVAL;
19335b13763SJacek Lawrynowicz 		break;
19435b13763SJacek Lawrynowicz 	default:
19535b13763SJacek Lawrynowicz 		ret = -EINVAL;
19635b13763SJacek Lawrynowicz 	}
19735b13763SJacek Lawrynowicz 
19835b13763SJacek Lawrynowicz 	return ret;
19935b13763SJacek Lawrynowicz }
20035b13763SJacek Lawrynowicz 
20135b13763SJacek Lawrynowicz static int ivpu_open(struct drm_device *dev, struct drm_file *file)
20235b13763SJacek Lawrynowicz {
20335b13763SJacek Lawrynowicz 	struct ivpu_device *vdev = to_ivpu_device(dev);
20435b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv;
205263b2ba5SJacek Lawrynowicz 	u32 ctx_id;
206263b2ba5SJacek Lawrynowicz 	void *old;
207263b2ba5SJacek Lawrynowicz 	int ret;
208263b2ba5SJacek Lawrynowicz 
209263b2ba5SJacek Lawrynowicz 	ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL);
210263b2ba5SJacek Lawrynowicz 	if (ret) {
211263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
212263b2ba5SJacek Lawrynowicz 		return ret;
213263b2ba5SJacek Lawrynowicz 	}
21435b13763SJacek Lawrynowicz 
21535b13763SJacek Lawrynowicz 	file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
216263b2ba5SJacek Lawrynowicz 	if (!file_priv) {
217263b2ba5SJacek Lawrynowicz 		ret = -ENOMEM;
218263b2ba5SJacek Lawrynowicz 		goto err_xa_erase;
219263b2ba5SJacek Lawrynowicz 	}
22035b13763SJacek Lawrynowicz 
22135b13763SJacek Lawrynowicz 	file_priv->vdev = vdev;
22235b13763SJacek Lawrynowicz 	file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
22335b13763SJacek Lawrynowicz 	kref_init(&file_priv->ref);
224cd727221SJacek Lawrynowicz 	mutex_init(&file_priv->lock);
22535b13763SJacek Lawrynowicz 
226263b2ba5SJacek Lawrynowicz 	ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id);
227263b2ba5SJacek Lawrynowicz 	if (ret)
228cd727221SJacek Lawrynowicz 		goto err_mutex_destroy;
229263b2ba5SJacek Lawrynowicz 
230263b2ba5SJacek Lawrynowicz 	old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL);
231263b2ba5SJacek Lawrynowicz 	if (xa_is_err(old)) {
232263b2ba5SJacek Lawrynowicz 		ret = xa_err(old);
233263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret);
234263b2ba5SJacek Lawrynowicz 		goto err_ctx_fini;
235263b2ba5SJacek Lawrynowicz 	}
236263b2ba5SJacek Lawrynowicz 
237263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n",
238263b2ba5SJacek Lawrynowicz 		 ctx_id, current->comm, task_pid_nr(current));
239263b2ba5SJacek Lawrynowicz 
24035b13763SJacek Lawrynowicz 	file->driver_priv = file_priv;
24135b13763SJacek Lawrynowicz 	return 0;
242263b2ba5SJacek Lawrynowicz 
243263b2ba5SJacek Lawrynowicz err_ctx_fini:
244263b2ba5SJacek Lawrynowicz 	ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
245cd727221SJacek Lawrynowicz err_mutex_destroy:
246cd727221SJacek Lawrynowicz 	mutex_destroy(&file_priv->lock);
247263b2ba5SJacek Lawrynowicz 	kfree(file_priv);
248263b2ba5SJacek Lawrynowicz err_xa_erase:
249263b2ba5SJacek Lawrynowicz 	xa_erase_irq(&vdev->context_xa, ctx_id);
250263b2ba5SJacek Lawrynowicz 	return ret;
25135b13763SJacek Lawrynowicz }
25235b13763SJacek Lawrynowicz 
25335b13763SJacek Lawrynowicz static void ivpu_postclose(struct drm_device *dev, struct drm_file *file)
25435b13763SJacek Lawrynowicz {
25535b13763SJacek Lawrynowicz 	struct ivpu_file_priv *file_priv = file->driver_priv;
256263b2ba5SJacek Lawrynowicz 	struct ivpu_device *vdev = to_ivpu_device(dev);
257263b2ba5SJacek Lawrynowicz 
258263b2ba5SJacek Lawrynowicz 	ivpu_dbg(vdev, FILE, "file_priv close: ctx %u process %s pid %d\n",
259263b2ba5SJacek Lawrynowicz 		 file_priv->ctx.id, current->comm, task_pid_nr(current));
26035b13763SJacek Lawrynowicz 
26135b13763SJacek Lawrynowicz 	ivpu_file_priv_put(&file_priv);
26235b13763SJacek Lawrynowicz }
26335b13763SJacek Lawrynowicz 
26435b13763SJacek Lawrynowicz static const struct drm_ioctl_desc ivpu_drm_ioctls[] = {
26535b13763SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_GET_PARAM, ivpu_get_param_ioctl, 0),
26635b13763SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_SET_PARAM, ivpu_set_param_ioctl, 0),
267647371a6SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_BO_CREATE, ivpu_bo_create_ioctl, 0),
268647371a6SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_BO_INFO, ivpu_bo_info_ioctl, 0),
269cd727221SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_SUBMIT, ivpu_submit_ioctl, 0),
270cd727221SJacek Lawrynowicz 	DRM_IOCTL_DEF_DRV(IVPU_BO_WAIT, ivpu_bo_wait_ioctl, 0),
27135b13763SJacek Lawrynowicz };
27235b13763SJacek Lawrynowicz 
27302d5b0aaSJacek Lawrynowicz static int ivpu_wait_for_ready(struct ivpu_device *vdev)
27402d5b0aaSJacek Lawrynowicz {
27502d5b0aaSJacek Lawrynowicz 	struct ivpu_ipc_consumer cons;
27602d5b0aaSJacek Lawrynowicz 	struct ivpu_ipc_hdr ipc_hdr;
27702d5b0aaSJacek Lawrynowicz 	unsigned long timeout;
27802d5b0aaSJacek Lawrynowicz 	int ret;
27902d5b0aaSJacek Lawrynowicz 
28002d5b0aaSJacek Lawrynowicz 	if (ivpu_test_mode == IVPU_TEST_MODE_FW_TEST)
28102d5b0aaSJacek Lawrynowicz 		return 0;
28202d5b0aaSJacek Lawrynowicz 
28302d5b0aaSJacek Lawrynowicz 	ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG);
28402d5b0aaSJacek Lawrynowicz 
28502d5b0aaSJacek Lawrynowicz 	timeout = jiffies + msecs_to_jiffies(vdev->timeout.boot);
28602d5b0aaSJacek Lawrynowicz 	while (1) {
28702d5b0aaSJacek Lawrynowicz 		ret = ivpu_ipc_irq_handler(vdev);
28802d5b0aaSJacek Lawrynowicz 		if (ret)
28902d5b0aaSJacek Lawrynowicz 			break;
29002d5b0aaSJacek Lawrynowicz 		ret = ivpu_ipc_receive(vdev, &cons, &ipc_hdr, NULL, 0);
29102d5b0aaSJacek Lawrynowicz 		if (ret != -ETIMEDOUT || time_after_eq(jiffies, timeout))
29202d5b0aaSJacek Lawrynowicz 			break;
29302d5b0aaSJacek Lawrynowicz 
29402d5b0aaSJacek Lawrynowicz 		cond_resched();
29502d5b0aaSJacek Lawrynowicz 	}
29602d5b0aaSJacek Lawrynowicz 
29702d5b0aaSJacek Lawrynowicz 	ivpu_ipc_consumer_del(vdev, &cons);
29802d5b0aaSJacek Lawrynowicz 
29902d5b0aaSJacek Lawrynowicz 	if (!ret && ipc_hdr.data_addr != IVPU_IPC_BOOT_MSG_DATA_ADDR) {
30002d5b0aaSJacek Lawrynowicz 		ivpu_err(vdev, "Invalid VPU ready message: 0x%x\n",
30102d5b0aaSJacek Lawrynowicz 			 ipc_hdr.data_addr);
30202d5b0aaSJacek Lawrynowicz 		return -EIO;
30302d5b0aaSJacek Lawrynowicz 	}
30402d5b0aaSJacek Lawrynowicz 
30502d5b0aaSJacek Lawrynowicz 	if (!ret)
30602d5b0aaSJacek Lawrynowicz 		ivpu_info(vdev, "VPU ready message received successfully\n");
30702d5b0aaSJacek Lawrynowicz 	else
30802d5b0aaSJacek Lawrynowicz 		ivpu_hw_diagnose_failure(vdev);
30902d5b0aaSJacek Lawrynowicz 
31002d5b0aaSJacek Lawrynowicz 	return ret;
31102d5b0aaSJacek Lawrynowicz }
31202d5b0aaSJacek Lawrynowicz 
31302d5b0aaSJacek Lawrynowicz /**
31402d5b0aaSJacek Lawrynowicz  * ivpu_boot() - Start VPU firmware
31502d5b0aaSJacek Lawrynowicz  * @vdev: VPU device
31602d5b0aaSJacek Lawrynowicz  *
31702d5b0aaSJacek Lawrynowicz  * This function is paired with ivpu_shutdown() but it doesn't power up the
31802d5b0aaSJacek Lawrynowicz  * VPU because power up has to be called very early in ivpu_probe().
31902d5b0aaSJacek Lawrynowicz  */
32002d5b0aaSJacek Lawrynowicz int ivpu_boot(struct ivpu_device *vdev)
32102d5b0aaSJacek Lawrynowicz {
32202d5b0aaSJacek Lawrynowicz 	int ret;
32302d5b0aaSJacek Lawrynowicz 
32402d5b0aaSJacek Lawrynowicz 	/* Update boot params located at first 4KB of FW memory */
32502d5b0aaSJacek Lawrynowicz 	ivpu_fw_boot_params_setup(vdev, vdev->fw->mem->kvaddr);
32602d5b0aaSJacek Lawrynowicz 
32702d5b0aaSJacek Lawrynowicz 	ret = ivpu_hw_boot_fw(vdev);
32802d5b0aaSJacek Lawrynowicz 	if (ret) {
32902d5b0aaSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to start the firmware: %d\n", ret);
33002d5b0aaSJacek Lawrynowicz 		return ret;
33102d5b0aaSJacek Lawrynowicz 	}
33202d5b0aaSJacek Lawrynowicz 
33302d5b0aaSJacek Lawrynowicz 	ret = ivpu_wait_for_ready(vdev);
33402d5b0aaSJacek Lawrynowicz 	if (ret) {
33502d5b0aaSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret);
33602d5b0aaSJacek Lawrynowicz 		return ret;
33702d5b0aaSJacek Lawrynowicz 	}
33802d5b0aaSJacek Lawrynowicz 
33902d5b0aaSJacek Lawrynowicz 	ivpu_hw_irq_clear(vdev);
34002d5b0aaSJacek Lawrynowicz 	enable_irq(vdev->irq);
34102d5b0aaSJacek Lawrynowicz 	ivpu_hw_irq_enable(vdev);
34202d5b0aaSJacek Lawrynowicz 	ivpu_ipc_enable(vdev);
34302d5b0aaSJacek Lawrynowicz 	return 0;
34402d5b0aaSJacek Lawrynowicz }
34502d5b0aaSJacek Lawrynowicz 
34635b13763SJacek Lawrynowicz int ivpu_shutdown(struct ivpu_device *vdev)
34735b13763SJacek Lawrynowicz {
34835b13763SJacek Lawrynowicz 	int ret;
34935b13763SJacek Lawrynowicz 
35035b13763SJacek Lawrynowicz 	ivpu_hw_irq_disable(vdev);
35102d5b0aaSJacek Lawrynowicz 	disable_irq(vdev->irq);
3525d7422cfSJacek Lawrynowicz 	ivpu_ipc_disable(vdev);
353263b2ba5SJacek Lawrynowicz 	ivpu_mmu_disable(vdev);
35435b13763SJacek Lawrynowicz 
35535b13763SJacek Lawrynowicz 	ret = ivpu_hw_power_down(vdev);
35635b13763SJacek Lawrynowicz 	if (ret)
35735b13763SJacek Lawrynowicz 		ivpu_warn(vdev, "Failed to power down HW: %d\n", ret);
35835b13763SJacek Lawrynowicz 
35935b13763SJacek Lawrynowicz 	return ret;
36035b13763SJacek Lawrynowicz }
36135b13763SJacek Lawrynowicz 
36235b13763SJacek Lawrynowicz static const struct file_operations ivpu_fops = {
36335b13763SJacek Lawrynowicz 	.owner		= THIS_MODULE,
36435b13763SJacek Lawrynowicz 	DRM_ACCEL_FOPS,
36535b13763SJacek Lawrynowicz };
36635b13763SJacek Lawrynowicz 
36735b13763SJacek Lawrynowicz static const struct drm_driver driver = {
36835b13763SJacek Lawrynowicz 	.driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL,
36935b13763SJacek Lawrynowicz 
37035b13763SJacek Lawrynowicz 	.open = ivpu_open,
37135b13763SJacek Lawrynowicz 	.postclose = ivpu_postclose,
372647371a6SJacek Lawrynowicz 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
373647371a6SJacek Lawrynowicz 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
374647371a6SJacek Lawrynowicz 	.gem_prime_import = ivpu_gem_prime_import,
375647371a6SJacek Lawrynowicz 	.gem_prime_mmap = drm_gem_prime_mmap,
37635b13763SJacek Lawrynowicz 
37735b13763SJacek Lawrynowicz 	.ioctls = ivpu_drm_ioctls,
37835b13763SJacek Lawrynowicz 	.num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls),
37935b13763SJacek Lawrynowicz 	.fops = &ivpu_fops,
38035b13763SJacek Lawrynowicz 
38135b13763SJacek Lawrynowicz 	.name = DRIVER_NAME,
38235b13763SJacek Lawrynowicz 	.desc = DRIVER_DESC,
38335b13763SJacek Lawrynowicz 	.date = DRIVER_DATE,
38435b13763SJacek Lawrynowicz 	.major = DRM_IVPU_DRIVER_MAJOR,
38535b13763SJacek Lawrynowicz 	.minor = DRM_IVPU_DRIVER_MINOR,
38635b13763SJacek Lawrynowicz };
38735b13763SJacek Lawrynowicz 
38835b13763SJacek Lawrynowicz static int ivpu_irq_init(struct ivpu_device *vdev)
38935b13763SJacek Lawrynowicz {
39035b13763SJacek Lawrynowicz 	struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
39135b13763SJacek Lawrynowicz 	int ret;
39235b13763SJacek Lawrynowicz 
39335b13763SJacek Lawrynowicz 	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX);
39435b13763SJacek Lawrynowicz 	if (ret < 0) {
39535b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to allocate a MSI IRQ: %d\n", ret);
39635b13763SJacek Lawrynowicz 		return ret;
39735b13763SJacek Lawrynowicz 	}
39835b13763SJacek Lawrynowicz 
39935b13763SJacek Lawrynowicz 	vdev->irq = pci_irq_vector(pdev, 0);
40035b13763SJacek Lawrynowicz 
40135b13763SJacek Lawrynowicz 	ret = devm_request_irq(vdev->drm.dev, vdev->irq, vdev->hw->ops->irq_handler,
40235b13763SJacek Lawrynowicz 			       IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
40335b13763SJacek Lawrynowicz 	if (ret)
40435b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to request an IRQ %d\n", ret);
40535b13763SJacek Lawrynowicz 
40635b13763SJacek Lawrynowicz 	return ret;
40735b13763SJacek Lawrynowicz }
40835b13763SJacek Lawrynowicz 
40935b13763SJacek Lawrynowicz static int ivpu_pci_init(struct ivpu_device *vdev)
41035b13763SJacek Lawrynowicz {
41135b13763SJacek Lawrynowicz 	struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
41235b13763SJacek Lawrynowicz 	struct resource *bar0 = &pdev->resource[0];
41335b13763SJacek Lawrynowicz 	struct resource *bar4 = &pdev->resource[4];
41435b13763SJacek Lawrynowicz 	int ret;
41535b13763SJacek Lawrynowicz 
41635b13763SJacek Lawrynowicz 	ivpu_dbg(vdev, MISC, "Mapping BAR0 (RegV) %pR\n", bar0);
41735b13763SJacek Lawrynowicz 	vdev->regv = devm_ioremap_resource(vdev->drm.dev, bar0);
41835b13763SJacek Lawrynowicz 	if (IS_ERR(vdev->regv)) {
41935b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to map bar 0: %pe\n", vdev->regv);
42035b13763SJacek Lawrynowicz 		return PTR_ERR(vdev->regv);
42135b13763SJacek Lawrynowicz 	}
42235b13763SJacek Lawrynowicz 
42335b13763SJacek Lawrynowicz 	ivpu_dbg(vdev, MISC, "Mapping BAR4 (RegB) %pR\n", bar4);
42435b13763SJacek Lawrynowicz 	vdev->regb = devm_ioremap_resource(vdev->drm.dev, bar4);
42535b13763SJacek Lawrynowicz 	if (IS_ERR(vdev->regb)) {
42635b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to map bar 4: %pe\n", vdev->regb);
42735b13763SJacek Lawrynowicz 		return PTR_ERR(vdev->regb);
42835b13763SJacek Lawrynowicz 	}
42935b13763SJacek Lawrynowicz 
43035b13763SJacek Lawrynowicz 	ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(38));
43135b13763SJacek Lawrynowicz 	if (ret) {
43235b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to set DMA mask: %d\n", ret);
43335b13763SJacek Lawrynowicz 		return ret;
43435b13763SJacek Lawrynowicz 	}
43562079b6fSStanislaw Gruszka 	dma_set_max_seg_size(vdev->drm.dev, UINT_MAX);
43635b13763SJacek Lawrynowicz 
43735b13763SJacek Lawrynowicz 	/* Clear any pending errors */
43835b13763SJacek Lawrynowicz 	pcie_capability_clear_word(pdev, PCI_EXP_DEVSTA, 0x3f);
43935b13763SJacek Lawrynowicz 
44035b13763SJacek Lawrynowicz 	ret = pcim_enable_device(pdev);
44135b13763SJacek Lawrynowicz 	if (ret) {
44235b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to enable PCI device: %d\n", ret);
44335b13763SJacek Lawrynowicz 		return ret;
44435b13763SJacek Lawrynowicz 	}
44535b13763SJacek Lawrynowicz 
44635b13763SJacek Lawrynowicz 	pci_set_master(pdev);
44735b13763SJacek Lawrynowicz 
44835b13763SJacek Lawrynowicz 	return 0;
44935b13763SJacek Lawrynowicz }
45035b13763SJacek Lawrynowicz 
45135b13763SJacek Lawrynowicz static int ivpu_dev_init(struct ivpu_device *vdev)
45235b13763SJacek Lawrynowicz {
45335b13763SJacek Lawrynowicz 	int ret;
45435b13763SJacek Lawrynowicz 
45535b13763SJacek Lawrynowicz 	vdev->hw = drmm_kzalloc(&vdev->drm, sizeof(*vdev->hw), GFP_KERNEL);
45635b13763SJacek Lawrynowicz 	if (!vdev->hw)
45735b13763SJacek Lawrynowicz 		return -ENOMEM;
45835b13763SJacek Lawrynowicz 
459263b2ba5SJacek Lawrynowicz 	vdev->mmu = drmm_kzalloc(&vdev->drm, sizeof(*vdev->mmu), GFP_KERNEL);
460263b2ba5SJacek Lawrynowicz 	if (!vdev->mmu)
461263b2ba5SJacek Lawrynowicz 		return -ENOMEM;
462263b2ba5SJacek Lawrynowicz 
46302d5b0aaSJacek Lawrynowicz 	vdev->fw = drmm_kzalloc(&vdev->drm, sizeof(*vdev->fw), GFP_KERNEL);
46402d5b0aaSJacek Lawrynowicz 	if (!vdev->fw)
46502d5b0aaSJacek Lawrynowicz 		return -ENOMEM;
46602d5b0aaSJacek Lawrynowicz 
4675d7422cfSJacek Lawrynowicz 	vdev->ipc = drmm_kzalloc(&vdev->drm, sizeof(*vdev->ipc), GFP_KERNEL);
4685d7422cfSJacek Lawrynowicz 	if (!vdev->ipc)
4695d7422cfSJacek Lawrynowicz 		return -ENOMEM;
4705d7422cfSJacek Lawrynowicz 
471852be13fSJacek Lawrynowicz 	vdev->pm = drmm_kzalloc(&vdev->drm, sizeof(*vdev->pm), GFP_KERNEL);
472852be13fSJacek Lawrynowicz 	if (!vdev->pm)
473852be13fSJacek Lawrynowicz 		return -ENOMEM;
474852be13fSJacek Lawrynowicz 
47535b13763SJacek Lawrynowicz 	vdev->hw->ops = &ivpu_hw_mtl_ops;
47635b13763SJacek Lawrynowicz 	vdev->platform = IVPU_PLATFORM_INVALID;
477*3ff6edbcSStanislaw Gruszka 	vdev->context_xa_limit.min = IVPU_USER_CONTEXT_MIN_SSID;
478*3ff6edbcSStanislaw Gruszka 	vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID;
47902d5b0aaSJacek Lawrynowicz 	atomic64_set(&vdev->unique_id_counter, 0);
48035b13763SJacek Lawrynowicz 	xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC);
481cd727221SJacek Lawrynowicz 	xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1);
482cd727221SJacek Lawrynowicz 	lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key);
48335b13763SJacek Lawrynowicz 
48435b13763SJacek Lawrynowicz 	ret = ivpu_pci_init(vdev);
48535b13763SJacek Lawrynowicz 	if (ret) {
48635b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize PCI device: %d\n", ret);
48735b13763SJacek Lawrynowicz 		goto err_xa_destroy;
48835b13763SJacek Lawrynowicz 	}
48935b13763SJacek Lawrynowicz 
49035b13763SJacek Lawrynowicz 	ret = ivpu_irq_init(vdev);
49135b13763SJacek Lawrynowicz 	if (ret) {
49235b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize IRQs: %d\n", ret);
49335b13763SJacek Lawrynowicz 		goto err_xa_destroy;
49435b13763SJacek Lawrynowicz 	}
49535b13763SJacek Lawrynowicz 
49635b13763SJacek Lawrynowicz 	/* Init basic HW info based on buttress registers which are accessible before power up */
49735b13763SJacek Lawrynowicz 	ret = ivpu_hw_info_init(vdev);
49835b13763SJacek Lawrynowicz 	if (ret) {
49935b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize HW info: %d\n", ret);
50035b13763SJacek Lawrynowicz 		goto err_xa_destroy;
50135b13763SJacek Lawrynowicz 	}
50235b13763SJacek Lawrynowicz 
50335b13763SJacek Lawrynowicz 	/* Power up early so the rest of init code can access VPU registers */
50435b13763SJacek Lawrynowicz 	ret = ivpu_hw_power_up(vdev);
50535b13763SJacek Lawrynowicz 	if (ret) {
50635b13763SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to power up HW: %d\n", ret);
50735b13763SJacek Lawrynowicz 		goto err_xa_destroy;
50835b13763SJacek Lawrynowicz 	}
50935b13763SJacek Lawrynowicz 
510263b2ba5SJacek Lawrynowicz 	ret = ivpu_mmu_global_context_init(vdev);
511263b2ba5SJacek Lawrynowicz 	if (ret) {
512263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize global MMU context: %d\n", ret);
513263b2ba5SJacek Lawrynowicz 		goto err_power_down;
514263b2ba5SJacek Lawrynowicz 	}
515263b2ba5SJacek Lawrynowicz 
516263b2ba5SJacek Lawrynowicz 	ret = ivpu_mmu_init(vdev);
517263b2ba5SJacek Lawrynowicz 	if (ret) {
518263b2ba5SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize MMU device: %d\n", ret);
519263b2ba5SJacek Lawrynowicz 		goto err_mmu_gctx_fini;
520263b2ba5SJacek Lawrynowicz 	}
521263b2ba5SJacek Lawrynowicz 
52202d5b0aaSJacek Lawrynowicz 	ret = ivpu_fw_init(vdev);
52302d5b0aaSJacek Lawrynowicz 	if (ret) {
52402d5b0aaSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize firmware: %d\n", ret);
52502d5b0aaSJacek Lawrynowicz 		goto err_mmu_gctx_fini;
52602d5b0aaSJacek Lawrynowicz 	}
52702d5b0aaSJacek Lawrynowicz 
5285d7422cfSJacek Lawrynowicz 	ret = ivpu_ipc_init(vdev);
5295d7422cfSJacek Lawrynowicz 	if (ret) {
5305d7422cfSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize IPC: %d\n", ret);
53102d5b0aaSJacek Lawrynowicz 		goto err_fw_fini;
53202d5b0aaSJacek Lawrynowicz 	}
53302d5b0aaSJacek Lawrynowicz 
534852be13fSJacek Lawrynowicz 	ret = ivpu_pm_init(vdev);
535852be13fSJacek Lawrynowicz 	if (ret) {
536852be13fSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize PM: %d\n", ret);
537852be13fSJacek Lawrynowicz 		goto err_ipc_fini;
538852be13fSJacek Lawrynowicz 	}
539852be13fSJacek Lawrynowicz 
540cd727221SJacek Lawrynowicz 	ret = ivpu_job_done_thread_init(vdev);
541cd727221SJacek Lawrynowicz 	if (ret) {
542cd727221SJacek Lawrynowicz 		ivpu_err(vdev, "Failed to initialize job done thread: %d\n", ret);
543cd727221SJacek Lawrynowicz 		goto err_ipc_fini;
544cd727221SJacek Lawrynowicz 	}
545cd727221SJacek Lawrynowicz 
54602d5b0aaSJacek Lawrynowicz 	ret = ivpu_fw_load(vdev);
54702d5b0aaSJacek Lawrynowicz 	if (ret) {
54802d5b0aaSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to load firmware: %d\n", ret);
549cd727221SJacek Lawrynowicz 		goto err_job_done_thread_fini;
55002d5b0aaSJacek Lawrynowicz 	}
55102d5b0aaSJacek Lawrynowicz 
55202d5b0aaSJacek Lawrynowicz 	ret = ivpu_boot(vdev);
55302d5b0aaSJacek Lawrynowicz 	if (ret) {
55402d5b0aaSJacek Lawrynowicz 		ivpu_err(vdev, "Failed to boot: %d\n", ret);
555cd727221SJacek Lawrynowicz 		goto err_job_done_thread_fini;
5565d7422cfSJacek Lawrynowicz 	}
5575d7422cfSJacek Lawrynowicz 
558852be13fSJacek Lawrynowicz 	ivpu_pm_enable(vdev);
559852be13fSJacek Lawrynowicz 
56035b13763SJacek Lawrynowicz 	return 0;
56135b13763SJacek Lawrynowicz 
562cd727221SJacek Lawrynowicz err_job_done_thread_fini:
563cd727221SJacek Lawrynowicz 	ivpu_job_done_thread_fini(vdev);
564cd727221SJacek Lawrynowicz err_ipc_fini:
565cd727221SJacek Lawrynowicz 	ivpu_ipc_fini(vdev);
56602d5b0aaSJacek Lawrynowicz err_fw_fini:
56702d5b0aaSJacek Lawrynowicz 	ivpu_fw_fini(vdev);
568263b2ba5SJacek Lawrynowicz err_mmu_gctx_fini:
569263b2ba5SJacek Lawrynowicz 	ivpu_mmu_global_context_fini(vdev);
570263b2ba5SJacek Lawrynowicz err_power_down:
571263b2ba5SJacek Lawrynowicz 	ivpu_hw_power_down(vdev);
57235b13763SJacek Lawrynowicz err_xa_destroy:
573cd727221SJacek Lawrynowicz 	xa_destroy(&vdev->submitted_jobs_xa);
57435b13763SJacek Lawrynowicz 	xa_destroy(&vdev->context_xa);
57535b13763SJacek Lawrynowicz 	return ret;
57635b13763SJacek Lawrynowicz }
57735b13763SJacek Lawrynowicz 
57835b13763SJacek Lawrynowicz static void ivpu_dev_fini(struct ivpu_device *vdev)
57935b13763SJacek Lawrynowicz {
580852be13fSJacek Lawrynowicz 	ivpu_pm_disable(vdev);
58135b13763SJacek Lawrynowicz 	ivpu_shutdown(vdev);
582cd727221SJacek Lawrynowicz 	ivpu_job_done_thread_fini(vdev);
5836013aa84SStanislaw Gruszka 	ivpu_pm_cancel_recovery(vdev);
5846013aa84SStanislaw Gruszka 
5855d7422cfSJacek Lawrynowicz 	ivpu_ipc_fini(vdev);
58602d5b0aaSJacek Lawrynowicz 	ivpu_fw_fini(vdev);
587263b2ba5SJacek Lawrynowicz 	ivpu_mmu_global_context_fini(vdev);
58835b13763SJacek Lawrynowicz 
589cd727221SJacek Lawrynowicz 	drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
590cd727221SJacek Lawrynowicz 	xa_destroy(&vdev->submitted_jobs_xa);
59135b13763SJacek Lawrynowicz 	drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->context_xa));
59235b13763SJacek Lawrynowicz 	xa_destroy(&vdev->context_xa);
59335b13763SJacek Lawrynowicz }
59435b13763SJacek Lawrynowicz 
59535b13763SJacek Lawrynowicz static struct pci_device_id ivpu_pci_ids[] = {
59635b13763SJacek Lawrynowicz 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
59735b13763SJacek Lawrynowicz 	{ }
59835b13763SJacek Lawrynowicz };
59935b13763SJacek Lawrynowicz MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
60035b13763SJacek Lawrynowicz 
60135b13763SJacek Lawrynowicz static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
60235b13763SJacek Lawrynowicz {
60335b13763SJacek Lawrynowicz 	struct ivpu_device *vdev;
60435b13763SJacek Lawrynowicz 	int ret;
60535b13763SJacek Lawrynowicz 
60635b13763SJacek Lawrynowicz 	vdev = devm_drm_dev_alloc(&pdev->dev, &driver, struct ivpu_device, drm);
60735b13763SJacek Lawrynowicz 	if (IS_ERR(vdev))
60835b13763SJacek Lawrynowicz 		return PTR_ERR(vdev);
60935b13763SJacek Lawrynowicz 
61035b13763SJacek Lawrynowicz 	pci_set_drvdata(pdev, vdev);
61135b13763SJacek Lawrynowicz 
61235b13763SJacek Lawrynowicz 	ret = ivpu_dev_init(vdev);
61335b13763SJacek Lawrynowicz 	if (ret) {
61435b13763SJacek Lawrynowicz 		dev_err(&pdev->dev, "Failed to initialize VPU device: %d\n", ret);
61535b13763SJacek Lawrynowicz 		return ret;
61635b13763SJacek Lawrynowicz 	}
61735b13763SJacek Lawrynowicz 
61835b13763SJacek Lawrynowicz 	ret = drm_dev_register(&vdev->drm, 0);
61935b13763SJacek Lawrynowicz 	if (ret) {
62035b13763SJacek Lawrynowicz 		dev_err(&pdev->dev, "Failed to register DRM device: %d\n", ret);
62135b13763SJacek Lawrynowicz 		ivpu_dev_fini(vdev);
62235b13763SJacek Lawrynowicz 	}
62335b13763SJacek Lawrynowicz 
62435b13763SJacek Lawrynowicz 	return ret;
62535b13763SJacek Lawrynowicz }
62635b13763SJacek Lawrynowicz 
62735b13763SJacek Lawrynowicz static void ivpu_remove(struct pci_dev *pdev)
62835b13763SJacek Lawrynowicz {
62935b13763SJacek Lawrynowicz 	struct ivpu_device *vdev = pci_get_drvdata(pdev);
63035b13763SJacek Lawrynowicz 
6314522ad76SStanislaw Gruszka 	drm_dev_unplug(&vdev->drm);
63235b13763SJacek Lawrynowicz 	ivpu_dev_fini(vdev);
63335b13763SJacek Lawrynowicz }
63435b13763SJacek Lawrynowicz 
635852be13fSJacek Lawrynowicz static const struct dev_pm_ops ivpu_drv_pci_pm = {
636852be13fSJacek Lawrynowicz 	SET_SYSTEM_SLEEP_PM_OPS(ivpu_pm_suspend_cb, ivpu_pm_resume_cb)
637852be13fSJacek Lawrynowicz 	SET_RUNTIME_PM_OPS(ivpu_pm_runtime_suspend_cb, ivpu_pm_runtime_resume_cb, NULL)
638852be13fSJacek Lawrynowicz };
639852be13fSJacek Lawrynowicz 
640852be13fSJacek Lawrynowicz static const struct pci_error_handlers ivpu_drv_pci_err = {
641852be13fSJacek Lawrynowicz 	.reset_prepare = ivpu_pm_reset_prepare_cb,
642852be13fSJacek Lawrynowicz 	.reset_done = ivpu_pm_reset_done_cb,
643852be13fSJacek Lawrynowicz };
644852be13fSJacek Lawrynowicz 
64535b13763SJacek Lawrynowicz static struct pci_driver ivpu_pci_driver = {
64635b13763SJacek Lawrynowicz 	.name = KBUILD_MODNAME,
64735b13763SJacek Lawrynowicz 	.id_table = ivpu_pci_ids,
64835b13763SJacek Lawrynowicz 	.probe = ivpu_probe,
64935b13763SJacek Lawrynowicz 	.remove = ivpu_remove,
650852be13fSJacek Lawrynowicz 	.driver = {
651852be13fSJacek Lawrynowicz 		.pm = &ivpu_drv_pci_pm,
652852be13fSJacek Lawrynowicz 	},
653852be13fSJacek Lawrynowicz 	.err_handler = &ivpu_drv_pci_err,
65435b13763SJacek Lawrynowicz };
65535b13763SJacek Lawrynowicz 
65635b13763SJacek Lawrynowicz module_pci_driver(ivpu_pci_driver);
65735b13763SJacek Lawrynowicz 
65835b13763SJacek Lawrynowicz MODULE_AUTHOR("Intel Corporation");
65935b13763SJacek Lawrynowicz MODULE_DESCRIPTION(DRIVER_DESC);
66035b13763SJacek Lawrynowicz MODULE_LICENSE("GPL and additional rights");
66135b13763SJacek Lawrynowicz MODULE_VERSION(DRIVER_VERSION_STR);
662