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