mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
drm fixes for 6.8-rc2
fb: - fix simpledrm/i915 regression by reverting change scheduler: - fix regression affecting amdgpu users due to sched draining nouveau: - revert 6.7 deadlock fix as it has side effects dp: - fix documentation warning ttm: - fix dummy page read on some platforms bridge: - anx7625 suspend fix - sii902x: fix probing and audio registration - parade-ps8640: fix suspend of bridge, aux fixes - samsung-dsim: avoid using FORCE_STOP_STATE panel: - simple add missing bus flags - fix samsung-s6d7aa0 flags amdgpu: - AC/DC power supply tracking fix - Don't show invalid vram vendor data - SMU 13.0.x fixes - GART fix for umr on systems without VRAM - GFX 10/11 UNORD_DISPATCH fixes - IPS display fixes (required for S0ix on some platforms) - Misc fixes i915: - DSI sequence revert to fix GitLab #10071 and DP test-pattern fix - Drop -Wstringop-overflow (broken on GCC11) ivpu: - fix recovery/reset support - improve submit ioctl stability - fix dev open/close races on unbind - PLL disable reset fix - deprecate context priority param - improve debug buffer logging - disable buffer sharing across VPU contexts - free buffer sgt on unbind - fix missing lock around shmem vmap - add better boot diagnostics - add more debug prints around mapping - dump MMU events in case of timeout v3d: - NULL ptr dereference fix exynos: - fix stack usage - fix incorrect type - fix dt typo - fix gsc runtime resume xe: - Make an ops struct static - Fix an implicit 0 to NULL conversion - A couple of 32-bit fixes - A migration coherency fix for Lunar Lake. - An error path vm id leak fix - Remove PVC references in kunit tests -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmWz/lsACgkQDHTzWXnE hr4m2Q/8DB5XlLPXQCW7xGwS6H546xItKZv32VxnqChl2qG7CIzLpqO1ZTQm8OtW QSE5Xc1kBG2qZeWV5vvtRn3wtwejgzIMBg1KUkDUXllAHGhifZfzti4J8muWXLIx ioL4pWefwnq/bhL4F0IzN7j1qSxxR0UyL/0WORvCjIIVBVG/QJpHbpM5gX/00qQE APPLJrrU+2dnAEHlKzFwCkp9bR1b2Tf6yRRh7p1gbLjkYS8rfy36BWFYdP6JC/a3 EU1tPclLVJomt9rfPjhB33lD8DpBVGxi2cDjquMmrgLNPIuaOdD3Lk/awe7TKfiF g/ECLojJCIr50268cZ5X6Q1RvZZrbcorcG6EX2JzkP4sKI6fsc6XVPhtfXj59ysR jIRUp5eMKZPLF/FS2g68jFFos2HcNqopezNmo1pM/kT1FMT4k0N93PlW+Zr+Uhxx BEA2OsdCEXCwJLaLCXiRQkgpsvqyeRy7jK28J7CaY22bJFaRtGyzeSEcSrNb+nGI y+1Qqgy/7cSP4+yC7uOtytm/e20zzLt3lOsDPK3atHKa1X/HuWtm1gX2U4sGl9+A DChn2p5Xdl10SOt+f346kNGuJict59TGDsXD6ETsbmFG49VRZEzGhoSLZ7UYl90G NUBPS8dc6ctQnsLnOZ1iyp3NZxOGm+jLEPXb76Wt2sJPw4KBP1A= =eZEy -----END PGP SIGNATURE----- Merge tag 'drm-fixes-2024-01-27' of git://anongit.freedesktop.org/drm/drm Pull drm fixes from Dave Airlie: "Lots going on for rc2, ivpu has a bunch of stabilisation and debugging work, then amdgpu and xe are the main fixes. i915, exynos have a few, then some misc panel and bridge fixes. Worth mentioning are three regressions. One of the nouveau fixes in 6.7 for a serious deadlock had side effects, so I guess we will bring back the deadlock until I can figure out what should be done properly. There was a scheduler regression vs amdgpu which was reported in a few places and is now fixed. There was an i915 vs simpledrm problem resulting in black screens, that is reverted also. I'll be working on a proper nouveau fix, it kinda looks like one of those cases where someone tried to use an atomic where they should have probably used a lock, but I'll see. fb: - fix simpledrm/i915 regression by reverting change scheduler: - fix regression affecting amdgpu users due to sched draining nouveau: - revert 6.7 deadlock fix as it has side effects dp: - fix documentation warning ttm: - fix dummy page read on some platforms bridge: - anx7625 suspend fix - sii902x: fix probing and audio registration - parade-ps8640: fix suspend of bridge, aux fixes - samsung-dsim: avoid using FORCE_STOP_STATE panel: - simple add missing bus flags - fix samsung-s6d7aa0 flags amdgpu: - AC/DC power supply tracking fix - Don't show invalid vram vendor data - SMU 13.0.x fixes - GART fix for umr on systems without VRAM - GFX 10/11 UNORD_DISPATCH fixes - IPS display fixes (required for S0ix on some platforms) - Misc fixes i915: - DSI sequence revert to fix GitLab #10071 and DP test-pattern fix - Drop -Wstringop-overflow (broken on GCC11) ivpu: - fix recovery/reset support - improve submit ioctl stability - fix dev open/close races on unbind - PLL disable reset fix - deprecate context priority param - improve debug buffer logging - disable buffer sharing across VPU contexts - free buffer sgt on unbind - fix missing lock around shmem vmap - add better boot diagnostics - add more debug prints around mapping - dump MMU events in case of timeout v3d: - NULL ptr dereference fix exynos: - fix stack usage - fix incorrect type - fix dt typo - fix gsc runtime resume xe: - Make an ops struct static - Fix an implicit 0 to NULL conversion - A couple of 32-bit fixes - A migration coherency fix for Lunar Lake. - An error path vm id leak fix - Remove PVC references in kunit tests" * tag 'drm-fixes-2024-01-27' of git://anongit.freedesktop.org/drm/drm: (66 commits) Revert "nouveau: push event block/allowing out of the fence context" drm: bridge: samsung-dsim: Don't use FORCE_STOP_STATE drm/sched: Drain all entities in DRM sched run job worker drm/amd/display: "Enable IPS by default" drm/amd: Add a DC debug mask for IPS drm/amd/display: Disable ips before dc interrupt setting drm/amd/display: Replay + IPS + ABM in Full Screen VPB drm/amd/display: Add IPS checks before dcn register access drm/amd/display: Add Replay IPS register for DMUB command table drm/amd/display: Allow IPS2 during Replay drm/amdgpu/gfx11: set UNORD_DISPATCH in compute MQDs drm/amdgpu/gfx10: set UNORD_DISPATCH in compute MQDs drm/amd/amdgpu: Assign GART pages to AMD device mapping drm/amd/pm: Fetch current power limit from FW drm/amdgpu: Fix null pointer dereference drm/amdgpu: Show vram vendor only if available drm/amd/pm: update the power cap setting drm/amdgpu: Avoid fetching vram vendor information drm/amdgpu/pm: Fix the power source flag error drm/amd/display: Fix uninitialized variable usage in core_link_ 'read_dpcd() & write_dpcd()' functions ...
This commit is contained in:
commit
168174d781
@ -85,7 +85,7 @@ allOf:
|
||||
clocks:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
regs:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
@ -99,7 +99,7 @@ allOf:
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
regs:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
@ -116,7 +116,7 @@ allOf:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
regs:
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
|
||||
|
@ -102,7 +102,7 @@ static int reset_pending_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct ivpu_device *vdev = seq_to_ivpu(s);
|
||||
|
||||
seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset));
|
||||
seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_pending));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -130,7 +130,9 @@ dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size
|
||||
|
||||
fw->dvfs_mode = dvfs_mode;
|
||||
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -190,7 +192,10 @@ fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf,
|
||||
return ret;
|
||||
|
||||
ivpu_hw_profiling_freq_drive(vdev, enable);
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
|
||||
ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -301,11 +306,18 @@ static ssize_t
|
||||
ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos)
|
||||
{
|
||||
struct ivpu_device *vdev = file->private_data;
|
||||
int ret;
|
||||
|
||||
if (!size)
|
||||
return -EINVAL;
|
||||
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ret = ivpu_rpm_get(vdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ivpu_pm_trigger_recovery(vdev, "debugfs");
|
||||
flush_work(&vdev->pm->recovery_work);
|
||||
ivpu_rpm_put(vdev);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_accel.h>
|
||||
#include <drm/drm_file.h>
|
||||
@ -17,6 +18,7 @@
|
||||
#include "ivpu_debugfs.h"
|
||||
#include "ivpu_drv.h"
|
||||
#include "ivpu_fw.h"
|
||||
#include "ivpu_fw_log.h"
|
||||
#include "ivpu_gem.h"
|
||||
#include "ivpu_hw.h"
|
||||
#include "ivpu_ipc.h"
|
||||
@ -65,22 +67,20 @@ struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
|
||||
return file_priv;
|
||||
}
|
||||
|
||||
struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id)
|
||||
static void file_priv_unbind(struct ivpu_device *vdev, struct ivpu_file_priv *file_priv)
|
||||
{
|
||||
struct ivpu_file_priv *file_priv;
|
||||
mutex_lock(&file_priv->lock);
|
||||
if (file_priv->bound) {
|
||||
ivpu_dbg(vdev, FILE, "file_priv unbind: ctx %u\n", file_priv->ctx.id);
|
||||
|
||||
xa_lock_irq(&vdev->context_xa);
|
||||
file_priv = xa_load(&vdev->context_xa, id);
|
||||
/* file_priv may still be in context_xa during file_priv_release() */
|
||||
if (file_priv && !kref_get_unless_zero(&file_priv->ref))
|
||||
file_priv = NULL;
|
||||
xa_unlock_irq(&vdev->context_xa);
|
||||
|
||||
if (file_priv)
|
||||
ivpu_dbg(vdev, KREF, "file_priv get by id: ctx %u refcount %u\n",
|
||||
file_priv->ctx.id, kref_read(&file_priv->ref));
|
||||
|
||||
return file_priv;
|
||||
ivpu_cmdq_release_all_locked(file_priv);
|
||||
ivpu_jsm_context_release(vdev, file_priv->ctx.id);
|
||||
ivpu_bo_unbind_all_bos_from_context(vdev, &file_priv->ctx);
|
||||
ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
|
||||
file_priv->bound = false;
|
||||
drm_WARN_ON(&vdev->drm, !xa_erase_irq(&vdev->context_xa, file_priv->ctx.id));
|
||||
}
|
||||
mutex_unlock(&file_priv->lock);
|
||||
}
|
||||
|
||||
static void file_priv_release(struct kref *ref)
|
||||
@ -88,13 +88,15 @@ static void file_priv_release(struct kref *ref)
|
||||
struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
|
||||
struct ivpu_device *vdev = file_priv->vdev;
|
||||
|
||||
ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id);
|
||||
ivpu_dbg(vdev, FILE, "file_priv release: ctx %u bound %d\n",
|
||||
file_priv->ctx.id, (bool)file_priv->bound);
|
||||
|
||||
pm_runtime_get_sync(vdev->drm.dev);
|
||||
mutex_lock(&vdev->context_list_lock);
|
||||
file_priv_unbind(vdev, file_priv);
|
||||
mutex_unlock(&vdev->context_list_lock);
|
||||
pm_runtime_put_autosuspend(vdev->drm.dev);
|
||||
|
||||
ivpu_cmdq_release_all(file_priv);
|
||||
ivpu_jsm_context_release(vdev, file_priv->ctx.id);
|
||||
ivpu_bo_remove_all_bos_from_context(vdev, &file_priv->ctx);
|
||||
ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
|
||||
drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv);
|
||||
mutex_destroy(&file_priv->lock);
|
||||
kfree(file_priv);
|
||||
}
|
||||
@ -176,9 +178,6 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
|
||||
case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
|
||||
args->value = vdev->hw->ranges.user.start;
|
||||
break;
|
||||
case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
|
||||
args->value = file_priv->priority;
|
||||
break;
|
||||
case DRM_IVPU_PARAM_CONTEXT_ID:
|
||||
args->value = file_priv->ctx.id;
|
||||
break;
|
||||
@ -218,17 +217,10 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
|
||||
|
||||
static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
{
|
||||
struct ivpu_file_priv *file_priv = file->driver_priv;
|
||||
struct drm_ivpu_param *args = data;
|
||||
int ret = 0;
|
||||
|
||||
switch (args->param) {
|
||||
case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
|
||||
if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME)
|
||||
file_priv->priority = args->value;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
@ -241,50 +233,53 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file)
|
||||
struct ivpu_device *vdev = to_ivpu_device(dev);
|
||||
struct ivpu_file_priv *file_priv;
|
||||
u32 ctx_id;
|
||||
void *old;
|
||||
int ret;
|
||||
int idx, ret;
|
||||
|
||||
ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (!drm_dev_enter(dev, &idx))
|
||||
return -ENODEV;
|
||||
|
||||
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
|
||||
if (!file_priv) {
|
||||
ret = -ENOMEM;
|
||||
goto err_xa_erase;
|
||||
goto err_dev_exit;
|
||||
}
|
||||
|
||||
file_priv->vdev = vdev;
|
||||
file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
|
||||
file_priv->bound = true;
|
||||
kref_init(&file_priv->ref);
|
||||
mutex_init(&file_priv->lock);
|
||||
|
||||
mutex_lock(&vdev->context_list_lock);
|
||||
|
||||
ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, file_priv,
|
||||
vdev->context_xa_limit, GFP_KERNEL);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id);
|
||||
if (ret)
|
||||
goto err_mutex_destroy;
|
||||
goto err_xa_erase;
|
||||
|
||||
old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL);
|
||||
if (xa_is_err(old)) {
|
||||
ret = xa_err(old);
|
||||
ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret);
|
||||
goto err_ctx_fini;
|
||||
}
|
||||
mutex_unlock(&vdev->context_list_lock);
|
||||
drm_dev_exit(idx);
|
||||
|
||||
file->driver_priv = file_priv;
|
||||
|
||||
ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n",
|
||||
ctx_id, current->comm, task_pid_nr(current));
|
||||
|
||||
file->driver_priv = file_priv;
|
||||
return 0;
|
||||
|
||||
err_ctx_fini:
|
||||
ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
|
||||
err_mutex_destroy:
|
||||
mutex_destroy(&file_priv->lock);
|
||||
kfree(file_priv);
|
||||
err_xa_erase:
|
||||
xa_erase_irq(&vdev->context_xa, ctx_id);
|
||||
err_unlock:
|
||||
mutex_unlock(&vdev->context_list_lock);
|
||||
mutex_destroy(&file_priv->lock);
|
||||
kfree(file_priv);
|
||||
err_dev_exit:
|
||||
drm_dev_exit(idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -340,8 +335,6 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev)
|
||||
|
||||
if (!ret)
|
||||
ivpu_dbg(vdev, PM, "VPU ready message received successfully\n");
|
||||
else
|
||||
ivpu_hw_diagnose_failure(vdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -369,6 +362,9 @@ int ivpu_boot(struct ivpu_device *vdev)
|
||||
ret = ivpu_wait_for_ready(vdev);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret);
|
||||
ivpu_hw_diagnose_failure(vdev);
|
||||
ivpu_mmu_evtq_dump(vdev);
|
||||
ivpu_fw_log_dump(vdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -540,6 +536,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
|
||||
lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key);
|
||||
INIT_LIST_HEAD(&vdev->bo_list);
|
||||
|
||||
ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock);
|
||||
if (ret)
|
||||
goto err_xa_destroy;
|
||||
|
||||
ret = drmm_mutex_init(&vdev->drm, &vdev->bo_list_lock);
|
||||
if (ret)
|
||||
goto err_xa_destroy;
|
||||
@ -611,14 +611,30 @@ err_xa_destroy:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev)
|
||||
{
|
||||
struct ivpu_file_priv *file_priv;
|
||||
unsigned long ctx_id;
|
||||
|
||||
mutex_lock(&vdev->context_list_lock);
|
||||
|
||||
xa_for_each(&vdev->context_xa, ctx_id, file_priv)
|
||||
file_priv_unbind(vdev, file_priv);
|
||||
|
||||
mutex_unlock(&vdev->context_list_lock);
|
||||
}
|
||||
|
||||
static void ivpu_dev_fini(struct ivpu_device *vdev)
|
||||
{
|
||||
ivpu_pm_disable(vdev);
|
||||
ivpu_shutdown(vdev);
|
||||
if (IVPU_WA(d3hot_after_power_off))
|
||||
pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot);
|
||||
|
||||
ivpu_jobs_abort_all(vdev);
|
||||
ivpu_job_done_consumer_fini(vdev);
|
||||
ivpu_pm_cancel_recovery(vdev);
|
||||
ivpu_bo_unbind_all_user_contexts(vdev);
|
||||
|
||||
ivpu_ipc_fini(vdev);
|
||||
ivpu_fw_fini(vdev);
|
||||
|
@ -56,6 +56,7 @@
|
||||
#define IVPU_DBG_JSM BIT(10)
|
||||
#define IVPU_DBG_KREF BIT(11)
|
||||
#define IVPU_DBG_RPM BIT(12)
|
||||
#define IVPU_DBG_MMU_MAP BIT(13)
|
||||
|
||||
#define ivpu_err(vdev, fmt, ...) \
|
||||
drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
|
||||
@ -114,6 +115,7 @@ struct ivpu_device {
|
||||
|
||||
struct ivpu_mmu_context gctx;
|
||||
struct ivpu_mmu_context rctx;
|
||||
struct mutex context_list_lock; /* Protects user context addition/removal */
|
||||
struct xarray context_xa;
|
||||
struct xa_limit context_xa_limit;
|
||||
|
||||
@ -145,8 +147,8 @@ struct ivpu_file_priv {
|
||||
struct mutex lock; /* Protects cmdq */
|
||||
struct ivpu_cmdq *cmdq[IVPU_NUM_ENGINES];
|
||||
struct ivpu_mmu_context ctx;
|
||||
u32 priority;
|
||||
bool has_mmu_faults;
|
||||
bool bound;
|
||||
};
|
||||
|
||||
extern int ivpu_dbg_mask;
|
||||
@ -162,7 +164,6 @@ extern bool ivpu_disable_mmu_cont_pages;
|
||||
extern int ivpu_test_mode;
|
||||
|
||||
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv);
|
||||
struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id);
|
||||
void ivpu_file_priv_put(struct ivpu_file_priv **link);
|
||||
|
||||
int ivpu_boot(struct ivpu_device *vdev);
|
||||
|
@ -24,14 +24,11 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs;
|
||||
|
||||
static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action)
|
||||
{
|
||||
if (bo->ctx)
|
||||
ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n",
|
||||
action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt,
|
||||
bo->handle, bo->ctx->id, bo->vpu_addr, bo->mmu_mapped);
|
||||
else
|
||||
ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n",
|
||||
action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt,
|
||||
bo->handle);
|
||||
ivpu_dbg(vdev, BO,
|
||||
"%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n",
|
||||
action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0,
|
||||
(bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc,
|
||||
(bool)bo->base.base.import_attach);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -49,12 +46,7 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo)
|
||||
mutex_lock(&bo->lock);
|
||||
|
||||
ivpu_dbg_bo(vdev, bo, "pin");
|
||||
|
||||
if (!bo->ctx) {
|
||||
ivpu_err(vdev, "vpu_addr not allocated for BO %d\n", bo->handle);
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
drm_WARN_ON(&vdev->drm, !bo->ctx);
|
||||
|
||||
if (!bo->mmu_mapped) {
|
||||
struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
|
||||
@ -85,7 +77,10 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
|
||||
const struct ivpu_addr_range *range)
|
||||
{
|
||||
struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
|
||||
int ret;
|
||||
int idx, ret;
|
||||
|
||||
if (!drm_dev_enter(&vdev->drm, &idx))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&bo->lock);
|
||||
|
||||
@ -101,6 +96,8 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
|
||||
|
||||
mutex_unlock(&bo->lock);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -108,11 +105,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
|
||||
{
|
||||
struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
|
||||
|
||||
lockdep_assert_held(&bo->lock);
|
||||
|
||||
ivpu_dbg_bo(vdev, bo, "unbind");
|
||||
|
||||
/* TODO: dma_unmap */
|
||||
lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount));
|
||||
|
||||
if (bo->mmu_mapped) {
|
||||
drm_WARN_ON(&vdev->drm, !bo->ctx);
|
||||
@ -124,19 +117,23 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
|
||||
|
||||
if (bo->ctx) {
|
||||
ivpu_mmu_context_remove_node(bo->ctx, &bo->mm_node);
|
||||
bo->vpu_addr = 0;
|
||||
bo->ctx = NULL;
|
||||
}
|
||||
|
||||
if (bo->base.base.import_attach)
|
||||
return;
|
||||
|
||||
dma_resv_lock(bo->base.base.resv, NULL);
|
||||
if (bo->base.sgt) {
|
||||
dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0);
|
||||
sg_free_table(bo->base.sgt);
|
||||
kfree(bo->base.sgt);
|
||||
bo->base.sgt = NULL;
|
||||
}
|
||||
dma_resv_unlock(bo->base.base.resv);
|
||||
}
|
||||
|
||||
static void ivpu_bo_unbind(struct ivpu_bo *bo)
|
||||
{
|
||||
mutex_lock(&bo->lock);
|
||||
ivpu_bo_unbind_locked(bo);
|
||||
mutex_unlock(&bo->lock);
|
||||
}
|
||||
|
||||
void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx)
|
||||
void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx)
|
||||
{
|
||||
struct ivpu_bo *bo;
|
||||
|
||||
@ -146,8 +143,10 @@ void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m
|
||||
mutex_lock(&vdev->bo_list_lock);
|
||||
list_for_each_entry(bo, &vdev->bo_list, bo_list_node) {
|
||||
mutex_lock(&bo->lock);
|
||||
if (bo->ctx == ctx)
|
||||
if (bo->ctx == ctx) {
|
||||
ivpu_dbg_bo(vdev, bo, "unbind");
|
||||
ivpu_bo_unbind_locked(bo);
|
||||
}
|
||||
mutex_unlock(&bo->lock);
|
||||
}
|
||||
mutex_unlock(&vdev->bo_list_lock);
|
||||
@ -199,9 +198,6 @@ ivpu_bo_create(struct ivpu_device *vdev, u64 size, u32 flags)
|
||||
list_add_tail(&bo->bo_list_node, &vdev->bo_list);
|
||||
mutex_unlock(&vdev->bo_list_lock);
|
||||
|
||||
ivpu_dbg(vdev, BO, "create: vpu_addr 0x%llx size %zu flags 0x%x\n",
|
||||
bo->vpu_addr, bo->base.base.size, flags);
|
||||
|
||||
return bo;
|
||||
}
|
||||
|
||||
@ -212,6 +208,12 @@ static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file)
|
||||
struct ivpu_bo *bo = to_ivpu_bo(obj);
|
||||
struct ivpu_addr_range *range;
|
||||
|
||||
if (bo->ctx) {
|
||||
ivpu_warn(vdev, "Can't add BO to ctx %u: already in ctx %u\n",
|
||||
file_priv->ctx.id, bo->ctx->id);
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
if (bo->flags & DRM_IVPU_BO_SHAVE_MEM)
|
||||
range = &vdev->hw->ranges.shave;
|
||||
else if (bo->flags & DRM_IVPU_BO_DMA_MEM)
|
||||
@ -227,62 +229,24 @@ static void ivpu_bo_free(struct drm_gem_object *obj)
|
||||
struct ivpu_device *vdev = to_ivpu_device(obj->dev);
|
||||
struct ivpu_bo *bo = to_ivpu_bo(obj);
|
||||
|
||||
ivpu_dbg_bo(vdev, bo, "free");
|
||||
|
||||
mutex_lock(&vdev->bo_list_lock);
|
||||
list_del(&bo->bo_list_node);
|
||||
mutex_unlock(&vdev->bo_list_lock);
|
||||
|
||||
drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ));
|
||||
|
||||
ivpu_dbg_bo(vdev, bo, "free");
|
||||
|
||||
ivpu_bo_unbind(bo);
|
||||
ivpu_bo_unbind_locked(bo);
|
||||
mutex_destroy(&bo->lock);
|
||||
|
||||
drm_WARN_ON(obj->dev, bo->base.pages_use_count > 1);
|
||||
drm_gem_shmem_free(&bo->base);
|
||||
}
|
||||
|
||||
static const struct dma_buf_ops ivpu_bo_dmabuf_ops = {
|
||||
.cache_sgt_mapping = true,
|
||||
.attach = drm_gem_map_attach,
|
||||
.detach = drm_gem_map_detach,
|
||||
.map_dma_buf = drm_gem_map_dma_buf,
|
||||
.unmap_dma_buf = drm_gem_unmap_dma_buf,
|
||||
.release = drm_gem_dmabuf_release,
|
||||
.mmap = drm_gem_dmabuf_mmap,
|
||||
.vmap = drm_gem_dmabuf_vmap,
|
||||
.vunmap = drm_gem_dmabuf_vunmap,
|
||||
};
|
||||
|
||||
static struct dma_buf *ivpu_bo_export(struct drm_gem_object *obj, int flags)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct dma_buf_export_info exp_info = {
|
||||
.exp_name = KBUILD_MODNAME,
|
||||
.owner = dev->driver->fops->owner,
|
||||
.ops = &ivpu_bo_dmabuf_ops,
|
||||
.size = obj->size,
|
||||
.flags = flags,
|
||||
.priv = obj,
|
||||
.resv = obj->resv,
|
||||
};
|
||||
void *sgt;
|
||||
|
||||
/*
|
||||
* Make sure that pages are allocated and dma-mapped before exporting the bo.
|
||||
* DMA-mapping is required if the bo will be imported to the same device.
|
||||
*/
|
||||
sgt = drm_gem_shmem_get_pages_sgt(to_drm_gem_shmem_obj(obj));
|
||||
if (IS_ERR(sgt))
|
||||
return sgt;
|
||||
|
||||
return drm_gem_dmabuf_export(dev, &exp_info);
|
||||
}
|
||||
|
||||
static const struct drm_gem_object_funcs ivpu_gem_funcs = {
|
||||
.free = ivpu_bo_free,
|
||||
.open = ivpu_bo_open,
|
||||
.export = ivpu_bo_export,
|
||||
.print_info = drm_gem_shmem_object_print_info,
|
||||
.pin = drm_gem_shmem_object_pin,
|
||||
.unpin = drm_gem_shmem_object_unpin,
|
||||
@ -315,11 +279,9 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
|
||||
return PTR_ERR(bo);
|
||||
}
|
||||
|
||||
ret = drm_gem_handle_create(file, &bo->base.base, &bo->handle);
|
||||
if (!ret) {
|
||||
ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
|
||||
if (!ret)
|
||||
args->vpu_addr = bo->vpu_addr;
|
||||
args->handle = bo->handle;
|
||||
}
|
||||
|
||||
drm_gem_object_put(&bo->base.base);
|
||||
|
||||
@ -361,7 +323,9 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla
|
||||
if (ret)
|
||||
goto err_put;
|
||||
|
||||
dma_resv_lock(bo->base.base.resv, NULL);
|
||||
ret = drm_gem_shmem_vmap(&bo->base, &map);
|
||||
dma_resv_unlock(bo->base.base.resv);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
|
||||
@ -376,7 +340,10 @@ void ivpu_bo_free_internal(struct ivpu_bo *bo)
|
||||
{
|
||||
struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr);
|
||||
|
||||
dma_resv_lock(bo->base.base.resv, NULL);
|
||||
drm_gem_shmem_vunmap(&bo->base, &map);
|
||||
dma_resv_unlock(bo->base.base.resv);
|
||||
|
||||
drm_gem_object_put(&bo->base.base);
|
||||
}
|
||||
|
||||
@ -432,19 +399,11 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file
|
||||
|
||||
static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p)
|
||||
{
|
||||
unsigned long dma_refcount = 0;
|
||||
|
||||
mutex_lock(&bo->lock);
|
||||
|
||||
if (bo->base.base.dma_buf && bo->base.base.dma_buf->file)
|
||||
dma_refcount = atomic_long_read(&bo->base.base.dma_buf->file->f_count);
|
||||
|
||||
drm_printf(p, "%-3u %-6d 0x%-12llx %-10lu 0x%-8x %-4u %-8lu",
|
||||
bo->ctx->id, bo->handle, bo->vpu_addr, bo->base.base.size,
|
||||
bo->flags, kref_read(&bo->base.base.refcount), dma_refcount);
|
||||
|
||||
if (bo->base.base.import_attach)
|
||||
drm_printf(p, " imported");
|
||||
drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u",
|
||||
bo, bo->ctx->id, bo->vpu_addr, bo->base.base.size,
|
||||
bo->flags, kref_read(&bo->base.base.refcount));
|
||||
|
||||
if (bo->base.pages)
|
||||
drm_printf(p, " has_pages");
|
||||
@ -452,6 +411,9 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p)
|
||||
if (bo->mmu_mapped)
|
||||
drm_printf(p, " mmu_mapped");
|
||||
|
||||
if (bo->base.base.import_attach)
|
||||
drm_printf(p, " imported");
|
||||
|
||||
drm_printf(p, "\n");
|
||||
|
||||
mutex_unlock(&bo->lock);
|
||||
@ -462,8 +424,8 @@ void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p)
|
||||
struct ivpu_device *vdev = to_ivpu_device(dev);
|
||||
struct ivpu_bo *bo;
|
||||
|
||||
drm_printf(p, "%-3s %-6s %-14s %-10s %-10s %-4s %-8s %s\n",
|
||||
"ctx", "handle", "vpu_addr", "size", "flags", "refs", "dma_refs", "attribs");
|
||||
drm_printf(p, "%-9s %-3s %-14s %-10s %-10s %-4s %s\n",
|
||||
"bo", "ctx", "vpu_addr", "size", "flags", "refs", "attribs");
|
||||
|
||||
mutex_lock(&vdev->bo_list_lock);
|
||||
list_for_each_entry(bo, &vdev->bo_list, bo_list_node)
|
||||
|
@ -19,14 +19,13 @@ struct ivpu_bo {
|
||||
|
||||
struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */
|
||||
u64 vpu_addr;
|
||||
u32 handle;
|
||||
u32 flags;
|
||||
u32 job_status; /* Valid only for command buffer */
|
||||
bool mmu_mapped;
|
||||
};
|
||||
|
||||
int ivpu_bo_pin(struct ivpu_bo *bo);
|
||||
void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx);
|
||||
void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx);
|
||||
|
||||
struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size);
|
||||
struct ivpu_bo *ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags);
|
||||
|
@ -875,24 +875,18 @@ static void ivpu_hw_37xx_irq_disable(struct ivpu_device *vdev)
|
||||
|
||||
static void ivpu_hw_37xx_irq_wdt_nce_handler(struct ivpu_device *vdev)
|
||||
{
|
||||
ivpu_err_ratelimited(vdev, "WDT NCE irq\n");
|
||||
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ");
|
||||
}
|
||||
|
||||
static void ivpu_hw_37xx_irq_wdt_mss_handler(struct ivpu_device *vdev)
|
||||
{
|
||||
ivpu_err_ratelimited(vdev, "WDT MSS irq\n");
|
||||
|
||||
ivpu_hw_wdt_disable(vdev);
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ");
|
||||
}
|
||||
|
||||
static void ivpu_hw_37xx_irq_noc_firewall_handler(struct ivpu_device *vdev)
|
||||
{
|
||||
ivpu_err_ratelimited(vdev, "NOC Firewall irq\n");
|
||||
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ");
|
||||
}
|
||||
|
||||
/* Handler for IRQs from VPU core (irqV) */
|
||||
@ -970,7 +964,7 @@ static bool ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq)
|
||||
REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status);
|
||||
|
||||
if (schedule_recovery)
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -746,7 +746,7 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ivpu_hw_40xx_reset(struct ivpu_device *vdev)
|
||||
static int ivpu_hw_40xx_ip_reset(struct ivpu_device *vdev)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
@ -768,6 +768,23 @@ static int ivpu_hw_40xx_reset(struct ivpu_device *vdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ivpu_hw_40xx_reset(struct ivpu_device *vdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ivpu_hw_40xx_ip_reset(vdev)) {
|
||||
ivpu_err(vdev, "Failed to reset VPU IP\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
if (ivpu_pll_disable(vdev)) {
|
||||
ivpu_err(vdev, "Failed to disable PLL\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ivpu_hw_40xx_d0i3_enable(struct ivpu_device *vdev)
|
||||
{
|
||||
int ret;
|
||||
@ -913,7 +930,7 @@ static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev)
|
||||
|
||||
ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev);
|
||||
|
||||
if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev))
|
||||
if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev))
|
||||
ivpu_warn(vdev, "Failed to reset the VPU\n");
|
||||
|
||||
if (ivpu_pll_disable(vdev)) {
|
||||
@ -1032,18 +1049,18 @@ static void ivpu_hw_40xx_irq_disable(struct ivpu_device *vdev)
|
||||
static void ivpu_hw_40xx_irq_wdt_nce_handler(struct ivpu_device *vdev)
|
||||
{
|
||||
/* TODO: For LNN hang consider engine reset instead of full recovery */
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ");
|
||||
}
|
||||
|
||||
static void ivpu_hw_40xx_irq_wdt_mss_handler(struct ivpu_device *vdev)
|
||||
{
|
||||
ivpu_hw_wdt_disable(vdev);
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ");
|
||||
}
|
||||
|
||||
static void ivpu_hw_40xx_irq_noc_firewall_handler(struct ivpu_device *vdev)
|
||||
{
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ");
|
||||
}
|
||||
|
||||
/* Handler for IRQs from VPU core (irqV) */
|
||||
@ -1137,7 +1154,7 @@ static bool ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq)
|
||||
REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status);
|
||||
|
||||
if (schedule_recovery)
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -343,10 +343,8 @@ int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *r
|
||||
hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE,
|
||||
&hb_resp, VPU_IPC_CHAN_ASYNC_CMD,
|
||||
vdev->timeout.jsm);
|
||||
if (hb_ret == -ETIMEDOUT) {
|
||||
ivpu_hw_diagnose_failure(vdev);
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
}
|
||||
if (hb_ret == -ETIMEDOUT)
|
||||
ivpu_pm_trigger_recovery(vdev, "IPC timeout");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -112,22 +112,20 @@ static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engin
|
||||
}
|
||||
}
|
||||
|
||||
void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv)
|
||||
void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&file_priv->lock);
|
||||
lockdep_assert_held(&file_priv->lock);
|
||||
|
||||
for (i = 0; i < IVPU_NUM_ENGINES; i++)
|
||||
ivpu_cmdq_release_locked(file_priv, i);
|
||||
|
||||
mutex_unlock(&file_priv->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the doorbell as unregistered and reset job queue pointers.
|
||||
* This function needs to be called when the VPU hardware is restarted
|
||||
* and FW looses job queue state. The next time job queue is used it
|
||||
* and FW loses job queue state. The next time job queue is used it
|
||||
* will be registered again.
|
||||
*/
|
||||
static void ivpu_cmdq_reset_locked(struct ivpu_file_priv *file_priv, u16 engine)
|
||||
@ -161,15 +159,13 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev)
|
||||
struct ivpu_file_priv *file_priv;
|
||||
unsigned long ctx_id;
|
||||
|
||||
xa_for_each(&vdev->context_xa, ctx_id, file_priv) {
|
||||
file_priv = ivpu_file_priv_get_by_ctx_id(vdev, ctx_id);
|
||||
if (!file_priv)
|
||||
continue;
|
||||
mutex_lock(&vdev->context_list_lock);
|
||||
|
||||
xa_for_each(&vdev->context_xa, ctx_id, file_priv)
|
||||
ivpu_cmdq_reset_all(file_priv);
|
||||
|
||||
ivpu_file_priv_put(&file_priv);
|
||||
}
|
||||
mutex_unlock(&vdev->context_list_lock);
|
||||
|
||||
}
|
||||
|
||||
static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job)
|
||||
@ -243,60 +239,32 @@ static struct dma_fence *ivpu_fence_create(struct ivpu_device *vdev)
|
||||
return &fence->base;
|
||||
}
|
||||
|
||||
static void job_get(struct ivpu_job *job, struct ivpu_job **link)
|
||||
static void ivpu_job_destroy(struct ivpu_job *job)
|
||||
{
|
||||
struct ivpu_device *vdev = job->vdev;
|
||||
|
||||
kref_get(&job->ref);
|
||||
*link = job;
|
||||
|
||||
ivpu_dbg(vdev, KREF, "Job get: id %u refcount %u\n", job->job_id, kref_read(&job->ref));
|
||||
}
|
||||
|
||||
static void job_release(struct kref *ref)
|
||||
{
|
||||
struct ivpu_job *job = container_of(ref, struct ivpu_job, ref);
|
||||
struct ivpu_device *vdev = job->vdev;
|
||||
u32 i;
|
||||
|
||||
ivpu_dbg(vdev, JOB, "Job destroyed: id %3u ctx %2d engine %d",
|
||||
job->job_id, job->file_priv->ctx.id, job->engine_idx);
|
||||
|
||||
for (i = 0; i < job->bo_count; i++)
|
||||
if (job->bos[i])
|
||||
drm_gem_object_put(&job->bos[i]->base.base);
|
||||
|
||||
dma_fence_put(job->done_fence);
|
||||
ivpu_file_priv_put(&job->file_priv);
|
||||
|
||||
ivpu_dbg(vdev, KREF, "Job released: id %u\n", job->job_id);
|
||||
kfree(job);
|
||||
|
||||
/* Allow the VPU to get suspended, must be called after ivpu_file_priv_put() */
|
||||
ivpu_rpm_put(vdev);
|
||||
}
|
||||
|
||||
static void job_put(struct ivpu_job *job)
|
||||
{
|
||||
struct ivpu_device *vdev = job->vdev;
|
||||
|
||||
ivpu_dbg(vdev, KREF, "Job put: id %u refcount %u\n", job->job_id, kref_read(&job->ref));
|
||||
kref_put(&job->ref, job_release);
|
||||
}
|
||||
|
||||
static struct ivpu_job *
|
||||
ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
|
||||
ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
|
||||
{
|
||||
struct ivpu_device *vdev = file_priv->vdev;
|
||||
struct ivpu_job *job;
|
||||
int ret;
|
||||
|
||||
ret = ivpu_rpm_get(vdev);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
job = kzalloc(struct_size(job, bos, bo_count), GFP_KERNEL);
|
||||
if (!job)
|
||||
goto err_rpm_put;
|
||||
|
||||
kref_init(&job->ref);
|
||||
return NULL;
|
||||
|
||||
job->vdev = vdev;
|
||||
job->engine_idx = engine_idx;
|
||||
@ -310,17 +278,14 @@ ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
|
||||
job->file_priv = ivpu_file_priv_get(file_priv);
|
||||
|
||||
ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx);
|
||||
|
||||
return job;
|
||||
|
||||
err_free_job:
|
||||
kfree(job);
|
||||
err_rpm_put:
|
||||
ivpu_rpm_put(vdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)
|
||||
static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job_status)
|
||||
{
|
||||
struct ivpu_job *job;
|
||||
|
||||
@ -337,9 +302,10 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)
|
||||
ivpu_dbg(vdev, JOB, "Job complete: id %3u ctx %2d engine %d status 0x%x\n",
|
||||
job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status);
|
||||
|
||||
ivpu_job_destroy(job);
|
||||
ivpu_stop_job_timeout_detection(vdev);
|
||||
|
||||
job_put(job);
|
||||
ivpu_rpm_put(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -349,10 +315,10 @@ void ivpu_jobs_abort_all(struct ivpu_device *vdev)
|
||||
unsigned long id;
|
||||
|
||||
xa_for_each(&vdev->submitted_jobs_xa, id, job)
|
||||
ivpu_job_done(vdev, id, VPU_JSM_STATUS_ABORTED);
|
||||
ivpu_job_signal_and_destroy(vdev, id, VPU_JSM_STATUS_ABORTED);
|
||||
}
|
||||
|
||||
static int ivpu_direct_job_submission(struct ivpu_job *job)
|
||||
static int ivpu_job_submit(struct ivpu_job *job)
|
||||
{
|
||||
struct ivpu_file_priv *file_priv = job->file_priv;
|
||||
struct ivpu_device *vdev = job->vdev;
|
||||
@ -360,53 +326,65 @@ static int ivpu_direct_job_submission(struct ivpu_job *job)
|
||||
struct ivpu_cmdq *cmdq;
|
||||
int ret;
|
||||
|
||||
ret = ivpu_rpm_get(vdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&file_priv->lock);
|
||||
|
||||
cmdq = ivpu_cmdq_acquire(job->file_priv, job->engine_idx);
|
||||
if (!cmdq) {
|
||||
ivpu_warn(vdev, "Failed get job queue, ctx %d engine %d\n",
|
||||
file_priv->ctx.id, job->engine_idx);
|
||||
ivpu_warn_ratelimited(vdev, "Failed get job queue, ctx %d engine %d\n",
|
||||
file_priv->ctx.id, job->engine_idx);
|
||||
ret = -EINVAL;
|
||||
goto err_unlock;
|
||||
goto err_unlock_file_priv;
|
||||
}
|
||||
|
||||
job_id_range.min = FIELD_PREP(JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1));
|
||||
job_id_range.max = job_id_range.min | JOB_ID_JOB_MASK;
|
||||
|
||||
job_get(job, &job);
|
||||
ret = xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL);
|
||||
xa_lock(&vdev->submitted_jobs_xa);
|
||||
ret = __xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL);
|
||||
if (ret) {
|
||||
ivpu_warn_ratelimited(vdev, "Failed to allocate job id: %d\n", ret);
|
||||
goto err_job_put;
|
||||
ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n",
|
||||
file_priv->ctx.id);
|
||||
ret = -EBUSY;
|
||||
goto err_unlock_submitted_jobs_xa;
|
||||
}
|
||||
|
||||
ret = ivpu_cmdq_push_job(cmdq, job);
|
||||
if (ret)
|
||||
goto err_xa_erase;
|
||||
goto err_erase_xa;
|
||||
|
||||
ivpu_start_job_timeout_detection(vdev);
|
||||
|
||||
ivpu_dbg(vdev, JOB, "Job submitted: id %3u addr 0x%llx ctx %2d engine %d next %d\n",
|
||||
job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id,
|
||||
job->engine_idx, cmdq->jobq->header.tail);
|
||||
|
||||
if (ivpu_test_mode & IVPU_TEST_MODE_NULL_HW) {
|
||||
ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS);
|
||||
if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) {
|
||||
cmdq->jobq->header.head = cmdq->jobq->header.tail;
|
||||
wmb(); /* Flush WC buffer for jobq header */
|
||||
} else {
|
||||
ivpu_cmdq_ring_db(vdev, cmdq);
|
||||
}
|
||||
|
||||
ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d addr 0x%llx next %d\n",
|
||||
job->job_id, file_priv->ctx.id, job->engine_idx,
|
||||
job->cmd_buf_vpu_addr, cmdq->jobq->header.tail);
|
||||
|
||||
xa_unlock(&vdev->submitted_jobs_xa);
|
||||
|
||||
mutex_unlock(&file_priv->lock);
|
||||
|
||||
if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW))
|
||||
ivpu_job_signal_and_destroy(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS);
|
||||
|
||||
return 0;
|
||||
|
||||
err_xa_erase:
|
||||
xa_erase(&vdev->submitted_jobs_xa, job->job_id);
|
||||
err_job_put:
|
||||
job_put(job);
|
||||
err_unlock:
|
||||
err_erase_xa:
|
||||
__xa_erase(&vdev->submitted_jobs_xa, job->job_id);
|
||||
err_unlock_submitted_jobs_xa:
|
||||
xa_unlock(&vdev->submitted_jobs_xa);
|
||||
err_unlock_file_priv:
|
||||
mutex_unlock(&file_priv->lock);
|
||||
ivpu_rpm_put(vdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -488,6 +466,9 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
if (params->engine > DRM_IVPU_ENGINE_COPY)
|
||||
return -EINVAL;
|
||||
|
||||
if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
|
||||
return -EINVAL;
|
||||
|
||||
if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
@ -509,44 +490,49 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
params->buffer_count * sizeof(u32));
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
goto free_handles;
|
||||
goto err_free_handles;
|
||||
}
|
||||
|
||||
if (!drm_dev_enter(&vdev->drm, &idx)) {
|
||||
ret = -ENODEV;
|
||||
goto free_handles;
|
||||
goto err_free_handles;
|
||||
}
|
||||
|
||||
ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n",
|
||||
file_priv->ctx.id, params->buffer_count);
|
||||
|
||||
job = ivpu_create_job(file_priv, params->engine, params->buffer_count);
|
||||
job = ivpu_job_create(file_priv, params->engine, params->buffer_count);
|
||||
if (!job) {
|
||||
ivpu_err(vdev, "Failed to create job\n");
|
||||
ret = -ENOMEM;
|
||||
goto dev_exit;
|
||||
goto err_exit_dev;
|
||||
}
|
||||
|
||||
ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count,
|
||||
params->commands_offset);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to prepare job, ret %d\n", ret);
|
||||
goto job_put;
|
||||
ivpu_err(vdev, "Failed to prepare job: %d\n", ret);
|
||||
goto err_destroy_job;
|
||||
}
|
||||
|
||||
ret = ivpu_direct_job_submission(job);
|
||||
if (ret) {
|
||||
dma_fence_signal(job->done_fence);
|
||||
ivpu_err(vdev, "Failed to submit job to the HW, ret %d\n", ret);
|
||||
}
|
||||
down_read(&vdev->pm->reset_lock);
|
||||
ret = ivpu_job_submit(job);
|
||||
up_read(&vdev->pm->reset_lock);
|
||||
if (ret)
|
||||
goto err_signal_fence;
|
||||
|
||||
job_put:
|
||||
job_put(job);
|
||||
dev_exit:
|
||||
drm_dev_exit(idx);
|
||||
free_handles:
|
||||
kfree(buf_handles);
|
||||
return ret;
|
||||
|
||||
err_signal_fence:
|
||||
dma_fence_signal(job->done_fence);
|
||||
err_destroy_job:
|
||||
ivpu_job_destroy(job);
|
||||
err_exit_dev:
|
||||
drm_dev_exit(idx);
|
||||
err_free_handles:
|
||||
kfree(buf_handles);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -568,7 +554,7 @@ ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr,
|
||||
}
|
||||
|
||||
payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload;
|
||||
ret = ivpu_job_done(vdev, payload->job_id, payload->job_status);
|
||||
ret = ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status);
|
||||
if (!ret && !xa_empty(&vdev->submitted_jobs_xa))
|
||||
ivpu_start_job_timeout_detection(vdev);
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ struct ivpu_cmdq {
|
||||
will update the job status
|
||||
*/
|
||||
struct ivpu_job {
|
||||
struct kref ref;
|
||||
struct ivpu_device *vdev;
|
||||
struct ivpu_file_priv *file_priv;
|
||||
struct dma_fence *done_fence;
|
||||
@ -56,7 +55,7 @@ struct ivpu_job {
|
||||
|
||||
int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
|
||||
|
||||
void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv);
|
||||
void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv);
|
||||
void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
|
||||
|
||||
void ivpu_job_done_consumer_init(struct ivpu_device *vdev);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <linux/highmem.h>
|
||||
|
||||
#include "ivpu_drv.h"
|
||||
#include "ivpu_hw.h"
|
||||
#include "ivpu_hw_reg_io.h"
|
||||
#include "ivpu_mmu.h"
|
||||
#include "ivpu_mmu_context.h"
|
||||
@ -518,6 +519,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev)
|
||||
|
||||
ivpu_err(vdev, "Timed out waiting for MMU consumer: %d, error: %s\n", ret,
|
||||
ivpu_mmu_cmdq_err_to_str(err));
|
||||
ivpu_hw_diagnose_failure(vdev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -885,7 +887,6 @@ static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev)
|
||||
|
||||
void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
|
||||
{
|
||||
bool schedule_recovery = false;
|
||||
u32 *event;
|
||||
u32 ssid;
|
||||
|
||||
@ -895,14 +896,21 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
|
||||
ivpu_mmu_dump_event(vdev, event);
|
||||
|
||||
ssid = FIELD_GET(IVPU_MMU_EVT_SSID_MASK, event[0]);
|
||||
if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID)
|
||||
schedule_recovery = true;
|
||||
else
|
||||
ivpu_mmu_user_context_mark_invalid(vdev, ssid);
|
||||
}
|
||||
if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) {
|
||||
ivpu_pm_trigger_recovery(vdev, "MMU event");
|
||||
return;
|
||||
}
|
||||
|
||||
if (schedule_recovery)
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_mmu_user_context_mark_invalid(vdev, ssid);
|
||||
}
|
||||
}
|
||||
|
||||
void ivpu_mmu_evtq_dump(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 *event;
|
||||
|
||||
while ((event = ivpu_mmu_get_event(vdev)) != NULL)
|
||||
ivpu_mmu_dump_event(vdev, event);
|
||||
}
|
||||
|
||||
void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev)
|
||||
|
@ -46,5 +46,6 @@ int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid);
|
||||
|
||||
void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev);
|
||||
void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev);
|
||||
void ivpu_mmu_evtq_dump(struct ivpu_device *vdev);
|
||||
|
||||
#endif /* __IVPU_MMU_H__ */
|
||||
|
@ -355,6 +355,9 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
|
||||
dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset;
|
||||
size_t size = sg_dma_len(sg) + sg->offset;
|
||||
|
||||
ivpu_dbg(vdev, MMU_MAP, "Map ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n",
|
||||
ctx->id, dma_addr, vpu_addr, size);
|
||||
|
||||
ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to map context pages\n");
|
||||
@ -366,6 +369,7 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
|
||||
|
||||
/* Ensure page table modifications are flushed from wc buffers to memory */
|
||||
wmb();
|
||||
|
||||
mutex_unlock(&ctx->lock);
|
||||
|
||||
ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
|
||||
@ -388,14 +392,19 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct
|
||||
mutex_lock(&ctx->lock);
|
||||
|
||||
for_each_sgtable_dma_sg(sgt, sg, i) {
|
||||
dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset;
|
||||
size_t size = sg_dma_len(sg) + sg->offset;
|
||||
|
||||
ivpu_dbg(vdev, MMU_MAP, "Unmap ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n",
|
||||
ctx->id, dma_addr, vpu_addr, size);
|
||||
|
||||
ivpu_mmu_context_unmap_pages(ctx, vpu_addr, size);
|
||||
vpu_addr += size;
|
||||
}
|
||||
|
||||
/* Ensure page table modifications are flushed from wc buffers to memory */
|
||||
wmb();
|
||||
|
||||
mutex_unlock(&ctx->lock);
|
||||
|
||||
ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "ivpu_drv.h"
|
||||
#include "ivpu_hw.h"
|
||||
#include "ivpu_fw.h"
|
||||
#include "ivpu_fw_log.h"
|
||||
#include "ivpu_ipc.h"
|
||||
#include "ivpu_job.h"
|
||||
#include "ivpu_jsm_msg.h"
|
||||
@ -111,6 +112,14 @@ static void ivpu_pm_recovery_work(struct work_struct *work)
|
||||
char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL};
|
||||
int ret;
|
||||
|
||||
ivpu_err(vdev, "Recovering the VPU (reset #%d)\n", atomic_read(&vdev->pm->reset_counter));
|
||||
|
||||
ret = pm_runtime_resume_and_get(vdev->drm.dev);
|
||||
if (ret)
|
||||
ivpu_err(vdev, "Failed to resume VPU: %d\n", ret);
|
||||
|
||||
ivpu_fw_log_dump(vdev);
|
||||
|
||||
retry:
|
||||
ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
|
||||
if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) {
|
||||
@ -122,11 +131,13 @@ retry:
|
||||
ivpu_err(vdev, "Failed to reset VPU: %d\n", ret);
|
||||
|
||||
kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt);
|
||||
pm_runtime_mark_last_busy(vdev->drm.dev);
|
||||
pm_runtime_put_autosuspend(vdev->drm.dev);
|
||||
}
|
||||
|
||||
void ivpu_pm_schedule_recovery(struct ivpu_device *vdev)
|
||||
void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason)
|
||||
{
|
||||
struct ivpu_pm_info *pm = vdev->pm;
|
||||
ivpu_err(vdev, "Recovery triggered by %s\n", reason);
|
||||
|
||||
if (ivpu_disable_recovery) {
|
||||
ivpu_err(vdev, "Recovery not available when disable_recovery param is set\n");
|
||||
@ -138,10 +149,11 @@ void ivpu_pm_schedule_recovery(struct ivpu_device *vdev)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Schedule recovery if it's not in progress */
|
||||
if (atomic_cmpxchg(&pm->in_reset, 0, 1) == 0) {
|
||||
ivpu_hw_irq_disable(vdev);
|
||||
queue_work(system_long_wq, &pm->recovery_work);
|
||||
/* Trigger recovery if it's not in progress */
|
||||
if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) {
|
||||
ivpu_hw_diagnose_failure(vdev);
|
||||
ivpu_hw_irq_disable(vdev); /* Disable IRQ early to protect from IRQ storm */
|
||||
queue_work(system_long_wq, &vdev->pm->recovery_work);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,12 +161,8 @@ static void ivpu_job_timeout_work(struct work_struct *work)
|
||||
{
|
||||
struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, job_timeout_work.work);
|
||||
struct ivpu_device *vdev = pm->vdev;
|
||||
unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr;
|
||||
|
||||
ivpu_err(vdev, "TDR detected, timeout %lu ms", timeout_ms);
|
||||
ivpu_hw_diagnose_failure(vdev);
|
||||
|
||||
ivpu_pm_schedule_recovery(vdev);
|
||||
ivpu_pm_trigger_recovery(vdev, "TDR");
|
||||
}
|
||||
|
||||
void ivpu_start_job_timeout_detection(struct ivpu_device *vdev)
|
||||
@ -227,6 +235,9 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
|
||||
bool hw_is_idle = true;
|
||||
int ret;
|
||||
|
||||
drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
|
||||
drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work));
|
||||
|
||||
ivpu_dbg(vdev, PM, "Runtime suspend..\n");
|
||||
|
||||
if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) {
|
||||
@ -247,7 +258,8 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
|
||||
ivpu_err(vdev, "Failed to set suspend VPU: %d\n", ret);
|
||||
|
||||
if (!hw_is_idle) {
|
||||
ivpu_warn(vdev, "VPU failed to enter idle, force suspended.\n");
|
||||
ivpu_err(vdev, "VPU failed to enter idle, force suspended.\n");
|
||||
ivpu_fw_log_dump(vdev);
|
||||
ivpu_pm_prepare_cold_boot(vdev);
|
||||
} else {
|
||||
ivpu_pm_prepare_warm_boot(vdev);
|
||||
@ -308,11 +320,12 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev)
|
||||
{
|
||||
struct ivpu_device *vdev = pci_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(vdev->drm.dev);
|
||||
|
||||
ivpu_dbg(vdev, PM, "Pre-reset..\n");
|
||||
atomic_inc(&vdev->pm->reset_counter);
|
||||
atomic_set(&vdev->pm->in_reset, 1);
|
||||
atomic_set(&vdev->pm->reset_pending, 1);
|
||||
|
||||
pm_runtime_get_sync(vdev->drm.dev);
|
||||
down_write(&vdev->pm->reset_lock);
|
||||
ivpu_prepare_for_reset(vdev);
|
||||
ivpu_hw_reset(vdev);
|
||||
ivpu_pm_prepare_cold_boot(vdev);
|
||||
@ -329,9 +342,11 @@ void ivpu_pm_reset_done_cb(struct pci_dev *pdev)
|
||||
ret = ivpu_resume(vdev);
|
||||
if (ret)
|
||||
ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret);
|
||||
atomic_set(&vdev->pm->in_reset, 0);
|
||||
up_write(&vdev->pm->reset_lock);
|
||||
atomic_set(&vdev->pm->reset_pending, 0);
|
||||
ivpu_dbg(vdev, PM, "Post-reset done.\n");
|
||||
|
||||
pm_runtime_mark_last_busy(vdev->drm.dev);
|
||||
pm_runtime_put_autosuspend(vdev->drm.dev);
|
||||
}
|
||||
|
||||
@ -344,7 +359,10 @@ void ivpu_pm_init(struct ivpu_device *vdev)
|
||||
pm->vdev = vdev;
|
||||
pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
|
||||
|
||||
atomic_set(&pm->in_reset, 0);
|
||||
init_rwsem(&pm->reset_lock);
|
||||
atomic_set(&pm->reset_pending, 0);
|
||||
atomic_set(&pm->reset_counter, 0);
|
||||
|
||||
INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work);
|
||||
INIT_DELAYED_WORK(&pm->job_timeout_work, ivpu_job_timeout_work);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#ifndef __IVPU_PM_H__
|
||||
#define __IVPU_PM_H__
|
||||
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct ivpu_device;
|
||||
@ -14,8 +15,9 @@ struct ivpu_pm_info {
|
||||
struct ivpu_device *vdev;
|
||||
struct delayed_work job_timeout_work;
|
||||
struct work_struct recovery_work;
|
||||
atomic_t in_reset;
|
||||
struct rw_semaphore reset_lock;
|
||||
atomic_t reset_counter;
|
||||
atomic_t reset_pending;
|
||||
bool is_warmboot;
|
||||
u32 suspend_reschedule_counter;
|
||||
};
|
||||
@ -37,7 +39,7 @@ int __must_check ivpu_rpm_get(struct ivpu_device *vdev);
|
||||
int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev);
|
||||
void ivpu_rpm_put(struct ivpu_device *vdev);
|
||||
|
||||
void ivpu_pm_schedule_recovery(struct ivpu_device *vdev);
|
||||
void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason);
|
||||
void ivpu_start_job_timeout_detection(struct ivpu_device *vdev);
|
||||
void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev);
|
||||
|
||||
|
@ -128,4 +128,4 @@ unlock_mutex:
|
||||
}
|
||||
|
||||
/* must execute after PCI subsystem for EFI quirks */
|
||||
subsys_initcall_sync(sysfb_init);
|
||||
device_initcall(sysfb_init);
|
||||
|
@ -121,6 +121,7 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev)
|
||||
struct amdgpu_bo_param bp;
|
||||
dma_addr_t dma_addr;
|
||||
struct page *p;
|
||||
unsigned long x;
|
||||
int ret;
|
||||
|
||||
if (adev->gart.bo != NULL)
|
||||
@ -130,6 +131,10 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev)
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
/* assign pages to this device */
|
||||
for (x = 0; x < (1UL << order); x++)
|
||||
p[x].mapping = adev->mman.bdev.dev_mapping;
|
||||
|
||||
/* If the hardware does not support UTCL2 snooping of the CPU caches
|
||||
* then set_memory_wc() could be used as a workaround to mark the pages
|
||||
* as write combine memory.
|
||||
@ -223,6 +228,7 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
|
||||
unsigned int order = get_order(adev->gart.table_size);
|
||||
struct sg_table *sg = adev->gart.bo->tbo.sg;
|
||||
struct page *p;
|
||||
unsigned long x;
|
||||
int ret;
|
||||
|
||||
ret = amdgpu_bo_reserve(adev->gart.bo, false);
|
||||
@ -234,6 +240,8 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
|
||||
sg_free_table(sg);
|
||||
kfree(sg);
|
||||
p = virt_to_page(adev->gart.ptr);
|
||||
for (x = 0; x < (1UL << order); x++)
|
||||
p[x].mapping = NULL;
|
||||
__free_pages(p, order);
|
||||
|
||||
adev->gart.ptr = NULL;
|
||||
|
@ -221,8 +221,23 @@ static struct attribute *amdgpu_vram_mgr_attributes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static umode_t amdgpu_vram_attrs_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int i)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
|
||||
if (attr == &dev_attr_mem_info_vram_vendor.attr &&
|
||||
!adev->gmc.vram_vendor)
|
||||
return 0;
|
||||
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
const struct attribute_group amdgpu_vram_mgr_attr_group = {
|
||||
.attrs = amdgpu_vram_mgr_attributes
|
||||
.attrs = amdgpu_vram_mgr_attributes,
|
||||
.is_visible = amdgpu_vram_attrs_is_visible
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6589,7 +6589,7 @@ static int gfx_v10_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
|
||||
#ifdef __BIG_ENDIAN
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ENDIAN_SWAP, 1);
|
||||
#endif
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0);
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1);
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH,
|
||||
prop->allow_tunneling);
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1);
|
||||
|
@ -3846,7 +3846,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
|
||||
(order_base_2(prop->queue_size / 4) - 1));
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE,
|
||||
(order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1));
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0);
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1);
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH,
|
||||
prop->allow_tunneling);
|
||||
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1);
|
||||
|
@ -1950,7 +1950,8 @@ static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev)
|
||||
static const u32 regBIF_BIOS_SCRATCH_4 = 0x50;
|
||||
u32 vram_info;
|
||||
|
||||
if (!amdgpu_sriov_vf(adev)) {
|
||||
/* Only for dGPU, vendor informaton is reliable */
|
||||
if (!amdgpu_sriov_vf(adev) && !(adev->flags & AMD_IS_APU)) {
|
||||
vram_info = RREG32(regBIF_BIOS_SCRATCH_4);
|
||||
adev->gmc.vram_vendor = vram_info & 0xF;
|
||||
}
|
||||
|
@ -170,6 +170,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
||||
m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT;
|
||||
m->cp_hqd_pq_control |=
|
||||
ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1;
|
||||
m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK;
|
||||
pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control);
|
||||
|
||||
m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
|
||||
|
@ -224,6 +224,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
||||
m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT;
|
||||
m->cp_hqd_pq_control |=
|
||||
ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1;
|
||||
m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK;
|
||||
pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control);
|
||||
|
||||
m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
|
||||
|
@ -272,6 +272,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
|
||||
{
|
||||
u32 v_blank_start, v_blank_end, h_position, v_position;
|
||||
struct amdgpu_crtc *acrtc = NULL;
|
||||
struct dc *dc = adev->dm.dc;
|
||||
|
||||
if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
|
||||
return -EINVAL;
|
||||
@ -284,6 +285,9 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
|
||||
dc_allow_idle_optimizations(dc, false);
|
||||
|
||||
/*
|
||||
* TODO rework base driver to use values directly.
|
||||
* for now parse it back into reg-format
|
||||
@ -1715,7 +1719,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
|
||||
init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0];
|
||||
init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0];
|
||||
|
||||
init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL;
|
||||
if (amdgpu_dc_debug_mask & DC_DISABLE_IPS)
|
||||
init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL;
|
||||
|
||||
init_data.flags.disable_ips_in_vpb = 1;
|
||||
|
||||
/* Enable DWB for tested platforms only */
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0))
|
||||
@ -8976,16 +8983,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
trace_amdgpu_dm_atomic_commit_tail_begin(state);
|
||||
|
||||
if (dm->dc->caps.ips_support) {
|
||||
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
|
||||
if (new_con_state->crtc &&
|
||||
new_con_state->crtc->state->active &&
|
||||
drm_atomic_crtc_needs_modeset(new_con_state->crtc->state)) {
|
||||
dc_dmub_srv_apply_idle_power_optimizations(dm->dc, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dm->dc->caps.ips_support && dm->dc->idle_optimizations_allowed)
|
||||
dc_allow_idle_optimizations(dm->dc, false);
|
||||
|
||||
drm_atomic_helper_update_legacy_modeset_state(dev, state);
|
||||
drm_dp_mst_atomic_wait_for_dependencies(state);
|
||||
|
@ -711,7 +711,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
|
||||
{
|
||||
bool st;
|
||||
enum dc_irq_source irq_source;
|
||||
|
||||
struct dc *dc = adev->dm.dc;
|
||||
struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc_id];
|
||||
|
||||
if (!acrtc) {
|
||||
@ -729,6 +729,9 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
|
||||
|
||||
st = (state == AMDGPU_IRQ_STATE_ENABLE);
|
||||
|
||||
if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
|
||||
dc_allow_idle_optimizations(dc, false);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, irq_source, st);
|
||||
return 0;
|
||||
}
|
||||
|
@ -434,6 +434,7 @@ struct dc_config {
|
||||
bool EnableMinDispClkODM;
|
||||
bool enable_auto_dpm_test_logs;
|
||||
unsigned int disable_ips;
|
||||
unsigned int disable_ips_in_vpb;
|
||||
};
|
||||
|
||||
enum visual_confirm {
|
||||
|
@ -1034,6 +1034,7 @@ enum replay_FW_Message_type {
|
||||
Replay_Msg_Not_Support = -1,
|
||||
Replay_Set_Timing_Sync_Supported,
|
||||
Replay_Set_Residency_Frameupdate_Timer,
|
||||
Replay_Set_Pseudo_VTotal,
|
||||
};
|
||||
|
||||
union replay_error_status {
|
||||
@ -1089,6 +1090,10 @@ struct replay_settings {
|
||||
uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM];
|
||||
/* Maximum link off frame count */
|
||||
enum replay_link_off_frame_count_level link_off_frame_count_level;
|
||||
/* Replay pseudo vtotal for abm + ips on full screen video which can improve ips residency */
|
||||
uint16_t abm_with_ips_on_full_screen_video_pseudo_vtotal;
|
||||
/* Replay last pseudo vtotal set to DMUB */
|
||||
uint16_t last_pseudo_vtotal;
|
||||
};
|
||||
|
||||
/* To split out "global" and "per-panel" config settings.
|
||||
|
@ -680,7 +680,7 @@ void dcn35_power_down_on_boot(struct dc *dc)
|
||||
bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable)
|
||||
{
|
||||
struct dc_link *edp_links[MAX_NUM_EDP];
|
||||
int edp_num;
|
||||
int i, edp_num;
|
||||
if (dc->debug.dmcub_emulation)
|
||||
return true;
|
||||
|
||||
@ -688,6 +688,13 @@ bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable)
|
||||
dc_get_edp_links(dc, edp_links, &edp_num);
|
||||
if (edp_num == 0 || edp_num > 1)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < dc->current_state->stream_count; ++i) {
|
||||
struct dc_stream_state *stream = dc->current_state->streams[i];
|
||||
|
||||
if (!stream->dpms_off && !dc_is_embedded_signal(stream->signal))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: review other cases when idle optimization is allowed
|
||||
|
@ -205,7 +205,7 @@ enum dc_status core_link_read_dpcd(
|
||||
uint32_t extended_size;
|
||||
/* size of the remaining partitioned address space */
|
||||
uint32_t size_left_to_read;
|
||||
enum dc_status status;
|
||||
enum dc_status status = DC_ERROR_UNEXPECTED;
|
||||
/* size of the next partition to be read from */
|
||||
uint32_t partition_size;
|
||||
uint32_t data_index = 0;
|
||||
@ -234,7 +234,7 @@ enum dc_status core_link_write_dpcd(
|
||||
{
|
||||
uint32_t partition_size;
|
||||
uint32_t data_index = 0;
|
||||
enum dc_status status;
|
||||
enum dc_status status = DC_ERROR_UNEXPECTED;
|
||||
|
||||
while (size) {
|
||||
partition_size = dpcd_get_next_partition_size(address, size);
|
||||
|
@ -2832,6 +2832,7 @@ struct dmub_rb_cmd_psr_set_power_opt {
|
||||
#define REPLAY_RESIDENCY_MODE_MASK (0x1 << REPLAY_RESIDENCY_MODE_SHIFT)
|
||||
# define REPLAY_RESIDENCY_MODE_PHY (0x0 << REPLAY_RESIDENCY_MODE_SHIFT)
|
||||
# define REPLAY_RESIDENCY_MODE_ALPM (0x1 << REPLAY_RESIDENCY_MODE_SHIFT)
|
||||
# define REPLAY_RESIDENCY_MODE_IPS 0x10
|
||||
|
||||
#define REPLAY_RESIDENCY_ENABLE_MASK (0x1 << REPLAY_RESIDENCY_ENABLE_SHIFT)
|
||||
# define REPLAY_RESIDENCY_DISABLE (0x0 << REPLAY_RESIDENCY_ENABLE_SHIFT)
|
||||
@ -2894,6 +2895,10 @@ enum dmub_cmd_replay_type {
|
||||
* Set Residency Frameupdate Timer.
|
||||
*/
|
||||
DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER = 6,
|
||||
/**
|
||||
* Set pseudo vtotal
|
||||
*/
|
||||
DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3076,6 +3081,26 @@ struct dmub_cmd_replay_set_timing_sync_data {
|
||||
uint8_t pad[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
|
||||
*/
|
||||
struct dmub_cmd_replay_set_pseudo_vtotal {
|
||||
/**
|
||||
* Panel Instance.
|
||||
* Panel isntance to identify which replay_state to use
|
||||
* Currently the support is only for 0 or 1
|
||||
*/
|
||||
uint8_t panel_inst;
|
||||
/**
|
||||
* Source Vtotal that Replay + IPS + ABM full screen video src vtotal
|
||||
*/
|
||||
uint16_t vtotal;
|
||||
/**
|
||||
* Explicit padding to 4 byte boundary.
|
||||
*/
|
||||
uint8_t pad;
|
||||
};
|
||||
|
||||
/**
|
||||
* Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command.
|
||||
*/
|
||||
@ -3156,6 +3181,20 @@ struct dmub_rb_cmd_replay_set_timing_sync {
|
||||
struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
|
||||
*/
|
||||
struct dmub_rb_cmd_replay_set_pseudo_vtotal {
|
||||
/**
|
||||
* Command header.
|
||||
*/
|
||||
struct dmub_cmd_header header;
|
||||
/**
|
||||
* Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
|
||||
*/
|
||||
struct dmub_cmd_replay_set_pseudo_vtotal data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Data passed from driver to FW in DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command.
|
||||
*/
|
||||
@ -3207,6 +3246,10 @@ union dmub_replay_cmd_set {
|
||||
* Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command data.
|
||||
*/
|
||||
struct dmub_cmd_replay_frameupdate_timer_data timer_data;
|
||||
/**
|
||||
* Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command data.
|
||||
*/
|
||||
struct dmub_cmd_replay_set_pseudo_vtotal pseudo_vtotal_data;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -4358,6 +4401,10 @@ union dmub_rb_cmd {
|
||||
* Definition of a DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command.
|
||||
*/
|
||||
struct dmub_rb_cmd_replay_set_frameupdate_timer replay_set_frameupdate_timer;
|
||||
/**
|
||||
* Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
|
||||
*/
|
||||
struct dmub_rb_cmd_replay_set_pseudo_vtotal replay_set_pseudo_vtotal;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -980,6 +980,11 @@ void set_replay_coasting_vtotal(struct dc_link *link,
|
||||
link->replay_settings.coasting_vtotal_table[type] = vtotal;
|
||||
}
|
||||
|
||||
void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal)
|
||||
{
|
||||
link->replay_settings.abm_with_ips_on_full_screen_video_pseudo_vtotal = vtotal;
|
||||
}
|
||||
|
||||
void calculate_replay_link_off_frame_count(struct dc_link *link,
|
||||
uint16_t vtotal, uint16_t htotal)
|
||||
{
|
||||
|
@ -57,6 +57,7 @@ void init_replay_config(struct dc_link *link, struct replay_config *pr_config);
|
||||
void set_replay_coasting_vtotal(struct dc_link *link,
|
||||
enum replay_coasting_vtotal_type type,
|
||||
uint16_t vtotal);
|
||||
void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal);
|
||||
void calculate_replay_link_off_frame_count(struct dc_link *link,
|
||||
uint16_t vtotal, uint16_t htotal);
|
||||
|
||||
|
@ -258,6 +258,7 @@ enum DC_DEBUG_MASK {
|
||||
DC_ENABLE_DML2 = 0x100,
|
||||
DC_DISABLE_PSR_SU = 0x200,
|
||||
DC_DISABLE_REPLAY = 0x400,
|
||||
DC_DISABLE_IPS = 0x800,
|
||||
};
|
||||
|
||||
enum amd_dpm_forced_level;
|
||||
|
@ -138,7 +138,7 @@ static inline size_t amdgpu_reginst_size(uint16_t num_inst, size_t inst_size,
|
||||
}
|
||||
|
||||
#define amdgpu_asic_get_reg_state_supported(adev) \
|
||||
((adev)->asic_funcs->get_reg_state ? 1 : 0)
|
||||
(((adev)->asic_funcs && (adev)->asic_funcs->get_reg_state) ? 1 : 0)
|
||||
|
||||
#define amdgpu_asic_get_reg_state(adev, state, buf, size) \
|
||||
((adev)->asic_funcs->get_reg_state ? \
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
@ -817,16 +818,8 @@ static int smu_late_init(void *handle)
|
||||
* handle the switch automatically. Driver involvement
|
||||
* is unnecessary.
|
||||
*/
|
||||
if (!smu->dc_controlled_by_gpio) {
|
||||
ret = smu_set_power_source(smu,
|
||||
adev->pm.ac_power ? SMU_POWER_SOURCE_AC :
|
||||
SMU_POWER_SOURCE_DC);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "Failed to switch to %s mode!\n",
|
||||
adev->pm.ac_power ? "AC" : "DC");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
adev->pm.ac_power = power_supply_is_system_supplied() > 0;
|
||||
smu_set_ac_dc(smu);
|
||||
|
||||
if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) ||
|
||||
(amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3)))
|
||||
@ -2710,6 +2703,7 @@ int smu_get_power_limit(void *handle,
|
||||
case SMU_PPT_LIMIT_CURRENT:
|
||||
switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
|
||||
case IP_VERSION(13, 0, 2):
|
||||
case IP_VERSION(13, 0, 6):
|
||||
case IP_VERSION(11, 0, 7):
|
||||
case IP_VERSION(11, 0, 11):
|
||||
case IP_VERSION(11, 0, 12):
|
||||
|
@ -1442,10 +1442,12 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev,
|
||||
case 0x3:
|
||||
dev_dbg(adev->dev, "Switched to AC mode!\n");
|
||||
schedule_work(&smu->interrupt_work);
|
||||
adev->pm.ac_power = true;
|
||||
break;
|
||||
case 0x4:
|
||||
dev_dbg(adev->dev, "Switched to DC mode!\n");
|
||||
schedule_work(&smu->interrupt_work);
|
||||
adev->pm.ac_power = false;
|
||||
break;
|
||||
case 0x7:
|
||||
/*
|
||||
|
@ -1379,10 +1379,12 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev,
|
||||
case 0x3:
|
||||
dev_dbg(adev->dev, "Switched to AC mode!\n");
|
||||
smu_v13_0_ack_ac_dc_interrupt(smu);
|
||||
adev->pm.ac_power = true;
|
||||
break;
|
||||
case 0x4:
|
||||
dev_dbg(adev->dev, "Switched to DC mode!\n");
|
||||
smu_v13_0_ack_ac_dc_interrupt(smu);
|
||||
adev->pm.ac_power = false;
|
||||
break;
|
||||
case 0x7:
|
||||
/*
|
||||
|
@ -2357,6 +2357,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
|
||||
PPTable_t *pptable = table_context->driver_pptable;
|
||||
SkuTable_t *skutable = &pptable->SkuTable;
|
||||
uint32_t power_limit, od_percent_upper, od_percent_lower;
|
||||
uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||
|
||||
if (smu_v13_0_get_current_power_limit(smu, &power_limit))
|
||||
power_limit = smu->adev->pm.ac_power ?
|
||||
@ -2380,7 +2381,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
|
||||
od_percent_upper, od_percent_lower, power_limit);
|
||||
|
||||
if (max_power_limit) {
|
||||
*max_power_limit = power_limit * (100 + od_percent_upper);
|
||||
*max_power_limit = msg_limit * (100 + od_percent_upper);
|
||||
*max_power_limit /= 100;
|
||||
}
|
||||
|
||||
@ -2959,6 +2960,55 @@ static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu)
|
||||
}
|
||||
}
|
||||
|
||||
static int smu_v13_0_0_set_power_limit(struct smu_context *smu,
|
||||
enum smu_ppt_limit_type limit_type,
|
||||
uint32_t limit)
|
||||
{
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
SkuTable_t *skutable = &pptable->SkuTable;
|
||||
uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||
struct smu_table_context *table_context = &smu->smu_table;
|
||||
OverDriveTableExternal_t *od_table =
|
||||
(OverDriveTableExternal_t *)table_context->overdrive_table;
|
||||
int ret = 0;
|
||||
|
||||
if (limit_type != SMU_DEFAULT_PPT_LIMIT)
|
||||
return -EINVAL;
|
||||
|
||||
if (limit <= msg_limit) {
|
||||
if (smu->current_power_limit > msg_limit) {
|
||||
od_table->OverDriveTable.Ppt = 0;
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
|
||||
|
||||
ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return smu_v13_0_set_power_limit(smu, limit_type, limit);
|
||||
} else if (smu->od_enabled) {
|
||||
ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
|
||||
|
||||
ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
smu->current_power_limit = limit;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
|
||||
.get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
|
||||
.set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
|
||||
@ -3013,7 +3063,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
|
||||
.set_fan_control_mode = smu_v13_0_set_fan_control_mode,
|
||||
.enable_mgpu_fan_boost = smu_v13_0_0_enable_mgpu_fan_boost,
|
||||
.get_power_limit = smu_v13_0_0_get_power_limit,
|
||||
.set_power_limit = smu_v13_0_set_power_limit,
|
||||
.set_power_limit = smu_v13_0_0_set_power_limit,
|
||||
.set_power_source = smu_v13_0_set_power_source,
|
||||
.get_power_profile_mode = smu_v13_0_0_get_power_profile_mode,
|
||||
.set_power_profile_mode = smu_v13_0_0_set_power_profile_mode,
|
||||
|
@ -160,8 +160,8 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU
|
||||
MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0),
|
||||
MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxDpmFreq, 1),
|
||||
MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxDpmFreq, 1),
|
||||
MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 0),
|
||||
MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 0),
|
||||
MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1),
|
||||
MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1),
|
||||
MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0),
|
||||
MSG_MAP(GetCTFLimit, PPSMC_MSG_GetCTFLimit, 0),
|
||||
MSG_MAP(GetThermalLimit, PPSMC_MSG_ReadThrottlerLimit, 0),
|
||||
|
@ -2321,6 +2321,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
|
||||
PPTable_t *pptable = table_context->driver_pptable;
|
||||
SkuTable_t *skutable = &pptable->SkuTable;
|
||||
uint32_t power_limit, od_percent_upper, od_percent_lower;
|
||||
uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||
|
||||
if (smu_v13_0_get_current_power_limit(smu, &power_limit))
|
||||
power_limit = smu->adev->pm.ac_power ?
|
||||
@ -2344,7 +2345,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
|
||||
od_percent_upper, od_percent_lower, power_limit);
|
||||
|
||||
if (max_power_limit) {
|
||||
*max_power_limit = power_limit * (100 + od_percent_upper);
|
||||
*max_power_limit = msg_limit * (100 + od_percent_upper);
|
||||
*max_power_limit /= 100;
|
||||
}
|
||||
|
||||
@ -2545,6 +2546,55 @@ static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu)
|
||||
return smu->smc_fw_version > 0x00524600;
|
||||
}
|
||||
|
||||
static int smu_v13_0_7_set_power_limit(struct smu_context *smu,
|
||||
enum smu_ppt_limit_type limit_type,
|
||||
uint32_t limit)
|
||||
{
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
SkuTable_t *skutable = &pptable->SkuTable;
|
||||
uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||
struct smu_table_context *table_context = &smu->smu_table;
|
||||
OverDriveTableExternal_t *od_table =
|
||||
(OverDriveTableExternal_t *)table_context->overdrive_table;
|
||||
int ret = 0;
|
||||
|
||||
if (limit_type != SMU_DEFAULT_PPT_LIMIT)
|
||||
return -EINVAL;
|
||||
|
||||
if (limit <= msg_limit) {
|
||||
if (smu->current_power_limit > msg_limit) {
|
||||
od_table->OverDriveTable.Ppt = 0;
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
|
||||
|
||||
ret = smu_v13_0_7_upload_overdrive_table(smu, od_table);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return smu_v13_0_set_power_limit(smu, limit_type, limit);
|
||||
} else if (smu->od_enabled) {
|
||||
ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
|
||||
|
||||
ret = smu_v13_0_7_upload_overdrive_table(smu, od_table);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
smu->current_power_limit = limit;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
|
||||
.get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask,
|
||||
.set_default_dpm_table = smu_v13_0_7_set_default_dpm_table,
|
||||
@ -2596,7 +2646,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
|
||||
.set_fan_control_mode = smu_v13_0_set_fan_control_mode,
|
||||
.enable_mgpu_fan_boost = smu_v13_0_7_enable_mgpu_fan_boost,
|
||||
.get_power_limit = smu_v13_0_7_get_power_limit,
|
||||
.set_power_limit = smu_v13_0_set_power_limit,
|
||||
.set_power_limit = smu_v13_0_7_set_power_limit,
|
||||
.set_power_source = smu_v13_0_set_power_source,
|
||||
.get_power_profile_mode = smu_v13_0_7_get_power_profile_mode,
|
||||
.set_power_profile_mode = smu_v13_0_7_set_power_profile_mode,
|
||||
|
@ -1762,6 +1762,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux,
|
||||
u8 request = msg->request & ~DP_AUX_I2C_MOT;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ctx->aux_lock);
|
||||
pm_runtime_get_sync(dev);
|
||||
msg->reply = 0;
|
||||
switch (request) {
|
||||
@ -1778,6 +1779,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux,
|
||||
msg->size, msg->buffer);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
mutex_unlock(&ctx->aux_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2474,7 +2476,9 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
ctx->connector = NULL;
|
||||
anx7625_dp_stop(ctx);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
mutex_lock(&ctx->aux_lock);
|
||||
pm_runtime_put_sync_suspend(dev);
|
||||
mutex_unlock(&ctx->aux_lock);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
@ -2668,6 +2672,7 @@ static int anx7625_i2c_probe(struct i2c_client *client)
|
||||
|
||||
mutex_init(&platform->lock);
|
||||
mutex_init(&platform->hdcp_wq_lock);
|
||||
mutex_init(&platform->aux_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func);
|
||||
platform->hdcp_workqueue = create_workqueue("hdcp workqueue");
|
||||
|
@ -475,6 +475,8 @@ struct anx7625_data {
|
||||
struct workqueue_struct *hdcp_workqueue;
|
||||
/* Lock for hdcp work queue */
|
||||
struct mutex hdcp_wq_lock;
|
||||
/* Lock for aux transfer and disable */
|
||||
struct mutex aux_lock;
|
||||
char edid_block;
|
||||
struct display_timing dt;
|
||||
u8 display_timing_valid;
|
||||
|
@ -107,6 +107,7 @@ struct ps8640 {
|
||||
struct device_link *link;
|
||||
bool pre_enabled;
|
||||
bool need_post_hpd_delay;
|
||||
struct mutex aux_lock;
|
||||
};
|
||||
|
||||
static const struct regmap_config ps8640_regmap_config[] = {
|
||||
@ -345,11 +346,20 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
|
||||
struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ps_bridge->aux_lock);
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000);
|
||||
if (ret) {
|
||||
pm_runtime_put_sync_suspend(dev);
|
||||
goto exit;
|
||||
}
|
||||
ret = ps8640_aux_transfer_msg(aux, msg);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ps_bridge->aux_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -470,7 +480,18 @@ static void ps8640_atomic_post_disable(struct drm_bridge *bridge,
|
||||
ps_bridge->pre_enabled = false;
|
||||
|
||||
ps8640_bridge_vdo_control(ps_bridge, DISABLE);
|
||||
|
||||
/*
|
||||
* The bridge seems to expect everything to be power cycled at the
|
||||
* disable process, so grab a lock here to make sure
|
||||
* ps8640_aux_transfer() is not holding a runtime PM reference and
|
||||
* preventing the bridge from suspend.
|
||||
*/
|
||||
mutex_lock(&ps_bridge->aux_lock);
|
||||
|
||||
pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev);
|
||||
|
||||
mutex_unlock(&ps_bridge->aux_lock);
|
||||
}
|
||||
|
||||
static int ps8640_bridge_attach(struct drm_bridge *bridge,
|
||||
@ -619,6 +640,8 @@ static int ps8640_probe(struct i2c_client *client)
|
||||
if (!ps_bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ps_bridge->aux_lock);
|
||||
|
||||
ps_bridge->supplies[0].supply = "vdd12";
|
||||
ps_bridge->supplies[1].supply = "vdd33";
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
|
||||
|
@ -969,10 +969,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi)
|
||||
reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
|
||||
reg &= ~DSIM_STOP_STATE_CNT_MASK;
|
||||
reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]);
|
||||
|
||||
if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
|
||||
reg |= DSIM_FORCE_STOP_STATE;
|
||||
|
||||
samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
|
||||
|
||||
reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff);
|
||||
@ -1431,18 +1427,6 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi)
|
||||
disable_irq(dsi->irq);
|
||||
}
|
||||
|
||||
static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable)
|
||||
{
|
||||
u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
|
||||
|
||||
if (enable)
|
||||
reg |= DSIM_FORCE_STOP_STATE;
|
||||
else
|
||||
reg &= ~DSIM_FORCE_STOP_STATE;
|
||||
|
||||
samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
|
||||
}
|
||||
|
||||
static int samsung_dsim_init(struct samsung_dsim *dsi)
|
||||
{
|
||||
const struct samsung_dsim_driver_data *driver_data = dsi->driver_data;
|
||||
@ -1492,9 +1476,6 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
ret = samsung_dsim_init(dsi);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
samsung_dsim_set_display_mode(dsi);
|
||||
samsung_dsim_set_display_enable(dsi, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1503,12 +1484,8 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge,
|
||||
{
|
||||
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
|
||||
|
||||
if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) {
|
||||
samsung_dsim_set_display_mode(dsi);
|
||||
samsung_dsim_set_display_enable(dsi, true);
|
||||
} else {
|
||||
samsung_dsim_set_stop_state(dsi, false);
|
||||
}
|
||||
samsung_dsim_set_display_mode(dsi);
|
||||
samsung_dsim_set_display_enable(dsi, true);
|
||||
|
||||
dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
|
||||
}
|
||||
@ -1521,9 +1498,6 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge,
|
||||
if (!(dsi->state & DSIM_STATE_ENABLED))
|
||||
return;
|
||||
|
||||
if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
|
||||
samsung_dsim_set_stop_state(dsi, true);
|
||||
|
||||
dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
|
||||
}
|
||||
|
||||
@ -1828,8 +1802,6 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
samsung_dsim_set_stop_state(dsi, false);
|
||||
|
||||
ret = mipi_dsi_create_packet(&xfer.packet, msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -1080,6 +1080,26 @@ static int sii902x_init(struct sii902x *sii902x)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sii902x_audio_codec_init(sii902x, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c_set_clientdata(sii902x->i2c, sii902x);
|
||||
|
||||
sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev,
|
||||
1, 0, I2C_MUX_GATE,
|
||||
sii902x_i2c_bypass_select,
|
||||
sii902x_i2c_bypass_deselect);
|
||||
if (!sii902x->i2cmux) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unreg_audio;
|
||||
}
|
||||
|
||||
sii902x->i2cmux->priv = sii902x;
|
||||
ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
|
||||
if (ret)
|
||||
goto err_unreg_audio;
|
||||
|
||||
sii902x->bridge.funcs = &sii902x_bridge_funcs;
|
||||
sii902x->bridge.of_node = dev->of_node;
|
||||
sii902x->bridge.timings = &default_sii902x_timings;
|
||||
@ -1090,19 +1110,13 @@ static int sii902x_init(struct sii902x *sii902x)
|
||||
|
||||
drm_bridge_add(&sii902x->bridge);
|
||||
|
||||
sii902x_audio_codec_init(sii902x, dev);
|
||||
return 0;
|
||||
|
||||
i2c_set_clientdata(sii902x->i2c, sii902x);
|
||||
err_unreg_audio:
|
||||
if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev))
|
||||
platform_device_unregister(sii902x->audio.pdev);
|
||||
|
||||
sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev,
|
||||
1, 0, I2C_MUX_GATE,
|
||||
sii902x_i2c_bypass_select,
|
||||
sii902x_i2c_bypass_deselect);
|
||||
if (!sii902x->i2cmux)
|
||||
return -ENOMEM;
|
||||
|
||||
sii902x->i2cmux->priv = sii902x;
|
||||
return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sii902x_probe(struct i2c_client *client)
|
||||
@ -1170,12 +1184,14 @@ static int sii902x_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static void sii902x_remove(struct i2c_client *client)
|
||||
|
||||
{
|
||||
struct sii902x *sii902x = i2c_get_clientdata(client);
|
||||
|
||||
i2c_mux_del_adapters(sii902x->i2cmux);
|
||||
drm_bridge_remove(&sii902x->bridge);
|
||||
i2c_mux_del_adapters(sii902x->i2cmux);
|
||||
|
||||
if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev))
|
||||
platform_device_unregister(sii902x->audio.pdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id sii902x_dt_ids[] = {
|
||||
|
@ -5491,6 +5491,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc);
|
||||
* - 0 if the new state is valid
|
||||
* - %-ENOSPC, if the new state is invalid, because of BW limitation
|
||||
* @failing_port is set to:
|
||||
*
|
||||
* - The non-root port where a BW limit check failed
|
||||
* with all the ports downstream of @failing_port passing
|
||||
* the BW limit check.
|
||||
@ -5499,6 +5500,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc);
|
||||
* - %NULL if the BW limit check failed at the root port
|
||||
* with all the ports downstream of the root port passing
|
||||
* the BW limit check.
|
||||
*
|
||||
* - %-EINVAL, if the new state is invalid, because the root port has
|
||||
* too many payloads.
|
||||
*/
|
||||
|
@ -319,9 +319,9 @@ static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win,
|
||||
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
||||
struct drm_framebuffer *fb)
|
||||
{
|
||||
struct exynos_drm_plane plane = ctx->planes[win];
|
||||
struct exynos_drm_plane *plane = &ctx->planes[win];
|
||||
struct exynos_drm_plane_state *state =
|
||||
to_exynos_plane_state(plane.base.state);
|
||||
to_exynos_plane_state(plane->base.state);
|
||||
unsigned int alpha = state->base.alpha;
|
||||
unsigned int pixel_alpha;
|
||||
unsigned long val;
|
||||
|
@ -480,7 +480,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
|
||||
struct fimd_context *ctx = crtc->ctx;
|
||||
struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
|
||||
const struct fimd_driver_data *driver_data = ctx->driver_data;
|
||||
void *timing_base = ctx->regs + driver_data->timing_base;
|
||||
void __iomem *timing_base = ctx->regs + driver_data->timing_base;
|
||||
u32 val;
|
||||
|
||||
if (ctx->suspended)
|
||||
@ -661,9 +661,9 @@ static void fimd_win_set_bldmod(struct fimd_context *ctx, unsigned int win,
|
||||
static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
|
||||
struct drm_framebuffer *fb, int width)
|
||||
{
|
||||
struct exynos_drm_plane plane = ctx->planes[win];
|
||||
struct exynos_drm_plane *plane = &ctx->planes[win];
|
||||
struct exynos_drm_plane_state *state =
|
||||
to_exynos_plane_state(plane.base.state);
|
||||
to_exynos_plane_state(plane->base.state);
|
||||
uint32_t pixel_format = fb->format->format;
|
||||
unsigned int alpha = state->base.alpha;
|
||||
u32 val = WINCONx_ENWIN;
|
||||
|
@ -1341,7 +1341,7 @@ static int __maybe_unused gsc_runtime_resume(struct device *dev)
|
||||
for (i = 0; i < ctx->num_clocks; i++) {
|
||||
ret = clk_prepare_enable(ctx->clocks[i]);
|
||||
if (ret) {
|
||||
while (--i > 0)
|
||||
while (--i >= 0)
|
||||
clk_disable_unprepare(ctx->clocks[i]);
|
||||
return ret;
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ subdir-ccflags-y += $(call cc-option, -Wunused-const-variable)
|
||||
subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned)
|
||||
subdir-ccflags-y += $(call cc-option, -Wformat-overflow)
|
||||
subdir-ccflags-y += $(call cc-option, -Wformat-truncation)
|
||||
subdir-ccflags-y += $(call cc-option, -Wstringop-overflow)
|
||||
subdir-ccflags-y += $(call cc-option, -Wstringop-truncation)
|
||||
# The following turn off the warnings enabled by -Wextra
|
||||
ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),)
|
||||
|
@ -1155,6 +1155,7 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
|
||||
}
|
||||
|
||||
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
|
||||
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
|
||||
|
||||
/* ensure all panel commands dispatched before enabling transcoder */
|
||||
wait_for_cmds_dispatched_to_panel(encoder);
|
||||
@ -1255,8 +1256,6 @@ static void gen11_dsi_enable(struct intel_atomic_state *state,
|
||||
/* step6d: enable dsi transcoder */
|
||||
gen11_dsi_enable_transcoder(encoder);
|
||||
|
||||
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
|
||||
|
||||
/* step7: enable backlight */
|
||||
intel_backlight_enable(crtc_state, conn_state);
|
||||
intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
|
||||
|
@ -1525,8 +1525,18 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
|
||||
* can rely on frontbuffer tracking.
|
||||
*/
|
||||
mask = EDP_PSR_DEBUG_MASK_MEMUP |
|
||||
EDP_PSR_DEBUG_MASK_HPD |
|
||||
EDP_PSR_DEBUG_MASK_LPSP;
|
||||
EDP_PSR_DEBUG_MASK_HPD;
|
||||
|
||||
/*
|
||||
* For some unknown reason on HSW non-ULT (or at least on
|
||||
* Dell Latitude E6540) external displays start to flicker
|
||||
* when PSR is enabled on the eDP. SR/PC6 residency is much
|
||||
* higher than should be possible with an external display.
|
||||
* As a workaround leave LPSP unmasked to prevent PSR entry
|
||||
* when external displays are active.
|
||||
*/
|
||||
if (DISPLAY_VER(dev_priv) >= 8 || IS_HASWELL_ULT(dev_priv))
|
||||
mask |= EDP_PSR_DEBUG_MASK_LPSP;
|
||||
|
||||
if (DISPLAY_VER(dev_priv) < 20)
|
||||
mask |= EDP_PSR_DEBUG_MASK_MAX_SLEEP;
|
||||
|
@ -62,7 +62,7 @@ nouveau_fence_signal(struct nouveau_fence *fence)
|
||||
if (test_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags)) {
|
||||
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
|
||||
|
||||
if (atomic_dec_and_test(&fctx->notify_ref))
|
||||
if (!--fctx->notify_ref)
|
||||
drop = 1;
|
||||
}
|
||||
|
||||
@ -103,7 +103,6 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error)
|
||||
void
|
||||
nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
|
||||
{
|
||||
cancel_work_sync(&fctx->allow_block_work);
|
||||
nouveau_fence_context_kill(fctx, 0);
|
||||
nvif_event_dtor(&fctx->event);
|
||||
fctx->dead = 1;
|
||||
@ -168,18 +167,6 @@ nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_fence_work_allow_block(struct work_struct *work)
|
||||
{
|
||||
struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan,
|
||||
allow_block_work);
|
||||
|
||||
if (atomic_read(&fctx->notify_ref) == 0)
|
||||
nvif_event_block(&fctx->event);
|
||||
else
|
||||
nvif_event_allow(&fctx->event);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
|
||||
{
|
||||
@ -191,7 +178,6 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
|
||||
} args;
|
||||
int ret;
|
||||
|
||||
INIT_WORK(&fctx->allow_block_work, nouveau_fence_work_allow_block);
|
||||
INIT_LIST_HEAD(&fctx->flip);
|
||||
INIT_LIST_HEAD(&fctx->pending);
|
||||
spin_lock_init(&fctx->lock);
|
||||
@ -535,19 +521,15 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f)
|
||||
struct nouveau_fence *fence = from_fence(f);
|
||||
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
|
||||
bool ret;
|
||||
bool do_work;
|
||||
|
||||
if (atomic_inc_return(&fctx->notify_ref) == 0)
|
||||
do_work = true;
|
||||
if (!fctx->notify_ref++)
|
||||
nvif_event_allow(&fctx->event);
|
||||
|
||||
ret = nouveau_fence_no_signaling(f);
|
||||
if (ret)
|
||||
set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags);
|
||||
else if (atomic_dec_and_test(&fctx->notify_ref))
|
||||
do_work = true;
|
||||
|
||||
if (do_work)
|
||||
schedule_work(&fctx->allow_block_work);
|
||||
else if (!--fctx->notify_ref)
|
||||
nvif_event_block(&fctx->event);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
#define __NOUVEAU_FENCE_H__
|
||||
|
||||
#include <linux/dma-fence.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <nvif/event.h>
|
||||
|
||||
struct nouveau_drm;
|
||||
@ -46,9 +45,7 @@ struct nouveau_fence_chan {
|
||||
char name[32];
|
||||
|
||||
struct nvif_event event;
|
||||
struct work_struct allow_block_work;
|
||||
atomic_t notify_ref;
|
||||
int dead, killed;
|
||||
int notify_ref, dead, killed;
|
||||
};
|
||||
|
||||
struct nouveau_fence_priv {
|
||||
|
@ -539,6 +539,8 @@ config DRM_PANEL_RAYDIUM_RM692E5
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_DP_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
help
|
||||
Say Y here if you want to enable support for Raydium RM692E5-based
|
||||
display panels, such as the one found in the Fairphone 5 smartphone.
|
||||
|
@ -309,7 +309,7 @@ static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = {
|
||||
.off_func = s6d7aa0_lsl080al02_off,
|
||||
.drm_mode = &s6d7aa0_lsl080al02_mode,
|
||||
.mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
|
||||
.bus_flags = 0,
|
||||
|
||||
.has_backlight = false,
|
||||
.use_passwd3 = false,
|
||||
|
@ -3948,6 +3948,7 @@ static const struct panel_desc tianma_tm070jdhg30 = {
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
|
||||
};
|
||||
|
||||
static const struct panel_desc tianma_tm070jvhg33 = {
|
||||
@ -3960,6 +3961,7 @@ static const struct panel_desc tianma_tm070jvhg33 = {
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
|
||||
};
|
||||
|
||||
static const struct display_timing tianma_tm070rvhg71_timing = {
|
||||
|
@ -1178,21 +1178,20 @@ static void drm_sched_run_job_work(struct work_struct *w)
|
||||
struct drm_sched_entity *entity;
|
||||
struct dma_fence *fence;
|
||||
struct drm_sched_fence *s_fence;
|
||||
struct drm_sched_job *sched_job;
|
||||
struct drm_sched_job *sched_job = NULL;
|
||||
int r;
|
||||
|
||||
if (READ_ONCE(sched->pause_submit))
|
||||
return;
|
||||
|
||||
entity = drm_sched_select_entity(sched);
|
||||
if (!entity)
|
||||
return;
|
||||
|
||||
sched_job = drm_sched_entity_pop_job(entity);
|
||||
if (!sched_job) {
|
||||
complete_all(&entity->entity_idle);
|
||||
return; /* No more work */
|
||||
/* Find entity with a ready job */
|
||||
while (!sched_job && (entity = drm_sched_select_entity(sched))) {
|
||||
sched_job = drm_sched_entity_pop_job(entity);
|
||||
if (!sched_job)
|
||||
complete_all(&entity->entity_idle);
|
||||
}
|
||||
if (!entity)
|
||||
return; /* No more work */
|
||||
|
||||
s_fence = sched_job->s_fence;
|
||||
|
||||
|
@ -188,13 +188,13 @@ out:
|
||||
|
||||
static void drm_test_mm_debug(struct kunit *test)
|
||||
{
|
||||
struct drm_printer p = drm_debug_printer(test->name);
|
||||
struct drm_mm mm;
|
||||
struct drm_mm_node nodes[2];
|
||||
|
||||
/* Create a small drm_mm with a couple of nodes and a few holes, and
|
||||
* check that the debug iterator doesn't explode over a trivial drm_mm.
|
||||
*/
|
||||
|
||||
drm_mm_init(&mm, 0, 4096);
|
||||
|
||||
memset(nodes, 0, sizeof(nodes));
|
||||
@ -209,6 +209,9 @@ static void drm_test_mm_debug(struct kunit *test)
|
||||
KUNIT_ASSERT_FALSE_MSG(test, drm_mm_reserve_node(&mm, &nodes[1]),
|
||||
"failed to reserve node[0] {start=%lld, size=%lld)\n",
|
||||
nodes[0].start, nodes[0].size);
|
||||
|
||||
drm_mm_print(&mm, &p);
|
||||
KUNIT_SUCCEED(test);
|
||||
}
|
||||
|
||||
static bool expect_insert(struct kunit *test, struct drm_mm *mm,
|
||||
|
@ -95,11 +95,17 @@ static int ttm_global_init(void)
|
||||
ttm_pool_mgr_init(num_pages);
|
||||
ttm_tt_mgr_init(num_pages, num_dma32);
|
||||
|
||||
glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32);
|
||||
glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32 |
|
||||
__GFP_NOWARN);
|
||||
|
||||
/* Retry without GFP_DMA32 for platforms DMA32 is not available */
|
||||
if (unlikely(glob->dummy_read_page == NULL)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
glob->dummy_read_page = alloc_page(__GFP_ZERO);
|
||||
if (unlikely(glob->dummy_read_page == NULL)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
pr_warn("Using GFP_DMA32 fallback for dummy_read_page\n");
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&glob->device_list);
|
||||
|
@ -147,6 +147,13 @@ v3d_job_allocate(void **container, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
v3d_job_deallocate(void **container)
|
||||
{
|
||||
kfree(*container);
|
||||
*container = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
|
||||
struct v3d_job *job, void (*free)(struct kref *ref),
|
||||
@ -273,8 +280,10 @@ v3d_setup_csd_jobs_and_bos(struct drm_file *file_priv,
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, &(*job)->base,
|
||||
v3d_job_free, args->in_sync, se, V3D_CSD);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
v3d_job_deallocate((void *)job);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = v3d_job_allocate((void *)clean_job, sizeof(**clean_job));
|
||||
if (ret)
|
||||
@ -282,8 +291,10 @@ v3d_setup_csd_jobs_and_bos(struct drm_file *file_priv,
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, *clean_job,
|
||||
v3d_job_free, 0, NULL, V3D_CACHE_CLEAN);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
v3d_job_deallocate((void *)clean_job);
|
||||
return ret;
|
||||
}
|
||||
|
||||
(*job)->args = *args;
|
||||
|
||||
@ -860,8 +871,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, &render->base,
|
||||
v3d_render_job_free, args->in_sync_rcl, &se, V3D_RENDER);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
v3d_job_deallocate((void *)&render);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
render->start = args->rcl_start;
|
||||
render->end = args->rcl_end;
|
||||
@ -874,8 +887,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, &bin->base,
|
||||
v3d_job_free, args->in_sync_bcl, &se, V3D_BIN);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
v3d_job_deallocate((void *)&bin);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bin->start = args->bcl_start;
|
||||
bin->end = args->bcl_end;
|
||||
@ -892,8 +907,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, clean_job,
|
||||
v3d_job_free, 0, NULL, V3D_CACHE_CLEAN);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
v3d_job_deallocate((void *)&clean_job);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
last_job = clean_job;
|
||||
} else {
|
||||
@ -1015,8 +1032,10 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, &job->base,
|
||||
v3d_job_free, args->in_sync, &se, V3D_TFU);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
v3d_job_deallocate((void *)&job);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles),
|
||||
sizeof(*job->base.bo), GFP_KERNEL);
|
||||
@ -1233,8 +1252,10 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, &cpu_job->base,
|
||||
v3d_job_free, 0, &se, V3D_CPU);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
v3d_job_deallocate((void *)&cpu_job);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
clean_job = cpu_job->indirect_csd.clean_job;
|
||||
csd_job = cpu_job->indirect_csd.job;
|
||||
|
@ -35,12 +35,10 @@ static inline int i915_gem_object_read_from_page(struct xe_bo *bo,
|
||||
u32 ofs, u64 *ptr, u32 size)
|
||||
{
|
||||
struct ttm_bo_kmap_obj map;
|
||||
void *virtual;
|
||||
void *src;
|
||||
bool is_iomem;
|
||||
int ret;
|
||||
|
||||
XE_WARN_ON(size != 8);
|
||||
|
||||
ret = xe_bo_lock(bo, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -50,11 +48,12 @@ static inline int i915_gem_object_read_from_page(struct xe_bo *bo,
|
||||
goto out_unlock;
|
||||
|
||||
ofs &= ~PAGE_MASK;
|
||||
virtual = ttm_kmap_obj_virtual(&map, &is_iomem);
|
||||
src = ttm_kmap_obj_virtual(&map, &is_iomem);
|
||||
src += ofs;
|
||||
if (is_iomem)
|
||||
*ptr = readq((void __iomem *)(virtual + ofs));
|
||||
memcpy_fromio(ptr, (void __iomem *)src, size);
|
||||
else
|
||||
*ptr = *(u64 *)(virtual + ofs);
|
||||
memcpy(ptr, src, size);
|
||||
|
||||
ttm_bo_kunmap(&map);
|
||||
out_unlock:
|
||||
|
@ -74,9 +74,6 @@ static const struct platform_test_case cases[] = {
|
||||
SUBPLATFORM_CASE(DG2, G11, B1),
|
||||
SUBPLATFORM_CASE(DG2, G12, A0),
|
||||
SUBPLATFORM_CASE(DG2, G12, A1),
|
||||
PLATFORM_CASE(PVC, B0),
|
||||
PLATFORM_CASE(PVC, B1),
|
||||
PLATFORM_CASE(PVC, C0),
|
||||
GMDID_CASE(METEORLAKE, 1270, A0, 1300, A0),
|
||||
GMDID_CASE(METEORLAKE, 1271, A0, 1300, A0),
|
||||
GMDID_CASE(LUNARLAKE, 2004, A0, 2000, A0),
|
||||
|
@ -613,7 +613,7 @@ void xe_device_wmb(struct xe_device *xe)
|
||||
u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size)
|
||||
{
|
||||
return xe_device_has_flat_ccs(xe) ?
|
||||
DIV_ROUND_UP(size, NUM_BYTES_PER_CCS_BYTE(xe)) : 0;
|
||||
DIV_ROUND_UP_ULL(size, NUM_BYTES_PER_CCS_BYTE(xe)) : 0;
|
||||
}
|
||||
|
||||
bool xe_device_mem_access_ongoing(struct xe_device *xe)
|
||||
|
@ -175,7 +175,7 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dma_buf_ops xe_dmabuf_ops = {
|
||||
static const struct dma_buf_ops xe_dmabuf_ops = {
|
||||
.attach = xe_dma_buf_attach,
|
||||
.detach = xe_dma_buf_detach,
|
||||
.pin = xe_dma_buf_pin,
|
||||
|
@ -419,7 +419,7 @@ static int xe_hwmon_pcode_read_i1(struct xe_gt *gt, u32 *uval)
|
||||
|
||||
return xe_pcode_read(gt, PCODE_MBOX(PCODE_POWER_SETUP,
|
||||
POWER_SETUP_SUBCOMMAND_READ_I1, 0),
|
||||
uval, 0);
|
||||
uval, NULL);
|
||||
}
|
||||
|
||||
static int xe_hwmon_pcode_write_i1(struct xe_gt *gt, u32 uval)
|
||||
|
@ -472,7 +472,7 @@ static void emit_pte(struct xe_migrate *m,
|
||||
/* Indirect access needs compression enabled uncached PAT index */
|
||||
if (GRAPHICS_VERx100(xe) >= 2000)
|
||||
pat_index = is_comp_pte ? xe->pat.idx[XE_CACHE_NONE_COMPRESSION] :
|
||||
xe->pat.idx[XE_CACHE_NONE];
|
||||
xe->pat.idx[XE_CACHE_WB];
|
||||
else
|
||||
pat_index = xe->pat.idx[XE_CACHE_WB];
|
||||
|
||||
@ -760,14 +760,14 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m,
|
||||
if (src_is_vram && xe_migrate_allow_identity(src_L0, &src_it))
|
||||
xe_res_next(&src_it, src_L0);
|
||||
else
|
||||
emit_pte(m, bb, src_L0_pt, src_is_vram, true, &src_it, src_L0,
|
||||
src);
|
||||
emit_pte(m, bb, src_L0_pt, src_is_vram, copy_system_ccs,
|
||||
&src_it, src_L0, src);
|
||||
|
||||
if (dst_is_vram && xe_migrate_allow_identity(src_L0, &dst_it))
|
||||
xe_res_next(&dst_it, src_L0);
|
||||
else
|
||||
emit_pte(m, bb, dst_L0_pt, dst_is_vram, true, &dst_it, src_L0,
|
||||
dst);
|
||||
emit_pte(m, bb, dst_L0_pt, dst_is_vram, copy_system_ccs,
|
||||
&dst_it, src_L0, dst);
|
||||
|
||||
if (copy_system_ccs)
|
||||
emit_pte(m, bb, ccs_pt, false, false, &ccs_it, ccs_size, src);
|
||||
@ -1009,8 +1009,8 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m,
|
||||
if (clear_vram && xe_migrate_allow_identity(clear_L0, &src_it))
|
||||
xe_res_next(&src_it, clear_L0);
|
||||
else
|
||||
emit_pte(m, bb, clear_L0_pt, clear_vram, true, &src_it, clear_L0,
|
||||
dst);
|
||||
emit_pte(m, bb, clear_L0_pt, clear_vram, clear_system_ccs,
|
||||
&src_it, clear_L0, dst);
|
||||
|
||||
bb->cs[bb->len++] = MI_BATCH_BUFFER_END;
|
||||
update_idx = bb->len;
|
||||
|
@ -272,8 +272,8 @@ int xe_mmio_probe_vram(struct xe_device *xe)
|
||||
drm_info(&xe->drm, "VRAM[%u, %u]: Actual physical size %pa, usable size exclude stolen %pa, CPU accessible size %pa\n", id,
|
||||
tile->id, &tile->mem.vram.actual_physical_size, &tile->mem.vram.usable_size, &tile->mem.vram.io_size);
|
||||
drm_info(&xe->drm, "VRAM[%u, %u]: DPA range: [%pa-%llx], io range: [%pa-%llx]\n", id, tile->id,
|
||||
&tile->mem.vram.dpa_base, tile->mem.vram.dpa_base + tile->mem.vram.actual_physical_size,
|
||||
&tile->mem.vram.io_start, tile->mem.vram.io_start + tile->mem.vram.io_size);
|
||||
&tile->mem.vram.dpa_base, tile->mem.vram.dpa_base + (u64)tile->mem.vram.actual_physical_size,
|
||||
&tile->mem.vram.io_start, tile->mem.vram.io_start + (u64)tile->mem.vram.io_size);
|
||||
|
||||
/* calculate total size using tile size to get the correct HW sizing */
|
||||
total_size += tile_size;
|
||||
|
@ -1855,10 +1855,8 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data,
|
||||
mutex_lock(&xef->vm.lock);
|
||||
err = xa_alloc(&xef->vm.xa, &id, vm, xa_limit_32b, GFP_KERNEL);
|
||||
mutex_unlock(&xef->vm.lock);
|
||||
if (err) {
|
||||
xe_vm_close_and_put(vm);
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
goto err_close_and_put;
|
||||
|
||||
if (xe->info.has_asid) {
|
||||
mutex_lock(&xe->usm.lock);
|
||||
@ -1866,11 +1864,9 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data,
|
||||
XA_LIMIT(1, XE_MAX_ASID - 1),
|
||||
&xe->usm.next_asid, GFP_KERNEL);
|
||||
mutex_unlock(&xe->usm.lock);
|
||||
if (err < 0) {
|
||||
xe_vm_close_and_put(vm);
|
||||
return err;
|
||||
}
|
||||
err = 0;
|
||||
if (err < 0)
|
||||
goto err_free_id;
|
||||
|
||||
vm->usm.asid = asid;
|
||||
}
|
||||
|
||||
@ -1888,6 +1884,15 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data,
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_id:
|
||||
mutex_lock(&xef->vm.lock);
|
||||
xa_erase(&xef->vm.xa, id);
|
||||
mutex_unlock(&xef->vm.lock);
|
||||
err_close_and_put:
|
||||
xe_vm_close_and_put(vm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int xe_vm_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
|
@ -53,7 +53,7 @@ extern "C" {
|
||||
#define DRM_IVPU_PARAM_CORE_CLOCK_RATE 3
|
||||
#define DRM_IVPU_PARAM_NUM_CONTEXTS 4
|
||||
#define DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS 5
|
||||
#define DRM_IVPU_PARAM_CONTEXT_PRIORITY 6
|
||||
#define DRM_IVPU_PARAM_CONTEXT_PRIORITY 6 /* Deprecated */
|
||||
#define DRM_IVPU_PARAM_CONTEXT_ID 7
|
||||
#define DRM_IVPU_PARAM_FW_API_VERSION 8
|
||||
#define DRM_IVPU_PARAM_ENGINE_HEARTBEAT 9
|
||||
@ -64,11 +64,18 @@ extern "C" {
|
||||
|
||||
#define DRM_IVPU_PLATFORM_TYPE_SILICON 0
|
||||
|
||||
/* Deprecated, use DRM_IVPU_JOB_PRIORITY */
|
||||
#define DRM_IVPU_CONTEXT_PRIORITY_IDLE 0
|
||||
#define DRM_IVPU_CONTEXT_PRIORITY_NORMAL 1
|
||||
#define DRM_IVPU_CONTEXT_PRIORITY_FOCUS 2
|
||||
#define DRM_IVPU_CONTEXT_PRIORITY_REALTIME 3
|
||||
|
||||
#define DRM_IVPU_JOB_PRIORITY_DEFAULT 0
|
||||
#define DRM_IVPU_JOB_PRIORITY_IDLE 1
|
||||
#define DRM_IVPU_JOB_PRIORITY_NORMAL 2
|
||||
#define DRM_IVPU_JOB_PRIORITY_FOCUS 3
|
||||
#define DRM_IVPU_JOB_PRIORITY_REALTIME 4
|
||||
|
||||
/**
|
||||
* DRM_IVPU_CAP_METRIC_STREAMER
|
||||
*
|
||||
@ -112,10 +119,6 @@ struct drm_ivpu_param {
|
||||
* %DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
|
||||
* Lowest VPU virtual address available in the current context (read-only)
|
||||
*
|
||||
* %DRM_IVPU_PARAM_CONTEXT_PRIORITY:
|
||||
* Value of current context scheduling priority (read-write).
|
||||
* See DRM_IVPU_CONTEXT_PRIORITY_* for possible values.
|
||||
*
|
||||
* %DRM_IVPU_PARAM_CONTEXT_ID:
|
||||
* Current context ID, always greater than 0 (read-only)
|
||||
*
|
||||
@ -286,6 +289,18 @@ struct drm_ivpu_submit {
|
||||
* to be executed. The offset has to be 8-byte aligned.
|
||||
*/
|
||||
__u32 commands_offset;
|
||||
|
||||
/**
|
||||
* @priority:
|
||||
*
|
||||
* Priority to be set for related job command queue, can be one of the following:
|
||||
* %DRM_IVPU_JOB_PRIORITY_DEFAULT
|
||||
* %DRM_IVPU_JOB_PRIORITY_IDLE
|
||||
* %DRM_IVPU_JOB_PRIORITY_NORMAL
|
||||
* %DRM_IVPU_JOB_PRIORITY_FOCUS
|
||||
* %DRM_IVPU_JOB_PRIORITY_REALTIME
|
||||
*/
|
||||
__u32 priority;
|
||||
};
|
||||
|
||||
/* drm_ivpu_bo_wait job status codes */
|
||||
|
Loading…
Reference in New Issue
Block a user