diff --git a/MAINTAINERS b/MAINTAINERS index 13b540f3137a..782389bd5cd3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8013,6 +8013,7 @@ F: include/uapi/drm/ivpu_accel.h DRM ACCEL DRIVER FOR ROCKCHIP NPU M: Tomeu Vizoso +R: Heiko Stuebner L: dri-devel@lists.freedesktop.org S: Supported T: git https://gitlab.freedesktop.org/drm/misc/kernel.git @@ -8574,7 +8575,7 @@ F: Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml F: drivers/gpu/drm/panel/panel-synaptics-r63353.c DRM DRIVER FOR SYNOPSYS DESIGNWARE DISPLAYPORT BRIDGE -M: Andy Yan +M: Andy Yan S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml @@ -8927,7 +8928,7 @@ F: include/linux/platform_data/shmob_drm.h DRM DRIVERS FOR ROCKCHIP M: Sandy Huang M: Heiko Stübner -M: Andy Yan +M: Andy Yan L: dri-devel@lists.freedesktop.org L: linux-rockchip@lists.infradead.org S: Maintained @@ -12879,7 +12880,7 @@ S: Maintained F: drivers/power/supply/ip5xxx_power.c INNOSILICON HDMI BRIDGE DRIVER -M: Andy Yan +M: Andy Yan L: dri-devel@lists.freedesktop.org S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git diff --git a/drivers/accel/amdxdna/Kconfig b/drivers/accel/amdxdna/Kconfig index f39d7a87296c..eddff490b4f7 100644 --- a/drivers/accel/amdxdna/Kconfig +++ b/drivers/accel/amdxdna/Kconfig @@ -6,6 +6,7 @@ config DRM_ACCEL_AMDXDNA depends on DRM_ACCEL depends on PCI && HAS_IOMEM depends on X86_64 + depends on AMD_PMF || !AMD_PMF select DRM_SCHED select DRM_GEM_SHMEM_HELPER select FW_LOADER diff --git a/drivers/accel/rocket/rocket_device.c b/drivers/accel/rocket/rocket_device.c index 46e6ee1e72c5..efd004194c1a 100644 --- a/drivers/accel/rocket/rocket_device.c +++ b/drivers/accel/rocket/rocket_device.c @@ -31,6 +31,8 @@ struct rocket_device *rocket_device_init(struct platform_device *pdev, if (of_device_is_available(core_node)) num_cores++; + rdev->max_cores = num_cores; + rdev->cores = devm_kcalloc(dev, num_cores, sizeof(*rdev->cores), GFP_KERNEL); if (!rdev->cores) return ERR_PTR(-ENOMEM); diff --git a/drivers/accel/rocket/rocket_device.h b/drivers/accel/rocket/rocket_device.h index ce662abc01d3..c62d56701069 100644 --- a/drivers/accel/rocket/rocket_device.h +++ b/drivers/accel/rocket/rocket_device.h @@ -19,6 +19,7 @@ struct rocket_device { struct rocket_core *cores; unsigned int num_cores; + unsigned int max_cores; }; struct rocket_device *rocket_device_init(struct platform_device *pdev, diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c index 8bbbce594883..5d7805c41dc3 100644 --- a/drivers/accel/rocket/rocket_drv.c +++ b/drivers/accel/rocket/rocket_drv.c @@ -165,8 +165,11 @@ static int rocket_probe(struct platform_device *pdev) /* First core probing, initialize DRM device. */ rdev = rocket_device_init(drm_dev, &rocket_drm_driver); if (IS_ERR(rdev)) { + int err = PTR_ERR(rdev); + dev_err(&pdev->dev, "failed to initialize rocket device\n"); - return PTR_ERR(rdev); + rdev = NULL; + return err; } } @@ -223,7 +226,7 @@ static int find_core_for_dev(struct device *dev) { struct rocket_device *rdev = dev_get_drvdata(dev); - for (unsigned int core = 0; core < rdev->num_cores; core++) { + for (unsigned int core = 0; core < rdev->max_cores; core++) { if (dev == rdev->cores[core].dev) return core; } diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c index f40435505818..4bc4f9c8ee40 100644 --- a/drivers/accel/rocket/rocket_job.c +++ b/drivers/accel/rocket/rocket_job.c @@ -283,7 +283,7 @@ static struct rocket_core *sched_to_core(struct rocket_device *rdev, { unsigned int core; - for (core = 0; core < rdev->num_cores; core++) { + for (core = 0; core < rdev->max_cores; core++) { if (&rdev->cores[core].sched == sched) return &rdev->cores[core]; } diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index e4f078a326a4..7efc0f0d0712 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -43,7 +43,7 @@ config UDMABUF config DMABUF_DEBUG bool "DMA-BUF debug checks" depends on DMA_SHARED_BUFFER - default y if DEBUG_KERNEL + default y if DEBUG help This option enables additional checks for DMA-BUF importers and exporters. Specifically it validates that importers do not peek at the diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 03b41f803520..ef8a61ce4b1d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1431,6 +1431,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser) int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_bo_list_entry *e; struct amdgpu_cs_parser parser; int r; @@ -1465,25 +1466,31 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) r = amdgpu_cs_patch_jobs(&parser); if (r) - goto error_fini; + goto error_free_user_pages; r = amdgpu_cs_vm_handling(&parser); if (r) - goto error_fini; + goto error_free_user_pages; r = amdgpu_cs_sync_rings(&parser); if (r) - goto error_fini; + goto error_free_user_pages; trace_amdgpu_cs_ibs(&parser); r = amdgpu_cs_submit(&parser, data); if (r) - goto error_fini; + goto error_free_user_pages; amdgpu_cs_parser_fini(&parser); return 0; +error_free_user_pages: + /* amdgpu_cs_submit() only drops the ranges once it got that far. */ + amdgpu_bo_list_for_each_userptr_entry(e, parser.bo_list) { + amdgpu_hmm_range_free(e->range); + e->range = NULL; + } error_fini: amdgpu_cs_parser_fini(&parser); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index ab7ccfaea22a..4f9b72ac5698 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -1266,7 +1266,6 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf, { struct amdgpu_device *adev = f->f_inode->i_private; int r; - ssize_t result = 0; uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data; if (size > 4096 || size & 3 || *pos & 3) @@ -1310,25 +1309,11 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf, mutex_unlock(&adev->grbm_idx_mutex); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - - while (size) { - uint32_t value; - - value = data[result >> 2]; - r = put_user(value, (uint32_t *)buf); - if (r) { - amdgpu_virt_disable_access_debugfs(adev); - goto err; - } - - result += 4; - buf += 4; - size -= 4; - } - - kfree(data); amdgpu_virt_disable_access_debugfs(adev); - return result; + + r = copy_to_user(buf, data, size) ? -EFAULT : size; + kfree(data); + return r; err: pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 165344f7197f..afd8502a2bc4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -337,11 +337,14 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, goto out_unlock; } + bo_va = amdgpu_vm_bo_find(vm, bo); + /* the fence is attached once per bo_va, so keep it for other handles */ + if (bo_va && --bo_va->ref_count) + goto out_unlock; + if (!amdgpu_vm_is_bo_always_valid(vm, bo)) amdgpu_evf_mgr_detach_fence(&fpriv->evf_mgr, bo); - - bo_va = amdgpu_vm_bo_find(vm, bo); - if (!bo_va || --bo_va->ref_count) + if (!bo_va) goto out_unlock; amdgpu_vm_bo_del(adev, bo_va); @@ -567,8 +570,10 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) { range = amdgpu_hmm_range_alloc(NULL); - if (unlikely(!range)) - return -ENOMEM; + if (unlikely(!range)) { + r = -ENOMEM; + goto release_object; + } r = amdgpu_ttm_tt_get_user_pages(bo, range); if (r) { amdgpu_hmm_range_free(range); @@ -1236,7 +1241,7 @@ int amdgpu_gem_list_handles_ioctl(struct drm_device *dev, void *data, bo_entry->alloc_flags = bo->flags & AMDGPU_GEM_CREATE_SETTABLE_MASK; bo_entry->preferred_domains = bo->preferred_domains; bo_entry->gem_handle = id; - bo_entry->alignment = bo->tbo.page_alignment; + bo_entry->alignment = (u64)bo->tbo.page_alignment << PAGE_SHIFT; if (bo->tbo.base.import_attach) bo_entry->flags |= AMDGPU_GEM_LIST_HANDLES_FLAG_IS_IMPORT; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 3838e464703c..83968886c29a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2065,14 +2065,15 @@ static int amdgpu_ttm_buffer_entity_init(struct amdgpu_gtt_mgr *mgr, int i, r, num_pages; const u64 GTT_MAX_PAGES = (AMDGPU_GTT_MAX_TRANSFER_SIZE >> PAGE_SHIFT); + if (ARRAY_SIZE(entity->gart_window_offs) < num_gart_windows) + return -EINVAL; + r = drm_sched_entity_init(&entity->base, prio, scheds, num_schedulers, NULL); if (r) return r; mutex_init(&entity->lock); - if (ARRAY_SIZE(entity->gart_window_offs) < num_gart_windows) - return -EINVAL; if (num_gart_windows == 0) return 0; @@ -2080,6 +2081,7 @@ static int amdgpu_ttm_buffer_entity_init(struct amdgpu_gtt_mgr *mgr, r = amdgpu_gtt_mgr_alloc_entries(mgr, &entity->gart_node, num_pages, DRM_MM_INSERT_BEST); if (r) { + mutex_destroy(&entity->lock); drm_sched_entity_destroy(&entity->base); return r; } @@ -2097,6 +2099,7 @@ static void amdgpu_ttm_buffer_entity_fini(struct amdgpu_gtt_mgr *mgr, struct amdgpu_ttm_buffer_entity *entity) { amdgpu_gtt_mgr_free_entries(mgr, &entity->gart_node); + mutex_destroy(&entity->lock); drm_sched_entity_destroy(&entity->base); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 9316423f9340..b3dc5dd49a64 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -980,19 +980,21 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec, { struct ttm_operation_ctx ctx = { false, false }; struct amdgpu_bo_va *bo_va; - struct amdgpu_bo *bo; + struct amdgpu_bo *bo, *tmp; int ret; spin_lock(&vm->individual_lock); - while (!list_empty(&vm->always_valid.evicted)) { - bo_va = list_first_entry(&vm->always_valid.evicted, + while (!list_empty(&vm->individual.evicted)) { + bo_va = list_first_entry(&vm->individual.evicted, struct amdgpu_bo_va, base.vm_status); + bo = bo_va->base.bo; + tmp = amdgpu_bo_ref(bo); spin_unlock(&vm->individual_lock); - bo = bo_va->base.bo; ret = drm_exec_prepare_obj(exec, &bo->tbo.base, TTM_NUM_MOVE_FENCES + 1); + amdgpu_bo_unref(&tmp); if (unlikely(ret)) return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 05cce4bde73e..c390767c9088 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -457,6 +457,9 @@ static void sdma_v3_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) else ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA1, 1); + /* Hang workaround */ + amdgpu_ring_write(ring, SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP)); + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(1) | SDMA_PKT_POLL_REGMEM_HEADER_FUNC(3)); /* == */ @@ -484,6 +487,10 @@ static void sdma_v3_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se unsigned flags) { bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT; + + /* Hang workaround */ + amdgpu_ring_write(ring, SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP)); + /* write the fence */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); amdgpu_ring_write(ring, lower_32_bits(addr)); @@ -492,7 +499,11 @@ static void sdma_v3_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se /* optionally write high bits as well */ if (write64bit) { + /* Hang workaround */ + amdgpu_ring_write(ring, SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP)); + addr += 4; + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); @@ -1033,6 +1044,9 @@ static void sdma_v3_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) uint32_t seq = ring->fence_drv.sync_seq; uint64_t addr = ring->fence_drv.gpu_addr; + /* Hang workaround */ + amdgpu_ring_write(ring, SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP)); + /* wait for idle */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(0) | @@ -1061,6 +1075,9 @@ static void sdma_v3_0_ring_emit_vm_flush(struct amdgpu_ring *ring, { amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + /* Hang workaround */ + amdgpu_ring_write(ring, SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP)); + /* wait for flush */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(0) | @@ -1510,11 +1527,11 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = { .get_wptr = sdma_v3_0_ring_get_wptr, .set_wptr = sdma_v3_0_ring_set_wptr, .emit_frame_size = - 6 + /* sdma_v3_0_ring_emit_hdp_flush */ + 6 + 1 + /* sdma_v3_0_ring_emit_hdp_flush */ 3 + /* hdp invalidate */ - 6 + /* sdma_v3_0_ring_emit_pipeline_sync */ - VI_FLUSH_GPU_TLB_NUM_WREG * 3 + 6 + /* sdma_v3_0_ring_emit_vm_flush */ - 10 + 10 + 10, /* sdma_v3_0_ring_emit_fence x3 for user fence, vm fence */ + 6 + 1 + /* sdma_v3_0_ring_emit_pipeline_sync */ + VI_FLUSH_GPU_TLB_NUM_WREG * 3 + 6 + 1 + /* sdma_v3_0_ring_emit_vm_flush */ + (10 + 1) * 3, /* sdma_v3_0_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 7 + 6, /* sdma_v3_0_ring_emit_ib */ .emit_ib = sdma_v3_0_ring_emit_ib, .emit_fence = sdma_v3_0_ring_emit_fence, diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c index efb3fde919ee..b7d451f439a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c @@ -288,7 +288,7 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) int i; uint32_t keysel = adev->uvd.keyselect; - if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { + if (RREG32(mmUVD_FW_START)) { dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", RREG32(mmUVD_FW_START), adev->uvd.keyselect); return 0; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 48b086d15ab0..25ec3d38a14e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -2306,9 +2306,14 @@ static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, i { ASSERT(stream->sink); - struct dc_link *link = stream->sink->link; + struct dc_link *link; int req_bw = stream_bw; + if (!stream->sink) + return false; + + link = stream->sink->link; + DC_LOGGER_INIT(link->ctx->logger); if (!link->dpia_bw_alloc_config.bw_alloc_enabled) @@ -2355,9 +2360,13 @@ static bool allocate_usb4_bandwidth(struct dc_stream_state *stream) ASSERT(stream->sink); bool ret; + int bw; - int bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, - dc_link_get_highest_encoding_format(stream->sink->link)); + if (!stream->sink) + return false; + + bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, + dc_link_get_highest_encoding_format(stream->sink->link)); ret = allocate_usb4_bandwidth_for_stream(stream, bw); @@ -2419,7 +2428,8 @@ enum dc_status link_set_dpms_off(struct pipe_ctx *pipe_ctx) update_psp_stream_config(pipe_ctx, true); dc->hwss.blank_stream(pipe_ctx); - if (pipe_ctx->link_config.dp_tunnel_settings.should_use_dp_bw_allocation) + if (pipe_ctx->link_config.dp_tunnel_settings.should_use_dp_bw_allocation && + stream->sink) deallocate_usb4_bandwidth(stream); if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index ed99e61f18e1..6621e50de965 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -89,6 +89,7 @@ static const struct smu_feature_bits smu_v14_0_2_dpm_features = { #define PP_OD_FEATURE_FAN_TARGET_TEMPERATURE 9 #define PP_OD_FEATURE_FAN_MINIMUM_PWM 10 #define PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE 11 +#define PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP 12 static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -1020,6 +1021,10 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, od_min_setting = overdrive_lowerlimits->FanZeroRpmEnable; od_max_setting = overdrive_upperlimits->FanZeroRpmEnable; break; + case PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP: + od_min_setting = pptable->SkuTable.MsgLimits.FanStopTempMin; + od_max_setting = pptable->SkuTable.MsgLimits.FanStopTempMax; + break; default: od_min_setting = od_max_setting = INT_MAX; break; @@ -1244,6 +1249,24 @@ static int smu_v14_0_2_emit_clk_levels(struct smu_context *smu, min_value, max_value); break; + case SMU_OD_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v14_0_2_is_od_feature_supported(smu, + PP_OD_FEATURE_ZERO_FAN_BIT)) + break; + + size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_STOP_TEMPERATURE:\n"); + size += sysfs_emit_at(buf, size, "%d\n", + (int)od_table->OverDriveTable.FanZeroRpmStopTemp); + + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + smu_v14_0_2_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &min_value, + &max_value); + size += sysfs_emit_at(buf, size, "ZERO_RPM_STOP_TEMPERATURE: %u %u\n", + min_value, max_value); + break; + case SMU_OD_RANGE: if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && !smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && @@ -2311,7 +2334,9 @@ static void smu_v14_0_2_set_supported_od_feature_mask(struct smu_context *smu) OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE | OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET | OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE | - OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET; + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_RETRIEVE | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_SET; } static int smu_v14_0_2_get_overdrive_table(struct smu_context *smu, @@ -2392,6 +2417,8 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanMinimumPwm; user_od_table->OverDriveTable.FanZeroRpmEnable = user_od_table_bak.OverDriveTable.FanZeroRpmEnable; + user_od_table->OverDriveTable.FanZeroRpmStopTemp = + user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp; } smu_v14_0_2_set_supported_od_feature_mask(smu); @@ -2446,6 +2473,11 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp boot_overdrive_table->OverDriveTable.FanZeroRpmEnable; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; + case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: + od_table->OverDriveTable.FanZeroRpmStopTemp = + boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; case PP_OD_EDIT_ACOUSTIC_LIMIT: od_table->OverDriveTable.AcousticLimitRpmThreshold = boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold; @@ -2752,6 +2784,27 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; + case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) { + dev_warn(adev->dev, "Zero RPM setting not supported!\n"); + return -ENOTSUPP; + } + + smu_v14_0_2_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &minimum, + &maximum); + if (input[0] < minimum || + input[0] > maximum) { + dev_info(adev->dev, "zero RPM stop temperature setting(%ld) must be within [%d, %d]!\n", + input[0], minimum, maximum); + return -EINVAL; + } + + od_table->OverDriveTable.FanZeroRpmStopTemp = input[0]; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + case PP_OD_RESTORE_DEFAULT_TABLE: if (size == 1) { ret = smu_v14_0_2_od_restore_table_single(smu, input[0]); diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index 2453ec41360f..6fa3568ceba6 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -48,6 +48,16 @@ * See struct dma_exec for more details. */ +/* Unlock and put the prelocked obj */ +static void drm_exec_drop_prelocked(struct drm_exec *exec) +{ + if (exec->prelocked) { + dma_resv_unlock(exec->prelocked->resv); + drm_gem_object_put(exec->prelocked); + exec->prelocked = NULL; + } +} + /* Unlock all objects and drop references */ static void drm_exec_unlock_all(struct drm_exec *exec) { @@ -58,8 +68,7 @@ static void drm_exec_unlock_all(struct drm_exec *exec) drm_gem_object_put(obj); } - drm_gem_object_put(exec->prelocked); - exec->prelocked = NULL; + drm_exec_drop_prelocked(exec); } /** @@ -118,6 +127,14 @@ EXPORT_SYMBOL(drm_exec_fini); bool drm_exec_cleanup(struct drm_exec *exec) { if (likely(!exec->contended)) { + + /* + * The contended and prelocked object might never be passed to + * drm_exec_lock_obj() again. This can happen when the object + * is about to be cleaned up and we now hold the last reference + * to it. Make sure that we don't unnecessarily keep it around. + */ + drm_exec_drop_prelocked(exec); ww_acquire_done(&exec->ticket); return false; } @@ -175,16 +192,16 @@ static int drm_exec_lock_contended(struct drm_exec *exec) dma_resv_lock_slow(obj->resv, &exec->ticket); } - ret = drm_exec_obj_locked(exec, obj); - if (unlikely(ret)) - goto error_unlock; + /* + * It is perfectly possible that we see another contention before the + * first one is fully handled. + */ + drm_exec_drop_prelocked(exec); + /* We move the reference from contended to prelocked here */ exec->prelocked = obj; return 0; -error_unlock: - dma_resv_unlock(obj->resv); - error_dropref: drm_gem_object_put(obj); return ret; @@ -212,35 +229,31 @@ int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj) if (exec->prelocked == obj) { drm_gem_object_put(exec->prelocked); exec->prelocked = NULL; - return 0; + } else { + if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) + ret = dma_resv_lock_interruptible(obj->resv, + &exec->ticket); + else + ret = dma_resv_lock(obj->resv, &exec->ticket); + + if (unlikely(ret == -EDEADLK)) { + drm_gem_object_get(obj); + exec->contended = obj; + return -EDEADLK; + } + + if (unlikely(ret == -EALREADY) && + exec->flags & DRM_EXEC_IGNORE_DUPLICATES) + return 0; + + if (unlikely(ret)) + return ret; } - if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) - ret = dma_resv_lock_interruptible(obj->resv, &exec->ticket); - else - ret = dma_resv_lock(obj->resv, &exec->ticket); - - if (unlikely(ret == -EDEADLK)) { - drm_gem_object_get(obj); - exec->contended = obj; - return -EDEADLK; - } - - if (unlikely(ret == -EALREADY) && - exec->flags & DRM_EXEC_IGNORE_DUPLICATES) - return 0; - - if (unlikely(ret)) - return ret; - ret = drm_exec_obj_locked(exec, obj); if (ret) - goto error_unlock; + dma_resv_unlock(obj->resv); - return 0; - -error_unlock: - dma_resv_unlock(obj->resv); return ret; } EXPORT_SYMBOL(drm_exec_lock_obj); diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index dbebd7210848..de450ebf541f 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2342,12 +2342,14 @@ static void intel_c10pll_dump_hw_state(struct drm_printer *p, static bool is_arrowlake_s_by_host_bridge(void) { struct pci_dev *pdev = NULL; - u16 host_bridge_pci_dev_id; + while ((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, pdev))) { + if (IS_ARROWLAKE_S_BY_HOST_BRIDGE_ID(pdev->device)) { + pci_dev_put(pdev); + return true; + } + } - while ((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, pdev))) - host_bridge_pci_dev_id = pdev->device; - - return pdev && IS_ARROWLAKE_S_BY_HOST_BRIDGE_ID(host_bridge_pci_dev_id); + return false; } static u16 intel_c20_hdmi_tmds_tx_cgf_1(struct intel_display *display) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index a191eee240d9..6611765fd62c 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -1023,6 +1023,55 @@ static void dmc_set_fw_offset(struct intel_dmc *dmc, } } +/* + * Check if the load address is within the valid range for the given DMC ID. + */ +static bool dmc_load_addr_sanity_check(struct intel_dmc *dmc, + u32 start_addr, u32 payload_size, + int header_ver, enum intel_dmc_id dmc_id) +{ + u32 start_range, end_range, end_addr; + + if (header_ver != 3) + return true; + + switch (dmc_id) { + case DMC_FW_MAIN: + start_range = DMC_MAIN_PROGRAM_BASE_START; + end_range = DMC_MAIN_PROGRAM_BASE_END; + break; + case DMC_FW_PIPEA: + start_range = DMC_PIPEA_PROGRAM_BASE_START; + end_range = DMC_PIPEA_PROGRAM_BASE_END; + break; + case DMC_FW_PIPEB: + start_range = DMC_PIPEB_PROGRAM_BASE_START; + end_range = DMC_PIPEB_PROGRAM_BASE_END; + break; + case DMC_FW_PIPEC: + start_range = DMC_PIPEC_PROGRAM_BASE_START; + end_range = DMC_PIPEC_PROGRAM_BASE_END; + break; + case DMC_FW_PIPED: + start_range = DMC_PIPED_PROGRAM_BASE_START; + end_range = DMC_PIPED_PROGRAM_BASE_END; + break; + default: + MISSING_CASE(dmc_id); + return false; + } + + if (payload_size == 0) + end_addr = start_addr; + else if (check_add_overflow(start_addr, payload_size - 1, &end_addr)) + return false; + + if (start_addr < start_range || end_addr > end_range) + return false; + + return true; +} + static bool dmc_mmio_addr_sanity_check(struct intel_dmc *dmc, const u32 *mmioaddr, u32 mmio_count, int header_ver, enum intel_dmc_id dmc_id) @@ -1120,7 +1169,7 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc, } /* Cache the dmc header info. */ - if (mmio_count > mmio_count_max) { + if (!mmio_count || mmio_count > mmio_count_max) { drm_err(display->drm, "DMC firmware has wrong mmio count %u\n", mmio_count); return 0; } @@ -1166,13 +1215,21 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc, disable_dmc_evt(display, dmc_id, dmc_info->mmioaddr[i], dmc_info->mmiodata[i]) ? " (disabling)" : ""); } - dmc_info->mmio_count = mmio_count; - dmc_info->start_mmioaddr = start_mmioaddr; rem_size -= header_len_bytes; /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ - payload_size = dmc_header->fw_size * 4; + if (check_mul_overflow(dmc_header->fw_size, 4u, &payload_size)) { + drm_err(display->drm, "DMC fw_size too large (%u dwords)\n", + dmc_header->fw_size); + return 0; + } + + if (!payload_size) { + drm_err(display->drm, "DMC firmware has empty payload\n"); + return 0; + } + if (rem_size < payload_size) goto error_truncated; @@ -1180,12 +1237,21 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc, drm_err(display->drm, "DMC FW too big (%u bytes)\n", payload_size); return 0; } - dmc_info->dmc_fw_size = dmc_header->fw_size; + + if (!dmc_load_addr_sanity_check(dmc, start_mmioaddr, payload_size, + dmc_header->header_ver, dmc_id)) { + drm_err(display->drm, "DMC %d: firmware has wrong load address\n", dmc_id); + return 0; + } dmc_info->payload = kmalloc(payload_size, GFP_KERNEL); if (!dmc_info->payload) return 0; + dmc_info->mmio_count = mmio_count; + dmc_info->start_mmioaddr = start_mmioaddr; + dmc_info->dmc_fw_size = dmc_header->fw_size; + payload = (u8 *)(dmc_header) + header_len_bytes; memcpy(dmc_info->payload, payload, payload_size); diff --git a/drivers/gpu/drm/i915/display/intel_dmc_regs.h b/drivers/gpu/drm/i915/display/intel_dmc_regs.h index 6b7978fb8986..324320afad58 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dmc_regs.h @@ -521,6 +521,18 @@ enum pipedmc_event_id { #define TGL_PIPE_MMIO_END(dmc_id) _PICK_EVEN(((dmc_id) - 1), _TGL_PIPEA_MMIO_END,\ _TGL_PIPEB_MMIO_END) +/* For DMC header version v3*/ +#define DMC_MAIN_PROGRAM_BASE_START 0x80000 +#define DMC_MAIN_PROGRAM_BASE_END 0x86fff +#define DMC_PIPEA_PROGRAM_BASE_START 0x90000 +#define DMC_PIPEA_PROGRAM_BASE_END 0x96fff +#define DMC_PIPEB_PROGRAM_BASE_START 0x98000 +#define DMC_PIPEB_PROGRAM_BASE_END 0x9efff +#define DMC_PIPEC_PROGRAM_BASE_START 0x52000 +#define DMC_PIPEC_PROGRAM_BASE_END 0x53fff +#define DMC_PIPED_PROGRAM_BASE_START 0x59000 +#define DMC_PIPED_PROGRAM_BASE_END 0x5afff + #define SKL_DMC_DC3_DC5_COUNT _MMIO(0x80030) #define SKL_DMC_DC5_DC6_COUNT _MMIO(0x8002C) #define BXT_DMC_DC3_DC5_COUNT _MMIO(0x80038) diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c index 7e315708ca7c..ea1e222ef121 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.c +++ b/drivers/gpu/drm/panthor/panthor_hw.c @@ -136,7 +136,7 @@ static char *get_gpu_model_name(struct panthor_device *ptdev) case GPU_PROD_ID_MAKE(10, 7): return "Mali-G610"; case GPU_PROD_ID_MAKE(11, 2): - if (shader_core_count > 10 && ray_intersection) + if (shader_core_count >= 10 && ray_intersection) return "Mali-G715-Immortalis"; else if (shader_core_count >= 7) return "Mali-G715"; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 17c8635c5afa..d4672aa81d85 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -894,7 +894,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); + HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, VC4_HDMI_RAM_PACKET_ENABLE); HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB); @@ -1663,9 +1663,6 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, WARN_ONCE(ret, "Timeout waiting for " "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); } else { - HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, - HDMI_READ(HDMI_RAM_PACKET_CONFIG) & - ~(VC4_HDMI_RAM_PACKET_ENABLE)); HDMI_WRITE(HDMI_SCHEDULER_CONTROL, HDMI_READ(HDMI_SCHEDULER_CONTROL) & ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); @@ -1684,9 +1681,6 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) & VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE)); - HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, - VC4_HDMI_RAM_PACKET_ENABLE); - spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); vc4_hdmi->packet_ram_enabled = true; @@ -3143,6 +3137,11 @@ static int vc5_hdmi_init_resources(struct drm_device *drm, static int vc4_hdmi_runtime_suspend(struct device *dev) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); clk_disable_unprepare(vc4_hdmi->audio_clock); clk_disable_unprepare(vc4_hdmi->hsm_clock); @@ -3153,9 +3152,8 @@ static int vc4_hdmi_runtime_suspend(struct device *dev) static int vc4_hdmi_runtime_resume(struct device *dev) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); - unsigned long __maybe_unused flags; + unsigned long rate, flags; u32 __maybe_unused value; - unsigned long rate; int ret; ret = clk_prepare_enable(vc4_hdmi->hsm_clock); @@ -3201,6 +3199,10 @@ static int vc4_hdmi_runtime_resume(struct device *dev) } #endif + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, VC4_HDMI_RAM_PACKET_ENABLE); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + return 0; err_disable_clk: diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 2aaa7cb08085..52c174f9bff7 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -225,6 +225,7 @@ static int virtgpu_freeze(struct virtio_device *vdev) goto err_resume; } + virtio_reset_device(vdev); vdev->config->del_vqs(vdev); return 0; diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index b422eba42a5f..640815af4098 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -589,7 +589,6 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, struct drm_plane *plane; const uint32_t *formats; int nformats; - int ret; if (type == DRM_PLANE_TYPE_CURSOR) { formats = virtio_gpu_cursor_formats; @@ -615,17 +614,5 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI)); - if (type == DRM_PLANE_TYPE_CURSOR) { - /* - * The cursor plane exposes a format with an alpha channel, - * which requires a blend mode property. The host blends - * premultiplied alpha, matching the property's default. - */ - ret = drm_plane_create_blend_mode_property(plane, - BIT(DRM_MODE_BLEND_PREMULTI)); - if (ret) - return ERR_PTR(ret); - } - return plane; } diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 7b95ce0445a9..1813c8ab0500 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -330,6 +330,12 @@ static void xe_evict_flags(struct ttm_buffer_object *tbo, return; } + /* No resource: nothing is placed/mapped, so there is nothing to evict. */ + if (!tbo->resource) { + placement->num_placement = 0; + return; + } + bo = ttm_to_xe_bo(tbo); if (bo->flags & XE_BO_FLAG_CPU_ADDR_MIRROR) { *placement = sys_placement; @@ -944,6 +950,8 @@ static int xe_bo_move_notify(struct xe_bo *bo, * * Transfers pages between shrinkable and purgeable buckets when the BO * purgeable state changes. Called automatically from xe_bo_set_purgeable_state(). + * For pinned BOs, whose pages are not accounted, only the purgeable flag is + * updated, so that the correct bucket is used when the BO is unpinned. */ static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo, enum xe_madv_purgeable_state new_state) @@ -960,7 +968,8 @@ static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo, return; xe_tt = container_of(tt, struct xe_ttm_tt, ttm); - tt_pages = tt->num_pages; + /* Pinned bos are not accounted. Only update the purgeable flag. */ + tt_pages = xe_bo_is_pinned(bo) ? 0 : tt->num_pages; if (!xe_tt->purgeable && new_state == XE_MADV_PURGEABLE_DONTNEED) { xe_tt->purgeable = true; diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index d5293bc33a67..7dc9a0a1f569 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -346,11 +346,8 @@ retry: xe_sched_job_push(job); xe_vm_reactivate_rebind(vm); - if (!err && !xe_vm_in_lr_mode(vm)) { - spin_lock(&xe->ttm.lru_lock); - ttm_lru_bulk_move_tail(&vm->lru_bulk_move); - spin_unlock(&xe->ttm.lru_lock); - } + if (!err && !xe_vm_in_lr_mode(vm)) + xe_vm_bump_lru(vm, exec); if (mode == EXEC_MODE_LR) xe_hw_engine_group_resume_faulting_lr_jobs(group); diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index ab09dcff5860..64f01d9988a7 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -914,6 +914,13 @@ static int xe_oa_alloc_oa_buffer(struct xe_oa_stream *stream, size_t size) if (IS_ERR(bo)) return PTR_ERR(bo); + /* + * ttm_bo_type_kernel BOs are not zeroed on allocation, so the buffer can + * hold stale data from previously freed pages. Since the OA buffer is + * mmap'able by userspace, clear it here to avoid leaking kernel memory. + */ + xe_map_memset(stream->oa->xe, &bo->vmap, 0, 0, xe_bo_size(bo)); + stream->oa_buffer.bo = bo; stream->oa_buffer.bounce = kmalloc(stream->oa_buffer.format->size, GFP_KERNEL); diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index ef20e205a734..99e42bd29e79 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -410,6 +410,33 @@ int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec, return 0; } +/** + * xe_vm_bump_lru() - Bump the LRU position of BOs used by a submission + * @vm: The vm for which we are bumping LRUs. + * @exec: The struct drm_exec with the locked GEM objects. + * + * Move the VM's private BOs, and all external objects locked by @exec, + * to the LRU tail. Private BOs are moved in bulk using @vm's + * &xe_vm.lru_bulk_move. External objects, which may be shared with other + * VMs, are not part of that bulk move and are bumped individually. + */ +void xe_vm_bump_lru(struct xe_vm *vm, struct drm_exec *exec) +{ + spinlock_t *lru_lock = &vm->xe->ttm.lru_lock; + struct drm_gem_object *obj; + + spin_lock(lru_lock); + ttm_lru_bulk_move_tail(&vm->lru_bulk_move); + drm_exec_for_each_locked_object(exec, obj) { + if (!drm_gpuvm_is_extobj(&vm->gpuvm, obj)) + continue; + + ttm_bo_move_to_lru_tail(&gem_to_xe_bo(obj)->ttm); + cond_resched_lock(lru_lock); + } + spin_unlock(lru_lock); +} + static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm, bool *done) { @@ -560,9 +587,7 @@ retry: #undef retry_required - spin_lock(&vm->xe->ttm.lru_lock); - ttm_lru_bulk_move_tail(&vm->lru_bulk_move); - spin_unlock(&vm->xe->ttm.lru_lock); + xe_vm_bump_lru(vm, &exec); /* Point of no return. */ arm_preempt_fences(vm, &preempt_fences); diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h index c5b900f38ded..4b606445799c 100644 --- a/drivers/gpu/drm/xe/xe_vm.h +++ b/drivers/gpu/drm/xe/xe_vm.h @@ -284,6 +284,8 @@ int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma); int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec, unsigned int num_fences); +void xe_vm_bump_lru(struct xe_vm *vm, struct drm_exec *exec); + struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo, struct xe_exec_queue *q, u64 addr, enum xe_cache_level cache_lvl); diff --git a/include/drm/drm_exec.h b/include/drm/drm_exec.h index cc2937185a9f..c92d69a2c793 100644 --- a/include/drm/drm_exec.h +++ b/include/drm/drm_exec.h @@ -73,13 +73,15 @@ drm_exec_obj(struct drm_exec *exec, unsigned long index) /* Helper for drm_exec_for_each_locked_object(). Internal use only. */ #define __drm_exec_for_each_locked_object(exec, obj, __index) \ - for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); ++__index) + for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); \ + ++__index) /** * drm_exec_for_each_locked_object - iterate over all the locked objects * @exec: drm_exec object * @obj: the current GEM object * - * Iterate over all the locked GEM objects inside the drm_exec object. + * Iterate over all the explicitly locked GEM objects inside the drm_exec + * container, except for the contended and implicit prelocked one. */ #define drm_exec_for_each_locked_object(exec, obj) \ __drm_exec_for_each_locked_object(exec, obj, __UNIQUE_ID(drm_exec)) @@ -94,12 +96,13 @@ drm_exec_obj(struct drm_exec *exec, unsigned long index) * @exec: drm_exec object * @obj: the current GEM object * - * Iterate over all the locked GEM objects inside the drm_exec object in - * reverse locking order. Note that the internal index may wrap around, - * but that will be caught by drm_exec_obj(), returning a NULL object. + * Iterate over all the explicitly locked GEM objects inside the drm_exec + * container in reverse locking order. Note that the internal index may wrap + * around, but that will be caught by drm_exec_obj(), returning a NULL object. */ #define drm_exec_for_each_locked_object_reverse(exec, obj) \ - __drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec)) + __drm_exec_for_each_locked_object_reverse(exec, obj, \ + __UNIQUE_ID(drm_exec)) /** * drm_exec_until_all_locked - loop until all GEM objects are locked