Skip to content

Commit

Permalink
accel/ivpu: Add Intel VPU MMU support
Browse files Browse the repository at this point in the history
VPU Memory Management Unit is based on ARM MMU-600.
It allows the creation of multiple virtual address spaces for
the device and map noncontinuous host memory (there is no dedicated
memory on the VPU).

Address space is implemented as a struct ivpu_mmu_context, it has an ID,
drm_mm allocator for VPU addresses and struct ivpu_mmu_pgtable that
holds actual 3-level, 4KB page table.
Context with ID 0 (global context) is created upon driver initialization
and it's mainly used for mapping memory required to execute
the firmware.
Contexts with non-zero IDs are user contexts allocated each time
the devices is open()-ed and they map command buffers and other
workload-related memory.
Workloads executing in a given contexts have access only
to the memory mapped in this context.

This patch is has two main files:
  - ivpu_mmu_context.c handles MMU page tables and memory mapping
  - ivpu_mmu.c implements a driver that programs the MMU device

Co-developed-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Co-developed-by: Krystian Pradzynski <krystian.pradzynski@linux.intel.com>
Signed-off-by: Krystian Pradzynski <krystian.pradzynski@linux.intel.com>
Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Reviewed-by: Oded Gabbay <ogabbay@kernel.org>
Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20230117092723.60441-3-jacek.lawrynowicz@linux.intel.com
  • Loading branch information
Jacek Lawrynowicz authored and Daniel Vetter committed Jan 19, 2023
1 parent 35b1376 commit 263b2ba
Show file tree
Hide file tree
Showing 9 changed files with 1,479 additions and 3 deletions.
4 changes: 3 additions & 1 deletion drivers/accel/ivpu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

intel_vpu-y := \
ivpu_drv.o \
ivpu_hw_mtl.o
ivpu_hw_mtl.o \
ivpu_mmu.o \
ivpu_mmu_context.o

obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o
83 changes: 81 additions & 2 deletions drivers/accel/ivpu/ivpu_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

#include "ivpu_drv.h"
#include "ivpu_hw.h"
#include "ivpu_mmu.h"
#include "ivpu_mmu_context.h"

#ifndef DRIVER_VERSION_STR
#define DRIVER_VERSION_STR __stringify(DRM_IVPU_DRIVER_MAJOR) "." \
Expand All @@ -37,23 +39,38 @@ MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set VPU frequency");

struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
{
struct ivpu_device *vdev = file_priv->vdev;

kref_get(&file_priv->ref);

ivpu_dbg(vdev, KREF, "file_priv get: ctx %u refcount %u\n",
file_priv->ctx.id, kref_read(&file_priv->ref));

return file_priv;
}

static void file_priv_release(struct kref *ref)
{
struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
struct ivpu_device *vdev = file_priv->vdev;

ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id);

ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
WARN_ON(xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv);
kfree(file_priv);
}

void ivpu_file_priv_put(struct ivpu_file_priv **link)
{
struct ivpu_file_priv *file_priv = *link;
struct ivpu_device *vdev = file_priv->vdev;

WARN_ON(!file_priv);

ivpu_dbg(vdev, KREF, "file_priv put: ctx %u refcount %u\n",
file_priv->ctx.id, kref_read(&file_priv->ref));

*link = NULL;
kref_put(&file_priv->ref, file_priv_release);
}
Expand Down Expand Up @@ -88,6 +105,9 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
args->value = file_priv->priority;
break;
case DRM_IVPU_PARAM_CONTEXT_ID:
args->value = file_priv->ctx.id;
break;
default:
ret = -EINVAL;
break;
Expand Down Expand Up @@ -120,22 +140,59 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file)
{
struct ivpu_device *vdev = to_ivpu_device(dev);
struct ivpu_file_priv *file_priv;
u32 ctx_id;
void *old;
int ret;

ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL);
if (ret) {
ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
return ret;
}

file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
if (!file_priv) {
ret = -ENOMEM;
goto err_xa_erase;
}

file_priv->vdev = vdev;
file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
kref_init(&file_priv->ref);

ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id);
if (ret)
goto err_free_file_priv;

old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL);
if (xa_is_err(old)) {
ret = xa_err(old);
ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret);
goto err_ctx_fini;
}

ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n",
ctx_id, current->comm, task_pid_nr(current));

file->driver_priv = file_priv;
return 0;

err_ctx_fini:
ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
err_free_file_priv:
kfree(file_priv);
err_xa_erase:
xa_erase_irq(&vdev->context_xa, ctx_id);
return ret;
}

