Skip to content

Commit 263b2ba

Browse files
jlawrynodanvet
authored andcommitted
accel/ivpu: Add Intel VPU MMU support
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
1 parent 35b1376 commit 263b2ba

File tree

9 files changed

+1479
-3
lines changed

9 files changed

+1479
-3
lines changed

drivers/accel/ivpu/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
intel_vpu-y := \
55
ivpu_drv.o \
6-
ivpu_hw_mtl.o
6+
ivpu_hw_mtl.o \
7+
ivpu_mmu.o \
8+
ivpu_mmu_context.o
79

810
obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o

drivers/accel/ivpu/ivpu_drv.c

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include "ivpu_drv.h"
1717
#include "ivpu_hw.h"
18+
#include "ivpu_mmu.h"
19+
#include "ivpu_mmu_context.h"
1820

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

3840
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
3941
{
42+
struct ivpu_device *vdev = file_priv->vdev;
43+
4044
kref_get(&file_priv->ref);
45+
46+
ivpu_dbg(vdev, KREF, "file_priv get: ctx %u refcount %u\n",
47+
file_priv->ctx.id, kref_read(&file_priv->ref));
48+
4149
return file_priv;
4250
}
4351

4452
static void file_priv_release(struct kref *ref)
4553
{
4654
struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
55+
struct ivpu_device *vdev = file_priv->vdev;
4756

57+
ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id);
58+
59+
ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
60+
WARN_ON(xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv);
4861
kfree(file_priv);
4962
}
5063

5164
void ivpu_file_priv_put(struct ivpu_file_priv **link)
5265
{
5366
struct ivpu_file_priv *file_priv = *link;
67+
struct ivpu_device *vdev = file_priv->vdev;
5468

5569
WARN_ON(!file_priv);
5670

71+
ivpu_dbg(vdev, KREF, "file_priv put: ctx %u refcount %u\n",
72+
file_priv->ctx.id, kref_read(&file_priv->ref));
73+
5774
*link = NULL;
5875
kref_put(&file_priv->ref, file_priv_release);
5976
}
@@ -88,6 +105,9 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
88105
case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
89106
args->value = file_priv->priority;
90107
break;
108+
case DRM_IVPU_PARAM_CONTEXT_ID:
109+
args->value = file_priv->ctx.id;
110+
break;
91111
default:
92112
ret = -EINVAL;
93113
break;
@@ -120,22 +140,59 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file)
120140
{
121141
struct ivpu_device *vdev = to_ivpu_device(dev);
122142
struct ivpu_file_priv *file_priv;
143+
u32 ctx_id;
144+
void *old;
145+
int ret;
146+
147+
ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL);
148+
if (ret) {
149+
ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
150+
return ret;
151+
}
123152

124153
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
125-
if (!file_priv)
126-
return -ENOMEM;
154+
if (!file_priv) {
155+
ret = -ENOMEM;
156+
goto err_xa_erase;
157+
}
127158

128159
file_priv->vdev = vdev;
129160
file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
130161
kref_init(&file_priv->ref);
131162

163+
ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id);
164+
if (ret)
165+
goto err_free_file_priv;
166+
167+
old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL);
168+
if (xa_is_err(old)) {
169+
ret = xa_err(old);
170+
ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret);
171+
goto err_ctx_fini;
172+
}
173+
174+
ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n",
175+
ctx_id, current->comm, task_pid_nr(current));
176+
132177
file->driver_priv = file_priv;
133178
return 0;
179+
180+
err_ctx_fini:
181+
ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
182+
err_free_file_priv:
183+
kfree(file_priv);
184+
err_xa_erase:
185+
xa_erase_irq(&vdev->context_xa, ctx_id);
186+
return ret;
134187
}
135188

136189
static void ivpu_postclose(struct drm_device *dev, struct drm_file *file)
137190
{
138191
struct ivpu_file_priv *file_priv = file->driver_priv;
192+
struct ivpu_device *vdev = to_ivpu_device(dev);
193+
194+
ivpu_dbg(vdev, FILE, "file_priv close: ctx %u process %s pid %d\n",
195+
file_priv->ctx.id, current->comm, task_pid_nr(current));
139196

140197
ivpu_file_priv_put(&file_priv);
141198
}
@@ -150,6 +207,7 @@ int ivpu_shutdown(struct ivpu_device *vdev)
150207
int ret;
151208

