Merge tag 'drm-misc-next-2025-12-12' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for 6.19:

UAPI Changes:

  - panfrost: Add PANFROST_BO_SYNC ioctl
  - panthor: Add PANTHOR_BO_SYNC ioctl

Core Changes:

  - atomic: Add drm_device pointer to drm_private_obj
  - bridge: Introduce drm_bridge_unplug, drm_bridge_enter, and
    drm_bridge_exit
  - dma-buf: Improve sg_table debugging
  - dma-fence: Add new helpers, and use them when needed
  - dp_mst: Avoid out-of-bounds access with VCPI==0
  - gem: Reduce page table overhead with transparent huge pages
  - panic: Report invalid panic modes
  - sched: Add TODO entries
  - ttm: Various cleanups
  - vblank: Various refactoring and cleanups

  - Kconfig cleanups
  - Removed support for kdb

Driver Changes:

  - amdxdna: Fix race conditions at suspend, Improve handling of zero
    tail pointers, Fix cu_idx being overwritten during command setup
  - ast: Support imported cursor buffers
  -
  - panthor: Enable timestamp propagation, Multiple improvements and
    fixes to improve the overall robustness, notably of the scheduler.

  - panels:
    - panel-edp: Support for CSW MNE007QB3-1, AUO B140HAN06.4, AUO B140QAX01.H

Signed-off-by: Dave Airlie <airlied@redhat.com>

