Commit 466d6175 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'drm-fixes-2026-02-27' of https://gitlab.freedesktop.org/drm/kernel

Pull drm fixes from Dave Airlie:
 "Regular fixes pull, amdxdna and amdgpu are the main ones, with a
  couple of intel fixes, then a scattering of fixes across drivers,
  nothing too major.

  i915/display:
   - Fix Panel Replay stuck with X during mode transitions on Panther
     Lake

  xe:
   - W/a fix for multi-cast registers
   - Fix xe_sync initialization issues

  amdgpu:
   - UserQ fixes
   - DC fix
   - RAS fixes
   - VCN 5 fix
   - Slot reset fix
   - Remove MES workaround that's no longer needed

  amdxdna:
   - deadlock fix
   - NULL ptr deref fix
   - suspend failure fix
   - OOB access fix
   - buffer overflow fix
   - input sanitiation fix
   - firmware loading fix

  dw-dp:
   - An error handling fix

  ethosu:
   - A binary shift overflow fix

  imx:
   - An error handling fix

  logicvc:
   - A dt node reference leak fix

  nouveau:
   - A WARN_ON removal

  samsung-dsim:
   - A memory leak fix

  tiny:
   - sharp-memory: NULL pointer deref fix

  vmwgfx:
   - A reference count and error handling fix"

* tag 'drm-fixes-2026-02-27' of https://gitlab.freedesktop.org/drm/kernel: (39 commits)
  drm/amd: Disable MES LR compute W/A
  drm/amdgpu: Fix error handling in slot reset
  drm/amdgpu/vcn5: Add SMU dpm interface type
  drm/amdgpu: Fix locking bugs in error paths
  drm/amdgpu: Unlock a mutex before destroying it
  drm/amd/display: Use GFP_ATOMIC in dc_create_stream_for_sink
  drm/amdgpu: add upper bound check on user inputs in wait ioctl
  drm/amdgpu: add upper bound check on user inputs in signal ioctl
  drm/amdgpu/userq: Do not allow userspace to trivially triger kernel warnings
  drm/amdgpu/userq: Fix reference leak in amdgpu_userq_wait_ioctl
  accel/amdxdna: Use a different name for latest firmware
  drm/client: Do not destroy NULL modes
  drm/gpusvm: Fix drm_gpusvm_pages_valid_unlocked() kernel-doc
  drm/xe/sync: Fix user fence leak on alloc failure
  drm/xe/sync: Cleanup partially initialized sync on parse failure
  drm/xe/wa: Steer RMW of MCR registers while building default LRC
  accel/amdxdna: Validate command buffer payload count
  accel/amdxdna: Prevent ubuf size overflow
  accel/amdxdna: Fix out-of-bounds memset in command slot handling
  accel/amdxdna: Fix command hang on suspended hardware context
  ...
parents a75cb869 103d53eb
Loading
Loading
Loading
Loading
+19 −13
Original line number Diff line number Diff line
@@ -23,9 +23,9 @@
#include "amdxdna_pci_drv.h"
#include "amdxdna_pm.h"

static bool force_cmdlist;
static bool force_cmdlist = true;
module_param(force_cmdlist, bool, 0600);
MODULE_PARM_DESC(force_cmdlist, "Force use command list (Default false)");
MODULE_PARM_DESC(force_cmdlist, "Force use command list (Default true)");

#define HWCTX_MAX_TIMEOUT	60000 /* milliseconds */

@@ -53,6 +53,7 @@ static void aie2_hwctx_stop(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwct
{
	drm_sched_stop(&hwctx->priv->sched, bad_job);
	aie2_destroy_context(xdna->dev_handle, hwctx);
	drm_sched_start(&hwctx->priv->sched, 0);
}

static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwctx)
@@ -80,7 +81,6 @@ static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hw
	}

out:
	drm_sched_start(&hwctx->priv->sched, 0);
	XDNA_DBG(xdna, "%s restarted, ret %d", hwctx->name, ret);
	return ret;
}
@@ -297,19 +297,23 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
	struct dma_fence *fence;
	int ret;

	if (!hwctx->priv->mbox_chann)
	ret = amdxdna_pm_resume_get(hwctx->client->xdna);
	if (ret)
		return NULL;

	if (!hwctx->priv->mbox_chann) {
		amdxdna_pm_suspend_put(hwctx->client->xdna);
		return NULL;
	}

	if (!mmget_not_zero(job->mm))
	if (!mmget_not_zero(job->mm)) {
		amdxdna_pm_suspend_put(hwctx->client->xdna);
		return ERR_PTR(-ESRCH);
	}

	kref_get(&job->refcnt);
	fence = dma_fence_get(job->fence);

	ret = amdxdna_pm_resume_get(hwctx->client->xdna);
	if (ret)
		goto out;

	if (job->drv_cmd) {
		switch (job->drv_cmd->opcode) {
		case SYNC_DEBUG_BO:
@@ -497,7 +501,7 @@ static void aie2_release_resource(struct amdxdna_hwctx *hwctx)

	if (AIE2_FEATURE_ON(xdna->dev_handle, AIE2_TEMPORAL_ONLY)) {
		ret = aie2_destroy_context(xdna->dev_handle, hwctx);
		if (ret)
		if (ret && ret != -ENODEV)
			XDNA_ERR(xdna, "Destroy temporal only context failed, ret %d", ret);
	} else {
		ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx);
@@ -629,7 +633,7 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
		goto free_entity;
	}

	ret = amdxdna_pm_resume_get(xdna);
	ret = amdxdna_pm_resume_get_locked(xdna);
	if (ret)
		goto free_col_list;

@@ -760,7 +764,7 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size
	if (!hwctx->cus)
		return -ENOMEM;

	ret = amdxdna_pm_resume_get(xdna);
	ret = amdxdna_pm_resume_get_locked(xdna);
	if (ret)
		goto free_cus;

@@ -1070,6 +1074,8 @@ void aie2_hmm_invalidate(struct amdxdna_gem_obj *abo,

	ret = dma_resv_wait_timeout(gobj->resv, DMA_RESV_USAGE_BOOKKEEP,
				    true, MAX_SCHEDULE_TIMEOUT);
	if (!ret || ret == -ERESTARTSYS)
	if (!ret)
		XDNA_ERR(xdna, "Failed to wait for bo, ret %ld", ret);
	else if (ret == -ERESTARTSYS)
		XDNA_DBG(xdna, "Wait for bo interrupted by signal");
}
+10 −5
Original line number Diff line number Diff line
@@ -216,8 +216,10 @@ static int aie2_destroy_context_req(struct amdxdna_dev_hdl *ndev, u32 id)

	req.context_id = id;
	ret = aie2_send_mgmt_msg_wait(ndev, &msg);
	if (ret)
	if (ret && ret != -ENODEV)
		XDNA_WARN(xdna, "Destroy context failed, ret %d", ret);
	else if (ret == -ENODEV)
		XDNA_DBG(xdna, "Destroy context: device already stopped");

	return ret;
}
@@ -318,6 +320,9 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwc
	struct amdxdna_dev *xdna = ndev->xdna;
	int ret;

	if (!hwctx->priv->mbox_chann)
		return 0;

	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);
@@ -694,11 +699,11 @@ aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siz
	u32 cmd_len;
	void *cmd;

	memset(npu_slot, 0, sizeof(*npu_slot));
	cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
	if (*size < sizeof(*npu_slot) + cmd_len)
		return -EINVAL;

	memset(npu_slot, 0, sizeof(*npu_slot));
	npu_slot->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
	if (npu_slot->cu_idx == INVALID_CU_IDX)
		return -EINVAL;
@@ -719,7 +724,6 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si
	u32 cmd_len;
	u32 arg_sz;

	memset(npu_slot, 0, sizeof(*npu_slot));
	sn = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
	arg_sz = cmd_len - sizeof(*sn);
	if (cmd_len < sizeof(*sn) || arg_sz > MAX_NPU_ARGS_SIZE)
@@ -728,6 +732,7 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si
	if (*size < sizeof(*npu_slot) + arg_sz)
		return -EINVAL;

	memset(npu_slot, 0, sizeof(*npu_slot));
	npu_slot->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
	if (npu_slot->cu_idx == INVALID_CU_IDX)
		return -EINVAL;
@@ -751,7 +756,6 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t
	u32 cmd_len;
	u32 arg_sz;

	memset(npu_slot, 0, sizeof(*npu_slot));
	pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
	arg_sz = cmd_len - sizeof(*pd);
	if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE)
@@ -760,6 +764,7 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t
	if (*size < sizeof(*npu_slot) + arg_sz)
		return -EINVAL;

	memset(npu_slot, 0, sizeof(*npu_slot));
	npu_slot->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
	if (npu_slot->cu_idx == INVALID_CU_IDX)
		return -EINVAL;
@@ -787,7 +792,6 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si
	u32 cmd_len;
	u32 arg_sz;

	memset(npu_slot, 0, sizeof(*npu_slot));
	pd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
	arg_sz = cmd_len - sizeof(*pd);
	if (cmd_len < sizeof(*pd) || arg_sz > MAX_NPU_ARGS_SIZE)
@@ -796,6 +800,7 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si
	if (*size < sizeof(*npu_slot) + arg_sz)
		return -EINVAL;

	memset(npu_slot, 0, sizeof(*npu_slot));
	npu_slot->type = EXEC_NPU_TYPE_ELF;
	npu_slot->inst_buf_addr = pd->inst_buf;
	npu_slot->save_buf_addr = pd->save_buf;
+27 −9
Original line number Diff line number Diff line
@@ -32,6 +32,11 @@ static int aie2_max_col = XRS_MAX_COL;
module_param(aie2_max_col, uint, 0600);
MODULE_PARM_DESC(aie2_max_col, "Maximum column could be used");

static char *npu_fw[] = {
	"npu_7.sbin",
	"npu.sbin"
};

