Pull drm fixes from Dave Airlie:
 "Last set of fixes, mostly amdgpu, some i915 and xe.

  I think the dma-buf revert is probably the most important: while it is
  technically correct the fallout from it means we shouldn't enable
  DMABUF_DEBUG like that yet, and fix the fallout first.

  Summary:

  MAINTAINERS update

  dma-buf:
   - revert dma-debug y on debug kernel due to msm interaction

  core:
   - fix drm_exec prelocked object interaction

  i915:
   - Fix ARL-S host bridge detection
   - Add sanity checks for malformed DMC firmware

  xe:
   - OA uAPI fix
   - shrinker fix
   - fix eviction of object with no bo resource
   - fix LRU for external objects

  amdgpu:
   - UVD fix
   - TTM sched entity fixes
   - SMU 14 fix
   - Userptr leak fixes
   - Runpm ref count fix
   - CRIU fix
   - UserQ fixes
   - USB4 fix
   - SDMA 3 fix

  virtio-gpu:
   - revert double setting blend property
   - reset device before deleting vqs on freeze

  vc4:
   - fix hdmi audio runtime_pm interaction

  amdxdna:
   - fix Kconfig invalid configuration

  rocket:
   - fix error path for failed init
   - fix core unbinding and scheduler lookup paths

  panthor:
   - fix immortalis configuration"

* tag 'drm-fixes-2026-10-17' of https://gitlab.freedesktop.org/drm/kernel: (31 commits)
  drm/amdgpu/sdma3: Work around POLL_REGMEM / FENCE hang
  drm/amdgpu: keep the eviction fence until the last handle is closed
  drm/amd/display: Fix NULL sink dereference in USB4 bandwidth functions
  drm/amdgpu/userq: actually validate userq BOs
  drm/amdgpu: report the BO alignment in bytes in GEM_LIST_HANDLES
  drm/amdgpu: free the userptr ranges when a CS fails after parser_bos
  drm/amdgpu: don't drop the runtime PM reference twice in amdgpu_gpr
  drm/amdgpu: fix GEM object leak on ENOMEM in userptr ioctl
  drm/amd/pm: add zero fan stop temperature support on smu 14.0.2
  drm/amdgpu: destroy mutex when tearing down ttm buffer entity
  drm/amdgpu: fix sched entity leak in ttm buffer entity init
  drm/amdgpu/uvd3.1: Fix checking whether UVD firmware keyselect was already set
  drm/panthor: fix immortalis condition
  drm/i915/cx0_phy: Fix ARL-S host bridge detection
  drm/i915/dmc: Add sanity check for DMC load address
  drm/i915/dmc: Harden DMC firmware payload parsing
  drm/exec: don't immediately add prelocked obj to array of locked objs
  drm/virtio: Reset device before deleting virtqueues on freeze
  drm/xe: Bump LRU for external objects on exec and rebind
  drm/xe/oa: Zero OA buffer at allocation
  ...
This commit is contained in:
Linus Torvalds committed 2026-10-16 15:33:36 -10:00
commit 58161ead29
30 files changed
+348 -132

No files matched your search

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