From: sashiko-bot@kernel.org
To: "Cody Kang" <codykang.hk@gmail.com>
Cc: devicetree@vger.kernel.org, linux-phy@lists.infradead.org,
dri-devel@lists.freedesktop.org, neil.armstrong@linaro.org,
conor+dt@kernel.org, vkoul@kernel.org, robh@kernel.org,
olteanv@gmail.com
Subject: Re: [PATCH 08/17] drm/spacemit: add Saturn DPU core types, cmdlist and display MMU
Date: Sat, 25 Jul 2026 05:16:26 +0000 [thread overview]
Message-ID: <20260725051626.9AE561F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260724-k3-display-v1-8-f22a10a52867@gmail.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Passing exhausted NULL pointer to hardware programming function.
- [High] NULL pointer dereference when accessing state for disabled planes due to stale `in_use` flag.
- [High] DMMU page tables map multi-planar framebuffers out-of-bounds by exclusively using the first GEM object.
- [High] Hardware DMA state buffers are reused across atomic commits without double-buffering.
- [High] Missing bounds check in `cmdlist_regs_packing` causes DMA buffer overflow.
- [Medium] Unconditional dereference of `fb` in `dpu_plane_info` tracepoint.
--
--- Patch [8]: [PATCH 08/17] drm/spacemit: add Saturn DPU core types, cmdlist and display MMU ---
commit 82f0596ca65ff96e2081646dccab37f7bb9d1c0c
Author: Cody Kang <codykang.hk@gmail.com>
Subject: drm/spacemit: add Saturn DPU core types, cmdlist and display MMU
This commit introduces the Saturn DPU driver core types, register accessors,
and MMU table code. It implements a batched register programming model using
in-memory command lists mapped through the DPU's private address translation
unit.
> diff --git a/drivers/gpu/drm/spacemit/dpu/dpu_trace.h b/drivers/gpu/drm/spacemit/dpu/dpu_trace.h
> new file mode 100644
> index 0000000000000..abfe34a67a4bd
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/dpu/dpu_trace.h
[ ... ]
> +TRACE_EVENT(dpu_plane_info,
> + TP_PROTO(struct drm_plane_state *state, struct drm_framebuffer *fb,
> + u32 rdma_id, u32 alpha, u32 rotation),
> + TP_ARGS(state, fb, rdma_id, alpha, rotation),
> + TP_STRUCT__entry(
> + __field(u32, rdma_id)
> + __field(u32, src_w)
> + __field(u32, src_h)
> + __field(u32, src_x)
> + __field(u32, src_y)
> + __field(u32, crtc_w)
> + __field(u32, crtc_h)
> + __field(u32, crtc_x)
> + __field(u32, crtc_y)
> + __field(u32, width)
> + __field(u32, height)
> + __field(u32, format)
> + __field(u32, blend_mode)
> + __field(u32, alpha)
> + __field(u32, zpos)
> + __field(u32, rotation)
> + ),
> + TP_fast_assign(
> + __entry->rdma_id = rdma_id;
> + __entry->src_w = state->src_w >> 16;
> + __entry->src_h = state->src_h >> 16;
> + __entry->src_x = state->src_x >> 16;
> + __entry->src_y = state->src_y >> 16;
> + __entry->crtc_w = state->crtc_w;
> + __entry->crtc_h = state->crtc_h;
> + __entry->crtc_x = state->crtc_x;
> + __entry->crtc_y = state->crtc_y;
> + __entry->width = fb->width;
> + __entry->height = fb->height;
> + __entry->format = fb->format->format;
[Severity: Medium]
If this tracepoint fires during a plane disable operation, will the fb
parameter be NULL? Since state->fb is typically NULL during a disable, it
looks like evaluating fb->format->format here could cause a kernel panic
when tracing is enabled.
> + __entry->blend_mode = state->pixel_blend_mode;
> + __entry->alpha = alpha;
> + __entry->zpos = state->zpos;
> + __entry->rotation = rotation;
> + ),
> + TP_printk("rdma_id=%d src: w=%d h=%d x=%d y=%d crtc: w=%d h=%d x=%d y=%d width=%d height=%d fmt=0x%x blend=%d alpha=%d zpos=%d rot=%d",
[ ... ]
> diff --git a/drivers/gpu/drm/spacemit/spacemit_cmdlist.c b/drivers/gpu/drm/spacemit/spacemit_cmdlist.c
> new file mode 100644
> index 0000000000000..787d38e9e135f
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/spacemit_cmdlist.c
[ ... ]
> +void cmdlist_regs_packing(struct cmdlist *cl, enum cmdlist_mode_type mod,
> + struct cmdlist_regs *cl_regs)
> +{
[ ... ]
> + if (cl_regs->flags[i]) {
> + offset = cl_regs->base + i * sizeof(u32);
> + for (u8 j = 0; j < CMDLIST_ROW_REGS; j++) {
> + index = i + j;
> + if (likely(index < cl_regs->size)) {
> + if (cl_regs->flags[index]) {
> + value[j] = reg_base[index];
> + regs_in_row++;
> + strobe |= CMDLIST_REG_STROBE(j);
> + }
> + } else {
> + break;
> + }
> + }
> + hwdev->cmdlist_fill_data_row(cl, strobe, offset, value);
> + /*
> + * the row covers the whole window; a shorter stride
> + * would revisit covered words as duplicate rows
> + */
> + i += CMDLIST_ROW_REGS;
> + cl->nod_len++;
[Severity: High]
Is there a bounds check missing here to prevent cl->nod_len from exceeding
cl->size? If cl is shallow-copied and reused across commits, nod_len might
accumulate and eventually overflow the 4096-byte DMA buffer, overwriting
adjacent physical memory.
> + } else {
> + i++;
> + }
> + }
> +
> + drm_dbg(a_crtc->crtc.dev, "row_num = %d\n", cl->nod_len);
> +}
[ ... ]
> +void cmdlist_atomic_commit(struct drm_crtc *crtc,
> + struct drm_crtc_state *old_state)
> +{
> + int i;
> + struct cmdlist *cur_cl, *first_cl;
> + struct spacemit_crtc *a_crtc = NULL;
> + u32 chy, addrl, addrh;
> + struct spacemit_drm_private *priv = crtc->dev->dev_private;
> + struct spacemit_hw_device *hwdev = priv->hwdev;
> + struct spacemit_crtc_rdma *cur_rdmas =
> + to_spacemit_crtc_state(crtc->state)->rdmas;
> + struct spacemit_crtc_rdma *old_rdmas =
> + to_spacemit_crtc_state(old_state)->rdmas;
> +
> + a_crtc = to_spacemit_crtc(crtc);
> +
> + for (i = 0; i < hwdev->rdma_nums; i++) {
> + if (old_rdmas[i].in_use)
> + hwdev->enable_cmdlist(a_crtc, hwdev, i, false);
> +
> + if (cur_rdmas[i].in_use) {
> + drm_dbg(crtc->dev, "cmdlist group = %d\n", i);
> + cur_cl = priv->cmdlist_groups[i];
> + first_cl = cur_cl;
> + while (cur_cl) {
> + hwdev->cmdlist_fill_conf_row(cur_cl, hwdev,
> + CMDLIST_CMP_INVALID);
> + cmdlist_dump_node(cur_cl);
> + cur_cl = cur_cl->next;
> + }
> + chy = cl_to_spacemit_pstate(first_cl)->state.crtc_y;
[Severity: High]
Could first_cl be NULL here for a disabled plane? During atomic state
duplication, it seems the in_use flag is inherited. If a plane is disabled,
it is removed from the plane_mask and cmdlist_sort_by_group skips clearing
the flag. This would cause cur_cl and first_cl to be NULL, leading
cl_to_spacemit_pstate to apply container_of to a NULL pointer and trigger a
negative offset dereference.
> + addrl = (lower_32_bits(priv->cmdlist_groups[i]->pa) &
> + CMDLIST_ADDRL_ALIGN_MASK) >> CMDLIST_ADDRL_ALIGN_BITS;
> +
> + addrh = upper_32_bits(priv->cmdlist_groups[i]->pa);
> + hwdev->cfg_cmdlist(hwdev, i, chy, addrl, addrh);
> + hwdev->enable_cmdlist(a_crtc, hwdev, i, true);
> + priv->cmdlist_groups[i] = NULL;
> + }
> + }
> +}
[ ... ]
> +void crtc_cmdlist_atomic_commit(struct spacemit_crtc *a_crtc)
> +{
> + struct cmdlist *cur_cl;
> + struct drm_crtc *crtc = &a_crtc->crtc;
> + struct spacemit_drm_private *priv = crtc->dev->dev_private;
> + struct spacemit_hw_device *hwdev = priv->hwdev;
> + u8 crtc_id = drm_crtc_index(crtc);
> + u8 dev_id = a_crtc->dev_id;
> +
> + drm_dbg(crtc->dev, "cmdlist group = %d\n",
> + hwdev->rdma_nums + crtc_id);
> + cur_cl = priv->cmdlist_groups[hwdev->rdma_nums + crtc_id];
> + while (cur_cl) {
> + hwdev->cmdlist_fill_conf_row(cur_cl, hwdev, dev_id);
> + cmdlist_dump_node(cur_cl);
> + cur_cl = cur_cl->next;
> + }
> + hwdev->crtc_cmdlist(cur_cl, hwdev, priv, crtc_id, dev_id);
[Severity: High]
Does this loop exhaust cur_cl to NULL before passing it to
hwdev->crtc_cmdlist? Once the while loop finishes, cur_cl is guaranteed to be
NULL, which seems like it would pass an invalid pointer to the hardware
programming function instead of the intended command list head.
> +}
> +
> +/* Called from atomic_check(), where -ENOMEM is still an answer. */
> +int spacemit_cmdlist_alloc(struct device *dev, struct cmdlist *cl)
> +{
> + if (cl->va)
> + return 0;
> +
> + cl->size = PER_CMDLIST_SIZE;
> + cl->va = dma_alloc_coherent(dev, cl->size, &cl->pa,
> + GFP_KERNEL | __GFP_ZERO);
[Severity: High]
Does bypassing reallocation when cl->va is present cause the active hardware
state to be overwritten during the prepare phase of a non-blocking commit?
It looks like writing new register sequences directly into this reused buffer
could corrupt the in-flight display state being scanned out by the hardware.
> + if (!cl->va)
> + return -ENOMEM;
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/spacemit/spacemit_dmmu.c b/drivers/gpu/drm/spacemit/spacemit_dmmu.c
> new file mode 100644
> index 0000000000000..2ae30dd1a4f23
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/spacemit_dmmu.c
[ ... ]
> +int spacemit_dmmu_map(struct drm_framebuffer *fb, struct dpu_mmu_tbl *mmu_tbl,
> + u8 tbu_id, struct cmdlist_regs *cl_rdma,
> + struct drm_plane *plane)
> +{
> + struct spacemit_drm_private *priv = fb->dev->dev_private;
> + struct spacemit_hw_device *hwdev = priv->hwdev;
> + const struct drm_format_info *format = NULL;
> + struct sg_table *sgt = NULL;
> + u32 total_size, offset1, offset2;
> + struct tbu_instance tbu = { };
> + u8 plane_num;
> + u32 val;
> +
> + format = fb->format;
> + sgt = drm_gem_shmem_get_pages_sgt(to_drm_gem_shmem_obj(fb->obj[0]));
> + if (IS_ERR(sgt))
> + return PTR_ERR(sgt);
> +
> + plane_num = format->num_planes;
> +
> + total_size = roundup(fb->obj[0]->size, PAGE_SIZE);
> +
> + offset1 = plane_num > 1 ? fb->offsets[1] : total_size;
> + offset2 = plane_num > 2 ? fb->offsets[2] : total_size;
> +
> + switch (plane_num) {
> + case 3:
> + tbu.ttb_pa[2] = mmu_tbl->pa + (offset2 >> PAGE_SHIFT) * 4;
> + tbu.tbu_va[2] = TBU_BASE_VA(tbu_id) + offset2;
> + tbu.ttb_size[2] = PAGE_ALIGN(total_size - rounddown(offset2, PAGE_SIZE))
> + >> PAGE_SHIFT;
> + fallthrough;
> + case 2:
> + tbu.ttb_pa[1] = mmu_tbl->pa + (offset1 >> PAGE_SHIFT) * 4;
> + tbu.tbu_va[1] = TBU_BASE_VA(tbu_id) + offset1;
> + tbu.ttb_size[1] = PAGE_ALIGN(offset2 - rounddown(offset1, PAGE_SIZE)) >> PAGE_SHIFT;
[Severity: High]
For multi-planar formats with discrete GEM objects, does this map the
secondary planes out of bounds? The scatter/gather table is fetched strictly
from fb->obj[0]. Applying secondary offsets to the physical pages of the
first GEM object might break hardware isolation.
Could the size calculation offset2 - rounddown(offset1, PAGE_SIZE) also
underflow if these offsets belong to separate, un-ordered buffers?
> + fallthrough;
> + case 1:
> + tbu.ttb_pa[0] = mmu_tbl->pa;
> + tbu.tbu_va[0] = TBU_BASE_VA(tbu_id);
> + tbu.ttb_size[0] = PAGE_ALIGN(offset1) >> PAGE_SHIFT;
> + fallthrough;
> + default:
> + break;
> + }
> + spacemit_dmmu_fill_pgtable(mmu_tbl, sgt);
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-k3-display-v1-0-f22a10a52867@gmail.com?part=8
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
WARNING: multiple messages have this Message-ID (diff)
From: sashiko-bot@kernel.org
To: "Cody Kang" <codykang.hk@gmail.com>
Cc: devicetree@vger.kernel.org, linux-phy@lists.infradead.org,
dri-devel@lists.freedesktop.org, neil.armstrong@linaro.org,
conor+dt@kernel.org, vkoul@kernel.org, robh@kernel.org,
olteanv@gmail.com
Subject: Re: [PATCH 08/17] drm/spacemit: add Saturn DPU core types, cmdlist and display MMU
Date: Sat, 25 Jul 2026 05:16:26 +0000 [thread overview]
Message-ID: <20260725051626.9AE561F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260724-k3-display-v1-8-f22a10a52867@gmail.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Passing exhausted NULL pointer to hardware programming function.
- [High] NULL pointer dereference when accessing state for disabled planes due to stale `in_use` flag.
- [High] DMMU page tables map multi-planar framebuffers out-of-bounds by exclusively using the first GEM object.
- [High] Hardware DMA state buffers are reused across atomic commits without double-buffering.
- [High] Missing bounds check in `cmdlist_regs_packing` causes DMA buffer overflow.
- [Medium] Unconditional dereference of `fb` in `dpu_plane_info` tracepoint.
--
--- Patch [8]: [PATCH 08/17] drm/spacemit: add Saturn DPU core types, cmdlist and display MMU ---
commit 82f0596ca65ff96e2081646dccab37f7bb9d1c0c
Author: Cody Kang <codykang.hk@gmail.com>
Subject: drm/spacemit: add Saturn DPU core types, cmdlist and display MMU
This commit introduces the Saturn DPU driver core types, register accessors,
and MMU table code. It implements a batched register programming model using
in-memory command lists mapped through the DPU's private address translation
unit.
> diff --git a/drivers/gpu/drm/spacemit/dpu/dpu_trace.h b/drivers/gpu/drm/spacemit/dpu/dpu_trace.h
> new file mode 100644
> index 0000000000000..abfe34a67a4bd
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/dpu/dpu_trace.h
[ ... ]
> +TRACE_EVENT(dpu_plane_info,
> + TP_PROTO(struct drm_plane_state *state, struct drm_framebuffer *fb,
> + u32 rdma_id, u32 alpha, u32 rotation),
> + TP_ARGS(state, fb, rdma_id, alpha, rotation),
> + TP_STRUCT__entry(
> + __field(u32, rdma_id)
> + __field(u32, src_w)
> + __field(u32, src_h)
> + __field(u32, src_x)
> + __field(u32, src_y)
> + __field(u32, crtc_w)
> + __field(u32, crtc_h)
> + __field(u32, crtc_x)
> + __field(u32, crtc_y)
> + __field(u32, width)
> + __field(u32, height)
> + __field(u32, format)
> + __field(u32, blend_mode)
> + __field(u32, alpha)
> + __field(u32, zpos)
> + __field(u32, rotation)
> + ),
> + TP_fast_assign(
> + __entry->rdma_id = rdma_id;
> + __entry->src_w = state->src_w >> 16;
> + __entry->src_h = state->src_h >> 16;
> + __entry->src_x = state->src_x >> 16;
> + __entry->src_y = state->src_y >> 16;
> + __entry->crtc_w = state->crtc_w;
> + __entry->crtc_h = state->crtc_h;
> + __entry->crtc_x = state->crtc_x;
> + __entry->crtc_y = state->crtc_y;
> + __entry->width = fb->width;
> + __entry->height = fb->height;
> + __entry->format = fb->format->format;
[Severity: Medium]
If this tracepoint fires during a plane disable operation, will the fb
parameter be NULL? Since state->fb is typically NULL during a disable, it
looks like evaluating fb->format->format here could cause a kernel panic
when tracing is enabled.
> + __entry->blend_mode = state->pixel_blend_mode;
> + __entry->alpha = alpha;
> + __entry->zpos = state->zpos;
> + __entry->rotation = rotation;
> + ),
> + TP_printk("rdma_id=%d src: w=%d h=%d x=%d y=%d crtc: w=%d h=%d x=%d y=%d width=%d height=%d fmt=0x%x blend=%d alpha=%d zpos=%d rot=%d",
[ ... ]
> diff --git a/drivers/gpu/drm/spacemit/spacemit_cmdlist.c b/drivers/gpu/drm/spacemit/spacemit_cmdlist.c
> new file mode 100644
> index 0000000000000..787d38e9e135f
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/spacemit_cmdlist.c
[ ... ]
> +void cmdlist_regs_packing(struct cmdlist *cl, enum cmdlist_mode_type mod,
> + struct cmdlist_regs *cl_regs)
> +{
[ ... ]
> + if (cl_regs->flags[i]) {
> + offset = cl_regs->base + i * sizeof(u32);
> + for (u8 j = 0; j < CMDLIST_ROW_REGS; j++) {
> + index = i + j;
> + if (likely(index < cl_regs->size)) {
> + if (cl_regs->flags[index]) {
> + value[j] = reg_base[index];
> + regs_in_row++;
> + strobe |= CMDLIST_REG_STROBE(j);
> + }
> + } else {
> + break;
> + }
> + }
> + hwdev->cmdlist_fill_data_row(cl, strobe, offset, value);
> + /*
> + * the row covers the whole window; a shorter stride
> + * would revisit covered words as duplicate rows
> + */
> + i += CMDLIST_ROW_REGS;
> + cl->nod_len++;
[Severity: High]
Is there a bounds check missing here to prevent cl->nod_len from exceeding
cl->size? If cl is shallow-copied and reused across commits, nod_len might
accumulate and eventually overflow the 4096-byte DMA buffer, overwriting
adjacent physical memory.
> + } else {
> + i++;
> + }
> + }
> +
> + drm_dbg(a_crtc->crtc.dev, "row_num = %d\n", cl->nod_len);
> +}
[ ... ]
> +void cmdlist_atomic_commit(struct drm_crtc *crtc,
> + struct drm_crtc_state *old_state)
> +{
> + int i;
> + struct cmdlist *cur_cl, *first_cl;
> + struct spacemit_crtc *a_crtc = NULL;
> + u32 chy, addrl, addrh;
> + struct spacemit_drm_private *priv = crtc->dev->dev_private;
> + struct spacemit_hw_device *hwdev = priv->hwdev;
> + struct spacemit_crtc_rdma *cur_rdmas =
> + to_spacemit_crtc_state(crtc->state)->rdmas;
> + struct spacemit_crtc_rdma *old_rdmas =
> + to_spacemit_crtc_state(old_state)->rdmas;
> +
> + a_crtc = to_spacemit_crtc(crtc);
> +
> + for (i = 0; i < hwdev->rdma_nums; i++) {
> + if (old_rdmas[i].in_use)
> + hwdev->enable_cmdlist(a_crtc, hwdev, i, false);
> +
> + if (cur_rdmas[i].in_use) {
> + drm_dbg(crtc->dev, "cmdlist group = %d\n", i);
> + cur_cl = priv->cmdlist_groups[i];
> + first_cl = cur_cl;
> + while (cur_cl) {
> + hwdev->cmdlist_fill_conf_row(cur_cl, hwdev,
> + CMDLIST_CMP_INVALID);
> + cmdlist_dump_node(cur_cl);
> + cur_cl = cur_cl->next;
> + }
> + chy = cl_to_spacemit_pstate(first_cl)->state.crtc_y;
[Severity: High]
Could first_cl be NULL here for a disabled plane? During atomic state
duplication, it seems the in_use flag is inherited. If a plane is disabled,
it is removed from the plane_mask and cmdlist_sort_by_group skips clearing
the flag. This would cause cur_cl and first_cl to be NULL, leading
cl_to_spacemit_pstate to apply container_of to a NULL pointer and trigger a
negative offset dereference.
> + addrl = (lower_32_bits(priv->cmdlist_groups[i]->pa) &
> + CMDLIST_ADDRL_ALIGN_MASK) >> CMDLIST_ADDRL_ALIGN_BITS;
> +
> + addrh = upper_32_bits(priv->cmdlist_groups[i]->pa);
> + hwdev->cfg_cmdlist(hwdev, i, chy, addrl, addrh);
> + hwdev->enable_cmdlist(a_crtc, hwdev, i, true);
> + priv->cmdlist_groups[i] = NULL;
> + }
> + }
> +}
[ ... ]
> +void crtc_cmdlist_atomic_commit(struct spacemit_crtc *a_crtc)
> +{
> + struct cmdlist *cur_cl;
> + struct drm_crtc *crtc = &a_crtc->crtc;
> + struct spacemit_drm_private *priv = crtc->dev->dev_private;
> + struct spacemit_hw_device *hwdev = priv->hwdev;
> + u8 crtc_id = drm_crtc_index(crtc);
> + u8 dev_id = a_crtc->dev_id;
> +
> + drm_dbg(crtc->dev, "cmdlist group = %d\n",
> + hwdev->rdma_nums + crtc_id);
> + cur_cl = priv->cmdlist_groups[hwdev->rdma_nums + crtc_id];
> + while (cur_cl) {
> + hwdev->cmdlist_fill_conf_row(cur_cl, hwdev, dev_id);
> + cmdlist_dump_node(cur_cl);
> + cur_cl = cur_cl->next;
> + }
> + hwdev->crtc_cmdlist(cur_cl, hwdev, priv, crtc_id, dev_id);
[Severity: High]
Does this loop exhaust cur_cl to NULL before passing it to
hwdev->crtc_cmdlist? Once the while loop finishes, cur_cl is guaranteed to be
NULL, which seems like it would pass an invalid pointer to the hardware
programming function instead of the intended command list head.
> +}
> +
> +/* Called from atomic_check(), where -ENOMEM is still an answer. */
> +int spacemit_cmdlist_alloc(struct device *dev, struct cmdlist *cl)
> +{
> + if (cl->va)
> + return 0;
> +
> + cl->size = PER_CMDLIST_SIZE;
> + cl->va = dma_alloc_coherent(dev, cl->size, &cl->pa,
> + GFP_KERNEL | __GFP_ZERO);
[Severity: High]
Does bypassing reallocation when cl->va is present cause the active hardware
state to be overwritten during the prepare phase of a non-blocking commit?
It looks like writing new register sequences directly into this reused buffer
could corrupt the in-flight display state being scanned out by the hardware.
> + if (!cl->va)
> + return -ENOMEM;
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/spacemit/spacemit_dmmu.c b/drivers/gpu/drm/spacemit/spacemit_dmmu.c
> new file mode 100644
> index 0000000000000..2ae30dd1a4f23
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/spacemit_dmmu.c
[ ... ]
> +int spacemit_dmmu_map(struct drm_framebuffer *fb, struct dpu_mmu_tbl *mmu_tbl,
> + u8 tbu_id, struct cmdlist_regs *cl_rdma,
> + struct drm_plane *plane)
> +{
> + struct spacemit_drm_private *priv = fb->dev->dev_private;
> + struct spacemit_hw_device *hwdev = priv->hwdev;
> + const struct drm_format_info *format = NULL;
> + struct sg_table *sgt = NULL;
> + u32 total_size, offset1, offset2;
> + struct tbu_instance tbu = { };
> + u8 plane_num;
> + u32 val;
> +
> + format = fb->format;
> + sgt = drm_gem_shmem_get_pages_sgt(to_drm_gem_shmem_obj(fb->obj[0]));
> + if (IS_ERR(sgt))
> + return PTR_ERR(sgt);
> +
> + plane_num = format->num_planes;
> +
> + total_size = roundup(fb->obj[0]->size, PAGE_SIZE);
> +
> + offset1 = plane_num > 1 ? fb->offsets[1] : total_size;
> + offset2 = plane_num > 2 ? fb->offsets[2] : total_size;
> +
> + switch (plane_num) {
> + case 3:
> + tbu.ttb_pa[2] = mmu_tbl->pa + (offset2 >> PAGE_SHIFT) * 4;
> + tbu.tbu_va[2] = TBU_BASE_VA(tbu_id) + offset2;
> + tbu.ttb_size[2] = PAGE_ALIGN(total_size - rounddown(offset2, PAGE_SIZE))
> + >> PAGE_SHIFT;
> + fallthrough;
> + case 2:
> + tbu.ttb_pa[1] = mmu_tbl->pa + (offset1 >> PAGE_SHIFT) * 4;
> + tbu.tbu_va[1] = TBU_BASE_VA(tbu_id) + offset1;
> + tbu.ttb_size[1] = PAGE_ALIGN(offset2 - rounddown(offset1, PAGE_SIZE)) >> PAGE_SHIFT;
[Severity: High]
For multi-planar formats with discrete GEM objects, does this map the
secondary planes out of bounds? The scatter/gather table is fetched strictly
from fb->obj[0]. Applying secondary offsets to the physical pages of the
first GEM object might break hardware isolation.
Could the size calculation offset2 - rounddown(offset1, PAGE_SIZE) also
underflow if these offsets belong to separate, un-ordered buffers?
> + fallthrough;
> + case 1:
> + tbu.ttb_pa[0] = mmu_tbl->pa;
> + tbu.tbu_va[0] = TBU_BASE_VA(tbu_id);
> + tbu.ttb_size[0] = PAGE_ALIGN(offset1) >> PAGE_SHIFT;
> + fallthrough;
> + default:
> + break;
> + }
> + spacemit_dmmu_fill_pgtable(mmu_tbl, sgt);
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-k3-display-v1-0-f22a10a52867@gmail.com?part=8
next prev parent reply other threads:[~2026-07-25 5:16 UTC|newest]
Thread overview: 75+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-25 3:16 [PATCH 00/17] drm/spacemit: add SpacemiT K3 display support Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 01/17] dt-bindings: display: spacemit: add K3 Saturn DPU controller Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 02/17] dt-bindings: phy: add SpacemiT K3 Innosilicon DP PHY Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 03/17] dt-bindings: display: spacemit: add K3 Innosilicon DP/eDP controller Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 04/17] dt-bindings: soc: spacemit: allow eDP/DP PHY PLL pixel clocks on K3 APMU Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:16 ` sashiko-bot
2026-07-25 5:16 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 05/17] phy: spacemit: add Innosilicon DP TX PHY driver Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:16 ` sashiko-bot
2026-07-25 5:16 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 06/17] clk: spacemit: k3: parent eDP/DP pixel clock to the PHY PLL Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 07/17] drm/spacemit: add Saturn DPU register model Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 08/17] drm/spacemit: add Saturn DPU core types, cmdlist and display MMU Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:16 ` sashiko-bot [this message]
2026-07-25 5:16 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 09/17] drm/spacemit: add Saturn DPU hardware backend Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:22 ` sashiko-bot
2026-07-25 5:22 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 10/17] drm/spacemit: add Saturn DPU KMS pipeline Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:18 ` sashiko-bot
2026-07-25 5:18 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 11/17] drm/spacemit: add Saturn DPU DRM device driver Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:17 ` sashiko-bot
2026-07-25 5:17 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 12/17] drm/spacemit: add Innosilicon DP/eDP controller bridge driver Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:20 ` sashiko-bot
2026-07-25 5:20 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 13/17] MAINTAINERS: add SpacemiT K3 display driver entry Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 14/17] riscv: dts: spacemit: k3: add display nodes Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:20 ` sashiko-bot
2026-07-25 5:20 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 15/17] riscv: dts: spacemit: k3-pico-itx: enable the DisplayPort output Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 5:23 ` sashiko-bot
2026-07-25 5:23 ` sashiko-bot
2026-07-25 3:16 ` [PATCH 16/17] riscv: dts: spacemit: k3-com260-ifx: " Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` [PATCH 17/17] riscv: defconfig: spacemit: k3: enable display driver Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 3:16 ` Cody Kang
2026-07-25 6:36 ` [PATCH 00/17] drm/spacemit: add SpacemiT K3 display support Cody Kang
2026-07-25 6:36 ` Cody Kang
2026-07-25 6:36 ` Cody Kang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260725051626.9AE561F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=codykang.hk@gmail.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-phy@lists.infradead.org \
--cc=neil.armstrong@linaro.org \
--cc=olteanv@gmail.com \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.