Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2] dt-bindings: misc: qcom,fastrpc: Add Maili FastRPC compatible
From: Krzysztof Kozlowski @ 2026-06-08  8:04 UTC (permalink / raw)
  To: Yijie Yang
  Cc: Srinivas Kandagatla, Amol Maheshwari, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, dri-devel,
	devicetree, linux-kernel
In-Reply-To: <20260602-fastrpc-v2-1-67a55e22427b@oss.qualcomm.com>

On Tue, Jun 02, 2026 at 02:51:08PM +0800, Yijie Yang wrote:
> Document compatible string for the FastRPC interface on the Qualcomm Maili
> SoC, which is compatible with the Qualcomm Kaanapali FastRPC and can
> fallback to Kaanapali.
> 
> Signed-off-by: Yijie Yang <yijie.yang@oss.qualcomm.com>

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v2] dt-bindings: interconnect: qcom-bwmon: Add Maili cpu-bwmon compatible
From: Krzysztof Kozlowski @ 2026-06-08  8:02 UTC (permalink / raw)
  To: Yijie Yang
  Cc: Georgi Djakov, Rob Herring, Conor Dooley, linux-arm-msm, linux-pm,
	devicetree, linux-kernel
In-Reply-To: <20260602-bwmon-v2-1-d4a851c45f37@oss.qualcomm.com>

On Tue, Jun 02, 2026 at 02:54:13PM +0800, Yijie Yang wrote:
> Add the Qualcomm Maili SoC compatible string for the CPU bandwidth
> monitor (BWMONv4). This falls back to the sdm845-bwmon compatible,
> consistent with the existing pattern used by other recent SoCs such as
> sm8750 and kaanapali.
> 
> Signed-off-by: Yijie Yang <yijie.yang@oss.qualcomm.com>
> ---
> Changes in v2:
> - Drop Assisted-by tag; no functional change.
> - Link to v1: https://patch.msgid.link/20260525-bwmon-v1-1-b8f6e189c3e3@oss.qualcomm.com

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Best regards,
Krzysztof


^ permalink raw reply

* Re: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
From: Midgy Balon @ 2026-06-08  8:05 UTC (permalink / raw)
  To: Chaoyi Chen
  Cc: tomeu, ogabbay, heiko, robh, krzk+dt, conor+dt, joro, will,
	robin.murphy, dri-devel, linux-rockchip, devicetree,
	linux-arm-kernel, iommu, linux-kernel, Simon Xue, Finley Xiao
In-Reply-To: <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>

Hello Chaoyi,

Thanks -- this is exactly what I needed.

- v2/DTE: will do. I'll keep building on Simon's per-device-ops series -- with
  that in place the NPU MMU can use the 32-bit-DTE ops (the per-ops GFP_DMA32
  that's already in mainline) without the global rk_ops conflict. I'll
keep it as
  a stated dependency of the v4 cover letter.

- vdd_npu:  I'll switch the RK3568 NPU
  power domain to need_regulator + domain-supply = <&vdd_npu> and drop the
  regulator-always-on workaround. I suspect that's also the right fix for the
  power-off/on de-idle issue I described -- the always-on was really
just papering
  over the domain not being modelled with a regulator. I'll confirm on
the board.

- AUTO_GATING: thanks for the commit references -- I'll keep the bit-31
  read-modify-write form with your Suggested-by and write the comment
from those.
  For the record: on v7.1-rc6 the NPU MMU also completes translations
on the reset
  value (I couldn't reproduce a page-walk stall without the write), so I'll note
  in the commit that it matches the vendor clock-gating handling rather than
  fixing a failure I can reproduce here -- happy to drop it if the iommu
  maintainers would prefer.

- PVTPLL/NoC: I'll follow up with Finley. First I'll check whether the
  need_regulator change resolves the NoC re-power de-idle on its own;
if it still
  I'll bring him the details (the genpd power-on de-idle ack and the
  BUS_IDLE_ST state).

I'll send a v4 with these. Thanks again for the quick, detailed answers.

Kind regards,
Midgy

Le lun. 8 juin 2026 à 03:40, Chaoyi Chen <chaoyi.chen@rock-chips.com> a écrit :
>
> Hi Midgy,
>
> On 6/8/2026 5:03 AM, Midgy Balon wrote:
> > Hi Chaoyi,
> >
> > Thanks a lot for looking at this -- input from Rockchip is exactly what this
> > series needs.
> >
> >> Hmmm. If I understand correctly, the NPU IOMMU should be v2 rather than v1,
> >> implying it should support 40-bit PAs. Nevertheless, please note that the
> >> upper limit for DTE is 32 bits.
> >
> > Understood, and that 32-bit-DTE note is the crux of the trouble I had, so let
> > me lay out what I see and ask how you'd prefer to solve it.
> >
> > The mainline node is already v2 (rockchip,rk3568-iommu in rk356x-base.dtsi).
> > The problem on this 8 GiB board: with the v2 ops the page-table allocations
> > (gfp_flags == 0) can land above 4 GiB, so the DTE ends up > 32 bits and the
> > NPU's first translation faults with DMA_READ_ERROR. To work around that I had
> > switched the NPU MMU to the v1 compatible (rockchip,iommu), whose ops set
> > GFP_DMA32 and keep the DTE sub-4 GiB. That works in isolation, but because the
> > driver keeps a single global rk_ops, a v1 NPU MMU then trips
> > WARN_ON(rk_ops != ops) against the SoC's v2 instances (VOP/VDEC), which is why
> > I based the series on Simon's per-device-ops work.
> >
> > So my question: with per-device ops in place, what's the intended way to keep
> > the NPU MMU on v2 *and* cap its DTE at 32 bits on boards with >4 GiB of RAM?
> > A v2 ops variant carrying GFP_DMA32 for this device, or is there a register/
> > config bit that constrains the DTE address? I'd rather follow the Rockchip
> > intent here than carry the v1 workaround. (Simon, cc'd -- this is right next to
> > your per-device-ops series.)
> >
>
> If Simon's method works, please use it :)
>
> >> Can these operations not be completed via the pmdomain driver?
> >> If some operations are controlled by TF-A, are you using open source TF-A?
> >
> > Most of it is in pmdomain already. Power-on and NoC de-idle are done by the
> > RK3568 NPU power domain (genpd) at power-on -- the driver no longer pokes the
> > PMU directly. Two things remain outside it:
> >
> >  - vdd_npu: I mark it regulator-always-on in DT rather than wiring it as the
> >    domain's domain-supply, because as a domain-supply it created a device-link
> >    to the I2C PMIC (rk809) and genpd's power-off QoS-save path then hung
> >    reading the NPU QoS registers behind the (gated) NoC. If there's a clean way
> >    to let genpd own vdd_npu without that I2C ordering deadlock I'd much prefer
> >    that -- pointers welcome.
> >
>
> Please refer to the patch below regarding the RK3588 NPU pmdomain.
> In short, you need to set a "need_regulator" for the RK3568 NPU pmdomain.
>
> https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb@gmail.com/
>
> >  - the NPU compute clock (PVTPLL): set from the driver via SCMI, and only
> >    needed for actual compute, not for bring-up.
> >
> > One more pmdomain observation from testing, possibly relevant to how the NPU
> > domain should be modelled: the domain's power-off/on cycle doesn't reliably
> > re-de-idle the NoC. If the NPU is probed after genpd has already powered the
> > (unused) domain off, the power-on de-idle fails ("failed to set idle on domain
> > 'npu'") and the NPU IOMMU then takes an external abort on its first MMIO access.
> > Probing the NPU before the unused-domain power-off, or marking the domain
> > always-on, both avoid it. Is the NoC de-idle expected to work on a genpd
> > re-power here, or should this domain effectively stay on?
> >
>
> Not quite sure what's going on with PVTPLL and NOC.
> Maybe @Finley knows about this?
>
> > On TF-A: yes -- bl31 is built from upstream arm-trusted-firmware
> > (github.com/ARM-software/arm-trusted-firmware, RK3568 platform), providing PSCI
> > and the SCMI clock service. The only closed blob in the boot chain is Rockchip's
> > DDR init (rkbin), which is the standard situation for mainline RK356x.
>
> --
> Best,
> Chaoyi

^ permalink raw reply

* Re: [PATCH v3 1/5] dt-bindings: display: verisilicon,dc: generalize for single-output variants
From: Krzysztof Kozlowski @ 2026-06-08  8:02 UTC (permalink / raw)
  To: Joey Lu
  Cc: zhengxingda, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, ychuang3, schung, yclu4,
	dri-devel, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20260608023237.305036-2-a0987203069@gmail.com>

On Mon, Jun 08, 2026 at 10:32:33AM +0800, Joey Lu wrote:
> The existing schema hard-codes the five-clock/three-reset/dual-port
> topology of the DC8200 IP block, preventing reuse for single-output
> variants such as the Verisilicon DCUltraLite used in the Nuvoton MA35D1
> SoC.
> 
> Rework the schema so that variant-specific constraints are expressed via
> allOf/if blocks:
> 
> - Add nuvoton,ma35d1-dcu to the SoC-specific compatible enum.  The
>   generic verisilicon,dc fallback remains the driver-binding string.
> - Relax the top-level clocks/resets definitions to minItems ranges so
>   the base schema accepts both variants.
> - Keep ports in the global required list and keep additionalProperties
>   tightened to unevaluatedProperties.
> - Add an allOf/if block for thead,th1520-dc8200: five-clock (core, axi,
>   ahb, pix0, pix1), three-reset (core, axi, ahb).
> - Add an allOf/if block for nuvoton,ma35d1-dcu: two-clock (core, pix0),
>   one-reset (core).
> - Fix a stray space in the port@0 description.
> - Add a DT example for the Nuvoton MA35D1 DCU Lite using ports/port@0.

Difference in clocks and resets does not need a new new example.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v3 1/5] dt-bindings: display: verisilicon,dc: generalize for single-output variants
From: Krzysztof Kozlowski @ 2026-06-08  8:00 UTC (permalink / raw)
  To: Joey Lu
  Cc: zhengxingda, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, ychuang3, schung, yclu4,
	dri-devel, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20260608023237.305036-2-a0987203069@gmail.com>

On Mon, Jun 08, 2026 at 10:32:33AM +0800, Joey Lu wrote:
> The existing schema hard-codes the five-clock/three-reset/dual-port
> topology of the DC8200 IP block, preventing reuse for single-output
> variants such as the Verisilicon DCUltraLite used in the Nuvoton MA35D1
> SoC.
> 
> Rework the schema so that variant-specific constraints are expressed via
> allOf/if blocks:
> 
> - Add nuvoton,ma35d1-dcu to the SoC-specific compatible enum.  The
>   generic verisilicon,dc fallback remains the driver-binding string.
> - Relax the top-level clocks/resets definitions to minItems ranges so
>   the base schema accepts both variants.
> - Keep ports in the global required list and keep additionalProperties
>   tightened to unevaluatedProperties.
> - Add an allOf/if block for thead,th1520-dc8200: five-clock (core, axi,
>   ahb, pix0, pix1), three-reset (core, axi, ahb).
> - Add an allOf/if block for nuvoton,ma35d1-dcu: two-clock (core, pix0),
>   one-reset (core).
> - Fix a stray space in the port@0 description.
> - Add a DT example for the Nuvoton MA35D1 DCU Lite using ports/port@0.
> 
> Signed-off-by: Joey Lu <a0987203069@gmail.com>
> ---
>  .../bindings/display/verisilicon,dc.yaml      | 103 +++++++++++++++---
>  1 file changed, 90 insertions(+), 13 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/verisilicon,dc.yaml b/Documentation/devicetree/bindings/display/verisilicon,dc.yaml
> index 9dc35ab973f2..db0260d874c5 100644
> --- a/Documentation/devicetree/bindings/display/verisilicon,dc.yaml
> +++ b/Documentation/devicetree/bindings/display/verisilicon,dc.yaml
> @@ -17,7 +17,8 @@ properties:
>      items:
>        - enum:
>            - thead,th1520-dc8200
> -      - const: verisilicon,dc # DC IPs have discoverable ID/revision registers
> +          - nuvoton,ma35d1-dcu
> +      - const: verisilicon,dc  # DC IPs have discoverable ID/revision registers

Why do you need to change indentation? Why introducing irrelevant
changes to the diff?

>  
>    reg:
>      maxItems: 1
> @@ -26,6 +27,7 @@ properties:
>      maxItems: 1
>  
>    clocks:
> +    minItems: 2
>      items:
>        - description: DC Core clock
>        - description: DMA AXI bus clock

That's not true anymore. In such case the list should also be defined
per variant and here only min/maxItems.


> @@ -34,24 +36,19 @@ properties:
>        - description: Pixel clock of output 1
>  
>    clock-names:
> -    items:
> -      - const: core
> -      - const: axi
> -      - const: ahb
> -      - const: pix0
> -      - const: pix1
> +    minItems: 2
> +    maxItems: 5
>  
>    resets:
> +    minItems: 1
>      items:
>        - description: DC Core reset
>        - description: DMA AXI bus reset
>        - description: Configuration AHB bus reset
>  
>    reset-names:
> -    items:
> -      - const: core
> -      - const: axi
> -      - const: ahb

This stays, with minItems. Variants only need min/maxItems



> +    minItems: 1
> +    maxItems: 3
>  
>    ports:
>      $ref: /schemas/graph.yaml#/properties/ports
> @@ -59,7 +56,7 @@ properties:
>      properties:
>        port@0:
>          $ref: /schemas/graph.yaml#/properties/port
> -        description: The first output channel , endpoint 0 should be
> +        description: The first output channel, endpoint 0 should be
>            used for DPI format output and endpoint 1 should be used
>            for DP format output.
>  
> @@ -77,7 +74,60 @@ required:
>    - clock-names
>    - ports
>  
> -additionalProperties: false
> +allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: thead,th1520-dc8200
> +    then:
> +      properties:
> +        clocks:
> +          minItems: 5
> +          maxItems: 5
> +
> +        clock-names:
> +          items:
> +            - const: core
> +            - const: axi
> +            - const: ahb
> +            - const: pix0
> +            - const: pix1
> +
> +        resets:
> +          minItems: 3
> +          maxItems: 3
> +
> +        reset-names:

minItems: 3

> +          items:
> +            - const: core
> +            - const: axi
> +            - const: ahb
> +
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: nuvoton,ma35d1-dcu
> +    then:
> +      properties:
> +        clocks:
> +          minItems: 2
> +          maxItems: 2
> +
> +        clock-names:
> +          items:
> +            - const: core
> +            - const: pix0
> +
> +        resets:
> +          maxItems: 1
> +
> +        reset-names:

maxItems: 1

> +          items:
> +            - const: core
> +
> +unevaluatedProperties: false

Stop making random changes to the binding.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe Ethernet
From: Krzysztof Kozlowski @ 2026-06-08  7:57 UTC (permalink / raw)
  To: Ricardo Pardini
  Cc: Heiner Kallweit, nic_swsd, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Sebastian Reichel, netdev, devicetree, linux-kernel,
	linux-arm-kernel, linux-rockchip
In-Reply-To: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>

On Fri, Jun 05, 2026 at 01:49:08PM +0200, Ricardo Pardini wrote:
> Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
> driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).
> 
> The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
> spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
> need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
> compatibles documented in their own bindings (e.g. microchip,lan95xx)
> so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
> these PCI function nodes can be validated.
> 
> Suggested-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> Signed-off-by: Ricardo Pardini <ricardo@pardini.net>
> ---
>  .../devicetree/bindings/net/realtek,r8169.yaml     | 54 ++++++++++++++++++++++
>  MAINTAINERS                                        |  1 +
>  2 files changed, 55 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/realtek,r8169.yaml b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
> new file mode 100644
> index 0000000000000..6923211ff4c93
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/realtek,r8169.yaml

