mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-28 12:53:14 +01:00
Merge tag 'drm-fixes-2026-10-17' of https://gitlab.freedesktop.org/drm/kernel
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:
commit
58161ead29
30 files changed
+348
-132
No files matched your search
+4
-3
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user