/*
 * The management mailbox channel is allocated by firmware.
 * The related register and ring buffer information is on SRAM BAR.
@@ -323,6 +328,7 @@ static void aie2_hw_stop(struct amdxdna_dev *xdna)
		return;
	}

	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);
@@ -406,15 +412,15 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
		goto stop_psp;
	}

	ret = aie2_pm_init(ndev);
	ret = aie2_mgmt_fw_init(ndev);
	if (ret) {
		XDNA_ERR(xdna, "failed to init pm, ret %d", ret);
		XDNA_ERR(xdna, "initial mgmt firmware failed, ret %d", ret);
		goto destroy_mgmt_chann;
	}

	ret = aie2_mgmt_fw_init(ndev);
	ret = aie2_pm_init(ndev);
	if (ret) {
		XDNA_ERR(xdna, "initial mgmt firmware failed, ret %d", ret);
		XDNA_ERR(xdna, "failed to init pm, ret %d", ret);
		goto destroy_mgmt_chann;
	}

@@ -451,7 +457,6 @@ static int aie2_hw_suspend(struct amdxdna_dev *xdna)
{
	struct amdxdna_client *client;

	guard(mutex)(&xdna->dev_lock);
	list_for_each_entry(client, &xdna->client_list, node)
		aie2_hwctx_suspend(client);

@@ -489,6 +494,7 @@ static int aie2_init(struct amdxdna_dev *xdna)
	struct psp_config psp_conf;
	const struct firmware *fw;
	unsigned long bars = 0;
	char *fw_full_path;
	int i, nvec, ret;

	if (!hypervisor_is_type(X86_HYPER_NATIVE)) {
@@ -503,7 +509,19 @@ static int aie2_init(struct amdxdna_dev *xdna)
	ndev->priv = xdna->dev_info->dev_priv;
	ndev->xdna = xdna;

	ret = request_firmware(&fw, ndev->priv->fw_path, &pdev->dev);
	for (i = 0; i < ARRAY_SIZE(npu_fw); i++) {
		fw_full_path = kasprintf(GFP_KERNEL, "%s%s", ndev->priv->fw_path, npu_fw[i]);
		if (!fw_full_path)
			return -ENOMEM;

		ret = firmware_request_nowarn(&fw, fw_full_path, &pdev->dev);
		kfree(fw_full_path);
		if (!ret) {
			XDNA_INFO(xdna, "Load firmware %s%s", ndev->priv->fw_path, npu_fw[i]);
			break;
		}
	}

	if (ret) {
		XDNA_ERR(xdna, "failed to request_firmware %s, ret %d",
			 ndev->priv->fw_path, ret);
@@ -951,7 +969,7 @@ static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_i
	if (!drm_dev_enter(&xdna->ddev, &idx))
		return -ENODEV;

	ret = amdxdna_pm_resume_get(xdna);
	ret = amdxdna_pm_resume_get_locked(xdna);
	if (ret)
		goto dev_exit;

@@ -1044,7 +1062,7 @@ static int aie2_get_array(struct amdxdna_client *client,
	if (!drm_dev_enter(&xdna->ddev, &idx))
		return -ENODEV;

	ret = amdxdna_pm_resume_get(xdna);
	ret = amdxdna_pm_resume_get_locked(xdna);
	if (ret)
		goto dev_exit;

@@ -1134,7 +1152,7 @@ static int aie2_set_state(struct amdxdna_client *client,
	if (!drm_dev_enter(&xdna->ddev, &idx))
		return -ENODEV;

	ret = amdxdna_pm_resume_get(xdna);
	ret = amdxdna_pm_resume_get_locked(xdna);
	if (ret)
		goto dev_exit;

+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
{
	int ret;

	ret = amdxdna_pm_resume_get(ndev->xdna);
	ret = amdxdna_pm_resume_get_locked(ndev->xdna);
	if (ret)
		return ret;

+11 −13
Original line number Diff line number Diff line
@@ -104,7 +104,10 @@ void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size)

	if (size) {
		count = FIELD_GET(AMDXDNA_CMD_COUNT, cmd->header);
		if (unlikely(count <= num_masks)) {
		if (unlikely(count <= num_masks ||
			     count * sizeof(u32) +
			     offsetof(struct amdxdna_cmd, data[0]) >
			     abo->mem.size)) {
			*size = 0;
			return NULL;
		}
@@ -266,9 +269,9 @@ int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
	struct amdxdna_drm_config_hwctx *args = data;
	struct amdxdna_dev *xdna = to_xdna_dev(dev);
	struct amdxdna_hwctx *hwctx;
	int ret, idx;
	u32 buf_size;
	void *buf;
	int ret;
	u64 val;

	if (XDNA_MBZ_DBG(xdna, &args->pad, sizeof(args->pad)))
@@ -310,20 +313,17 @@ int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
		return -EINVAL;
	}

	mutex_lock(&xdna->dev_lock);
	idx = srcu_read_lock(&client->hwctx_srcu);
	guard(mutex)(&xdna->dev_lock);
	hwctx = xa_load(&client->hwctx_xa, args->handle);
	if (!hwctx) {
		XDNA_DBG(xdna, "PID %d failed to get hwctx %d", client->pid, args->handle);
		ret = -EINVAL;
		goto unlock_srcu;
		goto free_buf;
	}

	ret = xdna->dev_info->ops->hwctx_config(hwctx, args->param_type, val, buf, buf_size);

unlock_srcu:
	srcu_read_unlock(&client->hwctx_srcu, idx);
	mutex_unlock(&xdna->dev_lock);
free_buf:
	kfree(buf);
	return ret;
}
@@ -334,7 +334,7 @@ int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl)
	struct amdxdna_hwctx *hwctx;
	struct amdxdna_gem_obj *abo;
	struct drm_gem_object *gobj;
	int ret, idx;
	int ret;

	if (!xdna->dev_info->ops->hwctx_sync_debug_bo)
		return -EOPNOTSUPP;
@@ -345,17 +345,15 @@ int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl)

	abo = to_xdna_obj(gobj);
	guard(mutex)(&xdna->dev_lock);
	idx = srcu_read_lock(&client->hwctx_srcu);
	hwctx = xa_load(&client->hwctx_xa, abo->assigned_hwctx);
	if (!hwctx) {
		ret = -EINVAL;
		goto unlock_srcu;
		goto put_obj;
	}

	ret = xdna->dev_info->ops->hwctx_sync_debug_bo(hwctx, debug_bo_hdl);

unlock_srcu:
	srcu_read_unlock(&client->hwctx_srcu, idx);
put_obj:
	drm_gem_object_put(gobj);
	return ret;
}
Loading