r8169 but no r8169 devices at all. This must match the device name, so
most likely:

realtek,rtl8168.yaml


> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/realtek,r8169.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Realtek r8169 family PCIe Ethernet Controllers

rtl8169? 8168? There is no r8169, is there?

> +
> +maintainers:
> +  - Heiner Kallweit <hkallweit1@gmail.com>
> +
> +description:
> +  PCI function node properties for fixed/soldered Realtek Ethernet
> +  controllers driven by the r8169 driver.

Describe hardware, not drivers.


> +
> +allOf:
> +  - $ref: ethernet-controller.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - pci10ec,8125  # RTL8125 2.5GbE
> +      - pci10ec,8126  # RTL8126 5GbE
> +      - pci10ec,8127  # RTL8127
> +      - pci10ec,8161  # RTL8168 variant
> +      - pci10ec,8162  # RTL8168 variant
> +      - pci10ec,8168  # RTL8168/8111 GbE
> +
> +  reg:
> +    maxItems: 1
> +
> +  local-mac-address: true
> +  mac-address: true
> +  nvmem-cells: true
> +  nvmem-cell-names: true

Drop all above

> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false

uneavaluatedProperties instead

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
From: sashiko-bot @ 2026-06-08  7:57 UTC (permalink / raw)
  To: Jia Wang via B4 Relay; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260608-ultrarisc-pinctrl-v3-1-30a09ed74275@ultrarisc.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The newly added dt-bindings header file is not tracked in the MAINTAINERS entry.
--

commit f7f86b1233735eea88a3047d747f41d13c3dc00b
Author: Jia Wang <wangjia@ultrarisc.com>

dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller

This commit adds device tree binding documentation for the pin controllers 
on the UltraRISC DP1000 RISC-V SoC. It also introduces a new header file 
containing the corresponding pin definitions.

> diff --git a/MAINTAINERS b/MAINTAINERS
> --- a/MAINTAINERS
> +++ b/MAINTAINERS

[ ... ]

> @@ -27357,6 +27357,12 @@ S:	Maintained
>  F:	drivers/usb/common/ulpi.c
>  F:	include/linux/ulpi/
>  
> +ULTRARISC DP1000 PINCTRL DRIVER
> +M:	Jia Wang <wangjia@ultrarisc.com>
> +L:	linux-gpio@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
> +

[Severity: Low]
This isn't a bug, but should the new header file
include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h be added to this
MAINTAINERS block as well? Without it, get_maintainer.pl might miss CCing
the maintainer on future patches that modify the pin definitions.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608-ultrarisc-pinctrl-v3-0-30a09ed74275@ultrarisc.com?part=1

^ permalink raw reply

* Re: [PATCH v16 04/10] arm64: kexec_file: Use crash_prepare_headers() helper to simplify code
From: sashiko-bot @ 2026-06-08  7:56 UTC (permalink / raw)
  To: Jinjie Ruan; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260608073459.3119290-5-ruanjinjie@huawei.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Lockless memblock iteration in `arch_get_system_nr_ranges()` and `arch_crash_populate_cmem()` can lead to TOCTOU buffer overflow and Use-After-Free due to concurrent memory hotplug.
--

commit 3445143d0dcc2150e57d4b72a58250e2bbaf7ea7
Author: Jinjie Ruan <ruanjinjie@huawei.com>

arm64: kexec_file: Use crash_prepare_headers() helper to simplify code

This commit replaces the existing prepare_elf_headers() with the newly
introduced crash_prepare_headers() function. It implements the two required
architecture functions, arch_get_system_nr_ranges() and
arch_crash_populate_cmem(), to traverse and populate memory ranges.

> diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
> index e31fabed378a5..b019b31df48cb 100644
> --- a/arch/arm64/kernel/machine_kexec_file.c
> +++ b/arch/arm64/kernel/machine_kexec_file.c
[ ... ]
> -static int prepare_elf_headers(void **addr, unsigned long *sz)
> +unsigned int arch_get_system_nr_ranges(void)
>  {
> -	struct crash_mem *cmem;
> -	unsigned int nr_ranges;
> -	int ret;
> -	u64 i;
> +	unsigned int nr_ranges = 2; /* for exclusion of crashkernel region */
>  	phys_addr_t start, end;
> +	u64 i;
>  
> -	nr_ranges = 2; /* for exclusion of crashkernel region */
>  	for_each_mem_range(i, &start, &end)
>  		nr_ranges++;
>  
> -	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
> -	if (!cmem)
> -		return -ENOMEM;
> +	return nr_ranges;
> +}
> +
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
> +{
> +	phys_addr_t start, end;
> +	u64 i;
>  
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
>  	for_each_mem_range(i, &start, &end) {
>  		cmem->ranges[cmem->nr_ranges].start = start;
>  		cmem->ranges[cmem->nr_ranges].end = end - 1;
>  		cmem->nr_ranges++;
>  	}

[Severity: High]
This isn't a bug introduced by this patch, but could this lockless memblock
iteration lead to a TOCTOU buffer overflow or use-after-free during
concurrent memory hotplug?

arch_get_system_nr_ranges() locklessly calculates the max_nr_ranges used to
allocate cmem. If memory is hot-plugged between this calculation and the
array population here in arch_crash_populate_cmem(), could the second loop
encounter more regions than initially allocated? 

Because there is no bounds check against cmem->max_nr_ranges, could this
result in an out-of-bounds write past the flexible cmem->ranges array?

Additionally, memory hotplug calls memblock_add_node(), which can invoke
memblock_double_array(). This function reallocates memblock.memory.regions
and frees the old array. If this reallocation occurs while
for_each_mem_range() is iterating in either function, could the lockless
iteration dereference a freed regions array?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie@huawei.com?part=4

^ permalink raw reply

* Re: [PATCH v16 06/10] riscv: kexec_file: Use crash_prepare_headers() helper to simplify code
From: sashiko-bot @ 2026-06-08  7:54 UTC (permalink / raw)
  To: Jinjie Ruan; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260608073459.3119290-7-ruanjinjie@huawei.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] A Time-of-Check to Time-of-Use (TOCTOU) race condition in kexec segment preparation can cause a heap buffer overflow if memory hotplug occurs.
--

commit b23452d9853c692b4f51771e551dbfc49512243d
Author: Jinjie Ruan <ruanjinjie@huawei.com>

riscv: kexec_file: Use crash_prepare_headers() helper to simplify code

This patch simplifies the kexec_file code for RISC-V by using the newly
introduced crash_prepare_headers() helper. It replaces the architecture
specific prepare_elf_headers() with arch_get_system_nr_ranges() and
arch_crash_populate_cmem() to reduce code duplication.

> diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
> index 3f7766057cac3..439cbc50dfa69 100644
> --- a/arch/riscv/kernel/machine_kexec_file.c
> +++ b/arch/riscv/kernel/machine_kexec_file.c
[ ... ]
> @@ -55,41 +64,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
>  	return 0;
>  }
>  
> -static int prepare_elf_headers(void **addr, unsigned long *sz)
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
>  {
> -	struct crash_mem *cmem;
> -	unsigned int nr_ranges;
> -	int ret;
> -
> -	nr_ranges = 2; /* For exclusion of crashkernel region */
> -	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> -
> -	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
> -	if (!cmem)
> -		return -ENOMEM;
> -
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
> -	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
> -	if (ret)
> -		goto out;
> -
[ ... ]
> +	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
>  }

[Severity: High]
This is a pre-existing issue, but can this code suffer from a Time-of-Check
to Time-of-Use race condition during memory hotplug?

The crash_prepare_headers() helper in kernel/crash_core.c uses a lockless
two-pass sequence:

kernel/crash_core.c:crash_prepare_headers() {
    ...
    max_nr_ranges = arch_get_system_nr_ranges();
    ...
    cmem = alloc_cmem(max_nr_ranges);
    ...
    ret = arch_crash_populate_cmem(cmem);
    ...
}

Since the kexec syscall does not hold mem_hotplug_lock or use
get_online_mems(), could a concurrent memory hotplug event call add_memory()
and insert a new resource into the system RAM resource tree between the two
passes?

If that happens, the second walk_system_ram_res() pass in
arch_crash_populate_cmem() would encounter the newly inserted memory range.
This would cause it to execute prepare_elf64_ram_headers_callback() more
times than initially counted.

Because prepare_elf64_ram_headers_callback() unconditionally writes to
cmem->ranges[cmem->nr_ranges] without verifying that
cmem->nr_ranges < cmem->max_nr_ranges, would this result in an out-of-bounds
write that corrupts adjacent heap memory?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie@huawei.com?part=6

^ permalink raw reply

* Re: [PATCH net-next v4 15/16] dt-bindings: net: add onsemi's S2500
From: Krzysztof Kozlowski @ 2026-06-08  7:53 UTC (permalink / raw)
  To: Selvamani Rajagopal
  Cc: Andrew Lunn, Piergiorgio Beruto, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, Parthiban Veerasooran, Richard Cochran, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Simon Horman, Jonathan Corbet,
	Shuah Khan, netdev, linux-kernel, devicetree, linux-doc,
	Jerry Ray
In-Reply-To: <20260605-s2500-mac-phy-support-v4-15-de0fbc13c6d8@onsemi.com>

On Fri, Jun 05, 2026 at 10:42:46PM -0700, Selvamani Rajagopal wrote:
> Add YAML device tree binding for the onsemi S2500 IEEE 802.3cg
> compliant Ethernet transceiver device.
> 
> We use IRQF_TRIGGER_FALLING, though OPEN Alliance 10BASE-T1x
> Serial Interface specification calls for IRQF_TRIGGER_LOW.

Ah, and keep correct order of patches.

Please organize the patch documenting the compatible (DT bindings)
before the patch using that compatible.
See also: https://elixir.bootlin.com/linux/v6.14-rc6/source/Documentation/devicetree/bindings/submitting-patches.rst#L46

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v16 07/10] LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify code
From: sashiko-bot @ 2026-06-08  7:52 UTC (permalink / raw)
  To: Jinjie Ruan; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260608073459.3119290-8-ruanjinjie@huawei.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] A time-of-check to time-of-use (TOCTOU) race condition exists between arch_get_system_nr_ranges() and arch_crash_populate_cmem() against concurrent memory hotplug, potentially causing a buffer overflow or Use-After-Free.
--

commit e15fd7173b2be430036c153dea51e26db1b14d57
Author: Jinjie Ruan <ruanjinjie@huawei.com>

LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify code

This commit replaces prepare_elf_headers() with the generic
crash_prepare_headers() helper to simplify crash memory handling. It implements
arch_get_system_nr_ranges() to count memory ranges and
arch_crash_populate_cmem() to fill them.

> diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
> index 5584b798ba464..5412aa9f35687 100644
> --- a/arch/loongarch/kernel/machine_kexec_file.c
> +++ b/arch/loongarch/kernel/machine_kexec_file.c
[ ... ]
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
> +{
> +	phys_addr_t start, end;
> +	uint64_t i;
>  
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
>  	for_each_mem_range(i, &start, &end) {
>  		cmem->ranges[cmem->nr_ranges].start = start;
>  		cmem->ranges[cmem->nr_ranges].end = end - 1;
>  		cmem->nr_ranges++;
>  	}

[Severity: High]
This is a pre-existing issue, but is there a risk of a time-of-check to
time-of-use (TOCTOU) race condition here against concurrent memory hotplug?

Because sys_kexec_file_load() acquires kexec_mutex but does not hold memory
hotplug locks (e.g., mem_hotplug_begin()) or cpus_read_lock(), concurrent
memory hotplug events like add_memory_resource() could occur.

The generic crash_prepare_headers() separates counting and population:

kernel/crash_core.c:crash_prepare_headers() {
    ...
    max_nr_ranges = arch_get_system_nr_ranges();
    if (!max_nr_ranges)
        return -ENOMEM;
    
    cmem = alloc_cmem(max_nr_ranges);
    ...
    ret = arch_crash_populate_cmem(cmem);
    ...
}

If memblock regions are added dynamically between the time max_nr_ranges is
calculated and the cmem->ranges array is populated in
arch_crash_populate_cmem(), won't the loop above iterate more times than
max_nr_ranges and blindly write out-of-bounds to the flexible ranges array?

Additionally, could a concurrent memblock_add_node() trigger a
memblock_double_array(), which reallocates the regions array and frees the
old one, resulting in a use-after-free while for_each_mem_range() is
traversing it?

> +	return 0;
>  }
>  
>  /*

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie@huawei.com?part=7

^ permalink raw reply

* Re: [PATCH net-next v4 15/16] dt-bindings: net: add onsemi's S2500
From: Krzysztof Kozlowski @ 2026-06-08  7:52 UTC (permalink / raw)
  To: Selvamani Rajagopal
  Cc: Andrew Lunn, Piergiorgio Beruto, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, Parthiban Veerasooran, Richard Cochran, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Simon Horman, Jonathan Corbet,
	Shuah Khan, netdev, linux-kernel, devicetree, linux-doc,
	Jerry Ray
In-Reply-To: <20260605-s2500-mac-phy-support-v4-15-de0fbc13c6d8@onsemi.com>

On Fri, Jun 05, 2026 at 10:42:46PM -0700, Selvamani Rajagopal wrote:
> Add YAML device tree binding for the onsemi S2500 IEEE 802.3cg

s/YAML//

> compliant Ethernet transceiver device.
> 
> We use IRQF_TRIGGER_FALLING, though OPEN Alliance 10BASE-T1x
> Serial Interface specification calls for IRQF_TRIGGER_LOW.
> 
> This is to match IRQF_TRIGGER_FALLING used by OA TC6 framework code.
> This bug fix requires changes to the stable branch. At that time,
> this will be changed to IRQF_TRIGGER_LOW.
> 
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Best regards,
Krzysztof


^ permalink raw reply

* [PATCH v3 0/2] pinctrl: ultrarisc: add DP1000 pinctrl support
From: Jia Wang via B4 Relay @ 2026-06-08  7:50 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bartosz Golaszewski
  Cc: linux-gpio, devicetree, linux-kernel, Jia Wang

This series adds the devicetree schema and the pinctrl driver for the
DP1000 controller using generic pinctrl bindings.

Compared with v1, this series is narrowed down to the pinctrl binding
and driver only. v1 patches 1, 2, 3, 5, 7, 8, and 9 (vendor prefix,
CPU/SoC bindings, DTS files, and defconfig update) are not included in
v2 and will be sent separately.

Note:
- ARCH_ULTRARISC support is being reviewed separately:
  * Link: https://lore.kernel.org/lkml/20260427-ultrarisc-pcie-v4-1-98935f6cdfb5@ultrarisc.com/

Testing:
- dt_binding_check and yamllint
- Kernel build for RISC-V and boot-tested on DP1000 (Milk-V Titan and
  Rongda M0)

Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
Changes in v3:
- Re-add the DT binding header and use numeric pin IDs in the binding.
- Replace instance-specific mux names with generic function names.
- Tighten the schema constraints for A-D and LPC pins.
- Switch the driver to pinctrl_generic_pins_function_dt_node_to_map()
  and resolve mux routes from the pins + function combination.
- Link to v2: https://patch.msgid.link/20260601-ultrarisc-pinctrl-v2-0-07ac5130a96d@ultrarisc.com

Changes in v2:
- Split the vendor prefix, CPU binding, SoC binding, DTS, and defconfig
  patches out of this series for separate submission.
- Drop the legacy DT node format from both the binding and the driver,
  and switch to the generic pinctrl interface with
  pinconf_generic_dt_node_to_map_all().
- Drop the DT binding header from the series.
- Replace the generic func0/func1 mux names with named hardware functions
  in the binding and driver.
- Wire the driver through CONFIG_PINCTRL_ULTRARISC and add COMPILE_TEST
  coverage.
- Restrict function selection to valid pins in the driver.
- Link to v1: https://patch.msgid.link/20260515-ultrarisc-pinctrl-v1-0-bf559589ea8a@ultrarisc.com

---
Jia Wang (2):
      dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
      pinctrl: ultrarisc: Add UltraRISC DP1000 pinctrl driver

 .../bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml | 131 ++++++
 MAINTAINERS                                        |   7 +
 drivers/pinctrl/Kconfig                            |   1 +
 drivers/pinctrl/Makefile                           |   1 +
 drivers/pinctrl/ultrarisc/Kconfig                  |  21 +
 drivers/pinctrl/ultrarisc/Makefile                 |   4 +
 drivers/pinctrl/ultrarisc/pinctrl-dp1000.c         | 168 +++++++
 drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c      | 503 +++++++++++++++++++++
 drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h      |  63 +++
 .../dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h |  63 +++
 10 files changed, 962 insertions(+)
---
base-commit: 8e65320d91cdc3b241d4b94855c88459b91abf66
change-id: 20260316-ultrarisc-pinctrl-efa6e24c4803

Best regards,
--  
Jia Wang <wangjia@ultrarisc.com>



^ permalink raw reply

* [PATCH v3 2/2] pinctrl: ultrarisc: Add UltraRISC DP1000 pinctrl driver
From: Jia Wang via B4 Relay @ 2026-06-08  7:50 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bartosz Golaszewski
  Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
In-Reply-To: <20260608-ultrarisc-pinctrl-v3-0-30a09ed74275@ultrarisc.com>

From: Jia Wang <wangjia@ultrarisc.com>

Add support for the pin controller on the UltraRISC DP1000 SoC.

The controller provides mux selection for pins in ports A, B, C, D, and
LPC. Ports A-D default to GPIO and support peripheral muxing. LPC pins
can be switched to eSPI, but are not available as GPIOs. Basic pin
configuration controls such as drive strength, pull-up, and pull-down
are also supported.

Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
 MAINTAINERS                                   |   1 +
 drivers/pinctrl/Kconfig                       |   1 +
 drivers/pinctrl/Makefile                      |   1 +
 drivers/pinctrl/ultrarisc/Kconfig             |  21 ++
 drivers/pinctrl/ultrarisc/Makefile            |   4 +
 drivers/pinctrl/ultrarisc/pinctrl-dp1000.c    | 168 +++++++++
 drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c | 503 ++++++++++++++++++++++++++
 drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h |  63 ++++
 8 files changed, 762 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1ef874d342a5..04f2126d8af5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27362,6 +27362,7 @@ M:	Jia Wang <wangjia@ultrarisc.com>
 L:	linux-gpio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
+F:	drivers/pinctrl/ultrarisc/*
 
 ULTRATRONIK BOARD SUPPORT
 M:	Goran Rađenović <goran.radni@gmail.com>
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 03f2e3ee065f..2a5491e3fb47 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -708,6 +708,7 @@ source "drivers/pinctrl/sunplus/Kconfig"
 source "drivers/pinctrl/sunxi/Kconfig"
 source "drivers/pinctrl/tegra/Kconfig"
 source "drivers/pinctrl/ti/Kconfig"
+source "drivers/pinctrl/ultrarisc/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
 source "drivers/pinctrl/visconti/Kconfig"
 source "drivers/pinctrl/vt8500/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f7d5d5f76d0c..61d502ba06b9 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -95,6 +95,7 @@ obj-y				+= sunplus/
 obj-$(CONFIG_PINCTRL_SUNXI)	+= sunxi/
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-y				+= ti/
+obj-$(CONFIG_PINCTRL_ULTRARISC)	+= ultrarisc/
 obj-$(CONFIG_PINCTRL_UNIPHIER)	+= uniphier/
 obj-$(CONFIG_PINCTRL_VISCONTI)	+= visconti/
 obj-$(CONFIG_ARCH_VT8500)	+= vt8500/
diff --git a/drivers/pinctrl/ultrarisc/Kconfig b/drivers/pinctrl/ultrarisc/Kconfig
new file mode 100644
index 000000000000..d81a152f2f4b
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config PINCTRL_ULTRARISC
+	tristate
+	depends on OF
+	depends on ARCH_ULTRARISC || COMPILE_TEST
+	select GENERIC_PINCTRL
+	select PINMUX
+	select GPIOLIB
+
+config PINCTRL_ULTRARISC_DP1000
+	tristate "UltraRISC DP1000 SoC Pinctrl driver"
+	select PINCTRL_ULTRARISC
+	depends on OF && HAS_IOMEM
+	depends on ARCH_ULTRARISC || COMPILE_TEST
+	default ARCH_ULTRARISC
+	help
+	  Say Y to select the pinctrl driver for UltraRISC DP1000 SoC.
+	  This pin controller allows selecting the mux function for
+	  each pin. This driver can also be built as a module called
+	  pinctrl-dp1000.
diff --git a/drivers/pinctrl/ultrarisc/Makefile b/drivers/pinctrl/ultrarisc/Makefile
new file mode 100644
index 000000000000..5d49ce1c0af9
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_PINCTRL_ULTRARISC)		+= pinctrl-ultrarisc.o
+obj-$(CONFIG_PINCTRL_ULTRARISC_DP1000)	+= pinctrl-dp1000.o
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c
new file mode 100644
index 000000000000..f9c85c8c4433
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-ultrarisc.h"
+
+/* Port indices. */
+#define UR_DP1000_PORT_A_IDX		0
+#define UR_DP1000_PORT_B_IDX		1
+#define UR_DP1000_PORT_C_IDX		2
+#define UR_DP1000_PORT_D_IDX		3
+#define UR_DP1000_PORT_LPC_IDX		4
+
+/* Port mux register offsets. */
+#define UR_DP1000_PORTA_FUNC_OFFSET	0x2c0
+#define UR_DP1000_PORTB_FUNC_OFFSET	0x2c4
+#define UR_DP1000_PORTC_FUNC_OFFSET	0x2c8
+#define UR_DP1000_PORTD_FUNC_OFFSET	0x2cc
+#define UR_DP1000_PORTLPC_FUNC_OFFSET	0x2d0
+
+/* Port pinconf register offsets. */
+#define UR_DP1000_PORTA_CONF_OFFSET	0x310
+#define UR_DP1000_PORTB_CONF_OFFSET	0x318
+#define UR_DP1000_PORTC_CONF_OFFSET	0x31c
+#define UR_DP1000_PORTD_CONF_OFFSET	0x320
+#define UR_DP1000_PORTLPC_CONF_OFFSET	0x324
+
+/* Pin ranges for function descriptors. */
+#define UR_DP1000_PINS_ABCD	GENMASK_ULL(39, 0)
+#define UR_DP1000_PINS_LPC	GENMASK_ULL(52, 40)
+
+/* Static table entry helpers. */
+#define UR_DP1000_PORT(_base, _npins, _func, _conf, _modes, _gpio) \
+	{ .pin_base = (_base), .npins = (_npins), .func_offset = (_func), \
+	  .conf_offset = (_conf), .supported_modes = (_modes), \
+	  .supports_gpio = (_gpio) }
+
+#define UR_DP1000_PIN(_nr, _name, _port) \
+	{ .number = (_nr), .name = (_name), .drv_data = (void *)&ur_dp1000_ports[_port] }
+
+static const struct ur_func_route ur_dp1000_routes[] = {
+	{ "gpio", UR_FUNC_DEFAULT, UR_DP1000_PINS_ABCD },
+	{ "i2c", UR_FUNC_0, GENMASK_ULL(13, 12) },
+	{ "i2c", UR_FUNC_0, GENMASK_ULL(23, 22) },
+	{ "i2c", UR_FUNC_0, GENMASK_ULL(25, 24) },
+	{ "i2c", UR_FUNC_0, GENMASK_ULL(27, 26) },
+	{ "pwm", UR_FUNC_0, GENMASK_ULL(19, 16) },
+	{ "spi", UR_FUNC_1, GENMASK_ULL(39, 32) },
+	{ "spi", UR_FUNC_0, GENMASK_ULL(6, 0) },
+	{ "uart", UR_FUNC_1, GENMASK_ULL(9, 8) },
+	{ "uart", UR_FUNC_0, GENMASK_ULL(21, 20) },
+	{ "uart", UR_FUNC_0, GENMASK_ULL(29, 28) },
+	{ "uart", UR_FUNC_0, GENMASK_ULL(31, 30) },
+	{ "lpc", UR_FUNC_DEFAULT, UR_DP1000_PINS_LPC },
+	{ "espi", UR_FUNC_0, UR_DP1000_PINS_LPC },
+};
+
+static const struct ur_port_desc ur_dp1000_ports[] = {
+	UR_DP1000_PORT(0, 16, UR_DP1000_PORTA_FUNC_OFFSET,
+		       UR_DP1000_PORTA_CONF_OFFSET,
+		       UR_FUNC_0 | UR_FUNC_1, true),
+	UR_DP1000_PORT(16, 8, UR_DP1000_PORTB_FUNC_OFFSET,
+		       UR_DP1000_PORTB_CONF_OFFSET,
+		       UR_FUNC_0 | UR_FUNC_1, true),
+	UR_DP1000_PORT(24, 8, UR_DP1000_PORTC_FUNC_OFFSET,
+		       UR_DP1000_PORTC_CONF_OFFSET,
+		       UR_FUNC_0 | UR_FUNC_1, true),
+	UR_DP1000_PORT(32, 8, UR_DP1000_PORTD_FUNC_OFFSET,
+		       UR_DP1000_PORTD_CONF_OFFSET,
+		       UR_FUNC_0 | UR_FUNC_1, true),
+	UR_DP1000_PORT(40, 13, UR_DP1000_PORTLPC_FUNC_OFFSET,
+		       UR_DP1000_PORTLPC_CONF_OFFSET,
+		       UR_FUNC_0,             false),
+};
+
+static const struct pinctrl_pin_desc ur_dp1000_pins[] = {
+	UR_DP1000_PIN(0, "PA0", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(1, "PA1", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(2, "PA2", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(3, "PA3", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(4, "PA4", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(5, "PA5", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(6, "PA6", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(7, "PA7", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(8, "PA8", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(9, "PA9", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(10, "PA10", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(11, "PA11", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(12, "PA12", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(13, "PA13", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(14, "PA14", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(15, "PA15", UR_DP1000_PORT_A_IDX),
+	UR_DP1000_PIN(16, "PB0", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(17, "PB1", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(18, "PB2", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(19, "PB3", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(20, "PB4", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(21, "PB5", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(22, "PB6", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(23, "PB7", UR_DP1000_PORT_B_IDX),
+	UR_DP1000_PIN(24, "PC0", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(25, "PC1", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(26, "PC2", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(27, "PC3", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(28, "PC4", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(29, "PC5", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(30, "PC6", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(31, "PC7", UR_DP1000_PORT_C_IDX),
+	UR_DP1000_PIN(32, "PD0", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(33, "PD1", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(34, "PD2", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(35, "PD3", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(36, "PD4", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(37, "PD5", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(38, "PD6", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(39, "PD7", UR_DP1000_PORT_D_IDX),
+	UR_DP1000_PIN(40, "LPC0", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(41, "LPC1", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(42, "LPC2", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(43, "LPC3", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(44, "LPC4", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(45, "LPC5", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(46, "LPC6", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(47, "LPC7", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(48, "LPC8", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(49, "LPC9", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(50, "LPC10", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(51, "LPC11", UR_DP1000_PORT_LPC_IDX),
+	UR_DP1000_PIN(52, "LPC12", UR_DP1000_PORT_LPC_IDX),
+};
+
+static const struct ur_pinctrl_data ur_dp1000_pinctrl_data = {
+	.pins = ur_dp1000_pins,
+	.npins = ARRAY_SIZE(ur_dp1000_pins),
+	.routes = ur_dp1000_routes,
+	.num_routes = ARRAY_SIZE(ur_dp1000_routes),
+};
+
+static const struct of_device_id ur_pinctrl_of_match[] = {
+	{ .compatible = "ultrarisc,dp1000-pinctrl" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ur_pinctrl_of_match);
+
+static int ur_dp1000_pinctrl_probe(struct platform_device *pdev)
+{
+	return ur_pinctrl_probe(pdev, &ur_dp1000_pinctrl_data);
+}
+
+static struct platform_driver ur_pinctrl_driver = {
+	.driver = {
+		.name = "ultrarisc-pinctrl-dp1000",
+		.of_match_table = ur_pinctrl_of_match,
+	},
+	.probe = ur_dp1000_pinctrl_probe,
+};
+
+module_platform_driver(ur_pinctrl_driver);
+
+MODULE_DESCRIPTION("UltraRISC DP1000 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c
new file mode 100644
index 000000000000..5c123873f50e
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../devicetree.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+
+#include "pinctrl-ultrarisc.h"
+
+#define UR_CONF_BIT_PER_PIN	4
+#define UR_CONF_PIN_PER_REG	(32 / UR_CONF_BIT_PER_PIN)
+static const u32 ur_drive_strengths[] = { 20, 27, 33, 40 };
+
+static const struct ur_port_desc *ur_get_pin_port(struct pinctrl_dev *pctldev,
+						  unsigned int pin)
+{
+	const struct pin_desc *desc = pin_desc_get(pctldev, pin);
+
+	if (!desc || !desc->drv_data)
+		return NULL;
+
+	return desc->drv_data;
+}
+
+static u32 ur_get_pin_conf_offset(const struct ur_port_desc *port_desc, u32 pin)
+{
+	return port_desc->conf_offset +
+	       (pin / UR_CONF_PIN_PER_REG) * sizeof(u32);
+}
+
+static int ur_read_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 *conf)
+{
+	const struct ur_port_desc *port_desc;
+	u32 pin_offset;
+	u32 reg_offset;
+	u32 shift;
+	u32 mask;
+
+	port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+	if (!port_desc)
+		return -EINVAL;
+
+	pin_offset = pin - port_desc->pin_base;
+	reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
+	shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
+	mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
+	*conf = field_get(mask, readl_relaxed(pctrl->base + reg_offset));
+
+	return 0;
+}
+
+static int ur_write_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 conf)
+{
+	const struct ur_port_desc *port_desc;
+	unsigned long flags;
+	void __iomem *reg;
+	u32 pin_offset;
+	u32 reg_offset;
+	u32 shift;
+	u32 mask;
+	u32 val;
+
+	port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+	if (!port_desc)
+		return -EINVAL;
+
+	pin_offset = pin - port_desc->pin_base;
+	reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
+	reg = pctrl->base + reg_offset;
+	shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
+	mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
+
+	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	val = readl_relaxed(reg);
+	val = (val & ~mask) | field_prep(mask, conf);
+	writel_relaxed(val, reg);
+	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+	return 0;
+}
+
+static int ur_set_pin_mux(struct ur_pinctrl *pctrl,
+			  const struct ur_port_desc *port_desc,
+			  u32 pin_offset, u32 mode)
+{
+	void __iomem *reg = pctrl->base + port_desc->func_offset;
+	unsigned long flags;
+	u32 val;
+
+	if (WARN_ON(pin_offset >= UR_MAX_PINS_PER_PORT))
+		return -EINVAL;
+
+	raw_spin_lock_irqsave(&pctrl->lock, flags);
+	val = readl_relaxed(reg);
+	val &= ~((UR_FUNC_0 | UR_FUNC_1) << pin_offset);
+	val |= mode << pin_offset;
+	writel_relaxed(val, reg);
+	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+	return 0;
+}
+
+static int ur_set_pin_mux_by_num(struct ur_pinctrl *pctrl, unsigned int pin, u32 mode)
+{
+	const struct ur_port_desc *port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+	u32 pin_offset;
+
+	if (!port_desc)
+		return -EINVAL;
+
+	if (mode != UR_FUNC_DEFAULT && !(port_desc->supported_modes & mode))
+		return -EINVAL;
+
+	pin_offset = pin - port_desc->pin_base;
+
+	return ur_set_pin_mux(pctrl, port_desc, pin_offset, mode);
+}
+
+static int ur_hw_to_config(unsigned long *config, u32 conf)
+{
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	u32 drive = FIELD_GET(UR_DRIVE_MASK, conf);
+	u32 pull = FIELD_GET(UR_PULL_MASK, conf);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+		if (pull != UR_PULL_DIS)
+			return -EINVAL;
+		*config = pinconf_to_config_packed(param, 1);
+		return 0;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (pull != UR_PULL_UP)
+			return -EINVAL;
+		*config = pinconf_to_config_packed(param, 1);
+		return 0;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+		if (pull != UR_PULL_DOWN)
+			return -EINVAL;
+		*config = pinconf_to_config_packed(param, 1);
+		return 0;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		if (drive >= ARRAY_SIZE(ur_drive_strengths))
+			return -EINVAL;
+		*config = pinconf_to_config_packed(param, ur_drive_strengths[drive]);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ur_config_to_hw(unsigned long config, u32 *conf)
+{
+	enum pin_config_param param = pinconf_to_config_param(config);
+	u32 arg = pinconf_to_config_argument(config);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+		FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DIS);
+		return 0;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_UP);
+		return 0;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+		FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DOWN);
+		return 0;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		for (u32 i = 0; i < ARRAY_SIZE(ur_drive_strengths); i++) {
+			if (ur_drive_strengths[i] != arg)
+				continue;
+			FIELD_MODIFY(UR_DRIVE_MASK, conf, i);
+			return 0;
+		}
+		return -EINVAL;
+	case PIN_CONFIG_PERSIST_STATE:
+		/*
+		 * For PIN_CONFIG_PERSIST_STATE, gpiolib only treats
+		 * -ENOTSUPP as an optional unsupported result.
+		 * Do not use -EOPNOTSUPP here.
+		 */
+		return -ENOTSUPP;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ur_find_group_route(struct ur_pinctrl *pctrl,
+			       const char *function,
+			       u64 group_mask,
+			       const struct ur_func_route **route_out)
+{
+	const struct ur_func_route *match = NULL;
+
+	for (u32 i = 0; i < pctrl->data->num_routes; i++) {
+		const struct ur_func_route *route = &pctrl->data->routes[i];
+
+		if (strcmp(route->function, function))
+			continue;
+
+		if ((route->valid_pins & group_mask) != group_mask)
+			continue;
+
+		if (match) {
+			dev_err(pctrl->dev,
+				"ambiguous route for function %s group_mask=%#llx\n",
+				function, (unsigned long long)group_mask);
+			return -EINVAL;
+		}
+
+		match = route;
+	}
+
+	if (match) {
+		*route_out = match;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static const char *ur_get_group_function(struct pinctrl_dev *pctldev,
+					 unsigned int group_selector,
+					 unsigned int pin_index)
+{
+	const struct group_desc *group;
+	const char * const *functions;
+
+	group = pinctrl_generic_get_group(pctldev, group_selector);
+	if (!group || pin_index >= group->grp.npins || !group->data)
+		return NULL;
+
+	functions = group->data;
+
+	return functions[pin_index];
+}
+
+static int ur_resolve_group_mux(struct pinctrl_dev *pctldev,
+				struct ur_pinctrl *pctrl,
+				unsigned int group_selector,
+				const unsigned int *pins,
+				unsigned int npins,
+				const struct ur_func_route **route_out)
+{
+	const char *function;
+	u64 group_mask = 0;
+
+	if (!npins)
+		return -EINVAL;
+
+	function = ur_get_group_function(pctldev, group_selector, 0);
+	if (!function)
+		return -EINVAL;
+
+	for (u32 i = 0; i < npins; i++)
+		group_mask |= BIT_ULL(pins[i]);
+
+	return ur_find_group_route(pctrl, function, group_mask, route_out);
+}
+
+static bool ur_function_is_gpio(struct pinctrl_dev *pctldev,
+				unsigned int selector)
+{
+	const struct function_desc *function;
+
+	function = pinmux_generic_get_function(pctldev, selector);
+	if (!function)
+		return false;
+
+	for (u32 i = 0; i < function->func->ngroups; i++) {
+		const char *func_name;
+		int group_selector;
+
+		group_selector = pinctrl_get_group_selector(pctldev,
+							    function->func->groups[i]);
+		if (group_selector < 0)
+			return false;
+
+		func_name = ur_get_group_function(pctldev, group_selector, 0);
+		if (!func_name || strcmp(func_name, "gpio"))
+			return false;
+	}
+
+	return true;
+}
+
+static const struct pinctrl_ops ur_pinctrl_ops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+	.dt_node_to_map = pinctrl_generic_pins_function_dt_node_to_map,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int ur_gpio_request_enable(struct pinctrl_dev *pctldev,
+				  struct pinctrl_gpio_range *range,
+				  unsigned int offset)
+{
+	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+	const struct ur_port_desc *port_desc;
+	const struct ur_func_route *route;
+	int ret;
+
+	(void)range;
+
+	port_desc = ur_get_pin_port(pctldev, offset);
+	if (!port_desc || !port_desc->supports_gpio)
+		return -EINVAL;
+
+	ret = ur_find_group_route(pctrl, "gpio", BIT_ULL(offset), &route);
+	if (ret)
+		return ret;
+
+	return ur_set_pin_mux_by_num(pctrl, offset, route->mode);
+}
+
+static int ur_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
+		      unsigned int group_selector)
+{
+	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+	const struct ur_func_route *route;
+	const unsigned int *pins;
+	unsigned int npins;
+	int ret;
+
+	(void)func_selector;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group_selector, &pins, &npins);
+	if (ret)
+		return ret;
+
+	ret = ur_resolve_group_mux(pctldev, pctrl, group_selector, pins, npins,
+				   &route);
+	if (ret)
+		return ret;
+
+	for (u32 i = 0; i < npins; i++) {
+		ret = ur_set_pin_mux_by_num(pctrl, pins[i], route->mode);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct pinmux_ops ur_pinmux_ops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.function_is_gpio = ur_function_is_gpio,
+	.set_mux = ur_set_mux,
+	.gpio_request_enable = ur_gpio_request_enable,
+	.strict = true,
+};
+
+static int ur_pin_config_get(struct pinctrl_dev *pctldev,
+			     unsigned int pin,
+			     unsigned long *config)
+{
+	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+	u32 conf;
+	int ret;
+
+	ret = ur_read_pin_conf(pctrl, pin, &conf);
+	if (ret)
+		return ret;
+
+	return ur_hw_to_config(config, conf);
+}
+
+static int ur_pin_config_set(struct pinctrl_dev *pctldev,
+			     unsigned int pin,
+			     unsigned long *configs,
+			     unsigned int num_configs)
+{
+	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+	u32 conf;
+	int ret;
+
+	ret = ur_read_pin_conf(pctrl, pin, &conf);
+	if (ret)
+		return ret;
+
+	for (u32 i = 0; i < num_configs; i++) {
+		ret = ur_config_to_hw(configs[i], &conf);
+		if (ret)
+			return ret;
+	}
+
+	return ur_write_pin_conf(pctrl, pin, conf);
+}
+
+static int ur_pin_config_group_get(struct pinctrl_dev *pctldev,
+				   unsigned int selector,
+				   unsigned long *config)
+{
+	const unsigned int *pins;
+	unsigned int npins;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
+	if (ret || !npins)
+		return ret ?: -EINVAL;
+
+	return ur_pin_config_get(pctldev, pins[0], config);
+}
+
+static int ur_pin_config_group_set(struct pinctrl_dev *pctldev,
+				   unsigned int selector,
+				   unsigned long *configs,
+				   unsigned int num_configs)
+{
+	const unsigned int *pins;
+	unsigned int npins;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (u32 i = 0; i < npins; i++) {
+		ret = ur_pin_config_set(pctldev, pins[i], configs, num_configs);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct pinconf_ops ur_pinconf_ops = {
+	.pin_config_get = ur_pin_config_get,
+	.pin_config_set = ur_pin_config_set,
+	.pin_config_group_get = ur_pin_config_group_get,
+	.pin_config_group_set = ur_pin_config_group_set,
+#ifdef CONFIG_GENERIC_PINCONF
+	.is_generic = true,
+	.pin_config_config_dbg_show = pinconf_generic_dump_config,
+#endif
+};
+
+int ur_pinctrl_probe(struct platform_device *pdev,
+		     const struct ur_pinctrl_data *data)
+{
+	struct pinctrl_desc *desc;
+	struct ur_pinctrl *pctrl;
+	int ret;
+
+	if (!data)
+		return -ENODEV;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+	if (!pctrl)
+		return -ENOMEM;
+
+	pctrl->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pctrl->base))
+		return PTR_ERR(pctrl->base);
+	pctrl->dev = &pdev->dev;
+	pctrl->data = data;
+
+	raw_spin_lock_init(&pctrl->lock);
+
+	desc->name = dev_name(&pdev->dev);
+	desc->owner = THIS_MODULE;
+	desc->pins = data->pins;
+	desc->npins = data->npins;
+	desc->pctlops = &ur_pinctrl_ops;
+	desc->pmxops = &ur_pinmux_ops;
+	desc->confops = &ur_pinconf_ops;
+
+	ret = devm_pinctrl_register_and_init(&pdev->dev, desc, pctrl, &pctrl->pctl_dev);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "failed to register pinctrl\n");
+
+	platform_set_drvdata(pdev, pctrl);
+
+	return pinctrl_enable(pctrl->pctl_dev);
+}
+EXPORT_SYMBOL_GPL(ur_pinctrl_probe);
+
+MODULE_DESCRIPTION("UltraRISC pinctrl core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h
new file mode 100644
index 000000000000..c874688aafca
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#ifndef __PINCTRL_ULTRARISC_H__
+#define __PINCTRL_ULTRARISC_H__
+
+#include <linux/io.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/spinlock.h>
+
+struct platform_device;
+
+#define UR_FUNC_DEFAULT		0U
+#define UR_FUNC_0		1U
+#define UR_FUNC_1		0x10000U
+
+#define UR_MAX_PINS_PER_PORT	16
+
+#define UR_BIAS_MASK		0x0000000F
+#define UR_PULL_MASK		0x0C
+#define UR_PULL_DIS		0
+#define UR_PULL_UP		1
+#define UR_PULL_DOWN		2
+#define UR_DRIVE_MASK		0x03
+
+struct ur_port_desc {
+	u32 pin_base;
+	u32 npins;
+	u32 func_offset;
+	u32 conf_offset;
+	u32 supported_modes;
+	bool supports_gpio;
+};
+
+struct ur_func_route {
+	const char *function;
+	u32 mode;
+	u64 valid_pins;
+};
+
+struct ur_pinctrl_data {
+	const struct pinctrl_pin_desc *pins;
+	u32 npins;
+	const struct ur_func_route *routes;
+	u32 num_routes;
+};
+
+struct ur_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctl_dev;
+	const struct ur_pinctrl_data *data;
+	void __iomem *base;
+	raw_spinlock_t lock; /* Protects mux and conf registers */
+};
+
+int ur_pinctrl_probe(struct platform_device *pdev,
+		     const struct ur_pinctrl_data *data);
+
+#endif

-- 
2.34.1



^ permalink raw reply related

* [PATCH v3 1/2] dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
From: Jia Wang via B4 Relay @ 2026-06-08  7:50 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Bartosz Golaszewski
  Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
In-Reply-To: <20260608-ultrarisc-pinctrl-v3-0-30a09ed74275@ultrarisc.com>

From: Jia Wang <wangjia@ultrarisc.com>

Add doc for the pinctrl controllers on the UltraRISC DP1000 RISC-V SoC.

Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
 .../bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml | 131 +++++++++++++++++++++
 MAINTAINERS                                        |   6 +
 .../dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h |  63 ++++++++++
 3 files changed, 200 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
new file mode 100644
index 000000000000..a64fbfc616db
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
@@ -0,0 +1,131 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/ultrarisc,dp1000-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UltraRISC DP1000 Pin Controller
+
+maintainers:
+  - Jia Wang <wangjia@ultrarisc.com>
+
+description: |
+  UltraRISC RISC-V SoC DP1000 pin controller.
+  The controller manages ports A, B, C, D and LPC. Ports A-D default to
+  GPIO and provide additional SPI, UART, I2C, and PWM mux functions.
+  LPC pins default to the LPC interface and can be muxed to eSPI.
+  All pins also support pin configuration, including drive strength,
+  pull-up, and pull-down settings.
+
+properties:
+  compatible:
+    const: ultrarisc,dp1000-pinctrl
+
+  reg:
+    items:
+      - description: pin controller registers
+
+required:
+  - compatible
+  - reg
+
+patternProperties:
+  '.*-pins$':
+    type: object
+    unevaluatedProperties: false
+    allOf:
+      - $ref: /schemas/pinctrl/pincfg-node.yaml#
+      - $ref: /schemas/pinctrl/pinmux-node.yaml#
+      - if:
+          properties:
+            pins:
+              items:
+                minimum: 40
+                maximum: 52
+        then:
+          properties:
+            function:
+              enum:
+                - lpc
+                - espi
+        else:
+          properties:
+            pins:
+              items:
+                maximum: 39
+            function:
+              enum:
+                - gpio
+                - i2c
+                - pwm
+                - spi
+                - uart
+
+    properties:
+      pins:
+        description: |
+          List of pins affected by this state node, using the numeric pin IDs
+          defined in dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h.
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        uniqueItems: true
+        items:
+          minimum: 0
+          maximum: 52
+
+      function:
+        description: |
+          Mux function to select for the listed pins. Supported functions
+          depend on the selected pins and match the DP1000 hardware mux
+          table.
+        enum:
+          - gpio
+          - i2c
+          - pwm
+          - spi
+          - uart
+          - lpc
+          - espi
+
+      bias-disable: true
+      bias-high-impedance: true
+      bias-pull-up: true
+      bias-pull-down: true
+
+      drive-strength:
+        description: Output drive strength in mA.
+        enum: [20, 27, 33, 40]
+
+    required:
+      - pins
+      - function
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h>
+
+    soc {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      pinctrl@11081000 {
+        compatible = "ultrarisc,dp1000-pinctrl";
+        reg = <0x0 0x11081000 0x0 0x1000>;
+
+        i2c0-pins {
+          pins = <PA12 PA13>;
+          function = "i2c";
+          bias-pull-up;
+          drive-strength = <33>;
+        };
+
+        uart0-pins {
+          pins = <PA8 PA9>;
+          function = "uart";
+          bias-pull-up;
+          drive-strength = <33>;
+        };
+      };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index e035a3be797c..1ef874d342a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27357,6 +27357,12 @@ S:	Maintained
 F:	drivers/usb/common/ulpi.c
 F:	include/linux/ulpi/
 
+ULTRARISC DP1000 PINCTRL DRIVER
+M:	Jia Wang <wangjia@ultrarisc.com>
+L:	linux-gpio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
+
 ULTRATRONIK BOARD SUPPORT
 M:	Goran Rađenović <goran.radni@gmail.com>
 M:	Börge Strümpfel <boerge.struempfel@gmail.com>
diff --git a/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h
new file mode 100644
index 000000000000..f800c9722471
--- /dev/null
+++ b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H
+#define _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H
+
+#define PA0		0
+#define PA1		1
+#define PA2		2
+#define PA3		3
+#define PA4		4
+#define PA5		5
+#define PA6		6
+#define PA7		7
+#define PA8		8
+#define PA9		9
+#define PA10		10
+#define PA11		11
+#define PA12		12
+#define PA13		13
+#define PA14		14
+#define PA15		15
+#define PB0		16
+#define PB1		17
+#define PB2		18
+#define PB3		19
+#define PB4		20
+#define PB5		21
+#define PB6		22
+#define PB7		23
+#define PC0		24
+#define PC1		25
+#define PC2		26
+#define PC3		27
+#define PC4		28
+#define PC5		29
+#define PC6		30
+#define PC7		31
+#define PD0		32
+#define PD1		33
+#define PD2		34
+#define PD3		35
+#define PD4		36
+#define PD5		37
+#define PD6		38
+#define PD7		39
+#define LPC0		40
+#define LPC1		41
+#define LPC2		42
+#define LPC3		43
+#define LPC4		44
+#define LPC5		45
+#define LPC6		46
+#define LPC7		47
+#define LPC8		48
+#define LPC9		49
+#define LPC10		50
+#define LPC11		51
+#define LPC12		52
+
+#endif /* _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H */

-- 
2.34.1



^ permalink raw reply related

* Re: [PATCH v5 1/3] dt-bindings: clock: airoha: Document support for AN7583 clock
From: Krzysztof Kozlowski @ 2026-06-08  7:49 UTC (permalink / raw)
  To: Christian Marangi
  Cc: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Felix Fietkau,
	linux-clk, devicetree, linux-kernel
In-Reply-To: <20260528190000.9164-2-ansuelsmth@gmail.com>

On Thu, May 28, 2026 at 08:59:54PM +0200, Christian Marangi wrote:
> Document support for Airoha AN7583 clock. This is based on the EN7523
> clock schema with the new requirement of the "airoha,chip-scu".
> 
> Add additional binding for additional clock and reset lines.
> 
> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> ---
>  .../bindings/clock/airoha,en7523-scu.yaml     | 18 ++++++
>  include/dt-bindings/clock/en7523-clk.h        |  3 +
>  .../dt-bindings/reset/airoha,an7583-reset.h   | 62 +++++++++++++++++++
>  3 files changed, 83 insertions(+)
>  create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
> index eb24a5687639..6c3c88798515 100644
> --- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
> +++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
> @@ -30,6 +30,7 @@ properties:
>    compatible:
>      items:
>        - enum:
> +          - airoha,an7583-scu
>            - airoha,en7523-scu
>            - airoha,en7581-scu
>            - econet,en751221-scu
> @@ -50,12 +51,29 @@ properties:
>      description: ID of the controller reset line
>      const: 1
>  
> +  airoha,chip-scu:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: phandle to Chip SCU

Here you explain for what purpose this device needs to reference SCU.
This is SCU, so I don't understand why SCU needs phandle to Chip SCU...

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v16 01/10] riscv: kexec_file: Fix crashk_low_res not exclude bug
From: sashiko-bot @ 2026-06-08  7:48 UTC (permalink / raw)
  To: Jinjie Ruan; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260608073459.3119290-2-ruanjinjie@huawei.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] A Time-of-Check to Time-of-Use (TOCTOU) race condition in `crash_prepare_headers()` and `arch_crash_populate_cmem()` can lead to an out-of-bounds array write (Heap Buffer Overflow) if system RAM resources are hotplugged concurrently.
--

commit d18db7747e63171595f6e6caa523eb4a8bcc5bc5
Author: Jinjie Ruan <ruanjinjie@huawei.com>
Subject: riscv: kexec_file: Fix crashk_low_res not exclude bug

This commit ensures the "crashk_low_res" reserved ranges are excluded
from the crash kernel memory in RISC-V kexec_file to prevent them from
being exported through /proc/vmcore. It adds the necessary exclusion
logic and an extra crash_mem range.

Link: https://github.com/chenjh005/kexec-tools/tree/build-test-riscv-v2
Link: https://lore.kernel.org/all/20230726175000.2536220-1-chenjiahao16@huawei.com/

> diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
> index 54e2d9552e930..3f7766057cac3 100644
> --- a/arch/riscv/kernel/machine_kexec_file.c
> +++ b/arch/riscv/kernel/machine_kexec_file.c
> @@ -61,7 +61,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
>  	unsigned int nr_ranges;
>  	int ret;
>  
> -	nr_ranges = 1; /* For exclusion of crashkernel region */
> +	nr_ranges = 2; /* For exclusion of crashkernel region */
>  	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
>  
>  	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);

[Severity: High]
This is a pre-existing issue, but could this multi-pass allocation pattern
lead to an out-of-bounds array write if system RAM resources are hotplugged
concurrently?

Looking at the refactored logic in kernel/crash_core.c and the callbacks in
arch/riscv/kernel/machine_kexec_file.c, there appears to be a Time-of-Check
to Time-of-Use (TOCTOU) gap:

crash_prepare_headers()
   arch_get_system_nr_ranges()
       /* First walk: calculates max_nr_ranges */
   cmem = alloc_cmem(max_nr_ranges)
   arch_crash_populate_cmem(cmem)
       /* Second walk: populates cmem */

Since neither the global resource_lock nor device_hotplug_lock is held across
both passes, a concurrent memory hotplug event (e.g., add_memory()) could
insert new RAM ranges into iomem_resource between the two passes.

If the second pass encounters more ranges than originally allocated,
prepare_elf64_ram_headers_callback() writes directly to the array and
increments the counter:

    cmem->ranges[cmem->nr_ranges].start = res->start;
    cmem->ranges[cmem->nr_ranges].end = res->end;
    cmem->nr_ranges++;

Does this code need a bounds check against cmem->max_nr_ranges in the
callback to prevent a heap buffer overflow in the cmem->ranges array?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie@huawei.com?part=1

^ permalink raw reply

* Re: [PATCH v16 05/10] x86: kexec_file: Use crash_prepare_headers() helper to simplify code
From: sashiko-bot @ 2026-06-08  7:47 UTC (permalink / raw)
  To: Jinjie Ruan; +Cc: devicetree, conor+dt, robh
In-Reply-To: <20260608073459.3119290-6-ruanjinjie@huawei.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] A Time-of-Check to Time-of-Use (TOCTOU) race condition with concurrent memory hotplug can cause an out-of-bounds array write in `prepare_elf64_ram_headers_callback()` due to a missing bounds check.
--

commit 4e1090b66ab88651797483f0d06242b9bd18b6b3
Author: Jinjie Ruan <ruanjinjie@huawei.com>

x86: kexec_file: Use crash_prepare_headers() helper to simplify code

This commit replaces x86's custom prepare_elf_headers() with the generic
crash_prepare_headers() helper. It implements the required architecture
callbacks arch_get_system_nr_ranges(), arch_crash_populate_cmem(), and
arch_crash_exclude_ranges() to manage crash memory regions.

> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index cd796818d94d9..cb2ce7acfec45 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c

[ ... ]

> -/* Prepare elf headers. Return addr and size */
> -static int prepare_elf_headers(void **addr, unsigned long *sz,
> -			       unsigned long *nr_mem_ranges)
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
>  {
> -	struct crash_mem *cmem;
> -	int ret;
> -
> -	cmem = fill_up_crash_elf_data();
> -	if (!cmem)
> -		return -ENOMEM;
> -
> -	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
> -	if (ret)
> -		goto out;
> -
> -	/* Exclude unwanted mem ranges */
> -	ret = elf_header_exclude_ranges(cmem);
> -	if (ret)
> -		goto out;
> -
> -	/* Return the computed number of memory ranges, for hotplug usage */
> -	*nr_mem_ranges = cmem->nr_ranges;
> -
> -	/* By default prepare 64bit headers */
> -	ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz);
> -
> -out:
> -	vfree(cmem);
> -	return ret;
> +	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
>  }

[Severity: High]
This is a pre-existing issue, but can this sequence lead to an out-of-bounds 
write during concurrent memory hotplug?

The generic crash_prepare_headers() performs two lockless passes over system
RAM resources:

1. arch_get_system_nr_ranges() counts the regions to allocate cmem.
2. arch_crash_populate_cmem() populates them using walk_system_ram_res()
   and prepare_elf64_ram_headers_callback().

Since sys_kexec_file_load() does not hold mem_hotplug_lock, and 
walk_system_ram_res() temporarily drops resource_lock between iterations,
concurrent memory hot-add operations can insert new memory regions between or
during these passes.

If the number of dynamically added RAM regions exceeds the reserved padding, 
the second pass will encounter more regions than cmem->max_nr_ranges.

prepare_elf64_ram_headers_callback() currently does not verify bounds before
appending new regions:

    cmem->ranges[cmem->nr_ranges].start = res->start;
    cmem->ranges[cmem->nr_ranges].end = res->end;
    cmem->nr_ranges++;

Could this allow an out-of-bounds array write on the vmalloc heap if enough
memory ranges are hotplugged concurrently? Would it make sense to add a bounds
check to prepare_elf64_ram_headers_callback() to prevent exceeding 
cmem->max_nr_ranges, or perhaps hold the memory hotplug lock across the passes?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie@huawei.com?part=5

^ permalink raw reply

* Re: [PATCH 00/39] Add i.MX95 DPU/DSI/LVDS support
From: Liu Ying @ 2026-06-08  7:48 UTC (permalink / raw)
  To: Piyush Patle
  Cc: Marek Vasut, dri-devel, imx, linux-arm-kernel, linux-clk,
	devicetree, Shawn Guo, Fabio Estevam, Peng Fan, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Laurent Pinchart,
	Thomas Zimmermann, Abel Vesa, Pengutronix Kernel Team
In-Reply-To: <20260605121112.27866-1-piyushpatle228@gmail.com>

On Fri, Jun 05, 2026 at 05:41:05PM +0530, Piyush Patle wrote:
> Hi Marek, Liu Ying,

Hi,

> 
> I brought this series up on the i.MX95 15x15 FRDM (IT6263 LVDS-to-HDMI on
> LVDS ch1). It mostly works, but I ran into a few issues around DI routing,
> LVDS format handling, and DC enable sequencing which needed rework before
> HDMI would come up reliably on the board.
> 
> I don't see a v2 of the series and things seem to have been quiet since
> November. Are you planning to post an updated version?

My plan was to enable prefetch engine support[1] for i.MX8QXP display
controller and add device tree for a whole i.MX8QXP LVDS display pipeline,
before adding i.MX95 display controller support.

Unfortunately, it seems that Marek is not a big fan of [1] and I'm busy
with downstream development so the plan doesn't move forward well.  I still
think [1] makes sense(maybe I need to rebase it on latest drm-misc-next),
so I'd like to see review comments on [1] and hopefully people think that
the overall idea of [1] is ok.

> 
> I've accumulated a fair amount of rework while getting this running on the
> FRDM. If you're not planning a v2, I can clean things up and send one based
> on the current series.

I still think that i.MX95 display controller driver should be in a separate
driver, rather than sharing the same driver with i.MX8QXP display controller
like this patch series does, because the two display controllers are quite
different as I mentioned in comments on this patch series and in discussion
in [1].  Also, the common part between the two display controllers should
be extracted to a common helper library as I mentioned there too.

> 
> Thanks,
> Piyush

[1] lore.kernel.org/all/20251027-imx8-dc-prefetch-v5-0-4ecb6c6d4941@nxp.com/

-- 
Regards,
Liu Ying

^ permalink raw reply

* Re: [PATCH] arm64: dts: qcom: sdm670-google: add lpi reserved gpios
From: Dmitry Baryshkov @ 2026-06-08  7:44 UTC (permalink / raw)
  To: Richard Acayan
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Linus Walleij, linux-arm-msm, devicetree
In-Reply-To: <20260602021722.30760-1-mailingradian@gmail.com>

On Mon, Jun 01, 2026 at 10:17:22PM -0400, Richard Acayan wrote:
> Add reserved GPIOs for the Pixel 3a, which blocks access to the sensor
> GPIOs. The hunk in the original patch was dropped in the commit because
> it depended on an unapplied patch, which is now commit fe9f4a46895d
> ("arm64: dts: qcom: sdm670-google: add common device tree include").
> 
> Fixes: c4b423835ee7 ("arm64: dts: qcom: sdm670: add lpi pinctrl")
> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
> ---
>  arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi | 5 +++++
>  1 file changed, 5 insertions(+)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver
From: Joshua Crofts @ 2026-06-08  7:39 UTC (permalink / raw)
  To: Jakub Szczudlo
  Cc: linux-iio, jic23, dlechner, nuno.sa, andy, marcelo.schmitt, robh,
	krzk+dt, conor+dt, mike.looijmans, devicetree, linux-kernel,
	jorge.marques, antoniu.miclaus, mazziesaccount, jishnu.prakash,
	duje, wens, sakari.ailus, linusw
In-Reply-To: <20260607183542.368184-4-jakubszczudlo40@gmail.com>

Hi Jakub,

various comments inline, some nitpicks and some more serious.

Josh

On Sun, 7 Jun 2026 at 20:38, Jakub Szczudlo <jakubszczudlo40@gmail.com> wrote:
>
> From: jszczudlo <jakubszczudlo40@gmail.com>
>
> add ADS1100 support

Wrap the commit message to 72 characters per line, this is too
short.

> make changing gain and datarate wait for new reading
> fix unbalanced regulator disable when removing in singleshot mode

Additionally, write the commit messages as regular sentences, not
a list of changes.

>
> Signed-off-by: jszczudlo <jakubszczudlo40@gmail.com>

Ensure that your full name is in the Signed-off-by tag (this goes for all
patches in this series).

> ---
>  drivers/iio/adc/ti-ads1100.c | 165 ++++++++++++++++++++++++++---------
>  1 file changed, 126 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c
> index aa8946063c7d..11d6fe1e8abc 100644
> --- a/drivers/iio/adc/ti-ads1100.c
> +++ b/drivers/iio/adc/ti-ads1100.c
> @@ -5,18 +5,15 @@
>   * Copyright (c) 2023, Topic Embedded Products
>   *
>   * Datasheet: https://www.ti.com/lit/gpn/ads1100
> - * IIO driver for ADS1100 and ADS1000 ADC 16-bit I2C
> + * IIO driver for ADS1100, ADS1000 and ADS1110 ADC 16-bit I2C
>   */
>
>  #include <linux/bitfield.h>
>  #include <linux/bits.h>
> -#include <linux/cleanup.h>
> -#include <linux/delay.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
>  #include <linux/i2c.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
>  #include <linux/mutex.h>
> -#include <linux/property.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/units.h>

This should go as a separate patch (or part of a cleanup series). Not only
it's undocumented in the commit message, it's also unrelated to adding
support for a new device.

> @@ -39,17 +36,39 @@
>  #define        ADS1100_SINGLESHOT      ADS1100_CFG_SC
>
>  #define ADS1100_SLEEP_DELAY_MS 2000
> +#define ADS1110_REFERENCE_VOLTAGE_MICROVOLT 2048000
> +
> +/* Timeout based on the minimum sample rate of 8 SPS (7500000us) */
> +#define ADS11x0_MAX_DRDY_TIMEOUT       7500000
>
>  static const int ads1100_data_rate[] = { 128, 32, 16, 8 };
> +static const int ads1110_data_rate[] = { 240, 60, 30, 15 };
>  static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 };
>
> +struct ads11x0_config {
> +       const int *data_rate;
> +       bool has_reference_voltage;
> +};
> +
> +static const struct ads11x0_config ads1100_config = {
> +       .data_rate = ads1100_data_rate,
> +       .has_reference_voltage = false,
> +};
> +
> +static const struct ads11x0_config ads1110_config = {
> +       .data_rate = ads1110_data_rate,
> +       .has_reference_voltage = true,
> +};
> +
>  struct ads1100_data {
>         struct i2c_client *client;
>         struct regulator *reg_vdd;
>         struct mutex lock;
>         int scale_avail[2 * 4]; /* 4 gain settings */
>         u8 config;
> -       bool supports_data_rate; /* Only the ADS1100 can select the rate */
> +       bool supports_data_rate; /* Only the ADS1100/ADS1110 can select the rate */
> +       bool has_reference_voltage; /* The ADS1110 has an internal reference, so fixed scale */
> +       const int *data_rate;
>  };

Have you used pahole to ensure this struct layout is ideal? I'd
move the data_rate pointer up to the larger types.

>  static const struct iio_chan_spec ads1100_channel = {
> @@ -59,12 +78,6 @@ static const struct iio_chan_spec ads1100_channel = {
>             BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
>         .info_mask_shared_by_all_available =
>             BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
> -       .scan_type = {
> -                     .sign = 's',
> -                     .realbits = 16,
> -                     .storagebits = 16,
> -                     .endianness = IIO_CPU,
> -                      },
>         .datasheet_name = "AIN",
>  };
>
> @@ -85,6 +98,50 @@ static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value)
>         return 0;
>  };
>
> +static int ads11x0_get_voltage_microvolts(struct ads1100_data *data)
> +{
> +       if (data->has_reference_voltage)
> +               return ADS1110_REFERENCE_VOLTAGE_MICROVOLT;
> +       else
> +               return regulator_get_voltage(data->reg_vdd);
> +}
> +
> +static int ads11x0_get_voltage_milivolts(struct ads1100_data *data)
> +{
> +       return ads11x0_get_voltage_microvolts(data) / (MICRO / MILLI);
> +}
> +
> +static bool ads11x0_new_data_ready(struct ads1100_data *data)
> +{
> +       int ret;
> +       u8 buffer[3];
> +
> +       ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));
> +       if (ret < sizeof(buffer)) {

Sashiko raises an issue here. sizeof returns a size_t, therefore the compiler
will promote ret to a size_t, wrapping any potential negative error value to
a large positive value, throwing away the error.

> +               dev_err(&data->client->dev, "I2C read fail: %d\n", ret);
> +               return 0;
> +       }
> +
> +       int return_val = FIELD_GET(ADS1100_CFG_ST_BSY, buffer[2]);
> +
> +       return return_val;
> +}
> +
> +static int ads11x0_poll_data_ready(struct ads1100_data *data)
> +{
> +       bool data_ready;
> +       u8 buffer[3];
> +       int datarate = data->data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)];
> +       unsigned long wait_time = DIV_ROUND_CLOSEST(MICRO, 5 * datarate);

Reverse Christmas tree order please. This goes for all new functions
and variable
declarations.

> +
> +       /* To be sure that polled value will have value after config change */
> +       i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));

Add a check here as well maybe.

> +       return read_poll_timeout(ads11x0_new_data_ready, data_ready,
> +                                !data_ready, wait_time,
> +                                ADS11x0_MAX_DRDY_TIMEOUT, false, data);
> +}
> +
>  static int ads1100_data_bits(struct ads1100_data *data)
>  {
>         return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)];
> @@ -105,9 +162,10 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val)
>
>         ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));
>
> +       pm_runtime_mark_last_busy(&data->client->dev);

AFAIK pm_runtime_put_autosuspend automatically calls mark_last_busy
when executed, so this is probably unnecessary. Additionally, this has nothing
to do with adding new device support.

>         pm_runtime_put_autosuspend(&data->client->dev);
>
> -       if (ret < 0) {
> +       if (ret < sizeof(buffer)) {

Same issue with type promotion here.

>                 dev_err(&data->client->dev, "I2C read fail: %d\n", ret);
>                 return ret;
>         }
> @@ -127,7 +185,7 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
>  {
>         int microvolts;
>         int gain;
> -
> +       int ret;

Newline here.

>         /* With Vdd between 2.7 and 5V, the scale is always below 1 */
>         if (val)
>                 return -EINVAL;
> @@ -135,7 +193,7 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
>         if (!val2)
>                 return -EINVAL;
>
> -       microvolts = regulator_get_voltage(data->reg_vdd);
> +       microvolts = ads11x0_get_voltage_microvolts(data);
>         /*
>          * val2 is in 'micro' units, n = val2 / 1000000
>          * result must be millivolts, d = microvolts / 1000
> @@ -147,34 +205,49 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
>         if (gain < BIT(0) || gain > BIT(3))
>                 return -EINVAL;
>
> +       ret = pm_runtime_resume_and_get(&data->client->dev);
> +       if (ret < 0)
> +               return ret;
> +
>         ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1);
>
> -       return 0;
> +       ret = ads11x0_poll_data_ready(data);
> +
> +       pm_runtime_mark_last_busy(&data->client->dev);

Same issue with mark_last_busy being called automatically.

> +       pm_runtime_put_autosuspend(&data->client->dev);
> +
> +       return ret;
>  }
>
>  static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate)
>  {
>         unsigned int i;
>         unsigned int size;
> +       int ret;
>
>         size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1;
>         for (i = 0; i < size; i++) {
> -               if (ads1100_data_rate[i] == rate)
> -                       return ads1100_set_config_bits(data, ADS1100_DR_MASK,
> -                                                      FIELD_PREP(ADS1100_DR_MASK, i));
> +               if (data->data_rate[i] == rate) {
> +                       ret = pm_runtime_resume_and_get(&data->client->dev);
> +                       if (ret < 0)
> +                               return ret;
> +
> +                       ads1100_set_config_bits(data, ADS1100_DR_MASK,
> +                                               FIELD_PREP(ADS1100_DR_MASK, i));
> +                       ret = ads11x0_poll_data_ready(data);
> +
> +                       pm_runtime_mark_last_busy(&data->client->dev);
> +                       pm_runtime_put_autosuspend(&data->client->dev);
> +                       return ret;
> +               }
>         }
>
>         return -EINVAL;
>  }
>
> -static int ads1100_get_vdd_millivolts(struct ads1100_data *data)
> -{
> -       return regulator_get_voltage(data->reg_vdd) / (MICRO / MILLI);
> -}
> -
>  static void ads1100_calc_scale_avail(struct ads1100_data *data)
>  {
> -       int millivolts = ads1100_get_vdd_millivolts(data);
> +       int millivolts = ads11x0_get_voltage_milivolts(data);
>         unsigned int i;
>
>         for (i = 0; i < ARRAY_SIZE(data->scale_avail) / 2; i++) {
> @@ -196,7 +269,7 @@ static int ads1100_read_avail(struct iio_dev *indio_dev,
>         switch (mask) {
>         case IIO_CHAN_INFO_SAMP_FREQ:
>                 *type = IIO_VAL_INT;
> -               *vals = ads1100_data_rate;
> +               *vals = data->data_rate;
>                 if (data->supports_data_rate)
>                         *length = ARRAY_SIZE(ads1100_data_rate);
>                 else
> @@ -233,12 +306,11 @@ static int ads1100_read_raw(struct iio_dev *indio_dev,
>                 return IIO_VAL_INT;
>         case IIO_CHAN_INFO_SCALE:
>                 /* full-scale is the supply voltage in millivolts */
> -               *val = ads1100_get_vdd_millivolts(data);
> +               *val = ads11x0_get_voltage_milivolts(data);
>                 *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config);
>                 return IIO_VAL_FRACTIONAL_LOG2;
>         case IIO_CHAN_INFO_SAMP_FREQ:
> -               *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK,
> -                                                  data->config)];
> +               *val = data->data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)];
>                 return IIO_VAL_INT;
>         default:
>                 return -EINVAL;
> @@ -280,8 +352,8 @@ static int ads1100_setup(struct ads1100_data *data)
>                 return ret;
>
>         ret = i2c_master_recv(data->client, buffer, sizeof(buffer));
> -       if (ret < 0)
> -               return ret;
> +       if (ret < sizeof(buffer))
> +               return -1;

Same type promotion issue here. Additionally, I'd rather return -EIO than -1.

>
>         /* Config register returned in third byte, strip away the busy status */
>         data->config = buffer[2] & ~ADS1100_CFG_ST_BSY;
> @@ -292,9 +364,13 @@ static int ads1100_setup(struct ads1100_data *data)
>         return 0;
>  }
>
> -static void ads1100_reg_disable(void *reg)
> +static void ads1100_reg_disable(void *data)
>  {
> -       regulator_disable(reg);
> +       struct ads1100_data *ads1100_data = data;
> +
> +       /* Disable when not already disabled by the driver */
> +       if (!(ads1100_data->config & ADS1100_CFG_SC))
> +               regulator_disable(ads1100_data->reg_vdd);

Sashiko has something to say:

Could this leak the `vdd` regulator during device unbind due to the devres
execution order?
Devres executes registered actions in reverse order (LIFO). During unbind,
`ads1100_disable_continuous()` executes first and unconditionally sets
`ADS1100_CFG_SC`.
When `ads1100_reg_disable()` runs immediately after, the `ADS1100_CFG_SC` bit
is already set, causing this condition to fail and permanently skipping the
`regulator_disable()` call.

>  }
>
>  static void ads1100_disable_continuous(void *data)
> @@ -307,6 +383,7 @@ static int ads1100_probe(struct i2c_client *client)
>         struct iio_dev *indio_dev;
>         struct ads1100_data *data;
>         struct device *dev = &client->dev;
> +       const struct ads11x0_config *model;
>         int ret;
>
>         indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> @@ -334,10 +411,18 @@ static int ads1100_probe(struct i2c_client *client)
>                 return dev_err_probe(dev, ret,
>                                      "Failed to enable vdd regulator\n");
>
> -       ret = devm_add_action_or_reset(dev, ads1100_reg_disable, data->reg_vdd);
> +       ret = devm_add_action_or_reset(dev, ads1100_reg_disable, data);
>         if (ret)
>                 return ret;
>
> +       model = device_get_match_data(dev);
> +       if (!model)
> +               return dev_err_probe(dev, ret,
> +                               "Can't set device data\n");

Hmm, if device_get_match_data fails, ret will still be 0 per previous
devm_add_action_or_reset() call, therefore you're returning a "successful
error". Additionally, the error message isn't aligned with the parenthesis.

^ permalink raw reply

* Re: [PATCH v4 2/3] riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube Systems OpenNMC
From: Andre Przywara @ 2026-06-08  7:38 UTC (permalink / raw)
  To: Lukas Schmid, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Maxime Ripard
  Cc: devicetree, linux-arm-kernel, linux-sunxi, linux-kernel,
	linux-riscv
In-Reply-To: <20260606205452.2386930-3-lukas.schmid@netcube.li>

Hi,

On 6/6/26 22:54, Lukas Schmid wrote:
> Added the "uart4_pb_pins" pinctrl used by the OpenNMC

Checked against the datasheet:

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre

> 
> Signed-off-by: Lukas Schmid <lukas.schmid@netcube.li>
> ---
>   arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> index 82cc85acccb1..00fddedfa36f 100644
> --- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> +++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> @@ -191,6 +191,12 @@ uart3_pb_pins: uart3-pb-pins {
>   				pins = "PB6", "PB7";
>   				function = "uart3";
>   			};
> +
> +			/omit-if-no-ref/
> +			uart4_pb_pins: uart4-pb-pins {
> +				pins = "PB2", "PB3";
> +				function = "uart4";
> +			};
>   		};
>   
>   		ccu: clock-controller@2001000 {


^ permalink raw reply

* [PATCH v16 10/10] riscv: kexec_file: Add support for crashkernel CMA reservation
From: Jinjie Ruan @ 2026-06-08  7:34 UTC (permalink / raw)
  To: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
	mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
	dave.hansen, hpa, robh, saravanak, akpm, bhe, rppt,
	pasha.tatashin, pratyush, ruirui.yang, rdunlap, peterz, feng.tang,
	dapeng1.mi, kees, elver, kuba, lirongqing, ebiggers, paulmck,
	ruanjinjie, leitao, coxu, Liam.Howlett, ryan.roberts, osandov,
	jbohac, cfsworks, tangyouling, sourabhjain, ritesh.list, adityag,
	liaoyuanhong, seanjc, fuqiang.wang, ardb, chenjiahao16, guoren,
	x86, linux-doc, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, devicetree, kexec
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>

Commit 35c18f2933c5 ("Add a new optional ",cma" suffix to the
crashkernel= command line option") and commit ab475510e042 ("kdump:
implement reserve_crashkernel_cma") added CMA support for kdump
crashkernel reservation. This allows the kernel to dynamically allocate
contiguous memory for crash dumping when needed, rather than permanently
reserving a fixed region at boot time.

So extend crashkernel CMA reservation support to riscv. The following
changes are made to enable CMA reservation:

- Parse and obtain the CMA reservation size along with other crashkernel
  parameters.
- Call reserve_crashkernel_cma() to allocate the CMA region for kdump.
- Include the CMA-reserved ranges for kdump kernel to use, which was
  already done in of_kexec_alloc_and_setup_fdt().
- Exclude the CMA-reserved ranges from the crash kernel memory to
  prevent them from being exported through /proc/vmcore, which was
  already done in the crash core.

Update kernel-parameters.txt to document CMA support for crashkernel on
riscv architecture.

Cc: Paul Walmsley <pjw@kernel.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Acked-by: Baoquan He <bhe@redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Paul Walmsley <pjw@kernel.org> # arch/riscv
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 Documentation/admin-guide/kernel-parameters.txt | 16 ++++++++--------
 arch/riscv/kernel/machine_kexec_file.c          |  2 +-
 arch/riscv/mm/init.c                            |  5 +++--
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 52742fab49a9..3ff3ddd516cf 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1119,14 +1119,14 @@ Kernel parameters
 			It will be ignored when crashkernel=X,high is not used
 			or memory reserved is below 4G.
 	crashkernel=size[KMG],cma
-			[KNL, X86, ARM64, PPC] Reserve additional crash kernel memory from
-			CMA. This reservation is usable by the first system's
-			userspace memory and kernel movable allocations (memory
-			balloon, zswap). Pages allocated from this memory range
-			will not be included in the vmcore so this should not
-			be used if dumping of userspace memory is intended and
-			it has to be expected that some movable kernel pages
-			may be missing from the dump.
+			[KNL, X86, ARM64, RISCV, PPC] Reserve additional crash
+			kernel memory from CMA. This reservation is usable by
+			the first system's userspace memory and kernel movable
+			allocations (memory balloon, zswap). Pages allocated
+			from this memory range will not be included in the vmcore
+			so this should not be used if dumping of userspace memory
+			is intended and it has to be expected that some movable
+			kernel pages may be missing from the dump.
 
 			A standard crashkernel reservation, as described above,
 			is still needed to hold the crash kernel and initrd.
diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 439cbc50dfa6..85f14abceb50 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -46,7 +46,7 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 
 unsigned int arch_get_system_nr_ranges(void)
 {
-	unsigned int nr_ranges = 2; /* For exclusion of crashkernel region */
+	unsigned int nr_ranges = 2 + crashk_cma_cnt; /* For exclusion of crashkernel region */
 
 	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
 
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index decd7df40fa4..c848454b8349 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1295,7 +1295,7 @@ static inline void setup_vm_final(void)
  */
 static void __init arch_reserve_crashkernel(void)
 {
-	unsigned long long low_size = 0;
+	unsigned long long low_size = 0, cma_size = 0;
 	unsigned long long crash_base, crash_size;
 	bool high = false;
 	int ret;
@@ -1305,11 +1305,12 @@ static void __init arch_reserve_crashkernel(void)
 
 	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 				&crash_size, &crash_base,
-				&low_size, NULL, &high);
+				&low_size, &cma_size, &high);
 	if (ret)
 		return;
 
 	reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
+	reserve_crashkernel_cma(cma_size);
 }
 
 void __init paging_init(void)
-- 
2.34.1


^ permalink raw reply related

* [PATCH v16 09/10] arm64: kexec_file: Add support for crashkernel CMA reservation
From: Jinjie Ruan @ 2026-06-08  7:34 UTC (permalink / raw)
  To: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
	mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
	dave.hansen, hpa, robh, saravanak, akpm, bhe, rppt,
	pasha.tatashin, pratyush, ruirui.yang, rdunlap, peterz, feng.tang,
	dapeng1.mi, kees, elver, kuba, lirongqing, ebiggers, paulmck,
	ruanjinjie, leitao, coxu, Liam.Howlett, ryan.roberts, osandov,
	jbohac, cfsworks, tangyouling, sourabhjain, ritesh.list, adityag,
	liaoyuanhong, seanjc, fuqiang.wang, ardb, chenjiahao16, guoren,
	x86, linux-doc, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, devicetree, kexec
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>

Commit 35c18f2933c5 ("Add a new optional ",cma" suffix to the
crashkernel= command line option") and commit ab475510e042 ("kdump:
implement reserve_crashkernel_cma") added CMA support for kdump
crashkernel reservation.

Crash kernel memory reservation wastes production resources if too
large, risks kdump failure if too small, and faces allocation difficulties
on fragmented systems due to contiguous block constraints. The new
CMA-based crashkernel reservation scheme splits the "large fixed
reservation" into a "small fixed region + large CMA dynamic region": the
CMA memory is available to userspace during normal operation to avoid
waste, and is reclaimed for kdump upon crash—saving memory while
improving reliability.

So extend crashkernel CMA reservation support to arm64. The following
changes are made to enable CMA reservation:

- Parse and obtain the CMA reservation size along with other crashkernel
  parameters.
- Call reserve_crashkernel_cma() to allocate the CMA region for kdump.
- Include the CMA-reserved ranges for kdump kernel to use.
- Exclude the CMA-reserved ranges from the crash kernel memory to
  prevent them from being exported through /proc/vmcore, which is already
  done in the crash core.

Update kernel-parameters.txt to document CMA support for crashkernel on
arm64 architecture.

Tested-by: Breno Leitao <leitao@debian.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Acked-by: Baoquan He <bhe@redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
v7:
- Correct the inclusion of CMA-reserved ranges for kdump
  kernel in of/kexec.
v3:
- Add Acked-by.
v2:
- Free cmem in prepare_elf_headers()
- Add the mtivation.
---
 Documentation/admin-guide/kernel-parameters.txt | 2 +-
 arch/arm64/kernel/machine_kexec_file.c          | 2 +-
 arch/arm64/mm/init.c                            | 5 +++--
 drivers/of/fdt.c                                | 9 +++++----
 drivers/of/kexec.c                              | 9 +++++++++
 include/linux/crash_reserve.h                   | 4 +++-
 6 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..52742fab49a9 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1119,7 +1119,7 @@ Kernel parameters
 			It will be ignored when crashkernel=X,high is not used
 			or memory reserved is below 4G.
 	crashkernel=size[KMG],cma
-			[KNL, X86, ppc] Reserve additional crash kernel memory from
+			[KNL, X86, ARM64, PPC] Reserve additional crash kernel memory from
 			CMA. This reservation is usable by the first system's
 			userspace memory and kernel movable allocations (memory
 			balloon, zswap). Pages allocated from this memory range
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index b019b31df48c..854d872dfd0f 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -42,7 +42,7 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 #ifdef CONFIG_CRASH_DUMP
 unsigned int arch_get_system_nr_ranges(void)
 {
-	unsigned int nr_ranges = 2; /* for exclusion of crashkernel region */
+	unsigned int nr_ranges = 2 + crashk_cma_cnt; /* for exclusion of crashkernel region */
 	phys_addr_t start, end;
 	u64 i;
 
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 97987f850a33..227f58522dad 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -96,8 +96,8 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;
 
 static void __init arch_reserve_crashkernel(void)
 {
+	unsigned long long crash_base, crash_size, cma_size = 0;
 	unsigned long long low_size = 0;
-	unsigned long long crash_base, crash_size;
 	bool high = false;
 	int ret;
 
@@ -106,11 +106,12 @@ static void __init arch_reserve_crashkernel(void)
 
 	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 				&crash_size, &crash_base,
-				&low_size, NULL, &high);
+				&low_size, &cma_size, &high);
 	if (ret)
 		return;
 
 	reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
+	reserve_crashkernel_cma(cma_size);
 }
 
 static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 82f7327c59ea..0470acbd1fcf 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -880,11 +880,12 @@ static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND;
 /*
  * The main usage of linux,usable-memory-range is for crash dump kernel.
  * Originally, the number of usable-memory regions is one. Now there may
- * be two regions, low region and high region.
- * To make compatibility with existing user-space and older kdump, the low
- * region is always the last range of linux,usable-memory-range if exist.
+ * be 2 + CRASHK_CMA_RANGES_MAX regions, low region, high region and cma
+ * regions. To make compatibility with existing user-space and older kdump,
+ * the high and low region are always the first two ranges of
+ * linux,usable-memory-range if exist.
  */
-#define MAX_USABLE_RANGES		2
+#define MAX_USABLE_RANGES		(2 + CRASHK_CMA_RANGES_MAX)
 
 /**
  * early_init_dt_check_for_usable_mem_range - Decode usable memory range
diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
index b6837e299e7f..029903b986cb 100644
--- a/drivers/of/kexec.c
+++ b/drivers/of/kexec.c
@@ -458,6 +458,15 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
 			if (ret)
 				goto out;
 		}
+
+		for (int i = 0; i < crashk_cma_cnt; i++) {
+			ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
+					"linux,usable-memory-range",
+					crashk_cma_ranges[i].start,
+					crashk_cma_ranges[i].end - crashk_cma_ranges[i].start + 1);
+			if (ret)
+				goto out;
+		}
 #endif
 	}
 
diff --git a/include/linux/crash_reserve.h b/include/linux/crash_reserve.h
index f0dc03d94ca2..30864d90d7f5 100644
--- a/include/linux/crash_reserve.h
+++ b/include/linux/crash_reserve.h
@@ -14,9 +14,11 @@
 extern struct resource crashk_res;
 extern struct resource crashk_low_res;
 extern struct range crashk_cma_ranges[];
+
+#define CRASHK_CMA_RANGES_MAX 4
 #if defined(CONFIG_CMA) && defined(CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION)
 #define CRASHKERNEL_CMA
-#define CRASHKERNEL_CMA_RANGES_MAX 4
+#define CRASHKERNEL_CMA_RANGES_MAX (CRASHK_CMA_RANGES_MAX)
 extern int crashk_cma_cnt;
 #else
 #define crashk_cma_cnt 0
-- 
2.34.1


^ permalink raw reply related

* [PATCH v16 07/10] LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify code
From: Jinjie Ruan @ 2026-06-08  7:34 UTC (permalink / raw)
  To: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
	mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
	dave.hansen, hpa, robh, saravanak, akpm, bhe, rppt,
	pasha.tatashin, pratyush, ruirui.yang, rdunlap, peterz, feng.tang,
	dapeng1.mi, kees, elver, kuba, lirongqing, ebiggers, paulmck,
	ruanjinjie, leitao, coxu, Liam.Howlett, ryan.roberts, osandov,
	jbohac, cfsworks, tangyouling, sourabhjain, ritesh.list, adityag,
	liaoyuanhong, seanjc, fuqiang.wang, ardb, chenjiahao16, guoren,
	x86, linux-doc, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, devicetree, kexec
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
memory in the crash core, which reduce code duplication.

Only the following two architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Use for_each_mem_range to traverse
  and pre-count the max number of memory ranges.

- arch_crash_populate_cmem(). Use for_each_mem_range to traverse
  and collect the memory ranges and fills them into cmem.

Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: WANG Xuerui <kernel@xen0n.name>
Cc: Youling Tang <tangyouling@kylinos.cn>
Cc: Baoquan He <bhe@redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain@linux.ibm.com>
Acked-by: Baoquan He <bhe@redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/loongarch/kernel/machine_kexec_file.c | 40 +++++++---------------
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
index 5584b798ba46..5412aa9f3568 100644
--- a/arch/loongarch/kernel/machine_kexec_file.c
+++ b/arch/loongarch/kernel/machine_kexec_file.c
@@ -56,46 +56,30 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
 }
 
 #ifdef CONFIG_CRASH_DUMP
-
-static int prepare_elf_headers(void **addr, unsigned long *sz)
+unsigned int arch_get_system_nr_ranges(void)
 {
-	int ret, nr_ranges;
-	uint64_t i;
+	int nr_ranges = 2; /* for exclusion of crashkernel region */
 	phys_addr_t start, end;
-	struct crash_mem *cmem;
+	uint64_t i;
 
-	nr_ranges = 2; /* for exclusion of crashkernel region */
 	for_each_mem_range(i, &start, &end)
 		nr_ranges++;
 
-	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-	if (!cmem)
-		return -ENOMEM;
+	return nr_ranges;
+}
+
+int arch_crash_populate_cmem(struct crash_mem *cmem)
+{
+	phys_addr_t start, end;
+	uint64_t i;
 
-	cmem->max_nr_ranges = nr_ranges;
-	cmem->nr_ranges = 0;
 	for_each_mem_range(i, &start, &end) {
 		cmem->ranges[cmem->nr_ranges].start = start;
 		cmem->ranges[cmem->nr_ranges].end = end - 1;
 		cmem->nr_ranges++;
 	}
 
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret < 0)
-		goto out;
-
-	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-		if (ret < 0)
-			goto out;
-	}
-
-	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
-
-out:
-	kfree(cmem);
-	return ret;
+	return 0;
 }
 
 /*
@@ -163,7 +147,7 @@ int load_other_segments(struct kimage *image,
 		void *headers;
 		unsigned long headers_sz;
 
-		ret = prepare_elf_headers(&headers, &headers_sz);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
 		if (ret < 0) {
 			pr_err("Preparing elf core header failed\n");
 			goto out_err;
-- 
2.34.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox