* Re: [PATCH v5 1/3] dt-bindings: media: mediatek-jpeg-decoder: add MT8189 compatible string
From: Krzysztof Kozlowski @ 2026-03-31 6:58 UTC (permalink / raw)
To: Jianhua Lin
Cc: nicolas, mchehab, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, devicetree, linux-kernel, linux-media,
linux-arm-kernel, linux-mediatek,
Project_Global_Chrome_Upstream_Group, sirius.wang, vince-wl.liu,
jh.hsu
In-Reply-To: <20260331005458.24010-2-jianhua.lin@mediatek.com>
On Tue, Mar 31, 2026 at 08:54:56AM +0800, Jianhua Lin wrote:
> Add the compatible string for the JPEG decoder block found in the
> MediaTek MT8189 SoC.
>
> Compared to previous generation ICs, the MT8189 JPEG decoder requires
> 34-bit IOVA address space support and only needs a single clock
> ("jpgdec") instead of two. Therefore, it is added as a standalone
> compatible string without falling back to older SoCs.
>
> Update the binding schema to include the new compatible string and add
> an `allOf` block with conditional checks. This enforces the single clock
> requirement for MT8189 while preserving the two-clock requirement
> ("jpgdec-smi", "jpgdec") for older SoCs.
>
> Suggested-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Jianhua Lin <jianhua.lin@mediatek.com>
> ---
> .../bindings/media/mediatek-jpeg-decoder.yaml | 44 +++++++++++++++----
> 1 file changed, 36 insertions(+), 8 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> index a4aacd3eb189..601fe05b73e7 100644
> --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> @@ -15,10 +15,10 @@ description: |-
> properties:
> compatible:
> oneOf:
> - - items:
> - - enum:
> - - mediatek,mt8173-jpgdec
> - - mediatek,mt2701-jpgdec
> + - enum:
> + - mediatek,mt2701-jpgdec
> + - mediatek,mt8173-jpgdec
> + - mediatek,mt8189-jpgdec
> - items:
> - enum:
> - mediatek,mt7623-jpgdec
> @@ -32,13 +32,22 @@ properties:
> maxItems: 1
>
> clocks:
> + minItems: 1
> maxItems: 2
> - minItems: 2
>
> clock-names:
> - items:
> - - const: jpgdec-smi
> - - const: jpgdec
> + minItems: 1
> + maxItems: 2
Why jpgdec-smi alone is now valid? Drop these two.
> + oneOf:
> + - items:
> + - const: jpgdec
> + - items:
> + - const: jpgdec-smi
> + - const: jpgdec
> +
> + mediatek,larb:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: a phandle to the smi_larb node.
Best regards,
Krzysztof
^ permalink raw reply
* RE: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs and enable-dma properties
From: Ryan Chen @ 2026-03-31 6:58 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: jk@codeconstruct.com.au, andriy.shevchenko@linux.intel.com,
Andi Shyti, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley, Andrew Jeffery, Benjamin Herrenschmidt,
Philipp Zabel, linux-i2c@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org,
openbmc@lists.ozlabs.org
In-Reply-To: <20260331-fanatic-certain-bustard-fb13bc@quoll>
> Subject: Re: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs
> and enable-dma properties
>
> On Mon, Mar 30, 2026 at 04:21:47PM +0800, Ryan Chen wrote:
> > Add aspeed,enable-dma boolean property to indicate that DMA is
> > available for transfers on this I2C bus.
> >
> > Also add the aspeed,global-regs phandle to reference the AST2600
> > global registers syscon node, containing the SoC-common I2C register
> > set.
> >
> > These properties apply only to the AST2600 binding. Legacy DTs remain
> > unchanged.
> >
> > Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
> > ---
> > Changes in v28:
> > - update commit message correspond with aspeed,enable-dma.
> > - remove aspeed,transfer-mode and add aspeed,enable-dma property and
> > description.
> > - Fix aspeed,enable-dma description to reflect hardware capability rather
> > than software behavior
> > Changes in v27:
> > - change aspeed,transfer-mode to aspeed,enable-dma.
> > ---
> > .../devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml | 12
> ++++++++++++
> > 1 file changed, 12 insertions(+)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
> > b/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
> > index de2c359037da..67b23d1a4cec 100644
> > --- a/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
> > +++ b/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
> > @@ -37,6 +37,16 @@ properties:
> > resets:
> > maxItems: 1
> >
> > + aspeed,enable-dma:
> > + type: boolean
> > + description: Indicates this I2C controller instance has DMA capability.
>
> Compatible implies that "I2C controller instance has DMA capability", no?
>
> How two same devices, with exactly the same or compatible programming
> model can have difference in the programming model for DMA (one lacks it)?
>
> Best regards,
> Krzysztof
Thanks your review.
All AST2600 I2C controller instances have DMA hardware.
I will remove the aspeed,enable-dma property and instead expose sysfs
attribute in driver to allow users to enable dma/buffer/byte.
^ permalink raw reply
* Re: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs and enable-dma properties
From: Jeremy Kerr @ 2026-03-31 7:00 UTC (permalink / raw)
To: Ryan Chen, Krzysztof Kozlowski
Cc: andriy.shevchenko@linux.intel.com, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Philipp Zabel, linux-i2c@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org,
openbmc@lists.ozlabs.org
In-Reply-To: <TY2PPF5CB9A1BE6F267C60EEC34B6A75400F253A@TY2PPF5CB9A1BE6.apcprd06.prod.outlook.com>
Hi Ryan,
> All AST2600 I2C controller instances have DMA hardware.
> I will remove the aspeed,enable-dma property and instead expose sysfs
> attribute in driver to allow users to enable dma/buffer/byte.
Sounds reasonable, but before you do so, how are you planning to manage
the allocation of DMA channels across multiple i2c peripherals?
Cheers,
Jeremy
^ permalink raw reply
* Re: [PATCH v4 1/9] dt-bindings: mfd: mt6397: Add MT6392 PMIC
From: Krzysztof Kozlowski @ 2026-03-31 7:01 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Fabien Parent, Val Packett, Dmitry Torokhov,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sen Chu,
Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
AngeloGioacchino Del Regno, Linus Walleij, Liam Girdwood,
Mark Brown, Louis-Alexis Eyraud, Gary Bisson, Julien Massot,
Chen Zhong, linux-input, devicetree, linux-kernel, linux-pm,
linux-arm-kernel, linux-gpio
In-Reply-To: <20260330083429.359819-2-l.scorcia@gmail.com>
On Mon, Mar 30, 2026 at 09:29:35AM +0100, Luca Leonardo Scorcia wrote:
> - items:
> - enum:
> - mediatek,mt6366-rtc
> @@ -99,9 +107,6 @@ properties:
> - mediatek,mt6366-regulator
> - const: mediatek,mt6358-regulator
>
> - required:
> - - compatible
Not really, this affects existing ABI and might make the child schema
being applied. Basically regulators node can be anything now.
This is definitely not a binding we want. The syntax for parent schema
when listing only compatibles is requiring this compatible. You cannot
have here whatever empty node.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v4 3/9] regulator: dt-bindings: Add MediaTek MT6392 PMIC
From: Krzysztof Kozlowski @ 2026-03-31 7:04 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sen Chu, Sean Wang, Macpaul Lin, Lee Jones,
Matthias Brugger, AngeloGioacchino Del Regno, Linus Walleij,
Liam Girdwood, Mark Brown, Julien Massot, Gary Bisson,
Louis-Alexis Eyraud, Val Packett, Fabien Parent, Chen Zhong,
linux-input, devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-gpio
In-Reply-To: <20260330083429.359819-4-l.scorcia@gmail.com>
On Mon, Mar 30, 2026 at 09:29:37AM +0100, Luca Leonardo Scorcia wrote:
> Add bindings for the regulators found in the MediaTek MT6392 PMIC,
> usually found in board designs using the MediaTek MT8516/MT8167 SoCs.
>
> Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
> ---
> .../regulator/mediatek,mt6392-regulator.yaml | 74 +++++++++++++++++++
> .../regulator/mediatek,mt6392-regulator.h | 24 ++++++
> 2 files changed, 98 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
> create mode 100644 include/dt-bindings/regulator/mediatek,mt6392-regulator.h
>
> diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
> new file mode 100644
> index 000000000000..24fbaef0e717
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
> @@ -0,0 +1,74 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/mediatek,mt6392-regulator.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT6392 regulator
> +
> +description:
> + Regulator node of the PMIC. This node should under the PMIC's device node.
> + MT6392 is a power management system chip containing three buck converters and
> + 23 LDOs. All voltage regulators provided by the PMIC are described as
> + sub-nodes of this node.
> +
So that's a dead code / schema.
Try yourself if it works.
Your parent schema must reference this one for the regulators node.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v4] ASoC: dt-bindings: imx-card: Complete the full list of supported DAI formats
From: Krzysztof Kozlowski @ 2026-03-31 7:05 UTC (permalink / raw)
To: Chancel Liu
Cc: lgirdwood, broonie, robh, krzk+dt, conor+dt, Frank.Li,
shengjiu.wang, s.hauer, kernel, festevam, linux-sound, devicetree,
imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20260331012450.1298115-1-chancel.liu@nxp.com>
On Tue, Mar 31, 2026 at 10:24:50AM +0900, Chancel Liu wrote:
> Currently this binding only lists i2s and dsp_b formats that are used
> by existing sound cards. However, DT bindings should describe the full
> hardware capabilities rather than only the formats of current usage.
>
> The SAI audio controller of i.MX audio sound card supports multiple DAI
> formats, including:
> - i2s
> - left_j
> - right_j
> - dsp_a
> - dsp_b
> - pdm
> - msb
> - lsb
>
> Complete the full list of formats supported by i.MX audio sound card to
> ensure the binding correctly describes hardware.
>
> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
> ---
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 1/2] ti,j721e-system-controller.yaml: Allow audio-refclk as clock-controller child
From: Krzysztof Kozlowski @ 2026-03-31 7:09 UTC (permalink / raw)
To: Moteen Shah
Cc: krzk+dt, robh, conor+dt, nm, vigneshr, kristo, devicetree,
linux-arm-kernel, linux-kernel, u-kumar1, gehariprasath,
y-abhilashchandra
In-Reply-To: <20260330094459.128648-2-m-shah@ti.com>
On Mon, Mar 30, 2026 at 03:14:58PM +0530, Moteen Shah wrote:
> The ti,j721e-system-controller binding currently only allows
> clock-controller@ child nodes to reference the ti,am654-ehrpwm-tbclk
> schema. However, the system controller on J721S2 also contains audio
J721S2 or AM62?
> reference clock controllers (ti,am62-audio-refclk) that use the same
> clock-controller@XXXX naming pattern.
>
> Hence, extend the clock-controller pattern to accept either ehrpwm-tbclk
> or audio-refclk schemas using a oneOf constraint.
>
> Signed-off-by: Moteen Shah <m-shah@ti.com>
> ---
> .../bindings/soc/ti/ti,j721e-system-controller.yaml | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/soc/ti/ti,j721e-system-controller.yaml b/Documentation/devicetree/bindings/soc/ti/ti,j721e-system-controller.yaml
> index f3bd0be3b279..d5d84a8f1257 100644
> --- a/Documentation/devicetree/bindings/soc/ti/ti,j721e-system-controller.yaml
> +++ b/Documentation/devicetree/bindings/soc/ti/ti,j721e-system-controller.yaml
> @@ -53,9 +53,11 @@ patternProperties:
>
> "^clock-controller@[0-9a-f]+$":
> type: object
> - $ref: /schemas/clock/ti,am654-ehrpwm-tbclk.yaml#
> + oneOf:
> + - $ref: /schemas/clock/ti,am654-ehrpwm-tbclk.yaml#
> + - $ref: /schemas/clock/ti,am62-audio-refclk.yaml#
Alphanumerical order.
There is no ti,am62 in the top level compatibles, so why am62 is here?
Top level has j721s2 but this ti,am62-audio-refclk.yaml only am62.
Best regards,
Krzysztof
^ permalink raw reply
* RE: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs and enable-dma properties
From: Ryan Chen @ 2026-03-31 7:09 UTC (permalink / raw)
To: Jeremy Kerr, Krzysztof Kozlowski
Cc: andriy.shevchenko@linux.intel.com, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Philipp Zabel, linux-i2c@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org,
openbmc@lists.ozlabs.org
In-Reply-To: <09cbc12bea5707f794e139ea1bfafac82c2d2c12.camel@codeconstruct.com.au>
> Subject: Re: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs
> and enable-dma properties
>
> Hi Ryan,
>
> > All AST2600 I2C controller instances have DMA hardware.
> > I will remove the aspeed,enable-dma property and instead expose sysfs
> > attribute in driver to allow users to enable dma/buffer/byte.
>
> Sounds reasonable, but before you do so, how are you planning to manage the
> allocation of DMA channels across multiple i2c peripherals?
>
The AST2600 I2C hardware has only one can use DMA at a time.
To avoid the complexity of managing DMA channel contention,
I plan to use buffer mode by default for all controllers, which still provides
better performance than byte mode without requiring DMA channel allocation.
^ permalink raw reply
* Re: [PATCH 0/2] Add PWM support Amlogic S7 S7D S6
From: Xianwei Zhao @ 2026-03-31 7:10 UTC (permalink / raw)
To: Martin Blumenstingl
Cc: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Heiner Kallweit, Neil Armstrong, Kevin Hilman,
Jerome Brunet, linux-pwm, devicetree, linux-kernel,
linux-arm-kernel, linux-amlogic, Junyi Zhao
In-Reply-To: <CAFBinCD1GPP82MEBDHg3BwCJg6JY5k2HksEt+kCB=YjnYTO7Tw@mail.gmail.com>
Hi Martin,
I confirmed with Junyi Zhao that the current implementation counts
from zero, so this submission is correct.
We agree this should be fixed and will address it in a follow-up patch.
Thanks for pointing it out.
On 2026/3/31 05:54, Martin Blumenstingl wrote:
> Hi Xianwei Zhao,
>
> thanks for your contribution!
>
> On Thu, Mar 26, 2026 at 7:35 AM Xianwei Zhao via B4 Relay
> <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote:
>> Add bindings and driver support Amlogic S7/S7D/S6 SoCs.
> There is an old report that got lost, stating that the current
> pwm-meson driver has an off-by-one error with the hi and lo fields:
> [0]
> Since you are working on bringing up a new platform: is this something
> you can verify in your lab?
> To be clear: I'm not expecting you to work on this ad-hoc or bring a
> patch into this series. However, it would be great if you could verify
> if the findings from [0] are correct and send an updated patch in
> future.
>
> Thank you and best regards
> Martin
^ permalink raw reply
* Re: [PATCH v2 13/30] KVM: arm64: Clean up control flow in kvm_s2_fault_map()
From: Anshuman Khandual @ 2026-03-31 7:11 UTC (permalink / raw)
To: Marc Zyngier, kvmarm, linux-arm-kernel, kvm
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Fuad Tabba, Will Deacon, Quentin Perret
In-Reply-To: <20260327113618.4051534-14-maz@kernel.org>
On 27/03/26 5:06 PM, Marc Zyngier wrote:
> From: Fuad Tabba <tabba@google.com>
>
> Clean up the KVM MMU lock retry loop by pre-assigning the error code.
> Add clear braces to the THP adjustment integration for readability, and
> safely unnest the transparent hugepage logic branches.
>
> Signed-off-by: Fuad Tabba <tabba@google.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
> ---
> arch/arm64/kvm/mmu.c | 20 +++++++++++---------
> 1 file changed, 11 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index ee2a548999b1b..c6cd6ce5254be 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1897,10 +1897,9 @@ static int kvm_s2_fault_map(struct kvm_s2_fault *fault, void *memcache)
>
> kvm_fault_lock(kvm);
> pgt = fault->vcpu->arch.hw_mmu->pgt;
> - if (mmu_invalidate_retry(kvm, fault->mmu_seq)) {
> - ret = -EAGAIN;
> + ret = -EAGAIN;
> + if (mmu_invalidate_retry(kvm, fault->mmu_seq))
> goto out_unlock;
> - }
>
> /*
> * If we are not forced to use page mapping, check if we are
> @@ -1908,16 +1907,17 @@ static int kvm_s2_fault_map(struct kvm_s2_fault *fault, void *memcache)
> */
> if (fault->vma_pagesize == PAGE_SIZE &&
> !(fault->force_pte || fault->s2_force_noncacheable)) {
> - if (fault->fault_is_perm && fault->fault_granule > PAGE_SIZE)
> + if (fault->fault_is_perm && fault->fault_granule > PAGE_SIZE) {
> fault->vma_pagesize = fault->fault_granule;
> - else
> + } else {
> fault->vma_pagesize = transparent_hugepage_adjust(kvm, fault->memslot,
> fault->hva, &fault->pfn,
> &fault->fault_ipa);
>
> - if (fault->vma_pagesize < 0) {
> - ret = fault->vma_pagesize;
> - goto out_unlock;
> + if (fault->vma_pagesize < 0) {
> + ret = fault->vma_pagesize;
> + goto out_unlock;
> + }
> }
> }
>
> @@ -1951,7 +1951,9 @@ static int kvm_s2_fault_map(struct kvm_s2_fault *fault, void *memcache)
> if (fault->writable && !ret)
> mark_page_dirty_in_slot(kvm, fault->memslot, fault->gfn);
>
> - return ret != -EAGAIN ? ret : 0;
> + if (ret != -EAGAIN)
> + return ret;
> + return 0;
> }
>
> static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
^ permalink raw reply
* Re: [PATCH v3 2/2] arm64: dts: ti: Add audio overlay for k3-j721s2-evm
From: Krzysztof Kozlowski @ 2026-03-31 7:11 UTC (permalink / raw)
To: Moteen Shah
Cc: krzk+dt, robh, conor+dt, nm, vigneshr, kristo, devicetree,
linux-arm-kernel, linux-kernel, u-kumar1, gehariprasath,
y-abhilashchandra
In-Reply-To: <20260330094459.128648-3-m-shah@ti.com>
On Mon, Mar 30, 2026 at 03:14:59PM +0530, Moteen Shah wrote:
> + p10-hog {
> + /* P10 - MCASP/TRACE_MUX_S1 */
> + gpio-hog;
> + gpios = <10 GPIO_ACTIVE_HIGH>;
> + output-high;
> + line-name = "MCASP/TRACE_MUX_S1";
> + };
> +};
> +
> +&mux0 {
> + idle-state = <0>;
> +};
> +
> +&mux1 {
> + idle-state = <0>;
> +};
> +
> +&scm_conf {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + audio_refclk1: clock-controller@42e4 {
> + compatible = "ti,am62-audio-refclk";
there is no am62 compatible or DTSI include in the parent SoC file, so
am62n seems to be completely different device than j721s2.
Why does am62b appear here in this context?
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v5 1/3] crash_dump/dm-crypt: Don't print in arch-specific code
From: Baoquan He @ 2026-03-31 7:12 UTC (permalink / raw)
To: Coiby Xu
Cc: kexec, linux-arm-kernel, linuxppc-dev, devicetree, Will Deacon,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT), H. Peter Anvin,
Andrew Morton, Vivek Goyal, Dave Young,
open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)
In-Reply-To: <20260225060347.718905-2-coxu@redhat.com>
On 02/25/26 at 02:03pm, Coiby Xu wrote:
> When the vmcore dumping target is not a LUKS-encrypted target, it's
> expected that there is no dm-crypt key thus no need to return -ENOENT.
> Also print more logs in crash_load_dm_crypt_keys. The benefit is
> arch-specific code can be more succinct.
>
> Suggested-by: Will Deacon <will@kernel.org>
> Signed-off-by: Coiby Xu <coxu@redhat.com>
> ---
> arch/x86/kernel/kexec-bzimage64.c | 6 +-----
> kernel/crash_dump_dm_crypt.c | 7 +++++--
> 2 files changed, 6 insertions(+), 7 deletions(-)
Acked-by: Baoquan He <bhe@redhat.com>
>
> diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
> index 5630c7dca1f3..7e980ea49d8d 100644
> --- a/arch/x86/kernel/kexec-bzimage64.c
> +++ b/arch/x86/kernel/kexec-bzimage64.c
> @@ -525,12 +525,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> if (ret)
> return ERR_PTR(ret);
> ret = crash_load_dm_crypt_keys(image);
> - if (ret == -ENOENT) {
> - kexec_dprintk("No dm crypt key to load\n");
> - } else if (ret) {
> - pr_err("Failed to load dm crypt keys\n");
> + if (ret)
> return ERR_PTR(ret);
> - }
> if (image->dm_crypt_keys_addr &&
> cmdline_len + MAX_ELFCOREHDR_STR_LEN + MAX_DMCRYPTKEYS_STR_LEN >
> header->cmdline_size) {
> diff --git a/kernel/crash_dump_dm_crypt.c b/kernel/crash_dump_dm_crypt.c
> index 1f4067fbdb94..2f7b42b09673 100644
> --- a/kernel/crash_dump_dm_crypt.c
> +++ b/kernel/crash_dump_dm_crypt.c
> @@ -414,14 +414,16 @@ int crash_load_dm_crypt_keys(struct kimage *image)
>
> if (key_count <= 0) {
> kexec_dprintk("No dm-crypt keys\n");
> - return -ENOENT;
> + return 0;
> }
>
> if (!is_dm_key_reused) {
> image->dm_crypt_keys_addr = 0;
> r = build_keys_header();
> - if (r)
> + if (r) {
> + pr_err("Failed to build dm-crypt keys header, ret=%d\n", r);
> return r;
> + }
> }
>
> kbuf.buffer = keys_header;
> @@ -432,6 +434,7 @@ int crash_load_dm_crypt_keys(struct kimage *image)
> kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> r = kexec_add_buffer(&kbuf);
> if (r) {
> + pr_err("Failed to call kexec_add_buffer, ret=%d\n", r);
> kvfree((void *)kbuf.buffer);
> return r;
> }
> --
> 2.53.0
>
^ permalink raw reply
* Re: [PATCH v5 2/3] crash: Align the declaration of crash_load_dm_crypt_keys with CONFIG_CRASH_DM_CRYPT
From: Baoquan He @ 2026-03-31 7:12 UTC (permalink / raw)
To: Coiby Xu
Cc: kexec, linux-arm-kernel, linuxppc-dev, devicetree,
kernel test robot, Andrew Morton, Vivek Goyal, Dave Young,
open list
In-Reply-To: <20260225060347.718905-3-coxu@redhat.com>
On 02/25/26 at 02:03pm, Coiby Xu wrote:
> This will prevent a compiling failure when CONFIG_CRASH_DUMP is enabled
> but CONFIG_CRASH_DM_CRYPT is disabled,
>
> arch/powerpc/kexec/elf_64.c: In function 'elf64_load':
> >> arch/powerpc/kexec/elf_64.c:82:23: error: implicit declaration of function 'crash_load_dm_crypt_keys' [-Werror=implicit-function-declaration]
> 82 | ret = crash_load_dm_crypt_keys(image);
> | ^~~~~~~~~~~~~~~~~~~~~~~~
> cc1: some warnings being treated as errors
>
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202602120648.RgQALnnI-lkp@intel.com/
> Signed-off-by: Coiby Xu <coxu@redhat.com>
> ---
> include/linux/crash_core.h | 14 +++++++-------
> 1 file changed, 7 insertions(+), 7 deletions(-)
Acked-by: Baoquan He <bhe@redhat.com>
>
> diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
> index d35726d6a415..c1dee3f971a9 100644
> --- a/include/linux/crash_core.h
> +++ b/include/linux/crash_core.h
> @@ -34,13 +34,6 @@ static inline void arch_kexec_protect_crashkres(void) { }
> static inline void arch_kexec_unprotect_crashkres(void) { }
> #endif
>
> -#ifdef CONFIG_CRASH_DM_CRYPT
> -int crash_load_dm_crypt_keys(struct kimage *image);
> -ssize_t dm_crypt_keys_read(char *buf, size_t count, u64 *ppos);
> -#else
> -static inline int crash_load_dm_crypt_keys(struct kimage *image) {return 0; }
> -#endif
> -
> #ifndef arch_crash_handle_hotplug_event
> static inline void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) { }
> #endif
> @@ -96,4 +89,11 @@ static inline void crash_save_cpu(struct pt_regs *regs, int cpu) {};
> static inline int kimage_crash_copy_vmcoreinfo(struct kimage *image) { return 0; };
> #endif /* CONFIG_CRASH_DUMP*/
>
> +#ifdef CONFIG_CRASH_DM_CRYPT
> +int crash_load_dm_crypt_keys(struct kimage *image);
> +ssize_t dm_crypt_keys_read(char *buf, size_t count, u64 *ppos);
> +#else
> +static inline int crash_load_dm_crypt_keys(struct kimage *image) {return 0; }
> +#endif
> +
> #endif /* LINUX_CRASH_CORE_H */
> --
> 2.53.0
>
^ permalink raw reply
* Re: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs and enable-dma properties
From: Jeremy Kerr @ 2026-03-31 7:17 UTC (permalink / raw)
To: Ryan Chen, Krzysztof Kozlowski
Cc: andriy.shevchenko@linux.intel.com, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Philipp Zabel, linux-i2c@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org,
openbmc@lists.ozlabs.org
In-Reply-To: <TY2PPF5CB9A1BE6EA5BABE55EB8A7003D22F253A@TY2PPF5CB9A1BE6.apcprd06.prod.outlook.com>
Hi Ryan,
> > Sounds reasonable, but before you do so, how are you planning to manage the
> > allocation of DMA channels across multiple i2c peripherals?
> >
> The AST2600 I2C hardware has only one can use DMA at a time.
> To avoid the complexity of managing DMA channel contention,
> I plan to use buffer mode by default for all controllers, which still provides
> better performance than byte mode without requiring DMA channel allocation.
OK, but your wording there ("by default") implies that DMA is still
selectable for one controller peripheral. In which case: you still have
the problem of managing DMA channel contention, but now it's at runtime
instead.
So my question still stands: how are you planning to enforce that DMA is
only enabled for one controller?
Or are you planning to disable I2C DMA entirely on AST2600?
Cheers,
Jeremy
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: power: reset: cortina,gemini-power-controller: convert to DT schema
From: Krzysztof Kozlowski @ 2026-03-31 7:22 UTC (permalink / raw)
To: Khushal Chitturi
Cc: sre, robh, krzk+dt, conor+dt, ulli.kroll, linusw, daniel.baluta,
simona.toaca, d-gole, m-chawdhry, linux-pm, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260330110135.10316-2-khushalchitturi@gmail.com>
On Mon, Mar 30, 2026 at 04:31:34PM +0530, Khushal Chitturi wrote:
> Convert the Cortina Systems Gemini Poweroff Controller bindings to
> DT schema.
>
> Signed-off-by: Khushal Chitturi <khushalchitturi@gmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 2/2] ARM: dts: gemini: Rename power controller node to poweroff
From: Krzysztof Kozlowski @ 2026-03-31 7:22 UTC (permalink / raw)
To: Khushal Chitturi
Cc: sre, robh, krzk+dt, conor+dt, ulli.kroll, linusw, daniel.baluta,
simona.toaca, d-gole, m-chawdhry, linux-pm, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260330110135.10316-3-khushalchitturi@gmail.com>
On Mon, Mar 30, 2026 at 04:31:35PM +0530, Khushal Chitturi wrote:
> Update the node name for the Cortina Gemini power controller from
> power-controller to poweroff since node "power controller" is
> reserved for power domain controller.
>
> Signed-off-by: Khushal Chitturi <khushalchitturi@gmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* [RFC PATCH 0/7] media: amphion: Add DMA memory tracking support
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
From: Ming Qian <ming.qian@oss.nxp.com>
This series adds DMA memory tracking support to the Amphion VPU driver,
allowing userspace to monitor memory consumption of codec instances.
To implement this feature in a reusable way, a new V4L2 memory tracking
infrastructure (v4l2-memtrack) is introduced, which can be adopted by
other V4L2 drivers in the future.
Background
==========
The Amphion VPU codec driver allocates various DMA buffers internally:
- Firmware boot region and RPC buffers
- Stream ring buffers
- Codec-specific buffers (MBI, DCP, reference frames)
- Encoder/decoder working buffers
These allocations are not visible to userspace, making it difficult to
debug memory issues or monitor resource usage in multi-instance scenarios
(e.g., transcoding servers with multiple simultaneous streams).
Solution
========
This series introduces:
1. V4L2_CID_MEMORY_USAGE control
- New read-only control reporting memory usage in bytes
- Standard V4L2 interface, queryable via VIDIOC_G_CTRL
2. v4l2-memtrack infrastructure
- Hierarchical memory tracking (device -> instance -> queue)
- debugfs interface at /sys/kernel/debug/v4l2-memtrack/
- Reusable by other V4L2 drivers
3. videobuf2 integration
- Automatic tracking of vb2 buffer allocations
4. Amphion VPU integration
- Tracks all internal DMA allocations
- Organized as: device -> instance -> buffers
Ming Qian (7):
media: v4l2-ctrls: Add V4L2_CID_MEMORY_USAGE control
docs: media: v4l2-ctrls: Add V4L2_CID_MEMORY_USAGE control
media: v4l2-memtrack: Add V4L2 memory tracking infrastructure
docs: media: v4l2-memtrack: Add driver API documentation
MAINTAINERS: Add entry for V4L2 memory usage tracker
media: videobuf2: Add memory tracking support
media: amphion: Add V4L2 memory tracking support
Documentation/driver-api/media/v4l2-core.rst | 1 +
.../driver-api/media/v4l2-memtrack.rst | 140 +++
.../userspace-api/media/v4l/control.rst | 22 +-
MAINTAINERS | 8 +
drivers/media/common/Kconfig | 1 +
drivers/media/common/Makefile | 2 +-
drivers/media/common/v4l2-memtrack/Kconfig | 19 +
drivers/media/common/v4l2-memtrack/Makefile | 3 +
.../common/v4l2-memtrack/v4l2-memtrack.c | 825 ++++++++++++++++++
.../media/common/videobuf2/videobuf2-core.c | 13 +
drivers/media/platform/amphion/Kconfig | 1 +
drivers/media/platform/amphion/vdec.c | 9 +
drivers/media/platform/amphion/venc.c | 9 +
drivers/media/platform/amphion/vpu.h | 7 +
drivers/media/platform/amphion/vpu_core.c | 6 +
drivers/media/platform/amphion/vpu_dbg.c | 5 +
drivers/media/platform/amphion/vpu_drv.c | 2 +
drivers/media/platform/amphion/vpu_v4l2.c | 35 +-
drivers/media/v4l2-core/v4l2-ctrls-defs.c | 8 +
include/media/v4l2-memtrack.h | 220 +++++
include/media/videobuf2-core.h | 4 +
include/uapi/linux/v4l2-controls.h | 4 +-
22 files changed, 1340 insertions(+), 4 deletions(-)
create mode 100644 Documentation/driver-api/media/v4l2-memtrack.rst
create mode 100644 drivers/media/common/v4l2-memtrack/Kconfig
create mode 100644 drivers/media/common/v4l2-memtrack/Makefile
create mode 100644 drivers/media/common/v4l2-memtrack/v4l2-memtrack.c
create mode 100644 include/media/v4l2-memtrack.h
base-commit: 4fbeef21f5387234111b5d52924e77757626faa5
prerequisite-patch-id: 0000000000000000000000000000000000000000
--
2.53.0
^ permalink raw reply
* [RFC PATCH 1/7] media: v4l2-ctrls: Add V4L2_CID_MEMORY_USAGE control
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
In-Reply-To: <20260331072347.253-1-ming.qian@oss.nxp.com>
From: Ming Qian <ming.qian@oss.nxp.com>
Add a new read-only control V4L2_CID_MEMORY_USAGE that allows
applications to query the total amount of memory currently used
by a device instance.
This control reports the memory consumption in bytes, including
internal buffers, intermediate processing data, and other
driver-managed allocations. Applications can use this information
for debugging, resource monitoring, or making informed decisions
about buffer allocation strategies.
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
---
drivers/media/v4l2-core/v4l2-ctrls-defs.c | 8 ++++++++
include/uapi/linux/v4l2-controls.h | 4 +++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index 551426c4cd01..053db78ff661 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -831,6 +831,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component";
case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr";
case V4L2_CID_COLORFX_RGB: return "Color Effects, RGB";
+ case V4L2_CID_MEMORY_USAGE: return "Memory Usage";
/*
* Codec controls
@@ -1476,6 +1477,13 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
*min = 0;
*max = 0xffff;
break;
+ case V4L2_CID_MEMORY_USAGE:
+ *type = V4L2_CTRL_TYPE_INTEGER64;
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ *min = 0;
+ *max = S64_MAX;
+ *step = 1;
+ break;
case V4L2_CID_FLASH_FAULT:
case V4L2_CID_JPEG_ACTIVE_MARKER:
case V4L2_CID_3A_LOCK:
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 68dd0c4e47b2..02c6f960d38e 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -110,8 +110,10 @@ enum v4l2_colorfx {
#define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42)
#define V4L2_CID_COLORFX_RGB (V4L2_CID_BASE+43)
+#define V4L2_CID_MEMORY_USAGE (V4L2_CID_BASE+44)
+
/* last CID + 1 */
-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+44)
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+45)
/* USER-class private control IDs */
--
2.53.0
^ permalink raw reply related
* [RFC PATCH 2/7] docs: media: v4l2-ctrls: Add V4L2_CID_MEMORY_USAGE control
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
In-Reply-To: <20260331072347.253-1-ming.qian@oss.nxp.com>
From: Ming Qian <ming.qian@oss.nxp.com>
Add documentation for the V4L2_CID_MEMORY_USAGE control in the
userspace API documentation. This read-only control allows applications
to query the total amount of memory currently used by a device instance.
The documentation explains:
- The control reports memory usage in bytes for driver-managed allocations
- It includes internal buffers, intermediate processing data, and other
driver allocations associated with the instance
- Applications can use it for debugging, resource monitoring, and making
informed buffer allocation decisions
- The value may change dynamically during device operation
- It only reports driver-managed memory, not application-allocated buffers
Update V4L2_CID_LASTP1 definition to reflect the new control as the
last predefined control ID.
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
---
.../userspace-api/media/v4l/control.rst | 22 ++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/Documentation/userspace-api/media/v4l/control.rst b/Documentation/userspace-api/media/v4l/control.rst
index 19372bb32c4b..6904c5bdbf37 100644
--- a/Documentation/userspace-api/media/v4l/control.rst
+++ b/Documentation/userspace-api/media/v4l/control.rst
@@ -316,9 +316,29 @@ Control IDs
set the alpha component value of all pixels for further processing
in the device.
+``V4L2_CID_MEMORY_USAGE`` ``(integer64)``
+ This is an optional read-only control that reports the total amount of
+ memory, in bytes, currently allocated and used by this device instance.
+ This includes memory used for internal buffers, intermediate processing
+ data, and any other driver-managed allocations associated with the
+ instance.
+
+ Applications can use this control to monitor memory consumption for
+ debugging purposes, resource management, or to make informed decisions
+ about buffer allocation strategies. The value may change dynamically
+ as the device operates, for example when buffers are allocated or
+ released during streaming.
+
+ Note that this control only reports memory managed by the driver for
+ this specific instance; it does not include memory allocated by the
+ application itself (e.g., userspace buffers passed to the driver).
+
+ Not all drivers support this control. Applications should query for
+ its availability before use.
+
``V4L2_CID_LASTP1``
End of the predefined control IDs (currently
- ``V4L2_CID_ALPHA_COMPONENT`` + 1).
+ ``V4L2_CID_MEMORY_USAGE`` + 1).
``V4L2_CID_PRIVATE_BASE``
ID of the first custom (driver specific) control. Applications
--
2.53.0
^ permalink raw reply related
* [RFC PATCH 4/7] docs: media: v4l2-memtrack: Add driver API documentation
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
In-Reply-To: <20260331072347.253-1-ming.qian@oss.nxp.com>
From: Ming Qian <ming.qian@oss.nxp.com>
Add comprehensive documentation for the V4L2 memory tracking infrastructure
in the driver API documentation. This documentation covers:
- Overview of the hierarchical memory tracking system
- Basic usage examples showing root node creation and memory tracking
- Hierarchical tracking with parent-child node relationships
- debugfs interface for runtime memory inspection
- Notification callback registration and usage warnings
- Visual examples of tree structure and debugfs output
The documentation provides driver developers with practical examples
of how to integrate memory tracking into their V4L2 drivers, including
proper setup during probe/remove, buffer allocation tracking, and
per-context memory monitoring.
Add the new v4l2-memtrack documentation to the v4l2-core index to make
it accessible in the generated documentation.
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
---
Documentation/driver-api/media/v4l2-core.rst | 1 +
.../driver-api/media/v4l2-memtrack.rst | 140 ++++++++++++++++++
2 files changed, 141 insertions(+)
create mode 100644 Documentation/driver-api/media/v4l2-memtrack.rst
diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst
index a5f5102c64cc..09765d028375 100644
--- a/Documentation/driver-api/media/v4l2-core.rst
+++ b/Documentation/driver-api/media/v4l2-core.rst
@@ -28,3 +28,4 @@ Video4Linux devices
v4l2-tveeprom
v4l2-jpeg
v4l2-isp
+ v4l2-memtrack
diff --git a/Documentation/driver-api/media/v4l2-memtrack.rst b/Documentation/driver-api/media/v4l2-memtrack.rst
new file mode 100644
index 000000000000..bca6954cfa0b
--- /dev/null
+++ b/Documentation/driver-api/media/v4l2-memtrack.rst
@@ -0,0 +1,140 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+V4L2 Memory Usage Tracker
+=========================
+
+Overview
+--------
+
+The V4L2 memory tracking module provides hierarchical memory allocation
+tracking for V4L2 devices. It is useful for debugging memory leaks and
+monitoring buffer usage in video drivers.
+
+Features:
+
+- Tree-structured memory usage monitoring
+- Per-device and per-context tracking
+- debugfs interface for runtime inspection
+- Optional notification callbacks for memory changes
+- V4L2 control integration
+
+Usage Example
+-------------
+
+Basic usage in a V4L2 driver:
+
+.. code-block:: c
+
+ #include <media/v4l2-memtrack.h>
+
+ struct my_device {
+ struct v4l2_memtrack_node *memtrack;
+ /* ... */
+ };
+
+ static int my_probe(struct platform_device *pdev)
+ {
+ struct my_device *dev;
+
+ dev->memtrack = v4l2_memtrack_create_root("my-device");
+ if (!dev->memtrack)
+ return -ENOMEM;
+
+ return 0;
+ }
+
+ static void my_remove(struct platform_device *pdev)
+ {
+ v4l2_memtrack_destroy_node(dev->memtrack);
+ }
+
+ static int my_alloc_buffer(struct my_device *dev, size_t size)
+ {
+ void *buf = dma_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ v4l2_memtrack_add(dev->memtrack, size);
+ return 0;
+ }
+
+ static void my_free_buffer(struct my_device *dev, size_t size)
+ {
+ dma_free_coherent(dev, size, buf, dma_addr);
+ v4l2_memtrack_sub(dev->memtrack, size);
+ }
+
+Hierarchical Tracking
+---------------------
+
+For more detailed tracking, create child nodes:
+
+.. code-block:: c
+
+ struct my_context {
+ struct v4l2_memtrack_node *memtrack;
+ };
+
+ static int my_open(struct file *file)
+ {
+ struct my_context *ctx;
+
+ ctx->memtrack = v4l2_memtrack_create_node(dev->memtrack, "context");
+ return 0;
+ }
+
+ static int my_close(struct file *file)
+ {
+ v4l2_memtrack_destroy_node(ctx->memtrack);
+ return 0;
+ }
+
+This creates a tree structure::
+
+ my-device (root)
+ ├── context (pid=1234)
+ │ ├── buffer: 4096 bytes
+ │ └── buffer: 8192 bytes
+ └── context (pid=5678)
+ └── buffer: 4096 bytes
+
+debugfs Interface
+-----------------
+
+Memory usage is exposed via debugfs at::
+
+ /sys/kernel/debug/v4l2-memtrack/<device-name>
+
+Example output::
+
+ Total memory usage: 16384 bytes
+ my-device (tgid=1000, pid=1000) usage: 16384
+ context (tgid=1234, pid=1234) usage: 12288 (count=2)
+ context (tgid=5678, pid=5678) usage: 4096 (count=1)
+
+Notification Callbacks
+----------------------
+
+Register callbacks to be notified of memory changes:
+
+.. code-block:: c
+
+ static void my_notify(struct v4l2_memtrack_node *node,
+ size_t total, void *priv)
+ {
+ pr_info("Memory usage changed: %zu bytes\n", total);
+ }
+
+ v4l2_memtrack_register_notify(dev->memtrack, my_notify, dev);
+
+.. warning::
+
+ Callbacks are executed without holding internal locks, so most kernel
+ functions may be called safely. However, the callback MUST NOT call
+ v4l2_memtrack_unregister_notify() or v4l2_memtrack_destroy_node() on
+ the same node, as this will cause a deadlock.
+
+API Reference
+-------------
+
+.. kernel-doc:: include/media/v4l2-memtrack.h
--
2.53.0
^ permalink raw reply related
* [RFC PATCH 3/7] media: v4l2-memtrack: Add V4L2 memory tracking infrastructure
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
In-Reply-To: <20260331072347.253-1-ming.qian@oss.nxp.com>
From: Ming Qian <ming.qian@oss.nxp.com>
Add a hierarchical memory tracking system for V4L2 devices that allows
drivers to monitor and report memory usage. This infrastructure provides:
- Tree-structured memory tracking with parent-child relationships
- Per-node memory accounting with allocation counts
- Automatic aggregation of memory usage up the hierarchy
- debugfs interface for inspecting memory usage trees
- Notification callbacks for memory usage changes
The tracking system uses a context-based design where each root node
creates its own tracking tree. Memory changes propagate notifications up
the tree, allowing drivers to update controls or take other actions.
The debugfs interface creates entries under <debugfs>/v4l2-memtrack/
showing hierarchical memory usage with indentation, allocation counts,
and process information.
Drivers can use this to track internal buffers, intermediate processing
data, and other allocations, providing visibility into memory consumption
for debugging and resource monitoring.
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
---
drivers/media/common/Kconfig | 1 +
drivers/media/common/Makefile | 2 +-
drivers/media/common/v4l2-memtrack/Kconfig | 19 +
drivers/media/common/v4l2-memtrack/Makefile | 3 +
.../common/v4l2-memtrack/v4l2-memtrack.c | 825 ++++++++++++++++++
include/media/v4l2-memtrack.h | 220 +++++
6 files changed, 1069 insertions(+), 1 deletion(-)
create mode 100644 drivers/media/common/v4l2-memtrack/Kconfig
create mode 100644 drivers/media/common/v4l2-memtrack/Makefile
create mode 100644 drivers/media/common/v4l2-memtrack/v4l2-memtrack.c
create mode 100644 include/media/v4l2-memtrack.h
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index adcb6655385a..4da632f53970 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -27,5 +27,6 @@ config VIDEO_TVEEPROM
source "drivers/media/common/b2c2/Kconfig"
source "drivers/media/common/saa7146/Kconfig"
source "drivers/media/common/siano/Kconfig"
+source "drivers/media/common/v4l2-memtrack/Kconfig"
source "drivers/media/common/v4l2-tpg/Kconfig"
source "drivers/media/common/videobuf2/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index c5ab905e7c20..0010a4d904ca 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/
+obj-y += b2c2/ saa7146/ siano/ v4l2-memtrack/ v4l2-tpg/ videobuf2/
# Please keep it alphabetically sorted by Kconfig name
# (e. g. LC_ALL=C sort Makefile)
diff --git a/drivers/media/common/v4l2-memtrack/Kconfig b/drivers/media/common/v4l2-memtrack/Kconfig
new file mode 100644
index 000000000000..f4c97117b779
--- /dev/null
+++ b/drivers/media/common/v4l2-memtrack/Kconfig
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config V4L2_MEMTRACK
+ tristate "V4L2 memory usage tracking support"
+ help
+ This option enables hierarchical memory allocation tracking
+ for V4L2 devices. It provides:
+
+ - Tree-structured memory usage monitoring
+ - Per-device and per-context tracking
+ - debugfs interface at /sys/kernel/debug/v4l2-memtrack/
+ - Optional V4L2 control for userspace queries
+
+ This is useful for debugging memory leaks and monitoring
+ buffer allocation in video drivers.
+
+ To compile this as a module, choose M here.
+
+ If unsure, say N.
diff --git a/drivers/media/common/v4l2-memtrack/Makefile b/drivers/media/common/v4l2-memtrack/Makefile
new file mode 100644
index 000000000000..5ed59453b35a
--- /dev/null
+++ b/drivers/media/common/v4l2-memtrack/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_V4L2_MEMTRACK) += v4l2-memtrack.o
diff --git a/drivers/media/common/v4l2-memtrack/v4l2-memtrack.c b/drivers/media/common/v4l2-memtrack/v4l2-memtrack.c
new file mode 100644
index 000000000000..96eeaef7a653
--- /dev/null
+++ b/drivers/media/common/v4l2-memtrack/v4l2-memtrack.c
@@ -0,0 +1,825 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 Memory Usage Tracker
+ *
+ * Copyright 2026 NXP
+ *
+ * Provides hierarchical memory allocation tracking for V4L2 devices.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/atomic.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+
+#include <media/v4l2-memtrack.h>
+
+#define V4L2_MEMTRACK_DEBUGFS_ROOT "v4l2-memtrack"
+#define V4L2_MEMTRACK_MAX_DEPTH 16
+
+/**
+ * struct v4l2_memtrack_ctx - Memory tracker context
+ * @name: Tracker name (shown in debugfs)
+ * @root: Root node of tracking hierarchy
+ * @debugfs: debugfs file entry
+ * @lock: Protects the node tree
+ */
+struct v4l2_memtrack_ctx {
+ const char *name;
+ struct v4l2_memtrack_node *root;
+ struct dentry *debugfs;
+ struct mutex lock;
+};
+
+/**
+ * struct v4l2_memtrack_node - Memory tracking node
+ * @list: Linkage in parent's children list
+ * @parent: Parent node
+ * @children: List of child nodes
+ * @bytes: Memory usage in bytes
+ * @alloc_count: Number of allocations
+ * @name: Node name
+ * @depth: Depth of this node in the tree (root = 0)
+ * @pid: Process ID that created this node
+ * @tgid: Thread group ID that created this node
+ * @ctx: Back pointer to context
+ * @is_leaf: True if this is a leaf node (internal use only)
+ * @notify: Notification callback for memory changes
+ * @notify_priv: Private data for notification callback
+ * @notify_work: Per-node delayed work for coalesced notifications
+ * @notify_delay_ms: Notification delay (<0: off, 0: immediate, >0: delayed)
+ * @in_notify: Flag indicating if callback is currently executing
+ * @notify_done: Completion for waiting on callback completion
+ */
+struct v4l2_memtrack_node {
+ struct list_head list;
+ struct v4l2_memtrack_node *parent;
+ struct list_head children;
+
+ size_t bytes;
+ unsigned int alloc_count;
+
+ const char *name;
+ unsigned int depth;
+ pid_t pid;
+ pid_t tgid;
+
+ struct v4l2_memtrack_ctx *ctx;
+ bool is_leaf;
+
+ /* Notify fields - only used by non-leaf nodes */
+ v4l2_memtrack_notify_fn notify;
+ void *notify_priv;
+ struct delayed_work notify_work;
+ int notify_delay_ms;
+ bool in_notify;
+ struct completion notify_done;
+};
+
+static struct dentry *v4l2_memtrack_debugfs_root;
+static DEFINE_MUTEX(v4l2_memtrack_debugfs_lock);
+static struct kref v4l2_memtrack_debugfs_kref;
+static bool v4l2_memtrack_debugfs_initialized;
+
+struct v4l2_memtrack_iter_state {
+ struct v4l2_memtrack_node *node;
+ struct list_head *next_child;
+};
+
+typedef int (*v4l2_memtrack_visit_fn)(struct v4l2_memtrack_node *node, void *data);
+
+static int v4l2_memtrack_for_each_locked(struct v4l2_memtrack_node *root,
+ v4l2_memtrack_visit_fn visit,
+ void *data)
+{
+ struct v4l2_memtrack_iter_state stack[V4L2_MEMTRACK_MAX_DEPTH];
+ struct v4l2_memtrack_node *node;
+ int sp = 0;
+ int ret;
+
+ lockdep_assert_held(&root->ctx->lock);
+
+ ret = visit(root, data);
+ if (ret)
+ return ret;
+
+ if (list_empty(&root->children))
+ return 0;
+
+ stack[sp].node = root;
+ stack[sp].next_child = root->children.next;
+ sp++;
+
+ while (sp > 0) {
+ struct v4l2_memtrack_iter_state *top = &stack[sp - 1];
+
+ if (top->next_child == &top->node->children) {
+ sp--;
+ continue;
+ }
+
+ node = list_entry(top->next_child,
+ struct v4l2_memtrack_node, list);
+ top->next_child = top->next_child->next;
+
+ ret = visit(node, data);
+ if (ret)
+ return ret;
+
+ if (!list_empty(&node->children) &&
+ sp < V4L2_MEMTRACK_MAX_DEPTH) {
+ stack[sp].node = node;
+ stack[sp].next_child = node->children.next;
+ sp++;
+ }
+ }
+
+ return 0;
+}
+
+static void v4l2_memtrack_debugfs_release(struct kref *kref)
+{
+ debugfs_remove(v4l2_memtrack_debugfs_root);
+ v4l2_memtrack_debugfs_root = NULL;
+ v4l2_memtrack_debugfs_initialized = false;
+}
+
+static void v4l2_memtrack_debugfs_get(void)
+{
+ guard(mutex)(&v4l2_memtrack_debugfs_lock);
+
+ if (!v4l2_memtrack_debugfs_initialized) {
+ kref_init(&v4l2_memtrack_debugfs_kref);
+ v4l2_memtrack_debugfs_root =
+ debugfs_create_dir(V4L2_MEMTRACK_DEBUGFS_ROOT, NULL);
+ v4l2_memtrack_debugfs_initialized = true;
+ } else {
+ kref_get(&v4l2_memtrack_debugfs_kref);
+ }
+}
+
+static void v4l2_memtrack_debugfs_put(void)
+{
+ guard(mutex)(&v4l2_memtrack_debugfs_lock);
+ kref_put(&v4l2_memtrack_debugfs_kref, v4l2_memtrack_debugfs_release);
+}
+
+static void v4l2_memtrack_notify_work_handler(struct work_struct *work);
+
+static int v4l2_memtrack_node_init(struct v4l2_memtrack_node *node,
+ struct v4l2_memtrack_ctx *ctx,
+ unsigned int depth,
+ const char *name,
+ bool is_leaf)
+{
+ INIT_LIST_HEAD(&node->list);
+ INIT_LIST_HEAD(&node->children);
+ node->bytes = 0;
+ node->alloc_count = 0;
+ node->ctx = ctx;
+ node->depth = depth;
+ node->tgid = current->tgid;
+ node->pid = current->pid;
+ node->is_leaf = is_leaf;
+
+ /* Initialize notify fields only for non-leaf nodes */
+ if (!is_leaf) {
+ node->notify = NULL;
+ node->notify_priv = NULL;
+ INIT_DELAYED_WORK(&node->notify_work,
+ v4l2_memtrack_notify_work_handler);
+ node->notify_delay_ms = 0;
+ node->in_notify = false;
+ init_completion(&node->notify_done);
+ }
+
+ if (name) {
+ node->name = kstrdup_const(name, GFP_KERNEL);
+ if (!node->name)
+ return -ENOMEM;
+ } else {
+ node->name = NULL;
+ }
+
+ return 0;
+}
+
+static inline const char *v4l2_memtrack_name(struct v4l2_memtrack_node *node)
+{
+ return node->name ? : "(unnamed)";
+}
+
+static int v4l2_memtrack_sum_visitor(struct v4l2_memtrack_node *node, void *data)
+{
+ size_t *total = data;
+
+ *total += node->bytes;
+ return 0;
+}
+
+static size_t v4l2_memtrack_sum_bytes_locked(struct v4l2_memtrack_node *root)
+{
+ size_t total = 0;
+
+ lockdep_assert_held(&root->ctx->lock);
+
+ v4l2_memtrack_for_each_locked(root, v4l2_memtrack_sum_visitor, &total);
+ return total;
+}
+
+static void v4l2_memtrack_do_notify_locked(struct v4l2_memtrack_node *node)
+{
+ size_t total;
+ v4l2_memtrack_notify_fn notify;
+ void *priv;
+ struct v4l2_memtrack_ctx *ctx = node->ctx;
+
+ lockdep_assert_held(&ctx->lock);
+
+ if (!node->notify)
+ return;
+
+ total = v4l2_memtrack_sum_bytes_locked(node);
+ notify = node->notify;
+ priv = node->notify_priv;
+
+ node->in_notify = true;
+ reinit_completion(&node->notify_done);
+
+ mutex_unlock(&ctx->lock);
+ notify(node, total, priv);
+ mutex_lock(&ctx->lock);
+
+ node->in_notify = false;
+ complete_all(&node->notify_done);
+}
+
+static void v4l2_memtrack_notify_work_handler(struct work_struct *work)
+{
+ struct v4l2_memtrack_node *node =
+ container_of(to_delayed_work(work),
+ struct v4l2_memtrack_node, notify_work);
+ struct v4l2_memtrack_ctx *ctx = node->ctx;
+
+ guard(mutex)(&ctx->lock);
+ v4l2_memtrack_do_notify_locked(node);
+}
+
+static void v4l2_memtrack_schedule_notify(struct v4l2_memtrack_node *node)
+{
+ int delay;
+
+ if (node->is_leaf || !node->notify)
+ return;
+
+ delay = node->notify_delay_ms;
+ if (delay < 0)
+ return;
+
+ if (delay == 0)
+ v4l2_memtrack_do_notify_locked(node);
+ else
+ schedule_delayed_work(&node->notify_work,
+ msecs_to_jiffies(delay));
+}
+
+static void v4l2_memtrack_notify_change_locked(struct v4l2_memtrack_node *node)
+{
+ struct v4l2_memtrack_node *cur;
+
+ lockdep_assert_held(&node->ctx->lock);
+
+ for (cur = node; cur; cur = cur->parent) {
+ if (!cur->is_leaf)
+ v4l2_memtrack_schedule_notify(cur);
+ }
+}
+
+static void v4l2_memtrack_do_notify(struct v4l2_memtrack_node *node)
+{
+ if (!node || !node->ctx)
+ return;
+
+ guard(mutex)(&node->ctx->lock);
+ v4l2_memtrack_notify_change_locked(node);
+}
+
+struct v4l2_memtrack_seq_ctx {
+ struct seq_file *seq;
+};
+
+static int v4l2_memtrack_seq_visitor(struct v4l2_memtrack_node *node, void *data)
+{
+ struct v4l2_memtrack_seq_ctx *ctx = data;
+ struct seq_file *s = ctx->seq;
+ size_t bytes;
+
+ bytes = v4l2_memtrack_sum_bytes_locked(node);
+
+ seq_printf(s, "%*s", node->depth * 2, "");
+
+ if (node->name)
+ seq_printf(s, "%s ", node->name);
+
+ if (node->is_leaf)
+ seq_puts(s, "[leaf] ");
+
+ if (node->tgid && node->pid)
+ seq_printf(s, "(tgid=%d, pid=%d) ", node->tgid, node->pid);
+
+ seq_printf(s, "usage: %zu", bytes);
+
+ if (node->alloc_count > 1 || (node->alloc_count == 1 && !list_empty(&node->children))) {
+ seq_printf(s, " (count=%u", node->alloc_count);
+ if (!list_empty(&node->children))
+ seq_printf(s, ", self=%zu", node->bytes);
+ seq_puts(s, ")");
+ }
+
+ seq_puts(s, "\n");
+ return 0;
+}
+
+static int v4l2_memtrack_seq_show(struct seq_file *s, void *data)
+{
+ struct v4l2_memtrack_ctx *ctx = s->private;
+ struct v4l2_memtrack_seq_ctx seq_ctx = { .seq = s };
+
+ guard(mutex)(&ctx->lock);
+
+ seq_printf(s, "Total memory usage: %zu bytes\n",
+ v4l2_memtrack_sum_bytes_locked(ctx->root));
+ v4l2_memtrack_for_each_locked(ctx->root, v4l2_memtrack_seq_visitor, &seq_ctx);
+
+ return 0;
+}
+
+static int v4l2_memtrack_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, v4l2_memtrack_seq_show, inode->i_private);
+}
+
+static const struct file_operations v4l2_memtrack_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_memtrack_debugfs_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
+};
+
+static void v4l2_memtrack_create_debugfs(struct v4l2_memtrack_ctx *ctx)
+{
+ guard(mutex)(&v4l2_memtrack_debugfs_lock);
+
+ if (IS_ERR_OR_NULL(v4l2_memtrack_debugfs_root))
+ return;
+
+ ctx->debugfs = debugfs_create_file(ctx->name, 0444,
+ v4l2_memtrack_debugfs_root,
+ ctx, &v4l2_memtrack_debugfs_fops);
+}
+
+static struct v4l2_memtrack_ctx *v4l2_memtrack_ctx_create(const char *name)
+{
+ struct v4l2_memtrack_ctx *ctx;
+
+ ctx = kzalloc_obj(*ctx);
+ if (!ctx)
+ return NULL;
+
+ if (name) {
+ ctx->name = kstrdup_const(name, GFP_KERNEL);
+ if (!ctx->name) {
+ kfree(ctx);
+ return NULL;
+ }
+ }
+
+ mutex_init(&ctx->lock);
+
+ return ctx;
+}
+
+static void v4l2_memtrack_ctx_destroy(struct v4l2_memtrack_ctx *ctx)
+{
+ debugfs_remove(ctx->debugfs);
+ mutex_destroy(&ctx->lock);
+ kfree_const(ctx->name);
+ kfree(ctx);
+ v4l2_memtrack_debugfs_put();
+}
+
+struct v4l2_memtrack_node *v4l2_memtrack_create_root(const char *name)
+{
+ struct v4l2_memtrack_ctx *ctx;
+ struct v4l2_memtrack_node *node;
+
+ v4l2_memtrack_debugfs_get();
+
+ ctx = v4l2_memtrack_ctx_create(name);
+ if (!ctx) {
+ v4l2_memtrack_debugfs_put();
+ return NULL;
+ }
+
+ node = kzalloc_obj(*node);
+ if (!node) {
+ v4l2_memtrack_ctx_destroy(ctx);
+ return NULL;
+ }
+
+ if (v4l2_memtrack_node_init(node, ctx, 0, name, false)) {
+ kfree(node);
+ v4l2_memtrack_ctx_destroy(ctx);
+ return NULL;
+ }
+
+ ctx->root = node;
+
+ if (name)
+ v4l2_memtrack_create_debugfs(ctx);
+
+ return node;
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_create_root);
+
+struct v4l2_memtrack_node *v4l2_memtrack_create_node(struct v4l2_memtrack_node *parent,
+ const char *name)
+{
+ struct v4l2_memtrack_ctx *ctx;
+ struct v4l2_memtrack_node *node;
+ unsigned int new_depth;
+
+ if (!parent || !parent->ctx)
+ return NULL;
+
+ /* Leaf nodes cannot have children */
+ if (parent->is_leaf) {
+ pr_warn_once("v4l2-memtrack: cannot create child under leaf node\n");
+ return NULL;
+ }
+
+ new_depth = parent->depth + 1;
+ if (new_depth >= V4L2_MEMTRACK_MAX_DEPTH) {
+ pr_warn_once("v4l2-memtrack: max depth %d reached, cannot create child node\n",
+ V4L2_MEMTRACK_MAX_DEPTH);
+ return NULL;
+ }
+
+ ctx = parent->ctx;
+
+ node = kzalloc_obj(*node);
+ if (!node)
+ return NULL;
+
+ if (v4l2_memtrack_node_init(node, ctx, new_depth, name, false)) {
+ kfree(node);
+ return NULL;
+ }
+
+ node->parent = parent;
+
+ scoped_guard(mutex, &ctx->lock)
+ list_add_tail(&node->list, &parent->children);
+
+ return node;
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_create_node);
+
+static void v4l2_memtrack_cancel_notify(struct v4l2_memtrack_node *node)
+{
+ bool wait_needed = false;
+
+ if (node->is_leaf)
+ return;
+
+ cancel_delayed_work_sync(&node->notify_work);
+
+ scoped_guard(mutex, &node->ctx->lock) {
+ node->notify = NULL;
+ node->notify_priv = NULL;
+ wait_needed = node->in_notify;
+ }
+
+ if (wait_needed)
+ wait_for_completion(&node->notify_done);
+}
+
+static void v4l2_memtrack_delete_subtree_locked(struct v4l2_memtrack_node *root)
+{
+ struct v4l2_memtrack_ctx *ctx = root->ctx;
+ struct v4l2_memtrack_node * const stop = root->parent;
+ struct v4l2_memtrack_node *node, *parent;
+
+ lockdep_assert_held(&ctx->lock);
+
+ node = root;
+ while (node) {
+ if (!list_empty(&node->children)) {
+ node = list_first_entry(&node->children,
+ struct v4l2_memtrack_node, list);
+ } else {
+ parent = node->parent;
+ list_del(&node->list);
+ kfree_const(node->name);
+ kfree(node);
+
+ if (parent == stop)
+ break;
+ node = parent;
+ }
+ }
+}
+
+static int v4l2_memtrack_find_notify_visitor(struct v4l2_memtrack_node *node,
+ void *data)
+{
+ struct v4l2_memtrack_node **found = data;
+
+ if (!node->is_leaf && node->notify) {
+ *found = node;
+ return 1; /* Stop iteration */
+ }
+ return 0;
+}
+
+static struct v4l2_memtrack_node *
+v4l2_memtrack_get_next_notify_node_locked(struct v4l2_memtrack_node *root)
+{
+ struct v4l2_memtrack_node *found = NULL;
+
+ lockdep_assert_held(&root->ctx->lock);
+
+ v4l2_memtrack_for_each_locked(root, v4l2_memtrack_find_notify_visitor,
+ &found);
+ return found;
+}
+
+void v4l2_memtrack_destroy_node(struct v4l2_memtrack_node *node)
+{
+ struct v4l2_memtrack_ctx *ctx;
+ struct v4l2_memtrack_node *parent;
+ struct v4l2_memtrack_node *notify_node;
+ bool is_root;
+
+ if (!node || !node->ctx)
+ return;
+
+ ctx = node->ctx;
+ parent = node->parent;
+ is_root = !parent;
+
+ if (v4l2_memtrack_read(node))
+ v4l2_memtrack_print_debug(node);
+
+ /*
+ * Cancel all notify callbacks in the subtree.
+ * Get one node with notify at a time while holding lock,
+ * then cancel it without lock to avoid deadlock.
+ */
+ if (!node->is_leaf) {
+ while (true) {
+ scoped_guard(mutex, &ctx->lock)
+ notify_node = v4l2_memtrack_get_next_notify_node_locked(node);
+
+ if (!notify_node)
+ break;
+
+ v4l2_memtrack_cancel_notify(notify_node);
+ }
+ }
+
+ scoped_guard(mutex, &ctx->lock)
+ v4l2_memtrack_delete_subtree_locked(node);
+
+ if (is_root)
+ v4l2_memtrack_ctx_destroy(ctx);
+ else
+ v4l2_memtrack_do_notify(parent);
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_destroy_node);
+
+static int v4l2_memtrack_create_leaf_locked(struct v4l2_memtrack_node *node,
+ size_t bytes, const char *name)
+{
+ struct v4l2_memtrack_ctx *ctx = node->ctx;
+ struct v4l2_memtrack_node *child;
+ unsigned int new_depth;
+
+ lockdep_assert_held(&ctx->lock);
+
+ new_depth = node->depth + 1;
+ if (new_depth >= V4L2_MEMTRACK_MAX_DEPTH) {
+ pr_warn_once("v4l2-memtrack: max depth %d reached\n",
+ V4L2_MEMTRACK_MAX_DEPTH);
+ return -ENOSPC;
+ }
+
+ child = kzalloc(sizeof(*child), GFP_KERNEL);
+ if (!child)
+ return -ENOMEM;
+
+ if (v4l2_memtrack_node_init(child, ctx, new_depth, name, true)) {
+ kfree(child);
+ return -ENOMEM;
+ }
+
+ child->parent = node;
+ child->bytes = bytes;
+ child->alloc_count = 1;
+
+ list_add_tail(&child->list, &node->children);
+
+ return 0;
+}
+
+void v4l2_memtrack_add(struct v4l2_memtrack_node *node, size_t bytes,
+ const char *name)
+{
+ if (!node || !node->ctx)
+ return;
+
+ /* Leaf nodes cannot have children */
+ if (node->is_leaf) {
+ pr_warn_once("v4l2-memtrack: cannot add to leaf node\n");
+ return;
+ }
+
+ guard(mutex)(&node->ctx->lock);
+
+ if (name) {
+ /* Create a leaf node for named allocations */
+ if (v4l2_memtrack_create_leaf_locked(node, bytes, name) < 0) {
+ /* Fallback to direct tracking on failure */
+ node->bytes += bytes;
+ node->alloc_count++;
+ }
+ } else {
+ /* Direct tracking for unnamed allocations */
+ node->bytes += bytes;
+ node->alloc_count++;
+ }
+
+ v4l2_memtrack_notify_change_locked(node);
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_add);
+
+void v4l2_memtrack_sub(struct v4l2_memtrack_node *node, size_t bytes,
+ const char *name)
+{
+ struct v4l2_memtrack_node *child;
+ struct v4l2_memtrack_node *found = NULL;
+
+ if (!node || !node->ctx)
+ return;
+
+ guard(mutex)(&node->ctx->lock);
+
+ /* Try to find and remove a matching leaf node if name is provided */
+ if (name && !node->is_leaf) {
+ list_for_each_entry(child, &node->children, list) {
+ if (!child->is_leaf)
+ continue;
+ if (child->bytes != bytes)
+ continue;
+ if (!child->name || strcmp(child->name, name))
+ continue;
+
+ list_del(&child->list);
+ found = child;
+ break;
+ }
+ }
+
+ if (found) {
+ kfree_const(found->name);
+ kfree(found);
+ } else {
+ /* Direct subtraction */
+ if (node->bytes < bytes) {
+ pr_warn_once("v4l2-memtrack: %s: bytes underflow\n",
+ v4l2_memtrack_name(node));
+ node->bytes = 0;
+ } else {
+ node->bytes -= bytes;
+ }
+
+ if (node->alloc_count > 0)
+ node->alloc_count--;
+ }
+
+ v4l2_memtrack_notify_change_locked(node);
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_sub);
+
+void v4l2_memtrack_set(struct v4l2_memtrack_node *node, size_t bytes)
+{
+ if (!node || !node->ctx)
+ return;
+
+ guard(mutex)(&node->ctx->lock);
+
+ node->bytes = bytes;
+ node->alloc_count = bytes ? 1 : 0;
+ v4l2_memtrack_notify_change_locked(node);
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_set);
+
+size_t v4l2_memtrack_read(struct v4l2_memtrack_node *node)
+{
+ struct v4l2_memtrack_ctx *ctx;
+ size_t total;
+
+ if (!node || !node->ctx)
+ return 0;
+
+ ctx = node->ctx;
+
+ scoped_guard(mutex, &ctx->lock)
+ total = v4l2_memtrack_sum_bytes_locked(node);
+
+ return total;
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_read);
+
+int v4l2_memtrack_register_notify(struct v4l2_memtrack_node *node,
+ v4l2_memtrack_notify_fn notify,
+ void *priv)
+{
+ if (!node || !node->ctx)
+ return -EINVAL;
+
+ /* Leaf nodes do not support notifications */
+ if (node->is_leaf)
+ return -EINVAL;
+
+ guard(mutex)(&node->ctx->lock);
+
+ if (node->notify)
+ return -EBUSY;
+
+ node->notify = notify;
+ node->notify_priv = priv;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_register_notify);
+
+void v4l2_memtrack_unregister_notify(struct v4l2_memtrack_node *node)
+{
+ if (!node || !node->ctx || node->is_leaf)
+ return;
+
+ v4l2_memtrack_cancel_notify(node);
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_unregister_notify);
+
+void v4l2_memtrack_set_notify_delay(struct v4l2_memtrack_node *node, int delay_ms)
+{
+ if (!node || !node->ctx || node->is_leaf)
+ return;
+
+ guard(mutex)(&node->ctx->lock);
+ node->notify_delay_ms = delay_ms;
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_set_notify_delay);
+
+static int v4l2_memtrack_print_visitor(struct v4l2_memtrack_node *node, void *data)
+{
+ pr_debug("v4l2-memtrack: %*s%s%s: usage=%zu bytes, count=%u\n",
+ node->depth * 2, "",
+ v4l2_memtrack_name(node),
+ node->is_leaf ? " [leaf]" : "",
+ v4l2_memtrack_sum_bytes_locked(node),
+ node->alloc_count);
+ return 0;
+}
+
+void v4l2_memtrack_print_debug(struct v4l2_memtrack_node *node)
+{
+ struct v4l2_memtrack_ctx *ctx;
+
+ if (!node || !node->ctx)
+ return;
+
+ ctx = node->ctx;
+
+ pr_debug("v4l2-memtrack: Memory Tracker: %s\n", ctx->name ? : "(unnamed)");
+
+ scoped_guard(mutex, &ctx->lock)
+ v4l2_memtrack_for_each_locked(node, v4l2_memtrack_print_visitor, NULL);
+}
+EXPORT_SYMBOL_GPL(v4l2_memtrack_print_debug);
+
+MODULE_DESCRIPTION("V4L2 Memory Usage Tracker");
+MODULE_AUTHOR("Ming Qian <ming.qian@oss.nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/media/v4l2-memtrack.h b/include/media/v4l2-memtrack.h
new file mode 100644
index 000000000000..b146277ab98f
--- /dev/null
+++ b/include/media/v4l2-memtrack.h
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * V4L2 Memory Usage Tracker
+ *
+ * Copyright 2026 NXP
+ *
+ * Provides hierarchical memory allocation tracking for V4L2 devices,
+ * useful for debugging memory leaks and monitoring buffer usage.
+ */
+
+#ifndef _V4L2_MEMTRACK_H
+#define _V4L2_MEMTRACK_H
+
+#include <linux/types.h>
+
+struct v4l2_memtrack_node;
+
+/**
+ * typedef v4l2_memtrack_notify_fn - Memory change notification callback
+ * @node: The node whose subtree memory usage changed
+ * @total: Total memory usage of the node's subtree in bytes
+ * @priv: Private data passed during registration
+ *
+ * This callback is invoked when memory usage changes in the node or any
+ * of its descendants. The callback is executed without holding internal
+ * locks, so it may call most kernel functions safely.
+ *
+ * However, the callback MUST NOT call v4l2_memtrack_unregister_notify()
+ * or v4l2_memtrack_destroy_node() on the same node, as this will cause
+ * a deadlock. The callback should be kept reasonably short to avoid
+ * delaying other pending notifications.
+ */
+typedef void (*v4l2_memtrack_notify_fn)(struct v4l2_memtrack_node *node, size_t total, void *priv);
+
+#if IS_REACHABLE(CONFIG_V4L2_MEMTRACK)
+
+/**
+ * v4l2_memtrack_create_root - Create a root tracking node
+ * @name: Name for this tracker (shows in debugfs)
+ *
+ * Creates a root node that serves as the top of a tracking hierarchy.
+ * Each root node creates its own debugfs entry under <debugfs>/v4l2-memtrack/.
+ *
+ * Return: Pointer to the root node, or NULL on failure
+ */
+struct v4l2_memtrack_node *v4l2_memtrack_create_root(const char *name);
+
+/**
+ * v4l2_memtrack_create_node - Create a child tracking node
+ * @parent: Parent node
+ * @name: Optional name for this node
+ *
+ * Creates a child node under the specified parent. Child nodes
+ * contribute to their parent's total memory count.
+ *
+ * Return: Pointer to the new node, or NULL on failure
+ */
+struct v4l2_memtrack_node *v4l2_memtrack_create_node(struct v4l2_memtrack_node *parent,
+ const char *name);
+
+/**
+ * v4l2_memtrack_destroy_node - Destroy a tracking node
+ * @node: Node to destroy
+ *
+ * Destroys the node and all its children. If this is a root node,
+ * also removes the debugfs entry and frees all resources.
+ */
+void v4l2_memtrack_destroy_node(struct v4l2_memtrack_node *node);
+
+/**
+ * v4l2_memtrack_add - Record a memory allocation
+ * @node: Tracking node
+ * @bytes: Number of bytes allocated
+ * @name: Optional name for the allocation
+ *
+ * Records a memory allocation. If @name is provided, creates an internal
+ * leaf node to track this specific allocation, which can be matched and
+ * removed later by v4l2_memtrack_sub() with the same name and size.
+ * If @name is NULL, adds bytes directly to the node's counter.
+ *
+ * Triggers notification callbacks on this node and all ancestors.
+ */
+void v4l2_memtrack_add(struct v4l2_memtrack_node *node, size_t bytes,
+ const char *name);
+
+/**
+ * v4l2_memtrack_sub - Record a memory free
+ * @node: Tracking node
+ * @bytes: Number of bytes freed
+ * @name: Optional name to match (must match what was passed to add)
+ *
+ * Records a memory deallocation. If @name is provided, searches for a
+ * matching internal leaf node (by name and size) and removes it.
+ * If no match is found or @name is NULL, subtracts directly from the
+ * node's counter.
+ *
+ * Triggers notification callbacks on this node and all ancestors.
+ */
+void v4l2_memtrack_sub(struct v4l2_memtrack_node *node, size_t bytes,
+ const char *name);
+
+/**
+ * v4l2_memtrack_set - Set memory usage directly
+ * @node: Tracking node
+ * @bytes: Total bytes to set
+ *
+ * Sets the node's memory counter to the specified value.
+ * Allocation count is set to 1 if bytes > 0, otherwise 0.
+ */
+void v4l2_memtrack_set(struct v4l2_memtrack_node *node, size_t bytes);
+
+/**
+ * v4l2_memtrack_read - Read total memory usage
+ * @node: Tracking node
+ *
+ * Returns the total memory usage of this node plus all its children.
+ *
+ * Return: Total memory usage in bytes
+ */
+size_t v4l2_memtrack_read(struct v4l2_memtrack_node *node);
+
+/**
+ * v4l2_memtrack_register_notify - Register notification callback
+ * @node: Tracking node
+ * @notify: Callback function
+ * @priv: Private data passed to callback
+ *
+ * Register a callback that is called when memory usage changes on this
+ * node or any of its descendants. Only one callback per node is supported.
+ *
+ * Return: 0 on success, -EINVAL if node is invalid, -EBUSY if callback
+ * already registered
+ */
+int v4l2_memtrack_register_notify(struct v4l2_memtrack_node *node,
+ v4l2_memtrack_notify_fn notify,
+ void *priv);
+
+/**
+ * v4l2_memtrack_unregister_notify - Unregister notification callback
+ * @node: The tracking node
+ *
+ * Unregisters the notification callback and waits for any in-progress
+ * callback to complete.
+ *
+ * NOTE: This function MUST be called before v4l2_memtrack_destroy_node()
+ * if a notify callback was registered. Failing to do so will trigger
+ * a WARN and may cause use-after-free.
+ */
+void v4l2_memtrack_unregister_notify(struct v4l2_memtrack_node *node);
+
+/**
+ * v4l2_memtrack_set_notify_delay - Set notification delay
+ * @node: Any node in the tracking tree
+ * @delay_ms: Delay in milliseconds
+ * < 0: disable notifications
+ * = 0: immediate notification (default)
+ * > 0: coalesce notifications within delay period
+ *
+ * Sets the notification delay for the entire tracking tree.
+ * When delay > 0, multiple updates within the delay period are
+ * coalesced into a single notification, reducing overhead for
+ * batch operations.
+ */
+void v4l2_memtrack_set_notify_delay(struct v4l2_memtrack_node *node,
+ int delay_ms);
+
+/**
+ * v4l2_memtrack_print_debug - Print memory usage to kernel log
+ * @node: Tracking node
+ *
+ * Prints the memory usage tree starting from this node using pr_debug().
+ * Supports dynamic debug when CONFIG_DYNAMIC_DEBUG is enabled.
+ *
+ * Enable output with:
+ * echo 'file v4l2-memtrack.c +p' > /sys/kernel/debug/dynamic_debug/control
+ */
+void v4l2_memtrack_print_debug(struct v4l2_memtrack_node *node);
+
+#else /* !CONFIG_V4L2_MEMTRACK */
+
+static inline struct v4l2_memtrack_node *v4l2_memtrack_create_root(const char *name)
+{
+ return NULL;
+}
+
+static inline struct v4l2_memtrack_node *v4l2_memtrack_create_node(
+ struct v4l2_memtrack_node *parent, const char *name)
+{
+ return NULL;
+}
+
+static inline void v4l2_memtrack_destroy_node(struct v4l2_memtrack_node *node) {}
+
+static inline void v4l2_memtrack_add(struct v4l2_memtrack_node *node,
+ size_t bytes, const char *name) {}
+
+static inline void v4l2_memtrack_sub(struct v4l2_memtrack_node *node,
+ size_t bytes, const char *name) {}
+
+static inline void v4l2_memtrack_set(struct v4l2_memtrack_node *node, size_t bytes) {}
+
+static inline size_t v4l2_memtrack_read(struct v4l2_memtrack_node *node)
+{
+ return 0;
+}
+
+static inline int v4l2_memtrack_register_notify(struct v4l2_memtrack_node *node,
+ v4l2_memtrack_notify_fn notify,
+ void *priv)
+{
+ return 0;
+}
+
+static inline void v4l2_memtrack_unregister_notify(struct v4l2_memtrack_node *node) {}
+static inline void v4l2_memtrack_set_notify_delay(struct v4l2_memtrack_node *node, int delay_ms) {}
+static inline void v4l2_memtrack_print_debug(struct v4l2_memtrack_node *node) {}
+
+#endif /* CONFIG_V4L2_MEMTRACK */
+
+#endif /* _V4L2_MEMTRACK_H */
--
2.53.0
^ permalink raw reply related
* [RFC PATCH 5/7] MAINTAINERS: Add entry for V4L2 memory usage tracker
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
In-Reply-To: <20260331072347.253-1-ming.qian@oss.nxp.com>
From: Ming Qian <ming.qian@oss.nxp.com>
Add a MAINTAINERS entry for the V4L2 memory tracking infrastructure,
covering the driver API documentation, core implementation, and header
files.
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
---
MAINTAINERS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 32b1dfee8614..6de2f259415f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27667,6 +27667,14 @@ F: drivers/media/v4l2-core/v4l2-isp.c
F: include/media/v4l2-isp.h
F: include/uapi/linux/media/v4l2-isp.h
+V4L2 MEMORY USAGE TRACKER
+M: Ming Qian <ming.qian@oss.nxp.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/driver-api/media/v4l2-memtrack.rst
+F: drivers/media/common/v4l2-memtrack/v4l2-memtrack.c
+F: include/media/v4l2-memtrack.h
+
VF610 NAND DRIVER
M: Stefan Agner <stefan@agner.ch>
L: linux-mtd@lists.infradead.org
--
2.53.0
^ permalink raw reply related
* [RFC PATCH 6/7] media: videobuf2: Add memory tracking support
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
In-Reply-To: <20260331072347.253-1-ming.qian@oss.nxp.com>
From: Ming Qian <ming.qian@oss.nxp.com>
Add optional memtrack field to vb2_queue for tracking MMAP buffer
memory usage. When a driver sets q->memtrack, the core automatically
tracks allocations via v4l2_memtrack_add/sub calls.
Only MMAP type buffers are tracked since DMABUF memory is allocated
externally by userspace.
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
---
drivers/media/common/videobuf2/videobuf2-core.c | 13 +++++++++++++
include/media/videobuf2-core.h | 4 ++++
2 files changed, 17 insertions(+)
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index adf668b213c2..e42fdf829b22 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -28,6 +28,7 @@
#include <media/videobuf2-core.h>
#include <media/v4l2-mc.h>
+#include <media/v4l2-memtrack.h>
#include <trace/events/vb2.h>
@@ -251,12 +252,19 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
/* Associate allocator private data with this plane */
vb->planes[plane].mem_priv = mem_priv;
+
+ if (q->memtrack)
+ v4l2_memtrack_add(q->memtrack, size, NULL);
}
return 0;
free:
/* Free already allocated memory if one of the allocations failed */
for (; plane > 0; --plane) {
+ unsigned long size = PAGE_ALIGN(vb->planes[plane - 1].length);
+
+ if (q->memtrack)
+ v4l2_memtrack_sub(q->memtrack, size, NULL);
call_void_memop(vb, put, vb->planes[plane - 1].mem_priv);
vb->planes[plane - 1].mem_priv = NULL;
}
@@ -269,9 +277,14 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
*/
static void __vb2_buf_mem_free(struct vb2_buffer *vb)
{
+ struct vb2_queue *q = vb->vb2_queue;
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) {
+ unsigned long size = PAGE_ALIGN(vb->planes[plane].length);
+
+ if (q->memtrack)
+ v4l2_memtrack_sub(q->memtrack, size, NULL);
call_void_memop(vb, put, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
dprintk(vb->vb2_queue, 3, "freed plane %d of buffer %d\n",
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 4424d481d7f7..7cb6ff2fc892 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -47,6 +47,7 @@ enum vb2_memory {
struct vb2_fileio_data;
struct vb2_threadio_data;
struct vb2_buffer;
+struct v4l2_memtrack_node;
/**
* struct vb2_mem_ops - memory handling/memory allocator operations.
@@ -558,6 +559,7 @@ struct vb2_buf_ops {
* driver implements the V4L2_CID_MIN_BUFFERS_FOR_CAPTURE/OUTPUT
* control.
* @alloc_devs: &struct device memory type/allocator-specific per-plane device
+ * @memtrack: optional memory tracking node for debugging and monitoring.
*/
/*
* Private elements (won't appear at the uAPI book):
@@ -632,6 +634,8 @@ struct vb2_queue {
struct device *alloc_devs[VB2_MAX_PLANES];
+ struct v4l2_memtrack_node *memtrack;
+
/* private: internal use only */
struct mutex mmap_lock;
unsigned int memory;
--
2.53.0
^ permalink raw reply related
* [RFC PATCH 7/7] media: amphion: Add V4L2 memory tracking support
From: ming.qian @ 2026-03-31 7:23 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil-cisco, nicolas, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, Frank.li, xiahong.bao,
eagle.zhou, imx, linux-kernel, linux-arm-kernel
In-Reply-To: <20260331072347.253-1-ming.qian@oss.nxp.com>
From: Ming Qian <ming.qian@oss.nxp.com>
Integrate V4L2 memtrack framework to track DMA buffer allocations in the
Amphion VPU driver. Memory usage is organized hierarchically (device ->
instance -> queue) and exposed via V4L2_CID_MEMORY_USAGE control and
debugfs.
Tracked buffers include firmware boot region, RPC, stream ring buffers,
and codec-specific frame buffers (MBI, DCP, enc/ref frames).
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
---
drivers/media/platform/amphion/Kconfig | 1 +
drivers/media/platform/amphion/vdec.c | 9 ++++++
drivers/media/platform/amphion/venc.c | 9 ++++++
drivers/media/platform/amphion/vpu.h | 7 +++++
drivers/media/platform/amphion/vpu_core.c | 6 ++++
drivers/media/platform/amphion/vpu_dbg.c | 5 ++++
drivers/media/platform/amphion/vpu_drv.c | 2 ++
drivers/media/platform/amphion/vpu_v4l2.c | 35 ++++++++++++++++++++++-
8 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/amphion/Kconfig b/drivers/media/platform/amphion/Kconfig
index 4a363e07ccc9..2835c25415c5 100644
--- a/drivers/media/platform/amphion/Kconfig
+++ b/drivers/media/platform/amphion/Kconfig
@@ -12,6 +12,7 @@ config VIDEO_AMPHION_VPU
select V4L2_MEM2MEM_DEV
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_VMALLOC
+ select V4L2_MEMTRACK
help
Amphion VPU Codec IP contains two parts: Windsor and Malone.
Windsor is encoder that supports H.264, and Malone is decoder
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index a9f0521f2e1a..2b863fadb67f 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -279,6 +279,9 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ v4l2_ctrl_new_std(&inst->ctrl_handler, NULL,
+ V4L2_CID_MEMORY_USAGE, 0, S64_MAX, 1, 0);
+
if (inst->ctrl_handler.error) {
ret = inst->ctrl_handler.error;
v4l2_ctrl_handler_free(&inst->ctrl_handler);
@@ -1069,6 +1072,8 @@ static int vdec_alloc_fs_buffer(struct vpu_inst *inst, struct vdec_fs_info *fs)
vpu_free_dma(buffer);
buffer->length = fs->size;
+ buffer->memtrack = inst->memtrack;
+ buffer->label = fs->type == MEM_RES_MBI ? "mbi" : "dcp";
return vpu_alloc_dma(inst->core, buffer);
}
@@ -1683,6 +1688,8 @@ static int vdec_start(struct vpu_inst *inst)
vpu_trace(inst->dev, "[%d]\n", inst->id);
if (!vdec->udata.virt) {
vdec->udata.length = 0x1000;
+ vdec->udata.memtrack = inst->memtrack;
+ vdec->udata.label = "udata";
ret = vpu_alloc_dma(inst->core, &vdec->udata);
if (ret) {
dev_err(inst->dev, "[%d] alloc udata fail\n", inst->id);
@@ -1694,6 +1701,8 @@ static int vdec_start(struct vpu_inst *inst)
stream_buffer_size = vpu_iface_get_stream_buffer_size(inst->core);
if (stream_buffer_size > 0) {
inst->stream_buffer.length = stream_buffer_size;
+ inst->stream_buffer.memtrack = inst->memtrack;
+ inst->stream_buffer.label = "bitstream-ring-buffer";
ret = vpu_alloc_dma(inst->core, &inst->stream_buffer);
if (ret) {
dev_err(inst->dev, "[%d] alloc stream buffer fail\n", inst->id);
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index 0b3d58b9f2f7..193ee488eba4 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -678,6 +678,9 @@ static int venc_ctrl_init(struct vpu_inst *inst)
v4l2_ctrl_new_std(&inst->ctrl_handler, NULL,
V4L2_CID_MPEG_VIDEO_AVERAGE_QP, 0, 51, 1, 0);
+ v4l2_ctrl_new_std(&inst->ctrl_handler, NULL,
+ V4L2_CID_MEMORY_USAGE, 0, S64_MAX, 1, 0);
+
if (inst->ctrl_handler.error) {
ret = inst->ctrl_handler.error;
v4l2_ctrl_handler_free(&inst->ctrl_handler);
@@ -929,6 +932,8 @@ static int venc_start_session(struct vpu_inst *inst, u32 type)
stream_buffer_size = vpu_iface_get_stream_buffer_size(inst->core);
if (stream_buffer_size > 0) {
inst->stream_buffer.length = max_t(u32, stream_buffer_size, venc->cpb_size * 3);
+ inst->stream_buffer.memtrack = inst->memtrack;
+ inst->stream_buffer.label = "bitstream-ring-buffer";
ret = vpu_alloc_dma(inst->core, &inst->stream_buffer);
if (ret)
goto error;
@@ -1027,6 +1032,8 @@ static void venc_request_mem_resource(struct vpu_inst *inst,
for (i = 0; i < enc_frame_num; i++) {
venc->enc[i].length = enc_frame_size;
+ venc->enc[i].memtrack = inst->memtrack;
+ venc->enc[i].label = "enc-frame";
ret = vpu_alloc_dma(inst->core, &venc->enc[i]);
if (ret) {
venc_cleanup_mem_resource(inst);
@@ -1035,6 +1042,8 @@ static void venc_request_mem_resource(struct vpu_inst *inst,
}
for (i = 0; i < ref_frame_num; i++) {
venc->ref[i].length = ref_frame_size;
+ venc->ref[i].memtrack = inst->memtrack;
+ venc->ref[i].label = "ref-frame";
ret = vpu_alloc_dma(inst->core, &venc->ref[i]);
if (ret) {
venc_cleanup_mem_resource(inst);
diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h
index bfd171a3ded4..08913cc54cb1 100644
--- a/drivers/media/platform/amphion/vpu.h
+++ b/drivers/media/platform/amphion/vpu.h
@@ -9,6 +9,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-memtrack.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
#include <linux/kfifo.h>
@@ -17,6 +18,7 @@
#define VPU_TIMEOUT msecs_to_jiffies(1000)
#define VPU_INST_NULL_ID (-1L)
#define VPU_MSG_BUFFER_SIZE (8192)
+#define VPU_NOTIFY_DELAY_MS (200)
enum imx_plat_type {
IMX8QXP = 0,
@@ -47,6 +49,8 @@ struct vpu_buffer {
u32 length;
u32 bytesused;
struct device *dev;
+ struct v4l2_memtrack_node *memtrack;
+ const char *label;
};
struct vpu_func {
@@ -81,6 +85,7 @@ struct vpu_dev {
atomic_t ref_dec;
struct dentry *debugfs;
+ struct v4l2_memtrack_node *memtrack;
};
struct vpu_format {
@@ -279,6 +284,8 @@ struct vpu_inst {
pid_t tgid;
struct dentry *debugfs;
+ struct v4l2_memtrack_node *memtrack;
+
void *priv;
};
diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
index 85cc4a14f8ed..16c2efc86feb 100644
--- a/drivers/media/platform/amphion/vpu_core.c
+++ b/drivers/media/platform/amphion/vpu_core.c
@@ -150,6 +150,8 @@ static int __vpu_alloc_dma(struct device *dev, struct vpu_buffer *buf)
if (!buf->virt)
return -ENOMEM;
+ if (buf->memtrack)
+ v4l2_memtrack_add(buf->memtrack, buf->length, buf->label);
buf->dev = dev;
return 0;
@@ -160,6 +162,8 @@ void vpu_free_dma(struct vpu_buffer *buf)
if (!buf->virt || !buf->dev)
return;
+ if (buf->memtrack)
+ v4l2_memtrack_sub(buf->memtrack, buf->length, buf->label);
dma_free_coherent(buf->dev, buf->length, buf->virt, buf->phys);
buf->virt = NULL;
buf->phys = 0;
@@ -550,6 +554,7 @@ static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np)
core->fw.phys = res.start;
core->fw.length = resource_size(&res);
+ v4l2_memtrack_add(core->vpu->memtrack, core->fw.length, "fw");
ret = of_reserved_mem_region_to_resource(np, 1, &res);
if (ret) {
@@ -559,6 +564,7 @@ static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np)
core->rpc.phys = res.start;
core->rpc.length = resource_size(&res);
+ v4l2_memtrack_add(core->vpu->memtrack, core->rpc.length, "rpc");
if (core->rpc.length < core->res->rpc_size + core->res->fwlog_size) {
dev_err(core->dev, "the rpc-region <%pad, 0x%x> is not enough\n",
diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
index 497ae4e8a229..a82e21cc8a67 100644
--- a/drivers/media/platform/amphion/vpu_dbg.c
+++ b/drivers/media/platform/amphion/vpu_dbg.c
@@ -212,6 +212,11 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
if (seq_write(s, str, num))
return 0;
+ num = scnprintf(str, sizeof(str), "memory usage = %ld\n",
+ v4l2_memtrack_read(inst->memtrack));
+ if (seq_write(s, str, num))
+ return 0;
+
num = scnprintf(str, sizeof(str), "flow :\n");
if (seq_write(s, str, num))
return 0;
diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c
index 2cca61f41bea..73e01c55da82 100644
--- a/drivers/media/platform/amphion/vpu_drv.c
+++ b/drivers/media/platform/amphion/vpu_drv.c
@@ -138,6 +138,7 @@ static int vpu_probe(struct platform_device *pdev)
if (ret)
goto err_vpu_media;
vpu->debugfs = debugfs_create_dir("amphion_vpu", NULL);
+ vpu->memtrack = v4l2_memtrack_create_root("amphion-vpu");
of_platform_populate(dev->of_node, NULL, NULL, dev);
@@ -162,6 +163,7 @@ static void vpu_remove(struct platform_device *pdev)
struct vpu_dev *vpu = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
+ v4l2_memtrack_destroy_node(vpu->memtrack);
debugfs_remove_recursive(vpu->debugfs);
vpu->debugfs = NULL;
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index 7cccc994fc50..431f5f64e683 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -651,6 +651,14 @@ static const struct vb2_ops vpu_vb2_ops = {
.buf_queue = vpu_vb2_buf_queue,
};
+static void vpu_memtrack_ctrl_notify(struct v4l2_memtrack_node *node, size_t total, void *priv)
+{
+ struct v4l2_ctrl *ctrl = priv;
+
+ if (ctrl)
+ v4l2_ctrl_s_ctrl_int64(ctrl, total);
+}
+
static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
{
struct vpu_inst *inst = priv;
@@ -668,9 +676,13 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
src_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
src_vq->dev = inst->vpu->dev;
src_vq->lock = &inst->lock;
+ if (inst->memtrack)
+ src_vq->memtrack = v4l2_memtrack_create_node(inst->memtrack, "output");
ret = vb2_queue_init(src_vq);
- if (ret)
+ if (ret) {
+ v4l2_memtrack_destroy_node(src_vq->memtrack);
return ret;
+ }
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
inst->cap_format.type = dst_vq->type;
@@ -684,8 +696,12 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
dst_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
dst_vq->dev = inst->vpu->dev;
dst_vq->lock = &inst->lock;
+ if (inst->memtrack)
+ dst_vq->memtrack = v4l2_memtrack_create_node(inst->memtrack, "capture");
ret = vb2_queue_init(dst_vq);
if (ret) {
+ v4l2_memtrack_destroy_node(src_vq->memtrack);
+ v4l2_memtrack_destroy_node(dst_vq->memtrack);
vb2_queue_release(src_vq);
return ret;
}
@@ -706,6 +722,12 @@ static int vpu_v4l2_release(struct vpu_inst *inst)
vpu_release_core(inst->core);
put_device(inst->dev);
+ if (inst->memtrack) {
+ v4l2_memtrack_unregister_notify(inst->memtrack);
+ v4l2_memtrack_destroy_node(inst->memtrack);
+ inst->memtrack = NULL;
+ }
+
v4l2_ctrl_handler_free(&inst->ctrl_handler);
mutex_destroy(&inst->lock);
@@ -745,6 +767,8 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst)
inst->min_buffer_out = 2;
v4l2_fh_init(&inst->fh, func->vfd);
v4l2_fh_add(&inst->fh, file);
+ if (vpu->memtrack)
+ inst->memtrack = v4l2_memtrack_create_node(vpu->memtrack, "instance");
ret = call_vop(inst, ctrl_init);
if (ret)
@@ -757,6 +781,14 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst)
goto error;
}
+ if (inst->memtrack) {
+ v4l2_memtrack_set_notify_delay(inst->memtrack, VPU_NOTIFY_DELAY_MS);
+ v4l2_memtrack_register_notify(inst->memtrack,
+ vpu_memtrack_ctrl_notify,
+ v4l2_ctrl_find(&inst->ctrl_handler,
+ V4L2_CID_MEMORY_USAGE));
+ }
+
inst->fh.ctrl_handler = &inst->ctrl_handler;
inst->state = VPU_CODEC_STATE_DEINIT;
inst->workqueue = alloc_ordered_workqueue("vpu_inst", WQ_MEM_RECLAIM);
@@ -775,6 +807,7 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst)
return 0;
error:
+ v4l2_memtrack_destroy_node(inst->memtrack);
v4l2_fh_del(&inst->fh, file);
v4l2_fh_exit(&inst->fh);
vpu_inst_put(inst);
--
2.53.0
^ permalink raw reply related
* [PATCH] soc: apple: cleanup dead code in Kconfig
From: Julian Braha @ 2026-03-31 7:28 UTC (permalink / raw)
To: sven, j, neal; +Cc: asahi, linux-arm-kernel, linux-kernel, Julian Braha
There is already an 'if ARCH_APPLE || COMPILE_TEST' condition wrapping
these config options, making the 'depends on' statement for each a
duplicate dependency (dead code).
I propose leaving the outer 'if ARCH_APPLE || COMPILE_TEST...endif' and
removing the individual 'depends on' statement from each option.
This dead code was found by kconfirm, a static analysis tool for Kconfig.
Signed-off-by: Julian Braha <julianbraha@gmail.com>
---
drivers/soc/apple/Kconfig | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig
index d0ff32182a2b..e04a60722e0b 100644
--- a/drivers/soc/apple/Kconfig
+++ b/drivers/soc/apple/Kconfig
@@ -7,7 +7,7 @@ menu "Apple SoC drivers"
config APPLE_MAILBOX
tristate "Apple SoC mailboxes"
depends on PM
- depends on ARCH_APPLE || (64BIT && COMPILE_TEST)
+ depends on 64BIT
help
Apple SoCs have various co-processors required for certain
peripherals to work (NVMe, display controller, etc.). This
@@ -19,7 +19,6 @@ config APPLE_MAILBOX
config APPLE_RTKIT
tristate "Apple RTKit co-processor IPC protocol"
depends on APPLE_MAILBOX
- depends on ARCH_APPLE || COMPILE_TEST
help
Apple SoCs such as the M1 come with various co-processors running
their proprietary RTKit operating system. This option enables support
@@ -30,7 +29,6 @@ config APPLE_RTKIT
config APPLE_SART
tristate "Apple SART DMA address filter"
- depends on ARCH_APPLE || COMPILE_TEST
help
Apple SART is a simple DMA address filter used on Apple SoCs such
as the M1. It is usually required for the NVMe coprocessor which does
@@ -40,8 +38,7 @@ config APPLE_SART
config APPLE_TUNABLE
tristate
- depends on ARCH_APPLE || COMPILE_TEST
endmenu
-endif
+endif # ARCH_APPLE || COMPILE_TEST
--
2.51.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox