mirror of
https://github.com/torvalds/linux.git
synced 2026-03-07 21:24:37 +01:00
drm fixes for 7.0-rc3
mm: - mm: Fix a hmm_range_fault() livelock / starvation problem pagemap: - Revert "drm/pagemap: Disable device-to-device migration" ttm: - fix function return breaking reclaim - fix build failure on PREEMPT_RT - fix bo->resource UAF dma-buf: - include ioctl.h in uapi header sched: - fix kernel doc warning amdgpu: - LUT fixes - VCN5 fix - Dispclk fix - SMU 13.x fix - Fix race in VM acquire - PSP 15.x fix - UserQ fix amdxdna: - fix invalid payload for failed command - fix NULL ptr dereference - fix major fw version check - avoid inconsistent fw state on error i915/display: - Fix for Lenovo T14 G7 display not refreshing xe: - Do not preempt fence signaling CS instructions - Some leak and finalization fixes - Workaround fix nouveau: - avoid runtime suspend oops when using dp aux panthor: - fix gem_sync argument ordering solomon: - fix incorrect display output renesas: - fix DSI divider programming ethosu: - fix job submit error clean-up refcount - fix NPU_OP_ELEMENTWISE validation - handle possible underflows in IFM size calcs -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmmrODEACgkQDHTzWXnE hr6ENA/9E+ABsQPUSr1ZUR6MfS3FdDMfyNi34u9F0XE0vL/6J4DIN2MXHJN0yj4S YeR8RIH1uuteexRCVjK8gYrDFZm5GpdJ7tZsPBogKSjfr4P4zvSdcyP0DtubmHN8 k/Rbdr1m2BnAerviPUlQ09voG4VyM/IlnkOj/aUrAG4xHfNLWhQ/eY21HjvTaMEw eNPk75G32AkusybhYGLcfRKUqmZ9Sh/EAIOiqp5Gd61bSbNXFbXqU59AliRSW16D dRMjCenQbBtXnf1xzn9xmC95Mr5NhlId3BddY6nsmTvqnse50w1IBw4MbA5703iv teNAsRHNWBiyachtolylu63z8fjc3mqRgyB3qoYCIn4pGm6wej3SSuOr+WaKTPMr ucKNxvsluiXOIdUrkLYyl1LTU1Bqs2/mFTPzyHFykeB72swHGyCfYyh/RgL+dYIc nuOsY1n4JR1JCkg5p4Y8LZq0RXLE6PJfyxmpF9W2r9DVV4T52Yk5fiXEo+HJ9WaJ yaa3xBJJLP0z50JuaV7iEIiXQBwj482m0No+jG4+ZTatRm/4oz0cHpmoRkPuN6Og vc6UdFUtRysVqSetLfV1oBpLm3zkhumDxtrqb6GHB7n+ahY7mFCLc175wFXoGCqu DxCshK5FZchyPbOXaxOWyIVXDCYJtCJnK4vBCHwkJAkxLQCpv/k= =yGA4 -----END PGP SIGNATURE----- Merge tag 'drm-fixes-2026-03-07' of https://gitlab.freedesktop.org/drm/kernel Pull drm fixes from Dave Airlie: "Weekly fixes pull. There is one mm fix in here for a HMM livelock triggered by the xe driver tests. Otherwise it's a pretty wide range of fixes across the board, ttm UAF regression fix, amdgpu fixes, nouveau doesn't crash my laptop anymore fix, and a fair bit of misc. Seems about right for rc3. mm: - mm: Fix a hmm_range_fault() livelock / starvation problem pagemap: - Revert "drm/pagemap: Disable device-to-device migration" ttm: - fix function return breaking reclaim - fix build failure on PREEMPT_RT - fix bo->resource UAF dma-buf: - include ioctl.h in uapi header sched: - fix kernel doc warning amdgpu: - LUT fixes - VCN5 fix - Dispclk fix - SMU 13.x fix - Fix race in VM acquire - PSP 15.x fix - UserQ fix amdxdna: - fix invalid payload for failed command - fix NULL ptr dereference - fix major fw version check - avoid inconsistent fw state on error i915/display: - Fix for Lenovo T14 G7 display not refreshing xe: - Do not preempt fence signaling CS instructions - Some leak and finalization fixes - Workaround fix nouveau: - avoid runtime suspend oops when using dp aux panthor: - fix gem_sync argument ordering solomon: - fix incorrect display output renesas: - fix DSI divider programming ethosu: - fix job submit error clean-up refcount - fix NPU_OP_ELEMENTWISE validation - handle possible underflows in IFM size calcs" * tag 'drm-fixes-2026-03-07' of https://gitlab.freedesktop.org/drm/kernel: (38 commits) accel: ethosu: Handle possible underflow in IFM size calculations accel: ethosu: Fix NPU_OP_ELEMENTWISE validation with scalar accel: ethosu: Fix job submit error clean-up refcount underflows accel/amdxdna: Split mailbox channel create function drm/panthor: Correct the order of arguments passed to gem_sync Revert "drm/syncobj: Fix handle <-> fd ioctls with dirty stack" drm/ttm: Fix bo resource use-after-free nouveau/dpcd: return EBUSY for aux xfer if the device is asleep accel/amdxdna: Fix major version check on NPU1 platform drm/amdgpu/userq: refcount userqueues to avoid any race conditions drm/amdgpu/userq: Consolidate wait ioctl exit path drm/amdgpu/psp: Use Indirect access address for GFX to PSP mailbox drm/amdgpu: Fix use-after-free race in VM acquire drm/amd/pm: remove invalid gpu_metrics.energy_accumulator on smu v13.0.x drm/xe: Fix memory leak in xe_vm_madvise_ioctl drm/xe/reg_sr: Fix leak on xa_store failure drm/xe/xe2_hpg: Correct implementation of Wa_16025250150 drm/xe/gsc: Fix GSC proxy cleanup on early initialization failure Revert "drm/pagemap: Disable device-to-device migration" drm/i915/psr: Fix for Panel Replay X granularity DPCD register handling ...
This commit is contained in:
commit
dfb3142844
51 changed files with 516 additions and 291 deletions
|
|
@ -186,13 +186,13 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
|
|||
cmd_abo = job->cmd_bo;
|
||||
|
||||
if (unlikely(job->job_timeout)) {
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT);
|
||||
amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_TIMEOUT);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(!data) || unlikely(size != sizeof(u32))) {
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
|
||||
amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -202,7 +202,7 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
|
|||
if (status == AIE2_STATUS_SUCCESS)
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_COMPLETED);
|
||||
else
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ERROR);
|
||||
amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ERROR);
|
||||
|
||||
out:
|
||||
aie2_sched_notify(job);
|
||||
|
|
@ -244,13 +244,13 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
|
|||
cmd_abo = job->cmd_bo;
|
||||
|
||||
if (unlikely(job->job_timeout)) {
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT);
|
||||
amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_TIMEOUT);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(!data) || unlikely(size != sizeof(u32) * 3)) {
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
|
||||
amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -270,19 +270,12 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
|
|||
fail_cmd_idx, fail_cmd_status);
|
||||
|
||||
if (fail_cmd_status == AIE2_STATUS_SUCCESS) {
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
|
||||
amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ABORT);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
} else {
|
||||
amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ERROR);
|
||||
}
|
||||
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ERROR);
|
||||
|
||||
if (amdxdna_cmd_get_op(cmd_abo) == ERT_CMD_CHAIN) {
|
||||
struct amdxdna_cmd_chain *cc = amdxdna_cmd_get_payload(cmd_abo, NULL);
|
||||
|
||||
cc->error_index = fail_cmd_idx;
|
||||
if (cc->error_index >= cc->command_count)
|
||||
cc->error_index = 0;
|
||||
}
|
||||
out:
|
||||
aie2_sched_notify(job);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -40,11 +40,8 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev,
|
|||
return -ENODEV;
|
||||
|
||||
ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg);
|
||||
if (ret == -ETIME) {
|
||||
xdna_mailbox_stop_channel(ndev->mgmt_chann);
|
||||
xdna_mailbox_destroy_channel(ndev->mgmt_chann);
|
||||
ndev->mgmt_chann = NULL;
|
||||
}
|
||||
if (ret == -ETIME)
|
||||
aie2_destroy_mgmt_chann(ndev);
|
||||
|
||||
if (!ret && *hdl->status != AIE2_STATUS_SUCCESS) {
|
||||
XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x",
|
||||
|
|
@ -296,13 +293,20 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
|
|||
}
|
||||
|
||||
intr_reg = i2x.mb_head_ptr_reg + 4;
|
||||
hwctx->priv->mbox_chann = xdna_mailbox_create_channel(ndev->mbox, &x2i, &i2x,
|
||||
intr_reg, ret);
|
||||
hwctx->priv->mbox_chann = xdna_mailbox_alloc_channel(ndev->mbox);
|
||||
if (!hwctx->priv->mbox_chann) {
|
||||
XDNA_ERR(xdna, "Not able to create channel");
|
||||
ret = -EINVAL;
|
||||
goto del_ctx_req;
|
||||
}
|
||||
|
||||
ret = xdna_mailbox_start_channel(hwctx->priv->mbox_chann, &x2i, &i2x,
|
||||
intr_reg, ret);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Not able to create channel");
|
||||
ret = -EINVAL;
|
||||
goto free_channel;
|
||||
}
|
||||
ndev->hwctx_num++;
|
||||
|
||||
XDNA_DBG(xdna, "Mailbox channel irq: %d, msix_id: %d", ret, resp.msix_id);
|
||||
|
|
@ -310,6 +314,8 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
|
|||
|
||||
return 0;
|
||||
|
||||
free_channel:
|
||||
xdna_mailbox_free_channel(hwctx->priv->mbox_chann);
|
||||
del_ctx_req:
|
||||
aie2_destroy_context_req(ndev, hwctx->fw_ctx_id);
|
||||
return ret;
|
||||
|
|
@ -325,7 +331,7 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwc
|
|||
|
||||
xdna_mailbox_stop_channel(hwctx->priv->mbox_chann);
|
||||
ret = aie2_destroy_context_req(ndev, hwctx->fw_ctx_id);
|
||||
xdna_mailbox_destroy_channel(hwctx->priv->mbox_chann);
|
||||
xdna_mailbox_free_channel(hwctx->priv->mbox_chann);
|
||||
XDNA_DBG(xdna, "Destroyed fw ctx %d", hwctx->fw_ctx_id);
|
||||
hwctx->priv->mbox_chann = NULL;
|
||||
hwctx->fw_ctx_id = -1;
|
||||
|
|
@ -914,6 +920,20 @@ void aie2_msg_init(struct amdxdna_dev_hdl *ndev)
|
|||
ndev->exec_msg_ops = &legacy_exec_message_ops;
|
||||
}
|
||||
|
||||
void aie2_destroy_mgmt_chann(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
if (!ndev->mgmt_chann)
|
||||
return;
|
||||
|
||||
xdna_mailbox_stop_channel(ndev->mgmt_chann);
|
||||
xdna_mailbox_free_channel(ndev->mgmt_chann);
|
||||
ndev->mgmt_chann = NULL;
|
||||
}
|
||||
|
||||
static inline struct amdxdna_gem_obj *
|
||||
aie2_cmdlist_get_cmd_buf(struct amdxdna_sched_job *job)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -330,9 +330,7 @@ static void aie2_hw_stop(struct amdxdna_dev *xdna)
|
|||
|
||||
aie2_runtime_cfg(ndev, AIE2_RT_CFG_CLK_GATING, NULL);
|
||||
aie2_mgmt_fw_fini(ndev);
|
||||
xdna_mailbox_stop_channel(ndev->mgmt_chann);
|
||||
xdna_mailbox_destroy_channel(ndev->mgmt_chann);
|
||||
ndev->mgmt_chann = NULL;
|
||||
aie2_destroy_mgmt_chann(ndev);
|
||||
drmm_kfree(&xdna->ddev, ndev->mbox);
|
||||
ndev->mbox = NULL;
|
||||
aie2_psp_stop(ndev->psp_hdl);
|
||||
|
|
@ -363,10 +361,29 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
|||
}
|
||||
pci_set_master(pdev);
|
||||
|
||||
mbox_res.ringbuf_base = ndev->sram_base;
|
||||
mbox_res.ringbuf_size = pci_resource_len(pdev, xdna->dev_info->sram_bar);
|
||||
mbox_res.mbox_base = ndev->mbox_base;
|
||||
mbox_res.mbox_size = MBOX_SIZE(ndev);
|
||||
mbox_res.name = "xdna_mailbox";
|
||||
ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
|
||||
if (!ndev->mbox) {
|
||||
XDNA_ERR(xdna, "failed to create mailbox device");
|
||||
ret = -ENODEV;
|
||||
goto disable_dev;
|
||||
}
|
||||
|
||||
ndev->mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
|
||||
if (!ndev->mgmt_chann) {
|
||||
XDNA_ERR(xdna, "failed to alloc channel");
|
||||
ret = -ENODEV;
|
||||
goto disable_dev;
|
||||
}
|
||||
|
||||
ret = aie2_smu_init(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to init smu, ret %d", ret);
|
||||
goto disable_dev;
|
||||
goto free_channel;
|
||||
}
|
||||
|
||||
ret = aie2_psp_start(ndev->psp_hdl);
|
||||
|
|
@ -381,18 +398,6 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
|||
goto stop_psp;
|
||||
}
|
||||
|
||||
mbox_res.ringbuf_base = ndev->sram_base;
|
||||
mbox_res.ringbuf_size = pci_resource_len(pdev, xdna->dev_info->sram_bar);
|
||||
mbox_res.mbox_base = ndev->mbox_base;
|
||||
mbox_res.mbox_size = MBOX_SIZE(ndev);
|
||||
mbox_res.name = "xdna_mailbox";
|
||||
ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
|
||||
if (!ndev->mbox) {
|
||||
XDNA_ERR(xdna, "failed to create mailbox device");
|
||||
ret = -ENODEV;
|
||||
goto stop_psp;
|
||||
}
|
||||
|
||||
mgmt_mb_irq = pci_irq_vector(pdev, ndev->mgmt_chan_idx);
|
||||
if (mgmt_mb_irq < 0) {
|
||||
ret = mgmt_mb_irq;
|
||||
|
|
@ -401,13 +406,13 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
|||
}
|
||||
|
||||
xdna_mailbox_intr_reg = ndev->mgmt_i2x.mb_head_ptr_reg + 4;
|
||||
ndev->mgmt_chann = xdna_mailbox_create_channel(ndev->mbox,
|
||||
&ndev->mgmt_x2i,
|
||||
&ndev->mgmt_i2x,
|
||||
xdna_mailbox_intr_reg,
|
||||
mgmt_mb_irq);
|
||||
if (!ndev->mgmt_chann) {
|
||||
XDNA_ERR(xdna, "failed to create management mailbox channel");
|
||||
ret = xdna_mailbox_start_channel(ndev->mgmt_chann,
|
||||
&ndev->mgmt_x2i,
|
||||
&ndev->mgmt_i2x,
|
||||
xdna_mailbox_intr_reg,
|
||||
mgmt_mb_irq);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to start management mailbox channel");
|
||||
ret = -EINVAL;
|
||||
goto stop_psp;
|
||||
}
|
||||
|
|
@ -415,38 +420,41 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
|||
ret = aie2_mgmt_fw_init(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "initial mgmt firmware failed, ret %d", ret);
|
||||
goto destroy_mgmt_chann;
|
||||
goto stop_fw;
|
||||
}
|
||||
|
||||
ret = aie2_pm_init(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to init pm, ret %d", ret);
|
||||
goto destroy_mgmt_chann;
|
||||
goto stop_fw;
|
||||
}
|
||||
|
||||
ret = aie2_mgmt_fw_query(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to query fw, ret %d", ret);
|
||||
goto destroy_mgmt_chann;
|
||||
goto stop_fw;
|
||||
}
|
||||
|
||||
ret = aie2_error_async_events_alloc(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Allocate async events failed, ret %d", ret);
|
||||
goto destroy_mgmt_chann;
|
||||
goto stop_fw;
|
||||
}
|
||||
|
||||
ndev->dev_status = AIE2_DEV_START;
|
||||
|
||||
return 0;
|
||||
|
||||
destroy_mgmt_chann:
|
||||
stop_fw:
|
||||
aie2_suspend_fw(ndev);
|
||||
xdna_mailbox_stop_channel(ndev->mgmt_chann);
|
||||
xdna_mailbox_destroy_channel(ndev->mgmt_chann);
|
||||
stop_psp:
|
||||
aie2_psp_stop(ndev->psp_hdl);
|
||||
fini_smu:
|
||||
aie2_smu_fini(ndev);
|
||||
free_channel:
|
||||
xdna_mailbox_free_channel(ndev->mgmt_chann);
|
||||
ndev->mgmt_chann = NULL;
|
||||
disable_dev:
|
||||
pci_disable_device(pdev);
|
||||
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev,
|
|||
|
||||
/* aie2_message.c */
|
||||
void aie2_msg_init(struct amdxdna_dev_hdl *ndev);
|
||||
void aie2_destroy_mgmt_chann(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_resume_fw(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value);
|
||||
|
|
|
|||
|
|
@ -135,6 +135,33 @@ u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo)
|
|||
return INVALID_CU_IDX;
|
||||
}
|
||||
|
||||
int amdxdna_cmd_set_error(struct amdxdna_gem_obj *abo,
|
||||
struct amdxdna_sched_job *job, u32 cmd_idx,
|
||||
enum ert_cmd_state error_state)
|
||||
{
|
||||
struct amdxdna_client *client = job->hwctx->client;
|
||||
struct amdxdna_cmd *cmd = abo->mem.kva;
|
||||
struct amdxdna_cmd_chain *cc = NULL;
|
||||
|
||||
cmd->header &= ~AMDXDNA_CMD_STATE;
|
||||
cmd->header |= FIELD_PREP(AMDXDNA_CMD_STATE, error_state);
|
||||
|
||||
if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN) {
|
||||
cc = amdxdna_cmd_get_payload(abo, NULL);
|
||||
cc->error_index = (cmd_idx < cc->command_count) ? cmd_idx : 0;
|
||||
abo = amdxdna_gem_get_obj(client, cc->data[0], AMDXDNA_BO_CMD);
|
||||
if (!abo)
|
||||
return -EINVAL;
|
||||
cmd = abo->mem.kva;
|
||||
}
|
||||
|
||||
memset(cmd->data, 0xff, abo->mem.size - sizeof(*cmd));
|
||||
if (cc)
|
||||
amdxdna_gem_put_obj(abo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This should be called in close() and remove(). DO NOT call in other syscalls.
|
||||
* This guarantee that when hwctx and resources will be released, if user
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ amdxdna_cmd_get_state(struct amdxdna_gem_obj *abo)
|
|||
|
||||
void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size);
|
||||
u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo);
|
||||
int amdxdna_cmd_set_error(struct amdxdna_gem_obj *abo,
|
||||
struct amdxdna_sched_job *job, u32 cmd_idx,
|
||||
enum ert_cmd_state error_state);
|
||||
|
||||
void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job);
|
||||
void amdxdna_hwctx_remove_all(struct amdxdna_client *client);
|
||||
|
|
|
|||
|
|
@ -460,26 +460,49 @@ msg_id_failed:
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct mailbox_channel *
|
||||
xdna_mailbox_create_channel(struct mailbox *mb,
|
||||
const struct xdna_mailbox_chann_res *x2i,
|
||||
const struct xdna_mailbox_chann_res *i2x,
|
||||
u32 iohub_int_addr,
|
||||
int mb_irq)
|
||||
struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb)
|
||||
{
|
||||
struct mailbox_channel *mb_chann;
|
||||
int ret;
|
||||
|
||||
if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
|
||||
pr_err("Ring buf size must be power of 2");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mb_chann = kzalloc_obj(*mb_chann);
|
||||
if (!mb_chann)
|
||||
return NULL;
|
||||
|
||||
INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
|
||||
mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
|
||||
if (!mb_chann->work_q) {
|
||||
MB_ERR(mb_chann, "Create workqueue failed");
|
||||
goto free_chann;
|
||||
}
|
||||
mb_chann->mb = mb;
|
||||
|
||||
return mb_chann;
|
||||
|
||||
free_chann:
|
||||
kfree(mb_chann);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xdna_mailbox_free_channel(struct mailbox_channel *mb_chann)
|
||||
{
|
||||
destroy_workqueue(mb_chann->work_q);
|
||||
kfree(mb_chann);
|
||||
}
|
||||
|
||||
int
|
||||
xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
|
||||
const struct xdna_mailbox_chann_res *x2i,
|
||||
const struct xdna_mailbox_chann_res *i2x,
|
||||
u32 iohub_int_addr,
|
||||
int mb_irq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
|
||||
pr_err("Ring buf size must be power of 2");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mb_chann->msix_irq = mb_irq;
|
||||
mb_chann->iohub_int_addr = iohub_int_addr;
|
||||
memcpy(&mb_chann->res[CHAN_RES_X2I], x2i, sizeof(*x2i));
|
||||
|
|
@ -489,61 +512,37 @@ xdna_mailbox_create_channel(struct mailbox *mb,
|
|||
mb_chann->x2i_tail = mailbox_get_tailptr(mb_chann, CHAN_RES_X2I);
|
||||
mb_chann->i2x_head = mailbox_get_headptr(mb_chann, CHAN_RES_I2X);
|
||||
|
||||
INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
|
||||
mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
|
||||
if (!mb_chann->work_q) {
|
||||
MB_ERR(mb_chann, "Create workqueue failed");
|
||||
goto free_and_out;
|
||||
}
|
||||
|
||||
/* Everything look good. Time to enable irq handler */
|
||||
ret = request_irq(mb_irq, mailbox_irq_handler, 0, MAILBOX_NAME, mb_chann);
|
||||
if (ret) {
|
||||
MB_ERR(mb_chann, "Failed to request irq %d ret %d", mb_irq, ret);
|
||||
goto destroy_wq;
|
||||
return ret;
|
||||
}
|
||||
|
||||
mb_chann->bad_state = false;
|
||||
mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
|
||||
|
||||
MB_DBG(mb_chann, "Mailbox channel created (irq: %d)", mb_chann->msix_irq);
|
||||
return mb_chann;
|
||||
|
||||
destroy_wq:
|
||||
destroy_workqueue(mb_chann->work_q);
|
||||
free_and_out:
|
||||
kfree(mb_chann);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xdna_mailbox_destroy_channel(struct mailbox_channel *mb_chann)
|
||||
{
|
||||
struct mailbox_msg *mb_msg;
|
||||
unsigned long msg_id;
|
||||
|
||||
MB_DBG(mb_chann, "IRQ disabled and RX work cancelled");
|
||||
free_irq(mb_chann->msix_irq, mb_chann);
|
||||
destroy_workqueue(mb_chann->work_q);
|
||||
/* We can clean up and release resources */
|
||||
|
||||
xa_for_each(&mb_chann->chan_xa, msg_id, mb_msg)
|
||||
mailbox_release_msg(mb_chann, mb_msg);
|
||||
|
||||
xa_destroy(&mb_chann->chan_xa);
|
||||
|
||||
MB_DBG(mb_chann, "Mailbox channel destroyed, irq: %d", mb_chann->msix_irq);
|
||||
kfree(mb_chann);
|
||||
MB_DBG(mb_chann, "Mailbox channel started (irq: %d)", mb_chann->msix_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
|
||||
{
|
||||
struct mailbox_msg *mb_msg;
|
||||
unsigned long msg_id;
|
||||
|
||||
/* Disable an irq and wait. This might sleep. */
|
||||
disable_irq(mb_chann->msix_irq);
|
||||
free_irq(mb_chann->msix_irq, mb_chann);
|
||||
|
||||
/* Cancel RX work and wait for it to finish */
|
||||
cancel_work_sync(&mb_chann->rx_work);
|
||||
MB_DBG(mb_chann, "IRQ disabled and RX work cancelled");
|
||||
drain_workqueue(mb_chann->work_q);
|
||||
|
||||
/* We can clean up and release resources */
|
||||
xa_for_each(&mb_chann->chan_xa, msg_id, mb_msg)
|
||||
mailbox_release_msg(mb_chann, mb_msg);
|
||||
xa_destroy(&mb_chann->chan_xa);
|
||||
|
||||
MB_DBG(mb_chann, "Mailbox channel stopped, irq: %d", mb_chann->msix_irq);
|
||||
}
|
||||
|
||||
struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,
|
||||
|
|
|
|||
|
|
@ -74,9 +74,16 @@ struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,
|
|||
const struct xdna_mailbox_res *res);
|
||||
|
||||
/*
|
||||
* xdna_mailbox_create_channel() -- Create a mailbox channel instance
|
||||
* xdna_mailbox_alloc_channel() -- alloc a mailbox channel
|
||||
*
|
||||
* @mailbox: the handle return from xdna_mailbox_create()
|
||||
* @mb: mailbox handle
|
||||
*/
|
||||
struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb);
|
||||
|
||||
/*
|
||||
* xdna_mailbox_start_channel() -- start a mailbox channel instance
|
||||
*
|
||||
* @mb_chann: the handle return from xdna_mailbox_alloc_channel()
|
||||
* @x2i: host to firmware mailbox resources
|
||||
* @i2x: firmware to host mailbox resources
|
||||
* @xdna_mailbox_intr_reg: register addr of MSI-X interrupt
|
||||
|
|
@ -84,28 +91,24 @@ struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,
|
|||
*
|
||||
* Return: If success, return a handle of mailbox channel. Otherwise, return NULL.
|
||||
*/
|
||||
struct mailbox_channel *
|
||||
xdna_mailbox_create_channel(struct mailbox *mailbox,
|
||||
const struct xdna_mailbox_chann_res *x2i,
|
||||
const struct xdna_mailbox_chann_res *i2x,
|
||||
u32 xdna_mailbox_intr_reg,
|
||||
int mb_irq);
|
||||
int
|
||||
xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
|
||||
const struct xdna_mailbox_chann_res *x2i,
|
||||
const struct xdna_mailbox_chann_res *i2x,
|
||||
u32 xdna_mailbox_intr_reg,
|
||||
int mb_irq);
|
||||
|
||||
/*
|
||||
* xdna_mailbox_destroy_channel() -- destroy mailbox channel
|
||||
* xdna_mailbox_free_channel() -- free mailbox channel
|
||||
*
|
||||
* @mailbox_chann: the handle return from xdna_mailbox_create_channel()
|
||||
*
|
||||
* Return: if success, return 0. otherwise return error code
|
||||
*/
|
||||
int xdna_mailbox_destroy_channel(struct mailbox_channel *mailbox_chann);
|
||||
void xdna_mailbox_free_channel(struct mailbox_channel *mailbox_chann);
|
||||
|
||||
/*
|
||||
* xdna_mailbox_stop_channel() -- stop mailbox channel
|
||||
*
|
||||
* @mailbox_chann: the handle return from xdna_mailbox_create_channel()
|
||||
*
|
||||
* Return: if success, return 0. otherwise return error code
|
||||
*/
|
||||
void xdna_mailbox_stop_channel(struct mailbox_channel *mailbox_chann);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ const struct dpm_clk_freq npu1_dpm_clk_table[] = {
|
|||
|
||||
static const struct aie2_fw_feature_tbl npu1_fw_feature_table[] = {
|
||||
{ .major = 5, .min_minor = 7 },
|
||||
{ .features = BIT_U64(AIE2_NPU_COMMAND), .min_minor = 8 },
|
||||
{ .features = BIT_U64(AIE2_NPU_COMMAND), .major = 5, .min_minor = 8 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -245,11 +245,14 @@ static int calc_sizes(struct drm_device *ddev,
|
|||
((st->ifm.stride_kernel >> 1) & 0x1) + 1;
|
||||
u32 stride_x = ((st->ifm.stride_kernel >> 5) & 0x2) +
|
||||
(st->ifm.stride_kernel & 0x1) + 1;
|
||||
u32 ifm_height = st->ofm.height[2] * stride_y +
|
||||
s32 ifm_height = st->ofm.height[2] * stride_y +
|
||||
st->ifm.height[2] - (st->ifm.pad_top + st->ifm.pad_bottom);
|
||||
u32 ifm_width = st->ofm.width * stride_x +
|
||||
s32 ifm_width = st->ofm.width * stride_x +
|
||||
st->ifm.width - (st->ifm.pad_left + st->ifm.pad_right);
|
||||
|
||||
if (ifm_height < 0 || ifm_width < 0)
|
||||
return -EINVAL;
|
||||
|
||||
len = feat_matrix_length(info, &st->ifm, ifm_width,
|
||||
ifm_height, st->ifm.depth);
|
||||
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
|
||||
|
|
@ -417,7 +420,10 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
return ret;
|
||||
break;
|
||||
case NPU_OP_ELEMENTWISE:
|
||||
use_ifm2 = !((st.ifm2.broadcast == 8) || (param == 5) ||
|
||||
use_scale = ethosu_is_u65(edev) ?
|
||||
(st.ifm2.broadcast & 0x80) :
|
||||
(st.ifm2.broadcast == 8);
|
||||
use_ifm2 = !(use_scale || (param == 5) ||
|
||||
(param == 6) || (param == 7) || (param == 0x24));
|
||||
use_ifm = st.ifm.broadcast != 8;
|
||||
ret = calc_sizes_elemwise(ddev, info, cmd, &st, use_ifm, use_ifm2);
|
||||
|
|
|
|||
|
|
@ -143,17 +143,10 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void ethosu_job_cleanup(struct kref *ref)
|
||||
static void ethosu_job_err_cleanup(struct ethosu_job *job)
|
||||
{
|
||||
struct ethosu_job *job = container_of(ref, struct ethosu_job,
|
||||
refcount);
|
||||
unsigned int i;
|
||||
|
||||
pm_runtime_put_autosuspend(job->dev->base.dev);
|
||||
|
||||
dma_fence_put(job->done_fence);
|
||||
dma_fence_put(job->inference_done_fence);
|
||||
|
||||
for (i = 0; i < job->region_cnt; i++)
|
||||
drm_gem_object_put(job->region_bo[i]);
|
||||
|
||||
|
|
@ -162,6 +155,19 @@ static void ethosu_job_cleanup(struct kref *ref)
|
|||
kfree(job);
|
||||
}
|
||||
|
||||
static void ethosu_job_cleanup(struct kref *ref)
|
||||
{
|
||||
struct ethosu_job *job = container_of(ref, struct ethosu_job,
|
||||
refcount);
|
||||
|
||||
pm_runtime_put_autosuspend(job->dev->base.dev);
|
||||
|
||||
dma_fence_put(job->done_fence);
|
||||
dma_fence_put(job->inference_done_fence);
|
||||
|
||||
ethosu_job_err_cleanup(job);
|
||||
}
|
||||
|
||||
static void ethosu_job_put(struct ethosu_job *job)
|
||||
{
|
||||
kref_put(&job->refcount, ethosu_job_cleanup);
|
||||
|
|
@ -454,12 +460,16 @@ static int ethosu_ioctl_submit_job(struct drm_device *dev, struct drm_file *file
|
|||
}
|
||||
}
|
||||
ret = ethosu_job_push(ejob);
|
||||
if (!ret) {
|
||||
ethosu_job_put(ejob);
|
||||
return 0;
|
||||
}
|
||||
|
||||
out_cleanup_job:
|
||||
if (ret)
|
||||
drm_sched_job_cleanup(&ejob->base);
|
||||
out_put_job:
|
||||
ethosu_job_put(ejob);
|
||||
ethosu_job_err_cleanup(ejob);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1439,7 +1439,10 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
|
|||
*process_info = info;
|
||||
}
|
||||
|
||||
vm->process_info = *process_info;
|
||||
if (cmpxchg(&vm->process_info, NULL, *process_info) != NULL) {
|
||||
ret = -EINVAL;
|
||||
goto already_acquired;
|
||||
}
|
||||
|
||||
/* Validate page directory and attach eviction fence */
|
||||
ret = amdgpu_bo_reserve(vm->root.bo, true);
|
||||
|
|
@ -1479,6 +1482,7 @@ validate_pd_fail:
|
|||
amdgpu_bo_unreserve(vm->root.bo);
|
||||
reserve_pd_fail:
|
||||
vm->process_info = NULL;
|
||||
already_acquired:
|
||||
if (info) {
|
||||
dma_fence_put(&info->eviction_fence->base);
|
||||
*process_info = NULL;
|
||||
|
|
|
|||
|
|
@ -446,8 +446,7 @@ static int amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
|
||||
int queue_id)
|
||||
static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
|
|
@ -461,7 +460,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
|
|||
uq_funcs->mqd_destroy(queue);
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
|
||||
xa_erase_irq(&uq_mgr->userq_xa, (unsigned long)queue_id);
|
||||
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
|
||||
queue->userq_mgr = NULL;
|
||||
list_del(&queue->userq_va_list);
|
||||
|
|
@ -470,12 +468,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
|
|||
up_read(&adev->reset_domain->sem);
|
||||
}
|
||||
|
||||
static struct amdgpu_usermode_queue *
|
||||
amdgpu_userq_find(struct amdgpu_userq_mgr *uq_mgr, int qid)
|
||||
{
|
||||
return xa_load(&uq_mgr->userq_xa, qid);
|
||||
}
|
||||
|
||||
void
|
||||
amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_eviction_fence_mgr *evf_mgr)
|
||||
|
|
@ -625,22 +617,13 @@ unref_bo:
|
|||
}
|
||||
|
||||
static int
|
||||
amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
|
||||
amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_fpriv *fpriv = filp->driver_priv;
|
||||
struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
int r = 0;
|
||||
|
||||
cancel_delayed_work_sync(&uq_mgr->resume_work);
|
||||
mutex_lock(&uq_mgr->userq_mutex);
|
||||
queue = amdgpu_userq_find(uq_mgr, queue_id);
|
||||
if (!queue) {
|
||||
drm_dbg_driver(adev_to_drm(uq_mgr->adev), "Invalid queue id to destroy\n");
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
amdgpu_userq_wait_for_last_fence(queue);
|
||||
/* Cancel any pending hang detection work and cleanup */
|
||||
if (queue->hang_detect_fence) {
|
||||
|
|
@ -672,7 +655,7 @@ amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
|
|||
drm_warn(adev_to_drm(uq_mgr->adev), "trying to destroy a HW mapping userq\n");
|
||||
queue->state = AMDGPU_USERQ_STATE_HUNG;
|
||||
}
|
||||
amdgpu_userq_cleanup(queue, queue_id);
|
||||
amdgpu_userq_cleanup(queue);
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
|
@ -680,6 +663,37 @@ amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
|
|||
return r;
|
||||
}
|
||||
|
||||
static void amdgpu_userq_kref_destroy(struct kref *kref)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_usermode_queue *queue =
|
||||
container_of(kref, struct amdgpu_usermode_queue, refcount);
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
|
||||
r = amdgpu_userq_destroy(uq_mgr, queue);
|
||||
if (r)
|
||||
drm_file_err(uq_mgr->file, "Failed to destroy usermode queue %d\n", r);
|
||||
}
|
||||
|
||||
struct amdgpu_usermode_queue *amdgpu_userq_get(struct amdgpu_userq_mgr *uq_mgr, u32 qid)
|
||||
{
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
|
||||
xa_lock(&uq_mgr->userq_xa);
|
||||
queue = xa_load(&uq_mgr->userq_xa, qid);
|
||||
if (queue)
|
||||
kref_get(&queue->refcount);
|
||||
xa_unlock(&uq_mgr->userq_xa);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
void amdgpu_userq_put(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
if (queue)
|
||||
kref_put(&queue->refcount, amdgpu_userq_kref_destroy);
|
||||
}
|
||||
|
||||
static int amdgpu_userq_priority_permit(struct drm_file *filp,
|
||||
int priority)
|
||||
{
|
||||
|
|
@ -834,6 +848,9 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
/* drop this refcount during queue destroy */
|
||||
kref_init(&queue->refcount);
|
||||
|
||||
/* Wait for mode-1 reset to complete */
|
||||
down_read(&adev->reset_domain->sem);
|
||||
r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL));
|
||||
|
|
@ -985,7 +1002,9 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_file *filp)
|
||||
{
|
||||
union drm_amdgpu_userq *args = data;
|
||||
int r;
|
||||
struct amdgpu_fpriv *fpriv = filp->driver_priv;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
int r = 0;
|
||||
|
||||
if (!amdgpu_userq_enabled(dev))
|
||||
return -ENOTSUPP;
|
||||
|
|
@ -1000,11 +1019,16 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
|
|||
drm_file_err(filp, "Failed to create usermode queue\n");
|
||||
break;
|
||||
|
||||
case AMDGPU_USERQ_OP_FREE:
|
||||
r = amdgpu_userq_destroy(filp, args->in.queue_id);
|
||||
if (r)
|
||||
drm_file_err(filp, "Failed to destroy usermode queue\n");
|
||||
case AMDGPU_USERQ_OP_FREE: {
|
||||
xa_lock(&fpriv->userq_mgr.userq_xa);
|
||||
queue = __xa_erase(&fpriv->userq_mgr.userq_xa, args->in.queue_id);
|
||||
xa_unlock(&fpriv->userq_mgr.userq_xa);
|
||||
if (!queue)
|
||||
return -ENOENT;
|
||||
|
||||
amdgpu_userq_put(queue);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op);
|
||||
|
|
@ -1023,16 +1047,23 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
|
|||
|
||||
/* Resume all the queues for this process */
|
||||
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
|
||||
queue = amdgpu_userq_get(uq_mgr, queue_id);
|
||||
if (!queue)
|
||||
continue;
|
||||
|
||||
if (!amdgpu_userq_buffer_vas_mapped(queue)) {
|
||||
drm_file_err(uq_mgr->file,
|
||||
"trying restore queue without va mapping\n");
|
||||
queue->state = AMDGPU_USERQ_STATE_INVALID_VA;
|
||||
amdgpu_userq_put(queue);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = amdgpu_userq_restore_helper(queue);
|
||||
if (r)
|
||||
ret = r;
|
||||
|
||||
amdgpu_userq_put(queue);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
|
|
@ -1266,9 +1297,13 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
|
|||
amdgpu_userq_detect_and_reset_queues(uq_mgr);
|
||||
/* Try to unmap all the queues in this process ctx */
|
||||
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
|
||||
queue = amdgpu_userq_get(uq_mgr, queue_id);
|
||||
if (!queue)
|
||||
continue;
|
||||
r = amdgpu_userq_preempt_helper(queue);
|
||||
if (r)
|
||||
ret = r;
|
||||
amdgpu_userq_put(queue);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
|
|
@ -1301,16 +1336,24 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
|
|||
int ret;
|
||||
|
||||
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
|
||||
queue = amdgpu_userq_get(uq_mgr, queue_id);
|
||||
if (!queue)
|
||||
continue;
|
||||
|
||||
struct dma_fence *f = queue->last_fence;
|
||||
|
||||
if (!f || dma_fence_is_signaled(f))
|
||||
if (!f || dma_fence_is_signaled(f)) {
|
||||
amdgpu_userq_put(queue);
|
||||
continue;
|
||||
}
|
||||
ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100));
|
||||
if (ret <= 0) {
|
||||
drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n",
|
||||
f->context, f->seqno);
|
||||
amdgpu_userq_put(queue);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
amdgpu_userq_put(queue);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1361,20 +1404,23 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f
|
|||
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
|
||||
{
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
unsigned long queue_id;
|
||||
unsigned long queue_id = 0;
|
||||
|
||||
cancel_delayed_work_sync(&userq_mgr->resume_work);
|
||||
for (;;) {
|
||||
xa_lock(&userq_mgr->userq_xa);
|
||||
queue = xa_find(&userq_mgr->userq_xa, &queue_id, ULONG_MAX,
|
||||
XA_PRESENT);
|
||||
if (queue)
|
||||
__xa_erase(&userq_mgr->userq_xa, queue_id);
|
||||
xa_unlock(&userq_mgr->userq_xa);
|
||||
|
||||
mutex_lock(&userq_mgr->userq_mutex);
|
||||
amdgpu_userq_detect_and_reset_queues(userq_mgr);
|
||||
xa_for_each(&userq_mgr->userq_xa, queue_id, queue) {
|
||||
amdgpu_userq_wait_for_last_fence(queue);
|
||||
amdgpu_userq_unmap_helper(queue);
|
||||
amdgpu_userq_cleanup(queue, queue_id);
|
||||
if (!queue)
|
||||
break;
|
||||
|
||||
amdgpu_userq_put(queue);
|
||||
}
|
||||
|
||||
xa_destroy(&userq_mgr->userq_xa);
|
||||
mutex_unlock(&userq_mgr->userq_mutex);
|
||||
mutex_destroy(&userq_mgr->userq_mutex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ struct amdgpu_usermode_queue {
|
|||
struct dentry *debugfs_queue;
|
||||
struct delayed_work hang_detect_work;
|
||||
struct dma_fence *hang_detect_fence;
|
||||
struct kref refcount;
|
||||
|
||||
struct list_head userq_va_list;
|
||||
};
|
||||
|
|
@ -112,6 +113,9 @@ struct amdgpu_db_info {
|
|||
struct amdgpu_userq_obj *db_obj;
|
||||
};
|
||||
|
||||
struct amdgpu_usermode_queue *amdgpu_userq_get(struct amdgpu_userq_mgr *uq_mgr, u32 qid);
|
||||
void amdgpu_userq_put(struct amdgpu_usermode_queue *queue);
|
||||
|
||||
int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
|
||||
|
||||
int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv,
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_amdgpu_userq_signal *args = data;
|
||||
struct drm_gem_object **gobj_write = NULL;
|
||||
struct drm_gem_object **gobj_read = NULL;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
struct amdgpu_usermode_queue *queue = NULL;
|
||||
struct amdgpu_userq_fence *userq_fence;
|
||||
struct drm_syncobj **syncobj = NULL;
|
||||
u32 *bo_handles_write, num_write_bo_handles;
|
||||
|
|
@ -553,7 +553,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
/* Retrieve the user queue */
|
||||
queue = xa_load(&userq_mgr->userq_xa, args->queue_id);
|
||||
queue = amdgpu_userq_get(userq_mgr, args->queue_id);
|
||||
if (!queue) {
|
||||
r = -ENOENT;
|
||||
goto put_gobj_write;
|
||||
|
|
@ -648,6 +648,9 @@ free_syncobj:
|
|||
free_syncobj_handles:
|
||||
kfree(syncobj_handles);
|
||||
|
||||
if (queue)
|
||||
amdgpu_userq_put(queue);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -660,7 +663,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_amdgpu_userq_wait *wait_info = data;
|
||||
struct amdgpu_fpriv *fpriv = filp->driver_priv;
|
||||
struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr;
|
||||
struct amdgpu_usermode_queue *waitq;
|
||||
struct amdgpu_usermode_queue *waitq = NULL;
|
||||
struct drm_gem_object **gobj_write;
|
||||
struct drm_gem_object **gobj_read;
|
||||
struct dma_fence **fences = NULL;
|
||||
|
|
@ -926,7 +929,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
|
|||
*/
|
||||
num_fences = dma_fence_dedup_array(fences, num_fences);
|
||||
|
||||
waitq = xa_load(&userq_mgr->userq_xa, wait_info->waitq_id);
|
||||
waitq = amdgpu_userq_get(userq_mgr, wait_info->waitq_id);
|
||||
if (!waitq) {
|
||||
r = -EINVAL;
|
||||
goto free_fences;
|
||||
|
|
@ -983,32 +986,14 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
|
|||
r = -EFAULT;
|
||||
goto free_fences;
|
||||
}
|
||||
|
||||
kfree(fences);
|
||||
kfree(fence_info);
|
||||
}
|
||||
|
||||
drm_exec_fini(&exec);
|
||||
for (i = 0; i < num_read_bo_handles; i++)
|
||||
drm_gem_object_put(gobj_read[i]);
|
||||
kfree(gobj_read);
|
||||
|
||||
for (i = 0; i < num_write_bo_handles; i++)
|
||||
drm_gem_object_put(gobj_write[i]);
|
||||
kfree(gobj_write);
|
||||
|
||||
kfree(timeline_points);
|
||||
kfree(timeline_handles);
|
||||
kfree(syncobj_handles);
|
||||
kfree(bo_handles_write);
|
||||
kfree(bo_handles_read);
|
||||
|
||||
return 0;
|
||||
|
||||
free_fences:
|
||||
while (num_fences-- > 0)
|
||||
dma_fence_put(fences[num_fences]);
|
||||
kfree(fences);
|
||||
if (fences) {
|
||||
while (num_fences-- > 0)
|
||||
dma_fence_put(fences[num_fences]);
|
||||
kfree(fences);
|
||||
}
|
||||
free_fence_info:
|
||||
kfree(fence_info);
|
||||
exec_fini:
|
||||
|
|
@ -1032,5 +1017,8 @@ free_bo_handles_write:
|
|||
free_bo_handles_read:
|
||||
kfree(bo_handles_read);
|
||||
|
||||
if (waitq)
|
||||
amdgpu_userq_put(waitq);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ static int psp_v15_0_0_ring_stop(struct psp_context *psp,
|
|||
0x80000000, 0x80000000, false);
|
||||
} else {
|
||||
/* Write the ring destroy command*/
|
||||
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_64,
|
||||
WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64,
|
||||
GFX_CTRL_CMD_ID_DESTROY_RINGS);
|
||||
/* there might be handshake issue with hardware which needs delay */
|
||||
mdelay(20);
|
||||
/* Wait for response flag (bit 31) */
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
|
||||
0x80000000, 0x80000000, false);
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
|
|||
|
||||
} else {
|
||||
/* Wait for sOS ready for ring creation */
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
|
||||
0x80000000, 0x80000000, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
|
||||
|
|
@ -125,23 +125,23 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
|
|||
|
||||
/* Write low address of the ring to C2PMSG_69 */
|
||||
psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
|
||||
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_69, psp_ring_reg);
|
||||
WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_69, psp_ring_reg);
|
||||
/* Write high address of the ring to C2PMSG_70 */
|
||||
psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr);
|
||||
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_70, psp_ring_reg);
|
||||
WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_70, psp_ring_reg);
|
||||
/* Write size of ring to C2PMSG_71 */
|
||||
psp_ring_reg = ring->ring_size;
|
||||
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_71, psp_ring_reg);
|
||||
WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_71, psp_ring_reg);
|
||||
/* Write the ring initialization command to C2PMSG_64 */
|
||||
psp_ring_reg = ring_type;
|
||||
psp_ring_reg = psp_ring_reg << 16;
|
||||
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_64, psp_ring_reg);
|
||||
WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64, psp_ring_reg);
|
||||
|
||||
/* there might be handshake issue with hardware which needs delay */
|
||||
mdelay(20);
|
||||
|
||||
/* Wait for response flag (bit 31) in C2PMSG_64 */
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
|
||||
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
|
||||
0x80000000, 0x8000FFFF, false);
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ static uint32_t psp_v15_0_0_ring_get_wptr(struct psp_context *psp)
|
|||
if (amdgpu_sriov_vf(adev))
|
||||
data = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_102);
|
||||
else
|
||||
data = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_67);
|
||||
data = RREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ static void psp_v15_0_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
|
|||
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_101,
|
||||
GFX_CTRL_CMD_ID_CONSUME_CMD);
|
||||
} else
|
||||
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_67, value);
|
||||
WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67, value);
|
||||
}
|
||||
|
||||
static const struct psp_funcs psp_v15_0_0_funcs = {
|
||||
|
|
|
|||
|
|
@ -858,7 +858,9 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block)
|
|||
AMD_CG_SUPPORT_IH_CG |
|
||||
AMD_CG_SUPPORT_BIF_MGCG |
|
||||
AMD_CG_SUPPORT_BIF_LS;
|
||||
adev->pg_flags = AMD_PG_SUPPORT_VCN |
|
||||
adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG |
|
||||
AMD_PG_SUPPORT_VCN |
|
||||
AMD_PG_SUPPORT_JPEG_DPG |
|
||||
AMD_PG_SUPPORT_JPEG |
|
||||
AMD_PG_SUPPORT_GFX_PG;
|
||||
adev->external_rev_id = adev->rev_id + 0x1;
|
||||
|
|
|
|||
|
|
@ -1706,6 +1706,7 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
|
|||
struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
|
||||
struct drm_atomic_state *state = plane_state->state;
|
||||
const struct amdgpu_device *adev = drm_to_adev(colorop->dev);
|
||||
bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
|
||||
const struct drm_device *dev = colorop->dev;
|
||||
const struct drm_color_lut32 *lut3d;
|
||||
uint32_t lut3d_size;
|
||||
|
|
@ -1722,7 +1723,7 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
|
|||
}
|
||||
|
||||
if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_3D_LUT) {
|
||||
if (!adev->dm.dc->caps.color.dpp.hw_3d_lut) {
|
||||
if (!has_3dlut) {
|
||||
drm_dbg(dev, "3D LUT is not supported by hardware\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1875,6 +1876,7 @@ amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
|
|||
struct drm_colorop *colorop = plane_state->color_pipeline;
|
||||
struct drm_device *dev = plane_state->plane->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
|
||||
int ret;
|
||||
|
||||
/* 1D Curve - DEGAM TF */
|
||||
|
|
@ -1907,7 +1909,7 @@ amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adev->dm.dc->caps.color.dpp.hw_3d_lut) {
|
||||
if (has_3dlut) {
|
||||
/* 1D Curve & LUT - SHAPER TF & LUT */
|
||||
colorop = colorop->next;
|
||||
if (!colorop) {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
|
|||
struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
|
||||
int ret;
|
||||
int i = 0;
|
||||
|
||||
|
|
@ -112,7 +113,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
|
|||
|
||||
i++;
|
||||
|
||||
if (adev->dm.dc->caps.color.dpp.hw_3d_lut) {
|
||||
if (has_3dlut) {
|
||||
/* 1D curve - SHAPER TF */
|
||||
ops[i] = kzalloc_obj(*ops[0]);
|
||||
if (!ops[i]) {
|
||||
|
|
|
|||
|
|
@ -765,15 +765,15 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
|
|||
dm->adev->mode_info.crtcs[crtc_index] = acrtc;
|
||||
|
||||
/* Don't enable DRM CRTC degamma property for
|
||||
* 1. Degamma is replaced by color pipeline.
|
||||
* 2. DCE since it doesn't support programmable degamma anywhere.
|
||||
* 3. DCN401 since pre-blending degamma LUT doesn't apply to cursor.
|
||||
* 1. DCE since it doesn't support programmable degamma anywhere.
|
||||
* 2. DCN401 since pre-blending degamma LUT doesn't apply to cursor.
|
||||
* Note: DEGAMMA properties are created even if the primary plane has the
|
||||
* COLOR_PIPELINE property. User space can use either the DEGAMMA properties
|
||||
* or the COLOR_PIPELINE property. An atomic commit which attempts to enable
|
||||
* both is rejected.
|
||||
*/
|
||||
if (plane->color_pipeline_property)
|
||||
has_degamma = false;
|
||||
else
|
||||
has_degamma = dm->adev->dm.dc->caps.color.dpp.dcn_arch &&
|
||||
dm->adev->dm.dc->ctx->dce_version != DCN_VERSION_4_01;
|
||||
has_degamma = dm->adev->dm.dc->caps.color.dpp.dcn_arch &&
|
||||
dm->adev->dm.dc->ctx->dce_version != DCN_VERSION_4_01;
|
||||
|
||||
drm_crtc_enable_color_mgmt(&acrtc->base, has_degamma ? MAX_COLOR_LUT_ENTRIES : 0,
|
||||
true, MAX_COLOR_LUT_ENTRIES);
|
||||
|
|
|
|||
|
|
@ -1256,6 +1256,14 @@ static int amdgpu_dm_plane_atomic_check(struct drm_plane *plane,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Reject commits that attempt to use both COLOR_PIPELINE and CRTC DEGAMMA_LUT */
|
||||
if (new_plane_state->color_pipeline && new_crtc_state->degamma_lut) {
|
||||
drm_dbg_atomic(plane->dev,
|
||||
"[PLANE:%d:%s] COLOR_PIPELINE and CRTC DEGAMMA_LUT cannot be enabled simultaneously\n",
|
||||
plane->base.id, plane->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = amdgpu_dm_plane_fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -72,7 +72,11 @@ void dcn401_initialize_min_clocks(struct dc *dc)
|
|||
* audio corruption. Read current DISPCLK from DENTIST and request the same
|
||||
* freq to ensure that the timing is valid and unchanged.
|
||||
*/
|
||||
clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
|
||||
if (dc->clk_mgr->funcs->get_dispclk_from_dentist) {
|
||||
clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
|
||||
} else {
|
||||
clocks->dispclk_khz = dc->clk_mgr->boot_snapshot.dispclk * 1000;
|
||||
}
|
||||
}
|
||||
clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
|
||||
clocks->fclk_p_state_change_support = true;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,24 @@
|
|||
#define regMPASP_SMN_IH_SW_INT_CTRL 0x0142
|
||||
#define regMPASP_SMN_IH_SW_INT_CTRL_BASE_IDX 0
|
||||
|
||||
// addressBlock: mp_SmuMpASPPub_PcruDec
|
||||
// base address: 0x3800000
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_64 0x4280
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_64_BASE_IDX 3
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_65 0x4281
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_65_BASE_IDX 3
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_66 0x4282
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_66_BASE_IDX 3
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_67 0x4283
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_67_BASE_IDX 3
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_68 0x4284
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_68_BASE_IDX 3
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_69 0x4285
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_69_BASE_IDX 3
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_70 0x4286
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_70_BASE_IDX 3
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_71 0x4287
|
||||
#define regMPASP_PCRU1_MPASP_C2PMSG_71_BASE_IDX 3
|
||||
|
||||
// addressBlock: mp_SmuMp1_SmnDec
|
||||
// base address: 0x0
|
||||
|
|
|
|||
|
|
@ -2034,6 +2034,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
|
|||
smu, SMU_DRIVER_TABLE_GPU_METRICS);
|
||||
SmuMetricsExternal_t metrics_ext;
|
||||
SmuMetrics_t *metrics = &metrics_ext.SmuMetrics;
|
||||
uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
|
||||
int ret = 0;
|
||||
|
||||
ret = smu_cmn_get_metrics_table(smu,
|
||||
|
|
@ -2058,7 +2059,12 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
|
|||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
|
||||
if ((mp1_ver == IP_VERSION(13, 0, 0) && smu->smc_fw_version <= 0x004e1e00) ||
|
||||
(mp1_ver == IP_VERSION(13, 0, 10) && smu->smc_fw_version <= 0x00500800))
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
else
|
||||
gpu_metrics->energy_accumulator = UINT_MAX;
|
||||
|
||||
if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
|
||||
|
|
|
|||
|
|
@ -2065,7 +2065,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
|
|||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
gpu_metrics->energy_accumulator = smu->smc_fw_version <= 0x00521400 ?
|
||||
metrics->EnergyAccumulator : UINT_MAX;
|
||||
|
||||
if (metrics->AverageGfxActivity <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
|
||||
|
|
|
|||
|
|
@ -480,18 +480,8 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
|
|||
.start = start,
|
||||
.end = end,
|
||||
.pgmap_owner = pagemap->owner,
|
||||
/*
|
||||
* FIXME: MIGRATE_VMA_SELECT_DEVICE_PRIVATE intermittently
|
||||
* causes 'xe_exec_system_allocator --r *race*no*' to trigger aa
|
||||
* engine reset and a hard hang due to getting stuck on a folio
|
||||
* lock. This should work and needs to be root-caused. The only
|
||||
* downside of not selecting MIGRATE_VMA_SELECT_DEVICE_PRIVATE
|
||||
* is that device-to-device migrations won’t work; instead,
|
||||
* memory will bounce through system memory. This path should be
|
||||
* rare and only occur when the madvise attributes of memory are
|
||||
* changed or atomics are being used.
|
||||
*/
|
||||
.flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT,
|
||||
.flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT |
|
||||
MIGRATE_VMA_SELECT_DEVICE_PRIVATE,
|
||||
};
|
||||
unsigned long i, npages = npages_in_range(start, end);
|
||||
unsigned long own_pages = 0, migrated_pages = 0;
|
||||
|
|
|
|||
|
|
@ -1307,9 +1307,14 @@ static bool psr2_granularity_check(struct intel_crtc_state *crtc_state,
|
|||
u16 sink_y_granularity = crtc_state->has_panel_replay ?
|
||||
connector->dp.panel_replay_caps.su_y_granularity :
|
||||
connector->dp.psr_caps.su_y_granularity;
|
||||
u16 sink_w_granularity = crtc_state->has_panel_replay ?
|
||||
connector->dp.panel_replay_caps.su_w_granularity :
|
||||
connector->dp.psr_caps.su_w_granularity;
|
||||
u16 sink_w_granularity;
|
||||
|
||||
if (crtc_state->has_panel_replay)
|
||||
sink_w_granularity = connector->dp.panel_replay_caps.su_w_granularity ==
|
||||
DP_PANEL_REPLAY_FULL_LINE_GRANULARITY ?
|
||||
crtc_hdisplay : connector->dp.panel_replay_caps.su_w_granularity;
|
||||
else
|
||||
sink_w_granularity = connector->dp.psr_caps.su_w_granularity;
|
||||
|
||||
/* PSR2 HW only send full lines so we only need to validate the width */
|
||||
if (crtc_hdisplay % sink_w_granularity)
|
||||
|
|
|
|||
|
|
@ -1230,6 +1230,9 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg)
|
|||
u8 size = msg->size;
|
||||
int ret;
|
||||
|
||||
if (pm_runtime_suspended(nv_connector->base.dev->dev))
|
||||
return -EBUSY;
|
||||
|
||||
nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
|
||||
if (!nv_encoder)
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -893,14 +893,15 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue
|
|||
|
||||
out_sync:
|
||||
/* Make sure the CPU caches are invalidated before the seqno is read.
|
||||
* drm_gem_shmem_sync() is a NOP if map_wc=true, so no need to check
|
||||
* panthor_gem_sync() is a NOP if map_wc=true, so no need to check
|
||||
* it here.
|
||||
*/
|
||||
panthor_gem_sync(&bo->base.base, queue->syncwait.offset,
|
||||
panthor_gem_sync(&bo->base.base,
|
||||
DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE,
|
||||
queue->syncwait.offset,
|
||||
queue->syncwait.sync64 ?
|
||||
sizeof(struct panthor_syncobj_64b) :
|
||||
sizeof(struct panthor_syncobj_32b),
|
||||
DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE);
|
||||
sizeof(struct panthor_syncobj_32b));
|
||||
|
||||
return queue->syncwait.kmap + queue->syncwait.offset;
|
||||
|
||||
|
|
|
|||
|
|
@ -1122,6 +1122,7 @@ static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
|||
struct mipi_dsi_device *device)
|
||||
{
|
||||
struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
|
||||
int bpp;
|
||||
int ret;
|
||||
|
||||
if (device->lanes > dsi->num_data_lanes) {
|
||||
|
|
@ -1131,7 +1132,8 @@ static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (mipi_dsi_pixel_format_to_bpp(device->format)) {
|
||||
bpp = mipi_dsi_pixel_format_to_bpp(device->format);
|
||||
switch (bpp) {
|
||||
case 24:
|
||||
break;
|
||||
case 18:
|
||||
|
|
@ -1162,6 +1164,18 @@ static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
|||
|
||||
drm_bridge_add(&dsi->bridge);
|
||||
|
||||
/*
|
||||
* Report the required division ratio setting for the MIPI clock dividers.
|
||||
*
|
||||
* vclk * bpp = hsclk * 8 * num_lanes
|
||||
*
|
||||
* vclk * DSI_AB_divider = hsclk * 16
|
||||
*
|
||||
* which simplifies to...
|
||||
* DSI_AB_divider = bpp * 2 / num_lanes
|
||||
*/
|
||||
rzg2l_cpg_dsi_div_set_divider(bpp * 2 / dsi->lanes, PLL5_TARGET_DSI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -361,6 +361,7 @@ static void drm_sched_run_free_queue(struct drm_gpu_scheduler *sched)
|
|||
/**
|
||||
* drm_sched_job_done - complete a job
|
||||
* @s_job: pointer to the job which is done
|
||||
* @result: 0 on success, -ERRNO on error
|
||||
*
|
||||
* Finish the job's fence and resubmit the work items.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -737,6 +737,7 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
|
|||
unsigned int height = drm_rect_height(rect);
|
||||
unsigned int line_length = DIV_ROUND_UP(width, 8);
|
||||
unsigned int page_height = SSD130X_PAGE_HEIGHT;
|
||||
u8 page_start = ssd130x->page_offset + y / page_height;
|
||||
unsigned int pages = DIV_ROUND_UP(height, page_height);
|
||||
struct drm_device *drm = &ssd130x->drm;
|
||||
u32 array_idx = 0;
|
||||
|
|
@ -774,14 +775,11 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
|
|||
*/
|
||||
|
||||
if (!ssd130x->page_address_mode) {
|
||||
u8 page_start;
|
||||
|
||||
/* Set address range for horizontal addressing mode */
|
||||
ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset + x, width);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
page_start = ssd130x->page_offset + y / page_height;
|
||||
ret = ssd130x_set_page_range(ssd130x, page_start, pages);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -813,7 +811,7 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
|
|||
*/
|
||||
if (ssd130x->page_address_mode) {
|
||||
ret = ssd130x_set_page_pos(ssd130x,
|
||||
ssd130x->page_offset + i,
|
||||
page_start + i,
|
||||
ssd130x->col_offset + x);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -222,13 +222,13 @@ static void ttm_bo_reserve_interrupted(struct kunit *test)
|
|||
KUNIT_FAIL(test, "Couldn't create ttm bo reserve task\n");
|
||||
|
||||
/* Take a lock so the threaded reserve has to wait */
|
||||
mutex_lock(&bo->base.resv->lock.base);
|
||||
dma_resv_lock(bo->base.resv, NULL);
|
||||
|
||||
wake_up_process(task);
|
||||
msleep(20);
|
||||
err = kthread_stop(task);
|
||||
|
||||
mutex_unlock(&bo->base.resv->lock.base);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, err, -ERESTARTSYS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1107,8 +1107,7 @@ struct ttm_bo_swapout_walk {
|
|||
static s64
|
||||
ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
|
||||
{
|
||||
struct ttm_resource *res = bo->resource;
|
||||
struct ttm_place place = { .mem_type = res->mem_type };
|
||||
struct ttm_place place = { .mem_type = bo->resource->mem_type };
|
||||
struct ttm_bo_swapout_walk *swapout_walk =
|
||||
container_of(walk, typeof(*swapout_walk), walk);
|
||||
struct ttm_operation_ctx *ctx = walk->arg.ctx;
|
||||
|
|
@ -1148,7 +1147,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
|
|||
/*
|
||||
* Move to system cached
|
||||
*/
|
||||
if (res->mem_type != TTM_PL_SYSTEM) {
|
||||
if (bo->resource->mem_type != TTM_PL_SYSTEM) {
|
||||
struct ttm_resource *evict_mem;
|
||||
struct ttm_place hop;
|
||||
|
||||
|
|
@ -1180,15 +1179,15 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
|
|||
|
||||
if (ttm_tt_is_populated(tt)) {
|
||||
spin_lock(&bdev->lru_lock);
|
||||
ttm_resource_del_bulk_move(res, bo);
|
||||
ttm_resource_del_bulk_move(bo->resource, bo);
|
||||
spin_unlock(&bdev->lru_lock);
|
||||
|
||||
ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
|
||||
|
||||
spin_lock(&bdev->lru_lock);
|
||||
if (ret)
|
||||
ttm_resource_add_bulk_move(res, bo);
|
||||
ttm_resource_move_to_lru_tail(res);
|
||||
ttm_resource_add_bulk_move(bo->resource, bo);
|
||||
ttm_resource_move_to_lru_tail(bo->resource);
|
||||
spin_unlock(&bdev->lru_lock);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ static inline bool ttm_pool_uses_dma32(struct ttm_pool *pool)
|
|||
return pool->alloc_flags & TTM_ALLOCATION_POOL_USE_DMA32;
|
||||
}
|
||||
|
||||
static inline bool ttm_pool_beneficial_order(struct ttm_pool *pool)
|
||||
static inline unsigned int ttm_pool_beneficial_order(struct ttm_pool *pool)
|
||||
{
|
||||
return pool->alloc_flags & 0xff;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -830,6 +830,7 @@ static void xe_config_device_release(struct config_item *item)
|
|||
|
||||
mutex_destroy(&dev->lock);
|
||||
|
||||
kfree(dev->config.ctx_restore_mid_bb[0].cs);
|
||||
kfree(dev->config.ctx_restore_post_bb[0].cs);
|
||||
kfree(dev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,6 +266,16 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
|
|||
return q;
|
||||
}
|
||||
|
||||
static void __xe_exec_queue_fini(struct xe_exec_queue *q)
|
||||
{
|
||||
int i;
|
||||
|
||||
q->ops->fini(q);
|
||||
|
||||
for (i = 0; i < q->width; ++i)
|
||||
xe_lrc_put(q->lrc[i]);
|
||||
}
|
||||
|
||||
static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
|
||||
{
|
||||
int i, err;
|
||||
|
|
@ -320,21 +330,10 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
|
|||
return 0;
|
||||
|
||||
err_lrc:
|
||||
for (i = i - 1; i >= 0; --i)
|
||||
xe_lrc_put(q->lrc[i]);
|
||||
__xe_exec_queue_fini(q);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __xe_exec_queue_fini(struct xe_exec_queue *q)
|
||||
{
|
||||
int i;
|
||||
|
||||
q->ops->fini(q);
|
||||
|
||||
for (i = 0; i < q->width; ++i)
|
||||
xe_lrc_put(q->lrc[i]);
|
||||
}
|
||||
|
||||
struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *vm,
|
||||
u32 logical_mask, u16 width,
|
||||
struct xe_hw_engine *hwe, u32 flags,
|
||||
|
|
|
|||
|
|
@ -435,15 +435,11 @@ static int proxy_channel_alloc(struct xe_gsc *gsc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void xe_gsc_proxy_remove(void *arg)
|
||||
static void xe_gsc_proxy_stop(struct xe_gsc *gsc)
|
||||
{
|
||||
struct xe_gsc *gsc = arg;
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
|
||||
if (!gsc->proxy.component_added)
|
||||
return;
|
||||
|
||||
/* disable HECI2 IRQs */
|
||||
scoped_guard(xe_pm_runtime, xe) {
|
||||
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC);
|
||||
|
|
@ -455,6 +451,30 @@ static void xe_gsc_proxy_remove(void *arg)
|
|||
}
|
||||
|
||||
xe_gsc_wait_for_worker_completion(gsc);
|
||||
gsc->proxy.started = false;
|
||||
}
|
||||
|
||||
static void xe_gsc_proxy_remove(void *arg)
|
||||
{
|
||||
struct xe_gsc *gsc = arg;
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
|
||||
if (!gsc->proxy.component_added)
|
||||
return;
|
||||
|
||||
/*
|
||||
* GSC proxy start is an async process that can be ongoing during
|
||||
* Xe module load/unload. Using devm managed action to register
|
||||
* xe_gsc_proxy_stop could cause issues if Xe module unload has
|
||||
* already started when the action is registered, potentially leading
|
||||
* to the cleanup being called at the wrong time. Therefore, instead
|
||||
* of registering a separate devm action to undo what is done in
|
||||
* proxy start, we call it from here, but only if the start has
|
||||
* completed successfully (tracked with the 'started' flag).
|
||||
*/
|
||||
if (gsc->proxy.started)
|
||||
xe_gsc_proxy_stop(gsc);
|
||||
|
||||
component_del(xe->drm.dev, &xe_gsc_proxy_component_ops);
|
||||
gsc->proxy.component_added = false;
|
||||
|
|
@ -510,6 +530,7 @@ int xe_gsc_proxy_init(struct xe_gsc *gsc)
|
|||
*/
|
||||
int xe_gsc_proxy_start(struct xe_gsc *gsc)
|
||||
{
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
int err;
|
||||
|
||||
/* enable the proxy interrupt in the GSC shim layer */
|
||||
|
|
@ -521,12 +542,18 @@ int xe_gsc_proxy_start(struct xe_gsc *gsc)
|
|||
*/
|
||||
err = xe_gsc_proxy_request_handler(gsc);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_irq_disable;
|
||||
|
||||
if (!xe_gsc_proxy_init_done(gsc)) {
|
||||
xe_gt_err(gsc_to_gt(gsc), "GSC FW reports proxy init not completed\n");
|
||||
return -EIO;
|
||||
xe_gt_err(gt, "GSC FW reports proxy init not completed\n");
|
||||
err = -EIO;
|
||||
goto err_irq_disable;
|
||||
}
|
||||
|
||||
gsc->proxy.started = true;
|
||||
return 0;
|
||||
|
||||
err_irq_disable:
|
||||
gsc_proxy_irq_toggle(gsc, false);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ struct xe_gsc {
|
|||
struct mutex mutex;
|
||||
/** @proxy.component_added: whether the component has been added */
|
||||
bool component_added;
|
||||
/** @proxy.started: whether the proxy has been started */
|
||||
bool started;
|
||||
/** @proxy.bo: object to store message to and from the GSC */
|
||||
struct xe_bo *bo;
|
||||
/** @proxy.to_gsc: map of the memory used to send messages to the GSC */
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ static inline struct xe_lrc *xe_lrc_get(struct xe_lrc *lrc)
|
|||
*/
|
||||
static inline void xe_lrc_put(struct xe_lrc *lrc)
|
||||
{
|
||||
kref_put(&lrc->refcount, xe_lrc_destroy);
|
||||
if (lrc)
|
||||
kref_put(&lrc->refcount, xe_lrc_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -98,10 +98,12 @@ int xe_reg_sr_add(struct xe_reg_sr *sr,
|
|||
*pentry = *e;
|
||||
ret = xa_err(xa_store(&sr->xa, idx, pentry, GFP_KERNEL));
|
||||
if (ret)
|
||||
goto fail;
|
||||
goto fail_free;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free:
|
||||
kfree(pentry);
|
||||
fail:
|
||||
xe_gt_err(gt,
|
||||
"discarding save-restore reg %04lx (clear: %08x, set: %08x, masked: %s, mcr: %s): ret=%d\n",
|
||||
|
|
|
|||
|
|
@ -280,6 +280,9 @@ static void __emit_job_gen12_simple(struct xe_sched_job *job, struct xe_lrc *lrc
|
|||
|
||||
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
|
||||
|
||||
/* Don't preempt fence signaling */
|
||||
dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
|
||||
|
||||
if (job->user_fence.used) {
|
||||
i = emit_flush_dw(dw, i);
|
||||
i = emit_store_imm_ppgtt_posted(job->user_fence.addr,
|
||||
|
|
@ -345,6 +348,9 @@ static void __emit_job_gen12_video(struct xe_sched_job *job, struct xe_lrc *lrc,
|
|||
|
||||
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
|
||||
|
||||
/* Don't preempt fence signaling */
|
||||
dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
|
||||
|
||||
if (job->user_fence.used) {
|
||||
i = emit_flush_dw(dw, i);
|
||||
i = emit_store_imm_ppgtt_posted(job->user_fence.addr,
|
||||
|
|
@ -397,6 +403,9 @@ static void __emit_job_gen12_render_compute(struct xe_sched_job *job,
|
|||
|
||||
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
|
||||
|
||||
/* Don't preempt fence signaling */
|
||||
dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
|
||||
|
||||
i = emit_render_cache_flush(job, dw, i);
|
||||
|
||||
if (job->user_fence.used)
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
|
|||
madvise_range.num_vmas,
|
||||
args->atomic.val)) {
|
||||
err = -EINVAL;
|
||||
goto madv_fini;
|
||||
goto free_vmas;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -490,6 +490,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
|
|||
err_fini:
|
||||
if (madvise_range.has_bo_vmas)
|
||||
drm_exec_fini(&exec);
|
||||
free_vmas:
|
||||
kfree(madvise_range.vmas);
|
||||
madvise_range.vmas = NULL;
|
||||
madv_fini:
|
||||
|
|
|
|||
|
|
@ -241,12 +241,13 @@ static const struct xe_rtp_entry_sr gt_was[] = {
|
|||
|
||||
{ XE_RTP_NAME("16025250150"),
|
||||
XE_RTP_RULES(GRAPHICS_VERSION(2001)),
|
||||
XE_RTP_ACTIONS(SET(LSN_VC_REG2,
|
||||
LSN_LNI_WGT(1) |
|
||||
LSN_LNE_WGT(1) |
|
||||
LSN_DIM_X_WGT(1) |
|
||||
LSN_DIM_Y_WGT(1) |
|
||||
LSN_DIM_Z_WGT(1)))
|
||||
XE_RTP_ACTIONS(FIELD_SET(LSN_VC_REG2,
|
||||
LSN_LNI_WGT_MASK | LSN_LNE_WGT_MASK |
|
||||
LSN_DIM_X_WGT_MASK | LSN_DIM_Y_WGT_MASK |
|
||||
LSN_DIM_Z_WGT_MASK,
|
||||
LSN_LNI_WGT(1) | LSN_LNE_WGT(1) |
|
||||
LSN_DIM_X_WGT(1) | LSN_DIM_Y_WGT(1) |
|
||||
LSN_DIM_Z_WGT(1)))
|
||||
},
|
||||
|
||||
/* Xe2_HPM */
|
||||
|
|
|
|||
|
|
@ -571,6 +571,8 @@
|
|||
# define DP_PANEL_REPLAY_LINK_OFF_SUPPORTED_IN_PR_AFTER_ADAPTIVE_SYNC_SDP (1 << 7)
|
||||
|
||||
#define DP_PANEL_REPLAY_CAP_X_GRANULARITY 0xb2
|
||||
# define DP_PANEL_REPLAY_FULL_LINE_GRANULARITY 0xffff
|
||||
|
||||
#define DP_PANEL_REPLAY_CAP_Y_GRANULARITY 0xb4
|
||||
|
||||
/* Link Configuration */
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ bool isolate_folio_to_list(struct folio *folio, struct list_head *list);
|
|||
|
||||
int migrate_huge_page_move_mapping(struct address_space *mapping,
|
||||
struct folio *dst, struct folio *src);
|
||||
void migration_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
|
||||
void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
|
||||
__releases(ptl);
|
||||
void folio_migrate_flags(struct folio *newfolio, struct folio *folio);
|
||||
int folio_migrate_mapping(struct address_space *mapping,
|
||||
|
|
@ -97,6 +97,14 @@ static inline int set_movable_ops(const struct movable_operations *ops, enum pag
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
|
||||
__releases(ptl)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
|
||||
spin_unlock(ptl);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MIGRATION */
|
||||
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef _DMA_BUF_UAPI_H_
|
||||
#define _DMA_BUF_UAPI_H_
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
|
|
|
|||
15
mm/filemap.c
15
mm/filemap.c
|
|
@ -1379,14 +1379,16 @@ repeat:
|
|||
|
||||
#ifdef CONFIG_MIGRATION
|
||||
/**
|
||||
* migration_entry_wait_on_locked - Wait for a migration entry to be removed
|
||||
* @entry: migration swap entry.
|
||||
* softleaf_entry_wait_on_locked - Wait for a migration entry or
|
||||
* device_private entry to be removed.
|
||||
* @entry: migration or device_private swap entry.
|
||||
* @ptl: already locked ptl. This function will drop the lock.
|
||||
*
|
||||
* Wait for a migration entry referencing the given page to be removed. This is
|
||||
* Wait for a migration entry referencing the given page, or device_private
|
||||
* entry referencing a dvice_private page to be unlocked. This is
|
||||
* equivalent to folio_put_wait_locked(folio, TASK_UNINTERRUPTIBLE) except
|
||||
* this can be called without taking a reference on the page. Instead this
|
||||
* should be called while holding the ptl for the migration entry referencing
|
||||
* should be called while holding the ptl for @entry referencing
|
||||
* the page.
|
||||
*
|
||||
* Returns after unlocking the ptl.
|
||||
|
|
@ -1394,7 +1396,7 @@ repeat:
|
|||
* This follows the same logic as folio_wait_bit_common() so see the comments
|
||||
* there.
|
||||
*/
|
||||
void migration_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
|
||||
void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
|
||||
__releases(ptl)
|
||||
{
|
||||
struct wait_page_queue wait_page;
|
||||
|
|
@ -1428,6 +1430,9 @@ void migration_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
|
|||
* If a migration entry exists for the page the migration path must hold
|
||||
* a valid reference to the page, and it must take the ptl to remove the
|
||||
* migration entry. So the page is valid until the ptl is dropped.
|
||||
* Similarly any path attempting to drop the last reference to a
|
||||
* device-private page needs to grab the ptl to remove the device-private
|
||||
* entry.
|
||||
*/
|
||||
spin_unlock(ptl);
|
||||
|
||||
|
|
|
|||
|
|
@ -4763,7 +4763,8 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
|
|||
unlock_page(vmf->page);
|
||||
put_page(vmf->page);
|
||||
} else {
|
||||
pte_unmap_unlock(vmf->pte, vmf->ptl);
|
||||
pte_unmap(vmf->pte);
|
||||
softleaf_entry_wait_on_locked(entry, vmf->ptl);
|
||||
}
|
||||
} else if (softleaf_is_hwpoison(entry)) {
|
||||
ret = VM_FAULT_HWPOISON;
|
||||
|
|
|
|||
|
|
@ -500,7 +500,7 @@ void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
|
|||
if (!softleaf_is_migration(entry))
|
||||
goto out;
|
||||
|
||||
migration_entry_wait_on_locked(entry, ptl);
|
||||
softleaf_entry_wait_on_locked(entry, ptl);
|
||||
return;
|
||||
out:
|
||||
spin_unlock(ptl);
|
||||
|
|
@ -532,10 +532,10 @@ void migration_entry_wait_huge(struct vm_area_struct *vma, unsigned long addr, p
|
|||
* If migration entry existed, safe to release vma lock
|
||||
* here because the pgtable page won't be freed without the
|
||||
* pgtable lock released. See comment right above pgtable
|
||||
* lock release in migration_entry_wait_on_locked().
|
||||
* lock release in softleaf_entry_wait_on_locked().
|
||||
*/
|
||||
hugetlb_vma_unlock_read(vma);
|
||||
migration_entry_wait_on_locked(entry, ptl);
|
||||
softleaf_entry_wait_on_locked(entry, ptl);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -553,7 +553,7 @@ void pmd_migration_entry_wait(struct mm_struct *mm, pmd_t *pmd)
|
|||
ptl = pmd_lock(mm, pmd);
|
||||
if (!pmd_is_migration_entry(*pmd))
|
||||
goto unlock;
|
||||
migration_entry_wait_on_locked(softleaf_from_pmd(*pmd), ptl);
|
||||
softleaf_entry_wait_on_locked(softleaf_from_pmd(*pmd), ptl);
|
||||
return;
|
||||
unlock:
|
||||
spin_unlock(ptl);
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ static int migrate_vma_collect_huge_pmd(pmd_t *pmdp, unsigned long start,
|
|||
}
|
||||
|
||||
if (softleaf_is_migration(entry)) {
|
||||
migration_entry_wait_on_locked(entry, ptl);
|
||||
softleaf_entry_wait_on_locked(entry, ptl);
|
||||
spin_unlock(ptl);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue