mirror of
https://github.com/torvalds/linux.git
synced 2026-10-23 15:32:04 +02:00
drm fixes for 7.3-rc7
fb: - defer setup when fbdev_probe() fails, not just on -EAGAIN bridge: - Fix unlocked list_del in drm_bridge_add() - Fix unlocked list access in drm_bridge_attach() - th1520-dw-hdmi: Fix error check on dw_hdmi_probe() return value - th1520-dw-hdmi: Fix remove() callback aspeed: - Balance the display clock enable on teardown i915: - Fix a GT park race that could trigger spurious RPM wakelock warnings - Fix execbuffer relocation cleanup to avoid out-of-bounds free xe: - i2c removal - system Controller Maibox header handling - two bo pin/unpin accounting bugs - not emitting a w/a twice - xe_mmio_wait32() to honor delay/sleep maximums amdgpu: - Fix direct scanout alpha on some DRM_FORMATs - UserQ fixes - Fix tearing flips with PSR - GPU reset vblank fix - Debugfs register interface fix - Fix display mode patching - Expand Mac reserved memory workaround amdkfd: - SDMA doorbell fix - Fix dma-buf reference leak in error path imagination: - fix reference and vm_bo handling in remap() - size page table preallocation by device address gud: - don't keep a connector without a CRTC as connector_state panthor: - validate userspace queue count against initialized firmware slot count nouveau: - fix null ptr regression - skip turing CE workaround for non-GR vmwgfx: - validate pitch value - add blend mode property vc4: - drain hangcheck timer on unbind - free BO cache on teardown - use kvmalloc_objs for bo cache size list - disable V3D interrupt across runtime suspend - fix binner slot allocation - fix fw refcount leak -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmrKj3sACgkQDHTzWXnE hr6e+A/+I1d+UvVkSnIsMv7NGLGiNvDClWvTnypF0ys2poiUGZ88UPzGuE7r8zfc BK9zZnQ/+LSYu/NLhmLnxDxYmx+Y2rKMjQEq22RsjUAzrPhn0/UsoWTt5jRMfim+ If9gW5p51rX4TBH90fgiTiwvAHxfSSzPjIlQIcjSAQKFxOIZ6mQtyKU4453H//XQ AO1fIDOvcUnZXyQCveoLtaU9ICKv5HNTwF4UBAnRfOmrJr/1ny2H51/tsFkh4Dwy h/OMyJDMNSfa/w9JZOGC/+fEipEQZ15Hk3QUy8i+UUEtD/JKFeG2nlNPuKqjjhrA slQa8E9M7anw+akPjJ0vWrOrqMXcxXE9huRWUUvv9MXkXpFjYmUeBTw1Q9Oc2No4 kdqmS9Skl6R/VJjeWeV2m/iNftL0k3CUWr2paCb9nGUOoaxdoMC72JVl7MprrSOT KG46ggDMfqhIygfkT+PBighZkMCJs/Fkw/UCM9Dldc3M3ds1VmQnH9I+1W+LUqjN OHT5FJfiabejImgnrPtPDtGJtZQub7K9ZUJc13GqxjCK3IXp1oqit8wVZS1qqmw7 3dpc+mWB0Re9CnlaOVb/WTzbip3WGlX8mdHrm+gKYHhigR5EjwiZSal7jP+fKYqK riXBBTU4CE44Y92lutvtJ4NjSqiShK/pzAkzPVVL8bCYoQAL4fk= =TKVJ -----END PGP SIGNATURE----- Merge tag 'drm-fixes-2026-10-11' of https://gitlab.freedesktop.org/drm/kernel Pull drm fixes from Dave Ailie: "Live from Dublin Airport, it's Saturday Night drm fixes. This week has the missing misc fixes from last week which I tracked down and seemed to be a race/bug in my lei setup somehow, once I asked lei to ignore it's cache I got the missing email. But there are more misc fixes this week and amd and intel ones. The main ones in this are amdgpu and xe, with vc4, vmwgfx, nouveau and imagination in the middle, with a bunch of small single fixes. Bit busier than I'd like, but the missing misc might explain it, anyways time for me to fly home. fb: - defer setup when fbdev_probe() fails, not just on -EAGAIN bridge: - Fix unlocked list_del in drm_bridge_add() - Fix unlocked list access in drm_bridge_attach() - th1520-dw-hdmi: - Fix error check on dw_hdmi_probe() return value - Fix remove() callback aspeed: - Balance the display clock enable on teardown i915: - Fix a GT park race that could trigger spurious RPM wakelock warnings - Fix execbuffer relocation cleanup to avoid out-of-bounds free xe: - i2c removal - system Controller Maibox header handling - two bo pin/unpin accounting bugs - not emitting a w/a twice - xe_mmio_wait32() to honor delay/sleep maximums amdgpu: - Fix direct scanout alpha on some DRM_FORMATs - UserQ fixes - Fix tearing flips with PSR - GPU reset vblank fix - Debugfs register interface fix - Fix display mode patching - Expand Mac reserved memory workaround amdkfd: - SDMA doorbell fix - Fix dma-buf reference leak in error path imagination: - fix reference and vm_bo handling in remap() - size page table preallocation by device address gud: - don't keep a connector without a CRTC as connector_state panthor: - validate userspace queue count against initialized firmware slot count nouveau: - fix null ptr regression - skip turing CE workaround for non-GR vmwgfx: - validate pitch value - add blend mode property vc4: - drain hangcheck timer on unbind - free BO cache on teardown - use kvmalloc_objs for bo cache size list - disable V3D interrupt across runtime suspend - fix binner slot allocation - fix fw refcount leak" * tag 'drm-fixes-2026-10-11' of https://gitlab.freedesktop.org/drm/kernel: (39 commits) drm/nouveau: Skip the Turing CE workaround object for non-GR channels drm/vc4: Fix binner slot allocation failing on an idle GPU drm/vc4: Disable the V3D interrupt across runtime suspend drm/imagination: Size page table preallocation by device address drm/imagination: Fix reference and vm_bo handling in remap() drm/amdgpu: make Mac FB workaround generic drm/amdkfd: fix dma_buf reference leak in get_dmabuf_info drm/amd/display: Don't replace a sink mode that shares the native totals drm/amdkfd: align SDMA doorbell base for shader doorbell writes drm/amdgpu: copy debugfs register data outside the GRBM/SRBM locks drm/amdgpu: serialize vblank counter reads against GPU reset drm/amd/display: disable self-refresh on tearing flips drm/amdgpu/userq: return the memdup_user() error for the user MQD drm/amdgpu/userq: only accept doorbell BOs as queue doorbell drm/amd/display: Fix direct scanout alpha on some DRM_FORMATs drm/xe/i2c: cancel the client work on remove drm/xe/sysctrl: Fix mailbox header handling drm/i915/gt: Unmask interrupts only when ACTIVE is true drm/i915/gem: Prevent overstepping exec array boundary drm/gud: don't keep a connector without a CRTC as connector_state ...
This commit is contained in:
commit
bb934c29fd
|
|
@ -598,14 +598,18 @@ int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
|
|||
/* first get metadata_size by buffer = NULL */
|
||||
r = amdgpu_bo_get_metadata(bo, NULL, 0,
|
||||
metadata_size, NULL);
|
||||
if (r)
|
||||
goto out_put;
|
||||
|
||||
/* user buf_size is bigger than bo metadata_size
|
||||
* allocate a buf at kernel space and copy */
|
||||
if (*metadata_size <= buffer_size) {
|
||||
*metadata_buffer = kzalloc(*metadata_size, GFP_KERNEL);
|
||||
|
||||
if (!*metadata_buffer)
|
||||
return -ENOMEM;
|
||||
if (!*metadata_buffer) {
|
||||
r = -ENOMEM;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_get_metadata(bo, *metadata_buffer, *metadata_size,
|
||||
NULL, &metadata_flags);
|
||||
|
|
|
|||
|
|
@ -121,6 +121,20 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
|||
|
||||
*pos &= (1UL << 22) - 1;
|
||||
|
||||
if (size > PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Access the user buffer only while none of the locks below are held:
|
||||
* a fault takes mmap_lock, and grbm_idx_mutex and srbm_mutex nest
|
||||
* inside it.
|
||||
*/
|
||||
u32 *data __free(kfree) = kmalloc(size, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
if (!read && copy_from_user(data, buf, size))
|
||||
return -EFAULT;
|
||||
|
||||
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
|
||||
if (r < 0) {
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
|
@ -152,28 +166,16 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
|||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
if (read) {
|
||||
value = RREG32(*pos >> 2);
|
||||
r = put_user(value, (uint32_t *)buf);
|
||||
} else {
|
||||
r = get_user(value, (uint32_t *)buf);
|
||||
if (!r)
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, *pos >> 2, value, 0);
|
||||
}
|
||||
if (r) {
|
||||
result = r;
|
||||
goto end;
|
||||
}
|
||||
if (read)
|
||||
data[result >> 2] = RREG32(*pos >> 2);
|
||||
else
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, *pos >> 2, data[result >> 2], 0);
|
||||
|
||||
result += 4;
|
||||
buf += 4;
|
||||
*pos += 4;
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
end:
|
||||
if (use_bank) {
|
||||
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, 0);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
|
@ -188,6 +190,10 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
|||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
||||
amdgpu_virt_disable_access_debugfs(adev);
|
||||
|
||||
if (read && copy_to_user(buf, data, result))
|
||||
return -EFAULT;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -238,11 +244,24 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
|
|||
struct amdgpu_device *adev = rd->adev;
|
||||
ssize_t result = 0;
|
||||
int r;
|
||||
uint32_t value;
|
||||
|
||||
if (size & 0x3 || offset & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
if (size > PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Access the user buffer only while none of the locks below are held:
|
||||
* a fault takes mmap_lock, and grbm_idx_mutex and srbm_mutex nest
|
||||
* inside it.
|
||||
*/
|
||||
u32 *data __free(kfree) = kmalloc(size, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
if (write_en && copy_from_user(data, buf, size))
|
||||
return -EFAULT;
|
||||
|
||||
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
|
||||
if (r < 0) {
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
|
@ -281,24 +300,16 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
|
|||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
while (size) {
|
||||
if (!write_en) {
|
||||
value = RREG32(offset >> 2);
|
||||
r = put_user(value, (uint32_t *)buf);
|
||||
} else {
|
||||
r = get_user(value, (uint32_t *)buf);
|
||||
if (!r)
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value, rd->id.xcc_id);
|
||||
}
|
||||
if (r) {
|
||||
result = r;
|
||||
goto end;
|
||||
}
|
||||
if (!write_en)
|
||||
data[result >> 2] = RREG32(offset >> 2);
|
||||
else
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, data[result >> 2],
|
||||
rd->id.xcc_id);
|
||||
offset += 4;
|
||||
size -= 4;
|
||||
result += 4;
|
||||
buf += 4;
|
||||
}
|
||||
end:
|
||||
|
||||
if (rd->id.use_grbm) {
|
||||
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, rd->id.xcc_id);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
|
@ -317,6 +328,10 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
|
|||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
||||
amdgpu_virt_disable_access_debugfs(adev);
|
||||
|
||||
if (!write_en && copy_to_user(buf, data, result))
|
||||
return -EFAULT;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1080,20 +1080,17 @@ void amdgpu_gmc_init_vga_resv_regions(struct amdgpu_device *adev)
|
|||
case CHIP_RENOIR:
|
||||
adev->mman.keep_stolen_vga_memory = true;
|
||||
break;
|
||||
case CHIP_POLARIS10:
|
||||
case CHIP_POLARIS11:
|
||||
case CHIP_POLARIS12:
|
||||
/* MacBookPros with switchable graphics put VRAM at 0 when
|
||||
* the iGPU is enabled which results in cursor issues if
|
||||
* the cursor ends up at 0. Reserve vram at 0 in that case.
|
||||
*/
|
||||
if (adev->gmc.vram_start == 0)
|
||||
adev->mman.keep_stolen_vga_memory = true;
|
||||
break;
|
||||
default:
|
||||
adev->mman.keep_stolen_vga_memory = false;
|
||||
break;
|
||||
}
|
||||
/* MacBookPros with switchable graphics put VRAM at 0 when
|
||||
* the iGPU is enabled which results in cursor issues if
|
||||
* the cursor ends up at 0. Reserve vram at 0 in that case.
|
||||
*/
|
||||
if ((adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
|
||||
(adev->gmc.vram_start == 0))
|
||||
adev->mman.keep_stolen_vga_memory = true;
|
||||
|
||||
if (amdgpu_sriov_vf(adev) ||
|
||||
!amdgpu_device_has_display_hardware(adev)) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include "amdgpu_uvd.h"
|
||||
#include "amdgpu_vce.h"
|
||||
#include "atom.h"
|
||||
|
|
@ -1660,6 +1661,9 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
|
|||
DRM_ERROR("Invalid crtc %u\n", pipe);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!down_read_trylock(&adev->reset_domain->sem))
|
||||
return drm_crtc_vblank_count(crtc);
|
||||
|
||||
|
||||
/* The hw increments its frame counter at start of vsync, not at start
|
||||
* of vblank, as is required by DRM core vblank counter handling.
|
||||
|
|
@ -1705,6 +1709,7 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
|
|||
DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
|
||||
}
|
||||
|
||||
up_read(&adev->reset_domain->sem);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -472,6 +472,7 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
|||
u64 doorbell_index;
|
||||
struct drm_gem_object *gobj;
|
||||
struct amdgpu_userq_obj *db_obj = db_info->db_obj;
|
||||
struct amdgpu_bo *abo;
|
||||
int r, db_size;
|
||||
|
||||
gobj = drm_gem_object_lookup(filp, db_info->doorbell_handle);
|
||||
|
|
@ -480,7 +481,17 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
db_obj->obj = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
|
||||
/*
|
||||
* Pinning a regular BO into the doorbell domain would discard its
|
||||
* contents, possibly those of a buffer shared by another client.
|
||||
*/
|
||||
abo = gem_to_amdgpu_bo(gobj);
|
||||
if (!(abo->preferred_domains & AMDGPU_GEM_DOMAIN_DOORBELL)) {
|
||||
drm_gem_object_put(gobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
db_obj->obj = amdgpu_bo_ref(abo);
|
||||
drm_gem_object_put(gobj);
|
||||
|
||||
r = amdgpu_bo_reserve(db_obj->obj, true);
|
||||
|
|
|
|||
|
|
@ -361,8 +361,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
compute_mqd = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
|
||||
if (IS_ERR(compute_mqd)) {
|
||||
DRM_ERROR("Failed to read user MQD\n");
|
||||
r = -ENOMEM;
|
||||
r = PTR_ERR(compute_mqd);
|
||||
goto free_mqd;
|
||||
}
|
||||
|
||||
|
|
@ -406,8 +405,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
mqd_gfx_v11 = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
|
||||
if (IS_ERR(mqd_gfx_v11)) {
|
||||
DRM_ERROR("Failed to read user MQD\n");
|
||||
r = -ENOMEM;
|
||||
r = PTR_ERR(mqd_gfx_v11);
|
||||
goto free_mqd;
|
||||
}
|
||||
|
||||
|
|
@ -451,8 +449,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
mqd_sdma_v11 = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
|
||||
if (IS_ERR(mqd_sdma_v11)) {
|
||||
DRM_ERROR("Failed to read sdma user MQD\n");
|
||||
r = -ENOMEM;
|
||||
r = PTR_ERR(mqd_sdma_v11);
|
||||
goto free_mqd;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -572,12 +572,32 @@ static int allocate_doorbell(struct qcm_process_device *qpd,
|
|||
* we need the physical sdma engine id in order to get the
|
||||
* correct doorbell offset.
|
||||
*/
|
||||
uint32_t valid_id = idx_offset[qpd->dqm->dev->node_id *
|
||||
get_num_all_sdma_engines(qpd->dqm) +
|
||||
q->properties.sdma_engine_id]
|
||||
+ (q->properties.sdma_queue_id & 1)
|
||||
* KFD_QUEUE_DOORBELL_MIRROR_OFFSET
|
||||
+ (q->properties.sdma_queue_id >> 1);
|
||||
u32 engine_base = idx_offset[dev->node_id *
|
||||
get_num_all_sdma_engines(qpd->dqm) +
|
||||
q->properties.sdma_engine_id];
|
||||
u32 valid_id;
|
||||
|
||||
/*
|
||||
* With the aqua_vanjaram doorbell layout, a shader doorbell
|
||||
* write whose 32-byte block starts in the previous engine's
|
||||
* range rings that engine instead. Engine ranges are 10
|
||||
* indices apart (sdma_doorbell_range = 20 dwords, halved for
|
||||
* 8-byte doorbells, in aqua_vanjaram_doorbell_index_init()),
|
||||
* which puts odd engines 2 indices into a shared block.
|
||||
* Aligning costs at most 2 indices, and 8 queues per engine use
|
||||
* only 4 of the 10, so the aligned base stays in range. The
|
||||
* 512-index mirror offset keeps the alignment.
|
||||
*/
|
||||
if (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 3) ||
|
||||
KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 4) ||
|
||||
KFD_GC_VERSION(dev) == IP_VERSION(9, 5, 0))
|
||||
engine_base = ALIGN(engine_base,
|
||||
KFD_SDMA_SHADER_DOORBELL_GRANULARITY);
|
||||
|
||||
valid_id = engine_base +
|
||||
(q->properties.sdma_queue_id & 1) *
|
||||
KFD_QUEUE_DOORBELL_MIRROR_OFFSET +
|
||||
(q->properties.sdma_queue_id >> 1);
|
||||
|
||||
if (restore_id && *restore_id != valid_id)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -133,6 +133,13 @@
|
|||
*/
|
||||
#define KFD_QUEUE_DOORBELL_MIRROR_OFFSET 512
|
||||
|
||||
/*
|
||||
* On GC 9.4.3, 9.4.4 and 9.5.0, doorbell writes issued from shaders are
|
||||
* routed to an SDMA engine at 32-byte granularity, i.e. 4 indices with the
|
||||
* 8-byte SDMA doorbells used on SOC15.
|
||||
*/
|
||||
#define KFD_SDMA_SHADER_DOORBELL_GRANULARITY 4
|
||||
|
||||
/**
|
||||
* enum kfd_ioctl_flags - KFD ioctl flags
|
||||
* Various flags that can be set in &amdkfd_ioctl_desc.flags to control how
|
||||
|
|
|
|||
|
|
@ -3708,6 +3708,13 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
|
|||
struct amdgpu_dm_connector *aconn =
|
||||
(struct amdgpu_dm_connector *)acrtc_state->stream->dm_stream_context;
|
||||
|
||||
if (!acrtc_state->base.async_flip) {
|
||||
amdgpu_dm_psr_set_event(dm, acrtc_state->stream, false,
|
||||
psr_event_immediate_flip, false);
|
||||
amdgpu_dm_replay_set_event(dm, acrtc_state->stream, false,
|
||||
replay_event_immediate_flip, false);
|
||||
}
|
||||
|
||||
/* Decrement skip count when SR is enabled and we're doing fast updates. */
|
||||
if (acrtc_state->update_type == UPDATE_TYPE_FAST &&
|
||||
(psr->psr_feature_enabled || pr->replay_feature_enabled)) {
|
||||
|
|
@ -4118,6 +4125,18 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
|||
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
|
||||
}
|
||||
mutex_lock(&dm->dc_lock);
|
||||
/*
|
||||
* Tearing (immediate) flips cannot work with panel self-refresh
|
||||
* features. The event is cleared by
|
||||
* amdgpu_dm_enable_self_refresh() once async flips stop.
|
||||
*/
|
||||
if (immediate_flip) {
|
||||
dc_exit_ips_for_hw_access(dm->dc);
|
||||
amdgpu_dm_psr_set_event(dm, acrtc_state->stream, true,
|
||||
psr_event_immediate_flip, true);
|
||||
amdgpu_dm_replay_set_event(dm, acrtc_state->stream, true,
|
||||
replay_event_immediate_flip, true);
|
||||
}
|
||||
update_planes_and_stream_adapter(dm->dc,
|
||||
acrtc_state->update_type,
|
||||
planes_count,
|
||||
|
|
|
|||
|
|
@ -1012,10 +1012,15 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
|
|||
const struct drm_display_mode *native_mode,
|
||||
bool scale_enabled)
|
||||
{
|
||||
/* Inserted modes copy the native sync; a sink mode with equal totals may not */
|
||||
if (scale_enabled || (
|
||||
native_mode->clock == drm_mode->clock &&
|
||||
native_mode->htotal == drm_mode->htotal &&
|
||||
native_mode->vtotal == drm_mode->vtotal)) {
|
||||
native_mode->vtotal == drm_mode->vtotal &&
|
||||
native_mode->hsync_start == drm_mode->hsync_start &&
|
||||
native_mode->hsync_end == drm_mode->hsync_end &&
|
||||
native_mode->vsync_start == drm_mode->vsync_start &&
|
||||
native_mode->vsync_end == drm_mode->vsync_end)) {
|
||||
if (native_mode->crtc_clock)
|
||||
copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -112,25 +112,7 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state
|
|||
|
||||
if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
|
||||
plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
|
||||
static const uint32_t alpha_formats[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_RGBA8888,
|
||||
DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_ARGB2101010,
|
||||
DRM_FORMAT_ABGR2101010,
|
||||
DRM_FORMAT_ARGB16161616,
|
||||
DRM_FORMAT_ABGR16161616,
|
||||
DRM_FORMAT_ARGB16161616F,
|
||||
};
|
||||
uint32_t format = plane_state->fb->format->format;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
|
||||
if (format == alpha_formats[i]) {
|
||||
*per_pixel_alpha = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*per_pixel_alpha = plane_state->fb->format->has_alpha;
|
||||
|
||||
if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
|
||||
*pre_multiplied_alpha = false;
|
||||
|
|
|
|||
|
|
@ -1572,6 +1572,46 @@ static void dm_test_decide_crtc_timing_no_crtc_clock(struct kunit *test)
|
|||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 0);
|
||||
}
|
||||
|
||||
static void dm_test_decide_crtc_timing_sink_mode_same_totals(struct kunit *test)
|
||||
{
|
||||
struct drm_display_mode native_mode = {
|
||||
DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104,
|
||||
4400, 0, 2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
|
||||
struct drm_display_mode drm_mode = {
|
||||
DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184, 4272,
|
||||
4400, 0, 2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
|
||||
|
||||
drm_mode_set_crtcinfo(&native_mode, 0);
|
||||
drm_mode_set_crtcinfo(&drm_mode, 0);
|
||||
|
||||
decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 4096);
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hsync_start, 4184);
|
||||
}
|
||||
|
||||
static void dm_test_decide_crtc_timing_inserted_mode(struct kunit *test)
|
||||
{
|
||||
struct drm_display_mode native_mode = {
|
||||
DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104,
|
||||
4400, 0, 2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
|
||||
struct drm_display_mode drm_mode;
|
||||
|
||||
drm_mode_set_crtcinfo(&native_mode, 0);
|
||||
drm_mode = native_mode;
|
||||
drm_mode.hdisplay = 1920;
|
||||
drm_mode.vdisplay = 1080;
|
||||
drm_mode_set_crtcinfo(&drm_mode, 0);
|
||||
|
||||
decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 3840);
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_vdisplay, 2160);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_connector_funcs_reset() */
|
||||
|
||||
static const struct drm_connector_funcs dm_test_connector_funcs = {
|
||||
|
|
@ -5635,6 +5675,8 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
|
|||
KUNIT_CASE(dm_test_decide_crtc_timing_matching_mode),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_no_copy),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_no_crtc_clock),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_sink_mode_same_totals),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_inserted_mode),
|
||||
/* amdgpu_dm_connector_funcs_reset */
|
||||
KUNIT_CASE(dm_test_funcs_reset_sets_defaults),
|
||||
KUNIT_CASE(dm_test_funcs_reset_edp_abm_level),
|
||||
|
|
|
|||
|
|
@ -189,13 +189,12 @@ static int aspeed_gfx_load(struct drm_device *drm)
|
|||
}
|
||||
reset_control_deassert(priv->rst);
|
||||
|
||||
priv->clk = devm_clk_get(drm->dev, NULL);
|
||||
priv->clk = devm_clk_get_enabled(drm->dev, NULL);
|
||||
if (IS_ERR(priv->clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"missing or invalid clk device tree entry");
|
||||
"failed to get and enable clock\n");
|
||||
return PTR_ERR(priv->clk);
|
||||
}
|
||||
clk_prepare_enable(priv->clk);
|
||||
|
||||
/* Sanitize control registers */
|
||||
writel(0, priv->base + CRT_CTRL1);
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev)
|
|||
plat_data->priv_data = hdmi;
|
||||
|
||||
hdmi->dw_hdmi = dw_hdmi_probe(pdev, plat_data);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
if (IS_ERR(hdmi->dw_hdmi))
|
||||
return PTR_ERR(hdmi->dw_hdmi);
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
|
|
@ -145,9 +145,9 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev)
|
|||
|
||||
static void th1520_dw_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
struct th1520_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
|
||||
dw_hdmi_remove(hdmi);
|
||||
dw_hdmi_remove(hdmi->dw_hdmi);
|
||||
}
|
||||
|
||||
static const struct of_device_id th1520_dw_hdmi_of_table[] = {
|
||||
|
|
|
|||
|
|
@ -4634,7 +4634,9 @@ static int dp_aux_backlight_update_status(struct backlight_device *bd)
|
|||
|
||||
if (!backlight_is_blank(bd)) {
|
||||
if (!bl->enabled) {
|
||||
drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
|
||||
ret = drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
|
||||
if (ret)
|
||||
return ret;
|
||||
bl->enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,8 +454,10 @@ void drm_bridge_add(struct drm_bridge *bridge)
|
|||
* in bridge_lingering_list. Remove it or bridge_lingering_list will be
|
||||
* corrupted when adding this bridge to bridge_list below.
|
||||
*/
|
||||
mutex_lock(&bridge_lock);
|
||||
if (!list_empty(&bridge->list))
|
||||
list_del_init(&bridge->list);
|
||||
mutex_unlock(&bridge_lock);
|
||||
|
||||
mutex_init(&bridge->hpd_state_mutex);
|
||||
mutex_init(&bridge->hpd_mutex);
|
||||
|
|
@ -593,8 +595,10 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
|||
if (!bridge->container)
|
||||
DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n");
|
||||
|
||||
if (list_empty(&bridge->list))
|
||||
DRM_WARN("Missing drm_bridge_add() before attach\n");
|
||||
scoped_guard(mutex, &bridge_lock) {
|
||||
if (list_empty(&bridge->list))
|
||||
DRM_WARN("Missing drm_bridge_add() before attach\n");
|
||||
}
|
||||
|
||||
drm_bridge_get(bridge);
|
||||
|
||||
|
|
|
|||
|
|
@ -1724,10 +1724,10 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper)
|
|||
|
||||
ret = drm_fb_helper_single_fb_probe(fb_helper);
|
||||
if (ret < 0) {
|
||||
if (ret == -EAGAIN) {
|
||||
fb_helper->deferred_setup = true;
|
||||
/* modesets are probed but fb_helper->fb isn't; defer restore too */
|
||||
fb_helper->deferred_setup = true;
|
||||
if (ret == -EAGAIN)
|
||||
ret = 0;
|
||||
}
|
||||
mutex_unlock(&fb_helper->lock);
|
||||
|
||||
goto err_drm_fb_helper_release_info;
|
||||
|
|
|
|||
|
|
@ -507,6 +507,7 @@ int gud_plane_atomic_check(struct drm_plane *plane,
|
|||
for_each_new_connector_in_state(state, connector, connector_state, i) {
|
||||
if (connector_state->crtc)
|
||||
break;
|
||||
connector_state = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1766,6 +1766,7 @@ static int eb_reinit_userptr(struct i915_execbuffer *eb)
|
|||
|
||||
static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb)
|
||||
{
|
||||
const unsigned int count = eb->buffer_count;
|
||||
bool have_copy = false;
|
||||
struct eb_vma *ev;
|
||||
int err = 0;
|
||||
|
|
@ -1868,7 +1869,6 @@ static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb)
|
|||
|
||||
out:
|
||||
if (have_copy) {
|
||||
const unsigned int count = eb->buffer_count;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
|
|
|
|||
|
|
@ -1904,7 +1904,8 @@ static void rps_work(struct work_struct *work)
|
|||
|
||||
out:
|
||||
spin_lock_irq(gt->irq_lock);
|
||||
gen6_gt_pm_unmask_irq(gt, rps->pm_events);
|
||||
if (intel_rps_is_active(rps))
|
||||
gen6_gt_pm_unmask_irq(gt, rps->pm_events);
|
||||
spin_unlock_irq(gt->irq_lock);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2337,7 +2337,7 @@ void pvr_mmu_op_context_destroy(struct pvr_mmu_op_context *op_ctx)
|
|||
* @ctx: MMU context associated with owning VM context.
|
||||
* @sgt: Scatter gather table containing pages pinned for use by this context.
|
||||
* @device_addr: Virtual device address at the start of the requested mapping.
|
||||
* @sgt_offset: Start offset of the requested device-virtual memory mapping.
|
||||
* @sgt_offset: Offset into @sgt of the start of the requested mapping.
|
||||
* @size: Size in bytes of the requested device-virtual memory mapping. For an
|
||||
* unmapping, this should be zero so that no page tables are allocated.
|
||||
*
|
||||
|
|
@ -2350,7 +2350,6 @@ struct pvr_mmu_op_context *
|
|||
pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt,
|
||||
u64 device_addr, u64 sgt_offset, u64 size)
|
||||
{
|
||||
u64 start_addr = device_addr + sgt_offset;
|
||||
int err;
|
||||
|
||||
struct pvr_mmu_op_context *op_ctx = kzalloc_obj(*op_ctx);
|
||||
|
|
@ -2365,18 +2364,18 @@ pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt,
|
|||
|
||||
if (size) {
|
||||
/*
|
||||
* The number of page table objects we need to prealloc is
|
||||
* indicated by the mapping size, start address and the sizes
|
||||
* of the areas mapped per PT or PD. The range calculation is
|
||||
* identical to that for the index into a table for a device
|
||||
* address, so we reuse those functions here.
|
||||
* The page tables needed are set by the device-virtual range
|
||||
* being mapped: one level 1 table per 1GiB region and one
|
||||
* level 0 table per 2MiB region the range touches. Tables that
|
||||
* already exist are not consumed, so this is an upper bound.
|
||||
*/
|
||||
const u32 l1_start_idx = pvr_page_table_l2_idx(start_addr);
|
||||
const u32 l1_end_idx = pvr_page_table_l2_idx(start_addr + size);
|
||||
const u32 l1_count = l1_end_idx - l1_start_idx + 1;
|
||||
const u32 l0_start_idx = pvr_page_table_l1_idx(start_addr);
|
||||
const u32 l0_end_idx = pvr_page_table_l1_idx(start_addr + size);
|
||||
const u32 l0_count = l0_end_idx - l0_start_idx + 1;
|
||||
const u64 last_addr = device_addr + size - 1;
|
||||
const u64 l1_count =
|
||||
(last_addr >> ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT) -
|
||||
(device_addr >> ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT) + 1;
|
||||
const u64 l0_count =
|
||||
(last_addr >> ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT) -
|
||||
(device_addr >> ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT) + 1;
|
||||
|
||||
/*
|
||||
* Alloc and push page table entries until we have enough of
|
||||
|
|
|
|||
|
|
@ -418,6 +418,8 @@ pvr_vm_gpuva_unmap(struct drm_gpuva_op *op, void *op_ctx)
|
|||
static int
|
||||
pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx)
|
||||
{
|
||||
/* The split parts belong to the object of the mapping being split. */
|
||||
struct drm_gpuvm_bo *vm_bo = op->remap.unmap->va->vm_bo;
|
||||
struct pvr_vm_bind_op *ctx = op_ctx;
|
||||
u64 va_start = 0, va_range = 0;
|
||||
int err;
|
||||
|
|
@ -433,14 +435,12 @@ pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx)
|
|||
drm_gpuva_remap(&ctx->prev_va->base, &ctx->next_va->base, &op->remap);
|
||||
|
||||
if (op->remap.prev) {
|
||||
pvr_gem_object_get(gem_to_pvr_gem(ctx->prev_va->base.gem.obj));
|
||||
drm_gpuva_link(&ctx->prev_va->base, ctx->gpuvm_bo);
|
||||
drm_gpuva_link(&ctx->prev_va->base, vm_bo);
|
||||
ctx->prev_va = NULL;
|
||||
}
|
||||
|
||||
if (op->remap.next) {
|
||||
pvr_gem_object_get(gem_to_pvr_gem(ctx->next_va->base.gem.obj));
|
||||
drm_gpuva_link(&ctx->next_va->base, ctx->gpuvm_bo);
|
||||
drm_gpuva_link(&ctx->next_va->base, vm_bo);
|
||||
ctx->next_va = NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
|
|||
goto done;
|
||||
break;
|
||||
case NV_DEVICE_INFO_V0_TURING:
|
||||
if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC) {
|
||||
if (engine == NV_DEVICE_HOST_RUNLIST_ENGINES_GR) {
|
||||
ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar",
|
||||
0, TURING_DMA_COPY_A, NULL, 0,
|
||||
&chan->ce);
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ nvkm_udevice_gcx_ready(struct nvkm_udevice *udev, void *data, u32 size)
|
|||
} *args = data;
|
||||
int ret = -ENOSYS;
|
||||
|
||||
if (!gsp) {
|
||||
if (!gsp || !gsp->rm) {
|
||||
args->v0.ready = NV_DEVICE_GC6_READY | NV_DEVICE_GCOFF_READY;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3674,6 +3674,9 @@ int panthor_group_create(struct panthor_file *pfile,
|
|||
hweight64(group_args->tiler_core_mask) < group_args->max_tiler_cores)
|
||||
return -EINVAL;
|
||||
|
||||
if (group_args->queues.count > sched->cs_slot_count)
|
||||
return -EINVAL;
|
||||
|
||||
group = kzalloc_obj(*group);
|
||||
if (!group)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
|
|||
struct list_head *new_list;
|
||||
uint32_t i;
|
||||
|
||||
new_list = kmalloc_objs(struct list_head, new_size);
|
||||
new_list = kvmalloc_objs(struct list_head, new_size);
|
||||
if (!new_list)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
|
|||
for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
|
||||
INIT_LIST_HEAD(&new_list[i]);
|
||||
|
||||
kfree(vc4->bo_cache.size_list);
|
||||
kvfree(vc4->bo_cache.size_list);
|
||||
vc4->bo_cache.size_list = new_list;
|
||||
vc4->bo_cache.size_list_size = new_size;
|
||||
}
|
||||
|
|
@ -1052,6 +1052,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
|
|||
cancel_work_sync(&vc4->bo_cache.time_work);
|
||||
|
||||
vc4_bo_cache_purge(dev);
|
||||
kvfree(vc4->bo_cache.size_list);
|
||||
|
||||
for (i = 0; i < vc4->num_labels; i++) {
|
||||
if (vc4->bo_labels[i].num_allocated) {
|
||||
|
|
|
|||
|
|
@ -360,8 +360,11 @@ static int vc4_drm_bind(struct device *dev)
|
|||
}
|
||||
|
||||
ret = aperture_remove_all_conflicting_devices(driver->name);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (firmware)
|
||||
rpi_firmware_put(firmware);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (firmware) {
|
||||
ret = rpi_firmware_property(firmware,
|
||||
|
|
|
|||
|
|
@ -1051,7 +1051,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
|
|||
/* vc4_v3d.c */
|
||||
extern struct platform_driver vc4_v3d_driver;
|
||||
extern const struct of_device_id vc4_v3d_dt_match[];
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4);
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, long timeout);
|
||||
int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used);
|
||||
void vc4_v3d_bin_bo_put(struct vc4_dev *vc4);
|
||||
int vc4_v3d_pm_get(struct vc4_dev *vc4);
|
||||
|
|
|
|||
|
|
@ -877,11 +877,17 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
|
|||
drm_gem_object_put(&bo->base.base);
|
||||
}
|
||||
|
||||
/* Free up the allocation of any bin slots we used. */
|
||||
/* Free up the allocation of any bin slots we used. Jobs that ran to
|
||||
* completion had their slots released in vc4_irq_finish_render_job().
|
||||
* Only jobs that never completed still have slots to be released here.
|
||||
*/
|
||||
spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
vc4->bin_alloc_used &= ~exec->bin_slots;
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
|
||||
/* Let anyone waiting on the binner pool retry. */
|
||||
wake_up_all(&vc4->job_wait_queue);
|
||||
|
||||
/* Release the reference on the binner BO if needed. */
|
||||
if (exec->bin_bo_used)
|
||||
vc4_v3d_bin_bo_put(vc4);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ vc4_overflow_mem_work(struct work_struct *work)
|
|||
|
||||
bo = vc4->bin_bo;
|
||||
|
||||
bin_bo_slot = vc4_v3d_get_bin_slot(vc4);
|
||||
bin_bo_slot = vc4_v3d_get_bin_slot(vc4, msecs_to_jiffies(500));
|
||||
if (bin_bo_slot < 0) {
|
||||
drm_err(&vc4->base, "Couldn't allocate binner overflow mem\n");
|
||||
goto complete;
|
||||
|
|
@ -165,6 +165,10 @@ vc4_irq_finish_render_job(struct drm_device *dev)
|
|||
trace_vc4_rcl_end_irq(dev, exec->seqno);
|
||||
|
||||
vc4->finished_seqno++;
|
||||
|
||||
vc4->bin_alloc_used &= ~exec->bin_slots;
|
||||
exec->bin_slots = 0;
|
||||
|
||||
list_move_tail(&exec->head, &vc4->job_done_list);
|
||||
|
||||
nextbin = vc4_first_bin_job(vc4);
|
||||
|
|
@ -276,7 +280,7 @@ vc4_irq_disable(struct drm_device *dev)
|
|||
V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
|
||||
|
||||
/* Finish any interrupt handler still in flight. */
|
||||
synchronize_irq(vc4->irq);
|
||||
disable_irq(vc4->irq);
|
||||
|
||||
cancel_work_sync(&vc4->overflow_mem_work);
|
||||
}
|
||||
|
|
@ -284,7 +288,6 @@ vc4_irq_disable(struct drm_device *dev)
|
|||
int vc4_irq_install(struct drm_device *dev, int irq)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
int ret;
|
||||
|
||||
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
|
||||
return -ENODEV;
|
||||
|
|
@ -298,19 +301,8 @@ int vc4_irq_install(struct drm_device *dev, int irq)
|
|||
init_waitqueue_head(&vc4->job_wait_queue);
|
||||
INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
|
||||
|
||||
/* Clear any pending interrupts someone might have left around
|
||||
* for us.
|
||||
*/
|
||||
V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
|
||||
|
||||
ret = devm_request_irq(dev->dev, irq, vc4_irq, 0,
|
||||
dev_name(dev->dev), dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vc4_irq_enable(dev);
|
||||
|
||||
return 0;
|
||||
return devm_request_irq(dev->dev, irq, vc4_irq, IRQF_NO_AUTOEN,
|
||||
dev_name(dev->dev), dev);
|
||||
}
|
||||
|
||||
void vc4_irq_uninstall(struct drm_device *dev)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/component.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
|
|
@ -172,46 +173,42 @@ static void vc4_v3d_init_hw(struct drm_device *dev)
|
|||
V3D_WRITE(V3D_VPMBASE, 0);
|
||||
}
|
||||
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4)
|
||||
static int bin_slot_try_alloc(struct vc4_dev *vc4)
|
||||
{
|
||||
struct drm_device *dev = &vc4->base;
|
||||
unsigned long irqflags;
|
||||
int slot;
|
||||
uint64_t seqno = 0;
|
||||
struct vc4_exec_info *exec;
|
||||
|
||||
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
|
||||
return -ENODEV;
|
||||
guard(spinlock_irqsave)(&vc4->job_lock);
|
||||
|
||||
try_again:
|
||||
spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
slot = ffs(~vc4->bin_alloc_used);
|
||||
if (slot != 0) {
|
||||
/* Switch from ffs() bit index to a 0-based index. */
|
||||
slot--;
|
||||
vc4->bin_alloc_used |= BIT(slot);
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
return slot;
|
||||
} else {
|
||||
slot = -ENOMEM;
|
||||
}
|
||||
|
||||
/* Couldn't find an open slot. Wait for render to complete
|
||||
* and try again.
|
||||
*/
|
||||
exec = vc4_last_render_job(vc4);
|
||||
if (exec)
|
||||
seqno = exec->seqno;
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
return slot;
|
||||
}
|
||||
|
||||
if (seqno) {
|
||||
int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true);
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, long timeout)
|
||||
{
|
||||
int slot;
|
||||
long ret;
|
||||
|
||||
if (ret == 0)
|
||||
goto try_again;
|
||||
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
|
||||
return -ENODEV;
|
||||
|
||||
/* If the pool is full, wait for a job to release its slots. */
|
||||
ret = wait_event_interruptible_timeout(vc4->job_wait_queue,
|
||||
(slot = bin_slot_try_alloc(vc4)) >= 0,
|
||||
timeout);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return -ENOMEM;
|
||||
return slot;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -396,6 +393,7 @@ static int vc4_v3d_runtime_resume(struct device *dev)
|
|||
vc4_v3d_init_hw(&vc4->base);
|
||||
|
||||
vc4_irq_enable(&vc4->base);
|
||||
enable_irq(vc4->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -452,6 +450,12 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
|
|||
return ret;
|
||||
vc4->irq = ret;
|
||||
|
||||
ret = vc4_irq_install(drm, vc4->irq);
|
||||
if (ret) {
|
||||
drm_err(drm, "Failed to install IRQ handler\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -473,12 +477,6 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
|
|||
V3D_WRITE(V3D_BPOA, 0);
|
||||
V3D_WRITE(V3D_BPOS, 0);
|
||||
|
||||
ret = vc4_irq_install(drm, vc4->irq);
|
||||
if (ret) {
|
||||
drm_err(drm, "Failed to install IRQ handler\n");
|
||||
goto err_put_runtime_pm;
|
||||
}
|
||||
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
|
@ -497,8 +495,15 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
|
|||
struct drm_device *drm = data;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(drm);
|
||||
|
||||
/* A straggler vc4_reset() re-enables the interrupt. */
|
||||
timer_shutdown_sync(&vc4->hangcheck.timer);
|
||||
cancel_work_sync(&vc4->hangcheck.reset_work);
|
||||
|
||||
vc4_irq_uninstall(drm);
|
||||
|
||||
/* Flush rather than cancel, so queued completions release their jobs. */
|
||||
flush_work(&vc4->job_done_work);
|
||||
|
||||
/* Disable the binner's overflow memory address, so the next
|
||||
* driver probe (if any) doesn't try to reuse our old
|
||||
* allocation.
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ validate_tile_binning_config(VALIDATE_ARGS)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
bin_slot = vc4_v3d_get_bin_slot(vc4);
|
||||
bin_slot = vc4_v3d_get_bin_slot(vc4, MAX_SCHEDULE_TIMEOUT);
|
||||
if (bin_slot < 0) {
|
||||
if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {
|
||||
drm_err(dev, "Failed to allocate binner memory: %d\n",
|
||||
|
|
|
|||
|
|
@ -324,6 +324,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
unsigned long kmap_num;
|
||||
SVGA3dCopyBox *box;
|
||||
u32 box_count;
|
||||
u64 src_extent;
|
||||
void *virtual;
|
||||
bool is_iomem;
|
||||
struct vmw_dma_cmd {
|
||||
|
|
@ -335,6 +336,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT);
|
||||
const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock;
|
||||
|
||||
BUILD_BUG_ON(sizeof(*srf->snooper.image) != desc->pitchBytesPerBlock);
|
||||
|
||||
cmd = container_of(header, struct vmw_dma_cmd, header);
|
||||
|
||||
/* No snooper installed, nothing to copy */
|
||||
|
|
@ -372,8 +375,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
return;
|
||||
}
|
||||
|
||||
if (box->w == 0 || box->h == 0)
|
||||
return;
|
||||
|
||||
src_extent = (u64)(box->h - 1) * cmd->dma.guest.pitch +
|
||||
(u64)box->w * desc->pitchBytesPerBlock;
|
||||
if (src_extent > bo->base.size) {
|
||||
DRM_ERROR("Cursor snoop source of %llu bytes exceeds the %zu byte buffer\n",
|
||||
src_extent, bo->base.size);
|
||||
return;
|
||||
}
|
||||
|
||||
kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT;
|
||||
kmap_num = (VMW_CURSOR_SNOOP_HEIGHT * image_pitch) >> PAGE_SHIFT;
|
||||
kmap_num = PFN_UP(src_extent);
|
||||
|
||||
ret = ttm_bo_reserve(bo, true, false, NULL);
|
||||
if (unlikely(ret != 0)) {
|
||||
|
|
@ -387,14 +401,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
|
||||
virtual = ttm_kmap_obj_virtual(&map, &is_iomem);
|
||||
|
||||
if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) {
|
||||
if (box->w == VMW_CURSOR_SNOOP_WIDTH &&
|
||||
box->h == VMW_CURSOR_SNOOP_HEIGHT &&
|
||||
cmd->dma.guest.pitch == image_pitch) {
|
||||
memcpy(srf->snooper.image, virtual,
|
||||
VMW_CURSOR_SNOOP_HEIGHT * image_pitch);
|
||||
} else {
|
||||
/* Image is unsigned pointer. */
|
||||
/* The destination stride is in pixels. */
|
||||
for (i = 0; i < box->h; i++)
|
||||
memcpy(srf->snooper.image + i * image_pitch,
|
||||
virtual + i * cmd->dma.guest.pitch,
|
||||
memcpy(srf->snooper.image + i * VMW_CURSOR_SNOOP_WIDTH,
|
||||
virtual + (size_t)i * cmd->dma.guest.pitch,
|
||||
box->w * desc->pitchBytesPerBlock);
|
||||
}
|
||||
srf->snooper.id++;
|
||||
|
|
|
|||
|
|
@ -20,10 +20,18 @@
|
|||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_sysfs.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_blend.h>
|
||||
|
||||
void vmw_du_init(struct vmw_display_unit *du)
|
||||
{
|
||||
vmw_vkms_crtc_init(&du->crtc);
|
||||
drm_plane_create_blend_mode_property(&du->primary,
|
||||
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
|
||||
BIT(DRM_MODE_BLEND_PREMULTI));
|
||||
// Check that the cursor plane was actually initialized
|
||||
if (du->crtc.cursor == &du->cursor.base)
|
||||
drm_plane_create_blend_mode_property(&du->cursor.base,
|
||||
BIT(DRM_MODE_BLEND_PREMULTI));
|
||||
}
|
||||
|
||||
void vmw_du_cleanup(struct vmw_display_unit *du)
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt,
|
|||
drm_exec_retry_on_contention(&exec);
|
||||
xe_validation_retry_on_oom(&ctx, &ret);
|
||||
if (!ret)
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
xe_bo_pin_account(bo);
|
||||
}
|
||||
if (ret)
|
||||
goto err;
|
||||
|
|
@ -373,7 +373,7 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt,
|
|||
|
||||
err_unpin:
|
||||
ttm_bo_reserve(&bo->ttm, false, false, NULL);
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
xe_bo_unpin_account(bo);
|
||||
ttm_bo_unreserve(&bo->ttm);
|
||||
err:
|
||||
kfree(vma);
|
||||
|
|
@ -393,7 +393,7 @@ static void __xe_unpin_fb_vma(struct i915_vma *vma)
|
|||
xe_ggtt_node_remove(vma->node, false);
|
||||
|
||||
ttm_bo_reserve(&vma->bo->ttm, false, false, NULL);
|
||||
ttm_bo_unpin(&vma->bo->ttm);
|
||||
xe_bo_unpin_account(vma->bo);
|
||||
ttm_bo_unreserve(&vma->bo->ttm);
|
||||
kfree(vma);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -455,6 +455,100 @@ static void xe_ttm_tt_account_subtract(struct xe_device *xe, struct ttm_tt *tt)
|
|||
xe_shrinker_mod_pages(xe->mem.shrinker, -(long)tt->num_pages, 0);
|
||||
}
|
||||
|
||||
static bool xe_ttm_bo_is_imported(struct ttm_buffer_object *tbo)
|
||||
{
|
||||
dma_resv_assert_held(tbo->base.resv);
|
||||
|
||||
return tbo->ttm &&
|
||||
(tbo->ttm->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_EXTERNAL_MAPPABLE)) ==
|
||||
TTM_TT_FLAG_EXTERNAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Account @bo's pages as pinned for the shrinker. Removes @bo's pages
|
||||
* from the shrinker's shrinkable / purgeable counts on the transition
|
||||
* from unpinned to pinned. Must be called with @bo's dma-resv held,
|
||||
* after &ttm_buffer_object.pin_count has been incremented by
|
||||
* ttm_bo_pin(). Safe to call unconditionally regardless of which pin
|
||||
* path (kernel, external, framebuffer, backup object, ...) is pinning
|
||||
* @bo, since it only acts on the true 0->1 pin_count transition.
|
||||
*
|
||||
* Imported bos (xe_ttm_bo_is_imported()) are excluded: for those,
|
||||
* xe_ttm_tt_populate() never actually populates the tt or calls
|
||||
* xe_ttm_tt_account_add(), but TTM core's ttm_tt_populate() still
|
||||
* unconditionally marks the tt as populated on driver-hook success.
|
||||
* Relying on ttm_tt_is_populated() for these would subtract pages that
|
||||
* were never added, underflowing the shrinker's counts.
|
||||
*/
|
||||
static void xe_bo_account_pin(struct xe_bo *bo)
|
||||
{
|
||||
struct xe_device *xe = xe_bo_device(bo);
|
||||
|
||||
if (bo->ttm.pin_count == 1 && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm) &&
|
||||
!xe_ttm_bo_is_imported(&bo->ttm))
|
||||
xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Counterpart to xe_bo_account_pin(). Must be called with @bo's dma-resv
|
||||
* held, before &ttm_buffer_object.pin_count is decremented by
|
||||
* ttm_bo_unpin(), so that the check against the true 1->0 transition sees
|
||||
* the pin count that is about to be released. See xe_bo_account_pin() for
|
||||
* why imported bos are excluded.
|
||||
*
|
||||
* On the true last unpin, also removes @bo from whichever pinned-bo list
|
||||
* (external or kernel_bo_present) it may currently be linked on, since a
|
||||
* bo's final unpin can happen through a pin path (e.g. framebuffer,
|
||||
* backup object) that has no notion of, or ownership over, that list.
|
||||
* This is safe and list-agnostic: list_del_init() only needs the node
|
||||
* itself, not knowledge of which list it is threaded through, and is a
|
||||
* no-op if @bo is not linked.
|
||||
*/
|
||||
static void xe_bo_account_unpin(struct xe_bo *bo)
|
||||
{
|
||||
struct xe_device *xe = xe_bo_device(bo);
|
||||
bool last_unpin = bo->ttm.pin_count == 1;
|
||||
|
||||
if (last_unpin && !list_empty(&bo->pinned_link)) {
|
||||
spin_lock(&xe->pinned.lock);
|
||||
list_del_init(&bo->pinned_link);
|
||||
spin_unlock(&xe->pinned.lock);
|
||||
}
|
||||
|
||||
if (last_unpin && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm) &&
|
||||
!xe_ttm_bo_is_imported(&bo->ttm))
|
||||
xe_ttm_tt_account_add(xe, bo->ttm.ttm);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_bo_pin_account() - Pin a bo and account its pages for the shrinker
|
||||
* @bo: The buffer object to pin.
|
||||
*
|
||||
* Pins @bo via ttm_bo_pin() and updates the shrinker's shrinkable /
|
||||
* purgeable page accounting to match. Must be called with @bo's dma-resv
|
||||
* held. Safe to call regardless of which pin path (kernel, external,
|
||||
* framebuffer, backup object, ...) is pinning @bo.
|
||||
*/
|
||||
void xe_bo_pin_account(struct xe_bo *bo)
|
||||
{
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
xe_bo_account_pin(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_bo_unpin_account() - Unpin a bo and account its pages for the shrinker
|
||||
* @bo: The buffer object to unpin.
|
||||
*
|
||||
* Counterpart to xe_bo_pin_account(). Updates the shrinker's shrinkable /
|
||||
* purgeable page accounting to match, then unpins @bo via ttm_bo_unpin().
|
||||
* Must be called with @bo's dma-resv held.
|
||||
*/
|
||||
void xe_bo_unpin_account(struct xe_bo *bo)
|
||||
{
|
||||
xe_bo_account_unpin(bo);
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
}
|
||||
|
||||
static void update_global_total_pages(struct ttm_device *ttm_dev,
|
||||
long num_pages)
|
||||
{
|
||||
|
|
@ -1389,7 +1483,8 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
|
|||
}
|
||||
|
||||
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
|
||||
ttm_bo_pin(&backup->ttm);
|
||||
/* Note: XE_BO_FLAG_SYSTEM resolves to XE_PL_TT so already populated. */
|
||||
xe_bo_pin_account(backup);
|
||||
bo->backup_obj = backup;
|
||||
}
|
||||
|
||||
|
|
@ -1409,7 +1504,7 @@ int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
|
|||
{
|
||||
xe_bo_lock(bo, false);
|
||||
if (bo->backup_obj) {
|
||||
ttm_bo_unpin(&bo->backup_obj->ttm);
|
||||
xe_bo_unpin_account(bo->backup_obj);
|
||||
xe_bo_put(bo->backup_obj);
|
||||
bo->backup_obj = NULL;
|
||||
}
|
||||
|
|
@ -1620,7 +1715,7 @@ int xe_bo_restore_pinned(struct xe_bo *bo)
|
|||
xe_bo_vunmap(backup);
|
||||
if (!bo->backup_obj) {
|
||||
if (xe_bo_is_pinned(backup))
|
||||
ttm_bo_unpin(&backup->ttm);
|
||||
xe_bo_unpin_account(backup);
|
||||
xe_bo_put(backup);
|
||||
}
|
||||
out_unlock_bo:
|
||||
|
|
@ -2012,15 +2107,6 @@ static vm_fault_t xe_err_to_fault_t(int err)
|
|||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
static bool xe_ttm_bo_is_imported(struct ttm_buffer_object *tbo)
|
||||
{
|
||||
dma_resv_assert_held(tbo->base.resv);
|
||||
|
||||
return tbo->ttm &&
|
||||
(tbo->ttm->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_EXTERNAL_MAPPABLE)) ==
|
||||
TTM_TT_FLAG_EXTERNAL;
|
||||
}
|
||||
|
||||
static vm_fault_t xe_bo_cpu_fault_fastpath(struct vm_fault *vmf, struct xe_device *xe,
|
||||
struct xe_bo *bo, bool needs_rpm)
|
||||
{
|
||||
|
|
@ -3141,12 +3227,13 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
|
|||
int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
|
||||
{
|
||||
struct xe_device *xe = xe_bo_device(bo);
|
||||
bool first_pin = !xe_bo_is_pinned(bo);
|
||||
int err;
|
||||
|
||||
xe_assert(xe, !bo->vm);
|
||||
xe_assert(xe, xe_bo_is_user(bo));
|
||||
|
||||
if (!xe_bo_is_pinned(bo)) {
|
||||
if (first_pin) {
|
||||
if (!in_place) {
|
||||
err = xe_bo_validate(bo, NULL, false, exec);
|
||||
if (err)
|
||||
|
|
@ -3158,9 +3245,7 @@ int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
|
|||
spin_unlock(&xe->pinned.lock);
|
||||
}
|
||||
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
|
||||
xe_bo_pin_account(bo);
|
||||
|
||||
/*
|
||||
* FIXME: If we always use the reserve / unreserve functions for locking
|
||||
|
|
@ -3216,9 +3301,7 @@ int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec)
|
|||
spin_unlock(&xe->pinned.lock);
|
||||
}
|
||||
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
|
||||
xe_bo_pin_account(bo);
|
||||
|
||||
/*
|
||||
* FIXME: If we always use the reserve / unreserve functions for locking
|
||||
|
|
@ -3247,14 +3330,7 @@ void xe_bo_unpin_external(struct xe_bo *bo)
|
|||
xe_assert(xe, xe_bo_is_pinned(bo));
|
||||
xe_assert(xe, xe_bo_is_user(bo));
|
||||
|
||||
spin_lock(&xe->pinned.lock);
|
||||
if (bo->ttm.pin_count == 1 && !list_empty(&bo->pinned_link))
|
||||
list_del_init(&bo->pinned_link);
|
||||
spin_unlock(&xe->pinned.lock);
|
||||
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_add(xe, bo->ttm.ttm);
|
||||
xe_bo_unpin_account(bo);
|
||||
|
||||
/*
|
||||
* FIXME: If we always use the reserve / unreserve functions for locking
|
||||
|
|
@ -3272,21 +3348,16 @@ void xe_bo_unpin(struct xe_bo *bo)
|
|||
xe_assert(xe, xe_bo_is_pinned(bo));
|
||||
|
||||
if (mem_type_is_vram(place->mem_type) || bo->flags & XE_BO_FLAG_GGTT) {
|
||||
spin_lock(&xe->pinned.lock);
|
||||
xe_assert(xe, !list_empty(&bo->pinned_link));
|
||||
list_del_init(&bo->pinned_link);
|
||||
spin_unlock(&xe->pinned.lock);
|
||||
|
||||
if (bo->backup_obj) {
|
||||
if (xe_bo_is_pinned(bo->backup_obj))
|
||||
ttm_bo_unpin(&bo->backup_obj->ttm);
|
||||
xe_bo_unpin_account(bo->backup_obj);
|
||||
xe_bo_put(bo->backup_obj);
|
||||
bo->backup_obj = NULL;
|
||||
}
|
||||
}
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_add(xe, bo->ttm.ttm);
|
||||
xe_bo_unpin_account(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -229,6 +229,8 @@ int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec);
|
|||
int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec);
|
||||
void xe_bo_unpin_external(struct xe_bo *bo);
|
||||
void xe_bo_unpin(struct xe_bo *bo);
|
||||
void xe_bo_pin_account(struct xe_bo *bo);
|
||||
void xe_bo_unpin_account(struct xe_bo *bo);
|
||||
int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
|
||||
struct drm_exec *exec);
|
||||
|
||||
|
|
|
|||
|
|
@ -324,12 +324,15 @@ static void xe_i2c_remove(void *data)
|
|||
xe_i2c_irq_reset(xe);
|
||||
xe_amc_exit(i2c);
|
||||
|
||||
/* Stop the notifier from arming the client work before teardown. */
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
cancel_work_sync(&i2c->work);
|
||||
|
||||
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++) {
|
||||
i2c_unregister_device(i2c->client[i]);
|
||||
i2c->client[i] = NULL;
|
||||
}
|
||||
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
xe_i2c_unregister_adapter(i2c);
|
||||
xe->i2c = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1099,8 +1099,7 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
|
|||
#define CONTEXT_ACTIVE XE_LRC_CTX_TIMESTAMP_ACTIVE
|
||||
static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch,
|
||||
size_t max_len)
|
||||
u32 *batch, size_t max_len, bool indirect)
|
||||
{
|
||||
u32 *cmd = batch;
|
||||
|
||||
|
|
@ -1131,19 +1130,25 @@ static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
|
|||
}
|
||||
|
||||
static ssize_t setup_timestamp_wa(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len, bool indirect)
|
||||
{
|
||||
const u32 ts_addr = __xe_lrc_ctx_timestamp_ggtt_addr(lrc);
|
||||
u32 *cmd = batch;
|
||||
|
||||
if (!XE_GT_WA(lrc->gt, 16010904313) ||
|
||||
!(hwe->class == XE_ENGINE_CLASS_RENDER ||
|
||||
hwe->class == XE_ENGINE_CLASS_COMPUTE ||
|
||||
hwe->class == XE_ENGINE_CLASS_COPY ||
|
||||
if (!XE_GT_WA(lrc->gt, 16010904313))
|
||||
return 0;
|
||||
|
||||
if (!indirect &&
|
||||
!(hwe->class == XE_ENGINE_CLASS_COPY ||
|
||||
hwe->class == XE_ENGINE_CLASS_VIDEO_DECODE ||
|
||||
hwe->class == XE_ENGINE_CLASS_VIDEO_ENHANCE))
|
||||
return 0;
|
||||
|
||||
if (indirect &&
|
||||
!(hwe->class == XE_ENGINE_CLASS_RENDER ||
|
||||
hwe->class == XE_ENGINE_CLASS_COMPUTE))
|
||||
return 0;
|
||||
|
||||
if (xe_gt_WARN_ON(lrc->gt, max_len < 12))
|
||||
return -ENOSPC;
|
||||
|
||||
|
|
@ -1169,7 +1174,8 @@ static ssize_t setup_timestamp_wa(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
|
|||
|
||||
static ssize_t setup_configfs_post_ctx_restore_bb(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(lrc->gt);
|
||||
const u32 *user_batch;
|
||||
|
|
@ -1198,7 +1204,8 @@ static ssize_t setup_configfs_post_ctx_restore_bb(struct xe_lrc *lrc,
|
|||
|
||||
static ssize_t setup_configfs_mid_ctx_restore_bb(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(lrc->gt);
|
||||
const u32 *user_batch;
|
||||
|
|
@ -1227,7 +1234,8 @@ static ssize_t setup_configfs_mid_ctx_restore_bb(struct xe_lrc *lrc,
|
|||
|
||||
static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
u32 *cmd = batch;
|
||||
|
||||
|
|
@ -1247,7 +1255,8 @@ static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,
|
|||
|
||||
static ssize_t setup_invalidate_auxccs_wa(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
struct xe_gt *gt = lrc->gt;
|
||||
u32 *(*emit)(struct xe_gt *gt, u32 *cmd) =
|
||||
|
|
@ -1264,7 +1273,7 @@ static ssize_t setup_invalidate_auxccs_wa(struct xe_lrc *lrc,
|
|||
|
||||
struct bo_setup {
|
||||
ssize_t (*setup)(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_size);
|
||||
u32 *batch, size_t max_size, bool indirect);
|
||||
};
|
||||
|
||||
struct bo_setup_state {
|
||||
|
|
@ -1273,6 +1282,7 @@ struct bo_setup_state {
|
|||
struct xe_hw_engine *hwe;
|
||||
size_t max_size;
|
||||
size_t reserve_dw;
|
||||
bool indirect;
|
||||
unsigned int offset;
|
||||
const struct bo_setup *funcs;
|
||||
unsigned int num_funcs;
|
||||
|
|
@ -1298,7 +1308,8 @@ static int setup_bo(struct bo_setup_state *state)
|
|||
|
||||
for (size_t i = 0; i < state->num_funcs; i++) {
|
||||
ssize_t len = state->funcs[i].setup(state->lrc, state->hwe,
|
||||
state->ptr, remain);
|
||||
state->ptr, remain,
|
||||
state->indirect);
|
||||
|
||||
remain -= len;
|
||||
|
||||
|
|
@ -1404,6 +1415,7 @@ setup_indirect_ctx(struct xe_lrc *lrc, struct xe_hw_engine *hwe)
|
|||
struct bo_setup_state state = {
|
||||
.lrc = lrc,
|
||||
.hwe = hwe,
|
||||
.indirect = true,
|
||||
.max_size = (63 * 64) /* max 63 cachelines */,
|
||||
.buffer = NULL,
|
||||
.offset = __xe_lrc_indirect_ctx_offset(lrc),
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg)
|
|||
return (u64)udw << 32 | ldw;
|
||||
}
|
||||
|
||||
#define __XE_MMIO_WAIT_MAX_BACKOFF_100MS (100 * USEC_PER_MSEC)
|
||||
static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val,
|
||||
u32 timeout_us, u32 *out_val, bool atomic, bool expect_match)
|
||||
{
|
||||
|
|
@ -350,10 +351,10 @@ static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u
|
|||
wait = ktime_us_delta(end, cur);
|
||||
|
||||
if (atomic)
|
||||
udelay(wait);
|
||||
udelay(min_t(s64, wait, (MAX_UDELAY_MS * 1000)));
|
||||
else
|
||||
usleep_range(wait, wait << 1);
|
||||
wait <<= 1;
|
||||
wait = min_t(s64, wait << 1, __XE_MMIO_WAIT_MAX_BACKOFF_100MS);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
|
|
|
|||
|
|
@ -19,20 +19,20 @@
|
|||
#include "xe_sysctrl_mailbox_types.h"
|
||||
|
||||
struct xe_sysctrl_mailbox_msg_hdr {
|
||||
__le32 data;
|
||||
} __packed;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
#define XE_SYSCTRL_HDR_GROUP_ID(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, (hdr)->data)
|
||||
|
||||
#define XE_SYSCTRL_HDR_COMMAND(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, (hdr)->data)
|
||||
|
||||
#define XE_SYSCTRL_HDR_IS_RESPONSE(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, (hdr)->data)
|
||||
|
||||
#define XE_SYSCTRL_HDR_RESULT(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_RESULT_MASK, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_RESULT_MASK, (hdr)->data)
|
||||
|
||||
static bool sysctrl_wait_bit_clear(struct xe_sysctrl *sc, u32 bit_mask,
|
||||
unsigned int timeout_ms)
|
||||
|
|
@ -126,8 +126,8 @@ static int sysctrl_prepare_command(struct xe_device *xe,
|
|||
return -ENOMEM;
|
||||
|
||||
hdr = (struct xe_sysctrl_mailbox_msg_hdr *)buffer;
|
||||
hdr->data = cpu_to_le32(FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) |
|
||||
FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command));
|
||||
hdr->data = FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) |
|
||||
FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command);
|
||||
|
||||
if (data_in && data_in_len)
|
||||
memcpy(buffer + sizeof(*hdr), data_in, data_in_len);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user