[airlied: fix mm conflict]
From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20251212-spectacular-agama-of-abracadabra-aaef32@penduick
This commit is contained in:
Dave Airlie
2025-12-26 18:15:33 +10:00
103 changed files with 2546 additions and 1491 deletions
+23 -6
View File
@@ -155,7 +155,12 @@ drm_gem_object_init() will create an shmfs file of the
requested size and store it into the struct :c:type:`struct
drm_gem_object <drm_gem_object>` filp field. The memory is
used as either main storage for the object when the graphics hardware
uses system memory directly or as a backing store otherwise.
uses system memory directly or as a backing store otherwise. Drivers
can call drm_gem_huge_mnt_create() to create, mount and use a huge
shmem mountpoint instead of the default one ('shm_mnt'). For builds
with CONFIG_TRANSPARENT_HUGEPAGE enabled, further calls to
drm_gem_object_init() will let shmem allocate huge pages when
possible.
Drivers are responsible for the actual physical pages allocation by
calling shmem_read_mapping_page_gfp() for each page.
@@ -290,15 +295,27 @@ The open and close operations must update the GEM object reference
count. Drivers can use the drm_gem_vm_open() and drm_gem_vm_close() helper
functions directly as open and close handlers.
The fault operation handler is responsible for mapping individual pages
to userspace when a page fault occurs. Depending on the memory
allocation scheme, drivers can allocate pages at fault time, or can
decide to allocate memory for the GEM object at the time the object is
created.
The fault operation handler is responsible for mapping pages to
userspace when a page fault occurs. Depending on the memory allocation
scheme, drivers can allocate pages at fault time, or can decide to
allocate memory for the GEM object at the time the object is created.
Drivers that want to map the GEM object upfront instead of handling page
faults can implement their own mmap file operation handler.
In order to reduce page table overhead, if the internal shmem mountpoint
"shm_mnt" is configured to use transparent huge pages (for builds with
CONFIG_TRANSPARENT_HUGEPAGE enabled) and if the shmem backing store
managed to allocate a huge page for a faulty address, the fault handler
will first attempt to insert that huge page into the VMA before falling
back to individual page insertion. mmap() user address alignment for GEM
objects is handled by providing a custom get_unmapped_area file
operation which forwards to the shmem backing store. For most drivers,
which don't create a huge mountpoint by default or through a module
parameter, transparent huge pages can be enabled by either setting the
"transparent_hugepage_shmem" kernel parameter or the
"/sys/kernel/mm/transparent_hugepage/shmem_enabled" sysfs knob.
For platforms without MMU the GEM core provides a helper method
drm_gem_dma_get_unmapped_area(). The mmap() routines will call this to get a
proposed address for the mapping.
+45
View File
@@ -878,6 +878,51 @@ Contact: Christian König
Level: Starter
DRM GPU Scheduler
=================
Provide a universal successor for drm_sched_resubmit_jobs()
-----------------------------------------------------------
drm_sched_resubmit_jobs() is deprecated. Main reason being that it leads to
reinitializing dma_fences. See that function's docu for details. The better
approach for valid resubmissions by amdgpu and Xe is (apparently) to figure out
which job (and, through association: which entity) caused the hang. Then, the
job's buffer data, together with all other jobs' buffer data currently in the
same hardware ring, must be invalidated. This can for example be done by
overwriting it. amdgpu currently determines which jobs are in the ring and need
to be overwritten by keeping copies of the job. Xe obtains that information by
directly accessing drm_sched's pending_list.
Tasks:
1. implement scheduler functionality through which the driver can obtain the
information which *broken* jobs are currently in the hardware ring.
2. Such infrastructure would then typically be used in
drm_sched_backend_ops.timedout_job(). Document that.
3. Port a driver as first user.
4. Document the new alternative in the docu of deprecated
drm_sched_resubmit_jobs().
Contact: Christian König <christian.koenig@amd.com>
Philipp Stanner <phasta@kernel.org>
Level: Advanced
Add locking for runqueues
-------------------------
There is an old FIXME by Sima in include/drm/gpu_scheduler.h. It details that
struct drm_sched_rq is read at many places without any locks, not even with a
READ_ONCE. At XDC 2025 no one could really tell why that is the case, whether
locks are needed and whether they could be added. (But for real, that should
probably be locked!). Check whether it's possible to add locks everywhere, and
do so if yes.
Contact: Philipp Stanner <phasta@kernel.org>
Level: Intermediate
Outside DRM
===========
-28
View File
@@ -889,34 +889,6 @@ in the virtual console layer. On resuming kernel execution, the kernel
debugger calls kgdboc_post_exp_handler() which in turn calls
con_debug_leave().
Any video driver that wants to be compatible with the kernel debugger
and the atomic kms callbacks must implement the ``mode_set_base_atomic``,
``fb_debug_enter`` and ``fb_debug_leave operations``. For the
``fb_debug_enter`` and ``fb_debug_leave`` the option exists to use the
generic drm fb helper functions or implement something custom for the
hardware. The following example shows the initialization of the
.mode_set_base_atomic operation in
drivers/gpu/drm/i915/intel_display.c::
static const struct drm_crtc_helper_funcs intel_helper_funcs = {
[...]
.mode_set_base_atomic = intel_pipe_set_base_atomic,
[...]
};
Here is an example of how the i915 driver initializes the
fb_debug_enter and fb_debug_leave functions to use the generic drm
helpers in ``drivers/gpu/drm/i915/intel_fb.c``::
static struct fb_ops intelfb_ops = {
[...]
.fb_debug_enter = drm_fb_helper_debug_enter,
.fb_debug_leave = drm_fb_helper_debug_leave,
[...]
};
Credits
+12 -6
View File
@@ -39,7 +39,6 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev,
if (!ndev->mgmt_chann)
return -ENODEV;
drm_WARN_ON(&xdna->ddev, xdna->rpm_on && !mutex_is_locked(&xdna->dev_lock));
ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg);
if (ret == -ETIME) {
xdna_mailbox_stop_channel(ndev->mgmt_chann);
@@ -59,8 +58,15 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev,
int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev)
{
DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND);
int ret;
return aie2_send_mgmt_msg_wait(ndev, &msg);
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
if (ret) {
XDNA_ERR(ndev->xdna, "Failed to suspend fw, ret %d", ret);
return ret;
}
return aie2_psp_waitmode_poll(ndev->psp_hdl);
}
int aie2_resume_fw(struct amdxdna_dev_hdl *ndev)
@@ -646,6 +652,7 @@ 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;
@@ -654,7 +661,6 @@ aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siz
if (npu_slot->cu_idx == INVALID_CU_IDX)
return -EINVAL;
memset(npu_slot, 0, sizeof(*npu_slot));
npu_slot->type = EXEC_NPU_TYPE_NON_ELF;
npu_slot->arg_cnt = cmd_len / sizeof(u32);
memcpy(npu_slot->args, cmd, cmd_len);
@@ -671,6 +677,7 @@ 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)
@@ -683,7 +690,6 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *si
if (npu_slot->cu_idx == INVALID_CU_IDX)
return -EINVAL;
memset(npu_slot, 0, sizeof(*npu_slot));
npu_slot->type = EXEC_NPU_TYPE_PARTIAL_ELF;
npu_slot->inst_buf_addr = sn->buffer;
npu_slot->inst_size = sn->buffer_size;
@@ -703,6 +709,7 @@ 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)
@@ -715,7 +722,6 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t
if (npu_slot->cu_idx == INVALID_CU_IDX)
return -EINVAL;
memset(npu_slot, 0, sizeof(*npu_slot));
npu_slot->type = EXEC_NPU_TYPE_PREEMPT;
npu_slot->inst_buf_addr = pd->inst_buf;
npu_slot->save_buf_addr = pd->save_buf;
@@ -739,6 +745,7 @@ 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)
@@ -747,7 +754,6 @@ 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;
+1 -1
View File
@@ -322,7 +322,7 @@ static int aie2_xrs_set_dft_dpm_level(struct drm_device *ddev, u32 dpm_level)
if (ndev->pw_mode != POWER_MODE_DEFAULT || ndev->dpm_level == dpm_level)
return 0;
return ndev->priv->hw_ops.set_dpm(ndev, dpm_level);
return aie2_pm_set_dpm(ndev, dpm_level);
}
static struct xrs_action_ops aie2_xrs_actions = {
+3
View File
@@ -70,6 +70,7 @@ enum psp_reg_idx {
PSP_INTR_REG = PSP_NUM_IN_REGS,
PSP_STATUS_REG,
PSP_RESP_REG,
PSP_PWAITMODE_REG,
PSP_MAX_REGS /* Keep this at the end */
};
@@ -285,11 +286,13 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
/* aie2_pm.c */
int aie2_pm_init(struct amdxdna_dev_hdl *ndev);
int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target);
int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
/* aie2_psp.c */
struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf);
int aie2_psp_start(struct psp_device *psp);
void aie2_psp_stop(struct psp_device *psp);
int aie2_psp_waitmode_poll(struct psp_device *psp);
/* aie2_error.c */
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev);
+16 -1
View File
@@ -10,6 +10,7 @@
#include "aie2_pci.h"
#include "amdxdna_pci_drv.h"
#include "amdxdna_pm.h"
#define AIE2_CLK_GATING_ENABLE 1
#define AIE2_CLK_GATING_DISABLE 0
@@ -26,6 +27,20 @@ static int aie2_pm_set_clk_gating(struct amdxdna_dev_hdl *ndev, u32 val)
return 0;
}
int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
{
int ret;
ret = amdxdna_pm_resume_get(ndev->xdna);
if (ret)
return ret;
ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level);
amdxdna_pm_suspend_put(ndev->xdna);
return ret;
}
int aie2_pm_init(struct amdxdna_dev_hdl *ndev)
{
int ret;
@@ -94,7 +109,7 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type
return -EOPNOTSUPP;
}
ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level);
ret = aie2_pm_set_dpm(ndev, dpm_level);
if (ret)
return ret;
+15
View File
@@ -76,6 +76,21 @@ static int psp_exec(struct psp_device *psp, u32 *reg_vals)
return 0;
}
int aie2_psp_waitmode_poll(struct psp_device *psp)
{
struct amdxdna_dev *xdna = to_xdna_dev(psp->ddev);
u32 mode_reg;
int ret;
ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_PWAITMODE_REG), mode_reg,
(mode_reg & 0x1) == 1,
PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
if (ret)
XDNA_ERR(xdna, "fw waitmode reg error, ret %d", ret);
return ret;
}
void aie2_psp_stop(struct psp_device *psp)
{
u32 reg_vals[PSP_NUM_IN_REGS] = { PSP_RELEASE_TMR, };
+4 -23
View File
@@ -11,7 +11,6 @@
#include "aie2_pci.h"
#include "amdxdna_pci_drv.h"
#include "amdxdna_pm.h"
#define SMU_RESULT_OK 1
@@ -67,16 +66,12 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
u32 freq;
int ret;
ret = amdxdna_pm_resume_get(ndev->xdna);
if (ret)
return ret;
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ,
ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq);
if (ret) {
XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n",
ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret);
goto suspend_put;
return ret;
}
ndev->npuclk_freq = freq;
@@ -85,10 +80,9 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
if (ret) {
XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n",
ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret);
goto suspend_put;
return ret;
}
amdxdna_pm_suspend_put(ndev->xdna);
ndev->hclk_freq = freq;
ndev->dpm_level = dpm_level;
ndev->max_tops = 2 * ndev->total_col;
@@ -98,35 +92,26 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
ndev->npuclk_freq, ndev->hclk_freq);
return 0;
suspend_put:
amdxdna_pm_suspend_put(ndev->xdna);
return ret;
}
int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
{
int ret;
ret = amdxdna_pm_resume_get(ndev->xdna);
if (ret)
return ret;
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL);
if (ret) {
XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ",
dpm_level, ret);
goto suspend_put;
return ret;
}
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL);
if (ret) {
XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d",
dpm_level, ret);
goto suspend_put;
return ret;
}
amdxdna_pm_suspend_put(ndev->xdna);
ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk;
ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk;
ndev->dpm_level = dpm_level;
@@ -137,10 +122,6 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
ndev->npuclk_freq, ndev->hclk_freq);
return 0;
suspend_put:
amdxdna_pm_suspend_put(ndev->xdna);
return ret;
}
int aie2_smu_init(struct amdxdna_dev_hdl *ndev)
+1 -18
View File
@@ -112,22 +112,6 @@ static u32 mailbox_reg_read(struct mailbox_channel *mb_chann, u32 mbox_reg)
return readl(ringbuf_addr);
}
static int mailbox_reg_read_non_zero(struct mailbox_channel *mb_chann, u32 mbox_reg, u32 *val)
{
struct xdna_mailbox_res *mb_res = &mb_chann->mb->res;
void __iomem *ringbuf_addr = mb_res->mbox_base + mbox_reg;
int ret, value;
/* Poll till value is not zero */
ret = readx_poll_timeout(readl, ringbuf_addr, value,
value, 1 /* us */, 100);
if (ret < 0)
return ret;
*val = value;
return 0;
}
static inline void
mailbox_set_headptr(struct mailbox_channel *mb_chann, u32 headptr_val)
{
@@ -286,8 +270,7 @@ static int mailbox_get_msg(struct mailbox_channel *mb_chann)
u32 start_addr;
int ret;
if (mailbox_reg_read_non_zero(mb_chann, mb_chann->res[CHAN_RES_I2X].mb_tail_ptr_reg, &tail))
return -EINVAL;
tail = mailbox_get_tailptr(mb_chann, CHAN_RES_I2X);
head = mb_chann->i2x_head;
ringbuf_size = mailbox_get_ringbuf_size(mb_chann, CHAN_RES_I2X);
start_addr = mb_chann->res[CHAN_RES_I2X].rb_start_addr;
-1
View File
@@ -101,7 +101,6 @@ struct amdxdna_dev {
struct amdxdna_fw_ver fw_ver;
struct rw_semaphore notifier_lock; /* for mmu notifier*/
struct workqueue_struct *notifier_wq;
bool rpm_on;
};
/*
+2 -20
View File
@@ -15,14 +15,9 @@ int amdxdna_pm_suspend(struct device *dev)
{
struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev));
int ret = -EOPNOTSUPP;
bool rpm;
if (xdna->dev_info->ops->suspend) {
rpm = xdna->rpm_on;
xdna->rpm_on = false;
if (xdna->dev_info->ops->suspend)
ret = xdna->dev_info->ops->suspend(xdna);
xdna->rpm_on = rpm;
}
XDNA_DBG(xdna, "Suspend done ret %d", ret);
return ret;
@@ -32,14 +27,9 @@ int amdxdna_pm_resume(struct device *dev)
{
struct amdxdna_dev *xdna = to_xdna_dev(dev_get_drvdata(dev));
int ret = -EOPNOTSUPP;
bool rpm;
if (xdna->dev_info->ops->resume) {
rpm = xdna->rpm_on;
xdna->rpm_on = false;
if (xdna->dev_info->ops->resume)
ret = xdna->dev_info->ops->resume(xdna);
xdna->rpm_on = rpm;
}
XDNA_DBG(xdna, "Resume done ret %d", ret);
return ret;
@@ -50,9 +40,6 @@ int amdxdna_pm_resume_get(struct amdxdna_dev *xdna)
struct device *dev = xdna->ddev.dev;
int ret;
if (!xdna->rpm_on)
return 0;
ret = pm_runtime_resume_and_get(dev);
if (ret) {
XDNA_ERR(xdna, "Resume failed: %d", ret);
@@ -66,9 +53,6 @@ void amdxdna_pm_suspend_put(struct amdxdna_dev *xdna)
{
struct device *dev = xdna->ddev.dev;
if (!xdna->rpm_on)
return;
pm_runtime_put_autosuspend(dev);
}
@@ -81,14 +65,12 @@ void amdxdna_pm_init(struct amdxdna_dev *xdna)
pm_runtime_use_autosuspend(dev);
pm_runtime_allow(dev);
pm_runtime_put_autosuspend(dev);
xdna->rpm_on = true;
}
void amdxdna_pm_fini(struct amdxdna_dev *xdna)
{
struct device *dev = xdna->ddev.dev;
xdna->rpm_on = false;
pm_runtime_get_noresume(dev);
pm_runtime_forbid(dev);
}
+2
View File
@@ -13,6 +13,7 @@
#include "amdxdna_pci_drv.h"
/* Address definition from NPU1 docs */
#define MPNPU_PWAITMODE 0x3010034
#define MPNPU_PUB_SEC_INTR 0x3010090
#define MPNPU_PUB_PWRMGMT_INTR 0x3010094
#define MPNPU_PUB_SCRATCH2 0x30100A0
@@ -92,6 +93,7 @@ static const struct amdxdna_dev_priv npu1_dev_priv = {
DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU1_PSP, MPNPU_PUB_SEC_INTR),
DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU1_PSP, MPNPU_PUB_SCRATCH2),
DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU1_PSP, MPNPU_PUB_SCRATCH3),
DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU1_PSP, MPNPU_PWAITMODE),
},
.smu_regs_off = {
DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU1_SMU, MPNPU_PUB_SCRATCH5),
+2
View File
@@ -13,6 +13,7 @@
#include "amdxdna_pci_drv.h"
/* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */
#define MPNPU_PWAITMODE 0x301003C
#define MPNPU_PUB_SEC_INTR 0x3010060
#define MPNPU_PUB_PWRMGMT_INTR 0x3010064
#define MPNPU_PUB_SCRATCH0 0x301006C
@@ -85,6 +86,7 @@ static const struct amdxdna_dev_priv npu2_dev_priv = {
DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU2_PSP, MP0_C2PMSG_73),
DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU2_PSP, MP0_C2PMSG_123),
DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU2_REG, MPNPU_PUB_SCRATCH3),
DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU2_REG, MPNPU_PWAITMODE),
},
.smu_regs_off = {
DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU2_SMU, MP1_C2PMSG_0),
+2
View File
@@ -13,6 +13,7 @@
#include "amdxdna_pci_drv.h"
/* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */
#define MPNPU_PWAITMODE 0x301003C
#define MPNPU_PUB_SEC_INTR 0x3010060
#define MPNPU_PUB_PWRMGMT_INTR 0x3010064
#define MPNPU_PUB_SCRATCH0 0x301006C
@@ -116,6 +117,7 @@ static const struct amdxdna_dev_priv npu4_dev_priv = {
DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU4_PSP, MP0_C2PMSG_73),
DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU4_PSP, MP0_C2PMSG_123),
DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU4_REG, MPNPU_PUB_SCRATCH3),
DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU4_REG, MPNPU_PWAITMODE),
},
.smu_regs_off = {
DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU4_SMU, MP1_C2PMSG_0),
+2
View File
@@ -13,6 +13,7 @@
#include "amdxdna_pci_drv.h"
/* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */
#define MPNPU_PWAITMODE 0x301003C
#define MPNPU_PUB_SEC_INTR 0x3010060
#define MPNPU_PUB_PWRMGMT_INTR 0x3010064
#define MPNPU_PUB_SCRATCH0 0x301006C
@@ -85,6 +86,7 @@ static const struct amdxdna_dev_priv npu5_dev_priv = {
DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU5_PSP, MP0_C2PMSG_73),
DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU5_PSP, MP0_C2PMSG_123),
DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU5_REG, MPNPU_PUB_SCRATCH3),
DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU5_REG, MPNPU_PWAITMODE),
},
.smu_regs_off = {
DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU5_SMU, MP1_C2PMSG_0),
+2
View File
@@ -13,6 +13,7 @@
#include "amdxdna_pci_drv.h"
/* NPU Public Registers on MpNPUAxiXbar (refer to Diag npu_registers.h) */
#define MPNPU_PWAITMODE 0x301003C
#define MPNPU_PUB_SEC_INTR 0x3010060
#define MPNPU_PUB_PWRMGMT_INTR 0x3010064
#define MPNPU_PUB_SCRATCH0 0x301006C
@@ -85,6 +86,7 @@ static const struct amdxdna_dev_priv npu6_dev_priv = {
DEFINE_BAR_OFFSET(PSP_INTR_REG, NPU6_PSP, MP0_C2PMSG_73),
DEFINE_BAR_OFFSET(PSP_STATUS_REG, NPU6_PSP, MP0_C2PMSG_123),
DEFINE_BAR_OFFSET(PSP_RESP_REG, NPU6_REG, MPNPU_PUB_SCRATCH3),
DEFINE_BAR_OFFSET(PSP_PWAITMODE_REG, NPU6_REG, MPNPU_PWAITMODE),
},
.smu_regs_off = {
DEFINE_BAR_OFFSET(SMU_CMD_REG, NPU6_SMU, MP1_C2PMSG_0),
+1 -1
View File
@@ -55,7 +55,7 @@ config DMABUF_MOVE_NOTIFY
config DMABUF_DEBUG
bool "DMA-BUF debug checks"
depends on DMA_SHARED_BUFFER
default y if DMA_API_DEBUG
default y if DEBUG
help
This option enables additional checks for DMA-BUF importers and
exporters. Specifically it validates that importers do not peek at the
+61 -16
View File
@@ -35,6 +35,12 @@
#include "dma-buf-sysfs-stats.h"
/* Wrapper to hide the sg_table page link from the importer */
struct dma_buf_sg_table_wrapper {
struct sg_table *original;
struct sg_table wrapper;
};
static inline int is_dma_buf_file(struct file *);
static DEFINE_MUTEX(dmabuf_list_mutex);
@@ -820,21 +826,59 @@ void dma_buf_put(struct dma_buf *dmabuf)
}
EXPORT_SYMBOL_NS_GPL(dma_buf_put, "DMA_BUF");
static void mangle_sg_table(struct sg_table *sg_table)
static int dma_buf_wrap_sg_table(struct sg_table **sg_table)
{
#ifdef CONFIG_DMABUF_DEBUG
int i;
struct scatterlist *sg;
struct scatterlist *to_sg, *from_sg;
struct sg_table *from = *sg_table;
struct dma_buf_sg_table_wrapper *to;
int i, ret;
/* To catch abuse of the underlying struct page by importers mix
* up the bits, but take care to preserve the low SG_ bits to
* not corrupt the sgt. The mixing is undone on unmap
* before passing the sgt back to the exporter.
if (!IS_ENABLED(CONFIG_DMABUF_DEBUG))
return 0;
/*
* To catch abuse of the underlying struct page by importers copy the
* sg_table without copying the page_link and give only the copy back to
* the importer.
*/
for_each_sgtable_sg(sg_table, sg, i)
sg->page_link ^= ~0xffUL;
#endif
to = kzalloc(sizeof(*to), GFP_KERNEL);
if (!to)
return -ENOMEM;
ret = sg_alloc_table(&to->wrapper, from->nents, GFP_KERNEL);
if (ret)
goto free_to;
to_sg = to->wrapper.sgl;
for_each_sgtable_dma_sg(from, from_sg, i) {
to_sg->offset = 0;
to_sg->length = 0;
sg_assign_page(to_sg, NULL);
sg_dma_address(to_sg) = sg_dma_address(from_sg);
sg_dma_len(to_sg) = sg_dma_len(from_sg);
to_sg = sg_next(to_sg);
}
to->original = from;
*sg_table = &to->wrapper;
return 0;
free_to:
kfree(to);
return ret;
}
static void dma_buf_unwrap_sg_table(struct sg_table **sg_table)
{
struct dma_buf_sg_table_wrapper *copy;
if (!IS_ENABLED(CONFIG_DMABUF_DEBUG))
return;
copy = container_of(*sg_table, typeof(*copy), wrapper);
*sg_table = copy->original;
sg_free_table(&copy->wrapper);
kfree(copy);
}
static inline bool
@@ -1131,10 +1175,11 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
if (ret < 0)
goto error_unmap;
}
mangle_sg_table(sg_table);
ret = dma_buf_wrap_sg_table(&sg_table);
if (ret)
goto error_unmap;
#ifdef CONFIG_DMA_API_DEBUG
{
if (IS_ENABLED(CONFIG_DMA_API_DEBUG)) {
struct scatterlist *sg;
u64 addr;
int len;
@@ -1146,10 +1191,10 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
if (!PAGE_ALIGNED(addr) || !PAGE_ALIGNED(len)) {
pr_debug("%s: addr %llx or len %x is not page aligned!\n",
__func__, addr, len);
break;
}
}
}
#endif /* CONFIG_DMA_API_DEBUG */
return sg_table;
error_unmap:
@@ -1213,7 +1258,7 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
dma_resv_assert_held(attach->dmabuf->resv);
mangle_sg_table(sg_table);
dma_buf_unwrap_sg_table(&sg_table);
attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction);
if (dma_buf_pin_on_map(attach))
+62 -38
View File
@@ -358,11 +358,8 @@ void __dma_fence_might_wait(void)
*
* Unlike dma_fence_signal_timestamp(), this function must be called with
* &dma_fence.lock held.
*
* Returns 0 on success and a negative error value when @fence has been
* signalled already.
*/
int dma_fence_signal_timestamp_locked(struct dma_fence *fence,
void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
ktime_t timestamp)
{
struct dma_fence_cb *cur, *tmp;
@@ -372,7 +369,7 @@ int dma_fence_signal_timestamp_locked(struct dma_fence *fence,
if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&fence->flags)))
return -EINVAL;
return;
/* Stash the cb_list before replacing it with the timestamp */
list_replace(&fence->cb_list, &cb_list);
@@ -385,8 +382,6 @@ int dma_fence_signal_timestamp_locked(struct dma_fence *fence,
INIT_LIST_HEAD(&cur->node);
cur->func(fence, cur);
}
return 0;
}
EXPORT_SYMBOL(dma_fence_signal_timestamp_locked);
@@ -401,23 +396,17 @@ EXPORT_SYMBOL(dma_fence_signal_timestamp_locked);
* can only go from the unsignaled to the signaled state and not back, it will
* only be effective the first time. Set the timestamp provided as the fence
* signal timestamp.
*
* Returns 0 on success and a negative error value when @fence has been
* signalled already.
*/
int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp)
void dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp)
{
unsigned long flags;
int ret;
if (WARN_ON(!fence))
return -EINVAL;
return;
spin_lock_irqsave(fence->lock, flags);
ret = dma_fence_signal_timestamp_locked(fence, timestamp);
dma_fence_signal_timestamp_locked(fence, timestamp);
spin_unlock_irqrestore(fence->lock, flags);
return ret;
}
EXPORT_SYMBOL(dma_fence_signal_timestamp);
@@ -433,16 +422,57 @@ EXPORT_SYMBOL(dma_fence_signal_timestamp);
*
* Unlike dma_fence_signal(), this function must be called with &dma_fence.lock
* held.
*
* Returns 0 on success and a negative error value when @fence has been
* signalled already.
*/
int dma_fence_signal_locked(struct dma_fence *fence)
void dma_fence_signal_locked(struct dma_fence *fence)
{
return dma_fence_signal_timestamp_locked(fence, ktime_get());
dma_fence_signal_timestamp_locked(fence, ktime_get());
}
EXPORT_SYMBOL(dma_fence_signal_locked);
/**
* dma_fence_check_and_signal_locked - signal the fence if it's not yet signaled
* @fence: the fence to check and signal
*
* Checks whether a fence was signaled and signals it if it was not yet signaled.
*
* Unlike dma_fence_check_and_signal(), this function must be called with
* &struct dma_fence.lock being held.
*
* Return: true if fence has been signaled already, false otherwise.
*/
bool dma_fence_check_and_signal_locked(struct dma_fence *fence)
{
bool ret;
ret = dma_fence_test_signaled_flag(fence);
dma_fence_signal_locked(fence);
return ret;
}
EXPORT_SYMBOL(dma_fence_check_and_signal_locked);
/**
* dma_fence_check_and_signal - signal the fence if it's not yet signaled
* @fence: the fence to check and signal
*
* Checks whether a fence was signaled and signals it if it was not yet signaled.
* All this is done in a race-free manner.
*
* Return: true if fence has been signaled already, false otherwise.
*/
bool dma_fence_check_and_signal(struct dma_fence *fence)
{
unsigned long flags;
bool ret;
spin_lock_irqsave(fence->lock, flags);
ret = dma_fence_check_and_signal_locked(fence);
spin_unlock_irqrestore(fence->lock, flags);
return ret;
}
EXPORT_SYMBOL(dma_fence_check_and_signal);
/**
* dma_fence_signal - signal completion of a fence
* @fence: the fence to signal
@@ -452,28 +482,22 @@ EXPORT_SYMBOL(dma_fence_signal_locked);
* dma_fence_add_callback(). Can be called multiple times, but since a fence
* can only go from the unsignaled to the signaled state and not back, it will
* only be effective the first time.
*
* Returns 0 on success and a negative error value when @fence has been
* signalled already.
*/
int dma_fence_signal(struct dma_fence *fence)
void dma_fence_signal(struct dma_fence *fence)
{
unsigned long flags;
int ret;
bool tmp;
if (WARN_ON(!fence))
return -EINVAL;
return;
tmp = dma_fence_begin_signalling();
spin_lock_irqsave(fence->lock, flags);
ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
dma_fence_signal_timestamp_locked(fence, ktime_get());
spin_unlock_irqrestore(fence->lock, flags);
dma_fence_end_signalling(tmp);
return ret;
}
EXPORT_SYMBOL(dma_fence_signal);
@@ -543,7 +567,7 @@ void dma_fence_release(struct kref *kref)
trace_dma_fence_destroy(fence);
if (!list_empty(&fence->cb_list) &&
!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
!dma_fence_test_signaled_flag(fence)) {
const char __rcu *timeline;
const char __rcu *driver;
unsigned long flags;
@@ -600,7 +624,7 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence)
was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
&fence->flags);
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
if (dma_fence_test_signaled_flag(fence))
return false;
if (!was_set && fence->ops->enable_signaling) {
@@ -664,7 +688,7 @@ int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
if (WARN_ON(!fence || !func))
return -EINVAL;
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
if (dma_fence_test_signaled_flag(fence)) {
INIT_LIST_HEAD(&cb->node);
return -ENOENT;
}
@@ -781,7 +805,7 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
spin_lock_irqsave(fence->lock, flags);
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
if (dma_fence_test_signaled_flag(fence))
goto out;
if (intr && signal_pending(current)) {
@@ -798,7 +822,7 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
cb.task = current;
list_add(&cb.base.node, &fence->cb_list);
while (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) && ret > 0) {
while (!dma_fence_test_signaled_flag(fence) && ret > 0) {
if (intr)
__set_current_state(TASK_INTERRUPTIBLE);
else
@@ -830,7 +854,7 @@ dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count,
for (i = 0; i < count; ++i) {
struct dma_fence *fence = fences[i];
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
if (dma_fence_test_signaled_flag(fence)) {
if (idx)
*idx = i;
return true;
@@ -1108,7 +1132,7 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence)
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"RCU protection is required for safe access to returned string");
if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
if (!dma_fence_test_signaled_flag(fence))
return fence->ops->get_driver_name(fence);
else
return "detached-driver";
@@ -1140,7 +1164,7 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence)
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"RCU protection is required for safe access to returned string");
if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
if (!dma_fence_test_signaled_flag(fence))
return fence->ops->get_timeline_name(fence);
else
return "signaled-timeline";

Some files were not shown because too many files have changed in this diff Show More