mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
Merge tag 'drm-fixes-2026-07-10' of https://gitlab.freedesktop.org/drm/kernel
Pull drm fixes from Dave Airlie: "Weekly fixes pull for drm, amdgpu, amdxdna, xe leading the way, some small core fixes and a nouveau stability fix along with some minor changes in other drivers. Seems to be a bit quiter than last week at least. fb-helper: - Sync on first active crtc in fb_dirty, rather than first crtc drm_exec: - Use direct label in drm_exec buddy: - Rework try_harder in the buddy allocator i915: - fix underrun on panthor lake - LT PHY SSC programming fix - fix some NULL derefs and leaks nouveau: - fix a vmm large/small page table update race xe: - Fix PTE index in xe_vm_populate_pgtable for chunked binds - Wait on external BO kernel fences in exec IOCTL - Remove duplicate include - Free madvise VMA array on L2 flush failure - Stub notifier_lock helpers when DRM_GPUSVM=n amdgpu: - PSP 15.0.9 update - SMU 15.0.9 update - VCN 5.3 fix - VI ASPM fix - Userq fix - lifetime fix for amdgpu_vm_get_task_info_pasid() - Gfx10 fix - SMU 14 fix amdkfd: - CRIU bounds checking fixes - secondary context id fix - Event bounds checking fix amdxdna: - Fix uaf in mmap failure path - A lot of deadlocks, access races and return value fixes analogix_dp: - Fix analogix_dp bitshifts during link training v3d: - Fix absent indirect bo handling imagination: - Make function static to solve compiler warning - Fix error checking" * tag 'drm-fixes-2026-07-10' of https://gitlab.freedesktop.org/drm/kernel: (44 commits) nouveau/vmm: fix another SPT/LPT race drm/imagination: fix error checking of pvr_vm_context_lookup() drm/imagination: make pvr_fw_trace_init_mask_ops static gpu/buddy: bail out of try_harder when alignment cannot be honoured drm/xe/userptr: Stub notifier_lock helpers when DRM_GPUSVM=n drm/xe: free madvise VMA array on L2 flush failure drm/xe: remove duplicate <kunit/test-bug.h> include drm/xe: Wait on external BO kernel fences in exec IOCTL drm/xe: Fix PTE index in xe_vm_populate_pgtable() for chunked binds drm/fb-helper: Only consider active CRTCs for vblank sync drm/amdkfd: Check bounds on CRIU restore queue type and mqd size drm/amd/pm: fix smu14 power limit range calculation drm/amdkfd: Check bounds in allocate_event_notification_slot amdkfd: properly free secondary context id drm/amdkfd: Don't acquire buffers during CRIU queue restore drm/amdkfd: Check bounds on CRIU restore event id drm/gfx10: Program DB_RING_CONTROL drm/amdgpu: fix lifetime issue of amdgpu_vm_get_task_info_pasid() drm/amdgpu: trigger GPU recovery when userq destroy fails to unmap a hung queue drm/amd/amdgpu: disable ASPM on VI if pcie dpm is disabled ...
This commit is contained in:
@@ -875,7 +875,7 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size
|
||||
if (!hwctx->cus)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = amdxdna_pm_resume_get_locked(xdna);
|
||||
ret = amdxdna_pm_resume_get(xdna);
|
||||
if (ret)
|
||||
goto free_cus;
|
||||
|
||||
@@ -900,13 +900,16 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size
|
||||
static void aie2_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq)
|
||||
{
|
||||
struct dma_fence *out_fence = aie2_cmd_get_out_fence(hwctx, seq);
|
||||
struct amdxdna_dev *xdna = hwctx->client->xdna;
|
||||
|
||||
if (!out_fence) {
|
||||
XDNA_ERR(hwctx->client->xdna, "Failed to get fence");
|
||||
XDNA_ERR(xdna, "Failed to get fence");
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
dma_fence_wait_timeout(out_fence, false, MAX_SCHEDULE_TIMEOUT);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
dma_fence_put(out_fence);
|
||||
}
|
||||
|
||||
@@ -1039,7 +1042,7 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo)
|
||||
found = false;
|
||||
down_write(&xdna->notifier_lock);
|
||||
list_for_each_entry(mapp, &abo->mem.umap_list, node) {
|
||||
if (mapp->invalid) {
|
||||
if (mapp->invalid && kref_get_unless_zero(&mapp->refcnt)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -1050,11 +1053,9 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo)
|
||||
up_write(&xdna->notifier_lock);
|
||||
return 0;
|
||||
}
|
||||
kref_get(&mapp->refcnt);
|
||||
|
||||
up_write(&xdna->notifier_lock);
|
||||
|
||||
XDNA_DBG(xdna, "populate memory range %lx %lx",
|
||||
mapp->vma->vm_start, mapp->vma->vm_end);
|
||||
mm = mapp->notifier.mm;
|
||||
if (!mmget_not_zero(mm)) {
|
||||
amdxdna_umap_put(mapp);
|
||||
@@ -1221,10 +1222,6 @@ int aie2_hwctx_heap_expand(struct amdxdna_hwctx *hwctx,
|
||||
u64 addr;
|
||||
int ret;
|
||||
|
||||
ret = amdxdna_pm_resume_get_locked(xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = amdxdna_obj_dma_addr(heap);
|
||||
ret = aie2_add_host_buf(xdna->dev_handle, hwctx->fw_ctx_id,
|
||||
addr, heap->mem.size);
|
||||
@@ -1233,7 +1230,5 @@ int aie2_hwctx_heap_expand(struct amdxdna_hwctx *hwctx,
|
||||
hwctx->name, heap->mem.size, ret);
|
||||
}
|
||||
|
||||
amdxdna_pm_suspend_put(xdna);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -840,7 +840,7 @@ static struct aie2_exec_msg_ops npu_exec_message_ops = {
|
||||
static int aie2_init_exec_req(void *req, struct amdxdna_gem_obj *cmd_abo,
|
||||
size_t *size, u32 *msg_op)
|
||||
{
|
||||
struct amdxdna_dev *xdna = cmd_abo->client->xdna;
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(cmd_abo)->dev);
|
||||
int ret;
|
||||
u32 op;
|
||||
|
||||
@@ -874,7 +874,7 @@ static int
|
||||
aie2_cmdlist_fill_slot(void *slot, struct amdxdna_gem_obj *cmd_abo,
|
||||
size_t *size, u32 *cmd_op)
|
||||
{
|
||||
struct amdxdna_dev *xdna = cmd_abo->client->xdna;
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(cmd_abo)->dev);
|
||||
int ret;
|
||||
u32 op;
|
||||
|
||||
|
||||
@@ -310,6 +310,7 @@ int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct d
|
||||
if (!drm_dev_enter(dev, &idx))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&xdna->client_lock);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
hwctx = xa_erase(&client->hwctx_xa, args->handle);
|
||||
if (!hwctx) {
|
||||
@@ -328,6 +329,7 @@ int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct d
|
||||
XDNA_DBG(xdna, "PID %d destroyed HW context %d", client->pid, args->handle);
|
||||
out:
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
mutex_unlock(&xdna->client_lock);
|
||||
drm_dev_exit(idx);
|
||||
return ret;
|
||||
}
|
||||
@@ -382,16 +384,27 @@ int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
guard(mutex)(&xdna->dev_lock);
|
||||
ret = amdxdna_pm_resume_get(xdna);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Resume failed, ret %d", ret);
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
mutex_lock(&xdna->client_lock);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
hwctx = xa_load(&client->hwctx_xa, args->handle);
|
||||
if (!hwctx) {
|
||||
XDNA_DBG(xdna, "PID %d failed to get hwctx %d", client->pid, args->handle);
|
||||
ret = -EINVAL;
|
||||
goto free_buf;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = xdna->dev_info->ops->hwctx_config(hwctx, args->param_type, val, buf, buf_size);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
mutex_unlock(&xdna->client_lock);
|
||||
amdxdna_pm_suspend_put(xdna);
|
||||
free_buf:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
@@ -412,16 +425,27 @@ int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl)
|
||||
if (!gobj)
|
||||
return -EINVAL;
|
||||
|
||||
ret = amdxdna_pm_resume_get(xdna);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Resume failed, ret %d", ret);
|
||||
goto put_obj;
|
||||
}
|
||||
|
||||
abo = to_xdna_obj(gobj);
|
||||
guard(mutex)(&xdna->dev_lock);
|
||||
mutex_lock(&xdna->client_lock);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
hwctx = xa_load(&client->hwctx_xa, abo->assigned_hwctx);
|
||||
if (!hwctx) {
|
||||
ret = -EINVAL;
|
||||
goto put_obj;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = xdna->dev_info->ops->hwctx_sync_debug_bo(hwctx, debug_bo_hdl);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
mutex_unlock(&xdna->client_lock);
|
||||
amdxdna_pm_suspend_put(xdna);
|
||||
put_obj:
|
||||
drm_gem_object_put(gobj);
|
||||
return ret;
|
||||
@@ -448,9 +472,7 @@ static int amdxdna_hwctx_expand_heap(struct amdxdna_hwctx *hwctx)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&client->mm_lock);
|
||||
ret = xdna->dev_info->ops->hwctx_heap_expand(hwctx, heap);
|
||||
mutex_lock(&client->mm_lock);
|
||||
if (ret) {
|
||||
amdxdna_gem_unpin(heap);
|
||||
drm_gem_object_put(to_gobj(heap));
|
||||
@@ -469,18 +491,26 @@ int amdxdna_update_heap(struct amdxdna_client *client, struct amdxdna_hwctx *hwc
|
||||
unsigned long hwctx_id;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&client->mm_lock);
|
||||
ret = amdxdna_pm_resume_get_locked(client->xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (hwctx)
|
||||
return amdxdna_hwctx_expand_heap(hwctx);
|
||||
mutex_lock(&client->mm_lock);
|
||||
|
||||
amdxdna_for_each_hwctx(client, hwctx_id, hwctx) {
|
||||
if (hwctx) {
|
||||
ret = amdxdna_hwctx_expand_heap(hwctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
amdxdna_for_each_hwctx(client, hwctx_id, hwctx) {
|
||||
ret = amdxdna_hwctx_expand_heap(hwctx);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->mm_lock);
|
||||
|
||||
return 0;
|
||||
amdxdna_pm_suspend_put(client->xdna);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -198,6 +198,7 @@ amdxdna_gem_destroy_obj(struct amdxdna_gem_obj *abo)
|
||||
*/
|
||||
void *amdxdna_gem_vmap(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
|
||||
struct iosys_map map = IOSYS_MAP_INIT_VADDR(NULL);
|
||||
int ret;
|
||||
|
||||
@@ -210,7 +211,7 @@ void *amdxdna_gem_vmap(struct amdxdna_gem_obj *abo)
|
||||
if (!abo->mem.kva) {
|
||||
ret = drm_gem_vmap(to_gobj(abo), &map);
|
||||
if (ret)
|
||||
XDNA_ERR(abo->client->xdna, "Vmap bo failed, ret %d", ret);
|
||||
XDNA_ERR(xdna, "Vmap bo failed, ret %d", ret);
|
||||
else
|
||||
abo->mem.kva = map.vaddr;
|
||||
}
|
||||
@@ -254,7 +255,7 @@ static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni,
|
||||
|
||||
xdna = to_xdna_dev(to_gobj(abo)->dev);
|
||||
XDNA_DBG(xdna, "Invalidating range 0x%lx, 0x%lx, type %d",
|
||||
mapp->vma->vm_start, mapp->vma->vm_end, abo->type);
|
||||
mapp->range.start, mapp->range.end, abo->type);
|
||||
|
||||
if (!mmu_notifier_range_blockable(range))
|
||||
return false;
|
||||
@@ -284,15 +285,23 @@ static const struct mmu_interval_notifier_ops amdxdna_hmm_ops = {
|
||||
.invalidate = amdxdna_hmm_invalidate,
|
||||
};
|
||||
|
||||
static inline bool compare_range(struct amdxdna_umap *mapp,
|
||||
struct mm_struct *mm,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
return (!mapp->unmapped && mapp->notifier.mm == mm &&
|
||||
mapp->range.start == start && mapp->range.end == end);
|
||||
}
|
||||
|
||||
static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
|
||||
struct amdxdna_umap *mapp;
|
||||
|
||||
down_read(&xdna->notifier_lock);
|
||||
down_write(&xdna->notifier_lock);
|
||||
list_for_each_entry(mapp, &abo->mem.umap_list, node) {
|
||||
if (!vma || mapp->vma == vma) {
|
||||
if (!vma || compare_range(mapp, vma->vm_mm, vma->vm_start, vma->vm_end)) {
|
||||
if (!mapp->unmapped) {
|
||||
queue_work(xdna->notifier_wq, &mapp->hmm_unreg_work);
|
||||
mapp->unmapped = true;
|
||||
@@ -301,19 +310,16 @@ static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo,
|
||||
break;
|
||||
}
|
||||
}
|
||||
up_read(&xdna->notifier_lock);
|
||||
up_write(&xdna->notifier_lock);
|
||||
}
|
||||
|
||||
static void amdxdna_umap_release(struct kref *ref)
|
||||
{
|
||||
struct amdxdna_umap *mapp = container_of(ref, struct amdxdna_umap, refcnt);
|
||||
struct amdxdna_gem_obj *abo = mapp->abo;
|
||||
struct vm_area_struct *vma = mapp->vma;
|
||||
struct amdxdna_dev *xdna;
|
||||
|
||||
mmu_interval_notifier_remove(&mapp->notifier);
|
||||
if (is_import_bo(abo) && vma->vm_file && vma->vm_file->f_mapping)
|
||||
mapping_clear_unevictable(vma->vm_file->f_mapping);
|
||||
|
||||
xdna = to_xdna_dev(to_gobj(mapp->abo)->dev);
|
||||
down_write(&xdna->notifier_lock);
|
||||
@@ -346,15 +352,30 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo,
|
||||
unsigned long len = vma->vm_end - vma->vm_start;
|
||||
unsigned long addr = vma->vm_start;
|
||||
struct amdxdna_umap *mapp;
|
||||
u32 nr_pages;
|
||||
unsigned long nr_pages;
|
||||
int ret;
|
||||
|
||||
if (!amdxdna_pasid_on(abo->client)) {
|
||||
/*
|
||||
* When PASID is off, amdxdna_gem_obj_open() called amdxdna_dma_map_bo()
|
||||
* and mem.dma_addr is valid; use the DMA address directly and skip HMM.
|
||||
* Avoid dereferencing abo->client which may be NULL (cleared in close())
|
||||
* while internal kernel references are still held.
|
||||
*/
|
||||
if (abo->mem.dma_addr != AMDXDNA_INVALID_ADDR) {
|
||||
/* Need to set uva for heap uva validation */
|
||||
abo->mem.uva = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
down_read(&xdna->notifier_lock);
|
||||
list_for_each_entry(mapp, &abo->mem.umap_list, node) {
|
||||
if (compare_range(mapp, current->mm, addr, addr + len)) {
|
||||
up_read(&xdna->notifier_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
up_read(&xdna->notifier_lock);
|
||||
|
||||
mapp = kzalloc_obj(*mapp);
|
||||
if (!mapp)
|
||||
return -ENOMEM;
|
||||
@@ -380,13 +401,10 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo,
|
||||
mapp->range.start = vma->vm_start;
|
||||
mapp->range.end = vma->vm_end;
|
||||
mapp->range.default_flags = HMM_PFN_REQ_FAULT;
|
||||
mapp->vma = vma;
|
||||
mapp->abo = abo;
|
||||
kref_init(&mapp->refcnt);
|
||||
|
||||
INIT_WORK(&mapp->hmm_unreg_work, amdxdna_hmm_unreg_work);
|
||||
if (is_import_bo(abo) && vma->vm_file && vma->vm_file->f_mapping)
|
||||
mapping_set_unevictable(vma->vm_file->f_mapping);
|
||||
|
||||
down_write(&xdna->notifier_lock);
|
||||
if (list_empty(&abo->mem.umap_list))
|
||||
@@ -527,6 +545,7 @@ static int amdxdna_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struc
|
||||
|
||||
close_vma:
|
||||
vma->vm_ops->close(vma);
|
||||
return ret;
|
||||
put_obj:
|
||||
drm_gem_object_put(gobj);
|
||||
return ret;
|
||||
@@ -652,8 +671,11 @@ static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *fi
|
||||
/* No need to set up dma addr mapping in PASID mode. */
|
||||
if (!amdxdna_pasid_on(abo->client)) {
|
||||
ret = amdxdna_dma_map_bo(xdna, abo);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
abo->open_ref--;
|
||||
abo->client = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
amdxdna_gem_add_bo_usage(abo);
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
struct amdxdna_umap {
|
||||
struct vm_area_struct *vma;
|
||||
struct mmu_interval_notifier notifier;
|
||||
struct hmm_range range;
|
||||
struct work_struct hmm_unreg_work;
|
||||
@@ -89,12 +88,19 @@ u64 amdxdna_gem_dev_addr(struct amdxdna_gem_obj *abo);
|
||||
|
||||
static inline u64 amdxdna_dev_bo_offset(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
return amdxdna_gem_dev_addr(abo) - abo->client->xdna->dev_info->dev_mem_base;
|
||||
return amdxdna_gem_dev_addr(abo) - to_xdna_dev(to_gobj(abo)->dev)->dev_info->dev_mem_base;
|
||||
}
|
||||
|
||||
static inline u64 amdxdna_obj_dma_addr(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
return amdxdna_pasid_on(abo->client) ? amdxdna_gem_uva(abo) : abo->mem.dma_addr;
|
||||
/*
|
||||
* amdxdna_gem_obj_open() calls amdxdna_dma_map_bo() only when PASID is
|
||||
* off, leaving mem.dma_addr at AMDXDNA_INVALID_ADDR when PASID is on.
|
||||
* Avoid dereferencing abo->client, which is cleared to NULL by
|
||||
* amdxdna_gem_obj_close() while internal kernel references remain.
|
||||
*/
|
||||
return (abo->mem.dma_addr != AMDXDNA_INVALID_ADDR) ?
|
||||
abo->mem.dma_addr : amdxdna_gem_uva(abo);
|
||||
}
|
||||
|
||||
void amdxdna_umap_put(struct amdxdna_umap *mapp);
|
||||
|
||||
@@ -109,11 +109,16 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(ddev);
|
||||
struct amdxdna_client *client;
|
||||
int ret;
|
||||
|
||||
client = kzalloc_obj(*client);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = init_srcu_struct(&client->hwctx_srcu);
|
||||
if (ret)
|
||||
goto free_client;
|
||||
|
||||
client->pid = pid_nr(rcu_access_pointer(filp->pid));
|
||||
client->xdna = xdna;
|
||||
client->pasid = IOMMU_PASID_INVALID;
|
||||
@@ -125,13 +130,12 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
|
||||
XDNA_WARN(xdna, "PASID not available for pid %d", client->pid);
|
||||
if (!amdxdna_use_carveout(xdna)) {
|
||||
XDNA_ERR(xdna, "PASID unavailable and carveout not configured");
|
||||
kfree(client);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto cleanup_srcu;
|
||||
}
|
||||
}
|
||||
}
|
||||
mmgrab(client->mm);
|
||||
init_srcu_struct(&client->hwctx_srcu);
|
||||
xa_init_flags(&client->hwctx_xa, XA_FLAGS_ALLOC);
|
||||
xa_init_flags(&client->dev_heap_xa, XA_FLAGS_ALLOC);
|
||||
drm_mm_init(&client->dev_heap_mm, xdna->dev_info->dev_mem_base,
|
||||
@@ -149,6 +153,12 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
|
||||
|
||||
XDNA_DBG(xdna, "pid %d opened", client->pid);
|
||||
return 0;
|
||||
|
||||
cleanup_srcu:
|
||||
cleanup_srcu_struct(&client->hwctx_srcu);
|
||||
free_client:
|
||||
kfree(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void amdxdna_client_cleanup(struct amdxdna_client *client)
|
||||
@@ -373,7 +383,10 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drmm_mutex_init(ddev, &xdna->dev_lock);
|
||||
ret = drmm_mutex_init(ddev, &xdna->dev_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
init_rwsem(&xdna->notifier_lock);
|
||||
INIT_LIST_HEAD(&xdna->client_list);
|
||||
pci_set_drvdata(pdev, xdna);
|
||||
|
||||
@@ -1084,22 +1084,30 @@ static int __gpu_buddy_alloc_range(struct gpu_buddy *mm,
|
||||
blocks, total_allocated_on_err);
|
||||
}
|
||||
|
||||
static int __alloc_contig_aligned_retry(struct gpu_buddy *mm,
|
||||
u64 unaligned_offset,
|
||||
u64 size,
|
||||
u64 min_block_size,
|
||||
struct list_head *blocks)
|
||||
{
|
||||
u64 aligned_offset = round_down(unaligned_offset, min_block_size);
|
||||
|
||||
return __gpu_buddy_alloc_range(mm, aligned_offset, size, NULL, blocks);
|
||||
}
|
||||
|
||||
static int __alloc_contig_try_harder(struct gpu_buddy *mm,
|
||||
u64 size,
|
||||
u64 min_block_size,
|
||||
struct list_head *blocks)
|
||||
{
|
||||
u64 rhs_offset, lhs_offset, lhs_size, filled;
|
||||
u64 rhs_offset, lhs_offset, filled;
|
||||
struct gpu_buddy_block *block;
|
||||
unsigned int tree, order;
|
||||
LIST_HEAD(blocks_lhs);
|
||||
unsigned long pages;
|
||||
u64 modify_size;
|
||||
int err;
|
||||
|
||||
modify_size = rounddown_pow_of_two(size);
|
||||
pages = modify_size >> ilog2(mm->chunk_size);
|
||||
order = fls(pages) - 1;
|
||||
order = ilog2(modify_size) - ilog2(mm->chunk_size);
|
||||
if (order == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
@@ -1115,31 +1123,48 @@ static int __alloc_contig_try_harder(struct gpu_buddy *mm,
|
||||
while (iter) {
|
||||
block = rbtree_get_free_block(iter);
|
||||
|
||||
/* Allocate blocks traversing RHS */
|
||||
rhs_offset = gpu_buddy_block_offset(block);
|
||||
|
||||
/* Allocate blocks traversing RHS */
|
||||
err = __gpu_buddy_alloc_range(mm, rhs_offset, size,
|
||||
&filled, blocks);
|
||||
if (!err || err != -ENOSPC)
|
||||
if (err && err != -ENOSPC)
|
||||
return err;
|
||||
|
||||
lhs_size = max((size - filled), min_block_size);
|
||||
if (!IS_ALIGNED(lhs_size, min_block_size))
|
||||
lhs_size = round_up(lhs_size, min_block_size);
|
||||
|
||||
/* Allocate blocks traversing LHS */
|
||||
lhs_offset = gpu_buddy_block_offset(block) - lhs_size;
|
||||
err = __gpu_buddy_alloc_range(mm, lhs_offset, lhs_size,
|
||||
NULL, &blocks_lhs);
|
||||
if (!err) {
|
||||
list_splice(&blocks_lhs, blocks);
|
||||
if (!err && IS_ALIGNED(rhs_offset, min_block_size))
|
||||
return 0;
|
||||
} else if (err != -ENOSPC) {
|
||||
if (!err) {
|
||||
/* Allocate the unaligned RHS offset using round_down */
|
||||
gpu_buddy_free_list_internal(mm, blocks);
|
||||
err = __alloc_contig_aligned_retry(mm, rhs_offset,
|
||||
size,
|
||||
min_block_size,
|
||||
blocks);
|
||||
if (!err)
|
||||
return 0;
|
||||
if (err != -ENOSPC) {
|
||||
gpu_buddy_free_list_internal(mm, blocks);
|
||||
return err;
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (size - filled > rhs_offset)
|
||||
goto next;
|
||||
|
||||
lhs_offset = rhs_offset - (size - filled);
|
||||
|
||||
/* Allocate the unaligned LHS offset using round_down */
|
||||
gpu_buddy_free_list_internal(mm, blocks);
|
||||
err = __alloc_contig_aligned_retry(mm, lhs_offset, size,
|
||||
min_block_size, blocks);
|
||||
if (!err)
|
||||
return 0;
|
||||
if (err != -ENOSPC) {
|
||||
gpu_buddy_free_list_internal(mm, blocks);
|
||||
return err;
|
||||
}
|
||||
/* Free blocks for the next iteration */
|
||||
next:
|
||||
gpu_buddy_free_list_internal(mm, blocks);
|
||||
|
||||
iter = rb_prev(iter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1333,7 +1333,8 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
|
||||
* It's unclear if this is a platform-specific or GPU-specific issue.
|
||||
* Disable ASPM on SI for the time being.
|
||||
*/
|
||||
if (adev->family == AMDGPU_FAMILY_SI)
|
||||
if (adev->family == AMDGPU_FAMILY_SI ||
|
||||
(!(adev->pm.pp_feature & PP_PCIE_DPM_MASK) && adev->family == AMDGPU_FAMILY_VI))
|
||||
return true;
|
||||
|
||||
#if IS_ENABLED(CONFIG_X86)
|
||||
|
||||
@@ -2304,6 +2304,7 @@ static int amdgpu_discovery_set_psp_ip_blocks(struct amdgpu_device *adev)
|
||||
amdgpu_device_ip_block_add(adev, &psp_v14_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(15, 0, 0):
|
||||
case IP_VERSION(15, 0, 9):
|
||||
amdgpu_device_ip_block_add(adev, &psp_v15_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(15, 0, 8):
|
||||
@@ -2375,6 +2376,7 @@ static int amdgpu_discovery_set_smu_ip_blocks(struct amdgpu_device *adev)
|
||||
case IP_VERSION(15, 0, 0):
|
||||
case IP_VERSION(15, 0, 5):
|
||||
case IP_VERSION(15, 0, 8):
|
||||
case IP_VERSION(15, 0, 9):
|
||||
amdgpu_device_ip_block_add(adev, &smu_v15_0_ip_block);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -275,6 +275,7 @@ static int psp_early_init(struct amdgpu_ip_block *ip_block)
|
||||
psp->boot_time_tmr = false;
|
||||
break;
|
||||
case IP_VERSION(15, 0, 0):
|
||||
case IP_VERSION(15, 0, 9):
|
||||
psp_v15_0_0_set_psp_funcs(psp);
|
||||
psp->boot_time_tmr = false;
|
||||
break;
|
||||
@@ -3475,7 +3476,9 @@ static int psp_load_non_psp_fw(struct psp_context *psp)
|
||||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
|
||||
IP_VERSION(15, 0, 0) ||
|
||||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
|
||||
IP_VERSION(15, 0, 8)) &&
|
||||
IP_VERSION(15, 0, 8) ||
|
||||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
|
||||
IP_VERSION(15, 0, 9)) &&
|
||||
(ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 ||
|
||||
ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 ||
|
||||
ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3))
|
||||
|
||||
@@ -523,6 +523,15 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
||||
amdgpu_userq_cleanup(queue);
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
/*
|
||||
* A failed unmap means MES could not remove the hung queue and is now
|
||||
* unresponsive. Recover the GPU here so the wedged MES does not fail
|
||||
* the next, unrelated queue submission and trigger a reset attributed
|
||||
* to an innocent workload.
|
||||
*/
|
||||
if (r)
|
||||
queue_work(adev->reset_domain->wq, &uq_mgr->reset_work);
|
||||
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
queue->userq_mgr = NULL;
|
||||
|
||||
@@ -2460,19 +2460,6 @@ static void amdgpu_vm_destroy_task_info(struct kref *kref)
|
||||
kfree(ti);
|
||||
}
|
||||
|
||||
static inline struct amdgpu_vm *
|
||||
amdgpu_vm_get_vm_from_pasid(struct amdgpu_device *adev, u32 pasid)
|
||||
{
|
||||
struct amdgpu_vm *vm;
|
||||
unsigned long flags;
|
||||
|
||||
xa_lock_irqsave(&adev->vm_manager.pasids, flags);
|
||||
vm = xa_load(&adev->vm_manager.pasids, pasid);
|
||||
xa_unlock_irqrestore(&adev->vm_manager.pasids, flags);
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_put_task_info - reference down the vm task_info ptr
|
||||
*
|
||||
@@ -2519,8 +2506,16 @@ amdgpu_vm_get_task_info_vm(struct amdgpu_vm *vm)
|
||||
struct amdgpu_task_info *
|
||||
amdgpu_vm_get_task_info_pasid(struct amdgpu_device *adev, u32 pasid)
|
||||
{
|
||||
return amdgpu_vm_get_task_info_vm(
|
||||
amdgpu_vm_get_vm_from_pasid(adev, pasid));
|
||||
struct amdgpu_task_info *ti;
|
||||
struct amdgpu_vm *vm;
|
||||
unsigned long flags;
|
||||
|
||||
xa_lock_irqsave(&adev->vm_manager.pasids, flags);
|
||||
vm = xa_load(&adev->vm_manager.pasids, pasid);
|
||||
ti = amdgpu_vm_get_task_info_vm(vm);
|
||||
xa_unlock_irqrestore(&adev->vm_manager.pasids, flags);
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
static int amdgpu_vm_create_task_info(struct amdgpu_vm *vm)
|
||||
@@ -3015,6 +3010,8 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
|
||||
is_compute_context = vm->is_compute_context;
|
||||
|
||||
if (is_compute_context) {
|
||||
__label__ drm_exec_retry;
|
||||
|
||||
/* Release the root PD lock since svm_range_restore_pages
|
||||
* might try to take it.
|
||||
* TODO: rework svm_range_restore_pages so that this isn't
|
||||
|
||||
@@ -5350,6 +5350,15 @@ static void gfx_v10_0_constants_init(struct amdgpu_device *adev)
|
||||
gfx_v10_0_get_tcc_info(adev);
|
||||
adev->gfx.config.pa_sc_tile_steering_override =
|
||||
gfx_v10_0_init_pa_sc_tile_steering_override(adev);
|
||||
/* Program DB_RING_CONTROL for multiple GFX pipes
|
||||
* Default power up value is 1.
|
||||
* Possible values:
|
||||
* 0 - split occlusion counters between gfx pipes
|
||||
* 1 - all occlusion counters to pipe 0
|
||||
* 2 - all occlusion counters to pipe 1
|
||||
*/
|
||||
WREG32_FIELD15(GC, 0, DB_RING_CONTROL, COUNTER_CONTROL,
|
||||
(adev->gfx.me.num_pipe_per_me > 1) ? 0 : 1);
|
||||
|
||||
/* XXX SH_MEM regs */
|
||||
/* where to put LDS, scratch, GPUVM in FSA64 space */
|
||||
|
||||
@@ -406,6 +406,7 @@ soc21_asic_reset_method(struct amdgpu_device *adev)
|
||||
case IP_VERSION(14, 0, 4):
|
||||
case IP_VERSION(14, 0, 5):
|
||||
case IP_VERSION(15, 0, 0):
|
||||
case IP_VERSION(15, 0, 9):
|
||||
return AMD_RESET_METHOD_MODE2;
|
||||
default:
|
||||
if (amdgpu_dpm_is_baco_supported(adev))
|
||||
@@ -861,7 +862,6 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block)
|
||||
AMD_CG_SUPPORT_BIF_LS;
|
||||
adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG |
|
||||
AMD_PG_SUPPORT_VCN |
|
||||
AMD_PG_SUPPORT_JPEG_DPG |
|
||||
AMD_PG_SUPPORT_JPEG |
|
||||
AMD_PG_SUPPORT_GFX_PG;
|
||||
adev->external_rev_id = adev->rev_id + 0xF;
|
||||
@@ -889,7 +889,6 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block)
|
||||
AMD_CG_SUPPORT_BIF_LS;
|
||||
adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG |
|
||||
AMD_PG_SUPPORT_VCN |
|
||||
AMD_PG_SUPPORT_JPEG_DPG |
|
||||
AMD_PG_SUPPORT_JPEG |
|
||||
AMD_PG_SUPPORT_GFX_PG;
|
||||
adev->external_rev_id = adev->rev_id + 0x40;
|
||||
|
||||
@@ -3818,6 +3818,12 @@ bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm,
|
||||
dqm_unlock(dqm);
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t mqd_size_from_queue_type(struct device_queue_manager *dqm, enum kfd_queue_type type)
|
||||
{
|
||||
return dqm->mqd_mgrs[get_mqd_type_from_queue_type(type)]->mqd_size;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
static void seq_reg_dump(struct seq_file *m,
|
||||
|
||||
@@ -333,6 +333,8 @@ int debug_refresh_runlist(struct device_queue_manager *dqm);
|
||||
bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm,
|
||||
struct qcm_process_device *qpd,
|
||||
int doorbell_off, u32 *queue_format);
|
||||
size_t mqd_size_from_queue_type(struct device_queue_manager *dqm,
|
||||
enum kfd_queue_type type);
|
||||
|
||||
static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
|
||||
{
|
||||
|
||||
@@ -107,6 +107,9 @@ static int allocate_event_notification_slot(struct kfd_process *p,
|
||||
}
|
||||
|
||||
if (restore_id) {
|
||||
if (*restore_id >= KFD_SIGNAL_EVENT_LIMIT)
|
||||
return -EINVAL;
|
||||
|
||||
id = idr_alloc(&p->event_idr, ev, *restore_id, *restore_id + 1,
|
||||
GFP_KERNEL);
|
||||
} else {
|
||||
@@ -204,7 +207,7 @@ static int create_signal_event(struct file *devkfd, struct kfd_process *p,
|
||||
|
||||
ret = allocate_event_notification_slot(p, ev, restore_id);
|
||||
if (ret) {
|
||||
pr_warn("Signal event wasn't created because out of kernel memory\n");
|
||||
pr_warn("Failed to create signal event notification slot\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -440,7 +440,8 @@ enum kfd_queue_type {
|
||||
KFD_QUEUE_TYPE_SDMA,
|
||||
KFD_QUEUE_TYPE_HIQ,
|
||||
KFD_QUEUE_TYPE_SDMA_XGMI,
|
||||
KFD_QUEUE_TYPE_SDMA_BY_ENG_ID
|
||||
KFD_QUEUE_TYPE_SDMA_BY_ENG_ID,
|
||||
KFD_QUEUE_TYPE_MAX,
|
||||
};
|
||||
|
||||
enum kfd_queue_format {
|
||||
|
||||
@@ -910,7 +910,7 @@ static void kfd_process_free_id(struct kfd_process *process)
|
||||
{
|
||||
struct kfd_process *primary_process;
|
||||
|
||||
if (process->context_id != KFD_CONTEXT_ID_PRIMARY)
|
||||
if (process->context_id == KFD_CONTEXT_ID_PRIMARY)
|
||||
return;
|
||||
|
||||
primary_process = kfd_lookup_process_by_mm(process->lead_thread->mm);
|
||||
|
||||
@@ -265,6 +265,11 @@ static int init_user_queue(struct process_queue_manager *pqm,
|
||||
(*q)->process = pqm->process;
|
||||
|
||||
if (dev->kfd->shared_resources.enable_mes) {
|
||||
if (!q_properties->wptr_bo) {
|
||||
pr_debug("Queue initialization with shared MES requires queue buffers to be initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev,
|
||||
AMDGPU_MES_GANG_CTX_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_GTT,
|
||||
@@ -1003,6 +1008,23 @@ int kfd_criu_restore_queue(struct kfd_process *p,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pdd = kfd_process_device_data_by_id(p, q_data->gpu_id);
|
||||
if (!pdd) {
|
||||
pr_err("Failed to get pdd\n");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (q_data->type >= KFD_QUEUE_TYPE_MAX) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (q_data->mqd_size != mqd_size_from_queue_type(pdd->dev->dqm, q_data->type)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*priv_data_offset += sizeof(*q_data);
|
||||
q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size;
|
||||
|
||||
@@ -1025,13 +1047,6 @@ int kfd_criu_restore_queue(struct kfd_process *p,
|
||||
|
||||
*priv_data_offset += q_extra_data_size;
|
||||
|
||||
pdd = kfd_process_device_data_by_id(p, q_data->gpu_id);
|
||||
if (!pdd) {
|
||||
pr_err("Failed to get pdd\n");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* data stored in this order:
|
||||
* mqd[xcc0], mqd[xcc1],..., ctl_stack[xcc0], ctl_stack[xcc1]...
|
||||
@@ -1042,18 +1057,10 @@ int kfd_criu_restore_queue(struct kfd_process *p,
|
||||
memset(&qp, 0, sizeof(qp));
|
||||
set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->adev->gfx.xcc_mask));
|
||||
|
||||
ret = kfd_queue_acquire_buffers(pdd, &qp);
|
||||
if (ret) {
|
||||
pr_debug("failed to acquire user queue buffers for CRIU\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
print_queue_properties(&qp);
|
||||
|
||||
ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL);
|
||||
if (ret) {
|
||||
kfd_queue_unref_bo_vas(pdd, &qp);
|
||||
kfd_queue_release_buffers(pdd, &qp);
|
||||
pr_err("Failed to create new queue err:%d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -802,6 +802,7 @@ static int smu_set_funcs(struct amdgpu_device *adev)
|
||||
break;
|
||||
case IP_VERSION(15, 0, 0):
|
||||
case IP_VERSION(15, 0, 5):
|
||||
case IP_VERSION(15, 0, 9):
|
||||
smu_v15_0_0_set_ppt_funcs(smu);
|
||||
break;
|
||||
case IP_VERSION(15, 0, 8):
|
||||
|
||||
@@ -1621,19 +1621,23 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
|
||||
table_context->power_play_table;
|
||||
PPTable_t *pptable = table_context->driver_pptable;
|
||||
CustomSkuTable_t *skutable = &pptable->CustomSkuTable;
|
||||
int16_t od_percent_upper = 0, od_percent_lower = 0;
|
||||
uint32_t pp_limit = smu->adev->pm.ac_power ?
|
||||
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
|
||||
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
|
||||
uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||
uint32_t power_limit;
|
||||
uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit);
|
||||
uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit);
|
||||
int16_t od_percent_upper = 0, od_percent_lower = 0;
|
||||
int ret;
|
||||
|
||||
if (smu_v14_0_get_current_power_limit(smu, &power_limit))
|
||||
power_limit = smu->adev->pm.ac_power ?
|
||||
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
|
||||
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
|
||||
if (current_power_limit) {
|
||||
ret = smu_v14_0_get_current_power_limit(smu, current_power_limit);
|
||||
if (ret)
|
||||
*current_power_limit = pp_limit;
|
||||
}
|
||||
|
||||
if (current_power_limit)
|
||||
*current_power_limit = power_limit;
|
||||
if (default_power_limit)
|
||||
*default_power_limit = power_limit;
|
||||
*default_power_limit = pp_limit;
|
||||
|
||||
if (powerplay_table) {
|
||||
if (smu->od_enabled &&
|
||||
@@ -1647,15 +1651,15 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
|
||||
}
|
||||
|
||||
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
|
||||
od_percent_upper, od_percent_lower, power_limit);
|
||||
od_percent_upper, od_percent_lower, pp_limit);
|
||||
|
||||
if (max_power_limit) {
|
||||
*max_power_limit = msg_limit * (100 + od_percent_upper);
|
||||
*max_power_limit = max_limit * (100 + od_percent_upper);
|
||||
*max_power_limit /= 100;
|
||||
}
|
||||
|
||||
if (min_power_limit) {
|
||||
*min_power_limit = power_limit * (100 + od_percent_lower);
|
||||
*min_power_limit = min_limit * (100 + od_percent_lower);
|
||||
*min_power_limit /= 100;
|
||||
}
|
||||
|
||||
|
||||
@@ -664,6 +664,7 @@ int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable)
|
||||
|
||||
switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
|
||||
case IP_VERSION(15, 0, 0):
|
||||
case IP_VERSION(15, 0, 9):
|
||||
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
|
||||
return 0;
|
||||
if (enable)
|
||||
|
||||
@@ -1177,7 +1177,8 @@ static int smu_v15_0_common_get_dpm_profile_freq(struct smu_context *smu,
|
||||
smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit);
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 0))
|
||||
if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 0) ||
|
||||
amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 9))
|
||||
smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit);
|
||||
else
|
||||
clk_limit = SMU_15_0_UMD_PSTATE_FCLK;
|
||||
|
||||
@@ -309,7 +309,9 @@ static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp,
|
||||
lane_count = dp->link_train.lane_count;
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane);
|
||||
voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT;
|
||||
pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
|
||||
pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
|
||||
training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
|
||||
DPCD_PRE_EMPHASIS_SET(pre_emphasis);
|
||||
|
||||
@@ -355,7 +357,9 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
training_lane = analogix_dp_get_lane_link_training(dp, lane);
|
||||
voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane);
|
||||
voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT;
|
||||
pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
|
||||
pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
|
||||
|
||||
if (DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing &&
|
||||
DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis)
|
||||
|
||||
@@ -225,16 +225,106 @@ static void drm_fb_helper_resume_worker(struct work_struct *work)
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
static int find_crtc_index_atomic(struct drm_fb_helper *helper)
|
||||
{
|
||||
struct drm_device *dev = helper->dev;
|
||||
int crtc_index = -EINVAL;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
struct drm_plane *plane;
|
||||
int ret = 0;
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
retry:
|
||||
drm_for_each_plane(plane, dev) {
|
||||
const struct drm_plane_state *plane_state;
|
||||
|
||||
if (plane->type != DRM_PLANE_TYPE_PRIMARY)
|
||||
continue;
|
||||
|
||||
ret = drm_modeset_lock(&plane->mutex, &ctx);
|
||||
if (ret)
|
||||
goto err_drm_modeset_lock;
|
||||
plane_state = plane->state;
|
||||
|
||||
if (plane_state->fb == helper->fb && plane_state->crtc) {
|
||||
struct drm_crtc *crtc = plane_state->crtc;
|
||||
|
||||
ret = drm_modeset_lock(&crtc->mutex, &ctx);
|
||||
if (ret)
|
||||
goto err_drm_modeset_lock;
|
||||
if (crtc->state->active)
|
||||
crtc_index = crtc->index;
|
||||
drm_modeset_unlock(&crtc->mutex);
|
||||
}
|
||||
drm_modeset_unlock(&plane->mutex);
|
||||
|
||||
if (crtc_index >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
return crtc_index;
|
||||
|
||||
err_drm_modeset_lock:
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(&ctx);
|
||||
goto retry;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int find_crtc_index_legacy(struct drm_fb_helper *helper)
|
||||
{
|
||||
struct drm_device *dev = helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
drm_for_each_crtc(crtc, dev) {
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
|
||||
if (!crtc->enabled)
|
||||
continue;
|
||||
if (!plane || plane->fb != helper->fb)
|
||||
continue; /* CRTC doesn't display fbdev emulation */
|
||||
|
||||
return crtc->index;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int drm_fb_helper_find_crtc_index(struct drm_fb_helper *helper)
|
||||
{
|
||||
struct drm_device *dev = helper->dev;
|
||||
int crtc_index;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
if (drm_drv_uses_atomic_modeset(dev))
|
||||
crtc_index = find_crtc_index_atomic(helper);
|
||||
else
|
||||
crtc_index = find_crtc_index_legacy(helper);
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return crtc_index;
|
||||
}
|
||||
|
||||
static void drm_fb_helper_fb_dirty(struct drm_fb_helper *helper)
|
||||
{
|
||||
struct drm_device *dev = helper->dev;
|
||||
struct drm_clip_rect *clip = &helper->damage_clip;
|
||||
struct drm_clip_rect clip_copy;
|
||||
int crtc_index;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&helper->lock);
|
||||
drm_client_modeset_wait_for_vblank(&helper->client, 0);
|
||||
crtc_index = drm_fb_helper_find_crtc_index(helper);
|
||||
if (crtc_index >= 0)
|
||||
drm_client_modeset_wait_for_vblank(&helper->client, crtc_index);
|
||||
mutex_unlock(&helper->lock);
|
||||
|
||||
if (drm_WARN_ON_ONCE(dev, !helper->funcs->fb_dirty))
|
||||
|
||||
@@ -373,13 +373,25 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
return -EINVAL;
|
||||
file_priv->supports_virtualized_cursor_plane = req->value;
|
||||
break;
|
||||
case DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE:
|
||||
case DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE: {
|
||||
struct drm_plane *plane;
|
||||
bool has_plane_with_color_pipeline = false;
|
||||
|
||||
if (!file_priv->atomic)
|
||||
return -EINVAL;
|
||||
if (req->value > 1)
|
||||
return -EINVAL;
|
||||
drm_for_each_plane(plane, dev) {
|
||||
if (plane->color_pipeline_property) {
|
||||
has_plane_with_color_pipeline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_plane_with_color_pipeline)
|
||||
return -EOPNOTSUPP;
|
||||
file_priv->plane_color_pipeline = req->value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -5737,8 +5737,9 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
bool force_retrain = intel_dp->link.force_retrain;
|
||||
bool reprobe_needed = false;
|
||||
int tries = 33;
|
||||
|
||||
for (;;) {
|
||||
while (--tries) {
|
||||
u8 esi[4] = {};
|
||||
u8 ack[4] = {};
|
||||
bool new_irqs;
|
||||
@@ -5781,6 +5782,11 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tries) {
|
||||
drm_dbg_kms(display->drm, "DPRX ESI not clearing, device may be stuck\n");
|
||||
reprobe_needed = true;
|
||||
}
|
||||
|
||||
return !reprobe_needed;
|
||||
}
|
||||
|
||||
|
||||
@@ -1223,11 +1223,7 @@ intel_lt_phy_program_port_clock_ctl(struct intel_encoder *encoder,
|
||||
else
|
||||
val |= XELPDP_DDI_CLOCK_SELECT_PREP(display, XELPDP_DDI_CLOCK_SELECT_MAXPCLK);
|
||||
|
||||
/* DP2.0 10G and 20G rates enable MPLLA*/
|
||||
if (port_clock == 1000000 || port_clock == 2000000)
|
||||
val |= XELPDP_SSC_ENABLE_PLLA;
|
||||
else
|
||||
val |= ltpll->ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0;
|
||||
val |= ltpll->ssc_enabled ? XELPDP_SSC_ENABLE_PLLA : 0;
|
||||
|
||||
intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port),
|
||||
XELPDP_LANE1_PHY_CLOCK_SELECT | XELPDP_FORWARD_CLOCK_UNGATE |
|
||||
|
||||
@@ -1522,9 +1522,6 @@ int _intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state
|
||||
needs_panel_replay)
|
||||
return 0;
|
||||
|
||||
if (intel_vrr_always_use_vrr_tg(display))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -769,8 +769,8 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
|
||||
struct intel_engine_cs *engine;
|
||||
|
||||
if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
|
||||
kfree(set.engines);
|
||||
return -EFAULT;
|
||||
err = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset(&set.engines[n], 0, sizeof(set.engines[n]));
|
||||
@@ -786,8 +786,8 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
|
||||
drm_dbg(&i915->drm,
|
||||
"Invalid engine[%d]: { class:%d, instance:%d }\n",
|
||||
n, ci.engine_class, ci.engine_instance);
|
||||
kfree(set.engines);
|
||||
return -ENOENT;
|
||||
err = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
|
||||
@@ -800,15 +800,21 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
|
||||
set_proto_ctx_engines_extensions,
|
||||
ARRAY_SIZE(set_proto_ctx_engines_extensions),
|
||||
&set);
|
||||
if (err) {
|
||||
kfree(set.engines);
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
goto err_extensions;
|
||||
|
||||
pc->num_user_engines = set.num_engines;
|
||||
pc->user_engines = set.engines;
|
||||
|
||||
return 0;
|
||||
|
||||
err_extensions:
|
||||
for (n = 0; n < set.num_engines; n++)
|
||||
kfree(set.engines[n].siblings);
|
||||
err:
|
||||
kfree(set.engines);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
|
||||
@@ -850,7 +856,7 @@ static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
|
||||
pe = &pc->user_engines[idx];
|
||||
|
||||
/* Only render engine supports RPCS configuration. */
|
||||
if (pe->engine->class != RENDER_CLASS)
|
||||
if (!pe->engine || pe->engine->class != RENDER_CLASS)
|
||||
return -EINVAL;
|
||||
|
||||
sseu = &pe->sseu;
|
||||
|
||||
@@ -3932,11 +3932,11 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
|
||||
struct drm_i915_private *i915 = siblings[0]->i915;
|
||||
struct virtual_engine *ve;
|
||||
unsigned int n;
|
||||
int err;
|
||||
int err = -ENOMEM;
|
||||
|
||||
ve = kzalloc_flex(*ve, siblings, count);
|
||||
if (!ve)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto err;
|
||||
|
||||
ve->base.i915 = i915;
|
||||
ve->base.gt = siblings[0]->gt;
|
||||
@@ -3968,10 +3968,8 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
|
||||
intel_engine_init_execlists(&ve->base);
|
||||
|
||||
ve->base.sched_engine = i915_sched_engine_create(ENGINE_VIRTUAL);
|
||||
if (!ve->base.sched_engine) {
|
||||
err = -ENOMEM;
|
||||
goto err_put;
|
||||
}
|
||||
if (!ve->base.sched_engine)
|
||||
goto err_noput;
|
||||
ve->base.sched_engine->private_data = &ve->base;
|
||||
|
||||
ve->base.cops = &virtual_context_ops;
|
||||
@@ -3987,10 +3985,8 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
|
||||
intel_context_init(&ve->context, &ve->base);
|
||||
|
||||
ve->base.breadcrumbs = intel_breadcrumbs_create(NULL);
|
||||
if (!ve->base.breadcrumbs) {
|
||||
err = -ENOMEM;
|
||||
if (!ve->base.breadcrumbs)
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
for (n = 0; n < count; n++) {
|
||||
struct intel_engine_cs *sibling = siblings[n];
|
||||
@@ -4065,8 +4061,13 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
|
||||
virtual_engine_initial_hint(ve);
|
||||
return &ve->context;
|
||||
|
||||
err_noput:
|
||||
kfree(ve);
|
||||
goto err;
|
||||
|
||||
err_put:
|
||||
intel_context_put(&ve->context);
|
||||
err:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -309,8 +309,8 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co
|
||||
goto err_free_ctx;
|
||||
|
||||
ctx->vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle);
|
||||
if (IS_ERR(ctx->vm_ctx)) {
|
||||
err = PTR_ERR(ctx->vm_ctx);
|
||||
if (!ctx->vm_ctx) {
|
||||
err = -EINVAL;
|
||||
goto err_free_ctx;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ pvr_fw_trace_init_mask_set(const char *val, const struct kernel_param *kp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct kernel_param_ops pvr_fw_trace_init_mask_ops = {
|
||||
static const struct kernel_param_ops pvr_fw_trace_init_mask_ops = {
|
||||
.set = pvr_fw_trace_init_mask_set,
|
||||
.get = param_get_hexint,
|
||||
};
|
||||
|
||||
@@ -231,29 +231,26 @@ nvkm_vmm_unref_sptes(struct nvkm_vmm_iter *it, struct nvkm_vmm_pt *pgt,
|
||||
* covered by a number of LPTEs, the LPTEs once again take
|
||||
* control over their address range.
|
||||
*
|
||||
* Determine how many LPTEs need to transition state.
|
||||
* Transition each LPTE individually as each may have a
|
||||
* different target state (sparse, invalid, or valid).
|
||||
*/
|
||||
pgt->pte[ptei].s.spte_valid = false;
|
||||
for (ptes = 1, ptei++; ptei < lpti; ptes++, ptei++) {
|
||||
for (ptei++; ptei < lpti; ptei++) {
|
||||
if (pgt->pte[ptei].s.sptes)
|
||||
break;
|
||||
pgt->pte[ptei].s.spte_valid = false;
|
||||
}
|
||||
|
||||
if (pgt->pte[pteb].s.sparse) {
|
||||
TRA(it, "LPTE %05x: U -> S %d PTEs", pteb, ptes);
|
||||
pair->func->sparse(vmm, pgt->pt[0], pteb, ptes);
|
||||
} else if (!pgt->pte[pteb].s.lpte_valid) {
|
||||
if (pair->func->invalid) {
|
||||
/* If the MMU supports it, restore the LPTE to the
|
||||
* INVALID state to tell the MMU there is no point
|
||||
* trying to fetch the corresponding SPTEs.
|
||||
*/
|
||||
TRA(it, "LPTE %05x: U -> I %d PTEs", pteb, ptes);
|
||||
pair->func->invalid(vmm, pgt->pt[0], pteb, ptes);
|
||||
while (pteb < ptei) {
|
||||
pgt->pte[pteb].s.spte_valid = false;
|
||||
if (pgt->pte[pteb].s.sparse) {
|
||||
TRA(it, "LPTE %05x: U -> S", pteb);
|
||||
pair->func->sparse(vmm, pgt->pt[0], pteb, 1);
|
||||
} else if (!pgt->pte[pteb].s.lpte_valid) {
|
||||
if (pair->func->invalid) {
|
||||
TRA(it, "LPTE %05x: U -> I", pteb);
|
||||
pair->func->invalid(vmm, pgt->pt[0], pteb, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TRA(it, "LPTE %05x: V %d PTEs", pteb, ptes);
|
||||
pteb++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,19 +180,27 @@ static void test_multiple_loops(struct kunit *test)
|
||||
{
|
||||
struct drm_exec exec;
|
||||
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
|
||||
drm_exec_until_all_locked(&exec)
|
||||
{
|
||||
break;
|
||||
}
|
||||
drm_exec_fini(&exec);
|
||||
__label__ drm_exec_retry;
|
||||
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
|
||||
drm_exec_until_all_locked(&exec)
|
||||
{
|
||||
break;
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
|
||||
drm_exec_until_all_locked(&exec)
|
||||
{
|
||||
break;
|
||||
}
|
||||
drm_exec_fini(&exec);
|
||||
}
|
||||
|
||||
{
|
||||
__label__ drm_exec_retry;
|
||||
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
|
||||
drm_exec_until_all_locked(&exec)
|
||||
{
|
||||
break;
|
||||
}
|
||||
drm_exec_fini(&exec);
|
||||
}
|
||||
drm_exec_fini(&exec);
|
||||
KUNIT_SUCCEED(test);
|
||||
}
|
||||
|
||||
|
||||
@@ -495,6 +495,8 @@ v3d_get_cpu_indirect_csd_params(struct drm_file *file_priv,
|
||||
sizeof(indirect_csd.wg_uniform_offsets));
|
||||
|
||||
info->indirect = drm_gem_object_lookup(file_priv, indirect_csd.indirect);
|
||||
if (!info->indirect)
|
||||
return -ENOENT;
|
||||
|
||||
return v3d_setup_csd_jobs_and_bos(file_priv, v3d, &indirect_csd.submit,
|
||||
&info->job, &info->clean_job,
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <kunit/test-bug.h>
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/test-bug.h>
|
||||
#include <kunit/visibility.h>
|
||||
|
||||
#define PLATFORM_CASE(platform__, graphics_step__) \
|
||||
|
||||
@@ -292,13 +292,23 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
goto err_exec;
|
||||
}
|
||||
|
||||
/* Wait behind rebinds */
|
||||
/*
|
||||
* Wait behind rebinds and any kernel operations (evictions, defrag
|
||||
* moves, ...) on the VM and all external BOs. The VM's private BOs
|
||||
* carry their kernel ops in the VM dma-resv KERNEL slot, while each
|
||||
* external BO carries them in its own dma-resv KERNEL slot; both are
|
||||
* covered by iterating every object locked by the exec, mirroring the
|
||||
* drm_gpuvm_resv_add_fence() below.
|
||||
*/
|
||||
if (!xe_vm_in_lr_mode(vm)) {
|
||||
err = xe_sched_job_add_deps(job,
|
||||
xe_vm_resv(vm),
|
||||
DMA_RESV_USAGE_KERNEL);
|
||||
if (err)
|
||||
goto err_put_job;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
drm_exec_for_each_locked_object(exec, obj) {
|
||||
err = xe_sched_job_add_deps(job, obj->resv,
|
||||
DMA_RESV_USAGE_KERNEL);
|
||||
if (err)
|
||||
goto err_put_job;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_syncs && !err; i++)
|
||||
|
||||
@@ -1026,12 +1026,22 @@ xe_vm_populate_pgtable(struct xe_migrate_pt_update *pt_update, struct xe_tile *t
|
||||
u64 *ptr = data;
|
||||
u32 i;
|
||||
|
||||
/*
|
||||
* @qword_ofs is the absolute entry offset within the page table, while
|
||||
* @ptes is indexed relative to @update->ofs (its first entry). The GPU
|
||||
* path (write_pgtable) splits a single update into MAX_PTE_PER_SDI-sized
|
||||
* chunks, calling this with an advancing @qword_ofs but a fresh @data
|
||||
* pointer per chunk, so translate back into a @ptes index rather than
|
||||
* assuming the chunk starts at ptes[0].
|
||||
*/
|
||||
for (i = 0; i < num_qwords; i++) {
|
||||
u32 idx = qword_ofs - update->ofs + i;
|
||||
|
||||
if (map)
|
||||
xe_map_wr(tile_to_xe(tile), map, (qword_ofs + i) *
|
||||
sizeof(u64), u64, ptes[i].pte);
|
||||
sizeof(u64), u64, ptes[idx].pte);
|
||||
else
|
||||
ptr[i] = ptes[i].pte;
|
||||
ptr[i] = ptes[idx].pte;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1408,6 +1418,7 @@ static int xe_pt_pre_commit(struct xe_migrate_pt_update *pt_update)
|
||||
pt_update_ops, rftree);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_GPUSVM)
|
||||
/*
|
||||
* Acquire/release the svm notifier_lock around xe_pt_svm_userptr_pre_commit()
|
||||
* and the matching late release in xe_pt_update_ops_run(). Read mode by
|
||||
@@ -1434,6 +1445,10 @@ static void xe_pt_svm_userptr_notifier_unlock(struct xe_vm *vm)
|
||||
xe_svm_notifier_unlock(vm);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline void xe_pt_svm_userptr_notifier_lock(struct xe_vm *vm) { }
|
||||
static inline void xe_pt_svm_userptr_notifier_unlock(struct xe_vm *vm) { }
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_GPUSVM)
|
||||
#ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT
|
||||
|
||||
@@ -643,7 +643,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
|
||||
xe_device_is_l2_flush_optimized(xe) &&
|
||||
(pat_index != 19 && coh_mode != XE_COH_2WAY))) {
|
||||
err = -EINVAL;
|
||||
goto madv_fini;
|
||||
goto free_vmas;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,17 +101,6 @@ drm_exec_obj(struct drm_exec *exec, unsigned long index)
|
||||
#define drm_exec_for_each_locked_object_reverse(exec, obj) \
|
||||
__drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec))
|
||||
|
||||
/*
|
||||
* Helper to drm_exec_until_all_locked(). Don't use directly.
|
||||
*
|
||||
* Since labels can't be defined local to the loop's body we use a jump pointer
|
||||
* to make sure that the retry is only used from within the loop's body.
|
||||
*/
|
||||
#define __drm_exec_until_all_locked(exec, _label) \
|
||||
_label: \
|
||||
for (void *const __maybe_unused __drm_exec_retry_ptr = &&_label; \
|
||||
drm_exec_cleanup(exec);)
|
||||
|
||||
/**
|
||||
* drm_exec_until_all_locked - loop until all GEM objects are locked
|
||||
* @exec: drm_exec object
|
||||
@@ -119,9 +108,18 @@ _label: \
|
||||
* Core functionality of the drm_exec object. Loops until all GEM objects are
|
||||
* locked and no more contention exists. At the beginning of the loop it is
|
||||
* guaranteed that no GEM object is locked.
|
||||
*
|
||||
* A global label name drm_exec_retry is used, if you need to use more than one
|
||||
* instance of this macro in the same function the label needs to be made local
|
||||
* to the block with the __label__ keyword.
|
||||
*/
|
||||
#define drm_exec_until_all_locked(exec) \
|
||||
__drm_exec_until_all_locked(exec, __UNIQUE_ID(drm_exec))
|
||||
for (bool const __maybe_unused __drm_exec_loop = false; \
|
||||
drm_exec_cleanup(exec);) \
|
||||
if (false) { \
|
||||
drm_exec_retry: __maybe_unused; \
|
||||
continue; \
|
||||
} else
|
||||
|
||||
/**
|
||||
* drm_exec_retry_on_contention - restart the loop to grap all locks
|
||||
@@ -129,12 +127,14 @@ _label: \
|
||||
*
|
||||
* Control flow helper to continue when a contention was detected and we need to
|
||||
* clean up and re-start the loop to prepare all GEM objects.
|
||||
* The __drm_exec_loop check exists to prevent usage outside of an
|
||||
* drm_exec_until_all_locked() loop.
|
||||
*/
|
||||
#define drm_exec_retry_on_contention(exec) \
|
||||
do { \
|
||||
if (unlikely(drm_exec_is_contended(exec))) \
|
||||
goto *__drm_exec_retry_ptr; \
|
||||
} while (0)
|
||||
goto drm_exec_retry; \
|
||||
} while (__drm_exec_loop)
|
||||
|
||||
/**
|
||||
* drm_exec_is_contended - check for contention
|
||||
@@ -154,12 +154,14 @@ static inline bool drm_exec_is_contended(struct drm_exec *exec)
|
||||
*
|
||||
* Unconditionally retry the loop to lock all objects. For consistency,
|
||||
* the exec object needs to be newly initialized.
|
||||
* The __drm_exec_loop check exists to prevent usage outside of an
|
||||
* drm_exec_until_all_locked() loop.
|
||||
*/
|
||||
#define drm_exec_retry(_exec) \
|
||||
do { \
|
||||
WARN_ON((_exec)->contended != DRM_EXEC_DUMMY); \
|
||||
goto *__drm_exec_retry_ptr; \
|
||||
} while (0)
|
||||
goto drm_exec_retry; \
|
||||
} while (__drm_exec_loop)
|
||||
|
||||
/**
|
||||
* drm_exec_ticket - return the ww_acquire_ctx for this exec context
|
||||
|
||||
Reference in New Issue
Block a user