summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c23
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c545
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h63
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c322
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v11_5_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v12_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_userqueue.c145
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v1_0.c64
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v2_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c36
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c33
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c33
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c49
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c11
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h7
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c7
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/basics/vector.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c90
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_transform.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c8
-rw-r--r--drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c3
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c4
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c13
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c42
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c32
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c8
-rw-r--r--drivers/gpu/drm/bridge/chipone-icn6211.c4
-rw-r--r--drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c40
-rw-r--r--drivers/gpu/drm/bridge/ite-it66121.c5
-rw-r--r--drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c16
-rw-r--r--drivers/gpu/drm/bridge/tda998x_drv.c4
-rw-r--r--drivers/gpu/drm/drm_drv.c2
-rw-r--r--drivers/gpu/drm/drm_dumb_buffers.c7
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c2
-rw-r--r--drivers/gpu/drm/drm_gem.c89
-rw-r--r--drivers/gpu/drm/drm_ioctl.c3
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_sched.c16
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c8
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi.c1
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_lvds.c9
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_drv.c5
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_modeset.c15
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_proto.c113
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_core.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_irq.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux.c20
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c19
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpcd.h15
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane.c29
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c69
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm.c28
-rw-r--r--drivers/gpu/drm/i915/gt/intel_reset.c3
-rw-r--r--drivers/gpu/drm/i915/i915_driver.c5
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-scaler.c3
-rw-r--r--drivers/gpu/drm/loongson/lsdc_drv.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_cec.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_v2.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu.c7
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_hfi.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c8
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h2
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c12
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c3
-rw-r--r--drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c28
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c1
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c11
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h7
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c33
-rw-r--r--drivers/gpu/drm/msm/msm_gem_shrinker.c44
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c6
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c12
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c4
-rw-r--r--drivers/gpu/drm/msm/msm_iommu.c5
-rw-r--r--drivers/gpu/drm/msm/msm_ringbuffer.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c18
-rw-r--r--drivers/gpu/drm/panel/Kconfig1
-rw-r--r--drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c2
-rw-r--r--drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c4
-rw-r--r--drivers/gpu/drm/panel/panel-himax-hx83102.c2
-rw-r--r--drivers/gpu/drm/panel/panel-himax-hx83121a.c4
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c6
-rw-r--r--drivers/gpu/drm/radeon/ci_dpm.c9
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c6
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c8
-rw-r--r--drivers/gpu/drm/tiny/bochs.c10
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c18
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c11
-rw-r--r--drivers/gpu/drm/ttm/ttm_pool.c18
-rw-r--r--drivers/gpu/drm/ttm/ttm_resource.c18
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c8
-rw-r--r--drivers/gpu/drm/v3d/v3d_perfmon.c24
-rw-r--r--drivers/gpu/drm/v3d/v3d_sched.c33
-rw-r--r--drivers/gpu/drm/v3d/v3d_submit.c22
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h1
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_gem.c17
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_plane.c10
-rw-r--r--drivers/gpu/drm/xe/display/xe_hdcp_gsc.c12
-rw-r--r--drivers/gpu/drm/xe/regs/xe_gt_regs.h4
-rw-r--r--drivers/gpu/drm/xe/xe_bo.c6
-rw-r--r--drivers/gpu/drm/xe/xe_bo.h88
-rw-r--r--drivers/gpu/drm/xe/xe_bo_types.h28
-rw-r--r--drivers/gpu/drm/xe/xe_dma_buf.c80
-rw-r--r--drivers/gpu/drm/xe/xe_exec_queue.h17
-rw-r--r--drivers/gpu/drm/xe/xe_gsc.c5
-rw-r--r--drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c8
-rw-r--r--drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.c6
-rw-r--r--drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.h2
-rw-r--r--drivers/gpu/drm/xe/xe_gt_sriov_vf.c24
-rw-r--r--drivers/gpu/drm/xe/xe_gt_sriov_vf.h6
-rw-r--r--drivers/gpu/drm/xe/xe_gt_types.h7
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ads.c10
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.c78
-rw-r--r--drivers/gpu/drm/xe/xe_hw_engine_group.c10
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.c11
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.h2
-rw-r--r--drivers/gpu/drm/xe/xe_memirq.c26
-rw-r--r--drivers/gpu/drm/xe/xe_migrate.c18
-rw-r--r--drivers/gpu/drm/xe/xe_oa.c6
-rw-r--r--drivers/gpu/drm/xe/xe_pci.c9
-rw-r--r--drivers/gpu/drm/xe/xe_sriov_pf_migration.c7
-rw-r--r--drivers/gpu/drm/xe/xe_tile_types.h2
-rw-r--r--drivers/gpu/drm/xe/xe_tuning.c2
-rw-r--r--drivers/gpu/drm/xe/xe_uc_fw.c1
-rw-r--r--drivers/gpu/drm/xe/xe_vm.c51
-rw-r--r--drivers/gpu/drm/xe/xe_vm_madvise.c162
-rw-r--r--drivers/gpu/drm/xe/xe_vm_madvise.h2
-rw-r--r--drivers/gpu/drm/xe/xe_wa.c6
185 files changed, 2049 insertions, 1628 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 8bc591deb546..fd50da4c7b18 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1190,7 +1190,6 @@ struct amdgpu_device {
bool apu_prefer_gtt;
bool userq_halt_for_enforce_isolation;
- struct work_struct userq_reset_work;
struct amdgpu_uid *uid_info;
struct amdgpu_uma_carveout_info uma_info;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index d9e283f3b57d..9783a3cefb04 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -36,6 +36,9 @@
#include "amdgpu_ras.h"
#include "amdgpu_umc.h"
#include "amdgpu_reset.h"
+#if IS_ENABLED(CONFIG_HSA_AMD)
+#include "kfd_priv.h"
+#endif
/* Total memory size in system memory and all GPU VRAM. Used to
* estimate worst case amount of memory to reserve for page tables
@@ -320,6 +323,28 @@ void amdgpu_amdkfd_gpu_reset(struct amdgpu_device *adev)
(void)amdgpu_reset_domain_schedule(adev->reset_domain, &adev->kfd.reset_work);
}
+void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev)
+{
+#if IS_ENABLED(CONFIG_HSA_AMD)
+ struct kfd_dev *kfd = adev->kfd.dev;
+ unsigned int i;
+
+ if (!kfd)
+ return;
+
+ for (i = 0; i < kfd->num_nodes; i++) {
+ struct kfd_node *node = kfd->nodes[i];
+
+ kfd_dev_unmap_mapping_range(KFD_MMAP_TYPE_DOORBELL |
+ KFD_MMAP_GPU_ID(node->id),
+ kfd_doorbell_process_slice(kfd));
+ kfd_dev_unmap_mapping_range(KFD_MMAP_TYPE_MMIO |
+ KFD_MMAP_GPU_ID(node->id),
+ PAGE_SIZE);
+ }
+#endif
+}
+
int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size,
u32 domain, void **mem_obj, uint64_t *gpu_addr,
void **cpu_ptr, bool cp_mqd_gfx9)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index cdbab7f8cee8..2b4108f83f48 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -358,6 +358,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
uint64_t size, u32 alloc_flag, int8_t xcp_id);
void amdgpu_amdkfd_unreserve_mem_limit(struct amdgpu_device *adev,
uint64_t size, u32 alloc_flag, int8_t xcp_id);
+void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev);
u64 amdgpu_amdkfd_xcp_memory_size(struct amdgpu_device *adev, int xcp_id);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 66ca043658ff..feab90e3efd1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3787,7 +3787,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
}
INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func);
- INIT_WORK(&adev->userq_reset_work, amdgpu_userq_reset_work);
amdgpu_coredump_init(adev);
@@ -5478,7 +5477,7 @@ static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev)
if (!amdgpu_sriov_vf(adev))
cancel_work(&adev->reset_work);
#endif
- cancel_work(&adev->userq_reset_work);
+ amdgpu_userq_mgr_cancel_reset_work(adev);
if (adev->kfd.dev)
cancel_work(&adev->kfd.reset_work);
@@ -5836,6 +5835,12 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
/* We need to lock reset domain only once both for XGMI and single device */
amdgpu_device_recovery_get_reset_lock(adev, &device_list);
+ /* unmap all the mappings of doorbell and framebuffer to prevent user space from
+ * accessing them
+ */
+ unmap_mapping_range(adev->ddev.anon_inode->i_mapping, 0, 0, 1);
+ amdgpu_amdkfd_clear_kfd_mapping(adev);
+
amdgpu_device_halt_activities(adev, job, reset_context, &device_list,
hive, need_emergency_restart);
if (need_emergency_restart)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 8d99bfaa498f..80efeca0ab73 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -304,7 +304,7 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev,
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].offset;
adev->discovery.size =
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_IPD_TABLE_ID].size_kb << 10;
- if (!adev->discovery.offset || !adev->discovery.size)
+ if (!adev->discovery.size)
return -EINVAL;
} else {
goto out;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 46aae3fad4bf..60debd543e44 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -3149,11 +3149,7 @@ static int __init amdgpu_init(void)
r = amdgpu_sync_init();
if (r)
- goto error_sync;
-
- r = amdgpu_userq_fence_slab_init();
- if (r)
- goto error_fence;
+ return r;
amdgpu_register_atpx_handler();
amdgpu_acpi_detect();
@@ -3161,7 +3157,7 @@ static int __init amdgpu_init(void)
/* Ignore KFD init failures when CONFIG_HSA_AMD is not set. */
r = amdgpu_amdkfd_init();
if (r && r != -ENOENT)
- goto error_fence;
+ goto error_fini_sync;
if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) {
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
@@ -3172,10 +3168,8 @@ static int __init amdgpu_init(void)
/* let modprobe override vga console setting */
return pci_register_driver(&amdgpu_kms_pci_driver);
-error_fence:
+error_fini_sync:
amdgpu_sync_fini();
-
-error_sync:
return r;
}
@@ -3186,7 +3180,6 @@ static void __exit amdgpu_exit(void)
amdgpu_unregister_atpx_handler();
amdgpu_acpi_release();
amdgpu_sync_fini();
- amdgpu_userq_fence_slab_fini();
mmu_notifier_synchronize();
amdgpu_xcp_drv_release();
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
index bc772ca3dab7..c4c21dbbbdbf 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
@@ -262,12 +262,19 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
*/
int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
{
+ int r;
+
if (adev->gart.bo != NULL)
return 0;
- return amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
- NULL, (void *)&adev->gart.ptr);
+ r = amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
+ NULL, (void *)&adev->gart.ptr);
+ if (r)
+ return r;
+
+ memset_io(adev->gart.ptr, adev->gart.gart_pte_flags, adev->gart.table_size);
+ return 0;
}
/**
@@ -387,7 +394,8 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
uint64_t start_page, uint64_t num_pages,
uint64_t flags, void *dst)
{
- u32 i, idx;
+ u32 i, j, t, idx;
+ u64 page_base;
/* The SYSTEM flag indicates the pages aren't in VRAM. */
WARN_ON_ONCE(flags & AMDGPU_PTE_SYSTEM);
@@ -395,9 +403,12 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
if (!drm_dev_enter(adev_to_drm(adev), &idx))
return;
- for (i = 0; i < num_pages; ++i) {
- amdgpu_gmc_set_pte_pde(adev, dst,
- start_page + i, pa + AMDGPU_GPU_PAGE_SIZE * i, flags);
+ page_base = pa;
+ for (i = 0, t = 0; i < num_pages; i++) {
+ for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) {
+ amdgpu_gmc_set_pte_pde(adev, dst, start_page + t, page_base, flags);
+ page_base += AMDGPU_GPU_PAGE_SIZE;
+ }
}
drm_dev_exit(idx);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 5376035d32fe..fe6d988e7f24 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence-unwrap.h>
+#include <linux/uaccess.h>
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
@@ -508,6 +509,9 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
if (offset_in_page(args->addr | args->size))
return -EINVAL;
+ if (!access_ok((void __user *)(uintptr_t)args->addr, args->size))
+ return -EFAULT;
+
/* reject unknown flag values */
if (args->flags & ~(AMDGPU_GEM_USERPTR_READONLY |
AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_VALIDATE |
@@ -821,7 +825,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
struct drm_syncobj *timeline_syncobj = NULL;
struct dma_fence_chain *timeline_chain = NULL;
struct drm_exec exec;
- uint64_t vm_size;
+ uint64_t vm_size, tmp;
int r = 0;
/* Validate virtual address range against reserved regions. */
@@ -845,7 +849,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE;
vm_size -= AMDGPU_VA_RESERVED_TOP;
- if (args->va_address + args->map_size > vm_size) {
+ if (check_add_overflow(args->va_address, args->map_size, &tmp) || tmp > vm_size) {
dev_dbg(dev->dev,
"va_address 0x%llx is in top reserved area 0x%llx\n",
args->va_address + args->map_size, vm_size);
@@ -1089,9 +1093,16 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
* If that number is larger than the size of the array, the ioctl must
* be retried.
*/
+ if (args->num_entries > INT_MAX / sizeof(*vm_entries)) {
+ r = -EINVAL;
+ goto out_exec;
+ }
+
vm_entries = kvcalloc(args->num_entries, sizeof(*vm_entries), GFP_KERNEL);
- if (!vm_entries)
- return -ENOMEM;
+ if (!vm_entries) {
+ r = -ENOMEM;
+ goto out_exec;
+ }
amdgpu_vm_bo_va_for_each_valid_mapping(bo_va, mapping) {
if (num_mappings < args->num_entries) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index 3d9497d121ca..c076c5f06e77 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -170,7 +170,7 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
/*
* The following is for PTE only. GART does not have PDEs.
*/
- value = addr & 0x0000FFFFFFFFF000ULL;
+ value = addr & adev->gmc.pte_addr_mask;
value |= flags;
writeq(value, ptr + (gpu_page_idx * 8));
@@ -1003,7 +1003,7 @@ void amdgpu_gmc_noretry_set(struct amdgpu_device *adev)
gc_ver == IP_VERSION(9, 4, 3) ||
gc_ver == IP_VERSION(9, 4, 4) ||
gc_ver == IP_VERSION(9, 5, 0) ||
- gc_ver >= IP_VERSION(10, 3, 0));
+ gc_ver >= IP_VERSION(10, 1, 0));
if (!amdgpu_sriov_xnack_support(adev))
gmc->noretry = 1;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
index 6ab4c1e297fc..d03536b969b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
@@ -280,6 +280,7 @@ struct amdgpu_gmc {
u64 real_vram_size;
int vram_mtrr;
u64 mc_mask;
+ uint64_t pte_addr_mask;
const struct firmware *fw; /* MC firmware */
uint32_t fw_version;
struct amdgpu_irq_src vm_fault;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
index 620fddde4c4d..d23a91d029aa 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
@@ -199,11 +199,18 @@ int amdgpu_gtt_mgr_alloc_entries(struct amdgpu_gtt_mgr *mgr,
enum drm_mm_insert_mode mode)
{
struct amdgpu_device *adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
+ u32 alignment = 0;
int r;
+ /* Align to TLB L2 cache entry size to work around "V bit HW bug" */
+ if (adev->family == AMDGPU_FAMILY_SI) {
+ alignment = 32 * 1024 / AMDGPU_GPU_PAGE_SIZE;
+ num_pages = ALIGN(num_pages, alignment);
+ }
+
spin_lock(&mgr->lock);
r = drm_mm_insert_node_in_range(&mgr->mm, mm_node, num_pages,
- 0, GART_ENTRY_WITHOUT_BO_COLOR, 0,
+ alignment, GART_ENTRY_WITHOUT_BO_COLOR, 0,
adev->gmc.gart_size >> PAGE_SHIFT,
mode);
spin_unlock(&mgr->lock);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
index f72990ac046e..e452444b33b0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
@@ -51,8 +51,6 @@
#include "amdgpu_amdkfd.h"
#include "amdgpu_hmm.h"
-#define MAX_WALK_BYTE (2UL << 30)
-
/**
* amdgpu_hmm_invalidate_gfx - callback to notify about mm change
*
@@ -69,6 +67,7 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
{
struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
+ struct amdgpu_bo *vm_root = bo->vm_bo->vm->root.bo;
long r;
if (!mmu_notifier_range_blockable(range))
@@ -78,8 +77,10 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
mmu_interval_set_seq(mni, cur_seq);
- r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
- false, MAX_SCHEDULE_TIMEOUT);
+ amdgpu_vm_bo_invalidate(bo, false);
+ r = dma_resv_wait_timeout(vm_root->tbo.base.resv,
+ DMA_RESV_USAGE_BOOKKEEP, false,
+ MAX_SCHEDULE_TIMEOUT);
mutex_unlock(&adev->notifier_lock);
if (r <= 0)
DRM_ERROR("(%ld) failed to wait for user bo\n", r);
@@ -170,11 +171,13 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
void *owner,
struct amdgpu_hmm_range *range)
{
- unsigned long end;
+ const u64 max_bytes = SZ_2G;
+
+ struct hmm_range *hmm_range = &range->hmm_range;
unsigned long timeout;
unsigned long *pfns;
- int r = 0;
- struct hmm_range *hmm_range = &range->hmm_range;
+ unsigned long end;
+ int r;
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
if (unlikely(!pfns)) {
@@ -191,8 +194,9 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
end = start + npages * PAGE_SIZE;
hmm_range->dev_private_owner = owner;
+ hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
do {
- hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end);
+ hmm_range->end = min(hmm_range->start + max_bytes, end);
pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
hmm_range->start, hmm_range->end);
@@ -200,7 +204,6 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
retry:
- hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
r = hmm_range_fault(hmm_range);
if (unlikely(r)) {
if (r == -EBUSY && !time_after(jiffies, timeout))
@@ -210,7 +213,7 @@ retry:
if (hmm_range->end == end)
break;
- hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT;
+ hmm_range->hmm_pfns += max_bytes >> PAGE_SHIFT;
hmm_range->start = hmm_range->end;
} while (hmm_range->end < end);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
index 912c9afaf9e1..4d68732d6223 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -96,7 +96,8 @@ struct amdgpu_bo_va {
* if non-zero, cannot unmap from GPU because user queues may still access it
*/
unsigned int queue_refcount;
- atomic_t userq_va_mapped;
+ /* Indicates if this buffer is mapped for any user queue. Once set, never reset. */
+ bool userq_va_mapped;
};
struct amdgpu_bo {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index 6c644cfe6695..fc9f3adf9912 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -2280,7 +2280,8 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev)
list_for_each_entry(obj, &con->head, node) {
if (amdgpu_ras_is_supported(adev, obj->head.block) &&
(obj->attr_inuse == 1)) {
- sprintf(fs_info.debugfs_name, "%s_err_inject",
+ snprintf(fs_info.debugfs_name, sizeof(fs_info.debugfs_name),
+ "%s_err_inject",
get_ras_block_str(&obj->head));
fs_info.head = obj->head;
amdgpu_ras_debugfs_create(adev, &fs_info, dir);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index 66e8a2f7afcf..d6bee5c30073 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -552,8 +552,9 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
{
struct amdgpu_ring *ring = file_inode(f)->i_private;
- uint32_t value, result, early[3];
+ u32 value, result, early[3] = { 0 };
uint64_t p;
+ u32 avail_dw, start_dw, read_dw;
loff_t i;
int r;
@@ -565,10 +566,10 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
result = 0;
- if (*pos < 12) {
- if (ring->funcs->type == AMDGPU_RING_TYPE_CPER)
- mutex_lock(&ring->adev->cper.ring_lock);
+ if (ring->funcs->type == AMDGPU_RING_TYPE_CPER)
+ mutex_lock(&ring->adev->cper.ring_lock);
+ if (*pos < 12) {
early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask;
early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask;
early[2] = ring->wptr & ring->buf_mask;
@@ -600,13 +601,24 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
*pos += 4;
}
} else {
+ early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask;
+ early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask;
+
p = early[0];
if (early[0] <= early[1])
- size = (early[1] - early[0]);
+ avail_dw = early[1] - early[0];
else
- size = ring->ring_size - (early[0] - early[1]);
+ avail_dw = ring->buf_mask + 1 - (early[0] - early[1]);
- while (size) {
+ start_dw = (*pos > 12) ? ((*pos - 12) >> 2) : 0;
+ if (start_dw >= avail_dw)
+ goto out;
+
+ p = (p + start_dw) & ring->ptr_mask;
+ avail_dw -= start_dw;
+ read_dw = min_t(u32, avail_dw, size >> 2);
+
+ while (read_dw) {
if (p == early[1])
goto out;
@@ -619,9 +631,10 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
buf += 4;
result += 4;
- size--;
+ read_dw--;
p++;
p &= ring->ptr_mask;
+ *pos += 4;
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c
index a0b479d5fff1..21a225b0116a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c
@@ -173,13 +173,17 @@ error:
int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *va,
u64 *gpu_addr, u64 **cpu_addr)
{
- unsigned long bit_pos;
-
- bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem);
- if (bit_pos >= adev->seq64.num_sem)
- return -ENOSPC;
-
- __set_bit(bit_pos, adev->seq64.used);
+ unsigned long bit_pos = 0;
+
+ do {
+ bit_pos = find_next_zero_bit(adev->seq64.used,
+ adev->seq64.num_sem, bit_pos);
+ if (bit_pos >= adev->seq64.num_sem)
+ return -ENOSPC;
+ if (!test_and_set_bit(bit_pos, adev->seq64.used))
+ break;
+ bit_pos++;
+ } while (1);
*va = bit_pos * sizeof(u64) + amdgpu_seq64_get_va_base(adev);
@@ -205,7 +209,7 @@ void amdgpu_seq64_free(struct amdgpu_device *adev, u64 va)
bit_pos = (va - amdgpu_seq64_get_va_base(adev)) / sizeof(u64);
if (bit_pos < adev->seq64.num_sem)
- __clear_bit(bit_pos, adev->seq64.used);
+ clear_bit(bit_pos, adev->seq64.used);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
index 0238c2798de4..b8ed931f8a40 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
@@ -130,6 +130,7 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
adev->umc.ras->ras_block.hw_ops->query_ras_error_address &&
adev->umc.max_ras_err_cnt_per_query) {
+ kfree(err_data->err_addr);
err_data->err_addr =
kzalloc_objs(struct eeprom_table_record,
adev->umc.max_ras_err_cnt_per_query);
@@ -160,6 +161,7 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
if (adev->umc.ras &&
adev->umc.ras->ecc_info_query_ras_error_address &&
adev->umc.max_ras_err_cnt_per_query) {
+ kfree(err_data->err_addr);
err_data->err_addr =
kzalloc_objs(struct eeprom_table_record,
adev->umc.max_ras_err_cnt_per_query);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index de140a8ed135..59ffaa7b61c2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -82,19 +82,11 @@ static bool amdgpu_userq_is_reset_type_supported(struct amdgpu_device *adev,
return false;
}
-static void amdgpu_userq_gpu_reset(struct amdgpu_device *adev)
-{
- if (amdgpu_device_should_recover_gpu(adev)) {
- amdgpu_reset_domain_schedule(adev->reset_domain,
- &adev->userq_reset_work);
- /* Wait for the reset job to complete */
- flush_work(&adev->userq_reset_work);
- }
-}
-
-static int
-amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
+static void amdgpu_userq_mgr_reset_work(struct work_struct *work)
{
+ struct amdgpu_userq_mgr *uq_mgr =
+ container_of(work, struct amdgpu_userq_mgr,
+ reset_work);
struct amdgpu_device *adev = uq_mgr->adev;
const int queue_types[] = {
AMDGPU_RING_TYPE_COMPUTE,
@@ -103,15 +95,11 @@ amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
};
const int num_queue_types = ARRAY_SIZE(queue_types);
bool gpu_reset = false;
- int r = 0;
- int i;
-
- /* Warning if current process mutex is not held */
- WARN_ON(!mutex_is_locked(&uq_mgr->userq_mutex));
+ int i, r;
if (unlikely(adev->debug_disable_gpu_ring_reset)) {
dev_err(adev->dev, "userq reset disabled by debug mask\n");
- return 0;
+ return;
}
/*
@@ -119,7 +107,7 @@ amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
* skip all reset detection logic
*/
if (!amdgpu_gpu_recovery)
- return 0;
+ return;
/*
* Iterate through all queue types to detect and reset problematic queues
@@ -127,9 +115,11 @@ amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
*/
for (i = 0; i < num_queue_types; i++) {
int ring_type = queue_types[i];
- const struct amdgpu_userq_funcs *funcs = adev->userq_funcs[ring_type];
+ const struct amdgpu_userq_funcs *funcs =
+ adev->userq_funcs[ring_type];
- if (!amdgpu_userq_is_reset_type_supported(adev, ring_type, AMDGPU_RESET_TYPE_PER_QUEUE))
+ if (!amdgpu_userq_is_reset_type_supported(adev, ring_type,
+ AMDGPU_RESET_TYPE_PER_QUEUE))
continue;
if (atomic_read(&uq_mgr->userq_count[ring_type]) > 0 &&
@@ -142,46 +132,43 @@ amdgpu_userq_detect_and_reset_queues(struct amdgpu_userq_mgr *uq_mgr)
}
}
- if (gpu_reset)
- amdgpu_userq_gpu_reset(adev);
+ if (gpu_reset) {
+ struct amdgpu_reset_context reset_context;
- return r;
+ memset(&reset_context, 0, sizeof(reset_context));
+
+ reset_context.method = AMD_RESET_METHOD_NONE;
+ reset_context.reset_req_dev = adev;
+ reset_context.src = AMDGPU_RESET_SRC_USERQ;
+ set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
+ /*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
+
+ amdgpu_device_gpu_recover(adev, NULL, &reset_context);
+ }
}
static void amdgpu_userq_hang_detect_work(struct work_struct *work)
{
- struct amdgpu_usermode_queue *queue = container_of(work,
- struct amdgpu_usermode_queue,
- hang_detect_work.work);
- struct dma_fence *fence;
- struct amdgpu_userq_mgr *uq_mgr;
-
- if (!queue->userq_mgr)
- return;
-
- uq_mgr = queue->userq_mgr;
- fence = READ_ONCE(queue->hang_detect_fence);
- /* Fence already signaled – no action needed */
- if (!fence || dma_fence_is_signaled(fence))
- return;
+ struct amdgpu_usermode_queue *queue =
+ container_of(work, struct amdgpu_usermode_queue,
+ hang_detect_work.work);
- mutex_lock(&uq_mgr->userq_mutex);
- amdgpu_userq_detect_and_reset_queues(uq_mgr);
- mutex_unlock(&uq_mgr->userq_mutex);
+ /*
+ * Don't schedule the work here! Scheduling or queue work from one reset
+ * handler to another is illegal if you don't take extra precautions!
+ */
+ amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
}
/*
* Start hang detection for a user queue fence. A delayed work will be scheduled
- * to check if the fence is still pending after the timeout period.
-*/
+ * to reset the queues when the fence doesn't signal in time.
+ */
void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue)
{
struct amdgpu_device *adev;
unsigned long timeout_ms;
- if (!queue || !queue->userq_mgr || !queue->userq_mgr->adev)
- return;
-
adev = queue->userq_mgr->adev;
/* Determine timeout based on queue type */
switch (queue->queue_type) {
@@ -199,10 +186,8 @@ void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue)
break;
}
- /* Store the fence to monitor and schedule hang detection */
- WRITE_ONCE(queue->hang_detect_fence, queue->last_fence);
- schedule_delayed_work(&queue->hang_detect_work,
- msecs_to_jiffies(timeout_ms));
+ queue_delayed_work(adev->reset_domain->wq, &queue->hang_detect_work,
+ msecs_to_jiffies(timeout_ms));
}
void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
@@ -210,47 +195,35 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
struct xarray *xa = &adev->userq_doorbell_xa;
struct amdgpu_usermode_queue *queue;
unsigned long flags;
+ int r;
xa_lock_irqsave(xa, flags);
queue = xa_load(xa, doorbell);
- if (queue)
- amdgpu_userq_fence_driver_process(queue->fence_drv);
- xa_unlock_irqrestore(xa, flags);
-}
-
-static void amdgpu_userq_init_hang_detect_work(struct amdgpu_usermode_queue *queue)
-{
- INIT_DELAYED_WORK(&queue->hang_detect_work, amdgpu_userq_hang_detect_work);
- queue->hang_detect_fence = NULL;
-}
-
-static int amdgpu_userq_buffer_va_list_add(struct amdgpu_usermode_queue *queue,
- struct amdgpu_bo_va_mapping *va_map, u64 addr)
-{
- struct amdgpu_userq_va_cursor *va_cursor;
- struct userq_va_list;
-
- va_cursor = kzalloc_obj(*va_cursor);
- if (!va_cursor)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&va_cursor->list);
- va_cursor->gpu_addr = addr;
- atomic_set(&va_map->bo_va->userq_va_mapped, 1);
- list_add(&va_cursor->list, &queue->userq_va_list);
+ if (queue) {
+ r = amdgpu_userq_fence_driver_process(queue->fence_drv);
+ /*
+ * We are in interrupt context here, this *can't* wait for
+ * reset work to finish.
+ */
+ if (r >= 0)
+ cancel_delayed_work(&queue->hang_detect_work);
- return 0;
+ /* Restart the timer when there are still fences pending */
+ if (r == 1)
+ amdgpu_userq_start_hang_detect_work(queue);
+ }
+ xa_unlock_irqrestore(xa, flags);
}
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
struct amdgpu_usermode_queue *queue,
- u64 addr, u64 expected_size)
+ u64 addr, u64 expected_size,
+ u64 *va_out)
{
struct amdgpu_bo_va_mapping *va_map;
struct amdgpu_vm *vm = queue->vm;
u64 user_addr;
u64 size;
- int r = 0;
/* Caller must hold vm->root.bo reservation */
dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv);
@@ -259,20 +232,18 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
size = expected_size >> AMDGPU_GPU_PAGE_SHIFT;
va_map = amdgpu_vm_bo_lookup_mapping(vm, user_addr);
- if (!va_map) {
- r = -EINVAL;
- goto out_err;
- }
+ if (!va_map)
+ return -EINVAL;
+
/* Only validate the userq whether resident in the VM mapping range */
if (user_addr >= va_map->start &&
va_map->last - user_addr + 1 >= size) {
- amdgpu_userq_buffer_va_list_add(queue, va_map, user_addr);
+ va_map->bo_va->userq_va_mapped = true;
+ *va_out = user_addr;
return 0;
}
- r = -EINVAL;
-out_err:
- return r;
+ return -EINVAL;
}
static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
@@ -283,7 +254,7 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
dma_resv_assert_held(vm->root.bo->tbo.base.resv);
mapping = amdgpu_vm_bo_lookup_mapping(vm, addr);
- if (!IS_ERR_OR_NULL(mapping) && atomic_read(&mapping->bo_va->userq_va_mapped))
+ if (!IS_ERR_OR_NULL(mapping) && mapping->bo_va->userq_va_mapped)
r = true;
else
r = false;
@@ -293,14 +264,16 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
{
- struct amdgpu_userq_va_cursor *va_cursor, *tmp;
- int r = 0;
+ int i, r = 0;
- list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) {
- r += amdgpu_userq_buffer_va_mapped(queue->vm, va_cursor->gpu_addr);
+ for (i = 0; i < ARRAY_SIZE(queue->userq_vas.va_array); i++) {
+ if (!queue->userq_vas.va_array[i])
+ continue;
+ r += amdgpu_userq_buffer_va_mapped(queue->vm,
+ queue->userq_vas.va_array[i]);
dev_dbg(queue->userq_mgr->adev->dev,
"validate the userq mapping:%p va:%llx r:%d\n",
- queue, va_cursor->gpu_addr, r);
+ queue, queue->userq_vas.va_array[i], r);
}
if (r != 0)
@@ -309,35 +282,7 @@ static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
return false;
}
-static void amdgpu_userq_buffer_va_list_del(struct amdgpu_bo_va_mapping *mapping,
- struct amdgpu_userq_va_cursor *va_cursor)
-{
- atomic_set(&mapping->bo_va->userq_va_mapped, 0);
- list_del(&va_cursor->list);
- kfree(va_cursor);
-}
-
-static int amdgpu_userq_buffer_vas_list_cleanup(struct amdgpu_device *adev,
- struct amdgpu_usermode_queue *queue)
-{
- struct amdgpu_userq_va_cursor *va_cursor, *tmp;
- struct amdgpu_bo_va_mapping *mapping;
-
- /* Caller must hold vm->root.bo reservation */
- dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv);
-
- list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) {
- mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, va_cursor->gpu_addr);
- if (!mapping) {
- return -EINVAL;
- }
- dev_dbg(adev->dev, "delete the userq:%p va:%llx\n",
- queue, va_cursor->gpu_addr);
- amdgpu_userq_buffer_va_list_del(mapping, va_cursor);
- }
- return 0;
-}
static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue)
{
@@ -345,23 +290,18 @@ static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue)
struct amdgpu_device *adev = uq_mgr->adev;
const struct amdgpu_userq_funcs *userq_funcs =
adev->userq_funcs[queue->queue_type];
- bool found_hung_queue = false;
- int r = 0;
+ int r;
if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
r = userq_funcs->preempt(queue);
if (r) {
queue->state = AMDGPU_USERQ_STATE_HUNG;
- found_hung_queue = true;
+ return r;
} else {
queue->state = AMDGPU_USERQ_STATE_PREEMPTED;
}
}
-
- if (found_hung_queue)
- amdgpu_userq_detect_and_reset_queues(uq_mgr);
-
- return r;
+ return 0;
}
static int amdgpu_userq_restore_helper(struct amdgpu_usermode_queue *queue)
@@ -390,24 +330,21 @@ static int amdgpu_userq_unmap_helper(struct amdgpu_usermode_queue *queue)
struct amdgpu_device *adev = uq_mgr->adev;
const struct amdgpu_userq_funcs *userq_funcs =
adev->userq_funcs[queue->queue_type];
- bool found_hung_queue = false;
- int r = 0;
+ int r;
if ((queue->state == AMDGPU_USERQ_STATE_MAPPED) ||
- (queue->state == AMDGPU_USERQ_STATE_PREEMPTED)) {
+ (queue->state == AMDGPU_USERQ_STATE_PREEMPTED)) {
+
r = userq_funcs->unmap(queue);
if (r) {
queue->state = AMDGPU_USERQ_STATE_HUNG;
- found_hung_queue = true;
+ return r;
} else {
queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
}
}
- if (found_hung_queue)
- amdgpu_userq_detect_and_reset_queues(uq_mgr);
-
- return r;
+ return 0;
}
static int amdgpu_userq_map_helper(struct amdgpu_usermode_queue *queue)
@@ -416,19 +353,19 @@ static int amdgpu_userq_map_helper(struct amdgpu_usermode_queue *queue)
struct amdgpu_device *adev = uq_mgr->adev;
const struct amdgpu_userq_funcs *userq_funcs =
adev->userq_funcs[queue->queue_type];
- int r = 0;
+ int r;
if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
r = userq_funcs->map(queue);
if (r) {
queue->state = AMDGPU_USERQ_STATE_HUNG;
- amdgpu_userq_detect_and_reset_queues(uq_mgr);
+ return r;
} else {
queue->state = AMDGPU_USERQ_STATE_MAPPED;
}
}
- return r;
+ return 0;
}
static void amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue)
@@ -445,18 +382,14 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
{
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
- const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
/* Wait for mode-1 reset to complete */
down_read(&adev->reset_domain->sem);
- uq_funcs->mqd_destroy(queue);
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
amdgpu_userq_fence_driver_free(queue);
queue->fence_drv = NULL;
- queue->userq_mgr = NULL;
- list_del(&queue->userq_va_list);
up_read(&adev->reset_domain->sem);
}
@@ -495,74 +428,15 @@ retry:
dma_fence_put(ev_fence);
}
-int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
- struct amdgpu_userq_obj *userq_obj,
- int size)
-{
- struct amdgpu_device *adev = uq_mgr->adev;
- struct amdgpu_bo_param bp;
- int r;
-
- memset(&bp, 0, sizeof(bp));
- bp.byte_align = PAGE_SIZE;
- bp.domain = AMDGPU_GEM_DOMAIN_GTT;
- bp.flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
- AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
- bp.type = ttm_bo_type_kernel;
- bp.size = size;
- bp.resv = NULL;
- bp.bo_ptr_size = sizeof(struct amdgpu_bo);
-
- r = amdgpu_bo_create(adev, &bp, &userq_obj->obj);
- if (r) {
- drm_file_err(uq_mgr->file, "Failed to allocate BO for userqueue (%d)", r);
- return r;
- }
-
- r = amdgpu_bo_reserve(userq_obj->obj, true);
- if (r) {
- drm_file_err(uq_mgr->file, "Failed to reserve BO to map (%d)", r);
- goto free_obj;
- }
-
- r = amdgpu_ttm_alloc_gart(&(userq_obj->obj)->tbo);
- if (r) {
- drm_file_err(uq_mgr->file, "Failed to alloc GART for userqueue object (%d)", r);
- goto unresv;
- }
-
- r = amdgpu_bo_kmap(userq_obj->obj, &userq_obj->cpu_ptr);
- if (r) {
- drm_file_err(uq_mgr->file, "Failed to map BO for userqueue (%d)", r);
- goto unresv;
- }
-
- userq_obj->gpu_addr = amdgpu_bo_gpu_offset(userq_obj->obj);
- amdgpu_bo_unreserve(userq_obj->obj);
- memset(userq_obj->cpu_ptr, 0, size);
- return 0;
-
-unresv:
- amdgpu_bo_unreserve(userq_obj->obj);
-
-free_obj:
- amdgpu_bo_unref(&userq_obj->obj);
- return r;
-}
-void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
- struct amdgpu_userq_obj *userq_obj)
-{
- amdgpu_bo_kunmap(userq_obj->obj);
- amdgpu_bo_unref(&userq_obj->obj);
-}
-uint64_t
+static int
amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_db_info *db_info,
- struct drm_file *filp)
+ struct drm_file *filp,
+ u64 *index)
{
- uint64_t index;
+ u64 doorbell_index;
struct drm_gem_object *gobj;
struct amdgpu_userq_obj *db_obj = db_info->db_obj;
int r, db_size;
@@ -609,12 +483,13 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
goto unpin_bo;
}
- index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
- db_info->doorbell_offset, db_size);
+ doorbell_index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
+ db_info->doorbell_offset, db_size);
drm_dbg_driver(adev_to_drm(uq_mgr->adev),
- "[Usermode queues] doorbell index=%lld\n", index);
+ "[Usermode queues] doorbell index=%lld\n", doorbell_index);
amdgpu_bo_unreserve(db_obj->obj);
- return index;
+ *index = doorbell_index;
+ return 0;
unpin_bo:
amdgpu_bo_unpin(db_obj->obj);
@@ -629,9 +504,7 @@ static int
amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue)
{
struct amdgpu_device *adev = uq_mgr->adev;
- struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
- struct amdgpu_vm *vm = &fpriv->vm;
-
+ const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
int r = 0;
cancel_delayed_work_sync(&uq_mgr->resume_work);
@@ -639,36 +512,26 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
/* Cancel any pending hang detection work and cleanup */
cancel_delayed_work_sync(&queue->hang_detect_work);
- r = amdgpu_bo_reserve(vm->root.bo, false);
- if (r) {
- drm_file_err(uq_mgr->file, "Failed to reserve root bo during userqueue destroy\n");
- return r;
- }
- amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
- amdgpu_bo_unreserve(vm->root.bo);
-
mutex_lock(&uq_mgr->userq_mutex);
- queue->hang_detect_fence = NULL;
amdgpu_userq_wait_for_last_fence(queue);
#if defined(CONFIG_DEBUG_FS)
debugfs_remove_recursive(queue->debugfs_queue);
#endif
- amdgpu_userq_detect_and_reset_queues(uq_mgr);
r = amdgpu_userq_unmap_helper(queue);
atomic_dec(&uq_mgr->userq_count[queue->queue_type]);
amdgpu_userq_cleanup(queue);
mutex_unlock(&uq_mgr->userq_mutex);
+ cancel_delayed_work_sync(&queue->hang_detect_work);
+ uq_funcs->mqd_destroy(queue);
+ queue->userq_mgr = NULL;
+
amdgpu_bo_reserve(queue->db_obj.obj, true);
amdgpu_bo_unpin(queue->db_obj.obj);
amdgpu_bo_unreserve(queue->db_obj.obj);
amdgpu_bo_unref(&queue->db_obj.obj);
- amdgpu_bo_reserve(queue->wptr_obj.obj, true);
- amdgpu_bo_unpin(queue->wptr_obj.obj);
- amdgpu_bo_unreserve(queue->wptr_obj.obj);
- amdgpu_bo_unref(&queue->wptr_obj.obj);
kfree(queue);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@ -731,14 +594,14 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
const struct amdgpu_userq_funcs *uq_funcs;
struct amdgpu_usermode_queue *queue;
struct amdgpu_db_info db_info;
- bool skip_map_queue;
- u32 qid;
uint64_t index;
- int r = 0;
- int priority =
- (args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK) >>
- AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT;
+ int priority;
+ u32 qid;
+ int r;
+ priority =
+ (args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK)
+ >> AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT;
r = amdgpu_userq_priority_permit(filp, priority);
if (r)
return r;
@@ -751,128 +614,121 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
uq_funcs = adev->userq_funcs[args->in.ip_type];
if (!uq_funcs) {
- drm_file_err(uq_mgr->file, "Usermode queue is not supported for this IP (%u)\n",
- args->in.ip_type);
r = -EINVAL;
goto err_pm_runtime;
}
queue = kzalloc_obj(struct amdgpu_usermode_queue);
if (!queue) {
- drm_file_err(uq_mgr->file, "Failed to allocate memory for queue\n");
r = -ENOMEM;
goto err_pm_runtime;
}
- INIT_LIST_HEAD(&queue->userq_va_list);
+ kref_init(&queue->refcount);
queue->doorbell_handle = args->in.doorbell_handle;
queue->queue_type = args->in.ip_type;
queue->vm = &fpriv->vm;
queue->priority = priority;
-
- db_info.queue_type = queue->queue_type;
- db_info.doorbell_handle = queue->doorbell_handle;
- db_info.db_obj = &queue->db_obj;
- db_info.doorbell_offset = args->in.doorbell_offset;
-
queue->userq_mgr = uq_mgr;
+ INIT_DELAYED_WORK(&queue->hang_detect_work,
+ amdgpu_userq_hang_detect_work);
- /* Validate the userq virtual address.*/
- r = amdgpu_bo_reserve(fpriv->vm.root.bo, false);
+ r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv);
if (r)
goto free_queue;
- if (amdgpu_userq_input_va_validate(adev, queue, args->in.queue_va, args->in.queue_size) ||
- amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va, AMDGPU_GPU_PAGE_SIZE) ||
- amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va, AMDGPU_GPU_PAGE_SIZE)) {
+ xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
+ mutex_init(&queue->fence_drv_lock);
+ /* Make sure the queue can actually run with those virtual addresses. */
+ r = amdgpu_bo_reserve(fpriv->vm.root.bo, false);
+ if (r)
+ goto free_fence_drv;
+
+ if (amdgpu_userq_input_va_validate(adev, queue, args->in.queue_va,
+ args->in.queue_size,
+ &queue->userq_vas.va.queue_rb) ||
+ amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va,
+ AMDGPU_GPU_PAGE_SIZE,
+ &queue->userq_vas.va.rptr) ||
+ amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va,
+ AMDGPU_GPU_PAGE_SIZE,
+ &queue->userq_vas.va.wptr)) {
r = -EINVAL;
amdgpu_bo_unreserve(fpriv->vm.root.bo);
- goto clean_mapping;
+ goto free_fence_drv;
}
amdgpu_bo_unreserve(fpriv->vm.root.bo);
/* Convert relative doorbell offset into absolute doorbell index */
- index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp);
- if (index == (uint64_t)-EINVAL) {
+ db_info.queue_type = queue->queue_type;
+ db_info.doorbell_handle = queue->doorbell_handle;
+ db_info.db_obj = &queue->db_obj;
+ db_info.doorbell_offset = args->in.doorbell_offset;
+ r = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp, &index);
+ if (r) {
drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n");
- r = -EINVAL;
- goto clean_mapping;
+ goto free_fence_drv;
}
queue->doorbell_index = index;
- xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
- r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv);
- if (r) {
- drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n");
- goto clean_mapping;
- }
-
r = uq_funcs->mqd_create(queue, &args->in);
if (r) {
drm_file_err(uq_mgr->file, "Failed to create Queue\n");
- goto clean_fence_driver;
+ goto clean_doorbell_bo;
}
+ /* Update VM owner at userq submit-time for page-fault attribution. */
+ amdgpu_vm_set_task_info(&fpriv->vm);
+
+ r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue,
+ GFP_KERNEL));
+ if (r)
+ goto clean_mqd;
+
amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr);
/* don't map the queue if scheduling is halted */
- if (adev->userq_halt_for_enforce_isolation &&
- ((queue->queue_type == AMDGPU_HW_IP_GFX) ||
- (queue->queue_type == AMDGPU_HW_IP_COMPUTE)))
- skip_map_queue = true;
- else
- skip_map_queue = false;
- if (!skip_map_queue) {
+ if (!adev->userq_halt_for_enforce_isolation ||
+ ((queue->queue_type != AMDGPU_HW_IP_GFX) &&
+ (queue->queue_type != AMDGPU_HW_IP_COMPUTE))) {
r = amdgpu_userq_map_helper(queue);
if (r) {
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
- goto clean_mqd;
+ mutex_unlock(&uq_mgr->userq_mutex);
+ goto erase_doorbell;
}
}
- /* drop this refcount during queue destroy */
- kref_init(&queue->refcount);
-
- /* Wait for mode-1 reset to complete */
- down_read(&adev->reset_domain->sem);
+ atomic_inc(&uq_mgr->userq_count[queue->queue_type]);
+ mutex_unlock(&uq_mgr->userq_mutex);
r = xa_alloc(&uq_mgr->userq_xa, &qid, queue,
- XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT), GFP_KERNEL);
- if (r) {
- if (!skip_map_queue)
- amdgpu_userq_unmap_helper(queue);
- r = -ENOMEM;
- goto clean_reset_domain;
- }
-
- r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL));
+ XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT),
+ GFP_KERNEL);
if (r) {
- xa_erase(&uq_mgr->userq_xa, qid);
- if (!skip_map_queue)
- amdgpu_userq_unmap_helper(queue);
- goto clean_reset_domain;
+ /*
+ * This drops the last reference which should take care of
+ * all cleanup.
+ */
+ amdgpu_userq_put(queue);
+ return r;
}
- up_read(&adev->reset_domain->sem);
amdgpu_debugfs_userq_init(filp, queue, qid);
- amdgpu_userq_init_hang_detect_work(queue);
-
args->out.queue_id = qid;
- atomic_inc(&uq_mgr->userq_count[queue->queue_type]);
- mutex_unlock(&uq_mgr->userq_mutex);
return 0;
-clean_reset_domain:
- up_read(&adev->reset_domain->sem);
+erase_doorbell:
+ xa_erase_irq(&adev->userq_doorbell_xa, index);
clean_mqd:
- mutex_unlock(&uq_mgr->userq_mutex);
uq_funcs->mqd_destroy(queue);
-clean_fence_driver:
+clean_doorbell_bo:
+ amdgpu_bo_reserve(queue->db_obj.obj, true);
+ amdgpu_bo_unpin(queue->db_obj.obj);
+ amdgpu_bo_unreserve(queue->db_obj.obj);
+ amdgpu_bo_unref(&queue->db_obj.obj);
+free_fence_drv:
amdgpu_userq_fence_driver_free(queue);
-clean_mapping:
- amdgpu_bo_reserve(fpriv->vm.root.bo, true);
- amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
- amdgpu_bo_unreserve(fpriv->vm.root.bo);
free_queue:
kfree(queue);
err_pm_runtime:
@@ -1027,7 +883,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
continue;
}
- r = amdgpu_userq_restore_helper(queue);
+ r = amdgpu_userq_map_helper(queue);
if (r)
ret = r;
@@ -1262,37 +1118,23 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
unsigned long queue_id;
int ret = 0, r;
- amdgpu_userq_detect_and_reset_queues(uq_mgr);
/* Try to unmap all the queues in this process ctx */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
- r = amdgpu_userq_preempt_helper(queue);
+ r = amdgpu_userq_unmap_helper(queue);
if (r)
ret = r;
}
- if (ret)
+ if (ret) {
drm_file_err(uq_mgr->file,
"Couldn't unmap all the queues, eviction failed ret=%d\n", ret);
+ amdgpu_reset_domain_schedule(uq_mgr->adev->reset_domain,
+ &uq_mgr->reset_work);
+ flush_work(&uq_mgr->reset_work);
+ }
return ret;
}
-void amdgpu_userq_reset_work(struct work_struct *work)
-{
- struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
- userq_reset_work);
- struct amdgpu_reset_context reset_context;
-
- memset(&reset_context, 0, sizeof(reset_context));
-
- reset_context.method = AMD_RESET_METHOD_NONE;
- reset_context.reset_req_dev = adev;
- reset_context.src = AMDGPU_RESET_SRC_USERQ;
- set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
- /*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
-
- amdgpu_device_gpu_recover(adev, NULL, &reset_context);
-}
-
static void
amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
{
@@ -1326,9 +1168,24 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f
userq_mgr->file = file_priv;
INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker);
+ INIT_WORK(&userq_mgr->reset_work, amdgpu_userq_mgr_reset_work);
return 0;
}
+void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev)
+{
+ struct xarray *xa = &adev->userq_doorbell_xa;
+ struct amdgpu_usermode_queue *queue;
+ unsigned long flags, queue_id;
+
+ xa_lock_irqsave(xa, flags);
+ xa_for_each(xa, queue_id, queue) {
+ cancel_delayed_work(&queue->hang_detect_work);
+ cancel_work(&queue->userq_mgr->reset_work);
+ }
+ xa_unlock_irqrestore(xa, flags);
+}
+
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr)
{
cancel_delayed_work_sync(&userq_mgr->resume_work);
@@ -1354,6 +1211,14 @@ void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
}
xa_destroy(&userq_mgr->userq_xa);
+
+ /*
+ * Drain any in-flight reset_work. By this point all queues are freed
+ * and userq_count is 0, so if reset_work starts now it exits early.
+ * We still need to wait in case it was already executing gpu_recover.
+ */
+ cancel_work_sync(&userq_mgr->reset_work);
+
mutex_destroy(&userq_mgr->userq_mutex);
}
@@ -1372,7 +1237,6 @@ int amdgpu_userq_suspend(struct amdgpu_device *adev)
uqm = queue->userq_mgr;
cancel_delayed_work_sync(&uqm->resume_work);
guard(mutex)(&uqm->userq_mutex);
- amdgpu_userq_detect_and_reset_queues(uqm);
if (adev->in_s0ix)
r = amdgpu_userq_preempt_helper(queue);
else
@@ -1431,7 +1295,6 @@ int amdgpu_userq_stop_sched_for_enforce_isolation(struct amdgpu_device *adev,
if (((queue->queue_type == AMDGPU_HW_IP_GFX) ||
(queue->queue_type == AMDGPU_HW_IP_COMPUTE)) &&
(queue->xcp_id == idx)) {
- amdgpu_userq_detect_and_reset_queues(uqm);
r = amdgpu_userq_preempt_helper(queue);
if (r)
ret = r;
@@ -1477,8 +1340,7 @@ int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev,
}
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
- struct amdgpu_bo_va_mapping *mapping,
- uint64_t saddr)
+ struct amdgpu_bo_va_mapping *mapping)
{
u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
struct amdgpu_bo_va *bo_va = mapping->bo_va;
@@ -1487,12 +1349,9 @@ void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
if (!ip_mask)
return;
- dev_warn_once(adev->dev, "now unmapping a vital queue va:%llx\n", saddr);
/**
- * The userq VA mapping reservation should include the eviction fence,
- * if the eviction fence can't signal successfully during unmapping,
- * then driver will warn to flag this improper unmap of the userq VA.
- * Note: The eviction fence may be attached to different BOs, and this
+ * The userq VA mapping reservation should include the eviction fence.
+ * Note: The eviction fence may be attached to different BOs and this
* unmap is only for one kind of userq VAs, so at this point suppose
* the eviction fence is always unsignaled.
*/
@@ -1504,23 +1363,21 @@ void amdgpu_userq_pre_reset(struct amdgpu_device *adev)
{
const struct amdgpu_userq_funcs *userq_funcs;
struct amdgpu_usermode_queue *queue;
- struct amdgpu_userq_mgr *uqm;
unsigned long queue_id;
+ /* TODO: We probably need a new lock for the queue state */
xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
- uqm = queue->userq_mgr;
- cancel_delayed_work_sync(&uqm->resume_work);
- if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
- amdgpu_userq_wait_for_last_fence(queue);
- userq_funcs = adev->userq_funcs[queue->queue_type];
- userq_funcs->unmap(queue);
- /* just mark all queues as hung at this point.
- * if unmap succeeds, we could map again
- * in amdgpu_userq_post_reset() if vram is not lost
- */
- queue->state = AMDGPU_USERQ_STATE_HUNG;
- amdgpu_userq_fence_driver_force_completion(queue);
- }
+ if (queue->state != AMDGPU_USERQ_STATE_MAPPED)
+ continue;
+
+ userq_funcs = adev->userq_funcs[queue->queue_type];
+ userq_funcs->unmap(queue);
+ /* just mark all queues as hung at this point.
+ * if unmap succeeds, we could map again
+ * in amdgpu_userq_post_reset() if vram is not lost
+ */
+ queue->state = AMDGPU_USERQ_STATE_HUNG;
+ amdgpu_userq_fence_driver_force_completion(queue);
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
index 8b8f345b60b6..d1751febaefe 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
@@ -48,11 +48,6 @@ struct amdgpu_userq_obj {
struct amdgpu_bo *obj;
};
-struct amdgpu_userq_va_cursor {
- u64 gpu_addr;
- struct list_head list;
-};
-
struct amdgpu_usermode_queue {
int queue_type;
enum amdgpu_userq_state state;
@@ -66,17 +61,44 @@ struct amdgpu_usermode_queue {
struct amdgpu_userq_obj db_obj;
struct amdgpu_userq_obj fw_obj;
struct amdgpu_userq_obj wptr_obj;
+
+ /**
+ * @fence_drv_lock: Protecting @fence_drv_xa.
+ */
+ struct mutex fence_drv_lock;
+
+ /**
+ * @fence_drv_xa:
+ *
+ * References to the external fence drivers returned by wait_ioctl.
+ * Dropped on the next signaled dma_fence or queue destruction.
+ */
struct xarray fence_drv_xa;
struct amdgpu_userq_fence_driver *fence_drv;
struct dma_fence *last_fence;
u32 xcp_id;
int priority;
struct dentry *debugfs_queue;
- struct delayed_work hang_detect_work;
- struct dma_fence *hang_detect_fence;
+
+ /**
+ * @hang_detect_work:
+ *
+ * Delayed work which runs when userq_fences time out.
+ */
+ struct delayed_work hang_detect_work;
struct kref refcount;
- struct list_head userq_va_list;
+ union {
+ struct {
+ u64 queue_rb;
+ u64 wptr;
+ u64 rptr;
+ u64 eop;
+ u64 shadow;
+ u64 csa;
+ } va;
+ u64 va_array[6];
+ } userq_vas;
};
struct amdgpu_userq_funcs {
@@ -105,6 +127,13 @@ struct amdgpu_userq_mgr {
struct amdgpu_device *adev;
struct delayed_work resume_work;
struct drm_file *file;
+
+ /**
+ * @reset_work:
+ *
+ * Reset work which is used when eviction fails.
+ */
+ struct work_struct reset_work;
atomic_t userq_count[AMDGPU_RING_TYPE_MAX];
};
@@ -123,25 +152,15 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp
int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv,
struct amdgpu_device *adev);
+void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev);
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr);
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr);
-int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
- struct amdgpu_userq_obj *userq_obj,
- int size);
-
-void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
- struct amdgpu_userq_obj *userq_obj);
-
void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr);
void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr,
struct amdgpu_eviction_fence_mgr *evf_mgr);
-uint64_t amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
- struct amdgpu_db_info *db_info,
- struct drm_file *filp);
-
u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev);
bool amdgpu_userq_enabled(struct drm_device *dev);
@@ -160,8 +179,8 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell);
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
struct amdgpu_usermode_queue *queue,
- u64 addr, u64 expected_size);
+ u64 addr, u64 expected_size, u64 *va_out);
+
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
- struct amdgpu_bo_va_mapping *mapping,
- uint64_t saddr);
+ struct amdgpu_bo_va_mapping *mapping);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
index da39ac862f37..a41fb72dba94 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
@@ -32,29 +32,9 @@
#include "amdgpu.h"
#include "amdgpu_userq_fence.h"
-static const struct dma_fence_ops amdgpu_userq_fence_ops;
-static struct kmem_cache *amdgpu_userq_fence_slab;
-
#define AMDGPU_USERQ_MAX_HANDLES (1U << 16)
-int amdgpu_userq_fence_slab_init(void)
-{
- amdgpu_userq_fence_slab = kmem_cache_create("amdgpu_userq_fence",
- sizeof(struct amdgpu_userq_fence),
- 0,
- SLAB_HWCACHE_ALIGN,
- NULL);
- if (!amdgpu_userq_fence_slab)
- return -ENOMEM;
-
- return 0;
-}
-
-void amdgpu_userq_fence_slab_fini(void)
-{
- rcu_barrier();
- kmem_cache_destroy(amdgpu_userq_fence_slab);
-}
+static const struct dma_fence_ops amdgpu_userq_fence_ops;
static inline struct amdgpu_userq_fence *to_amdgpu_userq_fence(struct dma_fence *f)
{
@@ -141,6 +121,7 @@ amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq)
userq->last_fence = NULL;
amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa);
xa_destroy(&userq->fence_drv_xa);
+ mutex_destroy(&userq->fence_drv_lock);
/* Drop the queue's ownership reference to fence_drv explicitly */
amdgpu_userq_fence_driver_put(userq->fence_drv);
}
@@ -154,7 +135,14 @@ amdgpu_userq_fence_put_fence_drv_array(struct amdgpu_userq_fence *userq_fence)
userq_fence->fence_drv_array_count = 0;
}
-void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv)
+/*
+ * Returns:
+ * -ENOENT when no fences were processes
+ * 1 when more fences are pending
+ * 0 when no fences are pending any more
+ */
+int
+amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv)
{
struct amdgpu_userq_fence *userq_fence, *tmp;
LIST_HEAD(to_be_signaled);
@@ -162,9 +150,6 @@ void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_d
unsigned long flags;
u64 rptr;
- if (!fence_drv)
- return;
-
spin_lock_irqsave(&fence_drv->fence_list_lock, flags);
rptr = amdgpu_userq_fence_read(fence_drv);
@@ -177,6 +162,9 @@ void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_d
&userq_fence->link);
spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags);
+ if (list_empty(&to_be_signaled))
+ return -ENOENT;
+
list_for_each_entry_safe(userq_fence, tmp, &to_be_signaled, link) {
fence = &userq_fence->base;
list_del_init(&userq_fence->link);
@@ -188,6 +176,8 @@ void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_d
dma_fence_put(fence);
}
+ /* That doesn't need to be accurate so no locking */
+ return list_empty(&fence_drv->fences) ? 0 : 1;
}
void amdgpu_userq_fence_driver_destroy(struct kref *ref)
@@ -229,80 +219,84 @@ void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv)
kref_put(&fence_drv->refcount, amdgpu_userq_fence_driver_destroy);
}
-static int amdgpu_userq_fence_alloc(struct amdgpu_userq_fence **userq_fence)
+static int amdgpu_userq_fence_alloc(struct amdgpu_usermode_queue *userq,
+ struct amdgpu_userq_fence **pfence)
{
- *userq_fence = kmem_cache_alloc(amdgpu_userq_fence_slab, GFP_ATOMIC);
- return *userq_fence ? 0 : -ENOMEM;
+ struct amdgpu_userq_fence_driver *fence_drv = userq->fence_drv;
+ struct amdgpu_userq_fence *userq_fence;
+ void *entry;
+
+ userq_fence = kmalloc(sizeof(*userq_fence), GFP_KERNEL);
+ if (!userq_fence)
+ return -ENOMEM;
+
+ /*
+ * Get the next unused entry, since we fill from the start this can be
+ * used as size to allocate the array.
+ */
+ mutex_lock(&userq->fence_drv_lock);
+ XA_STATE(xas, &userq->fence_drv_xa, 0);
+
+ rcu_read_lock();
+ do {
+ entry = xas_find_marked(&xas, ULONG_MAX, XA_FREE_MARK);
+ } while (xas_retry(&xas, entry));
+ rcu_read_unlock();
+
+ userq_fence->fence_drv_array = kvmalloc_array(xas.xa_index,
+ sizeof(fence_drv),
+ GFP_KERNEL);
+ if (!userq_fence->fence_drv_array) {
+ mutex_unlock(&userq->fence_drv_lock);
+ kfree(userq_fence);
+ return -ENOMEM;
+ }
+
+ userq_fence->fence_drv_array_count = xas.xa_index;
+ xa_extract(&userq->fence_drv_xa, (void **)userq_fence->fence_drv_array,
+ 0, ULONG_MAX, xas.xa_index, XA_PRESENT);
+ xa_destroy(&userq->fence_drv_xa);
+
+ mutex_unlock(&userq->fence_drv_lock);
+
+ amdgpu_userq_fence_driver_get(fence_drv);
+ userq_fence->fence_drv = fence_drv;
+
+ *pfence = userq_fence;
+ return 0;
}
-static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq,
- struct amdgpu_userq_fence *userq_fence,
- u64 seq, struct dma_fence **f)
+static void amdgpu_userq_fence_init(struct amdgpu_usermode_queue *userq,
+ struct amdgpu_userq_fence *fence,
+ u64 seq)
{
- struct amdgpu_userq_fence_driver *fence_drv;
- struct dma_fence *fence;
+ struct amdgpu_userq_fence_driver *fence_drv = userq->fence_drv;
unsigned long flags;
bool signaled = false;
- fence_drv = userq->fence_drv;
- if (!fence_drv)
- return -EINVAL;
-
- spin_lock_init(&userq_fence->lock);
- INIT_LIST_HEAD(&userq_fence->link);
- fence = &userq_fence->base;
- userq_fence->fence_drv = fence_drv;
-
- dma_fence_init64(fence, &amdgpu_userq_fence_ops, &userq_fence->lock,
+ spin_lock_init(&fence->lock);
+ dma_fence_init64(&fence->base, &amdgpu_userq_fence_ops, &fence->lock,
fence_drv->context, seq);
- amdgpu_userq_fence_driver_get(fence_drv);
- dma_fence_get(fence);
-
- if (!xa_empty(&userq->fence_drv_xa)) {
- struct amdgpu_userq_fence_driver *stored_fence_drv;
- unsigned long index, count = 0;
- int i = 0;
-
- xa_lock(&userq->fence_drv_xa);
- xa_for_each(&userq->fence_drv_xa, index, stored_fence_drv)
- count++;
-
- userq_fence->fence_drv_array =
- kvmalloc_objs(struct amdgpu_userq_fence_driver *, count,
- GFP_ATOMIC);
-
- if (userq_fence->fence_drv_array) {
- xa_for_each(&userq->fence_drv_xa, index, stored_fence_drv) {
- userq_fence->fence_drv_array[i] = stored_fence_drv;
- __xa_erase(&userq->fence_drv_xa, index);
- i++;
- }
- }
-
- userq_fence->fence_drv_array_count = i;
- xa_unlock(&userq->fence_drv_xa);
- } else {
- userq_fence->fence_drv_array = NULL;
- userq_fence->fence_drv_array_count = 0;
- }
+ /* Make sure the fence is visible to the hang detect worker */
+ dma_fence_put(userq->last_fence);
+ userq->last_fence = dma_fence_get(&fence->base);
- /* Check if hardware has already processed the job */
+ /* Check if hardware has already processed the fence */
spin_lock_irqsave(&fence_drv->fence_list_lock, flags);
- if (!dma_fence_is_signaled(fence)) {
- list_add_tail(&userq_fence->link, &fence_drv->fences);
+ if (!dma_fence_is_signaled(&fence->base)) {
+ dma_fence_get(&fence->base);
+ list_add_tail(&fence->link, &fence_drv->fences);
} else {
+ INIT_LIST_HEAD(&fence->link);
signaled = true;
- dma_fence_put(fence);
}
spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags);
if (signaled)
- amdgpu_userq_fence_put_fence_drv_array(userq_fence);
-
- *f = fence;
-
- return 0;
+ amdgpu_userq_fence_put_fence_drv_array(fence);
+ else
+ amdgpu_userq_start_hang_detect_work(userq);
}
static const char *amdgpu_userq_fence_get_driver_name(struct dma_fence *f)
@@ -342,7 +336,7 @@ static void amdgpu_userq_fence_free(struct rcu_head *rcu)
amdgpu_userq_fence_driver_put(fence_drv);
kvfree(userq_fence->fence_drv_array);
- kmem_cache_free(amdgpu_userq_fence_slab, userq_fence);
+ kfree(userq_fence);
}
static void amdgpu_userq_fence_release(struct dma_fence *f)
@@ -376,56 +370,48 @@ static int amdgpu_userq_fence_read_wptr(struct amdgpu_device *adev,
{
struct amdgpu_bo_va_mapping *mapping;
struct amdgpu_bo *bo;
+ struct drm_exec exec;
u64 addr, *ptr;
- int r;
-
- r = amdgpu_bo_reserve(queue->vm->root.bo, false);
- if (r)
- return r;
+ int ret;
addr = queue->userq_prop->wptr_gpu_addr;
addr &= AMDGPU_GMC_HOLE_MASK;
- mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, addr >> PAGE_SHIFT);
- if (!mapping) {
- amdgpu_bo_unreserve(queue->vm->root.bo);
- DRM_ERROR("Failed to lookup amdgpu_bo_va_mapping\n");
- return -EINVAL;
- }
+ drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 2);
+ drm_exec_until_all_locked(&exec) {
+ ret = amdgpu_vm_lock_pd(queue->vm, &exec, 1);
+ drm_exec_retry_on_contention(&exec);
+ if (unlikely(ret))
+ goto lock_error;
+
+ mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, addr >> PAGE_SHIFT);
+ if (!mapping) {
+ ret = -EINVAL;
+ goto lock_error;
+ }
- bo = amdgpu_bo_ref(mapping->bo_va->base.bo);
- amdgpu_bo_unreserve(queue->vm->root.bo);
- r = amdgpu_bo_reserve(bo, true);
- if (r) {
- amdgpu_bo_unref(&bo);
- DRM_ERROR("Failed to reserve userqueue wptr bo");
- return r;
+ ret = drm_exec_lock_obj(&exec, &mapping->bo_va->base.bo->tbo.base);
+ drm_exec_retry_on_contention(&exec);
+ if (unlikely(ret))
+ goto lock_error;
}
- r = amdgpu_bo_kmap(bo, (void **)&ptr);
- if (r) {
+ bo = mapping->bo_va->base.bo;
+ ret = amdgpu_bo_kmap(bo, (void **)&ptr);
+ if (ret) {
DRM_ERROR("Failed mapping the userqueue wptr bo");
- goto map_error;
+ goto lock_error;
}
*wptr = le64_to_cpu(*ptr);
amdgpu_bo_kunmap(bo);
- amdgpu_bo_unreserve(bo);
- amdgpu_bo_unref(&bo);
-
+ drm_exec_fini(&exec);
return 0;
-map_error:
- amdgpu_bo_unreserve(bo);
- amdgpu_bo_unref(&bo);
-
- return r;
-}
-
-static void amdgpu_userq_fence_cleanup(struct dma_fence *fence)
-{
- dma_fence_put(fence);
+lock_error:
+ drm_exec_fini(&exec);
+ return ret;
}
static void
@@ -471,13 +457,14 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
const unsigned int num_read_bo_handles = args->num_bo_read_handles;
struct amdgpu_fpriv *fpriv = filp->driver_priv;
struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr;
+
struct drm_gem_object **gobj_write, **gobj_read;
u32 *syncobj_handles, num_syncobj_handles;
- struct amdgpu_userq_fence *userq_fence;
- struct amdgpu_usermode_queue *queue = NULL;
- struct drm_syncobj **syncobj = NULL;
- struct dma_fence *fence;
+ struct amdgpu_usermode_queue *queue;
+ struct amdgpu_userq_fence *fence;
+ struct drm_syncobj **syncobj;
struct drm_exec exec;
+ void __user *ptr;
int r, i, entry;
u64 wptr;
@@ -489,13 +476,14 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
num_syncobj_handles = args->num_syncobj_handles;
- syncobj_handles = memdup_array_user(u64_to_user_ptr(args->syncobj_handles),
- num_syncobj_handles, sizeof(u32));
+ ptr = u64_to_user_ptr(args->syncobj_handles);
+ syncobj_handles = memdup_array_user(ptr, num_syncobj_handles,
+ sizeof(u32));
if (IS_ERR(syncobj_handles))
return PTR_ERR(syncobj_handles);
- /* Array of pointers to the looked up syncobjs */
- syncobj = kmalloc_array(num_syncobj_handles, sizeof(*syncobj), GFP_KERNEL);
+ syncobj = kmalloc_array(num_syncobj_handles, sizeof(*syncobj),
+ GFP_KERNEL);
if (!syncobj) {
r = -ENOMEM;
goto free_syncobj_handles;
@@ -509,21 +497,17 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
}
}
- r = drm_gem_objects_lookup(filp,
- u64_to_user_ptr(args->bo_read_handles),
- num_read_bo_handles,
- &gobj_read);
+ ptr = u64_to_user_ptr(args->bo_read_handles);
+ r = drm_gem_objects_lookup(filp, ptr, num_read_bo_handles, &gobj_read);
if (r)
goto free_syncobj;
- r = drm_gem_objects_lookup(filp,
- u64_to_user_ptr(args->bo_write_handles),
- num_write_bo_handles,
+ ptr = u64_to_user_ptr(args->bo_write_handles);
+ r = drm_gem_objects_lookup(filp, ptr, num_write_bo_handles,
&gobj_write);
if (r)
goto put_gobj_read;
- /* Retrieve the user queue */
queue = amdgpu_userq_get(userq_mgr, args->queue_id);
if (!queue) {
r = -ENOENT;
@@ -532,73 +516,61 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
r = amdgpu_userq_fence_read_wptr(adev, queue, &wptr);
if (r)
- goto put_gobj_write;
+ goto put_queue;
- r = amdgpu_userq_fence_alloc(&userq_fence);
+ r = amdgpu_userq_fence_alloc(queue, &fence);
if (r)
- goto put_gobj_write;
+ goto put_queue;
/* We are here means UQ is active, make sure the eviction fence is valid */
amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr);
- /* Create a new fence */
- r = amdgpu_userq_fence_create(queue, userq_fence, wptr, &fence);
- if (r) {
- mutex_unlock(&userq_mgr->userq_mutex);
- kmem_cache_free(amdgpu_userq_fence_slab, userq_fence);
- goto put_gobj_write;
- }
+ /* Create the new fence */
+ amdgpu_userq_fence_init(queue, fence, wptr);
- dma_fence_put(queue->last_fence);
- queue->last_fence = dma_fence_get(fence);
- amdgpu_userq_start_hang_detect_work(queue);
mutex_unlock(&userq_mgr->userq_mutex);
+ /*
+ * This needs to come after the fence is created since
+ * amdgpu_userq_ensure_ev_fence() can't be called while holding the resv
+ * locks.
+ */
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
(num_read_bo_handles + num_write_bo_handles));
- /* Lock all BOs with retry handling */
drm_exec_until_all_locked(&exec) {
- r = drm_exec_prepare_array(&exec, gobj_read, num_read_bo_handles, 1);
+ r = drm_exec_prepare_array(&exec, gobj_read,
+ num_read_bo_handles, 1);
drm_exec_retry_on_contention(&exec);
- if (r) {
- amdgpu_userq_fence_cleanup(fence);
+ if (r)
goto exec_fini;
- }
- r = drm_exec_prepare_array(&exec, gobj_write, num_write_bo_handles, 1);
+ r = drm_exec_prepare_array(&exec, gobj_write,
+ num_write_bo_handles, 1);
drm_exec_retry_on_contention(&exec);
- if (r) {
- amdgpu_userq_fence_cleanup(fence);
+ if (r)
goto exec_fini;
- }
}
- for (i = 0; i < num_read_bo_handles; i++) {
- if (!gobj_read || !gobj_read[i]->resv)
- continue;
-
- dma_resv_add_fence(gobj_read[i]->resv, fence,
+ /* And publish the new fence in the BOs and syncobj */
+ for (i = 0; i < num_read_bo_handles; i++)
+ dma_resv_add_fence(gobj_read[i]->resv, &fence->base,
DMA_RESV_USAGE_READ);
- }
- for (i = 0; i < num_write_bo_handles; i++) {
- if (!gobj_write || !gobj_write[i]->resv)
- continue;
-
- dma_resv_add_fence(gobj_write[i]->resv, fence,
+ for (i = 0; i < num_write_bo_handles; i++)
+ dma_resv_add_fence(gobj_write[i]->resv, &fence->base,
DMA_RESV_USAGE_WRITE);
- }
- /* Add the created fence to syncobj/BO's */
for (i = 0; i < num_syncobj_handles; i++)
- drm_syncobj_replace_fence(syncobj[i], fence);
+ drm_syncobj_replace_fence(syncobj[i], &fence->base);
+exec_fini:
/* drop the reference acquired in fence creation function */
- dma_fence_put(fence);
+ dma_fence_put(&fence->base);
-exec_fini:
drm_exec_fini(&exec);
+put_queue:
+ amdgpu_userq_put(queue);
put_gobj_write:
for (i = 0; i < num_write_bo_handles; i++)
drm_gem_object_put(gobj_write[i]);
@@ -609,15 +581,11 @@ put_gobj_read:
kvfree(gobj_read);
free_syncobj:
while (entry-- > 0)
- if (syncobj[entry])
- drm_syncobj_put(syncobj[entry]);
+ drm_syncobj_put(syncobj[entry]);
kfree(syncobj);
free_syncobj_handles:
kfree(syncobj_handles);
- if (queue)
- amdgpu_userq_put(queue);
-
return r;
}
@@ -892,8 +860,10 @@ amdgpu_userq_wait_return_fence_info(struct drm_file *filp,
* Otherwise, we would gather those references until we don't
* have any more space left and crash.
*/
+ mutex_lock(&waitq->fence_drv_lock);
r = xa_alloc(&waitq->fence_drv_xa, &index, fence_drv,
xa_limit_32b, GFP_KERNEL);
+ mutex_unlock(&waitq->fence_drv_lock);
if (r)
goto put_waitq;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h
index d56246ad8c26..0bd51616cef1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h
@@ -58,15 +58,12 @@ struct amdgpu_userq_fence_driver {
char timeline_name[TASK_COMM_LEN];
};
-int amdgpu_userq_fence_slab_init(void);
-void amdgpu_userq_fence_slab_fini(void);
-
void amdgpu_userq_fence_driver_get(struct amdgpu_userq_fence_driver *fence_drv);
void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv);
int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev,
struct amdgpu_userq_fence_driver **fence_drv_req);
void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq);
-void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv);
+int amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv);
void amdgpu_userq_fence_driver_force_completion(struct amdgpu_usermode_queue *userq);
void amdgpu_userq_fence_driver_destroy(struct kref *ref);
int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 9ba9de16a27a..381901bc539f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1631,6 +1631,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
{
struct amdgpu_bo_va *bo_va;
struct dma_resv *resv;
+ struct amdgpu_bo *bo;
bool clear, unlock;
int r;
@@ -1650,11 +1651,13 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
while (!list_empty(&vm->invalidated)) {
bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
base.vm_status);
- resv = bo_va->base.bo->tbo.base.resv;
+ bo = bo_va->base.bo;
+ resv = bo->tbo.base.resv;
spin_unlock(&vm->status_lock);
/* Try to reserve the BO to avoid clearing its ptes */
- if (!adev->debug_vm && dma_resv_trylock(resv)) {
+ if (!adev->debug_vm && !amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
+ dma_resv_trylock(resv)) {
clear = false;
unlock = true;
/* The caller is already holding the reservation lock */
@@ -2002,8 +2005,8 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
* during user requests GEM unmap IOCTL except for forcing the unmap
* from user space.
*/
- if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0))
- amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
+ if (unlikely(bo_va->userq_va_mapped))
+ amdgpu_userq_gem_va_unmap_validate(adev, mapping);
list_del(&mapping->list);
amdgpu_vm_it_remove(mapping, &vm->va);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
index fd881388d612..f27f917e3cdb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
@@ -562,6 +562,11 @@ static void vpe_ring_emit_fence(struct amdgpu_ring *ring, uint64_t addr,
amdgpu_ring_write(ring, 0);
}
+ /* WA: Force sync after TRAP to avoid VPE1 fail to power off */
+ if (ring->adev->vpe.collaborate_mode) {
+ amdgpu_ring_write(ring, VPE_CMD_HEADER(VPE_CMD_OPCODE_COLLAB_SYNC, 0));
+ amdgpu_ring_write(ring, 0xabcd);
+ }
}
static void vpe_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
@@ -968,7 +973,7 @@ static const struct amdgpu_ring_funcs vpe_ring_funcs = {
.emit_frame_size =
5 + /* vpe_ring_init_cond_exec */
6 + /* vpe_ring_emit_pipeline_sync */
- 10 + 10 + 10 + /* vpe_ring_emit_fence */
+ 12 + 12 + 12 + /* vpe_ring_emit_fence */
/* vpe_ring_emit_vm_flush */
SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index 0e0b1e5b88fc..c35372e21261 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -602,6 +602,13 @@ static int gfx_v12_0_init_microcode(struct amdgpu_device *adev)
"amdgpu/%s_pfp.bin", ucode_prefix);
if (err)
goto out;
+
+ adev->gfx.rs64_enable = amdgpu_ucode_hdr_version(
+ (union amdgpu_firmware_header *)
+ adev->gfx.pfp_fw->data, 2, 0);
+ if (adev->gfx.rs64_enable)
+ dev_dbg(adev->dev, "CP RS64 enable\n");
+
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_PFP);
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_RS64_PFP_P0_STACK);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 95be105671ec..86c7c2a429b7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -5660,9 +5660,6 @@ static void gfx_v9_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
{
struct amdgpu_device *adev = ring->adev;
- /* we only allocate 32bit for each seq wb address */
- BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
-
/* write fence seq to the "addr" */
amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v11_5_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v11_5_0.c
index f9949fedfbb9..f2fe6f5bc7f7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v11_5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v11_5_0.c
@@ -449,12 +449,10 @@ static void gfxhub_v11_5_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_0.c
index 7609b9cecae8..efcaca70c27a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_0.c
@@ -454,12 +454,10 @@ static void gfxhub_v12_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c
index 3544eb42dca6..4c2fd1e6616e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v12_1.c
@@ -633,19 +633,17 @@ static void gfxhub_v12_1_xcc_set_fault_enable_default(struct amdgpu_device *adev
tmp = REG_SET_FIELD(tmp,
GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
OTHER_CLIENT_ID_NO_RETRY_FAULT_INTERRUPT, value);
- if (!value)
- tmp = REG_SET_FIELD(tmp,
- GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
- CRASH_ON_NO_RETRY_FAULT, 1);
+ tmp = REG_SET_FIELD(tmp,
+ GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
+ CRASH_ON_NO_RETRY_FAULT, !value);
WREG32_SOC15(GC, GET_INST(GC, i),
regGCVM_L2_PROTECTION_FAULT_CNTL_LO32, tmp);
tmp = RREG32_SOC15(GC, GET_INST(GC, i),
regGCVM_L2_PROTECTION_FAULT_CNTL_HI32);
- if (!value)
- tmp = REG_SET_FIELD(tmp,
- GCVM_L2_PROTECTION_FAULT_CNTL_HI32,
- CRASH_ON_RETRY_FAULT, 1);
+ tmp = REG_SET_FIELD(tmp,
+ GCVM_L2_PROTECTION_FAULT_CNTL_HI32,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, GET_INST(GC, i),
regGCVM_L2_PROTECTION_FAULT_CNTL_HI32, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
index a7bfc9f41d0e..bfe247b1a333 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
@@ -403,12 +403,10 @@ static void gfxhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, mmVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c
index 6c03bf9f1ae8..fbdf46070b38 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c
@@ -516,12 +516,10 @@ static void gfxhub_v1_2_xcc_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, GET_INST(GC, i), regVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
index 793faf62cb07..9ea593e2c719 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
@@ -418,12 +418,10 @@ static void gfxhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
index aceb8447feac..30b90d35abd0 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
@@ -449,12 +449,10 @@ static void gfxhub_v2_1_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c
index abe30c8bd2ba..f089f70571aa 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c
@@ -446,12 +446,10 @@ static void gfxhub_v3_0_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
index b3ef6e71811f..128115a2cb45 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
@@ -434,12 +434,10 @@ static void gfxhub_v3_0_3_set_fault_enable_default(struct amdgpu_device *adev,
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
- if (!value) {
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_NO_RETRY_FAULT, 1);
- tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
- CRASH_ON_RETRY_FAULT, 1);
- }
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_NO_RETRY_FAULT, !value);
+ tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
+ CRASH_ON_RETRY_FAULT, !value);
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
index e1ace7d44ffd..f5bdfea54afa 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -847,6 +847,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
+ adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
index 94d6631ce0bc..807bd180b9d4 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
@@ -821,6 +821,7 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
+ adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
index e10ac9788d13..8dc9c053897b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
@@ -812,8 +812,9 @@ static int gmc_v12_0_gart_init(struct amdgpu_device *adev)
static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
{
- int r, vram_width = 0, vram_type = 0, vram_vendor = 0;
+ int r, vram_width = 0, vram_type = 0, vram_vendor = 0, dma_addr_bits;
struct amdgpu_device *adev = ip_block->adev;
+ uint64_t pte_addr_mask = 0;
int i;
adev->mmhub.funcs->init(adev);
@@ -843,6 +844,8 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
* block size 512 (9bit)
*/
amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
+ pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
+ dma_addr_bits = 44;
break;
case IP_VERSION(12, 1, 0):
bitmap_set(adev->vmhubs_mask, AMDGPU_GFXHUB(0),
@@ -855,9 +858,13 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
* block size 512 (9bit)
*/
amdgpu_vm_adjust_size(adev, 128 * 1024 * 1024, 9, 4, 57);
+ pte_addr_mask = 0x000FFFFFFFFFF000ULL; /* 52 bit PA */
+ dma_addr_bits = 52;
break;
default:
- break;
+ dev_warn(adev->dev, "Unrecognized GC IP version: 0x%08x\n",
+ amdgpu_ip_version(adev, GC_HWIP, 0));
+ return -EINVAL;
}
/* This interrupt is VMC page fault.*/
@@ -911,14 +918,15 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = AMDGPU_GMC_HOLE_MASK;
+ adev->gmc.pte_addr_mask = pte_addr_mask;
- r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
+ r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(dma_addr_bits));
if (r) {
drm_warn(adev_to_drm(adev), "No suitable DMA available.\n");
return r;
}
- adev->need_swiotlb = drm_need_swiotlb(44);
+ adev->need_swiotlb = drm_need_swiotlb(dma_addr_bits);
r = gmc_v12_0_mc_init(adev);
if (r)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index cc272a96fcef..6aa581b1c148 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -836,6 +836,7 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
amdgpu_vm_adjust_size(adev, 64, 9, 1, 40);
adev->gmc.mc_mask = 0xffffffffffULL;
+ adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL;
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index bb16ba2ef6fd..2b0362c4d9eb 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -1016,6 +1016,7 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
+ adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL; /* 40 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index a59174f6bcc1..fbccfcb3d7cf 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -1131,6 +1131,7 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
+ adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL; /* 40 bit PA */
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index e7b78027002b..c6dbe25f2bd9 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -1994,6 +1994,7 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
* internal address space.
*/
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
+ adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
dma_addr_bits = amdgpu_ip_version(adev, GC_HWIP, 0) >=
IP_VERSION(9, 4, 2) ?
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
index 2fc39a6938f6..4cbd46f53e85 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
@@ -31,89 +31,70 @@
#define AMDGPU_USERQ_GANG_CTX_SZ PAGE_SIZE
static int
-mes_userq_map_gtt_bo_to_gart(struct amdgpu_bo *bo)
-{
- int ret;
-
- ret = amdgpu_bo_reserve(bo, true);
- if (ret) {
- DRM_ERROR("Failed to reserve bo. ret %d\n", ret);
- goto err_reserve_bo_failed;
- }
-
- ret = amdgpu_ttm_alloc_gart(&bo->tbo);
- if (ret) {
- DRM_ERROR("Failed to bind bo to GART. ret %d\n", ret);
- goto err_map_bo_gart_failed;
- }
-
- amdgpu_bo_unreserve(bo);
- bo = amdgpu_bo_ref(bo);
-
- return 0;
-
-err_map_bo_gart_failed:
- amdgpu_bo_unreserve(bo);
-err_reserve_bo_failed:
- return ret;
-}
-
-static int
mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_usermode_queue *queue,
uint64_t wptr)
{
struct amdgpu_bo_va_mapping *wptr_mapping;
- struct amdgpu_vm *wptr_vm;
struct amdgpu_userq_obj *wptr_obj = &queue->wptr_obj;
+ struct amdgpu_bo *obj;
+ struct amdgpu_vm *vm = queue->vm;
+ struct drm_exec exec;
int ret;
- wptr_vm = queue->vm;
- ret = amdgpu_bo_reserve(wptr_vm->root.bo, false);
- if (ret)
- return ret;
-
wptr &= AMDGPU_GMC_HOLE_MASK;
- wptr_mapping = amdgpu_vm_bo_lookup_mapping(wptr_vm, wptr >> PAGE_SHIFT);
- amdgpu_bo_unreserve(wptr_vm->root.bo);
- if (!wptr_mapping) {
- DRM_ERROR("Failed to lookup wptr bo\n");
- return -EINVAL;
- }
- wptr_obj->obj = wptr_mapping->bo_va->base.bo;
- if (wptr_obj->obj->tbo.base.size > PAGE_SIZE) {
- DRM_ERROR("Requested GART mapping for wptr bo larger than one page\n");
- return -EINVAL;
- }
+ drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 2);
+ drm_exec_until_all_locked(&exec) {
+ ret = amdgpu_vm_lock_pd(vm, &exec, 1);
+ drm_exec_retry_on_contention(&exec);
+ if (unlikely(ret))
+ goto fail_lock;
+
+ wptr_mapping = amdgpu_vm_bo_lookup_mapping(vm, wptr >> PAGE_SHIFT);
+ if (!wptr_mapping) {
+ ret = -EINVAL;
+ goto fail_lock;
+ }
- ret = mes_userq_map_gtt_bo_to_gart(wptr_obj->obj);
- if (ret) {
- DRM_ERROR("Failed to map wptr bo to GART\n");
- return ret;
+ obj = wptr_mapping->bo_va->base.bo;
+ ret = drm_exec_lock_obj(&exec, &obj->tbo.base);
+ drm_exec_retry_on_contention(&exec);
+ if (unlikely(ret))
+ goto fail_lock;
}
- ret = amdgpu_bo_reserve(wptr_obj->obj, true);
- if (ret) {
- DRM_ERROR("Failed to reserve wptr bo\n");
- return ret;
+ wptr_obj->obj = amdgpu_bo_ref(wptr_mapping->bo_va->base.bo);
+ if (wptr_obj->obj->tbo.base.size > PAGE_SIZE) {
+ ret = -EINVAL;
+ goto fail_map;
}
/* TODO use eviction fence instead of pinning. */
ret = amdgpu_bo_pin(wptr_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
if (ret) {
- drm_file_err(uq_mgr->file, "[Usermode queues] Failed to pin wptr bo\n");
- goto unresv_bo;
+ DRM_ERROR("Failed to pin wptr bo. ret %d\n", ret);
+ goto fail_map;
+ }
+
+ ret = amdgpu_ttm_alloc_gart(&wptr_obj->obj->tbo);
+ if (ret) {
+ DRM_ERROR("Failed to bind bo to GART. ret %d\n", ret);
+ goto fail_alloc_gart;
}
queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(wptr_obj->obj);
- amdgpu_bo_unreserve(wptr_obj->obj);
+ drm_exec_fini(&exec);
return 0;
-unresv_bo:
- amdgpu_bo_unreserve(wptr_obj->obj);
+fail_alloc_gart:
+ amdgpu_bo_unpin(wptr_obj->obj);
+fail_map:
+ amdgpu_bo_unref(&wptr_obj->obj);
+fail_lock:
+ drm_exec_fini(&exec);
return ret;
}
@@ -211,12 +192,16 @@ static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr,
* for the same.
*/
size = AMDGPU_USERQ_PROC_CTX_SZ + AMDGPU_USERQ_GANG_CTX_SZ;
- r = amdgpu_userq_create_object(uq_mgr, ctx, size);
+ r = amdgpu_bo_create_kernel(uq_mgr->adev, size, 0,
+ AMDGPU_GEM_DOMAIN_GTT,
+ &ctx->obj, &ctx->gpu_addr,
+ &ctx->cpu_ptr);
if (r) {
DRM_ERROR("Failed to allocate ctx space bo for userqueue, err:%d\n", r);
return r;
}
+ memset(ctx->cpu_ptr, 0, size);
return 0;
}
@@ -289,13 +274,19 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
return -ENOMEM;
}
- r = amdgpu_userq_create_object(uq_mgr, &queue->mqd,
- AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size));
+ r = amdgpu_bo_create_kernel(adev,
+ AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size),
+ 0, AMDGPU_GEM_DOMAIN_GTT,
+ &queue->mqd.obj, &queue->mqd.gpu_addr,
+ &queue->mqd.cpu_ptr);
if (r) {
DRM_ERROR("Failed to create MQD object for userqueue\n");
goto free_props;
}
+ memset(queue->mqd.cpu_ptr, 0,
+ AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size));
+
/* Initialize the MQD BO with user given values */
userq_props->wptr_gpu_addr = mqd_user->wptr_va;
userq_props->rptr_gpu_addr = mqd_user->rptr_va;
@@ -327,8 +318,9 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
kfree(compute_mqd);
goto free_mqd;
}
- r = amdgpu_userq_input_va_validate(adev, queue, compute_mqd->eop_va,
- 2048);
+ r = amdgpu_userq_input_va_validate(adev, queue,
+ compute_mqd->eop_va, 2048,
+ &queue->userq_vas.va.eop);
amdgpu_bo_unreserve(queue->vm->root.bo);
if (r) {
kfree(compute_mqd);
@@ -377,7 +369,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
goto free_mqd;
}
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->shadow_va,
- shadow_info.shadow_size);
+ shadow_info.shadow_size,
+ &queue->userq_vas.va.shadow);
if (r) {
amdgpu_bo_unreserve(queue->vm->root.bo);
kfree(mqd_gfx_v11);
@@ -385,7 +378,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
}
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->csa_va,
- shadow_info.csa_size);
+ shadow_info.csa_size,
+ &queue->userq_vas.va.csa);
amdgpu_bo_unreserve(queue->vm->root.bo);
if (r) {
kfree(mqd_gfx_v11);
@@ -415,7 +409,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
goto free_mqd;
}
r = amdgpu_userq_input_va_validate(adev, queue, mqd_sdma_v11->csa_va,
- 32);
+ 32,
+ &queue->userq_vas.va.csa);
amdgpu_bo_unreserve(queue->vm->root.bo);
if (r) {
kfree(mqd_sdma_v11);
@@ -451,10 +446,12 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
return 0;
free_ctx:
- amdgpu_userq_destroy_object(uq_mgr, &queue->fw_obj);
+ amdgpu_bo_free_kernel(&queue->fw_obj.obj, &queue->fw_obj.gpu_addr,
+ &queue->fw_obj.cpu_ptr);
free_mqd:
- amdgpu_userq_destroy_object(uq_mgr, &queue->mqd);
+ amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
+ &queue->mqd.cpu_ptr);
free_props:
kfree(userq_props);
@@ -464,11 +461,17 @@ free_props:
static void mes_userq_mqd_destroy(struct amdgpu_usermode_queue *queue)
{
- struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
- amdgpu_userq_destroy_object(uq_mgr, &queue->fw_obj);
+ amdgpu_bo_free_kernel(&queue->fw_obj.obj, &queue->fw_obj.gpu_addr,
+ &queue->fw_obj.cpu_ptr);
kfree(queue->userq_prop);
- amdgpu_userq_destroy_object(uq_mgr, &queue->mqd);
+ amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
+ &queue->mqd.cpu_ptr);
+
+ amdgpu_bo_reserve(queue->wptr_obj.obj, true);
+ amdgpu_bo_unpin(queue->wptr_obj.obj);
+ amdgpu_bo_unreserve(queue->wptr_obj.obj);
+ amdgpu_bo_unref(&queue->wptr_obj.obj);
}
static int mes_userq_preempt(struct amdgpu_usermode_queue *queue)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index 44f0f23e1148..e64f2f6df9a9 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -889,7 +889,7 @@ static void sdma_v4_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
/* write the fence */
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
/* zero in first two bits */
- BUG_ON(addr & 0x3);
+ WARN_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, lower_32_bits(seq));
@@ -899,7 +899,7 @@ static void sdma_v4_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
addr += 4;
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
/* zero in first two bits */
- BUG_ON(addr & 0x3);
+ WARN_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(seq));
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c
index 061934a2e93a..9c9bbe043a47 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c
@@ -1316,6 +1316,7 @@ static int sdma_v7_1_sw_init(struct amdgpu_ip_block *ip_block)
ring->ring_obj = NULL;
ring->use_doorbell = true;
ring->me = i;
+ ring->no_user_submission = adev->sdma.no_user_submission;
for (xcc_id = 0; xcc_id < fls(adev->gfx.xcc_mask); xcc_id++) {
if (adev->sdma.instance[i].xcc_id == GET_INST(GC, xcc_id))
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v1_0.c
index 5b7b46d242c6..93253db5e2de 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v1_0.c
@@ -42,9 +42,10 @@
#include "oss/oss_1_0_d.h"
#include "oss/oss_1_0_sh_mask.h"
+#define VCE_V1_0_ALIGNMENT (32 * 1024)
#define VCE_V1_0_FW_SIZE (256 * 1024)
#define VCE_V1_0_STACK_SIZE (64 * 1024)
-#define VCE_V1_0_DATA_SIZE (7808 * (AMDGPU_MAX_VCE_HANDLES + 1))
+#define VCE_V1_0_DATA_SIZE (ALIGN(7808 * (AMDGPU_MAX_VCE_HANDLES + 1), VCE_V1_0_ALIGNMENT))
#define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02
static void vce_v1_0_set_ring_funcs(struct amdgpu_device *adev);
@@ -177,7 +178,7 @@ static void vce_v1_0_init_cg(struct amdgpu_device *adev)
}
/**
- * vce_v1_0_load_fw_signature - load firmware signature into VCPU BO
+ * vce_v1_0_load_fw() - load firmware signature into VCPU BO
*
* @adev: amdgpu_device pointer
*
@@ -185,21 +186,26 @@ static void vce_v1_0_init_cg(struct amdgpu_device *adev)
* This function finds the signature appropriate for the current
* ASIC and writes that into the VCPU BO.
*/
-static int vce_v1_0_load_fw_signature(struct amdgpu_device *adev)
+static int vce_v1_0_load_fw(struct amdgpu_device *adev)
{
const struct common_firmware_header *hdr;
struct vce_v1_0_fw_signature *sign;
- unsigned int ucode_offset;
+ u32 ucode_offset;
+ u32 ucode_size;
uint32_t chip_id;
u32 *cpu_addr;
int i;
hdr = (const struct common_firmware_header *)adev->vce.fw->data;
ucode_offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
+ ucode_size = hdr->ucode_size_bytes - sizeof(struct vce_v1_0_fw_signature *);
cpu_addr = adev->vce.cpu_addr;
sign = (void *)adev->vce.fw->data + ucode_offset;
+ if (ucode_size > VCE_V1_0_FW_SIZE - AMDGPU_VCE_FIRMWARE_OFFSET)
+ return -EINVAL;
+
switch (adev->asic_type) {
case CHIP_TAHITI:
chip_id = 0x01000014;
@@ -226,12 +232,14 @@ static int vce_v1_0_load_fw_signature(struct amdgpu_device *adev)
return -EINVAL;
}
+ memset_io(&cpu_addr[0], 0, amdgpu_bo_size(adev->vce.vcpu_bo));
+
cpu_addr += (256 - 64) / 4;
memcpy_toio(&cpu_addr[0], &sign->val[i].nonce[0], 16);
cpu_addr[4] = cpu_to_le32(le32_to_cpu(sign->length) + 64);
memset_io(&cpu_addr[5], 0, 44);
- memcpy_toio(&cpu_addr[16], &sign[1], hdr->ucode_size_bytes - sizeof(*sign));
+ memcpy_toio(&cpu_addr[16], &sign[1], ucode_size);
cpu_addr += (le32_to_cpu(sign->length) + 64) / 4;
memcpy_toio(&cpu_addr[0], &sign->val[i].sigval[0], 16);
@@ -312,18 +320,23 @@ static int vce_v1_0_mc_resume(struct amdgpu_device *adev)
WREG32(mmVCE_VCPU_SCRATCH7, AMDGPU_MAX_VCE_HANDLES);
offset = adev->vce.gpu_addr + AMDGPU_VCE_FIRMWARE_OFFSET;
- size = VCE_V1_0_FW_SIZE;
- WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
+ size = VCE_V1_0_FW_SIZE - AMDGPU_VCE_FIRMWARE_OFFSET;
+ WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset);
WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
offset += size;
size = VCE_V1_0_STACK_SIZE;
- WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset & 0x7fffffff);
+ WARN_ON(!IS_ALIGNED(offset, VCE_V1_0_ALIGNMENT));
+ WARN_ON(!IS_ALIGNED(size, VCE_V1_0_ALIGNMENT));
+ WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset);
WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
offset += size;
size = VCE_V1_0_DATA_SIZE;
- WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset & 0x7fffffff);
+ WARN_ON(!IS_ALIGNED(offset, VCE_V1_0_ALIGNMENT));
+ WARN_ON(!IS_ALIGNED(size, VCE_V1_0_ALIGNMENT));
+ WARN_ON((offset + size - adev->vce.gpu_addr) > amdgpu_bo_size(adev->vce.vcpu_bo));
+ WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset);
WREG32(mmVCE_VCPU_CACHE_SIZE2, size);
WREG32_P(mmVCE_LMI_CTRL2, 0x0, ~0x100);
@@ -527,22 +540,31 @@ static int vce_v1_0_early_init(struct amdgpu_ip_block *ip_block)
* To accomodate that, we put GART to the LOW address range
* and reserve some GART pages where we map the VCPU BO,
* so that it gets a 32-bit address.
+ *
+ * The BAR address is zero and we can't change it
+ * due to the firmware validation mechanism.
+ * It seems that it fails to initialize if the address is >= 128 MiB.
*/
static int vce_v1_0_ensure_vcpu_bo_32bit_addr(struct amdgpu_device *adev)
{
u64 bo_size = amdgpu_bo_size(adev->vce.vcpu_bo);
- u64 max_vcpu_bo_addr = 0xffffffff - bo_size;
+ u64 max_vcpu_bo_addr = 0x07ffffff - bo_size;
u64 num_pages = ALIGN(bo_size, AMDGPU_GPU_PAGE_SIZE) / AMDGPU_GPU_PAGE_SIZE;
u64 pa = amdgpu_gmc_vram_pa(adev, adev->vce.vcpu_bo);
u64 flags = AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | AMDGPU_PTE_VALID;
u64 vce_gart_start_offs;
int r;
- r = amdgpu_gtt_mgr_alloc_entries(&adev->mman.gtt_mgr,
- &adev->vce.gart_node, num_pages,
- DRM_MM_INSERT_LOW);
- if (r)
- return r;
+ if (adev->gmc.vram_start < adev->gmc.gart_start)
+ return amdgpu_bo_gpu_offset(adev->vce.vcpu_bo) <= max_vcpu_bo_addr ? 0 : -EINVAL;
+
+ if (!drm_mm_node_allocated(&adev->vce.gart_node)) {
+ r = amdgpu_gtt_mgr_alloc_entries(&adev->mman.gtt_mgr,
+ &adev->vce.gart_node, num_pages,
+ DRM_MM_INSERT_LOW);
+ if (r)
+ return r;
+ }
vce_gart_start_offs = amdgpu_gtt_node_to_byte_offset(&adev->vce.gart_node);
@@ -553,8 +575,6 @@ static int vce_v1_0_ensure_vcpu_bo_32bit_addr(struct amdgpu_device *adev)
amdgpu_gart_map_vram_range(adev, pa, adev->vce.gart_node.start,
num_pages, flags, adev->gart.ptr);
adev->vce.gpu_addr = adev->gmc.gart_start + vce_gart_start_offs;
- if (adev->vce.gpu_addr > max_vcpu_bo_addr)
- return -EINVAL;
return 0;
}
@@ -574,10 +594,7 @@ static int vce_v1_0_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
- r = amdgpu_vce_resume(adev);
- if (r)
- return r;
- r = vce_v1_0_load_fw_signature(adev);
+ r = vce_v1_0_load_fw(adev);
if (r)
return r;
r = vce_v1_0_ensure_vcpu_bo_32bit_addr(adev);
@@ -696,10 +713,7 @@ static int vce_v1_0_resume(struct amdgpu_ip_block *ip_block)
struct amdgpu_device *adev = ip_block->adev;
int r;
- r = amdgpu_vce_resume(adev);
- if (r)
- return r;
- r = vce_v1_0_load_fw_signature(adev);
+ r = vce_v1_0_load_fw(adev);
if (r)
return r;
r = vce_v1_0_ensure_vcpu_bo_32bit_addr(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
index db149eda6204..3a6fc8604108 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
@@ -37,9 +37,14 @@
#include "oss/oss_2_0_d.h"
#include "oss/oss_2_0_sh_mask.h"
+
+/* Use 24K to be safe. The FW supposedly only requires 23744 bytes. */
+#define VCE_V2_0_DATA_ENTRY_SIZE (24 * 1024)
+
#define VCE_V2_0_FW_SIZE (256 * 1024)
#define VCE_V2_0_STACK_SIZE (64 * 1024)
-#define VCE_V2_0_DATA_SIZE (23552 * AMDGPU_MAX_VCE_HANDLES)
+#define VCE_V2_0_DATA_SIZE (VCE_V2_0_DATA_ENTRY_SIZE * (AMDGPU_MAX_VCE_HANDLES + 1))
+
#define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02
static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev);
@@ -183,7 +188,7 @@ static void vce_v2_0_mc_resume(struct amdgpu_device *adev)
WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
offset = AMDGPU_VCE_FIRMWARE_OFFSET;
- size = VCE_V2_0_FW_SIZE;
+ size = VCE_V2_0_FW_SIZE - AMDGPU_VCE_FIRMWARE_OFFSET;
WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 03d79e464f04..c69f7d82060f 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -574,7 +574,7 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
} else
WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
offset = AMDGPU_VCE_FIRMWARE_OFFSET;
- size = VCE_V3_0_FW_SIZE;
+ size = VCE_V3_0_FW_SIZE - AMDGPU_VCE_FIRMWARE_OFFSET;
WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index f829d65a79b4..8785f7810157 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -67,6 +67,21 @@ static const struct class kfd_class = {
.name = kfd_dev_name,
};
+/*
+ * Cache the address space of the chardev on first open so that the reset
+ * path can drop all userspace mappings of doorbell and MMIO ranges via
+ * unmap_mapping_range().
+ */
+static struct address_space *kfd_dev_mapping;
+
+void kfd_dev_unmap_mapping_range(loff_t const holebegin, loff_t const holelen)
+{
+ struct address_space *mapping = READ_ONCE(kfd_dev_mapping);
+
+ if (mapping)
+ unmap_mapping_range(mapping, holebegin, holelen, 1);
+}
+
static inline struct kfd_process_device *kfd_lock_pdd_by_id(struct kfd_process *p, __u32 gpu_id)
{
struct kfd_process_device *pdd;
@@ -133,6 +148,13 @@ static int kfd_open(struct inode *inode, struct file *filep)
if (iminor(inode) != 0)
return -ENODEV;
+ /*
+ * /dev/kfd is a single chardev so all opens share one inode. Cache
+ * its address_space on the first open for use by the reset path.
+ */
+ if (!READ_ONCE(kfd_dev_mapping))
+ cmpxchg(&kfd_dev_mapping, NULL, inode->i_mapping);
+
is_32bit_user_mode = in_compat_syscall();
if (is_32bit_user_mode) {
@@ -1360,7 +1382,7 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
peer_pdd = kfd_process_device_data_by_id(p, devices_arr[i]);
if (WARN_ON_ONCE(!peer_pdd))
continue;
- kfd_flush_tlb(peer_pdd, TLB_FLUSH_LEGACY);
+ kfd_flush_tlb(peer_pdd);
}
kfree(devices_arr);
@@ -1455,7 +1477,7 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
if (WARN_ON_ONCE(!peer_pdd))
continue;
if (flush_tlb)
- kfd_flush_tlb(peer_pdd, TLB_FLUSH_HEAVYWEIGHT);
+ kfd_flush_tlb(peer_pdd);
/* Remove dma mapping after tlb flush to avoid IO_PAGE_FAULT */
err = amdgpu_amdkfd_gpuvm_dmaunmap_mem(mem, peer_pdd->drm_priv);
@@ -2278,6 +2300,11 @@ static int criu_restore_devices(struct kfd_process *p,
ret = -EINVAL;
goto exit;
}
+
+ if (pdd->drm_file) {
+ ret = -EINVAL;
+ goto exit;
+ }
pdd->user_gpu_id = device_buckets[i].user_gpu_id;
drm_file = fget(device_buckets[i].drm_fd);
@@ -2288,11 +2315,6 @@ static int criu_restore_devices(struct kfd_process *p,
goto exit;
}
- if (pdd->drm_file) {
- ret = -EINVAL;
- goto exit;
- }
-
/* create the vm using render nodes for kfd pdd */
if (kfd_process_device_init_vm(pdd, drm_file)) {
pr_err("could not init vm for given pdd\n");
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index 8ff97bf7d95a..b7f8f7ff8198 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -1737,37 +1737,6 @@ bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entr
return false;
}
-/* check if there is kfd process still uses adev */
-static bool kgd2kfd_check_device_idle(struct amdgpu_device *adev)
-{
- struct kfd_process *p;
- struct hlist_node *p_temp;
- unsigned int temp;
- struct kfd_node *dev;
-
- mutex_lock(&kfd_processes_mutex);
-
- if (hash_empty(kfd_processes_table)) {
- mutex_unlock(&kfd_processes_mutex);
- return true;
- }
-
- /* check if there is device still use adev */
- hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) {
- for (int i = 0; i < p->n_pdds; i++) {
- dev = p->pdds[i]->dev;
- if (dev->adev == adev) {
- mutex_unlock(&kfd_processes_mutex);
- return false;
- }
- }
- }
-
- mutex_unlock(&kfd_processes_mutex);
-
- return true;
-}
-
/** kgd2kfd_teardown_processes - gracefully tear down existing
* kfd processes that use adev
*
@@ -1800,7 +1769,7 @@ void kgd2kfd_teardown_processes(struct amdgpu_device *adev)
mutex_unlock(&kfd_processes_mutex);
/* wait all kfd processes use adev terminate */
- while (!kgd2kfd_check_device_idle(adev))
+ while (!!atomic_read(&adev->kfd.dev->kfd_processes_count))
cond_resched();
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index ab3b2e7be9bd..31187ddbb79e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -475,6 +475,9 @@ static int allocate_doorbell(struct qcm_process_device *qpd,
} else {
/* For CP queues on SOC15 */
if (restore_id) {
+ if (*restore_id >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
+ return -EINVAL;
+
/* make sure that ID is free */
if (__test_and_set_bit(*restore_id, qpd->doorbell_bitmap))
return -EINVAL;
@@ -572,7 +575,7 @@ static int allocate_vmid(struct device_queue_manager *dqm,
qpd->vmid,
qpd->page_table_base);
/* invalidate the VM context after pasid and vmid mapping is set up */
- kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
+ kfd_flush_tlb(qpd_to_pdd(qpd));
if (dqm->dev->kfd2kgd->set_scratch_backing_va)
dqm->dev->kfd2kgd->set_scratch_backing_va(dqm->dev->adev,
@@ -610,7 +613,7 @@ static void deallocate_vmid(struct device_queue_manager *dqm,
if (flush_texture_cache_nocpsch(q->device, qpd))
dev_err(dev, "Failed to flush TC\n");
- kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
+ kfd_flush_tlb(qpd_to_pdd(qpd));
/* Release the vmid mapping */
set_pasid_vmid_mapping(dqm, 0, qpd->vmid);
@@ -1284,7 +1287,7 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
dqm->dev->adev,
qpd->vmid,
qpd->page_table_base);
- kfd_flush_tlb(pdd, TLB_FLUSH_LEGACY);
+ kfd_flush_tlb(pdd);
}
/* Take a safe reference to the mm_struct, which may otherwise
@@ -1587,6 +1590,9 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm,
}
if (restore_sdma_id) {
+ if (*restore_sdma_id >= get_num_sdma_queues(dqm))
+ return -EINVAL;
+
/* Re-use existing sdma_id */
if (!test_bit(*restore_sdma_id, dqm->sdma_bitmap)) {
dev_err(dev, "SDMA queue already in use\n");
@@ -1613,6 +1619,9 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm,
return -ENOMEM;
}
if (restore_sdma_id) {
+ if (*restore_sdma_id >= get_num_xgmi_sdma_queues(dqm))
+ return -EINVAL;
+
/* Re-use existing sdma_id */
if (!test_bit(*restore_sdma_id, dqm->xgmi_sdma_bitmap)) {
dev_err(dev, "SDMA queue already in use\n");
@@ -2493,6 +2502,9 @@ static int wait_on_destroy_queue(struct device_queue_manager *dqm,
if (pdd->qpd.is_debug)
return ret;
+ if (q->properties.is_being_destroyed)
+ return -EBUSY;
+
q->properties.is_being_destroyed = true;
if (pdd->process->debug_trap_enabled && q->properties.is_suspended) {
@@ -2505,6 +2517,9 @@ static int wait_on_destroy_queue(struct device_queue_manager *dqm,
dqm_lock(dqm);
}
+ if (ret)
+ q->properties.is_being_destroyed = false;
+
return ret;
}
@@ -2598,7 +2613,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,
return retval;
failed_try_destroy_debugged_queue:
-
+ q->properties.is_being_destroyed = false;
dqm_unlock(dqm);
return retval;
}
@@ -3299,12 +3314,14 @@ static void copy_context_work_handler(struct work_struct *work)
static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
{
- size_t array_size = num_queues * sizeof(uint32_t);
-
if (!usr_queue_id_array)
- return NULL;
+ return num_queues ? ERR_PTR(-EINVAL) : NULL;
+
+ if (num_queues > KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
+ return ERR_PTR(-EINVAL);
- return memdup_user(usr_queue_id_array, array_size);
+ return memdup_user(usr_queue_id_array,
+ array_size(num_queues, sizeof(uint32_t)));
}
int resume_queues(struct kfd_process *p,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
index a1e3cf2384dd..527c531676e4 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
@@ -320,8 +320,7 @@ static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, voi
static void restore_mqd(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
- struct queue_properties *qp,
- const void *mqd_src,
+ struct queue_properties *qp, const void *mqd_src,
const void *ctl_stack_src, const u32 ctl_stack_size)
{
uint64_t addr;
@@ -337,14 +336,48 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
*gart_addr = addr;
m->cp_hqd_pq_doorbell_control =
- qp->doorbell_off <<
- CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
- pr_debug("cp_hqd_pq_doorbell_control 0x%x\n",
- m->cp_hqd_pq_doorbell_control);
+ qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
+ pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
qp->is_active = 0;
}
+static void checkpoint_mqd_sdma(struct mqd_manager *mm,
+ void *mqd,
+ void *mqd_dst,
+ void *ctl_stack_dst)
+{
+ struct v11_sdma_mqd *m;
+
+ m = get_sdma_mqd(mqd);
+
+ memcpy(mqd_dst, m, sizeof(struct v11_sdma_mqd));
+}
+
+static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp,
+ const void *mqd_src,
+ const void *ctl_stack_src,
+ const u32 ctl_stack_size)
+{
+ uint64_t addr;
+ struct v11_sdma_mqd *m;
+
+ m = (struct v11_sdma_mqd *) mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memcpy(m, mqd_src, sizeof(*m));
+
+ m->sdmax_rlcx_doorbell_offset =
+ qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
static void init_mqd_hiq(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
@@ -529,8 +562,8 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type,
mqd->update_mqd = update_mqd_sdma;
mqd->destroy_mqd = kfd_destroy_mqd_sdma;
mqd->is_occupied = kfd_is_occupied_sdma;
- mqd->checkpoint_mqd = checkpoint_mqd;
- mqd->restore_mqd = restore_mqd;
+ mqd->checkpoint_mqd = checkpoint_mqd_sdma;
+ mqd->restore_mqd = restore_mqd_sdma;
mqd->mqd_size = sizeof(struct v11_sdma_mqd);
mqd->mqd_stride = kfd_mqd_stride;
#if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index e8f97de9d6e4..f6d9d81003dc 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -364,11 +364,15 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
{
struct v9_mqd *m;
struct kfd_context_save_area_header header;
+ u32 cntl_stack_size;
+ u32 cntl_stack_offset;
/* Control stack is located one page after MQD. */
void *mqd_ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE);
m = get_mqd(mqd);
+ cntl_stack_size = min_t(u32, m->cp_hqd_cntl_stack_size, q->ctl_stack_size);
+ cntl_stack_offset = min_t(u32, m->cp_hqd_cntl_stack_offset, cntl_stack_size);
*ctl_stack_used_size = m->cp_hqd_cntl_stack_size -
m->cp_hqd_cntl_stack_offset;
@@ -384,9 +388,10 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
if (copy_to_user(ctl_stack, &header, sizeof(header.wave_state)))
return -EFAULT;
- if (copy_to_user(ctl_stack + m->cp_hqd_cntl_stack_offset,
- mqd_ctl_stack + m->cp_hqd_cntl_stack_offset,
- *ctl_stack_used_size))
+ *ctl_stack_used_size = cntl_stack_size - cntl_stack_offset;
+
+ if (copy_to_user(ctl_stack + cntl_stack_offset, mqd_ctl_stack + cntl_stack_offset,
+ *ctl_stack_used_size))
return -EFAULT;
return 0;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 163d665a6074..d5b07789eda4 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -395,6 +395,7 @@ enum kfd_mempool {
/* Character device interface */
int kfd_chardev_init(void);
void kfd_chardev_exit(void);
+void kfd_dev_unmap_mapping_range(loff_t const holebegin, loff_t const holelen);
/**
* enum kfd_unmap_queues_filter - Enum for queue filters.
@@ -1554,13 +1555,13 @@ void kfd_signal_reset_event(struct kfd_node *dev);
void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid);
void kfd_signal_process_terminate_event(struct kfd_process *p);
-static inline void kfd_flush_tlb(struct kfd_process_device *pdd,
- enum TLB_FLUSH_TYPE type)
+static inline void kfd_flush_tlb(struct kfd_process_device *pdd)
{
struct amdgpu_device *adev = pdd->dev->adev;
struct amdgpu_vm *vm = drm_priv_to_vm(pdd->drm_priv);
- amdgpu_vm_flush_compute_tlb(adev, vm, type, pdd->dev->xcc_mask);
+ amdgpu_vm_flush_compute_tlb(adev, vm, TLB_FLUSH_HEAVYWEIGHT,
+ pdd->dev->xcc_mask);
}
static inline bool kfd_flush_tlb_after_unmap(struct kfd_dev *dev)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 38085a0a0f58..3841943da5ec 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -1424,7 +1424,7 @@ svm_range_unmap_from_gpus(struct svm_range *prange, unsigned long start,
if (r)
break;
}
- kfd_flush_tlb(pdd, TLB_FLUSH_HEAVYWEIGHT);
+ kfd_flush_tlb(pdd);
}
return r;
@@ -1571,7 +1571,7 @@ svm_range_map_to_gpus(struct svm_range *prange, unsigned long offset,
}
}
- kfd_flush_tlb(pdd, TLB_FLUSH_LEGACY);
+ kfd_flush_tlb(pdd);
}
return r;
@@ -3732,6 +3732,9 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
svms = &p->svms;
+ if (!process_info)
+ return -EINVAL;
+
mutex_lock(&process_info->lock);
svm_range_list_lock_and_flush_work(svms, mm);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 2409ac72b166..3a3d01ce0d42 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -1344,8 +1344,13 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b
if (size == 0)
return 0;
+ if (!connector->base.state || !connector->base.state->crtc)
+ return -ENODEV;
+
acrtc_state = to_dm_crtc_state(connector->base.state->crtc->state);
+ write_size = min_t(size_t, size, sizeof(data));
+
r = copy_from_user(data, buf, write_size);
write_size -= r;
diff --git a/drivers/gpu/drm/amd/display/dc/basics/vector.c b/drivers/gpu/drm/amd/display/dc/basics/vector.c
index e8736c134b8d..60bd9ead928a 100644
--- a/drivers/gpu/drm/amd/display/dc/basics/vector.c
+++ b/drivers/gpu/drm/amd/display/dc/basics/vector.c
@@ -289,8 +289,8 @@ bool dal_vector_reserve(struct vector *vector, uint32_t capacity)
if (capacity <= vector->capacity)
return true;
- new_container = krealloc(vector->container,
- capacity * vector->struct_size, GFP_KERNEL);
+ new_container = krealloc_array(vector->container,
+ capacity, vector->struct_size, GFP_KERNEL);
if (new_container) {
vector->container = new_container;
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
index c307f42fe0b9..507b628abdb5 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -222,6 +222,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
ATOM_COMMON_RECORD_HEADER *header;
ATOM_I2C_RECORD *record;
struct bios_parser *bp = BP_FROM_DCB(dcb);
+ int i;
if (!info)
return BP_RESULT_BADINPUT;
@@ -234,7 +235,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@@ -293,11 +294,12 @@ static enum bp_result bios_parser_get_device_tag_record(
{
ATOM_COMMON_RECORD_HEADER *header;
uint32_t offset;
+ int i;
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@@ -966,6 +968,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
{
ATOM_COMMON_RECORD_HEADER *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -975,7 +978,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@@ -1670,6 +1673,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
{
ATOM_COMMON_RECORD_HEADER *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -1679,7 +1683,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
offset = le16_to_cpu(object->usRecordOffset)
+ bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
if (!header)
@@ -2769,6 +2773,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
{
(void)i;
unsigned int j;
+ unsigned int n;
struct bios_parser *bp;
ATOM_BRACKET_LAYOUT_RECORD *record;
ATOM_COMMON_RECORD_HEADER *record_header;
@@ -2778,7 +2783,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
record = NULL;
record_header = NULL;
- for (;;) {
+ for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
if (record_header == NULL) {
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index a1c08e1cc411..0e1f973326ed 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -396,6 +396,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
struct atom_i2c_record *record;
struct atom_i2c_record dummy_record = {0};
struct bios_parser *bp = BP_FROM_DCB(dcb);
+ int i;
if (!info)
return BP_RESULT_BADINPUT;
@@ -429,7 +430,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
break;
}
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@@ -493,6 +494,10 @@ static enum bp_result get_gpio_i2c_info(
- sizeof(struct atom_common_table_header))
/ sizeof(struct atom_gpio_pin_assignment);
+ if (!bios_get_image(&bp->base, DATA_TABLES(gpio_pin_lut),
+ le16_to_cpu(header->table_header.structuresize)))
+ return BP_RESULT_BADBIOSTABLE;
+
pin = (struct atom_gpio_pin_assignment *) header->gpio_pin;
for (table_index = 0; table_index < count; table_index++) {
@@ -530,6 +535,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser
{
struct atom_common_record_header *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -538,7 +544,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@@ -607,6 +613,7 @@ static struct atom_hpd_int_record *get_hpd_record(
{
struct atom_common_record_header *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -616,7 +623,7 @@ static struct atom_hpd_int_record *get_hpd_record(
offset = le16_to_cpu(object->disp_recordoffset)
+ bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@@ -681,6 +688,11 @@ static enum bp_result bios_parser_get_gpio_pin_info(
count = (le16_to_cpu(header->table_header.structuresize)
- sizeof(struct atom_common_table_header))
/ sizeof(struct atom_gpio_pin_assignment);
+
+ if (!bios_get_image(&bp->base, DATA_TABLES(gpio_pin_lut),
+ le16_to_cpu(header->table_header.structuresize)))
+ return BP_RESULT_BADBIOSTABLE;
+
for (i = 0; i < count; ++i) {
if (header->gpio_pin[i].gpio_id != gpio_id)
continue;
@@ -692,8 +704,10 @@ static enum bp_result bios_parser_get_gpio_pin_info(
info->offset_en = info->offset + 1;
info->offset_mask = info->offset - 1;
- info->mask = (uint32_t) (1 <<
- header->gpio_pin[i].gpio_bitshift);
+ if (header->gpio_pin[i].gpio_bitshift >= 32)
+ return BP_RESULT_BADBIOSTABLE;
+
+ info->mask = 1u << header->gpio_pin[i].gpio_bitshift;
info->mask_y = info->mask + 2;
info->mask_en = info->mask + 1;
info->mask_mask = info->mask - 1;
@@ -2184,6 +2198,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record(
{
struct atom_common_record_header *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -2192,7 +2207,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record(
offset = object->encoder_recordoffset + bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@@ -2221,6 +2236,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record(
{
struct atom_common_record_header *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -2229,7 +2245,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record(
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@@ -2257,6 +2273,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_
{
struct atom_common_record_header *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -2265,7 +2282,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@@ -2343,6 +2360,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct
{
struct atom_common_record_header *header;
uint32_t offset;
+ int i;
if (!object) {
BREAK_TO_DEBUGGER(); /* Invalid object */
@@ -2351,7 +2369,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
- for (;;) {
+ for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
header = GET_IMAGE(struct atom_common_record_header, offset);
if (!header)
@@ -2591,14 +2609,16 @@ static enum bp_result get_integrated_info_v11(
info_v11->extdispconninfo.checksum;
info->dp0_ext_hdmi_slv_addr = info_v11->dp0_retimer_set.HdmiSlvAddr;
- info->dp0_ext_hdmi_reg_num = info_v11->dp0_retimer_set.HdmiRegNum;
+ info->dp0_ext_hdmi_reg_num = min_t(u8, info_v11->dp0_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp0_ext_hdmi_6g_reg_num = info_v11->dp0_retimer_set.Hdmi6GRegNum;
+ info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp0_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2607,14 +2627,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp1_ext_hdmi_slv_addr = info_v11->dp1_retimer_set.HdmiSlvAddr;
- info->dp1_ext_hdmi_reg_num = info_v11->dp1_retimer_set.HdmiRegNum;
+ info->dp1_ext_hdmi_reg_num = min_t(u8, info_v11->dp1_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp1_ext_hdmi_6g_reg_num = info_v11->dp1_retimer_set.Hdmi6GRegNum;
+ info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp1_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2623,14 +2645,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp2_ext_hdmi_slv_addr = info_v11->dp2_retimer_set.HdmiSlvAddr;
- info->dp2_ext_hdmi_reg_num = info_v11->dp2_retimer_set.HdmiRegNum;
+ info->dp2_ext_hdmi_reg_num = min_t(u8, info_v11->dp2_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp2_ext_hdmi_6g_reg_num = info_v11->dp2_retimer_set.Hdmi6GRegNum;
+ info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp2_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2639,14 +2663,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp3_ext_hdmi_slv_addr = info_v11->dp3_retimer_set.HdmiSlvAddr;
- info->dp3_ext_hdmi_reg_num = info_v11->dp3_retimer_set.HdmiRegNum;
+ info->dp3_ext_hdmi_reg_num = min_t(u8, info_v11->dp3_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp3_ext_hdmi_6g_reg_num = info_v11->dp3_retimer_set.Hdmi6GRegNum;
+ info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp3_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2796,14 +2822,16 @@ static enum bp_result get_integrated_info_v2_1(
info->ext_disp_conn_info.checksum =
info_v2_1->extdispconninfo.checksum;
info->dp0_ext_hdmi_slv_addr = info_v2_1->dp0_retimer_set.HdmiSlvAddr;
- info->dp0_ext_hdmi_reg_num = info_v2_1->dp0_retimer_set.HdmiRegNum;
+ info->dp0_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp0_ext_hdmi_6g_reg_num = info_v2_1->dp0_retimer_set.Hdmi6GRegNum;
+ info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2811,14 +2839,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp1_ext_hdmi_slv_addr = info_v2_1->dp1_retimer_set.HdmiSlvAddr;
- info->dp1_ext_hdmi_reg_num = info_v2_1->dp1_retimer_set.HdmiRegNum;
+ info->dp1_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp1_ext_hdmi_6g_reg_num = info_v2_1->dp1_retimer_set.Hdmi6GRegNum;
+ info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2826,14 +2856,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp2_ext_hdmi_slv_addr = info_v2_1->dp2_retimer_set.HdmiSlvAddr;
- info->dp2_ext_hdmi_reg_num = info_v2_1->dp2_retimer_set.HdmiRegNum;
+ info->dp2_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp2_ext_hdmi_6g_reg_num = info_v2_1->dp2_retimer_set.Hdmi6GRegNum;
+ info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2841,14 +2873,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp3_ext_hdmi_slv_addr = info_v2_1->dp3_retimer_set.HdmiSlvAddr;
- info->dp3_ext_hdmi_reg_num = info_v2_1->dp3_retimer_set.HdmiRegNum;
+ info->dp3_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.HdmiRegNum,
+ ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
- info->dp3_ext_hdmi_6g_reg_num = info_v2_1->dp3_retimer_set.Hdmi6GRegNum;
+ info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.Hdmi6GRegNum,
+ ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -3236,6 +3270,7 @@ static enum bp_result update_slot_layout_info(
{
unsigned int record_offset;
unsigned int j;
+ unsigned int n;
struct atom_display_object_path_v2 *object;
struct atom_bracket_layout_record *record;
struct atom_common_record_header *record_header;
@@ -3257,7 +3292,7 @@ static enum bp_result update_slot_layout_info(
(object->disp_recordoffset) +
(unsigned int)(bp->object_info_tbl_offset);
- for (;;) {
+ for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
record_header = (struct atom_common_record_header *)
GET_IMAGE(struct atom_common_record_header,
@@ -3351,6 +3386,7 @@ static enum bp_result update_slot_layout_info_v2(
struct slot_layout_info *slot_layout_info)
{
unsigned int record_offset;
+ unsigned int n;
struct atom_display_object_path_v3 *object;
struct atom_bracket_layout_record_v2 *record;
struct atom_common_record_header *record_header;
@@ -3373,7 +3409,7 @@ static enum bp_result update_slot_layout_info_v2(
(object->disp_recordoffset) +
(unsigned int)(bp->object_info_tbl_offset);
- for (;;) {
+ for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
record_header = (struct atom_common_record_header *)
GET_IMAGE(struct atom_common_record_header,
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
index 8d2cf95ae739..e00dc05c2d9d 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
@@ -37,10 +37,13 @@ uint8_t *bios_get_image(struct dc_bios *bp,
uint32_t offset,
uint32_t size)
{
- if (bp->bios && offset + size < bp->bios_size)
- return bp->bios + offset;
- else
+ if (!bp->bios)
return NULL;
+
+ if (offset > bp->bios_size || size > bp->bios_size - offset)
+ return NULL;
+
+ return bp->bios + offset;
}
#include "reg_helper.h"
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
index ab162f2fe577..19fd7aea18f1 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
@@ -37,4 +37,9 @@ void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);
#define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type)))
+/* Upper bound on the number of records in a VBIOS record chain. Prevents
+ * unbounded looping if the VBIOS image is malformed and lacks a terminator.
+ */
+#define BIOS_MAX_NUM_RECORD 256
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 419f894c87b0..b3530fbf32f7 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -6071,7 +6071,11 @@ bool dc_process_dmub_aux_transfer_async(struct dc *dc,
uint8_t action;
union dmub_rb_cmd cmd = {0};
- ASSERT(payload->length <= 16);
+ if (link_index >= dc->link_count || !dc->links[link_index])
+ return false;
+
+ if (payload->length > sizeof(cmd.dp_aux_access.aux_control.dpaux.data))
+ return false;
cmd.dp_aux_access.header.type = DMUB_CMD__DP_AUX_ACCESS;
cmd.dp_aux_access.header.payload_bytes = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 7fa336bf1115..7dd73eaaf940 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -1217,7 +1217,7 @@ struct dc_lttpr_caps {
union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
union dp_alpm_lttpr_cap alpm;
- uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
+ uint8_t aux_rd_interval[MAX_REPEATER_CNT];
uint8_t lttpr_ieee_oui[3]; // Always read from closest LTTPR to host
uint8_t lttpr_device_id[6]; // Always read from closest LTTPR to host
};
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
index c4d4eea140f3..1f23dfccf07a 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
@@ -105,15 +105,26 @@ static void dccg21_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppcl
* dccg2_init() unconditionally overwrites MICROSECOND_TIME_BASE_DIV to
* 0x00120264, destroying the marker before it can be read.
*
- * Guard the call: if the S0i3 marker is present, skip dccg2_init() so the
+ * Guard the call: if the S0i3 marker is present, skip init so the
* WA can function correctly. bios_golden_init() will handle init in that case.
+ *
+ * DCN21 uses 48MHz refclk, not 100MHz, so we must explicitly set the correct
+ * values (48MHz is taken from rn_clk_mgr_construct()).
*/
static void dccg21_init(struct dccg *dccg)
{
+ struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
if (dccg2_is_s0i3_golden_init_wa_done(dccg))
return;
- dccg2_init(dccg);
+ /* 48MHz refclk from rn_clk_mgr_construct() */
+ REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x00120230);
+ REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x0010bb80);
+ REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x0e01003c);
+
+ if (REG(REFCLK_CNTL))
+ REG_WRITE(REFCLK_CNTL, 0);
}
static const struct dccg_funcs dccg21_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
index c1448ae47366..0d312b40bcfa 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
@@ -110,7 +110,15 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
{ COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
{ COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
- 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
+ 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
+{ COLOR_SPACE_2020_RGB_FULLRANGE,
+ { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
+{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
+ { 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
+{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
+ 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
+{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
+ 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
};
static bool setup_scaling_configuration(
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
index cf63fac82832..1ed018aaa4bb 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
@@ -88,7 +88,15 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
{ COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
{ COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
- 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
+ 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
+{ COLOR_SPACE_2020_RGB_FULLRANGE,
+ { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
+{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
+ { 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
+{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
+ 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
+{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
+ 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
};
enum csc_color_mode {
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
index 82f81b586986..3751f7a94a05 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
@@ -92,9 +92,14 @@
#include "dml/dcn32/dcn32_fpu.h"
#include "dc_state_priv.h"
+#include "dc_fpu.h"
#include "dml2_0/dml2_wrapper.h"
+#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif
+
#define DC_LOGGER_INIT(logger)
enum dcn32_clk_src_array_id {
@@ -1684,7 +1689,8 @@ static void dcn32_enable_phantom_plane(struct dc *dc,
if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state)
phantom_plane = prev_phantom_plane;
else
- phantom_plane = dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state);
+ DC_RUN_WITH_PREEMPTION_ENABLED(phantom_plane =
+ dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state));
if (!phantom_plane)
continue;
diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c
index 0ca39873f807..324413a090bf 100644
--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c
+++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c
@@ -529,7 +529,8 @@ enum mod_hdcp_status mod_hdcp_read_rx_id_list(struct mod_hdcp *hdcp)
} else {
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST,
hdcp->auth.msg.hdcp2.rx_id_list,
- hdcp->auth.msg.hdcp2.rx_id_list_size);
+ MIN(hdcp->auth.msg.hdcp2.rx_id_list_size,
+ sizeof(hdcp->auth.msg.hdcp2.rx_id_list)));
}
return status;
}
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
index 36942467d4ad..c3aff5d0c53d 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
@@ -3076,6 +3076,10 @@ static bool si_dpm_vblank_too_short(void *handle)
/* we never hit the non-gddr5 limit so disable it */
u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;
+ /* Disregard vblank time when there are no displays connected */
+ if (!adev->pm.pm_display_cfg.num_display)
+ return false;
+
/* Consider zero vblank time too short and disable MCLK switching.
* Note that the vblank time is set to maximum when no displays are attached,
* so we'll still enable MCLK switching in that case.
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
index 731355bdb9bc..3650e7beeb67 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
@@ -1333,12 +1333,13 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
dev_id = adev->pdev->device;
- if ((dpm_table->mclk_table.count >= 2)
- && ((dev_id == 0x67B0) || (dev_id == 0x67B1))) {
- smu_data->smc_state_table.MemoryLevel[1].MinVddci =
- smu_data->smc_state_table.MemoryLevel[0].MinVddci;
- smu_data->smc_state_table.MemoryLevel[1].MinMvdd =
- smu_data->smc_state_table.MemoryLevel[0].MinMvdd;
+ if ((dpm_table->mclk_table.count >= 2) &&
+ ((dev_id == 0x67B0) || (dev_id == 0x67B1)) &&
+ (adev->pdev->revision == 0)) {
+ smu_data->smc_state_table.MemoryLevel[1].MinVddc =
+ smu_data->smc_state_table.MemoryLevel[0].MinVddc;
+ smu_data->smc_state_table.MemoryLevel[1].MinVddcPhases =
+ smu_data->smc_state_table.MemoryLevel[0].MinVddcPhases;
}
smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 0a7f5fa3c1d3..7f8d4bb47d02 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2390,28 +2390,30 @@ static int smu_v13_0_0_enable_mgpu_fan_boost(struct smu_context *smu)
}
static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+ uint32_t *current_power_limit,
+ uint32_t *default_power_limit,
+ uint32_t *max_power_limit,
+ uint32_t *min_power_limit)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_13_0_0_powerplay_table *powerplay_table =
(struct smu_13_0_0_powerplay_table *)table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
-
- if (smu_v13_0_get_current_power_limit(smu, &power_limit))
- power_limit = smu->adev->pm.ac_power ?
+ uint32_t pp_limit = smu->adev->pm.ac_power ?
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0;
+ int ret;
+
+ if (current_power_limit) {
+ ret = smu_v13_0_get_current_power_limit(smu, &power_limit);
+ if (ret)
+ *current_power_limit = pp_limit;
+ }
- if (current_power_limit)
- *current_power_limit = power_limit;
if (default_power_limit)
- *default_power_limit = power_limit;
+ *default_power_limit = pp_limit;
if (powerplay_table) {
if (smu->od_enabled &&
@@ -2425,15 +2427,15 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
}
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
+ od_percent_upper, od_percent_lower, pp_limit);
if (max_power_limit) {
- *max_power_limit = msg_limit * (100 + od_percent_upper);
+ *max_power_limit = pp_limit * (100 + od_percent_upper);
*max_power_limit /= 100;
}
if (min_power_limit) {
- *min_power_limit = power_limit * (100 - od_percent_lower);
+ *min_power_limit = pp_limit * (100 - od_percent_lower);
*min_power_limit /= 100;
}
@@ -2801,11 +2803,19 @@ static void smu_v13_0_0_i2c_control_fini(struct smu_context *smu)
static int smu_v13_0_0_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state)
{
+ uint32_t param;
int ret;
switch (mp1_state) {
case PP_MP1_STATE_UNLOAD:
- ret = smu_cmn_set_mp1_state(smu, mp1_state);
+ /*
+ * NOTE: Param 0x55 comes from PMFW 80.31.0, ignored in older versions.
+ * No PMFW version check required.
+ */
+ param = amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) ?
+ 0x55 : 0x00;
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PrepareMp1ForUnload,
+ param, NULL);
break;
default:
/* Ignore others */
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index 5abf2b0703c6..0f774b0920ce 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2372,28 +2372,32 @@ static int smu_v13_0_7_enable_mgpu_fan_boost(struct smu_context *smu)
}
static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+ uint32_t *current_power_limit,
+ uint32_t *default_power_limit,
+ uint32_t *max_power_limit,
+ uint32_t *min_power_limit)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_13_0_7_powerplay_table *powerplay_table =
(struct smu_13_0_7_powerplay_table *)table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
-
- if (smu_v13_0_get_current_power_limit(smu, &power_limit))
- power_limit = smu->adev->pm.ac_power ?
+ uint32_t pp_limit = smu->adev->pm.ac_power ?
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0;
+ int ret;
+
+ if (current_power_limit) {
+ ret = smu_v13_0_get_current_power_limit(smu, &power_limit);
+ if (ret)
+ power_limit = pp_limit;
- if (current_power_limit)
*current_power_limit = power_limit;
+ }
+
if (default_power_limit)
- *default_power_limit = power_limit;
+ *default_power_limit = pp_limit;
if (powerplay_table) {
if (smu->od_enabled &&
@@ -2407,15 +2411,15 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
}
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
+ od_percent_upper, od_percent_lower, pp_limit);
if (max_power_limit) {
- *max_power_limit = msg_limit * (100 + od_percent_upper);
+ *max_power_limit = pp_limit * (100 + od_percent_upper);
*max_power_limit /= 100;
}
if (min_power_limit) {
- *min_power_limit = power_limit * (100 - od_percent_lower);
+ *min_power_limit = pp_limit * (100 - od_percent_lower);
*min_power_limit /= 100;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
index a28624d4847a..75719c47a41e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
@@ -1231,7 +1231,8 @@ static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu,
switch (clk_type) {
case SMU_GFXCLK:
case SMU_SCLK:
- msg_set_min = SMU_MSG_SetHardMinGfxClk;
+ /* SoftMin lets PMFW throttle gfxclk; HardMin would override SoftMax. */
+ msg_set_min = SMU_MSG_SetSoftMinGfxclk;
msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
break;
case SMU_FCLK:
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 5ce4e982ca33..fdc1456b885c 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
@@ -2152,7 +2152,6 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
index c3cb36813806..940b43105817 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
@@ -435,10 +435,12 @@ int smu_v15_0_fini_smc_tables(struct smu_context *smu)
smu_table->watermarks_table = NULL;
smu_table->metrics_time = 0;
+ kfree(smu_dpm->dpm_policies);
kfree(smu_dpm->dpm_context);
kfree(smu_dpm->golden_dpm_context);
kfree(smu_dpm->dpm_current_power_state);
kfree(smu_dpm->dpm_request_power_state);
+ smu_dpm->dpm_policies = NULL;
smu_dpm->dpm_context = NULL;
smu_dpm->golden_dpm_context = NULL;
smu_dpm->dpm_context_size = 0;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 90c7127beabf..fe97fda8bfe9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -272,11 +272,15 @@ static void __smu_msg_v1_send(struct smu_msg_ctl *ctl, u16 index,
{
struct amdgpu_device *adev = ctl->smu->adev;
struct smu_msg_config *cfg = &ctl->config;
+ u32 arg;
int i;
WREG32(cfg->resp_reg, 0);
- for (i = 0; i < args->num_args; i++)
- WREG32(cfg->arg_regs[i], args->args[i]);
+ for (i = 0; i < cfg->num_arg_regs; i++) {
+ /* NOTE: Clear unused argument registers to avoid stale values. */
+ arg = i < args->num_args ? args->args[i] : 0;
+ WREG32(cfg->arg_regs[i], arg);
+ }
WREG32(cfg->msg_reg, index);
}
diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c
index 814713c5bea9..553a1df4688d 100644
--- a/drivers/gpu/drm/bridge/chipone-icn6211.c
+++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
@@ -758,7 +758,9 @@ static int chipone_i2c_probe(struct i2c_client *client)
dev_set_drvdata(dev, icn);
i2c_set_clientdata(client, icn);
- drm_bridge_add(&icn->bridge);
+ ret = devm_drm_bridge_add(dev, &icn->bridge);
+ if (ret)
+ return ret;
return chipone_dsi_host_attach(icn);
}
diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index 441fd32dc91c..d64e328bf542 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -222,52 +222,58 @@ static const struct drm_bridge_funcs imx8qxp_pxl2dpi_bridge_funcs = {
imx8qxp_pxl2dpi_bridge_atomic_get_output_bus_fmts,
};
-static struct device_node *
+static int
imx8qxp_pxl2dpi_get_available_ep_from_port(struct imx8qxp_pxl2dpi *p2d,
- u32 port_id)
+ u32 port_id,
+ struct device_node **ep)
{
- struct device_node *port, *ep;
+ struct device_node *port;
+ int ret = 0;
int ep_cnt;
+ *ep = NULL;
+
port = of_graph_get_port_by_id(p2d->dev->of_node, port_id);
if (!port) {
DRM_DEV_ERROR(p2d->dev, "failed to get port@%u\n", port_id);
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
ep_cnt = of_get_available_child_count(port);
if (ep_cnt == 0) {
DRM_DEV_ERROR(p2d->dev, "no available endpoints of port@%u\n",
port_id);
- ep = ERR_PTR(-ENODEV);
+ ret = -ENODEV;
goto out;
} else if (ep_cnt > 1) {
DRM_DEV_ERROR(p2d->dev,
"invalid available endpoints of port@%u\n",
port_id);
- ep = ERR_PTR(-EINVAL);
+ ret = -EINVAL;
goto out;
}
- ep = of_get_next_available_child(port, NULL);
- if (!ep) {
+ *ep = of_get_next_available_child(port, NULL);
+ if (!*ep) {
DRM_DEV_ERROR(p2d->dev,
"failed to get available endpoint of port@%u\n",
port_id);
- ep = ERR_PTR(-ENODEV);
+ ret = -ENODEV;
goto out;
}
out:
of_node_put(port);
- return ep;
+ return ret;
}
static int imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d)
{
- struct device_node *ep __free(device_node) =
- imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1);
- if (IS_ERR(ep))
- return PTR_ERR(ep);
+ struct device_node *ep __free(device_node) = NULL;
+ int ret;
+
+ ret = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1, &ep);
+ if (ret)
+ return ret;
struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(ep);
if (!remote || !of_device_is_available(remote)) {
@@ -291,9 +297,9 @@ static int imx8qxp_pxl2dpi_set_pixel_link_sel(struct imx8qxp_pxl2dpi *p2d)
struct of_endpoint endpoint;
int ret;
- ep = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 0);
- if (IS_ERR(ep))
- return PTR_ERR(ep);
+ ret = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 0, &ep);
+ if (ret)
+ return ret;
ret = of_graph_parse_endpoint(ep, &endpoint);
if (ret) {
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 9246e9c15a6e..ed21f09cd19a 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -1559,6 +1559,11 @@ static int it66121_probe(struct i2c_client *client)
return ret;
}
+ ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->gpio_reset))
+ return dev_err_probe(dev, PTR_ERR(ctx->gpio_reset),
+ "Failed to get reset GPIO\n");
+
it66121_hw_reset(ctx);
ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config);
diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
index c9e6505cbd88..2d02cc69f237 100644
--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -251,7 +251,6 @@ static void ge_b850v3_lvds_remove(void)
goto out;
drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
-
ge_b850v3_lvds_ptr = NULL;
out:
mutex_unlock(&ge_b850v3_lvds_dev_mutex);
@@ -261,6 +260,7 @@ static int ge_b850v3_register(void)
{
struct i2c_client *stdp4028_i2c = ge_b850v3_lvds_ptr->stdp4028_i2c;
struct device *dev = &stdp4028_i2c->dev;
+ int ret;
/* drm bridge initialization */
ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT |
@@ -277,11 +277,15 @@ static int ge_b850v3_register(void)
if (!stdp4028_i2c->irq)
return 0;
- return devm_request_threaded_irq(&stdp4028_i2c->dev,
- stdp4028_i2c->irq, NULL,
- ge_b850v3_lvds_irq_handler,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
- "ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr);
+ ret = devm_request_threaded_irq(&stdp4028_i2c->dev,
+ stdp4028_i2c->irq, NULL,
+ ge_b850v3_lvds_irq_handler,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr);
+ if (ret)
+ drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
+
+ return ret;
}
static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c)
diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c
index d9b388165de1..6c427bc75896 100644
--- a/drivers/gpu/drm/bridge/tda998x_drv.c
+++ b/drivers/gpu/drm/bridge/tda998x_drv.c
@@ -1293,7 +1293,7 @@ static const struct drm_edid *tda998x_edid_read(struct tda998x_priv *priv,
* can't handle signals gracefully.
*/
if (tda998x_edid_delay_wait(priv))
- return 0;
+ return NULL;
if (priv->rev == TDA19988)
reg_clear(priv, REG_TX4, TX4_PD_RAM);
@@ -1762,7 +1762,7 @@ static const struct drm_bridge_funcs tda998x_bridge_funcs = {
static int tda998x_get_audio_ports(struct tda998x_priv *priv,
struct device_node *np)
{
- const u32 *port_data;
+ const __be32 *port_data;
u32 size;
int i;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 985c283cf59f..675675480da4 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -697,6 +697,7 @@ static void drm_dev_init_release(struct drm_device *dev, void *res)
mutex_destroy(&dev->master_mutex);
mutex_destroy(&dev->clientlist_mutex);
mutex_destroy(&dev->filelist_mutex);
+ mutex_destroy(&dev->gem_lru_mutex);
}
static int drm_dev_init(struct drm_device *dev,
@@ -738,6 +739,7 @@ static int drm_dev_init(struct drm_device *dev,
INIT_LIST_HEAD(&dev->vblank_event_list);
spin_lock_init(&dev->event_lock);
+ mutex_init(&dev->gem_lru_mutex);
mutex_init(&dev->filelist_mutex);
mutex_init(&dev->clientlist_mutex);
mutex_init(&dev->master_mutex);
diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c
index e2b62e5fb891..2156dbe601c9 100644
--- a/drivers/gpu/drm/drm_dumb_buffers.c
+++ b/drivers/gpu/drm/drm_dumb_buffers.c
@@ -70,8 +70,11 @@ static int drm_mode_align_dumb(struct drm_mode_create_dumb *args,
if (!pitch)
return -EINVAL;
- if (hw_pitch_align)
+ if (hw_pitch_align) {
pitch = roundup(pitch, hw_pitch_align);
+ if (pitch < hw_pitch_align)
+ return -EINVAL;
+ }
if (!hw_size_align)
hw_size_align = PAGE_SIZE;
@@ -80,7 +83,7 @@ static int drm_mode_align_dumb(struct drm_mode_create_dumb *args,
if (check_mul_overflow(args->height, pitch, &size))
return -EINVAL;
- size = ALIGN(size, hw_size_align);
+ size = roundup(size, hw_size_align);
if (!size)
return -EINVAL;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index a80a335f4148..1541fc8a9ac2 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -490,7 +490,7 @@ static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off,
* the number of horizontal pixels that need an update.
*/
off_t bit_off = (off % line_length) * 8;
- off_t bit_end = (end % line_length) * 8;
+ off_t bit_end = bit_off + len * 8;
x1 = bit_off / info->var.bits_per_pixel;
x2 = DIV_ROUND_UP(bit_end, info->var.bits_per_pixel);
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index d6424267260b..3b2448a3a9de 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1015,12 +1015,25 @@ err:
return ret;
}
+/*
+ * This ioctl is disabled for security reasons but also it failed
+ * to follow process in terms of adding testing in igt and verifying
+ * all the corner cases which made fixing security bugs in it even
+ * harder than necessary.
+ *
+ * To re-enable this ioctl
+ * 1. land working IGT tests in igt-gpu-tools that cover
+ * all corner cases and race conditions.
+ * 2. handle idr_preload
+ * 3. handle == 0
+ * 4. handle == new_handle semantics definition.
+ */
int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_gem_change_handle *args = data;
struct drm_gem_object *obj;
- int handle, ret;
+ int new_handle, ret;
if (!drm_core_check_feature(dev, DRIVER_GEM))
return -EOPNOTSUPP;
@@ -1028,33 +1041,37 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
/* idr_alloc() limitation. */
if (args->new_handle > INT_MAX)
return -EINVAL;
- handle = args->new_handle;
+ new_handle = args->new_handle;
- obj = drm_gem_object_lookup(file_priv, args->handle);
- if (!obj)
- return -ENOENT;
-
- if (args->handle == handle) {
- ret = 0;
- goto out;
- }
+ if (args->handle == new_handle)
+ return 0;
mutex_lock(&file_priv->prime.lock);
-
spin_lock(&file_priv->table_lock);
- ret = idr_alloc(&file_priv->object_idr, obj, handle, handle + 1,
+ ret = idr_alloc(&file_priv->object_idr, NULL, new_handle, new_handle + 1,
GFP_NOWAIT);
- spin_unlock(&file_priv->table_lock);
- if (ret < 0)
+ if (ret < 0) {
+ spin_unlock(&file_priv->table_lock);
goto out_unlock;
+ }
+
+ obj = idr_replace(&file_priv->object_idr, NULL, args->handle);
+ if (IS_ERR_OR_NULL(obj)) {
+ idr_remove(&file_priv->object_idr, new_handle);
+ spin_unlock(&file_priv->table_lock);
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+ spin_unlock(&file_priv->table_lock);
if (obj->dma_buf) {
ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf,
- handle);
+ new_handle);
if (ret < 0) {
spin_lock(&file_priv->table_lock);
- idr_remove(&file_priv->object_idr, handle);
+ idr_remove(&file_priv->object_idr, new_handle);
+ idr_replace(&file_priv->object_idr, obj, args->handle);
spin_unlock(&file_priv->table_lock);
goto out_unlock;
}
@@ -1066,12 +1083,12 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
spin_lock(&file_priv->table_lock);
idr_remove(&file_priv->object_idr, args->handle);
+ obj = idr_replace(&file_priv->object_idr, obj, new_handle);
spin_unlock(&file_priv->table_lock);
+ WARN_ON(obj != NULL);
out_unlock:
mutex_unlock(&file_priv->prime.lock);
-out:
- drm_gem_object_put(obj);
return ret;
}
@@ -1541,12 +1558,10 @@ EXPORT_SYMBOL(drm_gem_unlock_reservations);
* drm_gem_lru_init - initialize a LRU
*
* @lru: The LRU to initialize
- * @lock: The lock protecting the LRU
*/
void
-drm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock)
+drm_gem_lru_init(struct drm_gem_lru *lru)
{
- lru->lock = lock;
lru->count = 0;
INIT_LIST_HEAD(&lru->list);
}
@@ -1571,14 +1586,10 @@ drm_gem_lru_remove_locked(struct drm_gem_object *obj)
void
drm_gem_lru_remove(struct drm_gem_object *obj)
{
- struct drm_gem_lru *lru = obj->lru;
-
- if (!lru)
- return;
-
- mutex_lock(lru->lock);
- drm_gem_lru_remove_locked(obj);
- mutex_unlock(lru->lock);
+ mutex_lock(&obj->dev->gem_lru_mutex);
+ if (obj->lru)
+ drm_gem_lru_remove_locked(obj);
+ mutex_unlock(&obj->dev->gem_lru_mutex);
}
EXPORT_SYMBOL(drm_gem_lru_remove);
@@ -1593,7 +1604,7 @@ EXPORT_SYMBOL(drm_gem_lru_remove);
void
drm_gem_lru_move_tail_locked(struct drm_gem_lru *lru, struct drm_gem_object *obj)
{
- lockdep_assert_held_once(lru->lock);
+ lockdep_assert_held_once(&obj->dev->gem_lru_mutex);
if (obj->lru)
drm_gem_lru_remove_locked(obj);
@@ -1617,9 +1628,9 @@ EXPORT_SYMBOL(drm_gem_lru_move_tail_locked);
void
drm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj)
{
- mutex_lock(lru->lock);
+ mutex_lock(&obj->dev->gem_lru_mutex);
drm_gem_lru_move_tail_locked(lru, obj);
- mutex_unlock(lru->lock);
+ mutex_unlock(&obj->dev->gem_lru_mutex);
}
EXPORT_SYMBOL(drm_gem_lru_move_tail);
@@ -1633,6 +1644,7 @@ EXPORT_SYMBOL(drm_gem_lru_move_tail);
* of the shrink callback to check for this (ie. dma_resv_test_signaled())
* or if necessary block until the buffer becomes idle.
*
+ * @dev: DRM device the LRU belongs to
* @lru: The LRU to scan
* @nr_to_scan: The number of pages to try to reclaim
* @remaining: The number of pages left to reclaim, should be initialized by caller
@@ -1640,7 +1652,8 @@ EXPORT_SYMBOL(drm_gem_lru_move_tail);
* @ticket: Optional ww_acquire_ctx context to use for locking
*/
unsigned long
-drm_gem_lru_scan(struct drm_gem_lru *lru,
+drm_gem_lru_scan(struct drm_device *dev,
+ struct drm_gem_lru *lru,
unsigned int nr_to_scan,
unsigned long *remaining,
bool (*shrink)(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket),
@@ -1650,9 +1663,9 @@ drm_gem_lru_scan(struct drm_gem_lru *lru,
struct drm_gem_object *obj;
unsigned freed = 0;
- drm_gem_lru_init(&still_in_lru, lru->lock);
+ drm_gem_lru_init(&still_in_lru);
- mutex_lock(lru->lock);
+ mutex_lock(&dev->gem_lru_mutex);
while (freed < nr_to_scan) {
obj = list_first_entry_or_null(&lru->list, typeof(*obj), lru_node);
@@ -1675,7 +1688,7 @@ drm_gem_lru_scan(struct drm_gem_lru *lru,
* rest of the loop body, to reduce contention with other
* code paths that need the LRU lock
*/
- mutex_unlock(lru->lock);
+ mutex_unlock(&dev->gem_lru_mutex);
if (ticket)
ww_acquire_init(ticket, &reservation_ww_class);
@@ -1709,7 +1722,7 @@ drm_gem_lru_scan(struct drm_gem_lru *lru,
tail:
drm_gem_object_put(obj);
- mutex_lock(lru->lock);
+ mutex_lock(&dev->gem_lru_mutex);
}
/*
@@ -1721,7 +1734,7 @@ tail:
list_splice_tail(&still_in_lru.list, &lru->list);
lru->count += still_in_lru.count;
- mutex_unlock(lru->lock);
+ mutex_unlock(&dev->gem_lru_mutex);
return freed;
}
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index ff193155129e..e2df4becce62 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -660,7 +660,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_gem_change_handle_ioctl, DRM_RENDER_ALLOW),
+ /* see drm_gem.c:drm_gem_change_handle_ioctl for why this is invalid */
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_invalid_op, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0),
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
index df4232d7e135..3cc50d697c89 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -116,16 +116,18 @@ int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit)
*/
mutex_lock(&gpu->sched_lock);
+ ret = xa_alloc_cyclic(&gpu->user_fences, &submit->out_fence_id,
+ NULL, xa_limit_32b, &gpu->next_user_fence,
+ GFP_KERNEL);
+ if (ret < 0)
+ goto out_unlock;
+
drm_sched_job_arm(&submit->sched_job);
submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished);
- ret = xa_alloc_cyclic(&gpu->user_fences, &submit->out_fence_id,
- submit->out_fence, xa_limit_32b,
- &gpu->next_user_fence, GFP_KERNEL);
- if (ret < 0) {
- drm_sched_job_cleanup(&submit->sched_job);
- goto out_unlock;
- }
+
+ xa_store(&gpu->user_fences, submit->out_fence_id,
+ submit->out_fence, GFP_KERNEL);
/* the scheduler holds on to the job now */
kref_get(&submit->refcount);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index 29a8366513fa..e68c954ec3e6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -423,7 +423,9 @@ static int exynos_mic_probe(struct platform_device *pdev)
mic->bridge.of_node = dev->of_node;
- drm_bridge_add(&mic->bridge);
+ ret = devm_drm_bridge_add(dev, &mic->bridge);
+ if (ret)
+ goto err;
pm_runtime_enable(dev);
@@ -443,12 +445,8 @@ err:
static void exynos_mic_remove(struct platform_device *pdev)
{
- struct exynos_mic *mic = platform_get_drvdata(pdev);
-
component_del(&pdev->dev, &exynos_mic_component_ops);
pm_runtime_disable(&pdev->dev);
-
- drm_bridge_remove(&mic->bridge);
}
static const struct of_device_id exynos_mic_of_match[] = {
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 58d7e191fd56..403d21cbb3a2 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -580,6 +580,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector)
} else {
edid = (struct edid *)raw_edid;
/* FIXME ? edid = drm_get_edid(connector, i2c_adap); */
+ i2c_put_adapter(i2c_adap);
}
if (edid) {
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 884d324f0044..e194d0cce067 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -293,7 +293,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
{
struct gma_encoder *gma_encoder;
struct gma_connector *gma_connector;
- struct gma_i2c_chan *ddc_bus;
+ struct gma_i2c_chan *ddc_bus = NULL;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
@@ -367,6 +367,8 @@ void oaktrail_lvds_init(struct drm_device *dev,
if (edid == NULL && dev_priv->lpc_gpio_base) {
ddc_bus = oaktrail_lvds_i2c_init(dev);
if (!IS_ERR(ddc_bus)) {
+ if (i2c_adap)
+ i2c_put_adapter(i2c_adap);
i2c_adap = &ddc_bus->base;
edid = drm_get_edid(connector, i2c_adap);
}
@@ -421,7 +423,10 @@ out:
err_unlock:
mutex_unlock(&dev->mode_config.mutex);
- gma_i2c_destroy(to_gma_i2c_chan(connector->ddc));
+ if (!IS_ERR_OR_NULL(ddc_bus))
+ gma_i2c_destroy(ddc_bus);
+ else if (i2c_adap)
+ i2c_put_adapter(i2c_adap);
drm_encoder_cleanup(encoder);
err_connector_cleanup:
drm_connector_cleanup(connector);
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
index 06b5d96e6eaf..b6bf6412ae34 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
@@ -150,6 +150,10 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
goto err_free_mmio;
}
+ /* If DRM panic path is stubbed out VMBus code must do the unload */
+ if (IS_ENABLED(CONFIG_DRM_PANIC))
+ vmbus_set_skip_unload(true);
+
drm_client_setup(dev, NULL);
return 0;
@@ -169,6 +173,7 @@ static void hyperv_vmbus_remove(struct hv_device *hdev)
struct drm_device *dev = hv_get_drvdata(hdev);
struct hyperv_drm_device *hv = to_hv(dev);
+ vmbus_set_skip_unload(false);
drm_dev_unplug(dev);
drm_atomic_helper_shutdown(dev);
vmbus_close(hdev->channel);
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
index 7978f8c8108c..d48ca6c23b7c 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
@@ -212,15 +212,16 @@ static void hyperv_plane_panic_flush(struct drm_plane *plane)
struct hyperv_drm_device *hv = to_hv(plane->dev);
struct drm_rect rect;
- if (!plane->state || !plane->state->fb)
- return;
+ if (plane->state && plane->state->fb) {
+ rect.x1 = 0;
+ rect.y1 = 0;
+ rect.x2 = plane->state->fb->width;
+ rect.y2 = plane->state->fb->height;
- rect.x1 = 0;
- rect.y1 = 0;
- rect.x2 = plane->state->fb->width;
- rect.y2 = plane->state->fb->height;
+ hyperv_update_dirt(hv->hdev, &rect);
+ }
- hyperv_update_dirt(hv->hdev, &rect);
+ vmbus_initiate_unload(true);
}
static const struct drm_plane_helper_funcs hyperv_plane_helper_funcs = {
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
index 051ecc526832..4e6f703a1b33 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
@@ -391,8 +391,11 @@ static int hyperv_get_supported_resolution(struct hv_device *hdev)
return -ETIMEDOUT;
}
- if (msg->resolution_resp.resolution_count == 0) {
- drm_err(dev, "No supported resolutions\n");
+ if (msg->resolution_resp.resolution_count == 0 ||
+ msg->resolution_resp.resolution_count >
+ SYNTHVID_MAX_RESOLUTION_COUNT) {
+ drm_err(dev, "Invalid resolution count: %d\n",
+ msg->resolution_resp.resolution_count);
return -ENODEV;
}
@@ -417,30 +420,92 @@ static int hyperv_get_supported_resolution(struct hv_device *hdev)
return 0;
}
-static void hyperv_receive_sub(struct hv_device *hdev)
+static void hyperv_receive_sub(struct hv_device *hdev, u32 bytes_recvd)
{
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct synthvid_msg *msg;
+ size_t hdr_size;
+ size_t need;
if (!hv)
return;
- msg = (struct synthvid_msg *)hv->recv_buf;
-
- /* Complete the wait event */
- if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
- msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
- msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
- memcpy(hv->init_buf, msg, VMBUS_MAX_PACKET_SIZE);
- complete(&hv->wait);
+ hdr_size = sizeof(struct pipe_msg_hdr) +
+ sizeof(struct synthvid_msg_hdr);
+ if (bytes_recvd < hdr_size) {
+ drm_err_ratelimited(&hv->dev,
+ "synthvid packet too small for header: %u\n",
+ bytes_recvd);
return;
}
- if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
+ msg = (struct synthvid_msg *)hv->recv_buf;
+ need = hdr_size;
+
+ switch (msg->vid_hdr.type) {
+ case SYNTHVID_VERSION_RESPONSE:
+ need += sizeof(struct synthvid_version_resp);
+ break;
+ case SYNTHVID_RESOLUTION_RESPONSE:
+ /*
+ * The resolution response is variable length: the host
+ * fills resolution_count entries, not the full
+ * SYNTHVID_MAX_RESOLUTION_COUNT array. Require the fixed
+ * prefix first so resolution_count can be read, then
+ * demand exactly the count-sized array.
+ */
+ need += offsetof(struct synthvid_supported_resolution_resp,
+ supported_resolution);
+ if (bytes_recvd < need)
+ break;
+ if (msg->resolution_resp.resolution_count >
+ SYNTHVID_MAX_RESOLUTION_COUNT) {
+ drm_err_ratelimited(&hv->dev,
+ "synthvid resolution count too large: %u\n",
+ msg->resolution_resp.resolution_count);
+ return;
+ }
+ need += msg->resolution_resp.resolution_count *
+ sizeof(struct hvd_screen_info);
+ break;
+ case SYNTHVID_VRAM_LOCATION_ACK:
+ need += sizeof(struct synthvid_vram_location_ack);
+ break;
+ case SYNTHVID_FEATURE_CHANGE:
+ /*
+ * Not a completion-driving message: validate its own payload
+ * and consume it here rather than falling through to the
+ * memcpy/complete shared by the wait-event responses.
+ */
+ if (bytes_recvd < need +
+ sizeof(struct synthvid_feature_change)) {
+ drm_err_ratelimited(&hv->dev,
+ "synthvid feature change packet too small: %u\n",
+ bytes_recvd);
+ return;
+ }
hv->dirt_needed = msg->feature_chg.is_dirt_needed;
if (hv->dirt_needed)
hyperv_hide_hw_ptr(hv->hdev);
+ return;
+ default:
+ return;
+ }
+
+ /*
+ * Shared completion path for the wait-event responses
+ * (VERSION_RESPONSE, RESOLUTION_RESPONSE, VRAM_LOCATION_ACK):
+ * require the type-specific payload before handing the buffer to
+ * the waiter.
+ */
+ if (bytes_recvd < need) {
+ drm_err_ratelimited(&hv->dev,
+ "synthvid packet too small for type %u: %u < %zu\n",
+ msg->vid_hdr.type, bytes_recvd, need);
+ return;
}
+ memcpy(hv->init_buf, msg, bytes_recvd);
+ complete(&hv->wait);
}
static void hyperv_receive(void *ctx)
@@ -461,9 +526,21 @@ static void hyperv_receive(void *ctx)
ret = vmbus_recvpacket(hdev->channel, recv_buf,
VMBUS_MAX_PACKET_SIZE,
&bytes_recvd, &req_id);
- if (bytes_recvd > 0 &&
- recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
- hyperv_receive_sub(hdev);
+ if (ret) {
+ /*
+ * A nonzero return (e.g. -ENOBUFS for an oversized
+ * packet) is itself a malformed message: bytes_recvd
+ * then reports the required length rather than a copied
+ * payload, so it must not be forwarded to the
+ * sub-handler. Channel recovery is not attempted.
+ */
+ drm_err_ratelimited(&hv->dev,
+ "vmbus_recvpacket failed: %d (need %u)\n",
+ ret, bytes_recvd);
+ } else if (bytes_recvd > 0 &&
+ recv_buf->pipe_hdr.type == PIPE_MSG_DATA) {
+ hyperv_receive_sub(hdev, bytes_recvd);
+ }
} while (bytes_recvd > 0 && ret == 0);
}
@@ -508,9 +585,13 @@ int hyperv_connect_vsp(struct hv_device *hdev)
ret = hyperv_get_supported_resolution(hdev);
if (ret)
drm_err(dev, "Failed to get supported resolution from host, use default\n");
- } else {
+ }
+
+ if (!hv->screen_width_max) {
hv->screen_width_max = SYNTHVID_WIDTH_WIN8;
hv->screen_height_max = SYNTHVID_HEIGHT_WIN8;
+ hv->preferred_width = SYNTHVID_WIDTH_WIN8;
+ hv->preferred_height = SYNTHVID_HEIGHT_WIN8;
}
hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
index e7950655434b..6d1cffc6d2be 100644
--- a/drivers/gpu/drm/i915/display/intel_color.c
+++ b/drivers/gpu/drm/i915/display/intel_color.c
@@ -3976,7 +3976,7 @@ xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb,
intel_de_write_dsb(display, dsb,
PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
(1 << 24));
- } while (i++ > 130);
+ } while (i++ < 130);
} else {
for (i = 0; i < lut_size; i++) {
u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1);
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index d9baca2d5aaf..78afcd42f44c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -497,6 +497,7 @@ struct intel_display {
u8 vblank_enabled;
int vblank_enable_count;
+ bool vblank_status_last_notified;
struct work_struct vblank_notify_work;
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c
index 70c1bba7c0a8..aedf3928a089 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -1773,8 +1773,12 @@ static void intel_display_vblank_notify_work(struct work_struct *work)
struct intel_display *display =
container_of(work, typeof(*display), irq.vblank_notify_work);
int vblank_enable_count = READ_ONCE(display->irq.vblank_enable_count);
+ bool vblank_status = !!vblank_enable_count;
- intel_psr_notify_vblank_enable_disable(display, vblank_enable_count);
+ if (display->irq.vblank_status_last_notified != vblank_status) {
+ intel_psr_notify_vblank_enable_disable(display, vblank_status);
+ display->irq.vblank_status_last_notified = vblank_status;
+ }
}
int bdw_enable_vblank(struct drm_crtc *_crtc)
@@ -1787,10 +1791,10 @@ int bdw_enable_vblank(struct drm_crtc *_crtc)
if (gen11_dsi_configure_te(crtc, true))
return 0;
+ spin_lock_irqsave(&display->irq.lock, irqflags);
if (crtc->vblank_psr_notify && display->irq.vblank_enable_count++ == 0)
schedule_work(&display->irq.vblank_notify_work);
- spin_lock_irqsave(&display->irq.lock, irqflags);
bdw_enable_pipe_irq(display, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&display->irq.lock, irqflags);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index f6cd0a062090..2e6a85708555 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -584,6 +584,7 @@ struct intel_connector {
struct {
u8 dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
+ u8 intel_wa_dpcd;
bool support;
bool su_support;
@@ -1789,6 +1790,8 @@ struct intel_psr {
u8 active_non_psr_pipes;
const char *no_psr_reason;
+
+ struct ref_tracker *vblank_wakeref;
};
struct intel_dp {
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4955bd8b11d7..6ef2a0043cda 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3119,8 +3119,13 @@ static void intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc
drm_WARN_ON(display->drm,
vsc->bpc == 6 && vsc->pixelformat != DP_PIXELFORMAT_RGB);
- /* all YCbCr are always limited range */
- vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA;
+ /* All YCbCr formats are always limited range. */
+ if (vsc->pixelformat == DP_PIXELFORMAT_RGB)
+ vsc->dynamic_range = crtc_state->limited_color_range ?
+ DP_DYNAMIC_RANGE_CTA : DP_DYNAMIC_RANGE_VESA;
+ else
+ vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA;
+
vsc->content_type = DP_CONTENT_TYPE_NOT_DEFINED;
}
@@ -5298,7 +5303,7 @@ int intel_dp_as_sdp_unpack(struct drm_dp_as_sdp *as_sdp,
as_sdp->length = sdp->sdp_header.HB3 & DP_ADAPTIVE_SYNC_SDP_LENGTH;
as_sdp->mode = sdp->db[0] & DP_ADAPTIVE_SYNC_SDP_OPERATION_MODE;
as_sdp->vtotal = (sdp->db[2] << 8) | sdp->db[1];
- as_sdp->target_rr = (u64)sdp->db[3] | ((u64)sdp->db[4] & 0x3);
+ as_sdp->target_rr = ((sdp->db[4] & 0x3) << 8) | sdp->db[3];
as_sdp->target_rr_divider = sdp->db[4] & 0x20 ? true : false;
return 0;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
index b20ec3e589fa..9c9b6410366d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
@@ -12,6 +12,7 @@
#include "intel_dp.h"
#include "intel_dp_aux.h"
#include "intel_dp_aux_regs.h"
+#include "intel_parent.h"
#include "intel_pps.h"
#include "intel_quirks.h"
#include "intel_tc.h"
@@ -60,18 +61,29 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp)
struct intel_display *display = to_intel_display(intel_dp);
i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
const unsigned int timeout_ms = 10;
+ bool done = true;
u32 status;
- bool done;
+ int ret;
+ if (intel_parent_irq_enabled(display)) {
#define C (((status = intel_de_read_notrace(display, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
- done = wait_event_timeout(display->gmbus.wait_queue, C,
- msecs_to_jiffies_timeout(timeout_ms));
+ done = wait_event_timeout(display->gmbus.wait_queue, C,
+ msecs_to_jiffies_timeout(timeout_ms));
+
+#undef C
+ } else {
+ ret = intel_de_wait_ms(display, ch_ctl,
+ DP_AUX_CH_CTL_SEND_BUSY, 0,
+ timeout_ms, &status);
+
+ if (ret == -ETIMEDOUT)
+ done = false;
+ }
if (!done)
drm_err(display->drm,
"%s: did not complete or timeout within %ums (status 0x%08x)\n",
intel_dp->aux.name, timeout_ms, status);
-#undef C
return status;
}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
index a8d56ebf06a2..7a6c07f6aaeb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
@@ -691,10 +691,9 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct drm_device *dev = connector->base.dev;
struct intel_panel *panel = &connector->panel;
- bool try_intel_interface = false;
+ bool try_intel_interface = false, try_vesa_interface = false;
- /*
- * Check the VBT and user's module parameters to figure out which
+ /* Check the VBT and user's module parameters to figure out which
* interfaces to probe
*/
switch (display->params.enable_dpcd_backlight) {
@@ -703,6 +702,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
case INTEL_DP_AUX_BACKLIGHT_AUTO:
switch (panel->vbt.backlight.type) {
case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE:
+ try_vesa_interface = true;
break;
case INTEL_BACKLIGHT_DISPLAY_DDI:
try_intel_interface = true;
@@ -715,12 +715,20 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
if (panel->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE)
try_intel_interface = true;
+ try_vesa_interface = true;
+ break;
+ case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA:
+ try_vesa_interface = true;
break;
case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL:
try_intel_interface = true;
break;
}
+ /* For eDP 1.5 and above we are supposed to use VESA interface for brightness control */
+ if (intel_dp->edp_dpcd[0] >= DP_EDP_15)
+ try_vesa_interface = true;
+
/*
* Since Intel has their own backlight control interface, the majority of machines out there
* using DPCD backlight controls with Intel GPUs will be using this interface as opposed to
@@ -733,9 +741,6 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
* panel with Intel's OUI - which is also required for us to be able to detect Intel's
* backlight interface at all. This means that the only sensible way for us to detect both
* interfaces is to probe for Intel's first, and VESA's second.
- *
- * Also there is a chance some VBTs may advertise false Intel backlight support even if the
- * TCON DPCD says otherwise. This means we keep VESA interface as fallback in that case.
*/
if (try_intel_interface && intel_dp->edp_dpcd[0] <= DP_EDP_14b &&
intel_dp_aux_supports_hdr_backlight(connector)) {
@@ -745,7 +750,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
return 0;
}
- if (intel_dp_aux_supports_vesa_backlight(connector)) {
+ if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) {
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Using VESA eDP backlight controls\n",
connector->base.base.id, connector->base.name);
panel->backlight.funcs = &intel_dp_vesa_bl_funcs;
diff --git a/drivers/gpu/drm/i915/display/intel_dpcd.h b/drivers/gpu/drm/i915/display/intel_dpcd.h
new file mode 100644
index 000000000000..4aea5326f2ed
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_dpcd.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef __INTEL_DPCD_H__
+#define __INTEL_DPCD_H__
+
+#define INTEL_DPCD_INTEL_WA_REGISTER_CAPS 0x3f0
+# define INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_EARLYSCANLINE_SDP_SUPPORT_MASK REG_GENMASK(1, 0)
+# define INTEL_DPCD_INTEL_WA_REGISTER_CAPS_FALL_BACK_TO_PSR1 0
+# define INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_WITH_EARLY_SCANLINE 1
+# define INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_WITHOUT_EARLY_SCANLINE 2
+
+#endif /* __INTEL_DPCD_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index 5390ceb21ca4..07eae4176dad 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -144,6 +144,15 @@ intel_plane_duplicate_state(struct drm_plane *plane)
if (intel_state->hw.fb)
drm_framebuffer_get(intel_state->hw.fb);
+ if (intel_state->hw.degamma_lut)
+ drm_property_blob_get(intel_state->hw.degamma_lut);
+ if (intel_state->hw.gamma_lut)
+ drm_property_blob_get(intel_state->hw.gamma_lut);
+ if (intel_state->hw.ctm)
+ drm_property_blob_get(intel_state->hw.ctm);
+ if (intel_state->hw.lut_3d)
+ drm_property_blob_get(intel_state->hw.lut_3d);
+
return &intel_state->uapi;
}
@@ -167,6 +176,16 @@ intel_plane_destroy_state(struct drm_plane *plane,
__drm_atomic_helper_plane_destroy_state(&plane_state->uapi);
if (plane_state->hw.fb)
drm_framebuffer_put(plane_state->hw.fb);
+
+ if (plane_state->hw.degamma_lut)
+ drm_property_blob_put(plane_state->hw.degamma_lut);
+ if (plane_state->hw.gamma_lut)
+ drm_property_blob_put(plane_state->hw.gamma_lut);
+ if (plane_state->hw.ctm)
+ drm_property_blob_put(plane_state->hw.ctm);
+ if (plane_state->hw.lut_3d)
+ drm_property_blob_put(plane_state->hw.lut_3d);
+
kfree(plane_state);
}
@@ -317,6 +336,14 @@ static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
{
if (plane_state->hw.fb)
drm_framebuffer_put(plane_state->hw.fb);
+ if (plane_state->hw.degamma_lut)
+ drm_property_blob_put(plane_state->hw.degamma_lut);
+ if (plane_state->hw.gamma_lut)
+ drm_property_blob_put(plane_state->hw.gamma_lut);
+ if (plane_state->hw.ctm)
+ drm_property_blob_put(plane_state->hw.ctm);
+ if (plane_state->hw.lut_3d)
+ drm_property_blob_put(plane_state->hw.lut_3d);
memset(&plane_state->hw, 0, sizeof(plane_state->hw));
}
@@ -373,7 +400,7 @@ intel_plane_color_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
bool changed = false;
int i = 0;
- iter_colorop = plane_state->uapi.color_pipeline;
+ iter_colorop = from_plane_state->uapi.color_pipeline;
while (iter_colorop) {
for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 53c10ae76ab5..598fe769a402 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -43,6 +43,7 @@
#include "intel_display_wa.h"
#include "intel_dmc.h"
#include "intel_dp.h"
+#include "intel_dpcd.h"
#include "intel_dp_aux.h"
#include "intel_dsb.h"
#include "intel_frontbuffer.h"
@@ -716,8 +717,14 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *co
connector->dp.psr_caps.su_support ? "" : "not ");
}
- if (connector->dp.psr_caps.su_support)
+ if (connector->dp.psr_caps.su_support) {
+ ret = drm_dp_dpcd_read_byte(&intel_dp->aux,
+ INTEL_DPCD_INTEL_WA_REGISTER_CAPS,
+ &connector->dp.psr_caps.intel_wa_dpcd);
+ if (ret < 0)
+ return;
_psr_compute_su_granularity(intel_dp, connector);
+ }
}
void intel_psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
@@ -1358,9 +1365,35 @@ static bool psr2_granularity_check(struct intel_crtc_state *crtc_state,
return true;
}
-static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_dp,
- struct intel_crtc_state *crtc_state)
+static bool apply_scanline_indication_wa(struct intel_crtc_state *crtc_state,
+ struct intel_connector *connector)
{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ u8 early_scanline_support = connector->dp.psr_caps.intel_wa_dpcd &
+ INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_EARLYSCANLINE_SDP_SUPPORT_MASK;
+
+ if (intel_dp->edp_dpcd[0] >= DP_EDP_15)
+ return true;
+
+ switch (early_scanline_support) {
+ case INTEL_DPCD_INTEL_WA_REGISTER_CAPS_FALL_BACK_TO_PSR1:
+ crtc_state->req_psr2_sdp_prior_scanline = false;
+ return false;
+ case INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_WITH_EARLY_SCANLINE:
+ return true;
+ case INTEL_DPCD_INTEL_WA_REGISTER_CAPS_PSR2_WITHOUT_EARLY_SCANLINE:
+ crtc_state->req_psr2_sdp_prior_scanline = false;
+ return true;
+ default:
+ MISSING_CASE(early_scanline_support);
+ return false;
+ }
+}
+
+static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_crtc_state *crtc_state,
+ struct intel_connector *connector)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_display *display = to_intel_display(intel_dp);
const struct drm_display_mode *adjusted_mode = &crtc_state->uapi.adjusted_mode;
u32 hblank_total, hblank_ns, req_ns;
@@ -1379,7 +1412,8 @@ static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_d
return false;
crtc_state->req_psr2_sdp_prior_scanline = true;
- return true;
+
+ return apply_scanline_indication_wa(crtc_state, connector);
}
static int intel_psr_entry_setup_frames(struct intel_dp *intel_dp,
@@ -1660,7 +1694,7 @@ static bool intel_sel_update_config_valid(struct intel_crtc_state *crtc_state,
conn_state))
goto unsupported;
- if (!_compute_psr2_sdp_prior_scanline_indication(intel_dp, crtc_state)) {
+ if (!_compute_psr2_sdp_prior_scanline_indication(crtc_state, connector)) {
drm_dbg_kms(display->drm,
"Selective update not enabled, SDP indication do not fit in hblank\n");
goto unsupported;
@@ -4122,27 +4156,22 @@ void intel_psr_notify_vblank_enable_disable(struct intel_display *display,
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
mutex_lock(&intel_dp->psr.lock);
- if (intel_dp->psr.panel_replay_enabled) {
- mutex_unlock(&intel_dp->psr.lock);
- break;
+ if (CAN_PANEL_REPLAY(intel_dp)) {
+ if (enable)
+ intel_dp->psr.vblank_wakeref =
+ intel_display_power_get(display,
+ POWER_DOMAIN_DC_OFF);
+ else
+ intel_display_power_put(display, POWER_DOMAIN_DC_OFF,
+ intel_dp->psr.vblank_wakeref);
}
- if (intel_dp->psr.enabled && intel_dp->psr.pkg_c_latency_used)
+ if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled &&
+ intel_dp->psr.pkg_c_latency_used)
intel_psr_apply_underrun_on_idle_wa_locked(intel_dp);
mutex_unlock(&intel_dp->psr.lock);
- return;
}
-
- /*
- * NOTE: intel_display_power_set_target_dc_state is used
- * only by PSR * code for DC3CO handling. DC3CO target
- * state is currently disabled in * PSR code. If DC3CO
- * is taken into use we need take that into account here
- * as well.
- */
- intel_display_power_set_target_dc_state(display, enable ? DC_STATE_DISABLE :
- DC_STATE_EN_UPTO_DC6);
}
static void
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index de70517b4ef2..df3fcc2b1248 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -419,8 +419,6 @@ void i915_ttm_free_cached_io_rsgt(struct drm_i915_gem_object *obj)
int i915_ttm_purge(struct drm_i915_gem_object *obj)
{
struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
- struct i915_ttm_tt *i915_tt =
- container_of(bo->ttm, typeof(*i915_tt), ttm);
struct ttm_operation_ctx ctx = {
.interruptible = true,
.no_wait_gpu = false,
@@ -435,16 +433,22 @@ int i915_ttm_purge(struct drm_i915_gem_object *obj)
if (ret)
return ret;
- if (bo->ttm && i915_tt->filp) {
- /*
- * The below fput(which eventually calls shmem_truncate) might
- * be delayed by worker, so when directly called to purge the
- * pages(like by the shrinker) we should try to be more
- * aggressive and release the pages immediately.
- */
- shmem_truncate_range(file_inode(i915_tt->filp),
- 0, (loff_t)-1);
- fput(fetch_and_zero(&i915_tt->filp));
+ if (bo->ttm) {
+ struct i915_ttm_tt *i915_tt =
+ container_of(bo->ttm, typeof(*i915_tt), ttm);
+
+ if (i915_tt->filp) {
+ /*
+ * The below fput(which eventually calls shmem_truncate)
+ * might be delayed by worker, so when directly called
+ * to purge the pages(like by the shrinker) we should
+ * try to be more aggressive and release the pages
+ * immediately.
+ */
+ shmem_truncate_range(file_inode(i915_tt->filp),
+ 0, (loff_t)-1);
+ fput(fetch_and_zero(&i915_tt->filp));
+ }
}
obj->write_domain = 0;
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
index 984d0056c01c..adff482a6c9c 100644
--- a/drivers/gpu/drm/i915/gt/intel_reset.c
+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
@@ -132,7 +132,8 @@ void __i915_request_reset(struct i915_request *rq, bool guilty)
rcu_read_lock(); /* protect the GEM context */
if (guilty) {
i915_request_set_error_once(rq, -EIO);
- __i915_request_skip(rq);
+ if (!i915_request_signaled(rq))
+ __i915_request_skip(rq);
banned = mark_guilty(rq);
} else {
i915_request_set_error_once(rq, -EAGAIN);
diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c
index 385a634c3ed0..d9be7a5a239c 100644
--- a/drivers/gpu/drm/i915/i915_driver.c
+++ b/drivers/gpu/drm/i915/i915_driver.c
@@ -750,9 +750,8 @@ static bool has_auxccs(struct drm_device *drm)
{
struct drm_i915_private *i915 = to_i915(drm);
- return IS_GRAPHICS_VER(i915, 9, 12) ||
- IS_ALDERLAKE_P(i915) ||
- IS_METEORLAKE(i915);
+ return IS_GRAPHICS_VER(i915, 9, 12) &&
+ !HAS_FLAT_CCS(i915);
}
static bool has_fenced_regions(struct drm_device *drm)
diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c
index 32c3f46b21da..5c7f8d952ec1 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c
+++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c
@@ -166,6 +166,7 @@ static int exp_approx_q(int x)
* dcss_scaler_gaussian_filter() - Generate gaussian prototype filter.
* @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
* @use_5_taps: indicates whether to use 5 taps or 7 taps
+ * @phase0_identity: whether to override phase 0 coefficients with identity filter
* @coef: output filter coefficients
*/
static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
@@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps,
* @src_length: length of input
* @dst_length: length of output
* @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
+ * @phase0_identity: whether to override phase 0 coefficients with identity filter
* @coef: output coefficients
+ * @nn_interpolation: whether to use nearest neighbor instead of gaussian filter
*/
static void dcss_scaler_filter_design(int src_length, int dst_length,
bool use_5_taps, bool phase0_identity,
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index 1ece1ea42f78..34405073c4d4 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -293,7 +293,7 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
vga_client_register(pdev, lsdc_vga_set_decode);
- drm_kms_helper_poll_init(ddev);
+ drmm_kms_helper_poll_init(ddev);
if (loongson_vblank) {
ret = drm_vblank_init(ddev, descp->num_of_crtc);
diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c
index c7be530ca041..b8ccd6e55bed 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -240,7 +240,7 @@ static const struct of_device_id mtk_cec_of_ids[] = {
};
MODULE_DEVICE_TABLE(of, mtk_cec_of_ids);
-struct platform_driver mtk_cec_driver = {
+static struct platform_driver mtk_cec_driver = {
.probe = mtk_cec_probe,
.remove = mtk_cec_remove,
.driver = {
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
index 6358e1af69b4..2acbdb025d89 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
@@ -328,7 +328,7 @@ static const struct of_device_id mtk_hdmi_ddc_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_hdmi_ddc_match);
-struct platform_driver mtk_hdmi_ddc_driver = {
+static struct platform_driver mtk_hdmi_ddc_driver = {
.probe = mtk_hdmi_ddc_probe,
.remove = mtk_hdmi_ddc_remove,
.driver = {
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
index d937219fdb7e..31e81a6de6d8 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c
@@ -389,7 +389,7 @@ static const struct of_device_id mtk_hdmi_ddc_v2_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_hdmi_ddc_v2_match);
-struct platform_driver mtk_hdmi_ddc_v2_driver = {
+static struct platform_driver mtk_hdmi_ddc_v2_driver = {
.probe = mtk_hdmi_ddc_v2_probe,
.driver = {
.name = "mediatek-hdmi-ddc-v2",
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
index b5c738380dc2..a8eb6fd0908b 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
@@ -50,7 +50,7 @@ enum mtk_hdmi_v2_clk_id {
MTK_HDMI_V2_CLK_COUNT,
};
-const char *const mtk_hdmi_v2_clk_names[MTK_HDMI_V2_CLK_COUNT] = {
+static const char *const mtk_hdmi_v2_clk_names[MTK_HDMI_V2_CLK_COUNT] = {
[MTK_HDMI_V2_CLK_HDMI_APB_SEL] = "bus",
[MTK_HDMI_V2_CLK_HDCP_SEL] = "hdcp",
[MTK_HDMI_V2_CLK_HDCP_24M_SEL] = "hdcp24m",
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index d5aba072f44c..7a3e3c2f5cf3 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2621,7 +2621,6 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
struct platform_device *pdev = priv->gpu_pdev;
struct adreno_platform_config *config = pdev->dev.platform_data;
const struct adreno_info *info = config->info;
- struct device_node *node;
struct a6xx_gpu *a6xx_gpu;
struct adreno_gpu *adreno_gpu;
struct msm_gpu *gpu;
@@ -2643,7 +2642,8 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
adreno_gpu->registers = NULL;
/* Check if there is a GMU phandle and set it up */
- node = of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0);
+ struct device_node *node __free(device_node) =
+ of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0);
/* FIXME: How do we gracefully handle this? */
BUG_ON(!node);
@@ -2690,7 +2690,6 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
ret = a6xx_gmu_wrapper_init(a6xx_gpu, node);
else
ret = a6xx_gmu_init(a6xx_gpu, node);
- of_node_put(node);
if (ret) {
a6xx_destroy(&(a6xx_gpu->base.base));
return ERR_PTR(ret);
@@ -2740,6 +2739,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = {
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
+ .sysprof_setup = a6xx_gmu_sysprof_setup,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_gmu_get_timestamp,
@@ -2808,6 +2808,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
+ .sysprof_setup = a6xx_gmu_sysprof_setup,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_gmu_get_timestamp,
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
index 487c2736f2b3..186a73c0b99c 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
@@ -289,6 +289,8 @@ static int a8xx_hfi_send_perf_table(struct a6xx_gmu *gmu)
(gmu->nr_gpu_freqs * num_gx_votes * sizeof(gmu->gx_arc_votes[0])) +
(gmu->nr_gmu_freqs * num_cx_votes * sizeof(gmu->cx_arc_votes[0]));
tbl = kzalloc(size, GFP_KERNEL);
+ if (!tbl)
+ return -ENOMEM;
tbl->type = HFI_TABLE_GPU_PERF;
/* First fill GX votes */
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 4edfe80c5be7..fc38331ce640 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -17,7 +17,7 @@ MODULE_PARM_DESC(snapshot_debugbus, "Include debugbus sections in GPU devcoredum
module_param_named(snapshot_debugbus, snapshot_debugbus, bool, 0600);
int enable_preemption = -1;
-MODULE_PARM_DESC(enable_preemption, "Enable preemption (A7xx only) (1=on , 0=disable, -1=auto (default))");
+MODULE_PARM_DESC(enable_preemption, "Enable preemption (A7xx+ only) (1=on , 0=disable, -1=auto (default))");
module_param(enable_preemption, int, 0600);
bool disable_acd;
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 66f80f2d12f9..03f96a1154e1 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -376,7 +376,7 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
*value = adreno_gpu->info->gmem;
return 0;
case MSM_PARAM_GMEM_BASE:
- if (adreno_gpu->info->family >= ADRENO_6XX_GEN4)
+ if (adreno_gpu->info->family >= ADRENO_6XX_GEN3)
*value = 0;
else
*value = 0x100000;
@@ -424,15 +424,21 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
*value = vm->mm_range;
return 0;
case MSM_PARAM_HIGHEST_BANK_BIT:
+ if (!adreno_gpu->ubwc_config)
+ return UERR(ENOENT, drm, "no UBWC on this platform");
*value = adreno_gpu->ubwc_config->highest_bank_bit;
return 0;
case MSM_PARAM_RAYTRACING:
*value = adreno_gpu->has_ray_tracing;
return 0;
case MSM_PARAM_UBWC_SWIZZLE:
+ if (!adreno_gpu->ubwc_config)
+ return UERR(ENOENT, drm, "no UBWC on this platform");
*value = adreno_gpu->ubwc_config->ubwc_swizzle;
return 0;
case MSM_PARAM_MACROTILE_MODE:
+ if (!adreno_gpu->ubwc_config)
+ return UERR(ENOENT, drm, "no UBWC on this platform");
*value = adreno_gpu->ubwc_config->macrotile_mode;
return 0;
case MSM_PARAM_UCHE_TRAP_BASE:
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h
index b7b06e45b529..06da1583fb1e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h
@@ -480,7 +480,7 @@ const struct dpu_mdss_cfg dpu_kaanapali_cfg = {
.wb_count = ARRAY_SIZE(kaanapali_wb),
.wb = kaanapali_wb,
.cwb_count = ARRAY_SIZE(kaanapali_cwb),
- .cwb = sm8650_cwb,
+ .cwb = kaanapali_cwb,
.intf_count = ARRAY_SIZE(kaanapali_intf),
.intf = kaanapali_intf,
.vbif = &sm8650_vbif,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
index 6e8883dbfad4..590922c4f69b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
@@ -61,7 +61,7 @@ static int _dpu_format_populate_plane_sizes_ubwc(
bool meta = MSM_FORMAT_IS_UBWC(fmt);
if (MSM_FORMAT_IS_YUV(fmt)) {
- unsigned int stride, sclines;
+ unsigned int stride, y_sclines, uv_sclines;
unsigned int y_tile_width, y_tile_height;
unsigned int y_meta_stride, y_meta_scanlines;
unsigned int uv_meta_stride, uv_meta_scanlines;
@@ -77,23 +77,25 @@ static int _dpu_format_populate_plane_sizes_ubwc(
y_tile_width = 32;
}
- sclines = round_up(fb->height, 16);
+ y_sclines = round_up(fb->height, 16);
+ uv_sclines = round_up((fb->height+1)>>1, 16);
y_tile_height = 4;
} else {
stride = round_up(fb->width, 128);
y_tile_width = 32;
- sclines = round_up(fb->height, 32);
+ y_sclines = round_up(fb->height, 32);
+ uv_sclines = round_up((fb->height+1)>>1, 32);
y_tile_height = 8;
}
layout->plane_pitch[0] = stride;
layout->plane_size[0] = round_up(layout->plane_pitch[0] *
- sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
+ y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
layout->plane_pitch[1] = stride;
layout->plane_size[1] = round_up(layout->plane_pitch[1] *
- sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
+ uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT);
if (!meta)
return 0;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
index 7545c0293efb..6f2370c9dd98 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
@@ -5,6 +5,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_managed.h>
#include "dpu_writeback.h"
@@ -125,7 +126,7 @@ int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
struct dpu_wb_connector *dpu_wb_conn;
int rc = 0;
- dpu_wb_conn = devm_kzalloc(dev->dev, sizeof(*dpu_wb_conn), GFP_KERNEL);
+ dpu_wb_conn = drmm_kzalloc(dev, sizeof(*dpu_wb_conn), GFP_KERNEL);
if (!dpu_wb_conn)
return -ENOMEM;
diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c
index 427d3ee2b833..e603ab3817cd 100644
--- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c
+++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c
@@ -5,11 +5,11 @@
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
-#include <generated/utsrelease.h>
+#include <linux/utsname.h>
#include "msm_disp_snapshot.h"
-static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr)
+static void msm_disp_state_dump_regs(u32 **reg, u32 len, void __iomem *base_addr)
{
u32 len_padded;
u32 num_rows;
@@ -19,11 +19,11 @@ static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *b
void __iomem *end_addr;
int i;
- len_padded = aligned_len * REG_DUMP_ALIGN;
- num_rows = aligned_len / REG_DUMP_ALIGN;
+ len_padded = round_up(len, REG_DUMP_ALIGN);
+ num_rows = DIV_ROUND_UP(len, REG_DUMP_ALIGN);
addr = base_addr;
- end_addr = base_addr + aligned_len;
+ end_addr = base_addr + len;
*reg = kvzalloc(len_padded, GFP_KERNEL);
if (!*reg)
@@ -48,8 +48,8 @@ static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *b
static void msm_disp_state_print_regs(const u32 *dump_addr, u32 len,
void __iomem *base_addr, struct drm_printer *p)
{
+ void __iomem *addr, *end_addr;
int i;
- void __iomem *addr;
u32 num_rows;
if (!dump_addr) {
@@ -58,6 +58,7 @@ static void msm_disp_state_print_regs(const u32 *dump_addr, u32 len,
}
addr = base_addr;
+ end_addr = base_addr + len;
num_rows = len / REG_DUMP_ALIGN;
for (i = 0; i < num_rows; i++) {
@@ -67,6 +68,17 @@ static void msm_disp_state_print_regs(const u32 *dump_addr, u32 len,
dump_addr[i * 4 + 2], dump_addr[i * 4 + 3]);
addr += REG_DUMP_ALIGN;
}
+
+ if (addr != end_addr) {
+ drm_printf(p, "0x%lx : %08x",
+ (unsigned long)(addr - base_addr),
+ dump_addr[i * 4]);
+ if (addr + 0x4 < end_addr)
+ drm_printf(p, " %08x", dump_addr[i * 4 + 1]);
+ if (addr + 0x8 < end_addr)
+ drm_printf(p, " %08x", dump_addr[i * 4 + 2]);
+ drm_printf(p, "\n");
+ }
}
void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p)
@@ -79,7 +91,7 @@ void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p)
}
drm_printf(p, "---\n");
- drm_printf(p, "kernel: " UTS_RELEASE "\n");
+ drm_printf(p, "kernel: %s\n", init_utsname()->release);
drm_printf(p, "module: " KBUILD_MODNAME "\n");
drm_printf(p, "dpu devcoredump\n");
drm_printf(p, "time: %ptSp\n", &state->time);
@@ -185,7 +197,7 @@ void msm_disp_snapshot_add_block(struct msm_disp_state *disp_state, u32 len,
va_end(va);
INIT_LIST_HEAD(&new_blk->node);
- new_blk->size = ALIGN(len, REG_DUMP_ALIGN);
+ new_blk->size = len;
new_blk->base_addr = base_addr;
msm_disp_state_dump_regs(&new_blk->state, new_blk->size, base_addr);
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 565d425f88b8..982abaaac00d 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -2033,6 +2033,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
/* fixup base address by io offset */
msm_host->ctrl_base += cfg->io_offset;
+ msm_host->ctrl_size -= cfg->io_offset;
ret = devm_regulator_bulk_get_const(&pdev->dev, cfg->num_regulators,
cfg->regulator_data,
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 195f40e331e5..cc2bcd14b1c2 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -128,11 +128,10 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv,
/*
* Initialize the LRUs:
*/
- mutex_init(&priv->lru.lock);
- drm_gem_lru_init(&priv->lru.unbacked, &priv->lru.lock);
- drm_gem_lru_init(&priv->lru.pinned, &priv->lru.lock);
- drm_gem_lru_init(&priv->lru.willneed, &priv->lru.lock);
- drm_gem_lru_init(&priv->lru.dontneed, &priv->lru.lock);
+ drm_gem_lru_init(&priv->lru.unbacked);
+ drm_gem_lru_init(&priv->lru.pinned);
+ drm_gem_lru_init(&priv->lru.willneed);
+ drm_gem_lru_init(&priv->lru.dontneed);
/* Initialize stall-on-fault */
spin_lock_init(&priv->fault_stall_lock);
@@ -140,7 +139,7 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv,
/* Teach lockdep about lock ordering wrt. shrinker: */
fs_reclaim_acquire(GFP_KERNEL);
- might_lock(&priv->lru.lock);
+ might_lock(&ddev->gem_lru_mutex);
fs_reclaim_release(GFP_KERNEL);
if (priv->kms_init) {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 6d847d593f1a..617b3c4b42c0 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -150,13 +150,6 @@ struct msm_drm_private {
* DONTNEED state (ie. can be purged)
*/
struct drm_gem_lru dontneed;
-
- /**
- * lock:
- *
- * Protects manipulation of all of the LRUs.
- */
- struct mutex lock;
} lru;
struct notifier_block vmap_notifier;
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 2cb3ab04f125..efd3d3c9a449 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -177,11 +177,11 @@ static void update_lru_locked(struct drm_gem_object *obj)
static void update_lru(struct drm_gem_object *obj)
{
- struct msm_drm_private *priv = obj->dev->dev_private;
+ struct drm_device *dev = obj->dev;
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
update_lru_locked(obj);
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
}
static struct page **get_pages(struct drm_gem_object *obj)
@@ -292,11 +292,11 @@ void msm_gem_pin_obj_locked(struct drm_gem_object *obj)
static void pin_obj_locked(struct drm_gem_object *obj)
{
- struct msm_drm_private *priv = obj->dev->dev_private;
+ struct drm_device *dev = obj->dev;
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
msm_gem_pin_obj_locked(obj);
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
}
struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj)
@@ -487,16 +487,16 @@ int msm_gem_pin_vma_locked(struct drm_gem_object *obj, struct drm_gpuva *vma)
void msm_gem_unpin_locked(struct drm_gem_object *obj)
{
- struct msm_drm_private *priv = obj->dev->dev_private;
+ struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_gem_assert_locked(obj);
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
msm_obj->pin_count--;
GEM_WARN_ON(msm_obj->pin_count < 0);
update_lru_locked(obj);
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
}
/* Special unpin path for use in fence-signaling path, avoiding the need
@@ -507,10 +507,10 @@ void msm_gem_unpin_locked(struct drm_gem_object *obj)
*/
void msm_gem_unpin_active(struct drm_gem_object *obj)
{
- struct msm_drm_private *priv = obj->dev->dev_private;
+ struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- GEM_WARN_ON(!mutex_is_locked(&priv->lru.lock));
+ GEM_WARN_ON(!mutex_is_locked(&dev->gem_lru_mutex));
msm_obj->pin_count--;
GEM_WARN_ON(msm_obj->pin_count < 0);
@@ -797,12 +797,12 @@ void msm_gem_put_vaddr(struct drm_gem_object *obj)
*/
int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv)
{
- struct msm_drm_private *priv = obj->dev->dev_private;
+ struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_gem_lock(obj);
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
if (msm_obj->madv != __MSM_MADV_PURGED)
msm_obj->madv = madv;
@@ -814,7 +814,7 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv)
*/
update_lru_locked(obj);
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
msm_gem_unlock(obj);
@@ -824,7 +824,6 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv)
void msm_gem_purge(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_gem_assert_locked(obj);
@@ -839,10 +838,10 @@ void msm_gem_purge(struct drm_gem_object *obj)
put_pages(obj);
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
/* A one-way transition: */
msm_obj->madv = __MSM_MADV_PURGED;
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
drm_gem_free_mmap_offset(obj);
diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c
index 31fa51a44f86..9d2788f79ace 100644
--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c
+++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c
@@ -43,8 +43,7 @@ msm_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
}
static bool
-with_vm_locks(struct ww_acquire_ctx *ticket,
- void (*fn)(struct drm_gem_object *obj),
+with_vm_locks(void (*fn)(struct drm_gem_object *obj),
struct drm_gem_object *obj)
{
/*
@@ -52,7 +51,7 @@ with_vm_locks(struct ww_acquire_ctx *ticket,
* success paths
*/
struct drm_gpuvm_bo *vm_bo, *last_locked = NULL;
- int ret = 0;
+ bool locked = true;
drm_gem_for_each_gpuvm_bo (vm_bo, obj) {
struct dma_resv *resv = drm_gpuvm_resv(vm_bo->vm);
@@ -60,23 +59,14 @@ with_vm_locks(struct ww_acquire_ctx *ticket,
if (resv == obj->resv)
continue;
- ret = dma_resv_lock(resv, ticket);
-
- /*
- * Since we already skip the case when the VM and obj
- * share a resv (ie. _NO_SHARE objs), we don't expect
- * to hit a double-locking scenario... which the lock
- * unwinding cannot really cope with.
- */
- WARN_ON(ret == -EALREADY);
-
/*
- * Don't bother with slow-lock / backoff / retry sequence,
- * if we can't get the lock just give up and move on to
- * the next object.
+ * dma_resv_lock can't be used due to acquiring 'ticket' before the
+ * fs_reclaim lock, which is held in shrinker context
*/
- if (ret)
+ if (!dma_resv_trylock(resv)) {
+ locked = false;
goto out_unlock;
+ }
/*
* Hold a ref to prevent the vm_bo from being freed
@@ -108,11 +98,11 @@ out_unlock:
}
}
- return ret == 0;
+ return locked;
}
static bool
-purge(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket)
+purge(struct drm_gem_object *obj, struct ww_acquire_ctx *unused)
{
if (!is_purgeable(to_msm_bo(obj)))
return false;
@@ -120,11 +110,11 @@ purge(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket)
if (msm_gem_active(obj))
return false;
- return with_vm_locks(ticket, msm_gem_purge, obj);
+ return with_vm_locks(msm_gem_purge, obj);
}
static bool
-evict(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket)
+evict(struct drm_gem_object *obj, struct ww_acquire_ctx *unused)
{
if (is_unevictable(to_msm_bo(obj)))
return false;
@@ -132,7 +122,7 @@ evict(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket)
if (msm_gem_active(obj))
return false;
- return with_vm_locks(ticket, msm_gem_evict, obj);
+ return with_vm_locks(msm_gem_evict, obj);
}
static bool
@@ -164,7 +154,6 @@ static unsigned long
msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
{
struct msm_drm_private *priv = shrinker->private_data;
- struct ww_acquire_ctx ticket;
struct {
struct drm_gem_lru *lru;
bool (*shrink)(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket);
@@ -185,11 +174,14 @@ msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
for (unsigned i = 0; (nr > 0) && (i < ARRAY_SIZE(stages)); i++) {
if (!stages[i].cond)
continue;
+ /*
+ * 'ticket' not needed on trylock paths
+ */
stages[i].freed =
- drm_gem_lru_scan(stages[i].lru, nr,
+ drm_gem_lru_scan(priv->dev, stages[i].lru, nr,
&stages[i].remaining,
stages[i].shrink,
- &ticket);
+ NULL);
nr -= stages[i].freed;
freed += stages[i].freed;
remaining += stages[i].remaining;
@@ -255,7 +247,7 @@ msm_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr)
unsigned long remaining = 0;
for (idx = 0; lrus[idx] && unmapped < vmap_shrink_limit; idx++) {
- unmapped += drm_gem_lru_scan(lrus[idx],
+ unmapped += drm_gem_lru_scan(priv->dev, lrus[idx],
vmap_shrink_limit - unmapped,
&remaining,
vmap_shrink,
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 26ea8a28be47..3c6bc90c3d48 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -352,7 +352,7 @@ static int submit_fence_sync(struct msm_gem_submit *submit)
static int submit_pin_objects(struct msm_gem_submit *submit)
{
- struct msm_drm_private *priv = submit->dev->dev_private;
+ struct drm_device *dev = submit->dev;
int i, ret = 0;
for (i = 0; i < submit->nr_bos; i++) {
@@ -381,11 +381,11 @@ static int submit_pin_objects(struct msm_gem_submit *submit)
* get_pages() which could trigger reclaim.. and if we held the LRU lock
* could trigger deadlock with the shrinker).
*/
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
for (i = 0; i < submit->nr_bos; i++) {
msm_gem_pin_obj_locked(submit->bos[i].obj);
}
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
submit->bos_pinned = true;
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index 1a952b171ed7..c4cfe036066b 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -702,7 +702,7 @@ static struct dma_fence *
msm_vma_job_run(struct drm_sched_job *_job)
{
struct msm_vm_bind_job *job = to_msm_vm_bind_job(_job);
- struct msm_drm_private *priv = job->vm->drm->dev_private;
+ struct drm_device *dev = job->vm->drm;
struct msm_gem_vm *vm = to_msm_vm(job->vm);
struct drm_gem_object *obj;
int ret = vm->unusable ? -EINVAL : 0;
@@ -745,13 +745,13 @@ msm_vma_job_run(struct drm_sched_job *_job)
if (ret)
msm_gem_vm_unusable(job->vm);
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
job_foreach_bo (obj, job) {
msm_gem_unpin_active(obj);
}
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
/* VM_BIND ops are synchronous, so no fence to wait on: */
return NULL;
@@ -1305,7 +1305,7 @@ vm_bind_job_pin_objects(struct msm_vm_bind_job *job)
return PTR_ERR(pages);
}
- struct msm_drm_private *priv = job->vm->drm->dev_private;
+ struct drm_device *dev = job->vm->drm;
/*
* A second loop while holding the LRU lock (a) avoids acquiring/dropping
@@ -1314,10 +1314,10 @@ vm_bind_job_pin_objects(struct msm_vm_bind_job *job)
* get_pages() which could trigger reclaim.. and if we held the LRU lock
* could trigger deadlock with the shrinker).
*/
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
job_foreach_bo (obj, job)
msm_gem_pin_obj_locked(obj);
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
job->bos_pinned = true;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 930e54d1b0a7..3f3925b11eea 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -13,11 +13,11 @@
#include "msm_gpu_trace.h"
//#include "adreno/adreno_gpu.h"
-#include <generated/utsrelease.h>
#include <linux/string_helpers.h>
#include <linux/devcoredump.h>
#include <linux/sched/task.h>
#include <linux/sched/mm.h>
+#include <linux/utsname.h>
/*
* Power Management:
@@ -196,7 +196,7 @@ static ssize_t msm_gpu_devcoredump_read(char *buffer, loff_t offset,
p = drm_coredump_printer(&iter);
drm_printf(&p, "---\n");
- drm_printf(&p, "kernel: " UTS_RELEASE "\n");
+ drm_printf(&p, "kernel: %s\n", init_utsname()->release);
drm_printf(&p, "module: " KBUILD_MODNAME "\n");
drm_printf(&p, "time: %ptSp\n", &state->time);
if (state->comm)
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 7d449e5202c5..058c71c82cf5 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -677,7 +677,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
int prot)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
- size_t ret;
+ ssize_t ret;
WARN_ON(off != 0);
@@ -686,7 +686,8 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
iova |= GENMASK_ULL(63, 49);
ret = iommu_map_sgtable(iommu->domain, iova, sgt, prot);
- WARN_ON(!ret);
+ if (ret < 0)
+ return ret;
return (ret == len) ? 0 : -EINVAL;
}
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index 30ddb5351e98..2d6b930b766e 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -16,13 +16,13 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job)
struct msm_gem_submit *submit = to_msm_submit(job);
struct msm_fence_context *fctx = submit->ring->fctx;
struct msm_gpu *gpu = submit->gpu;
- struct msm_drm_private *priv = gpu->dev->dev_private;
+ struct drm_device *dev = gpu->dev;
unsigned nr_cmds = submit->nr_cmds;
int i;
msm_fence_init(submit->hw_fence, fctx);
- mutex_lock(&priv->lru.lock);
+ mutex_lock(&dev->gem_lru_mutex);
for (i = 0; i < submit->nr_bos; i++) {
struct drm_gem_object *obj = submit->bos[i].obj;
@@ -32,7 +32,7 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job)
submit->bos_pinned = false;
- mutex_unlock(&priv->lru.lock);
+ mutex_unlock(&dev->gem_lru_mutex);
/* TODO move submit path over to using a per-ring lock.. */
mutex_lock(&gpu->lock);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index 72848ed80df7..b101e14f841e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -2513,6 +2513,7 @@ static const struct nvkm_device_chip
nv170_chipset = {
.name = "GA100",
.bar = { 0x00000001, tu102_bar_new },
+ .bios = { 0x00000001, nvkm_bios_new },
.devinit = { 0x00000001, ga100_devinit_new },
.fault = { 0x00000001, tu102_fault_new },
.fb = { 0x00000001, ga100_fb_new },
@@ -2529,7 +2530,6 @@ nv170_chipset = {
.vfn = { 0x00000001, ga100_vfn_new },
.ce = { 0x000003ff, ga100_ce_new },
.fifo = { 0x00000001, ga100_fifo_new },
- .sec2 = { 0x00000001, tu102_sec2_new },
};
static const struct nvkm_device_chip
@@ -3341,7 +3341,6 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x166: device->chip = &nv166_chipset; break;
case 0x167: device->chip = &nv167_chipset; break;
case 0x168: device->chip = &nv168_chipset; break;
- case 0x170: device->chip = &nv170_chipset; break;
case 0x172: device->chip = &nv172_chipset; break;
case 0x173: device->chip = &nv173_chipset; break;
case 0x174: device->chip = &nv174_chipset; break;
@@ -3361,6 +3360,14 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x1b6: device->chip = &nv1b6_chipset; break;
case 0x1b7: device->chip = &nv1b7_chipset; break;
default:
+ if (nvkm_boolopt(device->cfgopt, "NvEnableUnsupportedChipsets", false)) {
+ switch (device->chipset) {
+ case 0x170: device->chip = &nv170_chipset; break;
+ default:
+ break;
+ }
+ }
+
if (!device->chip) {
nvdev_error(device, "unknown chipset (%08x)\n", boot0);
ret = -ENODEV;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c
index fdd820eeef81..27a13aeccd3c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c
@@ -41,11 +41,15 @@ ga100_gsp_flcn = {
static const struct nvkm_gsp_func
ga100_gsp = {
.flcn = &ga100_gsp_flcn,
+ .fwsec = &tu102_gsp_fwsec,
.sig_section = ".fwsignature_ga100",
.booter.ctor = tu102_gsp_booter_ctor,
+ .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor,
+ .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor,
+
.dtor = r535_gsp_dtor,
.oneinit = tu102_gsp_oneinit,
.init = tu102_gsp_init,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c
index dd82c76b8b9a..19cb269e7a26 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c
@@ -318,13 +318,8 @@ tu102_gsp_oneinit(struct nvkm_gsp *gsp)
if (ret)
return ret;
- /*
- * Calculate FB layout. FRTS is a memory region created by the FWSEC-FRTS firmware.
- * FWSEC comes from VBIOS. So on systems with no VBIOS (e.g. GA100), the FRTS does
- * not exist. Therefore, use the existence of VBIOS to determine whether to reserve
- * an FRTS region.
- */
- gsp->fb.wpr2.frts.size = device->bios ? 0x100000 : 0;
+ /* Calculate FB layout. */
+ gsp->fb.wpr2.frts.size = 0x100000;
gsp->fb.wpr2.frts.addr = ALIGN_DOWN(gsp->fb.bios.addr, 0x20000) - gsp->fb.wpr2.frts.size;
gsp->fb.wpr2.boot.size = gsp->boot.fw.size;
@@ -348,12 +343,9 @@ tu102_gsp_oneinit(struct nvkm_gsp *gsp)
if (ret)
return ret;
- /* Only boot FWSEC-FRTS if it actually exists */
- if (gsp->fb.wpr2.frts.size) {
- ret = nvkm_gsp_fwsec_frts(gsp);
- if (WARN_ON(ret))
- return ret;
- }
+ ret = nvkm_gsp_fwsec_frts(gsp);
+ if (WARN_ON(ret))
+ return ret;
/* Reset GSP into RISC-V mode. */
ret = gsp->func->reset(gsp);
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d6863b28ddc5..d592f4f4b939 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -208,6 +208,7 @@ config DRM_PANEL_HIMAX_HX83121A
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_DSC_HELPER
select DRM_KMS_HELPER
help
Say Y here if you want to enable support for Himax HX83121A-based
diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
index d5fe105bdbdd..658ce64c71eb 100644
--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
+++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
@@ -1324,6 +1324,8 @@ static int boe_panel_disable(struct drm_panel *panel)
mipi_dsi_dcs_set_display_off_multi(&ctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
+ boe->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
mipi_dsi_msleep(&ctx, 150);
return ctx.accum_err;
diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
index 4f8d6d8c07e4..dbdb7e3cb7b6 100644
--- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
@@ -98,9 +98,7 @@ static int feiyang_enable(struct drm_panel *panel)
/* T12 (video & logic signal rise + backlight rise) T12 >= 200ms */
msleep(200);
- mipi_dsi_dcs_set_display_on(ctx->dsi);
-
- return 0;
+ return mipi_dsi_dcs_set_display_on(ctx->dsi);
}
static int feiyang_disable(struct drm_panel *panel)
diff --git a/drivers/gpu/drm/panel/panel-himax-hx83102.c b/drivers/gpu/drm/panel/panel-himax-hx83102.c
index 8b2a68ee851e..a5e5c9ea7a73 100644
--- a/drivers/gpu/drm/panel/panel-himax-hx83102.c
+++ b/drivers/gpu/drm/panel/panel-himax-hx83102.c
@@ -937,6 +937,8 @@ static int hx83102_disable(struct drm_panel *panel)
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
mipi_dsi_msleep(&dsi_ctx, 150);
return dsi_ctx.accum_err;
diff --git a/drivers/gpu/drm/panel/panel-himax-hx83121a.c b/drivers/gpu/drm/panel/panel-himax-hx83121a.c
index ebe643ba4184..bed79aa06f46 100644
--- a/drivers/gpu/drm/panel/panel-himax-hx83121a.c
+++ b/drivers/gpu/drm/panel/panel-himax-hx83121a.c
@@ -596,8 +596,8 @@ static int himax_probe(struct mipi_dsi_device *dsi)
ctx = devm_drm_panel_alloc(dev, struct himax, panel, &himax_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
- if (!ctx)
- return -ENOMEM;
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
ret = devm_regulator_bulk_get_const(&dsi->dev,
ARRAY_SIZE(himax_supplies),
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 711f5101aa04..074c0995ddc2 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -390,6 +390,8 @@ panfrost_ioctl_wait_bo(struct drm_device *dev, void *data,
true, timeout);
if (!ret)
ret = timeout ? -ETIMEDOUT : -EBUSY;
+ else if (ret > 0)
+ ret = 0;
drm_gem_object_put(gem_obj);
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 2bbb1168a3ff..1e6a2392d7c6 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -118,12 +118,13 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Complete initialization. */
ret = drm_dev_register(&qdev->ddev, ent->driver_data);
if (ret)
- goto modeset_cleanup;
+ goto poll_fini;
drm_client_setup(&qdev->ddev, NULL);
return 0;
-modeset_cleanup:
+poll_fini:
+ drm_kms_helper_poll_fini(&qdev->ddev);
qxl_modeset_fini(qdev);
unload:
qxl_device_fini(qdev);
@@ -154,6 +155,7 @@ qxl_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
+ drm_kms_helper_poll_fini(dev);
drm_dev_unregister(dev);
drm_atomic_helper_shutdown(dev);
if (pci_is_vga(pdev) && pdev->revision < 5)
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c
index 22321eb95b7d..703848fac189 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.c
+++ b/drivers/gpu/drm/radeon/ci_dpm.c
@@ -2461,7 +2461,8 @@ static void ci_register_patching_mc_arb(struct radeon_device *rdev,
if (patch &&
((rdev->pdev->device == 0x67B0) ||
- (rdev->pdev->device == 0x67B1))) {
+ (rdev->pdev->device == 0x67B1)) &&
+ (rdev->pdev->revision == 0)) {
if ((memory_clock > 100000) && (memory_clock <= 125000)) {
tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff;
*dram_timimg2 &= ~0x00ff0000;
@@ -3304,7 +3305,8 @@ static int ci_populate_all_memory_levels(struct radeon_device *rdev)
pi->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
if ((dpm_table->mclk_table.count >= 2) &&
- ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1))) {
+ ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1)) &&
+ (rdev->pdev->revision == 0)) {
pi->smc_state_table.MemoryLevel[1].MinVddc =
pi->smc_state_table.MemoryLevel[0].MinVddc;
pi->smc_state_table.MemoryLevel[1].MinVddcPhases =
@@ -4493,7 +4495,8 @@ static int ci_register_patching_mc_seq(struct radeon_device *rdev,
if (patch &&
((rdev->pdev->device == 0x67B0) ||
- (rdev->pdev->device == 0x67B1))) {
+ (rdev->pdev->device == 0x67B1)) &&
+ (rdev->pdev->revision == 0)) {
for (i = 0; i < table->last; i++) {
if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 3142ef4da7f4..9196f85db9ce 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -312,8 +312,10 @@ static int evergreen_surface_check(struct radeon_cs_parser *p,
case ARRAY_2D_TILED_THIN1:
return evergreen_surface_check_2d(p, surf, prefix);
default:
- dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
- __func__, __LINE__, prefix, surf->mode);
+ if (prefix) {
+ dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
+ __func__, __LINE__, prefix, surf->mode);
+ }
return -EINVAL;
}
return -EINVAL;
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index b7397827889c..360a88ca8f0c 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -741,6 +741,7 @@ static int sti_hda_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct sti_hda *hda;
struct resource *res;
+ int ret;
DRM_INFO("%s\n", __func__);
@@ -779,7 +780,9 @@ static int sti_hda_probe(struct platform_device *pdev)
return PTR_ERR(hda->clk_hddac);
}
- drm_bridge_add(&hda->bridge);
+ ret = devm_drm_bridge_add(dev, &hda->bridge);
+ if (ret)
+ return ret;
platform_set_drvdata(pdev, hda);
@@ -788,10 +791,7 @@ static int sti_hda_probe(struct platform_device *pdev)
static void sti_hda_remove(struct platform_device *pdev)
{
- struct sti_hda *hda = platform_get_drvdata(pdev);
-
component_del(&pdev->dev, &sti_hda_ops);
- drm_bridge_remove(&hda->bridge);
}
static const struct of_device_id hda_of_match[] = {
diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c
index 222e4ae1abbd..5d8dc5efec77 100644
--- a/drivers/gpu/drm/tiny/bochs.c
+++ b/drivers/gpu/drm/tiny/bochs.c
@@ -761,25 +761,21 @@ static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent
ret = pcim_enable_device(pdev);
if (ret)
- goto err_free_dev;
+ return ret;
pci_set_drvdata(pdev, dev);
ret = bochs_load(bochs);
if (ret)
- goto err_free_dev;
+ return ret;
ret = drm_dev_register(dev, 0);
if (ret)
- goto err_free_dev;
+ return ret;
drm_client_setup(dev, NULL);
return ret;
-
-err_free_dev:
- drm_dev_put(dev);
- return ret;
}
static void bochs_pci_remove(struct pci_dev *pdev)
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index d85f0a37ac35..bcd76f6bb7f0 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -739,7 +739,7 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM);
ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL);
if (ret) {
- if (ret != -ENOSPC && ret != -EAGAIN) {
+ if (ret != -ENOSPC) {
dmem_cgroup_pool_state_put(limit_pool);
return ret;
}
@@ -1177,17 +1177,13 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
bdev->funcs->swap_notify(bo);
if (ttm_tt_is_populated(tt)) {
- spin_lock(&bdev->lru_lock);
- ttm_resource_del_bulk_move(bo->resource, bo);
- spin_unlock(&bdev->lru_lock);
-
ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
-
- spin_lock(&bdev->lru_lock);
- if (ret)
- ttm_resource_add_bulk_move(bo->resource, bo);
- ttm_resource_move_to_lru_tail(bo->resource);
- spin_unlock(&bdev->lru_lock);
+ if (!ret) {
+ spin_lock(&bdev->lru_lock);
+ ttm_resource_del_bulk_move_unevictable(bo->resource, bo);
+ ttm_resource_move_to_lru_tail(bo->resource);
+ spin_unlock(&bdev->lru_lock);
+ }
}
out:
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index f83b7d5ec6c6..3e3c201a0222 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -1112,19 +1112,14 @@ long ttm_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
if (lret < 0)
return lret;
- if (bo->bulk_move) {
- spin_lock(&bdev->lru_lock);
- ttm_resource_del_bulk_move(bo->resource, bo);
- spin_unlock(&bdev->lru_lock);
- }
-
lret = ttm_tt_backup(bdev, bo->ttm, (struct ttm_backup_flags)
{.purge = flags.purge,
.writeback = flags.writeback});
- if (lret <= 0 && bo->bulk_move) {
+ if (lret > 0) {
spin_lock(&bdev->lru_lock);
- ttm_resource_add_bulk_move(bo->resource, bo);
+ ttm_resource_del_bulk_move_unevictable(bo->resource, bo);
+ ttm_resource_move_to_lru_tail(bo->resource);
spin_unlock(&bdev->lru_lock);
}
diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
index 26a3689e5fd9..278bbe7a11ad 100644
--- a/drivers/gpu/drm/ttm/ttm_pool.c
+++ b/drivers/gpu/drm/ttm/ttm_pool.c
@@ -206,6 +206,14 @@ error_free:
return NULL;
}
+static void __free_pages_gpu_account(struct page *p, unsigned int order,
+ bool reclaim)
+{
+ mod_lruvec_page_state(p, reclaim ? NR_GPU_RECLAIM : NR_GPU_ACTIVE,
+ -(1 << order));
+ __free_pages(p, order);
+}
+
/* Reset the caching and pages of size 1 << order */
static void ttm_pool_free_page(struct ttm_pool *pool, enum ttm_caching caching,
unsigned int order, struct page *p, bool reclaim)
@@ -223,9 +231,7 @@ static void ttm_pool_free_page(struct ttm_pool *pool, enum ttm_caching caching,
#endif
if (!pool || !ttm_pool_uses_dma_alloc(pool)) {
- mod_lruvec_page_state(p, reclaim ? NR_GPU_RECLAIM : NR_GPU_ACTIVE,
- -(1 << order));
- __free_pages(p, order);
+ __free_pages_gpu_account(p, order, reclaim);
return;
}
@@ -606,7 +612,7 @@ static int ttm_pool_restore_commit(struct ttm_pool_tt_restore *restore,
*/
ttm_pool_split_for_swap(restore->pool, p);
copy_highpage(restore->alloced_page + i, p);
- __free_pages(p, 0);
+ __free_pages_gpu_account(p, 0, false);
}
restore->restored_pages++;
@@ -1068,7 +1074,7 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
if (flags->purge) {
shrunken += num_pages;
page->private = 0;
- __free_pages(page, order);
+ __free_pages_gpu_account(page, order, false);
memset(tt->pages + i, 0,
num_pages * sizeof(*tt->pages));
}
@@ -1109,7 +1115,7 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
}
handle = shandle;
tt->pages[i] = ttm_backup_handle_to_page_ptr(handle);
- put_page(page);
+ __free_pages_gpu_account(page, 0, false);
shrunken++;
}
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index 9f36631d48b6..154d6739256f 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -292,6 +292,19 @@ void ttm_resource_del_bulk_move(struct ttm_resource *res,
ttm_lru_bulk_move_del(bo->bulk_move, res);
}
+/*
+ * Remove a resource from its bulk_move, bypassing the unevictable check.
+ * Use only when the resource is known to still be tracked in the range despite
+ * the BO having just become unevictable; asserts that this is the case.
+ */
+void ttm_resource_del_bulk_move_unevictable(struct ttm_resource *res,
+ struct ttm_buffer_object *bo)
+{
+ WARN_ON_ONCE(!ttm_resource_unevictable(res, bo));
+ if (bo->bulk_move)
+ ttm_lru_bulk_move_del(bo->bulk_move, res);
+}
+
/* Move a resource to the LRU or bulk tail */
void ttm_resource_move_to_lru_tail(struct ttm_resource *res)
{
@@ -385,8 +398,11 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo,
if (man->cg) {
ret = dmem_cgroup_try_charge(man->cg, bo->base.size, &pool, ret_limit_pool);
- if (ret)
+ if (ret) {
+ if (ret == -EAGAIN)
+ ret = -ENOSPC;
return ret;
+ }
}
ret = man->func->alloc(man, bo, place, res_ptr);
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 75d9eccd7966..dd7da419702f 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -213,6 +213,14 @@ v3d_clean_caches(struct v3d_dev *v3d)
trace_v3d_cache_clean_begin(dev);
+ /* GFXH-1897: Ensure pending flushes complete before writing L2TCACTL */
+ if (v3d->ver < V3D_GEN_71) {
+ if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
+ V3D_L2TCACTL_L2TFLS), 100)) {
+ drm_err(dev, "Timeout waiting for L2T clean\n");
+ }
+ }
+
V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
V3D_L2TCACTL_TMUWCF), 100)) {
diff --git a/drivers/gpu/drm/v3d/v3d_perfmon.c b/drivers/gpu/drm/v3d/v3d_perfmon.c
index 8e0249580bba..ecfd446ff75f 100644
--- a/drivers/gpu/drm/v3d/v3d_perfmon.c
+++ b/drivers/gpu/drm/v3d/v3d_perfmon.c
@@ -309,8 +309,11 @@ static void v3d_perfmon_delete(struct v3d_file_priv *v3d_priv,
if (perfmon == v3d->active_perfmon)
v3d_perfmon_stop(v3d, perfmon, false);
- /* If the global perfmon is being destroyed, set it to NULL */
- cmpxchg(&v3d->global_perfmon, perfmon, NULL);
+ /* If the global perfmon is being destroyed, clean it and release
+ * the reference stashed in v3d_perfmon_set_global_ioctl().
+ */
+ if (cmpxchg(&v3d->global_perfmon, perfmon, NULL) == perfmon)
+ v3d_perfmon_put(perfmon);
v3d_perfmon_put(perfmon);
}
@@ -461,16 +464,27 @@ int v3d_perfmon_set_global_ioctl(struct drm_device *dev, void *data,
/* If the request is to clear the global performance monitor */
if (req->flags & DRM_V3D_PERFMON_CLEAR_GLOBAL) {
- if (!v3d->global_perfmon)
+ struct v3d_perfmon *old;
+
+ /* DRM_V3D_PERFMON_CLEAR_GLOBAL doesn't check if
+ * v3d->global_perfmon == perfmon. Therefore, there
+ * is no need to keep perfmon's reference.
+ */
+ v3d_perfmon_put(perfmon);
+
+ old = xchg(&v3d->global_perfmon, NULL);
+ if (!old)
return -EINVAL;
- xchg(&v3d->global_perfmon, NULL);
+ v3d_perfmon_put(old);
return 0;
}
- if (cmpxchg(&v3d->global_perfmon, NULL, perfmon))
+ if (cmpxchg(&v3d->global_perfmon, NULL, perfmon)) {
+ v3d_perfmon_put(perfmon);
return -EBUSY;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
index 1855ef5b3b5f..8a635a9ec046 100644
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -126,20 +126,6 @@ v3d_performance_query_info_free(struct v3d_performance_query_info *query_info,
}
static void
-v3d_cpu_job_free(struct drm_sched_job *sched_job)
-{
- struct v3d_cpu_job *job = to_cpu_job(sched_job);
-
- v3d_timestamp_query_info_free(&job->timestamp_query,
- job->timestamp_query.count);
-
- v3d_performance_query_info_free(&job->performance_query,
- job->performance_query.count);
-
- v3d_job_cleanup(&job->base);
-}
-
-static void
v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job)
{
struct v3d_perfmon *perfmon = v3d->global_perfmon;
@@ -366,6 +352,16 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
return NULL;
}
+ /* The HW interprets a workgroup size of 0 as 65536; however, the
+ * user-space driver exposes a maximum of 65535. Therefore, a 0 in
+ * any dimension means that we have no workgroups and the compute
+ * shader should not be dispatched.
+ */
+ if (!V3D_GET_FIELD(job->args.cfg[0], V3D_CSD_QUEUED_CFG0_NUM_WGS_X) ||
+ !V3D_GET_FIELD(job->args.cfg[1], V3D_CSD_QUEUED_CFG1_NUM_WGS_Y) ||
+ !V3D_GET_FIELD(job->args.cfg[2], V3D_CSD_QUEUED_CFG2_NUM_WGS_Z))
+ return NULL;
+
v3d->queue[V3D_CSD].active_job = &job->base;
v3d_invalidate_caches(v3d);
@@ -416,13 +412,13 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job)
wg_counts = (uint32_t *)(bo->vaddr + indirect_csd->offset);
- if (wg_counts[0] == 0 || wg_counts[1] == 0 || wg_counts[2] == 0)
- return;
-
args->cfg[0] = wg_counts[0] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
args->cfg[1] = wg_counts[1] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
args->cfg[2] = wg_counts[2] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
+ if (wg_counts[0] == 0 || wg_counts[1] == 0 || wg_counts[2] == 0)
+ goto unmap_bo;
+
num_batches = DIV_ROUND_UP(indirect_csd->wg_size, 16) *
(wg_counts[0] * wg_counts[1] * wg_counts[2]);
@@ -442,6 +438,7 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job)
}
}
+unmap_bo:
v3d_put_bo_vaddr(indirect);
v3d_put_bo_vaddr(bo);
}
@@ -830,7 +827,7 @@ static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = {
static const struct drm_sched_backend_ops v3d_cpu_sched_ops = {
.run_job = v3d_cpu_job_run,
- .free_job = v3d_cpu_job_free
+ .free_job = v3d_sched_job_free
};
static int
diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c
index ee4512db294b..3ddd53b6f437 100644
--- a/drivers/gpu/drm/v3d/v3d_submit.c
+++ b/drivers/gpu/drm/v3d/v3d_submit.c
@@ -123,6 +123,24 @@ v3d_render_job_free(struct kref *ref)
v3d_job_free(ref);
}
+static void
+v3d_cpu_job_free(struct kref *ref)
+{
+ struct v3d_cpu_job *job = container_of(ref, struct v3d_cpu_job,
+ base.refcount);
+
+ v3d_timestamp_query_info_free(&job->timestamp_query,
+ job->timestamp_query.count);
+
+ v3d_performance_query_info_free(&job->performance_query,
+ job->performance_query.count);
+
+ if (job->indirect_csd.indirect)
+ drm_gem_object_put(job->indirect_csd.indirect);
+
+ v3d_job_free(ref);
+}
+
void v3d_job_cleanup(struct v3d_job *job)
{
if (!job)
@@ -1302,7 +1320,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data,
trace_v3d_submit_cpu_ioctl(&v3d->drm, cpu_job->job_type);
ret = v3d_job_init(v3d, file_priv, &cpu_job->base,
- v3d_job_free, 0, &se, V3D_CPU);
+ v3d_cpu_job_free, 0, &se, V3D_CPU);
if (ret) {
v3d_job_deallocate((void *)&cpu_job);
goto fail;
@@ -1385,8 +1403,6 @@ fail:
v3d_job_cleanup((void *)csd_job);
v3d_job_cleanup(clean_job);
v3d_put_multisync_post_deps(&se);
- kvfree(cpu_job->timestamp_query.queries);
- kvfree(cpu_job->performance_query.queries);
return ret;
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index f17660a71a3e..2f3531950aa4 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -317,6 +317,7 @@ virtio_gpu_array_from_handles(struct drm_file *drm_file, u32 *handles, u32 nents
void virtio_gpu_array_add_obj(struct virtio_gpu_object_array *objs,
struct drm_gem_object *obj);
int virtio_gpu_array_lock_resv(struct virtio_gpu_object_array *objs);
+int virtio_gpu_lock_one_resv_uninterruptible(struct virtio_gpu_object_array *objs);
void virtio_gpu_array_unlock_resv(struct virtio_gpu_object_array *objs);
void virtio_gpu_array_add_fence(struct virtio_gpu_object_array *objs,
struct dma_fence *fence);
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index f22dc5c21cd4..435d37d36034 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -238,6 +238,23 @@ int virtio_gpu_array_lock_resv(struct virtio_gpu_object_array *objs)
return ret;
}
+int virtio_gpu_lock_one_resv_uninterruptible(struct virtio_gpu_object_array *objs)
+{
+ int ret;
+
+ if (objs->nents != 1)
+ return -EINVAL;
+
+ dma_resv_lock(objs->objs[0]->resv, NULL);
+
+ ret = dma_resv_reserve_fences(objs->objs[0]->resv, 1);
+ if (ret) {
+ virtio_gpu_array_unlock_resv(objs);
+ return ret;
+ }
+ return 0;
+}
+
void virtio_gpu_array_unlock_resv(struct virtio_gpu_object_array *objs)
{
if (objs->nents == 1) {
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index a126d1b25f46..652352424744 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -215,7 +215,10 @@ static void virtio_gpu_resource_flush(struct drm_plane *plane,
if (!objs)
return;
virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
- virtio_gpu_array_lock_resv(objs);
+ if (virtio_gpu_lock_one_resv_uninterruptible(objs)) {
+ virtio_gpu_array_put_free(objs);
+ return;
+ }
virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
width, height, objs,
vgplane_st->fence);
@@ -459,7 +462,10 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
if (!objs)
return;
virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
- virtio_gpu_array_lock_resv(objs);
+ if (virtio_gpu_lock_one_resv_uninterruptible(objs)) {
+ virtio_gpu_array_put_free(objs);
+ return;
+ }
virtio_gpu_cmd_transfer_to_host_2d
(vgdev, 0,
plane->state->crtc_w,
diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
index 29c72aa4b0d2..33494b86205d 100644
--- a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
@@ -37,9 +37,17 @@ static bool intel_hdcp_gsc_check_status(struct drm_device *drm)
struct xe_device *xe = to_xe_device(drm);
struct xe_tile *tile = xe_device_get_root_tile(xe);
struct xe_gt *gt = tile->media_gt;
- struct xe_gsc *gsc = &gt->uc.gsc;
+ struct xe_gsc *gsc;
+
+ if (!gt) {
+ drm_dbg_kms(&xe->drm,
+ "not checking GSC status for HDCP2.x: media GT not present or disabled\n");
+ return false;
+ }
+
+ gsc = &gt->uc.gsc;
- if (!gsc || !xe_uc_fw_is_available(&gsc->fw)) {
+ if (!xe_uc_fw_is_available(&gsc->fw)) {
drm_dbg_kms(&xe->drm,
"GSC Components not ready for HDCP2.x\n");
return false;
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 9c88ca3ce768..353fe0bd49bf 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -152,10 +152,11 @@
#define XEHPG_INSTDONE_GEOM_SVGUNIT XE_REG_MCR(0x666c)
-#define CACHE_MODE_1 XE_REG(0x7004, XE_REG_OPTION_MASKED)
+#define CACHE_MODE_1 XE_REG_MCR(0x7004, XE_REG_OPTION_MASKED)
#define MSAA_OPTIMIZATION_REDUC_DISABLE REG_BIT(11)
#define COMMON_SLICE_CHICKEN1 XE_REG(0x7010, XE_REG_OPTION_MASKED)
+#define XEHP_COMMON_SLICE_CHICKEN1 XE_REG_MCR(0x7010, XE_REG_OPTION_MASKED)
#define DISABLE_BOTTOM_CLIP_RECTANGLE_TEST REG_BIT(14)
#define HIZ_CHICKEN XE_REG(0x7018, XE_REG_OPTION_MASKED)
@@ -178,6 +179,7 @@
#define XEHPG_SC_INSTDONE_EXTRA2 XE_REG_MCR(0x7108)
#define COMMON_SLICE_CHICKEN4 XE_REG(0x7300, XE_REG_OPTION_MASKED)
+#define XEHP_COMMON_SLICE_CHICKEN4 XE_REG_MCR(0x7300, XE_REG_OPTION_MASKED)
#define SBE_PUSH_CONSTANT_BEHIND_FIX_ENABLE REG_BIT(12)
#define DISABLE_TDC_LOAD_BALANCING_CALC REG_BIT(6)
#define HW_FILTERING REG_BIT(5)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index 4075edf97421..6b518858538f 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -897,10 +897,10 @@ void xe_bo_set_purgeable_state(struct xe_bo *bo,
new_state == XE_MADV_PURGEABLE_PURGED);
/* Once purged, always purged - cannot transition out */
- xe_assert(xe, !(bo->madv_purgeable == XE_MADV_PURGEABLE_PURGED &&
+ xe_assert(xe, !(bo->purgeable.state == XE_MADV_PURGEABLE_PURGED &&
new_state != XE_MADV_PURGEABLE_PURGED));
- bo->madv_purgeable = new_state;
+ bo->purgeable.state = new_state;
xe_bo_set_purgeable_shrinker(bo, new_state);
}
@@ -2368,7 +2368,7 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
INIT_LIST_HEAD(&bo->vram_userfault_link);
/* Initialize purge advisory state */
- bo->madv_purgeable = XE_MADV_PURGEABLE_WILLNEED;
+ bo->purgeable.state = XE_MADV_PURGEABLE_WILLNEED;
drm_gem_private_object_init(&xe->drm, &bo->ttm.base, size);
diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
index 68dea7d25a6b..6340317f7d2e 100644
--- a/drivers/gpu/drm/xe/xe_bo.h
+++ b/drivers/gpu/drm/xe/xe_bo.h
@@ -251,7 +251,7 @@ static inline bool xe_bo_is_protected(const struct xe_bo *bo)
static inline bool xe_bo_is_purged(struct xe_bo *bo)
{
xe_bo_assert_held(bo);
- return bo->madv_purgeable == XE_MADV_PURGEABLE_PURGED;
+ return bo->purgeable.state == XE_MADV_PURGEABLE_PURGED;
}
/**
@@ -268,11 +268,95 @@ static inline bool xe_bo_is_purged(struct xe_bo *bo)
static inline bool xe_bo_madv_is_dontneed(struct xe_bo *bo)
{
xe_bo_assert_held(bo);
- return bo->madv_purgeable == XE_MADV_PURGEABLE_DONTNEED;
+ return bo->purgeable.state == XE_MADV_PURGEABLE_DONTNEED;
}
void xe_bo_set_purgeable_state(struct xe_bo *bo, enum xe_madv_purgeable_state new_state);
+/**
+ * xe_bo_willneed_get_locked() - Acquire a WILLNEED holder on a BO
+ * @bo: Buffer object
+ *
+ * Increments willneed_count and, on a 0->1 transition, promotes the BO
+ * from DONTNEED to WILLNEED. PURGED is terminal and is never modified.
+ *
+ * Caller must hold the BO's dma-resv lock.
+ */
+static inline void xe_bo_willneed_get_locked(struct xe_bo *bo)
+{
+ xe_bo_assert_held(bo);
+
+ /* Imported BOs are owned externally; do not track purgeability. */
+ if (drm_gem_is_imported(&bo->ttm.base))
+ return;
+
+ if (bo->purgeable.willneed_count++ == 0 && xe_bo_madv_is_dontneed(bo))
+ xe_bo_set_purgeable_state(bo, XE_MADV_PURGEABLE_WILLNEED);
+}
+
+/**
+ * xe_bo_willneed_put_locked() - Release a WILLNEED holder on a BO
+ * @bo: Buffer object
+ *
+ * Decrements willneed_count and, on a 1->0 transition, marks the BO
+ * DONTNEED only if it still has VMAs (implying all active VMAs are
+ * DONTNEED). If the last VMA is being removed, preserve the current BO
+ * state to match the previous VMA-walk semantics.
+ *
+ * PURGED is terminal and the BO state is never modified.
+ *
+ * Caller must hold the BO's dma-resv lock.
+ */
+static inline void xe_bo_willneed_put_locked(struct xe_bo *bo)
+{
+ xe_bo_assert_held(bo);
+
+ if (drm_gem_is_imported(&bo->ttm.base))
+ return;
+
+ xe_assert(xe_bo_device(bo), bo->purgeable.willneed_count > 0);
+ if (--bo->purgeable.willneed_count == 0 && bo->purgeable.vma_count > 0 &&
+ !xe_bo_is_purged(bo))
+ xe_bo_set_purgeable_state(bo, XE_MADV_PURGEABLE_DONTNEED);
+}
+
+/**
+ * xe_bo_vma_count_inc_locked() - Account a new VMA on a BO
+ * @bo: Buffer object
+ *
+ * Increments vma_count.
+ *
+ * Caller must hold the BO's dma-resv lock.
+ */
+static inline void xe_bo_vma_count_inc_locked(struct xe_bo *bo)
+{
+ xe_bo_assert_held(bo);
+
+ if (drm_gem_is_imported(&bo->ttm.base))
+ return;
+
+ bo->purgeable.vma_count++;
+}
+
+/**
+ * xe_bo_vma_count_dec_locked() - Account a VMA removal on a BO
+ * @bo: Buffer object
+ *
+ * Decrements vma_count.
+ *
+ * Caller must hold the BO's dma-resv lock.
+ */
+static inline void xe_bo_vma_count_dec_locked(struct xe_bo *bo)
+{
+ xe_bo_assert_held(bo);
+
+ if (drm_gem_is_imported(&bo->ttm.base))
+ return;
+
+ xe_assert(xe_bo_device(bo), bo->purgeable.vma_count > 0);
+ bo->purgeable.vma_count--;
+}
+
static inline void xe_bo_unpin_map_no_vm(struct xe_bo *bo)
{
if (likely(bo)) {
diff --git a/drivers/gpu/drm/xe/xe_bo_types.h b/drivers/gpu/drm/xe/xe_bo_types.h
index 9d19940b8fc0..077e35b4cdce 100644
--- a/drivers/gpu/drm/xe/xe_bo_types.h
+++ b/drivers/gpu/drm/xe/xe_bo_types.h
@@ -111,10 +111,32 @@ struct xe_bo {
u64 min_align;
/**
- * @madv_purgeable: user space advise on BO purgeability, protected
- * by BO's dma-resv lock.
+ * @purgeable: Purgeability state and accounting.
+ *
+ * All fields are protected by the BO's dma-resv lock.
*/
- u32 madv_purgeable;
+ struct {
+ /**
+ * @purgeable.state: BO purgeability state
+ * (WILLNEED/DONTNEED/PURGED).
+ */
+ u32 state;
+
+ /**
+ * @purgeable.vma_count: Number of VMAs currently mapping this BO.
+ */
+ u32 vma_count;
+
+ /**
+ * @purgeable.willneed_count: Number of active WILLNEED holders.
+ *
+ * Counts WILLNEED VMAs plus active dma-buf exports for
+ * non-imported BOs. The BO flips to DONTNEED on a 1->0
+ * transition only when VMAs still exist; if the last VMA is
+ * removed, the previous BO state is preserved.
+ */
+ u32 willneed_count;
+ } purgeable;
};
#endif
diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c
index b9828da15897..8a920e58245c 100644
--- a/drivers/gpu/drm/xe/xe_dma_buf.c
+++ b/drivers/gpu/drm/xe/xe_dma_buf.c
@@ -193,6 +193,18 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
return 0;
}
+static void xe_dma_buf_release(struct dma_buf *dmabuf)
+{
+ struct drm_gem_object *obj = dmabuf->priv;
+ struct xe_bo *bo = gem_to_xe_bo(obj);
+
+ xe_bo_lock(bo, false);
+ xe_bo_willneed_put_locked(bo);
+ xe_bo_unlock(bo);
+
+ drm_gem_dmabuf_release(dmabuf);
+}
+
static const struct dma_buf_ops xe_dmabuf_ops = {
.attach = xe_dma_buf_attach,
.detach = xe_dma_buf_detach,
@@ -200,7 +212,7 @@ static const struct dma_buf_ops xe_dmabuf_ops = {
.unpin = xe_dma_buf_unpin,
.map_dma_buf = xe_dma_buf_map,
.unmap_dma_buf = xe_dma_buf_unmap,
- .release = drm_gem_dmabuf_release,
+ .release = xe_dma_buf_release,
.begin_cpu_access = xe_dma_buf_begin_cpu_access,
.mmap = drm_gem_dmabuf_mmap,
.vmap = drm_gem_dmabuf_vmap,
@@ -241,33 +253,33 @@ struct dma_buf *xe_gem_prime_export(struct drm_gem_object *obj, int flags)
ret = -EINVAL;
goto out_unlock;
}
+
+ xe_bo_willneed_get_locked(bo);
xe_bo_unlock(bo);
ret = ttm_bo_setup_export(&bo->ttm, &ctx);
if (ret)
- return ERR_PTR(ret);
+ goto out_put;
buf = drm_gem_prime_export(obj, flags);
- if (!IS_ERR(buf))
- buf->ops = &xe_dmabuf_ops;
+ if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
+ goto out_put;
+ }
+ buf->ops = &xe_dmabuf_ops;
return buf;
+out_put:
+ xe_bo_lock(bo, false);
+ xe_bo_willneed_put_locked(bo);
out_unlock:
xe_bo_unlock(bo);
return ERR_PTR(ret);
}
-/*
- * Takes ownership of @storage: on success it is transferred to the returned
- * drm_gem_object; on failure it is freed before returning the error.
- * This matches the contract of xe_bo_init_locked() which frees @storage on
- * its error paths, so callers need not (and must not) free @storage after
- * this call.
- */
static struct drm_gem_object *
-xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
- struct dma_buf *dma_buf)
+xe_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf)
{
struct dma_resv *resv = dma_buf->resv;
struct xe_device *xe = to_xe_device(dev);
@@ -278,10 +290,8 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
int ret = 0;
dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
- if (!dummy_obj) {
- xe_bo_free(storage);
+ if (!dummy_obj)
return ERR_PTR(-ENOMEM);
- }
dummy_obj->resv = resv;
xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {}, ret) {
@@ -290,8 +300,7 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
if (ret)
break;
- /* xe_bo_init_locked() frees storage on error */
- bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
+ bo = xe_bo_init_locked(xe, NULL, NULL, resv, NULL, dma_buf->size,
0, /* Will require 1way or 2way for vm_bind */
ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
drm_exec_retry_on_contention(&exec);
@@ -342,7 +351,6 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev,
const struct dma_buf_attach_ops *attach_ops;
struct dma_buf_attachment *attach;
struct drm_gem_object *obj;
- struct xe_bo *bo;
if (dma_buf->ops == &xe_dmabuf_ops) {
obj = dma_buf->priv;
@@ -358,13 +366,15 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev,
}
/*
- * Don't publish the bo until we have a valid attachment, and a
- * valid attachment needs the bo address. So pre-create a bo before
- * creating the attachment and publish.
+ * This needs to happen before the attach, since it will create a new
+ * attachment for this, and add it to the list of attachments, at which
+ * point it is globally visible, and at any point the export side can
+ * call into on invalidate_mappings callback, which require a working
+ * object.
*/
- bo = xe_bo_alloc();
- if (IS_ERR(bo))
- return ERR_CAST(bo);
+ obj = xe_dma_buf_create_obj(dev, dma_buf);
+ if (IS_ERR(obj))
+ return obj;
attach_ops = &xe_dma_buf_attach_ops;
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
@@ -372,29 +382,15 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev,
attach_ops = test->attach_ops;
#endif
- attach = dma_buf_dynamic_attach(dma_buf, dev->dev, attach_ops, &bo->ttm.base);
+ attach = dma_buf_dynamic_attach(dma_buf, dev->dev, attach_ops, obj);
if (IS_ERR(attach)) {
- obj = ERR_CAST(attach);
- goto out_err;
+ xe_bo_put(gem_to_xe_bo(obj));
+ return ERR_CAST(attach);
}
- /*
- * xe_dma_buf_init_obj() takes ownership of bo on both success
- * and failure, so we must not touch bo after this call.
- */
- obj = xe_dma_buf_init_obj(dev, bo, dma_buf);
- if (IS_ERR(obj)) {
- dma_buf_detach(dma_buf, attach);
- return obj;
- }
get_dma_buf(dma_buf);
obj->import_attach = attach;
return obj;
-
-out_err:
- xe_bo_free(bo);
-
- return obj;
}
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.h b/drivers/gpu/drm/xe/xe_exec_queue.h
index a82d99bd77bc..0225426c57b0 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.h
+++ b/drivers/gpu/drm/xe/xe_exec_queue.h
@@ -162,21 +162,4 @@ int xe_exec_queue_contexts_hwsp_rebase(struct xe_exec_queue *q, void *scratch);
struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q);
struct xe_lrc *xe_exec_queue_get_lrc(struct xe_exec_queue *q, u16 idx);
-/**
- * xe_exec_queue_idle_skip_suspend() - Can exec queue skip suspend
- * @q: The exec_queue
- *
- * If an exec queue is not parallel and is idle, the suspend steps can be
- * skipped in the submission backend immediatley signaling the suspend fence.
- * Parallel queues cannot skip this step due to limitations in the submission
- * backend.
- *
- * Return: True if exec queue is idle and can skip suspend steps, False
- * otherwise
- */
-static inline bool xe_exec_queue_idle_skip_suspend(struct xe_exec_queue *q)
-{
- return !xe_exec_queue_is_parallel(q) && xe_exec_queue_is_idle(q);
-}
-
#endif
diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c
index 0d13e357fb43..aab59dc647fb 100644
--- a/drivers/gpu/drm/xe/xe_gsc.c
+++ b/drivers/gpu/drm/xe/xe_gsc.c
@@ -482,8 +482,7 @@ int xe_gsc_init_post_hwconfig(struct xe_gsc *gsc)
EXEC_QUEUE_FLAG_PERMANENT, 0);
if (IS_ERR(q)) {
xe_gt_err(gt, "Failed to create queue for GSC submission\n");
- err = PTR_ERR(q);
- goto out_bo;
+ return PTR_ERR(q);
}
wq = alloc_ordered_workqueue("gsc-ordered-wq", 0);
@@ -506,8 +505,6 @@ int xe_gsc_init_post_hwconfig(struct xe_gsc *gsc)
out_q:
xe_exec_queue_put(q);
-out_bo:
- xe_bo_unpin_map_no_vm(bo);
return err;
}
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c
index 87a164efcc33..01fe03b9efe8 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c
@@ -385,10 +385,10 @@ static int pf_migration_mmio_save(struct xe_gt *gt, unsigned int vfid, void *buf
if (xe_gt_is_media_type(gt))
for (n = 0; n < MED_VF_SW_FLAG_COUNT; n++)
- regs[n] = xe_mmio_read32(&gt->mmio, MED_VF_SW_FLAG(n));
+ regs[n] = xe_mmio_read32(&mmio, MED_VF_SW_FLAG(n));
else
for (n = 0; n < VF_SW_FLAG_COUNT; n++)
- regs[n] = xe_mmio_read32(&gt->mmio, VF_SW_FLAG(n));
+ regs[n] = xe_mmio_read32(&mmio, VF_SW_FLAG(n));
return 0;
}
@@ -407,10 +407,10 @@ static int pf_migration_mmio_restore(struct xe_gt *gt, unsigned int vfid,
if (xe_gt_is_media_type(gt))
for (n = 0; n < MED_VF_SW_FLAG_COUNT; n++)
- xe_mmio_write32(&gt->mmio, MED_VF_SW_FLAG(n), regs[n]);
+ xe_mmio_write32(&mmio, MED_VF_SW_FLAG(n), regs[n]);
else
for (n = 0; n < VF_SW_FLAG_COUNT; n++)
- xe_mmio_write32(&gt->mmio, VF_SW_FLAG(n), regs[n]);
+ xe_mmio_write32(&mmio, VF_SW_FLAG(n), regs[n]);
return 0;
}
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.c
index 7d532bded02a..a85ba4435378 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.c
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.c
@@ -114,8 +114,10 @@ int xe_gt_sriov_pf_monitor_process_guc2pf(struct xe_gt *gt, const u32 *msg, u32
* VFs with no events are not printed.
*
* This function can only be called on PF.
+ *
+ * Return: always 0
*/
-void xe_gt_sriov_pf_monitor_print_events(struct xe_gt *gt, struct drm_printer *p)
+int xe_gt_sriov_pf_monitor_print_events(struct xe_gt *gt, struct drm_printer *p)
{
unsigned int n, total_vfs = xe_gt_sriov_pf_get_totalvfs(gt);
const struct xe_gt_sriov_monitor *data;
@@ -144,4 +146,6 @@ void xe_gt_sriov_pf_monitor_print_events(struct xe_gt *gt, struct drm_printer *p
#undef __format
#undef __value
}
+
+ return 0;
}
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.h
index 7ca9351a271b..0b8f088d3a16 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.h
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_monitor.h
@@ -13,7 +13,7 @@ struct drm_printer;
struct xe_gt;
void xe_gt_sriov_pf_monitor_flr(struct xe_gt *gt, u32 vfid);
-void xe_gt_sriov_pf_monitor_print_events(struct xe_gt *gt, struct drm_printer *p);
+int xe_gt_sriov_pf_monitor_print_events(struct xe_gt *gt, struct drm_printer *p);
#ifdef CONFIG_PCI_IOV
int xe_gt_sriov_pf_monitor_process_guc2pf(struct xe_gt *gt, const u32 *msg, u32 len);
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
index 8989c8e1be95..0cd9d77f3351 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
@@ -1137,13 +1137,15 @@ void xe_gt_sriov_vf_write32(struct xe_gt *gt, struct xe_reg reg, u32 val)
}
/**
- * xe_gt_sriov_vf_print_config - Print VF self config.
+ * xe_gt_sriov_vf_print_config() - Print VF self config.
* @gt: the &xe_gt
* @p: the &drm_printer
*
* This function is for VF use only.
+ *
+ * Return: always 0.
*/
-void xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p)
+int xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p)
{
struct xe_gt_sriov_vf_selfconfig *config = &gt->sriov.vf.self_config;
struct xe_device *xe = gt_to_xe(gt);
@@ -1170,16 +1172,20 @@ void xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p)
drm_printf(p, "GuC contexts:\t%u\n", config->num_ctxs);
drm_printf(p, "GuC doorbells:\t%u\n", config->num_dbs);
+
+ return 0;
}
/**
- * xe_gt_sriov_vf_print_runtime - Print VF's runtime regs received from PF.
+ * xe_gt_sriov_vf_print_runtime() - Print VF's runtime regs received from PF.
* @gt: the &xe_gt
* @p: the &drm_printer
*
* This function is for VF use only.
+ *
+ * Return: always 0.
*/
-void xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p)
+int xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p)
{
struct vf_runtime_reg *vf_regs = gt->sriov.vf.runtime.regs;
unsigned int size = gt->sriov.vf.runtime.num_regs;
@@ -1188,16 +1194,20 @@ void xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p)
for (; size--; vf_regs++)
drm_printf(p, "%#x = %#x\n", vf_regs->offset, vf_regs->value);
+
+ return 0;
}
/**
- * xe_gt_sriov_vf_print_version - Print VF ABI versions.
+ * xe_gt_sriov_vf_print_version() - Print VF ABI versions.
* @gt: the &xe_gt
* @p: the &drm_printer
*
* This function is for VF use only.
+ *
+ * Return: always 0.
*/
-void xe_gt_sriov_vf_print_version(struct xe_gt *gt, struct drm_printer *p)
+int xe_gt_sriov_vf_print_version(struct xe_gt *gt, struct drm_printer *p)
{
struct xe_device *xe = gt_to_xe(gt);
struct xe_uc_fw_version *guc_version = &gt->sriov.vf.guc_version;
@@ -1227,6 +1237,8 @@ void xe_gt_sriov_vf_print_version(struct xe_gt *gt, struct drm_printer *p)
GUC_RELAY_VERSION_LATEST_MAJOR, GUC_RELAY_VERSION_LATEST_MINOR);
drm_printf(p, "\thandshake:\t%u.%u\n",
pf_version->major, pf_version->minor);
+
+ return 0;
}
static bool vf_post_migration_shutdown(struct xe_gt *gt)
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.h b/drivers/gpu/drm/xe/xe_gt_sriov_vf.h
index a6f7127521a5..79878f21b1da 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.h
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.h
@@ -35,9 +35,9 @@ bool xe_gt_sriov_vf_sched_groups_enabled(struct xe_gt *gt);
u32 xe_gt_sriov_vf_read32(struct xe_gt *gt, struct xe_reg reg);
void xe_gt_sriov_vf_write32(struct xe_gt *gt, struct xe_reg reg, u32 val);
-void xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p);
-void xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p);
-void xe_gt_sriov_vf_print_version(struct xe_gt *gt, struct drm_printer *p);
+int xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p);
+int xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p);
+int xe_gt_sriov_vf_print_version(struct xe_gt *gt, struct drm_printer *p);
int xe_gt_sriov_vf_wait_valid_ggtt(struct xe_gt *gt);
int xe_vf_migration_fixups_complete_count(struct xe_gt *gt);
diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h
index 8b55cf25a75f..fffb5d631b69 100644
--- a/drivers/gpu/drm/xe/xe_gt_types.h
+++ b/drivers/gpu/drm/xe/xe_gt_types.h
@@ -145,6 +145,13 @@ struct xe_gt {
/** @info.has_indirect_ring_state: GT has indirect ring state support */
u8 has_indirect_ring_state:1;
/**
+ * @info.has_xe2_blt_instructions: GT supports Xe2-style MEM_SET
+ * and MEM_COPY blitter functionality. Note that despite the
+ * name, some Xe1 platforms may also support this "Xe2-style"
+ * feature.
+ */
+ u8 has_xe2_blt_instructions:1;
+ /**
* @info.num_geometry_xecore_fuse_regs: Number of 32b-bit fuse
* registers the geometry XeCore mask spans.
*/
diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c
index 81b5f01b1f65..5760251cb685 100644
--- a/drivers/gpu/drm/xe/xe_guc_ads.c
+++ b/drivers/gpu/drm/xe/xe_guc_ads.c
@@ -512,12 +512,9 @@ static void guc_golden_lrc_init(struct xe_guc_ads *ads)
* that starts after the execlists LRC registers. This is
* required to allow the GuC to restore just the engine state
* when a watchdog reset occurs.
- * We calculate the engine state size by removing the size of
- * what comes before it in the context image (which is identical
- * on all engines).
*/
ads_blob_write(ads, ads.eng_state_size[guc_class],
- real_size - xe_lrc_skip_size(xe));
+ xe_lrc_engine_state_size(gt, class));
ads_blob_write(ads, ads.golden_context_lrca[guc_class],
addr_ggtt);
@@ -770,6 +767,11 @@ static unsigned int guc_mmio_regset_write(struct xe_guc_ads *ads,
}
}
+ if (XE_GT_WA(hwe->gt, 16023105232))
+ guc_mmio_regset_write_one(ads, regset_map,
+ RING_IDLEDLY(hwe->mmio_base),
+ count++);
+
return count;
}
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index 10556156eaad..a4a8f0d41fe8 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -71,7 +71,6 @@ exec_queue_to_guc(struct xe_exec_queue *q)
#define EXEC_QUEUE_STATE_WEDGED (1 << 8)
#define EXEC_QUEUE_STATE_BANNED (1 << 9)
#define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 10)
-#define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 11)
static bool exec_queue_registered(struct xe_exec_queue *q)
{
@@ -218,21 +217,6 @@ static void clear_exec_queue_pending_resume(struct xe_exec_queue *q)
atomic_and(~EXEC_QUEUE_STATE_PENDING_RESUME, &q->guc->state);
}
-static bool exec_queue_idle_skip_suspend(struct xe_exec_queue *q)
-{
- return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND;
-}
-
-static void set_exec_queue_idle_skip_suspend(struct xe_exec_queue *q)
-{
- atomic_or(EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state);
-}
-
-static void clear_exec_queue_idle_skip_suspend(struct xe_exec_queue *q)
-{
- atomic_and(~EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state);
-}
-
static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q)
{
return (atomic_read(&q->guc->state) &
@@ -1153,7 +1137,7 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job)
if (!job->restore_replay || job->last_replay) {
if (xe_exec_queue_is_parallel(q))
wq_item_append(q);
- else if (!exec_queue_idle_skip_suspend(q))
+ else
xe_lrc_set_ring_tail(lrc, lrc->ring.tail);
job->last_replay = false;
}
@@ -1163,9 +1147,12 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job)
/*
* All queues in a multi-queue group will use the primary queue
- * of the group to interface with GuC.
+ * of the group to interface with GuC. If primay is suspended,
+ * just return. Jobs will get scheduled once primary is resumed.
*/
q = xe_exec_queue_multi_queue_primary(q);
+ if (exec_queue_suspended(q))
+ return;
if (!exec_queue_enabled(q) && !exec_queue_suspended(q)) {
action[len++] = XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET;
@@ -1673,6 +1660,14 @@ static void guc_exec_queue_fini(struct xe_exec_queue *q)
struct xe_guc_exec_queue *ge = q->guc;
struct xe_guc *guc = exec_queue_to_guc(q);
+ if (xe_exec_queue_is_multi_queue_secondary(q)) {
+ struct xe_exec_queue_group *group = q->multi_queue.group;
+
+ mutex_lock(&group->list_lock);
+ list_del(&q->multi_queue.link);
+ mutex_unlock(&group->list_lock);
+ }
+
release_guc_id(guc, q);
xe_sched_entity_fini(&ge->entity);
xe_sched_fini(&ge->sched);
@@ -1694,14 +1689,6 @@ static void __guc_exec_queue_destroy_async(struct work_struct *w)
guard(xe_pm_runtime)(guc_to_xe(guc));
trace_xe_exec_queue_destroy(q);
- if (xe_exec_queue_is_multi_queue_secondary(q)) {
- struct xe_exec_queue_group *group = q->multi_queue.group;
-
- mutex_lock(&group->list_lock);
- list_del(&q->multi_queue.link);
- mutex_unlock(&group->list_lock);
- }
-
/* Confirm no work left behind accessing device structures */
cancel_delayed_work_sync(&ge->sched.base.work_tdr);
@@ -1810,10 +1797,9 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg)
{
struct xe_exec_queue *q = msg->private_data;
struct xe_guc *guc = exec_queue_to_guc(q);
- bool idle_skip_suspend = xe_exec_queue_idle_skip_suspend(q);
- if (!idle_skip_suspend && guc_exec_queue_allowed_to_change_state(q) &&
- !exec_queue_suspended(q) && exec_queue_enabled(q)) {
+ if (guc_exec_queue_allowed_to_change_state(q) && !exec_queue_suspended(q) &&
+ exec_queue_enabled(q)) {
wait_event(guc->ct.wq, vf_recovery(guc) ||
((q->guc->resume_time != RESUME_PENDING ||
xe_guc_read_stopped(guc)) && !exec_queue_pending_disable(q)));
@@ -1832,33 +1818,11 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg)
disable_scheduling(q, false);
}
} else if (q->guc->suspend_pending) {
- if (idle_skip_suspend)
- set_exec_queue_idle_skip_suspend(q);
set_exec_queue_suspended(q);
suspend_fence_signal(q);
}
}
-static void sched_context(struct xe_exec_queue *q)
-{
- struct xe_guc *guc = exec_queue_to_guc(q);
- struct xe_lrc *lrc = q->lrc[0];
- u32 action[] = {
- XE_GUC_ACTION_SCHED_CONTEXT,
- q->guc->id,
- };
-
- xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_parallel(q));
- xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q));
- xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q));
- xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q));
-
- trace_xe_exec_queue_submit(q);
-
- xe_lrc_set_ring_tail(lrc, lrc->ring.tail);
- xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0);
-}
-
static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg)
{
struct xe_exec_queue *q = msg->private_data;
@@ -1866,22 +1830,12 @@ static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg)
if (guc_exec_queue_allowed_to_change_state(q)) {
clear_exec_queue_suspended(q);
if (!exec_queue_enabled(q)) {
- if (exec_queue_idle_skip_suspend(q)) {
- struct xe_lrc *lrc = q->lrc[0];
-
- clear_exec_queue_idle_skip_suspend(q);
- xe_lrc_set_ring_tail(lrc, lrc->ring.tail);
- }
q->guc->resume_time = RESUME_PENDING;
set_exec_queue_pending_resume(q);
enable_scheduling(q);
- } else if (exec_queue_idle_skip_suspend(q)) {
- clear_exec_queue_idle_skip_suspend(q);
- sched_context(q);
}
} else {
clear_exec_queue_suspended(q);
- clear_exec_queue_idle_skip_suspend(q);
}
}
@@ -2853,8 +2807,8 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q,
xe_gt_assert(guc_to_gt(guc), exec_queue_pending_disable(q));
if (q->guc->suspend_pending) {
- suspend_fence_signal(q);
clear_exec_queue_pending_disable(q);
+ suspend_fence_signal(q);
} else {
if (exec_queue_banned(q)) {
smp_wmb();
diff --git a/drivers/gpu/drm/xe/xe_hw_engine_group.c b/drivers/gpu/drm/xe/xe_hw_engine_group.c
index 4c2b113364d3..02cf32ae5aa9 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine_group.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine_group.c
@@ -208,21 +208,15 @@ static int xe_hw_engine_group_suspend_faulting_lr_jobs(struct xe_hw_engine_group
lockdep_assert_held_write(&group->mode_sem);
list_for_each_entry(q, &group->exec_queue_list, hw_engine_group_link) {
- bool idle_skip_suspend;
if (!xe_vm_in_fault_mode(q->vm))
continue;
- idle_skip_suspend = xe_exec_queue_idle_skip_suspend(q);
- if (!idle_skip_suspend && has_deps)
+ if (has_deps)
return -EAGAIN;
xe_gt_stats_incr(q->gt, XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_COUNT, 1);
- if (idle_skip_suspend)
- xe_gt_stats_incr(q->gt,
- XE_GT_STATS_ID_HW_ENGINE_GROUP_SKIP_LR_QUEUE_COUNT, 1);
-
- need_resume |= !idle_skip_suspend;
+ need_resume = true;
q->ops->suspend(q);
gt = q->gt;
}
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index c725cde4508d..4af9f0d7c6f3 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -746,9 +746,16 @@ size_t xe_lrc_reg_size(struct xe_device *xe)
return 80 * sizeof(u32);
}
-size_t xe_lrc_skip_size(struct xe_device *xe)
+/**
+ * xe_lrc_engine_state_size() - Get size of the engine state within LRC
+ * @gt: the &xe_gt struct instance
+ * @class: Hardware engine class
+ *
+ * Returns: Size of the engine state
+ */
+size_t xe_lrc_engine_state_size(struct xe_gt *gt, enum xe_engine_class class)
{
- return LRC_PPHWSP_SIZE + xe_lrc_reg_size(xe);
+ return xe_gt_lrc_hang_replay_size(gt, class) - xe_lrc_reg_size(gt_to_xe(gt));
}
static inline u32 __xe_lrc_seqno_offset(struct xe_lrc *lrc)
diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
index e7c975f9e2d9..5440663183f6 100644
--- a/drivers/gpu/drm/xe/xe_lrc.h
+++ b/drivers/gpu/drm/xe/xe_lrc.h
@@ -130,7 +130,7 @@ u32 xe_lrc_parallel_ggtt_addr(struct xe_lrc *lrc);
struct iosys_map xe_lrc_parallel_map(struct xe_lrc *lrc);
size_t xe_lrc_reg_size(struct xe_device *xe);
-size_t xe_lrc_skip_size(struct xe_device *xe);
+size_t xe_lrc_engine_state_size(struct xe_gt *gt, enum xe_engine_class class);
void xe_lrc_dump_default(struct drm_printer *p,
struct xe_gt *gt,
diff --git a/drivers/gpu/drm/xe/xe_memirq.c b/drivers/gpu/drm/xe/xe_memirq.c
index 811e07136efb..579af47edc61 100644
--- a/drivers/gpu/drm/xe/xe_memirq.c
+++ b/drivers/gpu/drm/xe/xe_memirq.c
@@ -427,13 +427,25 @@ static bool memirq_received(struct xe_memirq *memirq, struct iosys_map *vector,
return __memirq_received(memirq, vector, offset, name, true);
}
+static void memirq_assume_received(struct xe_memirq *memirq, const char *source,
+ u16 offset, const char *status)
+{
+ memirq_debug(memirq, "ASSUME %s %s(%u)\n", source, status, offset);
+}
+
static void memirq_dispatch_engine(struct xe_memirq *memirq, struct iosys_map *status,
struct xe_hw_engine *hwe)
{
memirq_debug(memirq, "STATUS %s %*ph\n", hwe->name, 16, status->vaddr);
- if (memirq_received(memirq, status, ilog2(GT_MI_USER_INTERRUPT), hwe->name))
- xe_hw_engine_handle_irq(hwe, GT_MI_USER_INTERRUPT);
+ /*
+ * The programming note says to assume that GT_MI_USER_INTERRUPT is always
+ * set. Check and clear related status byte just for a debug.
+ */
+ if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_MEMIRQ) &&
+ !memirq_received(memirq, status, ilog2(GT_MI_USER_INTERRUPT), hwe->name))
+ memirq_assume_received(memirq, hwe->name, ilog2(GT_MI_USER_INTERRUPT), "USER");
+ xe_hw_engine_handle_irq(hwe, GT_MI_USER_INTERRUPT);
}
static void memirq_dispatch_guc(struct xe_memirq *memirq, struct iosys_map *status,
@@ -443,8 +455,14 @@ static void memirq_dispatch_guc(struct xe_memirq *memirq, struct iosys_map *stat
memirq_debug(memirq, "STATUS %s %*ph\n", name, 16, status->vaddr);
- if (memirq_received(memirq, status, ilog2(GUC_INTR_GUC2HOST), name))
- xe_guc_irq_handler(guc, GUC_INTR_GUC2HOST);
+ /*
+ * The programming note says to assume that GUC_INTR_GUC2HOST is always
+ * set. Check and clear related status byte just for a debug.
+ */
+ if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_MEMIRQ) &&
+ !memirq_received(memirq, status, ilog2(GUC_INTR_GUC2HOST), name))
+ memirq_assume_received(memirq, name, ilog2(GUC_INTR_GUC2HOST), "GUC2HOST");
+ xe_guc_irq_handler(guc, GUC_INTR_GUC2HOST);
/*
* This is a software interrupt that must be cleared after it's consumed
diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c
index 5fdc89ed5256..a22413f892a0 100644
--- a/drivers/gpu/drm/xe/xe_migrate.c
+++ b/drivers/gpu/drm/xe/xe_migrate.c
@@ -1524,23 +1524,9 @@ static void emit_clear_main_copy(struct xe_gt *gt, struct xe_bb *bb,
bb->len += len;
}
-static bool has_service_copy_support(struct xe_gt *gt)
-{
- /*
- * What we care about is whether the architecture was designed with
- * service copy functionality (specifically the new MEM_SET / MEM_COPY
- * instructions) so check the architectural engine list rather than the
- * actual list since these instructions are usable on BCS0 even if
- * all of the actual service copy engines (BCS1-BCS8) have been fused
- * off.
- */
- return gt->info.engine_mask & GENMASK(XE_HW_ENGINE_BCS8,
- XE_HW_ENGINE_BCS1);
-}
-
static u32 emit_clear_cmd_len(struct xe_gt *gt)
{
- if (has_service_copy_support(gt))
+ if (gt->info.has_xe2_blt_instructions)
return PVC_MEM_SET_CMD_LEN_DW;
else
return XY_FAST_COLOR_BLT_DW;
@@ -1549,7 +1535,7 @@ static u32 emit_clear_cmd_len(struct xe_gt *gt)
static void emit_clear(struct xe_gt *gt, struct xe_bb *bb, u64 src_ofs,
u32 size, u32 pitch, bool is_vram)
{
- if (has_service_copy_support(gt))
+ if (gt->info.has_xe2_blt_instructions)
emit_clear_link_copy(gt, bb, src_ofs, size, pitch);
else
emit_clear_main_copy(gt, bb, src_ofs, size, pitch,
diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
index 6337e671c97a..d908f4e03906 100644
--- a/drivers/gpu/drm/xe/xe_oa.c
+++ b/drivers/gpu/drm/xe/xe_oa.c
@@ -2032,8 +2032,10 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f
if (XE_IOCTL_DBG(oa->xe, !param.exec_q))
return -ENOENT;
- if (XE_IOCTL_DBG(oa->xe, param.exec_q->width > 1))
- return -EOPNOTSUPP;
+ if (XE_IOCTL_DBG(oa->xe, param.exec_q->width > 1)) {
+ ret = -EOPNOTSUPP;
+ goto err_exec_q;
+ }
}
/*
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index 9f98d0334164..c2ecd27ec770 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -852,6 +852,15 @@ static struct xe_gt *alloc_primary_gt(struct xe_tile *tile,
gt->info.num_compute_xecore_fuse_regs = graphics_desc->num_compute_xecore_fuse_regs;
/*
+ * Even if the service copy engines wind up being fused off, their
+ * presence in the IP descriptor indicates that the platform supports
+ * Xe2-style MEM_SET and MEM_COPY functionality.
+ */
+ if (graphics_desc->hw_engine_mask & GENMASK(XE_HW_ENGINE_BCS8,
+ XE_HW_ENGINE_BCS1))
+ gt->info.has_xe2_blt_instructions = true;
+
+ /*
* Before media version 13, the media IP was part of the primary GT
* so we need to add the media engines to the primary GT's engine list.
*/
diff --git a/drivers/gpu/drm/xe/xe_sriov_pf_migration.c b/drivers/gpu/drm/xe/xe_sriov_pf_migration.c
index 6c4b16409cc9..150a241110fb 100644
--- a/drivers/gpu/drm/xe/xe_sriov_pf_migration.c
+++ b/drivers/gpu/drm/xe/xe_sriov_pf_migration.c
@@ -149,10 +149,11 @@ pf_migration_consume(struct xe_device *xe, unsigned int vfid)
for_each_gt(gt, xe, gt_id) {
data = xe_gt_sriov_pf_migration_save_consume(gt, vfid);
- if (data && PTR_ERR(data) != EAGAIN)
+ if (!data)
+ continue;
+ if (!IS_ERR(data) || PTR_ERR(data) != -EAGAIN)
return data;
- if (PTR_ERR(data) == -EAGAIN)
- more_data = true;
+ more_data = true;
}
if (!more_data)
diff --git a/drivers/gpu/drm/xe/xe_tile_types.h b/drivers/gpu/drm/xe/xe_tile_types.h
index 33932fd547d7..0048100ccb72 100644
--- a/drivers/gpu/drm/xe/xe_tile_types.h
+++ b/drivers/gpu/drm/xe/xe_tile_types.h
@@ -106,8 +106,6 @@ struct xe_tile {
struct xe_lmtt lmtt;
} pf;
struct {
- /** @sriov.vf.ggtt_balloon: GGTT regions excluded from use. */
- struct xe_ggtt_node *ggtt_balloon[2];
/** @sriov.vf.self_config: VF configuration data */
struct xe_tile_sriov_vf_selfconfig self_config;
} vf;
diff --git a/drivers/gpu/drm/xe/xe_tuning.c b/drivers/gpu/drm/xe/xe_tuning.c
index 0b78ec2bc6a4..fcb6698abc6e 100644
--- a/drivers/gpu/drm/xe/xe_tuning.c
+++ b/drivers/gpu/drm/xe/xe_tuning.c
@@ -129,7 +129,7 @@ static const struct xe_rtp_entry_sr engine_tunings[] = {
static const struct xe_rtp_entry_sr lrc_tunings[] = {
{ XE_RTP_NAME("Tuning: Windower HW Filtering"),
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3599), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN4, HW_FILTERING))
+ XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN4, HW_FILTERING))
},
/* DG2 */
diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c
index 9cebb2490245..18ebefd444fe 100644
--- a/drivers/gpu/drm/xe/xe_uc_fw.c
+++ b/drivers/gpu/drm/xe/xe_uc_fw.c
@@ -115,7 +115,6 @@ struct fw_blobs_by_type {
#define XE_GT_TYPE_ANY XE_GT_TYPE_UNINITIALIZED
#define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) \
- fw_def(NOVALAKE_S, GT_TYPE_ANY, mmp_ver(xe, guc, nvl, 70, 55, 4)) \
fw_def(PANTHERLAKE, GT_TYPE_ANY, major_ver(xe, guc, ptl, 70, 54, 0)) \
fw_def(BATTLEMAGE, GT_TYPE_ANY, major_ver(xe, guc, bmg, 70, 54, 0)) \
fw_def(LUNARLAKE, GT_TYPE_ANY, major_ver(xe, guc, lnl, 70, 53, 0)) \
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index a717a2b8dea3..ab6cc1f0a789 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1120,6 +1120,25 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
xe_bo_assert_held(bo);
+ /*
+ * Reject only WILLNEED mappings on DONTNEED/PURGED BOs. This
+ * gates new vm_bind ioctls (user supplies WILLNEED) while
+ * still allowing partial-unbind / remap splits whose new VMAs
+ * inherit the parent's DONTNEED attr. It must also run before
+ * xe_bo_willneed_get_locked() below so a 0->1 holder bump
+ * cannot silently promote DONTNEED back to WILLNEED.
+ */
+ if (vma->attr.purgeable_state == XE_MADV_PURGEABLE_WILLNEED) {
+ if (xe_bo_madv_is_dontneed(bo)) {
+ xe_vma_free(vma);
+ return ERR_PTR(-EBUSY);
+ }
+ if (xe_bo_is_purged(bo)) {
+ xe_vma_free(vma);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
vm_bo = drm_gpuvm_bo_obtain_locked(vma->gpuva.vm, &bo->ttm.base);
if (IS_ERR(vm_bo)) {
xe_vma_free(vma);
@@ -1131,6 +1150,10 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
vma->gpuva.gem.offset = bo_offset_or_userptr;
drm_gpuva_link(&vma->gpuva, vm_bo);
drm_gpuvm_bo_put(vm_bo);
+
+ xe_bo_vma_count_inc_locked(bo);
+ if (vma->attr.purgeable_state == XE_MADV_PURGEABLE_WILLNEED)
+ xe_bo_willneed_get_locked(bo);
} else /* userptr or null */ {
if (!is_null && !is_cpu_addr_mirror) {
struct xe_userptr_vma *uvma = to_userptr_vma(vma);
@@ -1208,7 +1231,10 @@ static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
xe_bo_assert_held(bo);
drm_gpuva_unlink(&vma->gpuva);
- xe_bo_recompute_purgeable_state(bo);
+
+ xe_bo_vma_count_dec_locked(bo);
+ if (vma->attr.purgeable_state == XE_MADV_PURGEABLE_WILLNEED)
+ xe_bo_willneed_put_locked(bo);
}
xe_vm_assert_held(vm);
@@ -3016,7 +3042,7 @@ static void vm_bind_ioctl_ops_unwind(struct xe_vm *vm,
* @res_evict: Allow evicting resources during validation
* @validate: Perform BO validation
* @request_decompress: Request BO decompression
- * @check_purged: Reject operation if BO is purged
+ * @check_purged: Reject operation if BO is DONTNEED or PURGED
*/
struct xe_vma_lock_and_validate_flags {
u32 res_evict : 1;
@@ -3030,6 +3056,7 @@ static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,
{
struct xe_bo *bo = xe_vma_bo(vma);
struct xe_vm *vm = xe_vma_vm(vma);
+ bool validate_bo = flags.validate;
int err = 0;
if (bo) {
@@ -3044,7 +3071,11 @@ static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,
err = -EINVAL; /* BO already purged */
}
- if (!err && flags.validate)
+ /* Don't validate the BO for DONTNEED/PURGED remap remnants. */
+ if (vma->attr.purgeable_state != XE_MADV_PURGEABLE_WILLNEED)
+ validate_bo = false;
+
+ if (!err && validate_bo)
err = xe_bo_validate(bo, vm,
xe_vm_allow_vm_eviction(vm) &&
flags.res_evict, exec);
@@ -3152,7 +3183,7 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
op->map.immediate,
.request_decompress =
op->map.request_decompress,
- .check_purged = true,
+ .check_purged = false,
});
break;
case DRM_GPUVA_OP_REMAP:
@@ -3174,7 +3205,7 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
.res_evict = res_evict,
.validate = true,
.request_decompress = false,
- .check_purged = true,
+ .check_purged = false,
});
if (!err && op->remap.next)
err = vma_lock_and_validate(exec, op->remap.next,
@@ -3182,7 +3213,7 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
.res_evict = res_evict,
.validate = true,
.request_decompress = false,
- .check_purged = true,
+ .check_purged = false,
});
break;
case DRM_GPUVA_OP_UNMAP:
@@ -3211,9 +3242,11 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
}
/*
- * Prefetch attempts to migrate BO's backing store without
- * repopulating it first. Purged BOs have no backing store
- * to migrate, so reject the operation.
+ * PREFETCH is the only op that still gates on BO purge state.
+ * MAP/REMAP handle this inside xe_vma_create() so partial
+ * unbind on a DONTNEED BO still works. PREFETCH skips
+ * xe_vma_create() and would migrate a BO with no backing
+ * store, so reject DONTNEED/PURGED here.
*/
err = vma_lock_and_validate(exec,
gpuva_to_vma(op->base.prefetch.va),
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c
index c78906dea82b..c4fb29004195 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.c
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.c
@@ -186,147 +186,6 @@ static void madvise_pat_index(struct xe_device *xe, struct xe_vm *vm,
}
/**
- * xe_bo_is_dmabuf_shared() - Check if BO is shared via dma-buf
- * @bo: Buffer object
- *
- * Prevent marking imported or exported dma-bufs as purgeable.
- * For imported BOs, Xe doesn't own the backing store and cannot
- * safely reclaim pages (exporter or other devices may still be
- * using them). For exported BOs, external devices may have active
- * mappings we cannot track.
- *
- * Return: true if BO is imported or exported, false otherwise
- */
-static bool xe_bo_is_dmabuf_shared(struct xe_bo *bo)
-{
- struct drm_gem_object *obj = &bo->ttm.base;
-
- /* Imported: exporter owns backing store */
- if (drm_gem_is_imported(obj))
- return true;
-
- /* Exported: external devices may be accessing */
- if (obj->dma_buf)
- return true;
-
- return false;
-}
-
-/**
- * enum xe_bo_vmas_purge_state - VMA purgeable state aggregation
- *
- * Distinguishes whether a BO's VMAs are all DONTNEED, have at least
- * one WILLNEED, or have no VMAs at all.
- *
- * Enum values align with XE_MADV_PURGEABLE_* states for consistency.
- */
-enum xe_bo_vmas_purge_state {
- /** @XE_BO_VMAS_STATE_WILLNEED: At least one VMA is WILLNEED */
- XE_BO_VMAS_STATE_WILLNEED = 0,
- /** @XE_BO_VMAS_STATE_DONTNEED: All VMAs are DONTNEED */
- XE_BO_VMAS_STATE_DONTNEED = 1,
- /** @XE_BO_VMAS_STATE_NO_VMAS: BO has no VMAs */
- XE_BO_VMAS_STATE_NO_VMAS = 2,
-};
-
-/*
- * xe_bo_recompute_purgeable_state() casts between xe_bo_vmas_purge_state and
- * xe_madv_purgeable_state. Enforce that WILLNEED=0 and DONTNEED=1 match across
- * both enums so the single-line cast is always valid.
- */
-static_assert(XE_BO_VMAS_STATE_WILLNEED == (int)XE_MADV_PURGEABLE_WILLNEED,
- "VMA purge state WILLNEED must equal madv purgeable WILLNEED");
-static_assert(XE_BO_VMAS_STATE_DONTNEED == (int)XE_MADV_PURGEABLE_DONTNEED,
- "VMA purge state DONTNEED must equal madv purgeable DONTNEED");
-
-/**
- * xe_bo_all_vmas_dontneed() - Determine BO VMA purgeable state
- * @bo: Buffer object
- *
- * Check all VMAs across all VMs to determine aggregate purgeable state.
- * Shared BOs require unanimous DONTNEED state from all mappings.
- *
- * Caller must hold BO dma-resv lock.
- *
- * Return: XE_BO_VMAS_STATE_DONTNEED if all VMAs are DONTNEED,
- * XE_BO_VMAS_STATE_WILLNEED if at least one VMA is not DONTNEED,
- * XE_BO_VMAS_STATE_NO_VMAS if BO has no VMAs
- */
-static enum xe_bo_vmas_purge_state xe_bo_all_vmas_dontneed(struct xe_bo *bo)
-{
- struct drm_gpuvm_bo *vm_bo;
- struct drm_gpuva *gpuva;
- struct drm_gem_object *obj = &bo->ttm.base;
- bool has_vmas = false;
-
- xe_bo_assert_held(bo);
-
- /* Shared dma-bufs cannot be purgeable */
- if (xe_bo_is_dmabuf_shared(bo))
- return XE_BO_VMAS_STATE_WILLNEED;
-
- drm_gem_for_each_gpuvm_bo(vm_bo, obj) {
- drm_gpuvm_bo_for_each_va(gpuva, vm_bo) {
- struct xe_vma *vma = gpuva_to_vma(gpuva);
-
- has_vmas = true;
-
- /* Any non-DONTNEED VMA prevents purging */
- if (vma->attr.purgeable_state != XE_MADV_PURGEABLE_DONTNEED)
- return XE_BO_VMAS_STATE_WILLNEED;
- }
- }
-
- /*
- * No VMAs => preserve existing BO purgeable state.
- * Avoids incorrectly flipping DONTNEED -> WILLNEED when last VMA unmapped.
- */
- if (!has_vmas)
- return XE_BO_VMAS_STATE_NO_VMAS;
-
- return XE_BO_VMAS_STATE_DONTNEED;
-}
-
-/**
- * xe_bo_recompute_purgeable_state() - Recompute BO purgeable state from VMAs
- * @bo: Buffer object
- *
- * Walk all VMAs to determine if BO should be purgeable or not.
- * Shared BOs require unanimous DONTNEED state from all mappings.
- * If the BO has no VMAs the existing state is preserved.
- *
- * Locking: Caller must hold BO dma-resv lock. When iterating GPUVM lists,
- * VM lock must also be held (write) to prevent concurrent VMA modifications.
- * This is satisfied at both call sites:
- * - xe_vma_destroy(): holds vm->lock write
- * - madvise_purgeable(): holds vm->lock write (from madvise ioctl path)
- *
- * Return: nothing
- */
-void xe_bo_recompute_purgeable_state(struct xe_bo *bo)
-{
- enum xe_bo_vmas_purge_state vma_state;
-
- if (!bo)
- return;
-
- xe_bo_assert_held(bo);
-
- /*
- * Once purged, always purged. Cannot transition back to WILLNEED.
- * This matches i915 semantics where purged BOs are permanently invalid.
- */
- if (bo->madv_purgeable == XE_MADV_PURGEABLE_PURGED)
- return;
-
- vma_state = xe_bo_all_vmas_dontneed(bo);
-
- if (vma_state != (enum xe_bo_vmas_purge_state)bo->madv_purgeable &&
- vma_state != XE_BO_VMAS_STATE_NO_VMAS)
- xe_bo_set_purgeable_state(bo, (enum xe_madv_purgeable_state)vma_state);
-}
-
-/**
* madvise_purgeable - Handle purgeable buffer object advice
* @xe: XE device
* @vm: VM
@@ -359,12 +218,6 @@ static void madvise_purgeable(struct xe_device *xe, struct xe_vm *vm,
/* BO must be locked before modifying madv state */
xe_bo_assert_held(bo);
- /* Skip shared dma-bufs - no PTEs to zap */
- if (xe_bo_is_dmabuf_shared(bo)) {
- vmas[i]->skip_invalidation = true;
- continue;
- }
-
/*
* Once purged, always purged. Cannot transition back to WILLNEED.
* This matches i915 semantics where purged BOs are permanently invalid.
@@ -377,13 +230,14 @@ static void madvise_purgeable(struct xe_device *xe, struct xe_vm *vm,
switch (op->purge_state_val.val) {
case DRM_XE_VMA_PURGEABLE_STATE_WILLNEED:
- vmas[i]->attr.purgeable_state = XE_MADV_PURGEABLE_WILLNEED;
vmas[i]->skip_invalidation = true;
-
- xe_bo_recompute_purgeable_state(bo);
+ /* Only act on a real DONTNEED -> WILLNEED transition. */
+ if (vmas[i]->attr.purgeable_state == XE_MADV_PURGEABLE_DONTNEED) {
+ vmas[i]->attr.purgeable_state = XE_MADV_PURGEABLE_WILLNEED;
+ xe_bo_willneed_get_locked(bo);
+ }
break;
case DRM_XE_VMA_PURGEABLE_STATE_DONTNEED:
- vmas[i]->attr.purgeable_state = XE_MADV_PURGEABLE_DONTNEED;
/*
* Don't zap PTEs at DONTNEED time -- pages are still
* alive. The zap happens in xe_bo_move_notify() right
@@ -391,7 +245,11 @@ static void madvise_purgeable(struct xe_device *xe, struct xe_vm *vm,
*/
vmas[i]->skip_invalidation = true;
- xe_bo_recompute_purgeable_state(bo);
+ /* Only act on a real WILLNEED -> DONTNEED transition. */
+ if (vmas[i]->attr.purgeable_state == XE_MADV_PURGEABLE_WILLNEED) {
+ vmas[i]->attr.purgeable_state = XE_MADV_PURGEABLE_DONTNEED;
+ xe_bo_willneed_put_locked(bo);
+ }
break;
default:
/* Should never hit - values validated in madvise_args_are_sane() */
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.h b/drivers/gpu/drm/xe/xe_vm_madvise.h
index 39acd2689ca0..a3078f634c7e 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.h
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.h
@@ -13,6 +13,4 @@ struct xe_bo;
int xe_vm_madvise_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
-void xe_bo_recompute_purgeable_state(struct xe_bo *bo);
-
#endif
diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c
index 4b1cbced06be..33df43d0bede 100644
--- a/drivers/gpu/drm/xe/xe_wa.c
+++ b/drivers/gpu/drm/xe/xe_wa.c
@@ -651,7 +651,7 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
},
{ XE_RTP_NAME("18033852989"),
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2004), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN1, DISABLE_BOTTOM_CLIP_RECTANGLE_TEST))
+ XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN1, DISABLE_BOTTOM_CLIP_RECTANGLE_TEST))
},
{ XE_RTP_NAME("15016589081"),
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2004), ENGINE_CLASS(RENDER)),
@@ -754,7 +754,7 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
},
{ XE_RTP_NAME("22021007897"),
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN4, SBE_PUSH_CONSTANT_BEHIND_FIX_ENABLE))
+ XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN4, SBE_PUSH_CONSTANT_BEHIND_FIX_ENABLE))
},
/* Xe3_LPG */
@@ -770,7 +770,7 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
},
{ XE_RTP_NAME("22021007897"),
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3005), ENGINE_CLASS(RENDER)),
- XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN4, SBE_PUSH_CONSTANT_BEHIND_FIX_ENABLE))
+ XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN4, SBE_PUSH_CONSTANT_BEHIND_FIX_ENABLE))
},
{ XE_RTP_NAME("14024681466"),
XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3005), ENGINE_CLASS(RENDER)),