From: sashiko-bot@kernel.org
To: "Nihal Kumar Gupta" <nihal.gupta@oss.qualcomm.com>
Cc: devicetree@vger.kernel.org, linux-phy@lists.infradead.org,
robh@kernel.org, conor+dt@kernel.org, media-ci@linuxtv.org,
vkoul@kernel.org, neil.armstrong@linaro.org, olteanv@gmail.com
Subject: Re: [PATCH v3 5/5] media: qcom: camss: Add support for Hawi
Date: Fri, 30 Oct 2026 13:07:50 +0000 [thread overview]
Message-ID: <sashiko-outbox-191048@kernel.org> (raw)
In-Reply-To: <20261030-hawi-maili-camss-v3-5-9742bca8cef2@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] media: qcom: camss: unconditional AUP strobes in csid_configure_stream()
- [High] media: camss: NULL hw_ops deref in msm_csiphy_subdev_init_legacy()
- [Medium] media: qcom: camss: wrong camnoc_rt_axi clock rates in vfe_res_hawi
- [Medium] media: qcom: camss: data race on csid->addr_update and csid->reg_update
- [Low] media: qcom: camss: duplicate CSID 1080 and VFE 1080 code in 1190 files
- [Low] media: qcom: camss: macros in camss-csid-1190.c implicitly capture csid
--
commit 25967aac8ac2c5b636dbbaab24c84dd484d99ab8
Author: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
media: qcom: camss: Add support for Hawi
This commit adds CAMSS support for the Hawi SoC, including CSID 1190 and
VFE 1190 hardware operations and Hawi resource definitions.
> diff --git a/drivers/media/platform/qcom/camss/camss-csid-1190.c b/drivers/media/platform/qcom/camss/camss-csid-1190.c
> new file mode 100644
> index 0000000000000..4bd2cce094402
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-csid-1190.c
> @@ -0,0 +1,417 @@
[ ... ]
> +#define MSM_CSID_MAX_SRC_STREAMS_1190 (csid_is_lite(csid) ? 4 : 5)
> +
> +/* RDI Configuration */
> +#define CSID_RDI_CFG0(rdi) (csid_is_lite(csid) ?\
> + (0x3080 + 0x200 * (rdi)) :\
> + (0x5480 + 0x200 * (rdi)))
> +#define RDI_CFG0_RETIME_BS BIT(5)
> +#define RDI_CFG0_TIMESTAMP_EN BIT(6)
> +#define RDI_CFG0_TIMESTAMP_STB_SEL BIT(8)
> +#define RDI_CFG0_DECODE_FORMAT 12
> +#define RDI_CFG0_DT 16
> +#define RDI_CFG0_VC 22
> +#define RDI_CFG0_EN BIT(31)
> +
> +/* RDI Control and Configuration */
> +#define CSID_RDI_CTRL(rdi) (csid_is_lite(csid) ?\
> + (0x3088 + 0x200 * (rdi)) :\
> + (0x5488 + 0x200 * (rdi)))
> +#define RDI_CTRL_START_CMD BIT(0)
> +
> +#define CSID_RDI_CFG1(rdi) (csid_is_lite(csid) ?\
> + (0x3094 + 0x200 * (rdi)) :\
> + (0x5494 + 0x200 * (rdi)))
[Severity: Low]
As reported by Sashiko on v2 [1], this isn't a bug, but
MSM_CSID_MAX_SRC_STREAMS_1190, CSID_RDI_CFG0(rdi), CSID_RDI_CTRL(rdi), and
CSID_RDI_CFG1(rdi) in drivers/media/platform/qcom/camss/camss-csid-1190.c
expand to expressions calling csid_is_lite(csid) without taking csid as a
macro parameter. Should these macros take csid explicitly instead of relying
on a local variable named csid in the caller's scope?
[ ... ]
> +static void __csid_aup_rup_trigger(struct csid_device *csid)
> +{
> + /* trigger SET in combined register */
> + writel(RUP_SET, csid->base + CSID_RUP_AUP_CMD);
> +}
> +
> +static void __csid_addr_update(struct csid_device *csid, int port_id)
> +{
> + csid->addr_update |= CSID_RUP_AUP_RDI(port_id);
> + writel(csid->addr_update, csid->base + CSID_AUP_CMD);
> +
> + __csid_aup_rup_trigger(csid);
> +}
> +
> +static void __csid_addr_update_clear(struct csid_device *csid, int port_id)
> +{
> + /* Hardware clears the registers upon consuming the settings */
> + csid->addr_update &= ~CSID_RUP_AUP_RDI(port_id);
> +}
> +
> +static void __csid_reg_update(struct csid_device *csid, int port_id)
> +{
> + csid->reg_update |= CSID_RUP_AUP_RDI(port_id);
> + writel(csid->reg_update, csid->base + CSID_RUP_CMD);
> +
> + __csid_aup_rup_trigger(csid);
> +}
> +
> +static void __csid_reg_update_clear(struct csid_device *csid, int port_id)
> +{
> + /* Hardware clears the registers upon consuming the settings */
> + csid->reg_update &= ~CSID_RUP_AUP_RDI(port_id);
> +}
[Severity: Medium]
As reported by Sashiko on v2 [1], can __csid_addr_update() and
__csid_reg_update() race with __csid_addr_update_clear() and
__csid_reg_update_clear() on csid->addr_update and csid->reg_update?
In drivers/media/platform/qcom/camss/camss-csid-1190.c, __csid_addr_update()
and __csid_reg_update() perform non-atomic read-modify-write operations on
csid->addr_update and csid->reg_update before writing CSID_AUP_CMD and
CSID_RUP_CMD.
Meanwhile, in hardirq context, csid_isr() clears those fields when
INFO_RUP_DONE is set without holding any lock:
drivers/media/platform/qcom/camss/camss-csid-1190.c:csid_isr() {
...
if (val & INFO_RUP_DONE) {
__csid_addr_update_clear(csid, i);
__csid_reg_update_clear(csid, i);
}
...
}
Because vfe_queue_buffer_v2() and vfe_enable_output_v2() only hold
vfe->output_lock (which csid_isr() does not acquire before camss_buf_done())
and csid_configure_stream() holds no spinlock, concurrent updates from process
context (for example during VIDIOC_QBUF or when starting multiple RDI streams
sharing a CSID) and hardirq context can clobber bits in csid->addr_update and
csid->reg_update.
[ ... ]
> +static void csid_configure_stream(struct csid_device *csid, u8 enable)
> +{
> + u8 i, k;
> +
> + __csid_configure_rx(csid, &csid->phy);
> +
> + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS_1190; i++) {
> + if (csid->phy.en_vc & BIT(i)) {
> + __csid_configure_rdi_stream(csid, enable, i, 0);
> + __csid_configure_rx_vc(csid, 0);
> +
> + for (k = 0; k < CAMSS_INIT_BUF_COUNT; k++)
> + __csid_addr_update(csid, i);
> +
> + __csid_reg_update(csid, i);
> +
> + __csid_ctrl_rdi(csid, enable, i);
> + }
> + }
> +}
[Severity: High]
What happens in csid_configure_stream() if VIDIOC_STREAMON is called with
fewer than CAMSS_INIT_BUF_COUNT (2) buffers queued?
In msm_video_register() in drivers/media/platform/qcom/camss/camss-video.c,
vb2_queue.min_queued_buffers is 0, so vb2_core_streamon() invokes
vb2_start_streaming() -> video_start_streaming() even when 0 or 1 buffer is
queued before VIDIOC_STREAMON.
video_start_streaming() first calls vfe_set_stream() -> vfe_enable_v2() ->
vfe_enable_output_v2(), which dequeues only the available pending buffers (0
or 1) and writes their addresses via ops->vfe_wm_update():
drivers/media/platform/qcom/camss/camss-vfe.c:vfe_enable_output_v2() {
...
for (i = 0; i < CAMSS_INIT_BUF_COUNT; i++) {
output->buf[i] = vfe_buf_get_pending(output);
if (!output->buf[i])
break;
output->gen2.active_num++;
ops->vfe_wm_update(vfe, output->wm_idx[0],
output->buf[i]->addr[0], line);
if (!ops->addr_update)
ops->reg_update(vfe, line->id);
}
...
}
Next, video_start_streaming() calls csid_set_stream() ->
csid_configure_stream(), which unconditionally loops CAMSS_INIT_BUF_COUNT (2)
times calling __csid_addr_update(csid, i) regardless of how many buffers were
queued in vfe_enable_output_v2(). Moreover, vfe_wm_stop() in
drivers/media/platform/qcom/camss/camss-vfe-1190.c only clears
VFE_BUS_WM_CFG(wm) without clearing VFE_BUS_WM_IMAGE_ADDR(wm).
When userspace later queues buffers via VIDIOC_QBUF, vfe_queue_buffer_v2()
sees output->state == VFE_OUTPUT_ON and output->gen2.active_num < 2, and
issues additional ops->addr_update() and ops->reg_update() strobes:
drivers/media/platform/qcom/camss/camss-vfe.c:vfe_queue_buffer_v2() {
...
if (output->state == VFE_OUTPUT_ON &&
output->gen2.active_num < 2) {
output->buf[output->gen2.active_num++] = buf;
ops->vfe_wm_update(vfe, output->wm_idx[0],
buf->addr[0], line);
if (ops->addr_update)
ops->addr_update(vfe, line->id);
ops->reg_update(vfe, line->id);
}
...
}
Doesn't issuing two unconditional __csid_addr_update() strobes in
csid_configure_stream() latch stale or duplicate DMA addresses in the write
master and desynchronize buffer tracking when fewer than two buffers were
queued before streamon?
[ ... ]
> +const struct csid_hw_ops csid_ops_1190 = {
> + .configure_stream = csid_configure_stream,
> + .configure_testgen_pattern = csid_configure_testgen_pattern,
> + .hw_version = csid_hw_version,
> + .isr = csid_isr,
> + .reset = csid_reset,
> + .src_pad_code = csid_src_pad_code,
> + .subdev_init = csid_subdev_init,
> + .reg_update = csid_subdev_reg_update,
> + .addr_update = csid_subdev_addr_update,
> +};
[Severity: Low]
This isn't a bug, but every register offset, bitmask macro, stream count
definition, helper function, interrupt handler, reset routine, and hardware
operation callback in drivers/media/platform/qcom/camss/camss-csid-1190.c
(including the unused lane_cnt local variable in
__csid_configure_rdi_stream()) is identical to
drivers/media/platform/qcom/camss/camss-csid-1080.c.
Similarly, drivers/media/platform/qcom/camss/camss-vfe-1190.c duplicates all
functions and callbacks of drivers/media/platform/qcom/camss/camss-vfe-1080.c
verbatim, differing only in the BUS_REG_BASE and write master register offset
macros.
Could csid_res_hawi reuse csid_ops_1080 directly (just as hawi_resources
reuses csiphy_res_kaanapali and tpg_res_x1e80100), and could the common VFE
1080/1190 helpers be shared?
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index df4b4cf30711b..0a67d4f746eeb 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -4359,6 +4359,218 @@ static const struct resources_icc icc_res_sa8775p[] = {
> },
> };
>
> +static const struct camss_subdev_resources vfe_res_hawi[] = {
> + /* VFE0 - TFE Full */
> + {
> + .clock = { "vfe0_fast_ahb", "vfe0", "cpas_vfe0",
> + "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
> + "cpas_mnoc_hf", "cpas_mnoc_sf" },
> + .clock_rate = { { 0 },
> + { 238200000, 397000000, 440000000, 480000000,
> + 630000000, 750000000, 833000000 },
> + { 0 },
> + { 171428571, 240000000, 300000000, 400000000,
> + 480000000, 600000000 },
[Severity: Medium]
Are the camnoc_rt_axi clock rates in vfe_res_hawi (for VFE0 through VFE4)
matching the Hawi CAMCC clock driver?
In drivers/clk/qcom/camcc-hawi.c, ftbl_cam_cc_camnoc_rt_axi_clk_src for
qcom,hawi-camcc defines a maximum rate of 480 MHz:
drivers/clk/qcom/camcc-hawi.c:
static const struct freq_tbl ftbl_cam_cc_camnoc_rt_axi_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(120000000, P_CAM_CC_PLL6_OUT_EVEN, 4, 0, 0),
F(160000000, P_CAM_CC_PLL6_OUT_EVEN, 3, 0, 0),
F(240000000, P_CAM_CC_PLL6_OUT_EVEN, 2, 0, 0),
F(320000000, P_CAM_CC_PLL6_OUT_EVEN, 1.5, 0, 0),
F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
{ }
};
(Whereas the 200/240/300/400/480/600 MHz table
ftbl_cam_cc_camnoc_rt_axi_clk_src_maili is only used for qcom,maili-camcc, and
171428571 Hz is in neither table.)
When vfe_get() -> vfe_set_clock_rates() runs with min_rate between 480 MHz and
600 MHz, it selects 600000000 Hz from vfe_res_hawi instead of rejecting the
rate, and clk_round_rate() on Hawi clamps it down to 480000000 Hz. When the
second pipeline entity calls vfe_get() -> vfe_check_clock_rates(), won't
clk_get_rate(clock->clk) < min_rate cause vfe_check_clock_rates() to fail with
-EBUSY?
[ ... ]
> @@ -6078,6 +6290,22 @@ static const struct camss_resources sm8650_resources = {
> .vfe_num = ARRAY_SIZE(vfe_res_sm8650),
> };
>
> +static const struct camss_resources hawi_resources = {
> + .version = CAMSS_HAWI,
> + .pd_name = "top",
> + .pm_clks = { "cpas_fast_ahb", "cpas_ahb", "gcc_axi_hf" },
> + .csiphy_res = csiphy_res_kaanapali,
[Severity: High]
As reported by Sashiko on v2 [2], can reusing csiphy_res_kaanapali in
hawi_resources lead to a NULL pointer dereference in
msm_csiphy_subdev_init_legacy() during probe?
The entries in csiphy_res_kaanapali do not set .csiphy.hw_ops, leaving hw_ops
as NULL. During camss_probe() -> camss_init_subdevices(),
camss_detect_legacy_phy() defaults camss->legacy_phy to true:
drivers/media/platform/qcom/camss/camss.c:camss_detect_legacy_phy() {
camss->legacy_phy = true;
/* Find first remote-endpoint and determine if its a PHY */
for_each_endpoint_of_node(camss->dev->of_node, ep) {
...
}
If the qcom,hawi-camss node has no endpoints in its ports node (for example,
when enabling CAMSS to use its internal Test Pattern Generators without
external sensors or PHYs), camss->legacy_phy remains true.
camss_init_subdevices() then calls msm_csiphy_subdev_init_legacy(), which
unconditionally dereferences csiphy->res->hw_ops:
drivers/media/platform/qcom/camss/camss-csiphy.c:msm_csiphy_subdev_init_legacy() {
...
ret = csiphy->res->hw_ops->init(csiphy);
...
}
[1] https://lore.kernel.org/r/20261013-hawi-maili-camss-v2-7-fc93222da89c@oss.qualcomm.com
[2] https://lore.kernel.org/r/20261013-hawi-maili-camss-v2-6-fc93222da89c@oss.qualcomm.com
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261030-hawi-maili-camss-v3-0-9742bca8cef2@oss.qualcomm.com?part=5
prev parent reply other threads:[~2026-10-30 13:07 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 12:43 [PATCH v3 0/5] Add CAMSS support for Qualcomm Hawi and Maili Nihal Kumar Gupta
2026-10-30 12:43 ` [PATCH v3 1/5] dt-bindings: i2c: qcom,i2c-cci: Add Hawi compatible Nihal Kumar Gupta
2026-10-30 12:51 ` sashiko-bot
2026-10-30 12:43 ` [PATCH v3 2/5] dt-bindings: phy: qcom,x1e80100-csi2-phy: Add Hawi and Maili compatibles Nihal Kumar Gupta
2026-10-30 12:43 ` [PATCH v3 3/5] dt-bindings: media: Add CAMSS device for Hawi and Maili Nihal Kumar Gupta
2026-10-30 12:55 ` sashiko-bot
2026-10-30 12:43 ` [PATCH v3 4/5] phy: qcom-mipi-csi2: Add Hawi support Nihal Kumar Gupta
2026-10-30 12:43 ` [PATCH v3 5/5] media: qcom: camss: Add support for Hawi Nihal Kumar Gupta
2026-10-30 13:05 ` Vladimir Zapolskiy
2026-10-30 13:07 ` sashiko-bot [this message]
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=sashiko-outbox-191048@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=media-ci@linuxtv.org \
--cc=neil.armstrong@linaro.org \
--cc=nihal.gupta@oss.qualcomm.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox