accel/ivpu: Add auto selection logic for job scheduler
authorJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Mon, 30 Sep 2024 19:53:07 +0000 (21:53 +0200)
committerJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Fri, 11 Oct 2024 10:44:38 +0000 (12:44 +0200)
Add ivpu_fw_sched_mode_select() function that can select scheduling mode
based on HW and FW versions. This prepares for a switch to HWS on
selected platforms.

Reviewed-by: Karol Wachowski <karol.wachowski@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240930195322.461209-17-jacek.lawrynowicz@linux.intel.com
Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
drivers/accel/ivpu/ivpu_drv.c
drivers/accel/ivpu/ivpu_drv.h
drivers/accel/ivpu/ivpu_fw.c
drivers/accel/ivpu/ivpu_fw.h
drivers/accel/ivpu/ivpu_hw.h
drivers/accel/ivpu/ivpu_hw_btrs.c
drivers/accel/ivpu/ivpu_job.c
drivers/accel/ivpu/ivpu_sysfs.c

index 9fd371a..fcf26e6 100644 (file)
@@ -54,9 +54,9 @@ u8 ivpu_pll_max_ratio = U8_MAX;
 module_param_named(pll_max_ratio, ivpu_pll_max_ratio, byte, 0644);
 MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set NPU frequency");
 
-int ivpu_sched_mode;
+int ivpu_sched_mode = IVPU_SCHED_MODE_AUTO;
 module_param_named(sched_mode, ivpu_sched_mode, int, 0444);
-MODULE_PARM_DESC(sched_mode, "Scheduler mode: 0 - Default scheduler, 1 - Force HW scheduler");
+MODULE_PARM_DESC(sched_mode, "Scheduler mode: -1 - Use default scheduler, 0 - Use OS scheduler, 1 - Use HW scheduler");
 
 bool ivpu_disable_mmu_cont_pages;
 module_param_named(disable_mmu_cont_pages, ivpu_disable_mmu_cont_pages, bool, 0444);
@@ -347,7 +347,7 @@ static int ivpu_hw_sched_init(struct ivpu_device *vdev)
 {
        int ret = 0;
 
-       if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) {
+       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
                ret = ivpu_jsm_hws_setup_priority_bands(vdev);
                if (ret) {
                        ivpu_err(vdev, "Failed to enable hw scheduler: %d", ret);
index 4714782..c4bd875 100644 (file)
@@ -56,6 +56,8 @@
 #define IVPU_PLATFORM_FPGA    3
 #define IVPU_PLATFORM_INVALID 8
 
+#define IVPU_SCHED_MODE_AUTO -1
+
 #define IVPU_DBG_REG    BIT(0)
 #define IVPU_DBG_IRQ    BIT(1)
 #define IVPU_DBG_MMU    BIT(2)
index 7e8593c..4d59dd1 100644 (file)
@@ -134,6 +134,15 @@ static bool is_within_range(u64 addr, size_t size, u64 range_start, size_t range
        return true;
 }
 
+static u32
+ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr)
+{
+       if (ivpu_sched_mode != IVPU_SCHED_MODE_AUTO)
+               return ivpu_sched_mode;
+
+       return VPU_SCHEDULING_MODE_OS;
+}
+
 static int ivpu_fw_parse(struct ivpu_device *vdev)
 {
        struct ivpu_fw_info *fw = vdev->fw;
@@ -215,8 +224,10 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
 
        fw->dvfs_mode = 0;
 
+       fw->sched_mode = ivpu_fw_sched_mode_select(vdev, fw_hdr);
        fw->primary_preempt_buf_size = fw_hdr->preemption_buffer_1_size;
        fw->secondary_preempt_buf_size = fw_hdr->preemption_buffer_2_size;
+       ivpu_info(vdev, "Scheduler mode: %s\n", fw->sched_mode ? "HW" : "OS");
 
        if (fw_hdr->ro_section_start_address && !is_within_range(fw_hdr->ro_section_start_address,
                                                                 fw_hdr->ro_section_size,
@@ -605,8 +616,8 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
        boot_params->punit_telemetry_sram_base = ivpu_hw_telemetry_offset_get(vdev);
        boot_params->punit_telemetry_sram_size = ivpu_hw_telemetry_size_get(vdev);
        boot_params->vpu_telemetry_enable = ivpu_hw_telemetry_enable_get(vdev);
-       boot_params->vpu_scheduling_mode = vdev->hw->sched_mode;
-       if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW)
+       boot_params->vpu_scheduling_mode = vdev->fw->sched_mode;
+       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
                boot_params->vpu_focus_present_timer_ms = IVPU_FOCUS_PRESENT_TIMER_MS;
        boot_params->dvfs_mode = vdev->fw->dvfs_mode;
        if (!IVPU_WA(disable_d0i3_msg))
index 5e8eb60..1d0b2bd 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef __IVPU_FW_H__
 #define __IVPU_FW_H__
 
+#include "vpu_jsm_api.h"
+
 #define FW_VERSION_HEADER_SIZE SZ_4K
 #define FW_VERSION_STR_SIZE    SZ_256
 
@@ -36,6 +38,7 @@ struct ivpu_fw_info {
        u32 secondary_preempt_buf_size;
        u64 read_only_addr;
        u32 read_only_size;
+       u32 sched_mode;
 };
 
 int ivpu_fw_init(struct ivpu_device *vdev);
index 1c0c98e..dc55182 100644 (file)
@@ -46,7 +46,6 @@ struct ivpu_hw_info {
                u32 profiling_freq;
        } pll;
        u32 tile_fuse;
-       u32 sched_mode;
        u32 sku;
        u16 config;
        int dma_bits;
index cad2ce7..7dc8e33 100644 (file)
@@ -163,7 +163,6 @@ static int info_init_mtl(struct ivpu_device *vdev)
        hw->tile_fuse = BTRS_MTL_TILE_FUSE_ENABLE_BOTH;
        hw->sku = BTRS_MTL_TILE_SKU_BOTH;
        hw->config = BTRS_MTL_WP_CONFIG_2_TILE_4_3_RATIO;
-       hw->sched_mode = ivpu_sched_mode;
 
        return 0;
 }
@@ -178,7 +177,6 @@ static int info_init_lnl(struct ivpu_device *vdev)
        if (ret)
                return ret;
 
-       hw->sched_mode = ivpu_sched_mode;
        hw->tile_fuse = tile_fuse_config;
        hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT;
 
index b00634a..b1abdca 100644 (file)
@@ -37,7 +37,7 @@ static int ivpu_preemption_buffers_create(struct ivpu_device *vdev,
        u64 secondary_size = ALIGN(vdev->fw->secondary_preempt_buf_size, PAGE_SIZE);
        struct ivpu_addr_range range;
 
-       if (vdev->hw->sched_mode != VPU_SCHEDULING_MODE_HW)
+       if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW)
                return 0;
 
        range.start = vdev->hw->ranges.user.end - (primary_size * IVPU_NUM_CMDQS_PER_CTX);
@@ -68,7 +68,7 @@ err_free_primary:
 static void ivpu_preemption_buffers_free(struct ivpu_device *vdev,
                                         struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
 {
-       if (vdev->hw->sched_mode != VPU_SCHEDULING_MODE_HW)
+       if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW)
                return;
 
        drm_WARN_ON(&vdev->drm, !cmdq->primary_preempt_buf);
@@ -149,7 +149,7 @@ static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *
        struct ivpu_device *vdev = file_priv->vdev;
        int ret;
 
-       if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW)
+       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
                ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, cmdq->db_id, cmdq->db_id,
                                               cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem));
        else
@@ -184,7 +184,7 @@ ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u16 eng
        jobq_header->tail = 0;
        wmb(); /* Flush WC buffer for jobq->header */
 
-       if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) {
+       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
                ret = ivpu_hws_cmdq_init(file_priv, cmdq, engine, priority);
                if (ret)
                        return ret;
@@ -211,7 +211,7 @@ static int ivpu_cmdq_fini(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cm
 
        cmdq->db_registered = false;
 
-       if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) {
+       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
                ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->db_id);
                if (!ret)
                        ivpu_dbg(vdev, JOB, "Command queue %d destroyed\n", cmdq->db_id);
@@ -335,7 +335,7 @@ void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv)
 
        ivpu_cmdq_fini_all(file_priv);
 
-       if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_OS)
+       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_OS)
                ivpu_jsm_context_release(vdev, file_priv->ctx.id);
 }
 
@@ -361,7 +361,7 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job)
        if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION))
                entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK;
 
-       if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW &&
+       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW &&
            (unlikely(!(ivpu_test_mode & IVPU_TEST_MODE_PREEMPTION_DISABLE)))) {
                entry->primary_preempt_buf_addr = cmdq->primary_preempt_buf->vpu_addr;
                entry->primary_preempt_buf_size = ivpu_bo_size(cmdq->primary_preempt_buf);
index 913669f..616477f 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/device.h>
 #include <linux/err.h>
 
+#include "ivpu_drv.h"
+#include "ivpu_fw.h"
 #include "ivpu_hw.h"
 #include "ivpu_sysfs.h"
 
@@ -39,8 +41,30 @@ npu_busy_time_us_show(struct device *dev, struct device_attribute *attr, char *b
 
 static DEVICE_ATTR_RO(npu_busy_time_us);
 
+/**
+ * DOC: sched_mode
+ *
+ * The sched_mode is used to report current NPU scheduling mode.
+ *
+ * It returns following strings:
+ * - "HW"              - Hardware Scheduler mode
+ * - "OS"              - Operating System Scheduler mode
+ *
+ */
+static ssize_t
+sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct drm_device *drm = dev_get_drvdata(dev);
+       struct ivpu_device *vdev = to_ivpu_device(drm);
+
+       return sysfs_emit(buf, "%s\n", vdev->fw->sched_mode ? "HW" : "OS");
+}
+
+static DEVICE_ATTR_RO(sched_mode);
+
 static struct attribute *ivpu_dev_attrs[] = {
        &dev_attr_npu_busy_time_us.attr,
+       &dev_attr_sched_mode.attr,
        NULL,
 };