static void ivpu_postclose(struct drm_device *dev, struct drm_file *file)
{
struct ivpu_file_priv *file_priv = file->driver_priv;
struct ivpu_device *vdev = to_ivpu_device(dev);

ivpu_dbg(vdev, FILE, "file_priv close: ctx %u process %s pid %d\n",
file_priv->ctx.id, current->comm, task_pid_nr(current));

ivpu_file_priv_put(&file_priv);
}
Expand All @@ -150,6 +207,7 @@ int ivpu_shutdown(struct ivpu_device *vdev)
int ret;

ivpu_hw_irq_disable(vdev);
ivpu_mmu_disable(vdev);

ret = ivpu_hw_power_down(vdev);
if (ret)
Expand Down Expand Up @@ -251,6 +309,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
if (!vdev->hw)
return -ENOMEM;

vdev->mmu = drmm_kzalloc(&vdev->drm, sizeof(*vdev->mmu), GFP_KERNEL);
if (!vdev->mmu)
return -ENOMEM;

vdev->hw->ops = &ivpu_hw_mtl_ops;
vdev->platform = IVPU_PLATFORM_INVALID;
vdev->context_xa_limit.min = IVPU_GLOBAL_CONTEXT_MMU_SSID + 1;
Expand Down Expand Up @@ -283,8 +345,24 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
goto err_xa_destroy;
}

ret = ivpu_mmu_global_context_init(vdev);
if (ret) {
ivpu_err(vdev, "Failed to initialize global MMU context: %d\n", ret);
goto err_power_down;
}

ret = ivpu_mmu_init(vdev);
if (ret) {
ivpu_err(vdev, "Failed to initialize MMU device: %d\n", ret);
goto err_mmu_gctx_fini;
}

return 0;

err_mmu_gctx_fini:
ivpu_mmu_global_context_fini(vdev);
err_power_down:
ivpu_hw_power_down(vdev);
err_xa_destroy:
xa_destroy(&vdev->context_xa);
return ret;
Expand All @@ -293,6 +371,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
static void ivpu_dev_fini(struct ivpu_device *vdev)
{
ivpu_shutdown(vdev);
ivpu_mmu_global_context_fini(vdev);

drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->context_xa));
xa_destroy(&vdev->context_xa);
Expand Down
7 changes: 7 additions & 0 deletions drivers/accel/ivpu/ivpu_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <linux/xarray.h>
#include <uapi/drm/ivpu_accel.h>

#include "ivpu_mmu_context.h"

#define DRIVER_NAME "intel_vpu"
#define DRIVER_DESC "Driver for Intel Versatile Processing Unit (VPU)"
#define DRIVER_DATE "20230117"
Expand Down Expand Up @@ -71,6 +73,7 @@ struct ivpu_wa_table {
};

struct ivpu_hw_info;
struct ivpu_mmu_info;

struct ivpu_device {
struct drm_device drm;
Expand All @@ -81,7 +84,9 @@ struct ivpu_device {

struct ivpu_wa_table wa;
struct ivpu_hw_info *hw;
struct ivpu_mmu_info *mmu;

struct ivpu_mmu_context gctx;
struct xarray context_xa;
struct xa_limit context_xa_limit;

Expand All @@ -100,7 +105,9 @@ struct ivpu_device {
struct ivpu_file_priv {
struct kref ref;
struct ivpu_device *vdev;
struct ivpu_mmu_context ctx;
u32 priority;
bool has_mmu_faults;
};

extern int ivpu_dbg_mask;
Expand Down
10 changes: 10 additions & 0 deletions drivers/accel/ivpu/ivpu_hw_mtl.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "ivpu_hw_mtl_reg.h"
#include "ivpu_hw_reg_io.h"
#include "ivpu_hw.h"
#include "ivpu_mmu.h"

#define TILE_FUSE_ENABLE_BOTH 0x0
#define TILE_FUSE_ENABLE_UPPER 0x1
Expand Down Expand Up @@ -930,6 +931,15 @@ static u32 ivpu_hw_mtl_irqv_handler(struct ivpu_device *vdev, int irq)

REGV_WR32(MTL_VPU_HOST_SS_ICB_CLEAR_0, status);

if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT, status))
ivpu_mmu_irq_evtq_handler(vdev);

if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status))
ivpu_dbg(vdev, IRQ, "MMU sync complete\n");

if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT, status))
ivpu_mmu_irq_gerr_handler(vdev);

if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, status))
ivpu_hw_mtl_irq_wdt_mss_handler(vdev);

Expand Down
Loading

0 comments on commit 263b2ba

Please sign in to comment.