152209
ivpu_hw_irq_disable(vdev);
210+
ivpu_mmu_disable(vdev);
153211

154212
ret = ivpu_hw_power_down(vdev);
155213
if (ret)
@@ -251,6 +309,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
251309
if (!vdev->hw)
252310
return -ENOMEM;
253311

312+
vdev->mmu = drmm_kzalloc(&vdev->drm, sizeof(*vdev->mmu), GFP_KERNEL);
313+
if (!vdev->mmu)
314+
return -ENOMEM;
315+
254316
vdev->hw->ops = &ivpu_hw_mtl_ops;
255317
vdev->platform = IVPU_PLATFORM_INVALID;
256318
vdev->context_xa_limit.min = IVPU_GLOBAL_CONTEXT_MMU_SSID + 1;
@@ -283,8 +345,24 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
283345
goto err_xa_destroy;
284346
}
285347

348+
ret = ivpu_mmu_global_context_init(vdev);
349+
if (ret) {
350+
ivpu_err(vdev, "Failed to initialize global MMU context: %d\n", ret);
351+
goto err_power_down;
352+
}
353+
354+
ret = ivpu_mmu_init(vdev);
355+
if (ret) {
356+
ivpu_err(vdev, "Failed to initialize MMU device: %d\n", ret);
357+
goto err_mmu_gctx_fini;
358+
}
359+
286360
return 0;
287361

362+
err_mmu_gctx_fini:
363+
ivpu_mmu_global_context_fini(vdev);
364+
err_power_down:
365+
ivpu_hw_power_down(vdev);
288366
err_xa_destroy:
289367
xa_destroy(&vdev->context_xa);
290368
return ret;
@@ -293,6 +371,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
293371
static void ivpu_dev_fini(struct ivpu_device *vdev)
294372
{
295373
ivpu_shutdown(vdev);
374+
ivpu_mmu_global_context_fini(vdev);
296375

297376
drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->context_xa));
298377
xa_destroy(&vdev->context_xa);

drivers/accel/ivpu/ivpu_drv.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <linux/xarray.h>
1616
#include <uapi/drm/ivpu_accel.h>
1717

18+
#include "ivpu_mmu_context.h"
19+
1820
#define DRIVER_NAME "intel_vpu"
1921
#define DRIVER_DESC "Driver for Intel Versatile Processing Unit (VPU)"
2022
#define DRIVER_DATE "20230117"
@@ -71,6 +73,7 @@ struct ivpu_wa_table {
7173
};
7274

7375
struct ivpu_hw_info;
76+
struct ivpu_mmu_info;
7477

7578
struct ivpu_device {
7679
struct drm_device drm;
@@ -81,7 +84,9 @@ struct ivpu_device {
8184

8285
struct ivpu_wa_table wa;
8386
struct ivpu_hw_info *hw;
87+
struct ivpu_mmu_info *mmu;
8488

89+
struct ivpu_mmu_context gctx;
8590
struct xarray context_xa;
8691
struct xa_limit context_xa_limit;
8792

@@ -100,7 +105,9 @@ struct ivpu_device {
100105
struct ivpu_file_priv {
101106
struct kref ref;
102107
struct ivpu_device *vdev;
108+
struct ivpu_mmu_context ctx;
103109
u32 priority;
110+
bool has_mmu_faults;
104111
};
105112

106113
extern int ivpu_dbg_mask;

drivers/accel/ivpu/ivpu_hw_mtl.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "ivpu_hw_mtl_reg.h"
88
#include "ivpu_hw_reg_io.h"
99
#include "ivpu_hw.h"
10+
#include "ivpu_mmu.h"
1011

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

931932
REGV_WR32(MTL_VPU_HOST_SS_ICB_CLEAR_0, status);
932933

934+
if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT, status))
935+
ivpu_mmu_irq_evtq_handler(vdev);
936+
937+
if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status))
938+
ivpu_dbg(vdev, IRQ, "MMU sync complete\n");
939+
940+
if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT, status))
941+
ivpu_mmu_irq_gerr_handler(vdev);
942+
933943
if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, status))
934944
ivpu_hw_mtl_irq_wdt_mss_handler(vdev);
935945

0 commit comments

Comments
 (0)