diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-01-16 11:03:44 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-01-16 11:04:03 +1000 |
| commit | 37b812b7fdc2f1c7cb9e22c888776be7347097b0 (patch) | |
| tree | a7584e45073dbf7f8da5d1a44835fbcc50b2ca52 /drivers/accel | |
| parent | 83dc0ba2755296b5e5882e044c80973b7c3fce9e (diff) | |
| parent | b36178488d479e9a53bbef2b01280378b5586e60 (diff) | |
| download | linux-37b812b7fdc2f1c7cb9e22c888776be7347097b0.tar.gz linux-37b812b7fdc2f1c7cb9e22c888776be7347097b0.tar.bz2 linux-37b812b7fdc2f1c7cb9e22c888776be7347097b0.zip | |
Merge tag 'drm-misc-next-2026-01-15' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for 6.20:
Core Changes:
- atomic: Introduce Gamma/Degamma LUT size check
- gem: Fix a leak in drm_gem_get_unmapped_area
- gpuvm: API sanitation for Rust bindings
- panic: Few corner-cases fixes
Driver Changes:
- Replace system workqueue with percpu equivalent
- amdxdna: Update message buffer allocation requirements, Update
firmware version check
- imagination: Add AM62P support
- ivpu: Implement warm boot flow
- rockchip: Get rid of atomic_check fixups, Add Rockchip RK3506 Support
- rocket: Cleanups
- bridge:
- dw-hdmi-qp: Add support for HPD-less setups
- panel:
- mantix: Various power management related improvements
- new panels: Innolux G150XGE-L05,
- dma-buf:
- cma: Call clear_page instead of memset
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20260115-lilac-dragon-of-opposition-ac0a30@houat
Diffstat (limited to 'drivers/accel')
| -rw-r--r-- | drivers/accel/amdxdna/aie2_error.c | 10 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/aie2_message.c | 33 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/aie2_pci.c | 36 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/aie2_pci.h | 10 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_pci_drv.c | 2 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/npu1_regs.c | 6 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/npu4_regs.c | 11 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/npu5_regs.c | 2 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/npu6_regs.c | 2 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_debugfs.c | 4 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_drv.c | 4 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_fw.c | 13 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_fw.h | 9 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_hw_40xx_reg.h | 6 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_hw_ip.c | 74 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_hw_ip.h | 1 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_pm.c | 13 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_pm.h | 1 | ||||
| -rw-r--r-- | drivers/accel/rocket/rocket_core.c | 7 | ||||
| -rw-r--r-- | drivers/accel/rocket/rocket_drv.c | 30 |
20 files changed, 163 insertions, 111 deletions
diff --git a/drivers/accel/amdxdna/aie2_error.c b/drivers/accel/amdxdna/aie2_error.c index d452008ec4f4..5e82df2b7cf6 100644 --- a/drivers/accel/amdxdna/aie2_error.c +++ b/drivers/accel/amdxdna/aie2_error.c @@ -338,8 +338,7 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev) destroy_workqueue(events->wq); mutex_lock(&xdna->dev_lock); - dma_free_noncoherent(xdna->ddev.dev, events->size, events->buf, - events->addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr); kfree(events); } @@ -355,8 +354,8 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) if (!events) return -ENOMEM; - events->buf = dma_alloc_noncoherent(xdna->ddev.dev, total_size, &events->addr, - DMA_FROM_DEVICE, GFP_KERNEL); + events->buf = aie2_alloc_msg_buffer(ndev, &total_size, &events->addr); + if (!events->buf) { ret = -ENOMEM; goto free_events; @@ -396,8 +395,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) free_wq: destroy_workqueue(events->wq); free_buf: - dma_free_noncoherent(xdna->ddev.dev, events->size, events->buf, - events->addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr); free_events: kfree(events); return ret; diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index 051f4ceaabae..99215328505e 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -55,6 +55,22 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev, return ret; } +void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, + dma_addr_t *dma_addr) +{ + struct amdxdna_dev *xdna = ndev->xdna; + int order; + + *size = max(*size, SZ_8K); + order = get_order(*size); + if (order > MAX_PAGE_ORDER) + return NULL; + *size = PAGE_SIZE << order; + + return dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, + DMA_FROM_DEVICE, GFP_KERNEL); +} + int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) { DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND); @@ -346,14 +362,13 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, { DECLARE_AIE2_MSG(aie_column_info, MSG_OP_QUERY_COL_STATUS); struct amdxdna_dev *xdna = ndev->xdna; + u32 buf_sz = size, aie_bitmap = 0; struct amdxdna_client *client; dma_addr_t dma_addr; - u32 aie_bitmap = 0; u8 *buff_addr; int ret; - buff_addr = dma_alloc_noncoherent(xdna->ddev.dev, size, &dma_addr, - DMA_FROM_DEVICE, GFP_KERNEL); + buff_addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); if (!buff_addr) return -ENOMEM; @@ -363,7 +378,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, *cols_filled = 0; req.dump_buff_addr = dma_addr; - req.dump_buff_size = size; + req.dump_buff_size = buf_sz; req.num_cols = hweight32(aie_bitmap); req.aie_bitmap = aie_bitmap; @@ -391,7 +406,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, *cols_filled = aie_bitmap; fail: - dma_free_noncoherent(xdna->ddev.dev, size, buff_addr, dma_addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, buf_sz, buff_addr, dma_addr); return ret; } @@ -402,19 +417,19 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, DECLARE_AIE2_MSG(get_telemetry, MSG_OP_GET_TELEMETRY); struct amdxdna_dev *xdna = ndev->xdna; dma_addr_t dma_addr; + u32 buf_sz = size; u8 *addr; int ret; if (header->type >= MAX_TELEMETRY_TYPE) return -EINVAL; - addr = dma_alloc_noncoherent(xdna->ddev.dev, size, &dma_addr, - DMA_FROM_DEVICE, GFP_KERNEL); + addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); if (!addr) return -ENOMEM; req.buf_addr = dma_addr; - req.buf_size = size; + req.buf_size = buf_sz; req.type = header->type; drm_clflush_virt_range(addr, size); /* device can access */ @@ -440,7 +455,7 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, header->minor = resp.minor; free_buf: - dma_free_noncoherent(xdna->ddev.dev, size, addr, dma_addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, buf_sz, addr, dma_addr); return ret; } diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index ec1c3ad57d49..f70ccf0f3c01 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -57,41 +57,23 @@ struct mgmt_mbox_chann_info { static int aie2_check_protocol(struct amdxdna_dev_hdl *ndev, u32 fw_major, u32 fw_minor) { const struct aie2_fw_feature_tbl *feature; - struct amdxdna_dev *xdna = ndev->xdna; - - /* - * The driver supported mailbox behavior is defined by - * ndev->priv->protocol_major and protocol_minor. - * - * When protocol_major and fw_major are different, it means driver - * and firmware are incompatible. - */ - if (ndev->priv->protocol_major != fw_major) { - XDNA_ERR(xdna, "Incompatible firmware protocol major %d minor %d", - fw_major, fw_minor); - return -EINVAL; - } + bool found = false; - /* - * When protocol_minor is greater then fw_minor, that means driver - * relies on operation the installed firmware does not support. - */ - if (ndev->priv->protocol_minor > fw_minor) { - XDNA_ERR(xdna, "Firmware minor version smaller than supported"); - return -EINVAL; - } - - for (feature = ndev->priv->fw_feature_tbl; feature && feature->min_minor; - feature++) { + for (feature = ndev->priv->fw_feature_tbl; feature->major; feature++) { + if (feature->major != fw_major) + continue; if (fw_minor < feature->min_minor) continue; if (feature->max_minor > 0 && fw_minor > feature->max_minor) continue; - set_bit(feature->feature, &ndev->feature_mask); + ndev->feature_mask |= feature->features; + + /* firmware version matches one of the driver support entry */ + found = true; } - return 0; + return found ? 0 : -EOPNOTSUPP; } static void aie2_dump_chann_info_debug(struct amdxdna_dev_hdl *ndev) diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index a929fa98a121..b20a3661078c 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -237,7 +237,8 @@ enum aie2_fw_feature { }; struct aie2_fw_feature_tbl { - enum aie2_fw_feature feature; + u64 features; + u32 major; u32 max_minor; u32 min_minor; }; @@ -246,8 +247,6 @@ struct aie2_fw_feature_tbl { struct amdxdna_dev_priv { const char *fw_path; - u64 protocol_major; - u64 protocol_minor; const struct rt_config *rt_config; const struct dpm_clk_freq *dpm_clk_tbl; const struct aie2_fw_feature_tbl *fw_feature_tbl; @@ -336,6 +335,11 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, int (*notify_cb)(void *, void __iomem *, size_t)); int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, int (*notify_cb)(void *, void __iomem *, size_t)); +void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, + dma_addr_t *dma_addr); +#define aie2_free_msg_buffer(ndev, size, buff_addr, dma_addr) \ + dma_free_noncoherent((ndev)->xdna->ddev.dev, size, buff_addr, \ + dma_addr, DMA_FROM_DEVICE) /* aie2_hwctx.c */ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx); diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index 7d59764d7869..45f5c12fc67f 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -275,7 +275,7 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) fs_reclaim_release(GFP_KERNEL); } - xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", 0); + xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM); if (!xdna->notifier_wq) return -ENOMEM; diff --git a/drivers/accel/amdxdna/npu1_regs.c b/drivers/accel/amdxdna/npu1_regs.c index ebc6e2802297..6f36a27b5a02 100644 --- a/drivers/accel/amdxdna/npu1_regs.c +++ b/drivers/accel/amdxdna/npu1_regs.c @@ -6,6 +6,7 @@ #include <drm/amdxdna_accel.h> #include <drm/drm_device.h> #include <drm/gpu_scheduler.h> +#include <linux/bits.h> #include <linux/sizes.h> #include "aie2_pci.h" @@ -65,14 +66,13 @@ const struct dpm_clk_freq npu1_dpm_clk_table[] = { }; static const struct aie2_fw_feature_tbl npu1_fw_feature_table[] = { - { .feature = AIE2_NPU_COMMAND, .min_minor = 8 }, + { .major = 5, .min_minor = 7 }, + { .features = BIT_U64(AIE2_NPU_COMMAND), .min_minor = 8 }, { 0 } }; static const struct amdxdna_dev_priv npu1_dev_priv = { .fw_path = "amdnpu/1502_00/npu.sbin", - .protocol_major = 0x5, - .protocol_minor = 0x7, .rt_config = npu1_default_rt_cfg, .dpm_clk_tbl = npu1_dpm_clk_table, .fw_feature_tbl = npu1_fw_feature_table, diff --git a/drivers/accel/amdxdna/npu4_regs.c b/drivers/accel/amdxdna/npu4_regs.c index a62234fd266d..a8d6f76dde5f 100644 --- a/drivers/accel/amdxdna/npu4_regs.c +++ b/drivers/accel/amdxdna/npu4_regs.c @@ -6,6 +6,7 @@ #include <drm/amdxdna_accel.h> #include <drm/drm_device.h> #include <drm/gpu_scheduler.h> +#include <linux/bits.h> #include <linux/sizes.h> #include "aie2_pci.h" @@ -88,16 +89,16 @@ const struct dpm_clk_freq npu4_dpm_clk_table[] = { }; const struct aie2_fw_feature_tbl npu4_fw_feature_table[] = { - { .feature = AIE2_NPU_COMMAND, .min_minor = 15 }, - { .feature = AIE2_PREEMPT, .min_minor = 12 }, - { .feature = AIE2_TEMPORAL_ONLY, .min_minor = 12 }, + { .major = 6, .min_minor = 12 }, + { .features = BIT_U64(AIE2_NPU_COMMAND), .major = 6, .min_minor = 15 }, + { .features = BIT_U64(AIE2_PREEMPT), .major = 6, .min_minor = 12 }, + { .features = BIT_U64(AIE2_TEMPORAL_ONLY), .major = 6, .min_minor = 12 }, + { .features = GENMASK_ULL(AIE2_TEMPORAL_ONLY, AIE2_NPU_COMMAND), .major = 7 }, { 0 } }; static const struct amdxdna_dev_priv npu4_dev_priv = { .fw_path = "amdnpu/17f0_10/npu.sbin", - .protocol_major = 0x6, - .protocol_minor = 12, .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .fw_feature_tbl = npu4_fw_feature_table, diff --git a/drivers/accel/amdxdna/npu5_regs.c b/drivers/accel/amdxdna/npu5_regs.c index 131080652ef0..c0a35cfd886c 100644 --- a/drivers/accel/amdxdna/npu5_regs.c +++ b/drivers/accel/amdxdna/npu5_regs.c @@ -64,8 +64,6 @@ static const struct amdxdna_dev_priv npu5_dev_priv = { .fw_path = "amdnpu/17f0_11/npu.sbin", - .protocol_major = 0x6, - .protocol_minor = 12, .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .fw_feature_tbl = npu4_fw_feature_table, diff --git a/drivers/accel/amdxdna/npu6_regs.c b/drivers/accel/amdxdna/npu6_regs.c index 1f71285655b2..1fb07df99186 100644 --- a/drivers/accel/amdxdna/npu6_regs.c +++ b/drivers/accel/amdxdna/npu6_regs.c @@ -64,8 +64,6 @@ static const struct amdxdna_dev_priv npu6_dev_priv = { .fw_path = "amdnpu/17f0_10/npu.sbin", - .protocol_major = 0x6, - .protocol_minor = 12, .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .fw_feature_tbl = npu4_fw_feature_table, diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 3bd85ee6c26b..a09f54fc4302 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -20,6 +20,7 @@ #include "ivpu_hw.h" #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" +#include "vpu_boot_api.h" static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s) { @@ -96,7 +97,8 @@ static int last_bootmode_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = seq_to_ivpu(s); - seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot"); + seq_printf(s, "%s\n", (vdev->fw->last_boot_mode == VPU_BOOT_TYPE_WARMBOOT) ? + "warm boot" : "cold boot"); return 0; } diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 3d6fccdefdd6..8ffda57459df 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -384,6 +384,7 @@ int ivpu_boot(struct ivpu_device *vdev) drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem_bp)); + vdev->fw->last_boot_mode = vdev->fw->next_boot_mode; ret = ivpu_hw_boot_fw(vdev); if (ret) { @@ -396,13 +397,12 @@ int ivpu_boot(struct ivpu_device *vdev) ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret); goto err_diagnose_failure; } - ivpu_hw_irq_clear(vdev); enable_irq(vdev->irq); ivpu_hw_irq_enable(vdev); ivpu_ipc_enable(vdev); - if (ivpu_fw_is_cold_boot(vdev)) { + if (!ivpu_fw_is_warm_boot(vdev)) { ret = ivpu_pm_dct_init(vdev); if (ret) goto err_disable_ipc; diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 48386d2cddbb..107f8ad31050 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -300,9 +300,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->image_load_offset = image_load_addr - runtime_addr; fw->image_size = image_size; fw->shave_nn_size = PAGE_ALIGN(fw_hdr->shave_nn_fw_size); - fw->cold_boot_entry_point = fw_hdr->entry_point; - fw->entry_point = fw->cold_boot_entry_point; fw->trace_level = min_t(u32, ivpu_fw_log_level, IVPU_FW_LOG_FATAL); fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; @@ -338,7 +336,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->image_load_offset, fw->image_size); ivpu_dbg(vdev, FW_BOOT, "Read-only section: address 0x%llx, size %u\n", fw->read_only_addr, fw->read_only_size); - ivpu_dbg(vdev, FW_BOOT, "FW entry point: 0x%llx\n", fw->entry_point); + ivpu_dbg(vdev, FW_BOOT, "FW cold boot entry point: 0x%llx\n", fw->cold_boot_entry_point); ivpu_dbg(vdev, FW_BOOT, "SHAVE NN size: %u\n", fw->shave_nn_size); return 0; @@ -616,6 +614,7 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->power_profile); ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_uses_ecc_mca_signal = 0x%x\n", boot_params->vpu_uses_ecc_mca_signal); + ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) @@ -623,7 +622,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx; /* In case of warm boot only update variable params */ - if (!ivpu_fw_is_cold_boot(vdev)) { + if (ivpu_fw_is_warm_boot(vdev)) { boot_params->d0i3_residency_time_us = ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts); boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts; @@ -635,16 +634,16 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->d0i3_entry_vpu_ts); ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n", boot_params->system_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type); boot_params->save_restore_ret_address = 0; - vdev->pm->is_warmboot = true; + boot_params->boot_type = VPU_BOOT_TYPE_WARMBOOT; wmb(); /* Flush WC buffers after writing save_restore_ret_address */ return; } memset(boot_params, 0, sizeof(*boot_params)); - vdev->pm->is_warmboot = false; - + boot_params->boot_type = VPU_BOOT_TYPE_COLDBOOT; boot_params->magic = VPU_BOOT_PARAMS_MAGIC; boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number; diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 00945892b55e..d3c410912c9c 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -6,6 +6,7 @@ #ifndef __IVPU_FW_H__ #define __IVPU_FW_H__ +#include "vpu_boot_api.h" #include "vpu_jsm_api.h" #define FW_VERSION_HEADER_SIZE SZ_4K @@ -34,8 +35,10 @@ struct ivpu_fw_info { u64 image_load_offset; u32 image_size; u32 shave_nn_size; - u64 entry_point; /* Cold or warm boot entry point for next boot */ + u64 warm_boot_entry_point; u64 cold_boot_entry_point; + u8 last_boot_mode; + u8 next_boot_mode; u32 trace_level; u32 trace_destination_mask; u64 trace_hw_component_mask; @@ -54,9 +57,9 @@ void ivpu_fw_fini(struct ivpu_device *vdev); void ivpu_fw_load(struct ivpu_device *vdev); void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params); -static inline bool ivpu_fw_is_cold_boot(struct ivpu_device *vdev) +static inline bool ivpu_fw_is_warm_boot(struct ivpu_device *vdev) { - return vdev->fw->entry_point == vdev->fw->cold_boot_entry_point; + return vdev->fw->next_boot_mode == VPU_BOOT_TYPE_WARMBOOT; } static inline u32 ivpu_fw_preempt_buf_size(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h index fc0ee8d637f9..421242acb184 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h @@ -121,6 +121,12 @@ #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0) +#define VPU_40XX_HOST_SS_AON_RETENTION0 0x0003000cu +#define VPU_40XX_HOST_SS_AON_RETENTION1 0x00030010u +#define VPU_40XX_HOST_SS_AON_RETENTION2 0x00030014u +#define VPU_40XX_HOST_SS_AON_RETENTION3 0x00030018u +#define VPU_40XX_HOST_SS_AON_RETENTION4 0x0003001cu + #define VPU_40XX_HOST_SS_AON_IDLE_GEN 0x00030200u #define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK BIT_MASK(0) #define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1) diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c index 06aa1e7dc50b..959984c54341 100644 --- a/drivers/accel/ivpu/ivpu_hw_ip.c +++ b/drivers/accel/ivpu/ivpu_hw_ip.c @@ -5,6 +5,7 @@ #include "ivpu_drv.h" #include "ivpu_fw.h" +#include "ivpu_gem.h" #include "ivpu_hw.h" #include "ivpu_hw_37xx_reg.h" #include "ivpu_hw_40xx_reg.h" @@ -816,6 +817,14 @@ void ivpu_hw_ip_tbu_mmu_enable(struct ivpu_device *vdev) return ivpu_hw_ip_tbu_mmu_enable_40xx(vdev); } +static inline u64 get_entry_point_addr(struct ivpu_device *vdev) +{ + if (ivpu_fw_is_warm_boot(vdev)) + return vdev->fw->warm_boot_entry_point; + else + return vdev->fw->cold_boot_entry_point; +} + static int soc_cpu_boot_37xx(struct ivpu_device *vdev) { u32 val; @@ -832,15 +841,12 @@ static int soc_cpu_boot_37xx(struct ivpu_device *vdev) val = REG_CLR_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val); REGV_WR32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); - val = vdev->fw->entry_point >> 9; + val = get_entry_point_addr(vdev) >> 9; REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val); val = REG_SET_FLD(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, DONE, val); REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val); - ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n", - vdev->fw->entry_point == vdev->fw->cold_boot_entry_point ? "cold boot" : "resume"); - return 0; } @@ -894,46 +900,68 @@ static int soc_cpu_drive_40xx(struct ivpu_device *vdev, bool enable) return ret; } -static int soc_cpu_enable(struct ivpu_device *vdev) +static void soc_cpu_set_entry_point_40xx(struct ivpu_device *vdev, u64 entry_point) { - if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX) - return 0; + u64 val64; + u32 val; + + val64 = entry_point; + val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1; + REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64); - return soc_cpu_drive_40xx(vdev, true); + val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO); + val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val); + REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val); } static int soc_cpu_boot_40xx(struct ivpu_device *vdev) { int ret; - u32 val; - u64 val64; - ret = soc_cpu_enable(vdev); + ret = soc_cpu_drive_40xx(vdev, true); if (ret) { ivpu_err(vdev, "Failed to enable SOC CPU: %d\n", ret); return ret; } - val64 = vdev->fw->entry_point; - val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1; - REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64); + soc_cpu_set_entry_point_40xx(vdev, get_entry_point_addr(vdev)); - val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO); - val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val); - REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val); + return 0; +} - ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n", - ivpu_fw_is_cold_boot(vdev) ? "cold boot" : "resume"); +static int soc_cpu_boot_60xx(struct ivpu_device *vdev) +{ + REGV_WR64(VPU_40XX_HOST_SS_AON_RETENTION1, vdev->fw->mem_bp->vpu_addr); + soc_cpu_set_entry_point_40xx(vdev, vdev->fw->cold_boot_entry_point); return 0; } int ivpu_hw_ip_soc_cpu_boot(struct ivpu_device *vdev) { - if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) - return soc_cpu_boot_37xx(vdev); - else - return soc_cpu_boot_40xx(vdev); + int ret; + + switch (ivpu_hw_ip_gen(vdev)) { + case IVPU_HW_IP_37XX: + ret = soc_cpu_boot_37xx(vdev); + break; + + case IVPU_HW_IP_40XX: + case IVPU_HW_IP_50XX: + ret = soc_cpu_boot_40xx(vdev); + break; + + default: + ret = soc_cpu_boot_60xx(vdev); + } + + if (ret) + return ret; + + ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n", + ivpu_fw_is_warm_boot(vdev) ? "warm boot" : "cold boot"); + + return 0; } static void wdt_disable_37xx(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_hw_ip.h b/drivers/accel/ivpu/ivpu_hw_ip.h index 5b1b391aa577..dbbcdd10a5f8 100644 --- a/drivers/accel/ivpu/ivpu_hw_ip.h +++ b/drivers/accel/ivpu/ivpu_hw_ip.h @@ -29,7 +29,6 @@ u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev); void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr); void ivpu_hw_ip_irq_enable(struct ivpu_device *vdev); void ivpu_hw_ip_irq_disable(struct ivpu_device *vdev); -void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev); void ivpu_hw_ip_fabric_req_override_enable_50xx(struct ivpu_device *vdev); void ivpu_hw_ip_fabric_req_override_disable_50xx(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 480c075d87f6..d20144a21e09 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -47,8 +47,10 @@ static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev) ivpu_ipc_reset(vdev); ivpu_fw_log_reset(vdev); ivpu_fw_load(vdev); - fw->entry_point = fw->cold_boot_entry_point; fw->last_heartbeat = 0; + + ivpu_dbg(vdev, FW_BOOT, "Cold boot entry point 0x%llx", vdev->fw->cold_boot_entry_point); + fw->next_boot_mode = VPU_BOOT_TYPE_COLDBOOT; } static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev) @@ -56,13 +58,14 @@ static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev) struct ivpu_fw_info *fw = vdev->fw; struct vpu_boot_params *bp = ivpu_bo_vaddr(fw->mem_bp); - if (!bp->save_restore_ret_address) { + fw->warm_boot_entry_point = bp->save_restore_ret_address; + if (!fw->warm_boot_entry_point) { ivpu_pm_prepare_cold_boot(vdev); return; } - ivpu_dbg(vdev, FW_BOOT, "Save/restore entry point %llx", bp->save_restore_ret_address); - fw->entry_point = bp->save_restore_ret_address; + ivpu_dbg(vdev, FW_BOOT, "Warm boot entry point 0x%llx", fw->warm_boot_entry_point); + fw->next_boot_mode = VPU_BOOT_TYPE_WARMBOOT; } static int ivpu_suspend(struct ivpu_device *vdev) @@ -110,7 +113,7 @@ err_power_down: ivpu_hw_power_down(vdev); pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); - if (!ivpu_fw_is_cold_boot(vdev)) { + if (ivpu_fw_is_warm_boot(vdev)) { ivpu_pm_prepare_cold_boot(vdev); goto retry; } else { diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index a2aa7a27f32e..00f2a01e3df6 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -18,7 +18,6 @@ struct ivpu_pm_info { struct rw_semaphore reset_lock; atomic_t reset_counter; atomic_t reset_pending; - bool is_warmboot; u8 dct_active_percent; }; diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c index abe7719c1db4..b3b2fa9ba645 100644 --- a/drivers/accel/rocket/rocket_core.c +++ b/drivers/accel/rocket/rocket_core.c @@ -59,8 +59,11 @@ int rocket_core_init(struct rocket_core *core) core->iommu_group = iommu_group_get(dev); err = rocket_job_init(core); - if (err) + if (err) { + iommu_group_put(core->iommu_group); + core->iommu_group = NULL; return err; + } pm_runtime_use_autosuspend(dev); @@ -76,7 +79,7 @@ int rocket_core_init(struct rocket_core *core) err = pm_runtime_resume_and_get(dev); if (err) { - rocket_job_fini(core); + rocket_core_fini(core); return err; } diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c index 5c0b63f0a8f0..e4cb2efeb55a 100644 --- a/drivers/accel/rocket/rocket_drv.c +++ b/drivers/accel/rocket/rocket_drv.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include "rocket_device.h" #include "rocket_drv.h" #include "rocket_gem.h" #include "rocket_job.h" @@ -158,6 +159,8 @@ static const struct drm_driver rocket_drm_driver = { static int rocket_probe(struct platform_device *pdev) { + int ret; + if (rdev == NULL) { /* First core probing, initialize DRM device. */ rdev = rocket_device_init(drm_dev, &rocket_drm_driver); @@ -177,20 +180,31 @@ static int rocket_probe(struct platform_device *pdev) rdev->num_cores++; - return rocket_core_init(&rdev->cores[core]); + ret = rocket_core_init(&rdev->cores[core]); + if (ret) { + rdev->num_cores--; + + if (rdev->num_cores == 0) { + rocket_device_fini(rdev); + rdev = NULL; + } + } + + return ret; } +static int find_core_for_dev |
