Skip to content

Commit 02d5b0a

Browse files
jlawrynodanvet
authored andcommitted
accel/ivpu: Implement firmware parsing and booting
Read, parse and boot VPU firmware image. Co-developed-by: Andrzej Kacprowski <[email protected]> Signed-off-by: Andrzej Kacprowski <[email protected]> Co-developed-by: Krystian Pradzynski <[email protected]> Signed-off-by: Krystian Pradzynski <[email protected]> Signed-off-by: Jacek Lawrynowicz <[email protected]> Reviewed-by: Oded Gabbay <[email protected]> Reviewed-by: Jeffrey Hugo <[email protected]> Signed-off-by: Daniel Vetter <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 5d7422c commit 02d5b0a

File tree

8 files changed

+979
-1
lines changed

8 files changed

+979
-1
lines changed

drivers/accel/ivpu/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
intel_vpu-y := \
55
ivpu_drv.o \
6+
ivpu_fw.o \
67
ivpu_gem.o \
78
ivpu_hw_mtl.o \
89
ivpu_ipc.o \

drivers/accel/ivpu/ivpu_drv.c

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
#include <drm/drm_ioctl.h>
1515
#include <drm/drm_prime.h>
1616

17+
#include "vpu_boot_api.h"
1718
#include "ivpu_drv.h"
19+
#include "ivpu_fw.h"
1820
#include "ivpu_gem.h"
1921
#include "ivpu_hw.h"
2022
#include "ivpu_ipc.h"
23+
#include "ivpu_jsm_msg.h"
2124
#include "ivpu_mmu.h"
2225
#include "ivpu_mmu_context.h"
2326

@@ -32,6 +35,10 @@ int ivpu_dbg_mask;
3235
module_param_named(dbg_mask, ivpu_dbg_mask, int, 0644);
3336
MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros.");
3437

38+
int ivpu_test_mode;
39+
module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644);
40+
MODULE_PARM_DESC(test_mode, "Test mode: 0 - normal operation, 1 - fw unit test, 2 - null hw");
41+
3542
u8 ivpu_pll_min_ratio;
3643
module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644);
3744
MODULE_PARM_DESC(pll_min_ratio, "Minimum PLL ratio used to set VPU frequency");
@@ -129,6 +136,28 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
129136
case DRM_IVPU_PARAM_CONTEXT_ID:
130137
args->value = file_priv->ctx.id;
131138
break;
139+
case DRM_IVPU_PARAM_FW_API_VERSION:
140+
if (args->index < VPU_FW_API_VER_NUM) {
141+
struct vpu_firmware_header *fw_hdr;
142+
143+
fw_hdr = (struct vpu_firmware_header *)vdev->fw->file->data;
144+
args->value = fw_hdr->api_version[args->index];
145+
} else {
146+
ret = -EINVAL;
147+
}
148+
break;
149+
case DRM_IVPU_PARAM_ENGINE_HEARTBEAT:
150+
ret = ivpu_jsm_get_heartbeat(vdev, args->index, &args->value);
151+
break;
152+
case DRM_IVPU_PARAM_UNIQUE_INFERENCE_ID:
153+
args->value = (u64)atomic64_inc_return(&vdev->unique_id_counter);
154+
break;
155+
case DRM_IVPU_PARAM_TILE_CONFIG:
156+
args->value = vdev->hw->tile_fuse;
157+
break;
158+
case DRM_IVPU_PARAM_SKU:
159+
args->value = vdev->hw->sku;
160+
break;
132161
default:
133162
ret = -EINVAL;
134163
break;
@@ -225,11 +254,85 @@ static const struct drm_ioctl_desc ivpu_drm_ioctls[] = {
225254
DRM_IOCTL_DEF_DRV(IVPU_BO_INFO, ivpu_bo_info_ioctl, 0),
226255
};
227256

257+
static int ivpu_wait_for_ready(struct ivpu_device *vdev)
258+
{
259+
struct ivpu_ipc_consumer cons;
260+
struct ivpu_ipc_hdr ipc_hdr;
261+
unsigned long timeout;
262+
int ret;
263+
264+
if (ivpu_test_mode == IVPU_TEST_MODE_FW_TEST)
265+
return 0;
266+
267+
ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG);
268+
269+
timeout = jiffies + msecs_to_jiffies(vdev->timeout.boot);
270+
while (1) {
271+
ret = ivpu_ipc_irq_handler(vdev);
272+
if (ret)
273+
break;
274+
ret = ivpu_ipc_receive(vdev, &cons, &ipc_hdr, NULL, 0);
275+
if (ret != -ETIMEDOUT || time_after_eq(jiffies, timeout))
276+
break;
277+
278+
cond_resched();
279+
}
280+
281+
ivpu_ipc_consumer_del(vdev, &cons);
282+
283+
if (!ret && ipc_hdr.data_addr != IVPU_IPC_BOOT_MSG_DATA_ADDR) {
284+
ivpu_err(vdev, "Invalid VPU ready message: 0x%x\n",
285+
ipc_hdr.data_addr);
286+
return -EIO;
287+
}
288+
289+
if (!ret)
290+
ivpu_info(vdev, "VPU ready message received successfully\n");
291+
else
292+
ivpu_hw_diagnose_failure(vdev);
293+
294+
return ret;
295+
}
296+
297+
/**
298+
* ivpu_boot() - Start VPU firmware
299+
* @vdev: VPU device
300+
*
301+
* This function is paired with ivpu_shutdown() but it doesn't power up the
302+
* VPU because power up has to be called very early in ivpu_probe().
303+
*/
304+
int ivpu_boot(struct ivpu_device *vdev)
305+
{
306+
int ret;
307+
308+
/* Update boot params located at first 4KB of FW memory */
309+
ivpu_fw_boot_params_setup(vdev, vdev->fw->mem->kvaddr);
310+
311+
ret = ivpu_hw_boot_fw(vdev);
312+
if (ret) {
313+
ivpu_err(vdev, "Failed to start the firmware: %d\n", ret);
314+
return ret;
315+
}
316+
317+
ret = ivpu_wait_for_ready(vdev);
318+
if (ret) {
319+
ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret);
320+
return ret;
321+
}
322+
323+
ivpu_hw_irq_clear(vdev);
324+
enable_irq(vdev->irq);
325+
ivpu_hw_irq_enable(vdev);
326+
ivpu_ipc_enable(vdev);
327+
return 0;
328+
}
329+
228330
int ivpu_shutdown(struct ivpu_device *vdev)
229331
{
230332
int ret;
231333

232334
ivpu_hw_irq_disable(vdev);
335+
disable_irq(vdev->irq);
233336
ivpu_ipc_disable(vdev);
234337
ivpu_mmu_disable(vdev);
235338

@@ -341,6 +444,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
341444
if (!vdev->mmu)
342445
return -ENOMEM;
343446

447+
vdev->fw = drmm_kzalloc(&vdev->drm, sizeof(*vdev->fw), GFP_KERNEL);
448+
if (!vdev->fw)
449+
return -ENOMEM;
450+
344451
vdev->ipc = drmm_kzalloc(&vdev->drm, sizeof(*vdev->ipc), GFP_KERNEL);
345452
if (!vdev->ipc)
346453
return -ENOMEM;
@@ -349,6 +456,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
349456
vdev->platform = IVPU_PLATFORM_INVALID;
350457
vdev->context_xa_limit.min = IVPU_GLOBAL_CONTEXT_MMU_SSID + 1;
351458
vdev->context_xa_limit.max = IVPU_CONTEXT_LIMIT;
459+
atomic64_set(&vdev->unique_id_counter, 0);
352460
xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC);
353461

354462
ret = ivpu_pci_init(vdev);
@@ -389,14 +497,34 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
389497
goto err_mmu_gctx_fini;
390498
}
391499

500+
ret = ivpu_fw_init(vdev);
501+
if (ret) {
502+
ivpu_err(vdev, "Failed to initialize firmware: %d\n", ret);
503+
goto err_mmu_gctx_fini;
504+
}
505+
392506
ret = ivpu_ipc_init(vdev);
393507
if (ret) {
394508
ivpu_err(vdev, "Failed to initialize IPC: %d\n", ret);
395-
goto err_mmu_gctx_fini;
509+
goto err_fw_fini;
510+
}
511+
512+
ret = ivpu_fw_load(vdev);
513+
if (ret) {
514+
ivpu_err(vdev, "Failed to load firmware: %d\n", ret);
515+
goto err_fw_fini;
516+
}
517+
518+
ret = ivpu_boot(vdev);
519+
if (ret) {
520+
ivpu_err(vdev, "Failed to boot: %d\n", ret);
521+
goto err_fw_fini;
396522
}
397523

398524
return 0;
399525

526+
err_fw_fini:
527+
ivpu_fw_fini(vdev);
400528
err_mmu_gctx_fini:
401529
ivpu_mmu_global_context_fini(vdev);
402530
err_power_down:
@@ -410,6 +538,7 @@ static void ivpu_dev_fini(struct ivpu_device *vdev)
410538
{
411539
ivpu_shutdown(vdev);
412540
ivpu_ipc_fini(vdev);
541+
ivpu_fw_fini(vdev);
413542
ivpu_mmu_global_context_fini(vdev);
414543

415544
drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->context_xa));

drivers/accel/ivpu/ivpu_drv.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct ivpu_wa_table {
7474

7575
struct ivpu_hw_info;
7676
struct ivpu_mmu_info;
77+
struct ivpu_fw_info;
7778
struct ivpu_ipc_info;
7879

7980
struct ivpu_device {
@@ -86,12 +87,15 @@ struct ivpu_device {
8687
struct ivpu_wa_table wa;
8788
struct ivpu_hw_info *hw;
8889
struct ivpu_mmu_info *mmu;
90+
struct ivpu_fw_info *fw;
8991
struct ivpu_ipc_info *ipc;
9092

9193
struct ivpu_mmu_context gctx;
9294
struct xarray context_xa;
9395
struct xa_limit context_xa_limit;
9496

97+
atomic64_t unique_id_counter;
98+
9599
struct {
96100
int boot;
97101
int jsm;
@@ -116,9 +120,16 @@ extern int ivpu_dbg_mask;
116120
extern u8 ivpu_pll_min_ratio;
117121
extern u8 ivpu_pll_max_ratio;
118122

123+
#define IVPU_TEST_MODE_DISABLED 0
124+
#define IVPU_TEST_MODE_FW_TEST 1
125+
#define IVPU_TEST_MODE_NULL_HW 2
126+
extern int ivpu_test_mode;
127+
119128
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv);
120129
struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id);
121130
void ivpu_file_priv_put(struct ivpu_file_priv **link);
131+
132+
int ivpu_boot(struct ivpu_device *vdev);
122133
int ivpu_shutdown(struct ivpu_device *vdev);
123134

124135
static inline bool ivpu_is_mtl(struct ivpu_device *vdev)

0 commit comments

Comments
 (0)