* [PATCH 2/2] ARM: dts: aspeed: sanmiguel: add current-range property for PDB HSC
From: Mike Hsieh @ 2026-06-18 7:41 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Patrick Williams
Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
Cosmo Chou, Potin Lai, Mik Lin, Mike Hsieh, Mike Hsieh
In-Reply-To: <20260618-sanmiguel-dts-config-hsc-lm5066i-v1-0-cccf959c9b78@gmail.com>
Configure the ti,current-range property for the four TI LM5066i
hot-swap controllers on PDB board.
This defines the hardware current limit operating mode (low/high)
for each sensor to match the physical board design.
Specific configurations:
- HSC1 (0x11): low
- HSC2 (0x13): high
- HSC3 (0x15): high
- HSC4 (0x17): low
Signed-off-by: Mike Hsieh <mike.quanta.115@gmail.com>
---
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts
index 3faac0925a79..e518e3fc1c97 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts
@@ -451,6 +451,7 @@ pdb_ti_hsc1: power-monitor@11 {
compatible = "ti,lm5066i";
reg = <0x11>;
shunt-resistor-micro-ohms = <1000>;
+ ti,current-range = "low";
};
pdb_mps_hsc2: power-monitor@12 {
@@ -462,6 +463,7 @@ pdb_ti_hsc2: power-monitor@13 {
compatible = "ti,lm5066i";
reg = <0x13>;
shunt-resistor-micro-ohms = <321>;
+ ti,current-range = "high";
};
pdb_mps_hsc3: power-monitor@14 {
@@ -473,6 +475,7 @@ pdb_ti_hsc3: power-monitor@15 {
compatible = "ti,lm5066i";
reg = <0x15>;
shunt-resistor-micro-ohms = <321>;
+ ti,current-range = "high";
};
pdb_mps_hsc4: power-monitor@16 {
@@ -484,6 +487,7 @@ pdb_ti_hsc4: power-monitor@17 {
compatible = "ti,lm5066i";
reg = <0x17>;
shunt-resistor-micro-ohms = <500>;
+ ti,current-range = "low";
};
pdb_ioexp_20: gpio@20 {
--
2.53.0
^ permalink raw reply related
* [PATCH 1/2] ARM: dts: aspeed: sanmiguel: fix PDB HSC shunt resistor
From: Mike Hsieh @ 2026-06-18 7:41 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Patrick Williams
Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
Cosmo Chou, Potin Lai, Mik Lin, Mike Hsieh, Mike Hsieh
In-Reply-To: <20260618-sanmiguel-dts-config-hsc-lm5066i-v1-0-cccf959c9b78@gmail.com>
Correct the shunt-resistor-micro-ohms values for the four TI LM5066i
hot-swap controllers on the PDB. This ensures accurate current and
power sensor readings from the hardware monitors.
Signed-off-by: Mike Hsieh <mike.quanta.115@gmail.com>
---
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts
index d7ed497d7227..3faac0925a79 100644
--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts
@@ -450,7 +450,7 @@ pdb_mps_hsc1: power-monitor@10 {
pdb_ti_hsc1: power-monitor@11 {
compatible = "ti,lm5066i";
reg = <0x11>;
- shunt-resistor-micro-ohms = <763>;
+ shunt-resistor-micro-ohms = <1000>;
};
pdb_mps_hsc2: power-monitor@12 {
@@ -461,7 +461,7 @@ pdb_mps_hsc2: power-monitor@12 {
pdb_ti_hsc2: power-monitor@13 {
compatible = "ti,lm5066i";
reg = <0x13>;
- shunt-resistor-micro-ohms = <294>;
+ shunt-resistor-micro-ohms = <321>;
};
pdb_mps_hsc3: power-monitor@14 {
@@ -472,7 +472,7 @@ pdb_mps_hsc3: power-monitor@14 {
pdb_ti_hsc3: power-monitor@15 {
compatible = "ti,lm5066i";
reg = <0x15>;
- shunt-resistor-micro-ohms = <294>;
+ shunt-resistor-micro-ohms = <321>;
};
pdb_mps_hsc4: power-monitor@16 {
@@ -483,7 +483,7 @@ pdb_mps_hsc4: power-monitor@16 {
pdb_ti_hsc4: power-monitor@17 {
compatible = "ti,lm5066i";
reg = <0x17>;
- shunt-resistor-micro-ohms = <381>;
+ shunt-resistor-micro-ohms = <500>;
};
pdb_ioexp_20: gpio@20 {
--
2.53.0
^ permalink raw reply related
* [PATCH 0/2] ARM: dts: aspeed: sanmiguel: configure LM5066i HSCs for PDB
From: Mike Hsieh @ 2026-06-18 7:41 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Patrick Williams
Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
Cosmo Chou, Potin Lai, Mik Lin, Mike Hsieh, Mike Hsieh
This patch series updates the device tree configurations for
the four TI LM5066i hot-swap controllers (HSCs) on the Power
Distribution Board (PDB) for the sanmiguel platform.
Signed-off-by: Mike Hsieh <mike.quanta.115@gmail.com>
---
Mike Hsieh (2):
ARM: dts: aspeed: sanmiguel: fix PDB HSC shunt resistor
ARM: dts: aspeed: sanmiguel: add current-range property for PDB HSC
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-sanmiguel.dts | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
---
base-commit: 57596c043ad59cf2e53fadebf6d1b418190e3a49
change-id: 20260618-sanmiguel-dts-config-hsc-lm5066i-70f40e1b3c2e
Best regards,
--
Mike Hsieh <mike.quanta.115@gmail.com>
^ permalink raw reply
* Re: Question: SPEAr PLGPIO irq_enable on PREEMPT_RT and regmap updates
From: Viresh Kumar @ 2026-06-18 7:40 UTC (permalink / raw)
To: Runyu Xiao, Herve Codina
Cc: Viresh Kumar, Linus Walleij, Sebastian Andrzej Siewior,
Clark Williams, Steven Rostedt, linux-arm-kernel, soc, linux-gpio,
linux-rt-devel, linux-kernel, jianhao.xu
In-Reply-To: <20260618023418.213453-1-runyu.xiao@seu.edu.cn>
+ Herve (the last guy to work on this driver).
On 18-06-26, 10:34, Runyu Xiao wrote:
> Hi,
>
> While auditing GPIO/pinctrl irqchip callbacks, our static analysis tool
> flagged the SPEAr PLGPIO irq_enable path, and we manually reviewed it
> against the current tree.
>
> The path is:
>
> irq_startup()
> -> plgpio_irq_enable()
> -> gpiochip_enable_irq()
> -> spin_lock_irqsave(&plgpio->lock)
> -> plgpio_reg_reset()
> -> regmap_update_bits()
>
> On PREEMPT_RT, plgpio->lock is a regular spinlock_t and can become a
> sleeping lock. Since irq_enable/irq_disable can be called from IRQ
> management paths while the IRQ descriptor raw lock is held, taking that
> regular spinlock there looks unsafe.
>
> A minimal Lockdep reproducer preserving this irq_chip::irq_enable carrier
> reports:
>
> BUG: sleeping function called from invalid context
> irqs_disabled(): 1
> plgpio_rt_spin_lock_irqsave
> plgpio_irq_enable
> request_threaded_irq_probe_path
>
> My first thought was to convert the PLGPIO register lock to
> raw_spinlock_t. However, that does not seem sufficient because the IE/EIT
> updates go through regmap_update_bits()/regmap_read()/regmap_write(). For
> the syscon/MMIO regmap used here, regmap may still take its own regular
> fast-IO lock unless the regmap was created with use_raw_spinlock. So a
> raw_spinlock_t conversion in the PLGPIO driver alone may just move the
> PREEMPT_RT problem one level down into regmap.
>
> The repair I am considering is to keep the gpiolib resource updates in
> the fast irq_enable/irq_disable callbacks, but defer the actual PLGPIO
> IE/EIT register writes to irq_bus_sync_unlock(), after the IRQ core has
> dropped desc->lock. The driver would keep per-line shadow state for:
>
> - IRQ disabled/enabled state
> - pending IE update
> - edge direction state
> - pending EIT update
>
> and then synchronize those shadow updates from irq_bus_sync_unlock()
> under a mutex.
>
> In other words, the fast callbacks would only update local shadow state
> and call gpiochip_enable_irq()/gpiochip_disable_irq(), while the sleepable
> regmap writes would be batched into the irq bus sync phase.
>
> Does that sound like an acceptable direction for SPEAr PLGPIO, or would
> you prefer a different fix, such as changing the underlying syscon regmap
> locking model or handling only the IE register path?
>
> The draft patch I have locally is roughly:
>
> pinctrl: spear: defer PLGPIO IRQ updates to bus sync
>
> and it changes only drivers/pinctrl/spear/pinctrl-plgpio.c.
I haven't worked on this for a very long time now (15 yrs). There are some
people who use this hardware, and so it is not removed until now.
Also I am not sure if RT kernel is a valid use case here for this SoC family.
--
viresh
^ permalink raw reply
* Re: [PATCH] net: airoha: Stop TX queues on error path in airoha_dev_open
From: Lorenzo Bianconi @ 2026-06-18 7:33 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Wayen Yan, netdev, horms, pabeni, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <20260617164448.31e189bc@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 558 bytes --]
> On Tue, 16 Jun 2026 18:50:39 +0800 Wayen Yan wrote:
> > In airoha_dev_open(), if airoha_set_vip_for_gdm_port() fails after
> > netif_tx_start_all_queues() has been called, the TX queues remain
> > started while the device configuration is incomplete. This leaves
> > the device in an inconsistent state where packets could be
> > transmitted before the VIP/IFC port configuration is complete.
>
> Not sure if this was superseded by another posting but FWIW
> this posting did not apply.
I think we do not need this patch.
Regards,
Lorenzo
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v7 4/4] arm64: tegra: Reorder reg and reg-names to match bindings
From: Manivannan Sadhasivam @ 2026-06-18 7:27 UTC (permalink / raw)
To: Thierry Reding
Cc: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Karthikeyan Mitran, Hou Zhiqiang,
Thomas Petazzoni, Pali Rohár, Michal Simek, Kevin Xie,
Aksh Garg, linux-pci, devicetree, linux-tegra, linux-kernel,
linux-arm-kernel, Thierry Reding
In-Reply-To: <20260617-tegra264-pcie-v7-4-eae7ae964629@nvidia.com>
On Wed, Jun 17, 2026 at 06:01:31PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> The ECAM region cannot be the first entry in the "reg" property, because
> in that case the unit-address wouldn't match the first entry. The order
> of the nodes can also not be changed to match the ECAM entry because the
> ECAM region is global and outside of any of the control busses.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
- Mani
> ---
> Changes in v5:
> - rebase onto v7.1-rc1
>
> Changes in v4:
> - revert ECAM "reg" entry order
>
> Changes in v2:
> - order ECAM "reg" entry before others
> ---
> arch/arm64/boot/dts/nvidia/tegra264.dtsi | 48 ++++++++++++++++----------------
> 1 file changed, 24 insertions(+), 24 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> index 8f4350c7793b..4c701abd25a8 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi
> @@ -3513,11 +3513,11 @@ cmdqv4: cmdqv@b200000 {
>
> pci@c000000 {
> compatible = "nvidia,tegra264-pcie";
> - reg = <0xd0 0xb0000000 0x0 0x10000000>,
> - <0x00 0x0c000000 0x0 0x00004000>,
> + reg = <0x00 0x0c000000 0x0 0x00004000>,
> <0x00 0x0c004000 0x0 0x00001000>,
> - <0x00 0x0c005000 0x0 0x00001000>;
> - reg-names = "ecam", "xal", "xtl", "xtl-pri";
> + <0x00 0x0c005000 0x0 0x00001000>,
> + <0xd0 0xb0000000 0x0 0x10000000>;
> + reg-names = "xal", "xtl", "xtl-pri", "ecam";
> #address-cells = <3>;
> #size-cells = <2>;
> device_type = "pci";
> @@ -3893,12 +3893,12 @@ gpio_uphy: gpio@8300000 {
>
> pci@8400000 {
> compatible = "nvidia,tegra264-pcie";
> - reg = <0xa8 0xb0000000 0x0 0x10000000>,
> - <0x00 0x08400000 0x0 0x00004000>,
> + reg = <0x00 0x08400000 0x0 0x00004000>,
> <0x00 0x08404000 0x0 0x00001000>,
> <0x00 0x08405000 0x0 0x00001000>,
> - <0x00 0x08410000 0x0 0x00010000>;
> - reg-names = "ecam", "xal", "xtl", "xtl-pri", "xpl";
> + <0x00 0x08410000 0x0 0x00010000>,
> + <0xa8 0xb0000000 0x0 0x10000000>;
> + reg-names = "xal", "xtl", "xtl-pri", "xpl", "ecam";
> #address-cells = <3>;
> #size-cells = <2>;
> device_type = "pci";
> @@ -3925,12 +3925,12 @@ pci@8400000 {
>
> pci@8420000 {
> compatible = "nvidia,tegra264-pcie";
> - reg = <0xb0 0xb0000000 0x0 0x10000000>,
> - <0x00 0x08420000 0x0 0x00004000>,
> + reg = <0x00 0x08420000 0x0 0x00004000>,
> <0x00 0x08424000 0x0 0x00001000>,
> <0x00 0x08425000 0x0 0x00001000>,
> - <0x00 0x08430000 0x0 0x00010000>;
> - reg-names = "ecam", "xal", "xtl", "xtl-pri", "xpl";
> + <0x00 0x08430000 0x0 0x00010000>,
> + <0xb0 0xb0000000 0x0 0x10000000>;
> + reg-names = "xal", "xtl", "xtl-pri", "xpl", "ecam";
> #address-cells = <3>;
> #size-cells = <2>;
> device_type = "pci";
> @@ -3957,12 +3957,12 @@ pci@8420000 {
>
> pci@8440000 {
> compatible = "nvidia,tegra264-pcie";
> - reg = <0xb8 0xb0000000 0x0 0x10000000>,
> - <0x00 0x08440000 0x0 0x00004000>,
> + reg = <0x00 0x08440000 0x0 0x00004000>,
> <0x00 0x08444000 0x0 0x00001000>,
> <0x00 0x08445000 0x0 0x00001000>,
> - <0x00 0x08450000 0x0 0x00010000>;
> - reg-names = "ecam", "xal", "xtl", "xtl-pri", "xpl";
> + <0x00 0x08450000 0x0 0x00010000>,
> + <0xb8 0xb0000000 0x0 0x10000000>;
> + reg-names = "xal", "xtl", "xtl-pri", "xpl", "ecam";
> #address-cells = <3>;
> #size-cells = <2>;
> device_type = "pci";
> @@ -3989,12 +3989,12 @@ pci@8440000 {
>
> pci@8460000 {
> compatible = "nvidia,tegra264-pcie";
> - reg = <0xc0 0xb0000000 0x0 0x10000000>,
> - <0x00 0x08460000 0x0 0x00004000>,
> + reg = <0x00 0x08460000 0x0 0x00004000>,
> <0x00 0x08464000 0x0 0x00001000>,
> <0x00 0x08465000 0x0 0x00001000>,
> - <0x00 0x08470000 0x0 0x00010000>;
> - reg-names = "ecam", "xal", "xtl", "xtl-pri", "xpl";
> + <0x00 0x08470000 0x0 0x00010000>,
> + <0xc0 0xb0000000 0x0 0x10000000>;
> + reg-names = "xal", "xtl", "xtl-pri", "xpl", "ecam";
> #address-cells = <3>;
> #size-cells = <2>;
> device_type = "pci";
> @@ -4021,12 +4021,12 @@ pci@8460000 {
>
> pci@8480000 {
> compatible = "nvidia,tegra264-pcie";
> - reg = <0xc8 0xb0000000 0x0 0x10000000>,
> - <0x00 0x08480000 0x0 0x00004000>,
> + reg = <0x00 0x08480000 0x0 0x00004000>,
> <0x00 0x08484000 0x0 0x00001000>,
> <0x00 0x08485000 0x0 0x00001000>,
> - <0x00 0x08490000 0x0 0x00010000>;
> - reg-names = "ecam", "xal", "xtl", "xtl-pri", "xpl";
> + <0x00 0x08490000 0x0 0x00010000>,
> + <0xc8 0xb0000000 0x0 0x10000000>;
> + reg-names = "xal", "xtl", "xtl-pri", "xpl", "ecam";
> #address-cells = <3>;
> #size-cells = <2>;
> device_type = "pci";
>
> --
> 2.54.0
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v7 3/4] PCI: tegra: Add Tegra264 support
From: Manivannan Sadhasivam @ 2026-06-18 7:26 UTC (permalink / raw)
To: Thierry Reding
Cc: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Karthikeyan Mitran, Hou Zhiqiang,
Thomas Petazzoni, Pali Rohár, Michal Simek, Kevin Xie,
Aksh Garg, linux-pci, devicetree, linux-tegra, linux-kernel,
linux-arm-kernel, Thierry Reding, Manikanta Maddireddy
In-Reply-To: <20260617-tegra264-pcie-v7-3-eae7ae964629@nvidia.com>
On Wed, Jun 17, 2026 at 06:01:30PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> Add a driver for the PCIe controller found on NVIDIA Tegra264 SoCs. The
> driver is very small, with its main purpose being to set up the address
> translation registers and then creating a standard PCI host using ECAM.
>
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
> Changes in v7:
> - select PCI_ECAM to satisfy the build dependency (Jonathan Hunter)
> - remove pre-silicon support patch to avoid extra build dependency
>
> Changes in v6:
> - remove unneeded pm_runtime_disable() call (Sashiko)
> - do not use noirq suspend/resume callbacks (Sashiko)
> - wrap PM ops in pm_ptr() macro (Sashiko)
> - use standard wait times with msleep() (Lukas Wunner)
> - properly check errors for wake IRQs
> - fix build failures /o\
>
> Changes in v5:
> - make PCIE_TEGRA264 symbol tristate
> - drop dependency on PCI_MSI
> - reorganize tegra264_pcie struct
> - use standard wake-gpios property
> - rename tegra264_pcie_bpmp_set_rp_state() to tegra264_pcie_power_off()
> - use dev_err() instead of dev_info() for some error messages
> - add clarifying comment as to why bandwidth requests aren't fatal
> - address some compiler warnings on 32-bit physical address platforms
> - drop needless comments
> - explicitly deinitialize controller on suspend
> - use devm_pm_runtime_active_enabled()
> - rename "free" label to "free_ecam"
> - use dev_err_probe() in more places
> - reselect default pin state during resume, not probe
> - return early on absence of wake GPIO
> - simplify BW value calculation
>
> Changes in v2:
> - specify generations applicable for PCI_TEGRA driver to avoid confusion
> - drop SPDX-FileCopyrightText tag
> - rename link_state to link_up to clarify meaning
> - replace memset() by an empty initializer
> - sanity-check only enable BAR regions
> - bring PCI link out of reset in case firmware didn't
> - use common wait times instead of defining our own
> - use core helpers to parse and print PCI link speed
> - fix multi-line comment
> - use dev_err_probe() more ubiquitously
> - fix probe sequence and error cleanup
> - use DEFINE_NOIRQ_DEV_PM_OPS() to avoid warnings for !PM_SUSPEND
> - reuse more standard registers and remove unused register definitions
> - use %pe and ERR_PTR() to print symbolic errors
> - add signed-off-by from Manikanta as the original author
> - add myself as author after significantly modifying the driver
>
> pcie: remove pre-silicon conditionals
> ---
> drivers/pci/controller/Kconfig | 10 +-
> drivers/pci/controller/Makefile | 1 +
> drivers/pci/controller/pcie-tegra264.c | 538 +++++++++++++++++++++++++++++++++
> 3 files changed, 548 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
> index 2247709ef6d6..3045c8aecc7e 100644
> --- a/drivers/pci/controller/Kconfig
> +++ b/drivers/pci/controller/Kconfig
> @@ -255,7 +255,15 @@ config PCI_TEGRA
> select IRQ_MSI_LIB
> help
> Say Y here if you want support for the PCIe host controller found
> - on NVIDIA Tegra SoCs.
> + on NVIDIA Tegra SoCs (Tegra20 through Tegra186).
> +
> +config PCIE_TEGRA264
> + tristate "NVIDIA Tegra264 PCIe controller"
> + depends on ARCH_TEGRA || COMPILE_TEST
> + select PCI_ECAM
> + help
> + Say Y here if you want support for the PCIe host controller found
> + on NVIDIA Tegra264 SoCs.
>
> config PCIE_RCAR_HOST
> bool "Renesas R-Car PCIe controller (host mode)"
> diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
> index ac8db283f0fe..d478743b5142 100644
> --- a/drivers/pci/controller/Makefile
> +++ b/drivers/pci/controller/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o
> obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
> obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
> obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
> +obj-$(CONFIG_PCIE_TEGRA264) += pcie-tegra264.o
> obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
> obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o
> obj-$(CONFIG_PCIE_RCAR_EP) += pcie-rcar.o pcie-rcar-ep.o
> diff --git a/drivers/pci/controller/pcie-tegra264.c b/drivers/pci/controller/pcie-tegra264.c
> new file mode 100644
> index 000000000000..e2d295ea4403
> --- /dev/null
> +++ b/drivers/pci/controller/pcie-tegra264.c
> @@ -0,0 +1,538 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * PCIe host controller driver for Tegra264 SoC
> + *
> + * Copyright (c) 2022-2026, NVIDIA CORPORATION. All rights reserved.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/init.h>
> +#include <linux/interconnect.h>
> +#include <linux/interrupt.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/pci-ecam.h>
> +#include <linux/pci.h>
> +#include <linux/pinctrl/consumer.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/pm_wakeirq.h>
> +
> +#include <soc/tegra/bpmp.h>
> +#include <soc/tegra/bpmp-abi.h>
> +#include <soc/tegra/fuse.h>
> +
> +#include "../pci.h"
> +
> +/* XAL registers */
> +#define XAL_RC_ECAM_BASE_HI 0x00
> +#define XAL_RC_ECAM_BASE_LO 0x04
> +#define XAL_RC_ECAM_BUSMASK 0x08
> +#define XAL_RC_IO_BASE_HI 0x0c
> +#define XAL_RC_IO_BASE_LO 0x10
> +#define XAL_RC_IO_LIMIT_HI 0x14
> +#define XAL_RC_IO_LIMIT_LO 0x18
> +#define XAL_RC_MEM_32BIT_BASE_HI 0x1c
> +#define XAL_RC_MEM_32BIT_BASE_LO 0x20
> +#define XAL_RC_MEM_32BIT_LIMIT_HI 0x24
> +#define XAL_RC_MEM_32BIT_LIMIT_LO 0x28
> +#define XAL_RC_MEM_64BIT_BASE_HI 0x2c
> +#define XAL_RC_MEM_64BIT_BASE_LO 0x30
> +#define XAL_RC_MEM_64BIT_LIMIT_HI 0x34
> +#define XAL_RC_MEM_64BIT_LIMIT_LO 0x38
> +#define XAL_RC_BAR_CNTL_STANDARD 0x40
> +#define XAL_RC_BAR_CNTL_STANDARD_IOBAR_EN BIT(0)
> +#define XAL_RC_BAR_CNTL_STANDARD_32B_BAR_EN BIT(1)
> +#define XAL_RC_BAR_CNTL_STANDARD_64B_BAR_EN BIT(2)
> +
> +/* XTL registers */
> +#define XTL_RC_PCIE_CFG_LINK_STATUS 0x5a
> +
> +#define XTL_RC_MGMT_PERST_CONTROL 0x218
> +#define XTL_RC_MGMT_PERST_CONTROL_PERST_O_N BIT(0)
> +
> +#define XTL_RC_MGMT_CLOCK_CONTROL 0x47c
> +#define XTL_RC_MGMT_CLOCK_CONTROL_PEX_CLKREQ_I_N_PIN_USE_CONV_TO_PRSNT BIT(9)
> +
> +struct tegra264_pcie {
> + struct device *dev;
> +
> + /* I/O memory */
> + void __iomem *xal;
> + void __iomem *xtl;
> + void __iomem *ecam;
> +
> + /* bridge configuration */
> + struct pci_config_window *cfg;
> + struct pci_host_bridge *bridge;
> +
> + /* wake IRQ */
> + struct gpio_desc *wake_gpio;
> + unsigned int wake_irq;
> +
> + /* BPMP and bandwidth management */
> + struct icc_path *icc_path;
> + struct tegra_bpmp *bpmp;
> + u32 ctl_id;
> +
> + bool link_up;
> +};
> +
> +static int tegra264_pcie_parse_dt(struct tegra264_pcie *pcie)
> +{
> + struct device *dev = pcie->dev;
> + int err;
> +
> + pcie->wake_gpio = devm_gpiod_get_optional(dev, "wake", GPIOD_IN);
> + if (IS_ERR(pcie->wake_gpio))
> + return PTR_ERR(pcie->wake_gpio);
> +
> + if (!pcie->wake_gpio)
> + return 0;
> +
> + err = gpiod_to_irq(pcie->wake_gpio);
> + if (err < 0)
> + return dev_err_probe(dev, err, "failed to get wake IRQ\n");
> +
> + pcie->wake_irq = (unsigned int)err;
> +
> + err = devm_device_init_wakeup(dev);
> + if (err < 0)
> + return dev_err_probe(dev, err, "failed to initialize wakeup\n");
> +
> + err = devm_pm_set_wake_irq(dev, pcie->wake_irq);
> + if (err < 0)
> + return dev_err_probe(dev, err, "failed to set wakeup IRQ\n");
> +
I'd really like to get rid of custom WAKE# handling in the controller drivers.
Krishna is trying to add generic WAKE# handling in the PCI core and I'd suggest
you to take a look at the patches:
https://lore.kernel.org/linux-pci/20260511-wakeirq_support-v10-2-c10af9c9eb8c@oss.qualcomm.com/
But this also means that you need to use switch to Root Port binding to move the
Root Port properties out of the controller node. This is something we are
mandating for the new controllers. Not a big change though...
Reference:
Documentation/devicetree/bindings/pci/spacemit,k1-pcie-host.yaml#n80
> + return 0;
> +}
> +
> +static void tegra264_pcie_power_off(struct tegra264_pcie *pcie)
> +{
> + struct tegra_bpmp_message msg = {};
> + struct mrq_pcie_request req = {};
> + int err;
> +
> + req.cmd = CMD_PCIE_RP_CONTROLLER_OFF;
> + req.rp_ctrlr_off.rp_controller = pcie->ctl_id;
> +
> + msg.mrq = MRQ_PCIE;
> + msg.tx.data = &req;
> + msg.tx.size = sizeof(req);
> +
> + err = tegra_bpmp_transfer(pcie->bpmp, &msg);
> + if (err)
> + dev_err(pcie->dev, "failed to turn off PCIe #%u: %pe\n",
> + pcie->ctl_id, ERR_PTR(err));
> +
> + if (msg.rx.ret)
> + dev_err(pcie->dev, "failed to turn off PCIe #%u: %d\n",
> + pcie->ctl_id, msg.rx.ret);
> +}
> +
> +static void tegra264_pcie_icc_set(struct tegra264_pcie *pcie)
> +{
> + u32 value, speed, width;
> + int err;
> +
> + value = readw(pcie->ecam + XTL_RC_PCIE_CFG_LINK_STATUS);
> + speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, value);
> + width = FIELD_GET(PCI_EXP_LNKSTA_NLW, value);
> +
> + value = Mbps_to_icc(width * PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]));
> +
> + /*
> + * We don't want to error out here because a boot-critical device
> + * could be connected to this root port. Failure to set the bandwidth
> + * request may have an adverse impact on performance, but it is not
> + * generally fatal, so we opt to continue regardless so that users
> + * get a chance to fix things.
> + */
> + err = icc_set_bw(pcie->icc_path, value, value);
> + if (err < 0)
> + dev_err(pcie->dev,
> + "failed to request bandwidth (%u MBps): %pe\n",
> + value, ERR_PTR(err));
> +}
> +
> +/*
> + * The various memory regions used by the controller (I/O, memory, ECAM) are
> + * set up during early boot and have hardware-level protections in place. If
> + * the DT ranges don't match what's been setup, the controller won't be able
> + * to write the address endpoints properly, so make sure to validate that DT
> + * and firmware programming agree on these ranges.
> + */
> +static bool tegra264_pcie_check_ranges(struct platform_device *pdev)
> +{
> + struct tegra264_pcie *pcie = platform_get_drvdata(pdev);
> + struct device_node *np = pcie->dev->of_node;
> + struct of_pci_range_parser parser;
> + phys_addr_t phys, limit, hi, lo;
> + struct of_pci_range range;
> + struct resource *res;
> + bool status = true;
> + u32 value;
> + int err;
> +
> + err = of_pci_range_parser_init(&parser, np);
> + if (err < 0)
> + return false;
> +
> + for_each_of_pci_range(&parser, &range) {
> + unsigned int addr_hi, addr_lo, limit_hi, limit_lo, enable;
> + unsigned long type = range.flags & IORESOURCE_TYPE_BITS;
> + phys_addr_t start, end, mask;
> + const char *region = NULL;
> +
> + end = range.cpu_addr + range.size - 1;
> + start = range.cpu_addr;
> +
> + switch (type) {
> + case IORESOURCE_IO:
> + addr_hi = XAL_RC_IO_BASE_HI;
> + addr_lo = XAL_RC_IO_BASE_LO;
> + limit_hi = XAL_RC_IO_LIMIT_HI;
> + limit_lo = XAL_RC_IO_LIMIT_LO;
> + enable = XAL_RC_BAR_CNTL_STANDARD_IOBAR_EN;
> + mask = SZ_64K - 1;
> + region = "I/O";
> + break;
> +
> + case IORESOURCE_MEM:
> + if (range.flags & IORESOURCE_PREFETCH) {
> + addr_hi = XAL_RC_MEM_64BIT_BASE_HI;
> + addr_lo = XAL_RC_MEM_64BIT_BASE_LO;
> + limit_hi = XAL_RC_MEM_64BIT_LIMIT_HI;
> + limit_lo = XAL_RC_MEM_64BIT_LIMIT_LO;
> + enable = XAL_RC_BAR_CNTL_STANDARD_64B_BAR_EN;
> + region = "prefetchable memory";
> + } else {
> + addr_hi = XAL_RC_MEM_32BIT_BASE_HI;
> + addr_lo = XAL_RC_MEM_32BIT_BASE_LO;
> + limit_hi = XAL_RC_MEM_32BIT_LIMIT_HI;
> + limit_lo = XAL_RC_MEM_32BIT_LIMIT_LO;
> + enable = XAL_RC_BAR_CNTL_STANDARD_32B_BAR_EN;
> + region = "memory";
> + }
> +
> + mask = SZ_1M - 1;
> + break;
> + }
> +
> + /* not interested in anything that's not I/O or memory */
> + if (!region)
> + continue;
> +
> + /* don't check regions that haven't been enabled */
> + value = readl(pcie->xal + XAL_RC_BAR_CNTL_STANDARD);
> + if ((value & enable) == 0)
> + continue;
> +
> + hi = readl(pcie->xal + addr_hi);
> + lo = readl(pcie->xal + addr_lo);
> + phys = ((hi << 16) << 16) | lo;
> +
> + hi = readl(pcie->xal + limit_hi);
> + lo = readl(pcie->xal + limit_lo);
> + limit = ((hi << 16) << 16) | lo | mask;
> +
> + if (phys != start || limit != end) {
> + dev_err(pcie->dev,
> + "%s region mismatch: %pap-%pap -> %pap-%pap\n",
> + region, &phys, &limit, &start, &end);
> + status = false;
> + }
> + }
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecam");
> + if (!res)
> + return false;
> +
> + hi = readl(pcie->xal + XAL_RC_ECAM_BASE_HI);
> + lo = readl(pcie->xal + XAL_RC_ECAM_BASE_LO);
> + phys = ((hi << 16) << 16) | lo;
> +
> + value = readl(pcie->xal + XAL_RC_ECAM_BUSMASK);
> + limit = phys + ((value + 1) << 20) - 1;
> +
> + if (phys != res->start || limit != res->end) {
> + dev_err(pcie->dev,
> + "ECAM region mismatch: %pap-%pap -> %pap-%pap\n",
> + &phys, &limit, &res->start, &res->end);
> + status = false;
> + }
> +
> + return status;
> +}
> +
> +static bool tegra264_pcie_link_up(struct tegra264_pcie *pcie,
> + enum pci_bus_speed *speed)
> +{
> + u16 value = readw(pcie->ecam + XTL_RC_PCIE_CFG_LINK_STATUS);
> +
> + if (value & PCI_EXP_LNKSTA_DLLLA) {
> + if (speed)
> + *speed = pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS,
> + value)];
> +
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static void tegra264_pcie_init(struct tegra264_pcie *pcie)
> +{
> + enum pci_bus_speed speed;
> + unsigned int i;
> + u32 value;
> +
> + /* bring the endpoint out of reset */
> + value = readl(pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);
> + value |= XTL_RC_MGMT_PERST_CONTROL_PERST_O_N;
> + writel(value, pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);
> +
> + for (i = 0; i < PCIE_LINK_WAIT_MAX_RETRIES; i++) {
> + if (tegra264_pcie_link_up(pcie, NULL))
> + break;
> +
> + msleep(PCIE_LINK_WAIT_SLEEP_MS);
> + }
> +
> + if (tegra264_pcie_link_up(pcie, &speed)) {
> + msleep(PCIE_RESET_CONFIG_WAIT_MS);
> + dev_info(pcie->dev, "PCIe #%u link is up (speed: %s)\n",
> + pcie->ctl_id, pci_speed_string(speed));
> + tegra264_pcie_icc_set(pcie);
> + pcie->link_up = true;
> + } else {
> + dev_info(pcie->dev, "PCIe #%u link is down\n", pcie->ctl_id);
> +
> + value = readl(pcie->xtl + XTL_RC_MGMT_CLOCK_CONTROL);
> +
> + /*
> + * Set link state only when link fails and no hot-plug feature
> + * is present.
> + */
> + if ((value & XTL_RC_MGMT_CLOCK_CONTROL_PEX_CLKREQ_I_N_PIN_USE_CONV_TO_PRSNT) == 0) {
> + dev_info(pcie->dev,
> + "PCIe #%u link is down and not hotplug-capable, turning off\n",
> + pcie->ctl_id);
> + tegra264_pcie_power_off(pcie);
> + pcie->link_up = false;
> + } else {
> + pcie->link_up = true;
> + }
> + }
> +}
> +
> +static void tegra264_pcie_deinit(struct tegra264_pcie *pcie)
> +{
> + u32 value;
> +
> + /* take the endpoint into reset */
> + value = readl(pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);
> + value &= ~XTL_RC_MGMT_PERST_CONTROL_PERST_O_N;
> + writel(value, pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);
> +}
> +
> +static int tegra264_pcie_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct pci_host_bridge *bridge;
> + struct tegra264_pcie *pcie;
> + struct resource_entry *bus;
> + struct resource *res;
> + int err;
> +
> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct tegra264_pcie));
> + if (!bridge)
> + return dev_err_probe(dev, -ENOMEM,
> + "failed to allocate host bridge\n");
> +
> + pcie = pci_host_bridge_priv(bridge);
> + platform_set_drvdata(pdev, pcie);
> + pcie->bridge = bridge;
> + pcie->dev = dev;
> +
> + err = tegra264_pcie_parse_dt(pcie);
> + if (err < 0)
> + return dev_err_probe(dev, err, "failed to parse device tree\n");
> +
> + pcie->xal = devm_platform_ioremap_resource_byname(pdev, "xal");
> + if (IS_ERR(pcie->xal))
> + return dev_err_probe(dev, PTR_ERR(pcie->xal),
> + "failed to map XAL memory\n");
> +
> + pcie->xtl = devm_platform_ioremap_resource_byname(pdev, "xtl-pri");
> + if (IS_ERR(pcie->xtl))
> + return dev_err_probe(dev, PTR_ERR(pcie->xtl),
> + "failed to map XTL-PRI memory\n");
> +
> + bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
> + if (!bus)
> + return dev_err_probe(dev, -ENODEV,
> + "failed to get bus resources\n");
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecam");
> + if (!res)
> + return dev_err_probe(dev, -ENXIO,
> + "failed to get ECAM resource\n");
> +
> + pcie->icc_path = devm_of_icc_get(dev, "write");
> + if (IS_ERR(pcie->icc_path))
> + return dev_err_probe(dev, PTR_ERR(pcie->icc_path),
> + "failed to get ICC\n");
> +
> + pcie->bpmp = tegra_bpmp_get_with_id(dev, &pcie->ctl_id);
> + if (IS_ERR(pcie->bpmp))
> + return dev_err_probe(dev, PTR_ERR(pcie->bpmp),
> + "failed to get BPMP\n");
> +
> + err = devm_pm_runtime_set_active_enabled(dev);
I belive this has to come after pm_runtime_get_sync() because at this point, the
controller is not enabled.
> + if (err < 0) {
> + dev_err_probe(dev, err, "failed to enable runtime PM\n");
> + goto put_bpmp;
> + }
> +
> + err = pm_runtime_get_sync(dev);
> + if (err < 0) {
> + dev_err_probe(dev, err, "failed to power on device\n");
> + goto put_bpmp;
> + }
> +
> + /* sanity check that programmed ranges match what's in DT */
> + if (!tegra264_pcie_check_ranges(pdev)) {
> + err = -EINVAL;
> + goto put_pm;
> + }
> +
> + pcie->cfg = pci_ecam_create(dev, res, bus->res, &pci_generic_ecam_ops);
> + if (IS_ERR(pcie->cfg)) {
> + err = dev_err_probe(dev, PTR_ERR(pcie->cfg),
> + "failed to create ECAM\n");
> + goto put_pm;
> + }
> +
> + bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
> + bridge->sysdata = pcie->cfg;
> + pcie->ecam = pcie->cfg->win;
> +
> + tegra264_pcie_init(pcie);
> +
> + if (!pcie->link_up)
> + return 0;
So not hotplug support? Also, you do not want the driver to error out? I'm
wondering what's the use then?
> +
> + err = pci_host_probe(bridge);
> + if (err < 0) {
> + dev_err_probe(dev, err, "failed to register host\n");
> + goto free_ecam;
> + }
> +
> + return 0;
> +
> +free_ecam:
Nit: Prefix 'err' for the labels.
> + pci_ecam_free(pcie->cfg);
> +put_pm:
> + pm_runtime_put_sync(dev);
> +put_bpmp:
> + tegra_bpmp_put(pcie->bpmp);
> +
> + return err;
> +}
> +
> +static void tegra264_pcie_remove(struct platform_device *pdev)
> +{
> + struct tegra264_pcie *pcie = platform_get_drvdata(pdev);
> +
> + /*
> + * If we undo tegra264_pcie_init() then link goes down and need
> + * controller reset to bring up the link again. Remove intention is
> + * to clean up the root bridge and re-enumerate during bind.
But the controller will be consuming power even if PCIe is not used. Do you
really want that? Can't tegra264_pcie_init() handle the initialization? I'm
wondering how tegra264_pcie_deinit() in tegra264_pcie_suspend() works then.
> + */
> + pci_lock_rescan_remove();
> + pci_stop_root_bus(pcie->bridge->bus);
> + pci_remove_root_bus(pcie->bridge->bus);
> + pci_unlock_rescan_remove();
> +
> + pm_runtime_put_sync(&pdev->dev);
> + tegra_bpmp_put(pcie->bpmp);
> + pci_ecam_free(pcie->cfg);
> +}
> +
> +static int tegra264_pcie_suspend(struct device *dev)
> +{
> + struct tegra264_pcie *pcie = dev_get_drvdata(dev);
> + int err;
> +
> + tegra264_pcie_deinit(pcie);
> +
> + if (pcie->wake_gpio && device_may_wakeup(dev)) {
> + err = enable_irq_wake(pcie->wake_irq);
> + if (err < 0)
> + dev_err(dev, "failed to enable wake IRQ: %pe\n",
> + ERR_PTR(err));
> + }
> +
> + return 0;
> +}
> +
> +static int tegra264_pcie_resume(struct device *dev)
> +{
> + struct tegra264_pcie *pcie = dev_get_drvdata(dev);
> + int err;
> +
> + err = pinctrl_pm_select_default_state(dev);
> + if (err < 0)
> + dev_err(dev, "failed to configure sideband pins: %pe\n",
> + ERR_PTR(err));
Please remind me if you justified this manual pinctrl handling before.
> +
> + if (pcie->wake_gpio && device_may_wakeup(dev)) {
> + err = disable_irq_wake(pcie->wake_irq);
> + if (err < 0)
> + dev_err(dev, "failed to disable wake IRQ: %pe\n",
> + ERR_PTR(err));
> + }
> +
> + if (pcie->link_up == false)
> + return 0;
How is this possible? If 'pcie->link_up' was 'false' during probe(), then it is
going to stay until tegra264_pcie_init() is called below.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH net] net: stmmac: dwmac-spacemit: Fix wrong ctrl register definition
From: Inochi Amaoto @ 2026-06-18 7:12 UTC (permalink / raw)
To: Maxime Chevallier, Inochi Amaoto, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Maxime Coquelin,
Alexandre Torgue, Yixun Lan, Russell King (Oracle)
Cc: netdev, linux-stm32, linux-arm-kernel, linux-riscv, spacemit,
linux-kernel, Yixun Lan, Longbin Li
In-Reply-To: <9b39829d-92b4-4ffa-be0b-b2b0f857f58e@bootlin.com>
On Thu, Jun 18, 2026 at 09:03:21AM +0200, Maxime Chevallier wrote:
> Hi Inochi,
>
> On 6/18/26 08:41, Inochi Amaoto wrote:
> > There register layout of the phy ctrl register has something wrong,
> > fix it to match the right layout
> >
> > Fixes: 30f0ba420ed3 ("net: stmmac: Add glue layer for Spacemit K3 SoC")
> > Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> > ---
> > .../net/ethernet/stmicro/stmmac/dwmac-spacemit.c | 13 ++++++++-----
> > 1 file changed, 8 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> > index 223754cc5c79..6feffaa3ef3a 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> > @@ -18,10 +18,12 @@
> > #include "stmmac_platform.h"
> >
> > /* ctrl register bits */
> > -#define CTRL_PHY_INTF_RGMII BIT(3)
> > -#define CTRL_PHY_INTF_MII BIT(4)
> > -#define CTRL_WAKE_IRQ_EN BIT(9)
> > -#define CTRL_PHY_IRQ_EN BIT(12)
> > +#define CTRL_PHY_INTF_MODE GENMASK(4, 3)
> > +#define CTRL_PHY_INTF_RMII FIELD_PREP(CTRL_PHY_INTF_MODE, 0)
> > +#define CTRL_PHY_INTF_RGMII FIELD_PREP(CTRL_PHY_INTF_MODE, 1)
> > +#define CTRL_PHY_INTF_MII FIELD_PREP(CTRL_PHY_INTF_MODE, 3)
> > +#define CTRL_PHY_IRQ_EN BIT(9)
> > +#define CTRL_WAKE_IRQ_EN BIT(12)
>
> Looks like you're fixing 2 things there :
>
> -> Wake on Lan probably didn't work before, as the wake irq was apparently wrong.
I guess the vendor firmware and uboot may do something for it,
but the irq is wrong actually.
> -> The MII mode selection apparently also changes, but maybe you don't have a
> MII board around to test this ?
>
Actually, the only board of the K3 is the pico-itx board, and it only has
a RGMII phy. I even doube the spacemit vendor has not tested the MII phy
well....
> Is it possible you address these issues independently (i.e. split this in 2 patches) ?
> That way, if we ever revert one, we won't re-break the other thing that was broken.
>
>
Yes, it is fine for me to split it. I will send it in a few days.
Regards,
Inochi
^ permalink raw reply
* [PATCH V2 3/3] dmaengine: zynqmp_dma: Guard IRQ handler against spurious interrupts
From: Golla Nagendra @ 2026-06-18 7:10 UTC (permalink / raw)
To: vkoul, Frank.Li, michal.simek, robh, krzk+dt, conor+dt,
nagendra.golla, jay.buddhabhatti, harini.katakam, m.tretter,
radhey.shyam.pandey, abin.joseph, kees, sakari.ailus
Cc: git, dmaengine, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20260618071056.2024286-1-nagendra.golla@amd.com>
Add pm_runtime_get_if_active() check in zynqmp_dma_irq_handler() to
safely handle spurious interrupts that may arrive while the device is
runtime-suspended. Without this guard, a spurious interrupt could cause
the handler to access hardware registers (ISR, IMR) with clocks gated,
potentially leading to a synchronous external abort and kernel crash.
When the device is not runtime-active, pm_runtime_get_if_active()
returns false without incrementing the usage counter, and the handler
returns IRQ_NONE immediately. When the device is active, it increments
the usage counter to prevent a concurrent runtime suspend during
register access, and pm_runtime_put() releases the reference afterward.
Signed-off-by: Golla Nagendra <nagendra.golla@amd.com>
---
drivers/dma/xilinx/zynqmp_dma.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index a9dfec3c0ca3..ce9163138be7 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -730,6 +730,9 @@ static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data)
u32 isr, imr, status;
irqreturn_t ret = IRQ_NONE;
+ if (pm_runtime_get_if_active(chan->dev) <= 0)
+ return IRQ_NONE;
+
isr = readl(chan->regs + ZYNQMP_DMA_ISR);
imr = readl(chan->regs + ZYNQMP_DMA_IMR);
status = isr & ~imr;
@@ -756,6 +759,8 @@ static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data)
ret = IRQ_HANDLED;
}
+ pm_runtime_put(chan->dev);
+
return ret;
}
--
2.34.1
^ permalink raw reply related
* [PATCH V2 2/3] dmaengine: zynqmp_dma: Add per-channel reset support
From: Golla Nagendra @ 2026-06-18 7:10 UTC (permalink / raw)
To: vkoul, Frank.Li, michal.simek, robh, krzk+dt, conor+dt,
nagendra.golla, jay.buddhabhatti, harini.katakam, m.tretter,
radhey.shyam.pandey, abin.joseph, kees, sakari.ailus
Cc: git, dmaengine, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20260618071056.2024286-1-nagendra.golla@amd.com>
Versal Gen 2 and Versal Net SoCs expose a dedicated reset line per
ZDMA channel, replacing the earlier approach where a single reset
was shared across all channels. Add reset handling in the channel
probe path using device_reset_optional() to trigger a reset pulse
on the channel during initialization.
Platforms without per-channel reset continue to work unaffected
since device_reset_optional() returns 0 when no reset is specified.
add pm_runtime_put_noidle() in the probe error path before
pm_runtime_disable() to balance the usage counter incremented by
pm_runtime_resume_and_get(). This is particularly important since
device_reset_optional() can return -EPROBE_DEFER, causing the
kernel to retry probe() and leak one PM usage count per retry
without the put.
Signed-off-by: Golla Nagendra <nagendra.golla@amd.com>
---
drivers/dma/xilinx/zynqmp_dma.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index f6a812e49ddc..a9dfec3c0ca3 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -18,6 +18,7 @@
#include <linux/clk.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include "../dmaengine.h"
@@ -916,6 +917,11 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
if (IS_ERR(chan->regs))
return PTR_ERR(chan->regs);
+ err = device_reset_optional(&pdev->dev);
+ if (err)
+ return dev_err_probe(&pdev->dev, err,
+ "failed to reset channel\n");
+
chan->bus_width = ZYNQMP_DMA_BUS_WIDTH_64;
chan->dst_burst_len = ZYNQMP_DMA_MAX_DST_BURST_LEN;
chan->src_burst_len = ZYNQMP_DMA_MAX_SRC_BURST_LEN;
@@ -1152,6 +1158,7 @@ static int zynqmp_dma_probe(struct platform_device *pdev)
err_disable_pm:
if (!pm_runtime_enabled(zdev->dev))
zynqmp_dma_runtime_suspend(zdev->dev);
+ pm_runtime_put_noidle(zdev->dev);
pm_runtime_disable(zdev->dev);
return ret;
}
--
2.34.1
^ permalink raw reply related
* [PATCH V2 1/3] dt-bindings: dma: xilinx: Add optional resets property for ZDMA
From: Golla Nagendra @ 2026-06-18 7:10 UTC (permalink / raw)
To: vkoul, Frank.Li, michal.simek, robh, krzk+dt, conor+dt,
nagendra.golla, jay.buddhabhatti, harini.katakam, m.tretter,
radhey.shyam.pandey, abin.joseph, kees, sakari.ailus
Cc: git, dmaengine, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20260618071056.2024286-1-nagendra.golla@amd.com>
From: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Newer SoCs such as Versal Gen2 and Versal‑Net expose a reset line
for ZDMA. Older SoCs do not have this provision. Add an optional
resets property to describe this reset.
Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Co-developed-by: Golla Nagendra <nagendra.golla@amd.com>
Signed-off-by: Golla Nagendra <nagendra.golla@amd.com>
---
.../devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
index 2da86037ad79..dff16763e11b 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
+++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
@@ -56,6 +56,9 @@ properties:
iommus:
maxItems: 1
+ resets:
+ maxItems: 1
+
power-domains:
maxItems: 1
--
2.34.1
^ permalink raw reply related
* [PATCH V2 0/3] dmaengine: zynqmp_dma: Add per-channel reset support
From: Golla Nagendra @ 2026-06-18 7:10 UTC (permalink / raw)
To: vkoul, Frank.Li, michal.simek, robh, krzk+dt, conor+dt,
nagendra.golla, jay.buddhabhatti, harini.katakam, m.tretter,
radhey.shyam.pandey, abin.joseph, kees, sakari.ailus
Cc: git, dmaengine, devicetree, linux-arm-kernel, linux-kernel
This series adds per-channel reset support to the ZynqMP DMA driver using
the generic reset framework, along with the corresponding dt-bindings
update. It also adds a runtime PM guard in the IRQ handler to handle
spurious interrupts safely.
Patch 1 adds the optional 'resets' property to the ZynqMP DMA dt-binding.
Patch 2 adds reset control handling in the channel probe path to assert
and deassert the channel reset during initialization.
Patch 3 adds a pm_runtime_get_if_active() check in the IRQ handler to
avoid accessing hardware registers when the device is runtime-suspended,
which could occur on spurious interrupts.
Changes in V2:
- Added patch 3 to guard IRQ handler against spurious interrupts
Golla Nagendra (2):
dmaengine: zynqmp_dma: Add per-channel reset support
dmaengine: zynqmp_dma: Guard IRQ handler against spurious interrupts
Jay Buddhabhatti (1):
dt-bindings: dma: xilinx: Add optional resets property for ZDMA
.../bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml | 3 +++
drivers/dma/xilinx/zynqmp_dma.c | 12 ++++++++++++
2 files changed, 15 insertions(+)
--
2.34.1
^ permalink raw reply
* Re: [PATCH net] net: stmmac: dwmac-spacemit: Fix wrong ctrl register definition
From: Maxime Chevallier @ 2026-06-18 7:03 UTC (permalink / raw)
To: Inochi Amaoto, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
Yixun Lan, Russell King (Oracle)
Cc: netdev, linux-stm32, linux-arm-kernel, linux-riscv, spacemit,
linux-kernel, Yixun Lan, Longbin Li
In-Reply-To: <20260618064143.1102179-1-inochiama@gmail.com>
Hi Inochi,
On 6/18/26 08:41, Inochi Amaoto wrote:
> There register layout of the phy ctrl register has something wrong,
> fix it to match the right layout
>
> Fixes: 30f0ba420ed3 ("net: stmmac: Add glue layer for Spacemit K3 SoC")
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> ---
> .../net/ethernet/stmicro/stmmac/dwmac-spacemit.c | 13 ++++++++-----
> 1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> index 223754cc5c79..6feffaa3ef3a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> @@ -18,10 +18,12 @@
> #include "stmmac_platform.h"
>
> /* ctrl register bits */
> -#define CTRL_PHY_INTF_RGMII BIT(3)
> -#define CTRL_PHY_INTF_MII BIT(4)
> -#define CTRL_WAKE_IRQ_EN BIT(9)
> -#define CTRL_PHY_IRQ_EN BIT(12)
> +#define CTRL_PHY_INTF_MODE GENMASK(4, 3)
> +#define CTRL_PHY_INTF_RMII FIELD_PREP(CTRL_PHY_INTF_MODE, 0)
> +#define CTRL_PHY_INTF_RGMII FIELD_PREP(CTRL_PHY_INTF_MODE, 1)
> +#define CTRL_PHY_INTF_MII FIELD_PREP(CTRL_PHY_INTF_MODE, 3)
> +#define CTRL_PHY_IRQ_EN BIT(9)
> +#define CTRL_WAKE_IRQ_EN BIT(12)
Looks like you're fixing 2 things there :
-> Wake on Lan probably didn't work before, as the wake irq was apparently wrong
-> The MII mode selection apparently also changes, but maybe you don't have a
MII board around to test this ?
Is it possible you address these issues independently (i.e. split this in 2 patches) ?
That way, if we ever revert one, we won't re-break the other thing that was broken.
Maxime
^ permalink raw reply
* Re: [PATCH] memory: stm32_omm: initialize ret in stm32_omm_set_amcr
From: Patrice CHOTARD @ 2026-06-18 6:51 UTC (permalink / raw)
To: Ruoyu Wang, Krzysztof Kozlowski, Maxime Coquelin,
Alexandre Torgue, linux-kernel, linux-stm32, linux-arm-kernel
In-Reply-To: <20260617182202.961843-1-ruoyuw560@gmail.com>
On 6/17/26 20:22, Ruoyu Wang wrote:
> stm32_omm_set_amcr() returns ret after checking whether the AMCR value
> matches the device tree description. On the normal matching path ret is
> not otherwise assigned, so initialize it to 0 before the checks.
>
> Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
> ---
> drivers/memory/stm32_omm.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c
> index 5d06623f3f689..2a1af229d2444 100644
> --- a/drivers/memory/stm32_omm.c
> +++ b/drivers/memory/stm32_omm.c
> @@ -47,7 +47,7 @@ static int stm32_omm_set_amcr(struct device *dev, bool set)
> struct device_node *node;
> struct resource res, res1;
> unsigned int syscon_args[2];
> - int ret, idx;
> + int ret = 0, idx;
> unsigned int i, amcr, read_amcr;
>
> for (i = 0; i < omm->nb_child; i++) {
Hi Ruoyu
Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com>
Thanks
Patrice
^ permalink raw reply
* [PATCH] dt-bindings: spi: st,stm32-qspi: Add power-domains property
From: Patrice Chotard @ 2026-06-18 6:46 UTC (permalink / raw)
To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue, Christophe Kerello
Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, Patrice Chotard
STM32 QSPI may be in a power domain. Allow a single 'power-domains'
entry for STM32 QSPI.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml
index 3f1a27efff80..ee57739b73b8 100644
--- a/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml
+++ b/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml
@@ -50,6 +50,9 @@ properties:
minItems: 1
maxItems: 2
+ power-domains:
+ maxItems: 1
+
required:
- compatible
- reg
---
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
change-id: 20260618-add_power_domain_for_qpsi-898d2ebf20fa
Best regards,
--
Patrice Chotard <patrice.chotard@foss.st.com>
^ permalink raw reply related
* [PATCH net] net: stmmac: dwmac-spacemit: Fix wrong ctrl register definition
From: Inochi Amaoto @ 2026-06-18 6:41 UTC (permalink / raw)
To: Inochi Amaoto, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
Yixun Lan, Russell King (Oracle)
Cc: netdev, linux-stm32, linux-arm-kernel, linux-riscv, spacemit,
linux-kernel, Yixun Lan, Longbin Li
There register layout of the phy ctrl register has something wrong,
fix it to match the right layout
Fixes: 30f0ba420ed3 ("net: stmmac: Add glue layer for Spacemit K3 SoC")
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-spacemit.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
index 223754cc5c79..6feffaa3ef3a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
@@ -18,10 +18,12 @@
#include "stmmac_platform.h"
/* ctrl register bits */
-#define CTRL_PHY_INTF_RGMII BIT(3)
-#define CTRL_PHY_INTF_MII BIT(4)
-#define CTRL_WAKE_IRQ_EN BIT(9)
-#define CTRL_PHY_IRQ_EN BIT(12)
+#define CTRL_PHY_INTF_MODE GENMASK(4, 3)
+#define CTRL_PHY_INTF_RMII FIELD_PREP(CTRL_PHY_INTF_MODE, 0)
+#define CTRL_PHY_INTF_RGMII FIELD_PREP(CTRL_PHY_INTF_MODE, 1)
+#define CTRL_PHY_INTF_MII FIELD_PREP(CTRL_PHY_INTF_MODE, 3)
+#define CTRL_PHY_IRQ_EN BIT(9)
+#define CTRL_WAKE_IRQ_EN BIT(12)
/* dline register bits */
#define RGMII_RX_DLINE_EN BIT(0)
@@ -118,7 +120,7 @@ static void spacemit_get_interfaces(struct stmmac_priv *priv, void *bsp_priv,
static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
{
- unsigned int mask = CTRL_PHY_INTF_MII | CTRL_PHY_INTF_RGMII;
+ unsigned int mask = CTRL_PHY_INTF_MODE;
struct spacmit_dwmac *dwmac = bsp_priv;
unsigned int val = 0;
@@ -128,6 +130,7 @@ static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
break;
case PHY_INTF_SEL_RMII:
+ val = CTRL_PHY_INTF_RMII;
break;
case PHY_INTF_SEL_RGMII:
--
2.54.0
^ permalink raw reply related
* [PATCH net] net: airoha: fix BQL underflow and UAF in shared QDMA TX ring
From: Lorenzo Bianconi @ 2026-06-18 6:13 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Wayen Yan, linux-arm-kernel, linux-mediatek, netdev,
Lorenzo Bianconi
When multiple netdevs share a QDMA TX ring and one device is stopped,
netdev_tx_reset_subqueue() zeroes that device's BQL counters while its
pending skbs remain in the shared HW TX ring. When NAPI later completes
those skbs via netdev_tx_completed_queue(), the already-zeroed
dql->num_queued counter underflows.
Moreover, in the airoha_remove() path, netdevs are unregistered
sequentially while skbs from previously unregistered netdevs may still
reference freed net_device memory via skb->dev, causing a use-after-free
during BQL accounting.
Fix both issues:
- Remove netdev_tx_reset_subqueue() from airoha_dev_stop() so pending
skbs are completed naturally by NAPI with proper BQL accounting.
- Add netdev_tx_completed_queue() in airoha_qdma_cleanup_tx_queue()
to properly account for skbs freed during queue teardown.
- Introduce airoha_qdma_tx_disable() to stop TX on all registered
netdevs for a given QDMA instance under RTNL lock.
- Move DMA engine start/stop into probe/remove and
airoha_qdma_cleanup(), ensuring TX queues are cleaned up while all
netdevs are still registered and skb->dev is valid.
Fixes: 6df0488dc9dd ("net: airoha: fix BQL accounting in airoha_qdma_cleanup_tx_queue()")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 95 ++++++++++++++++++++++++--------
1 file changed, 72 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 64dde6464f3f..4d6a061cd779 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1004,6 +1004,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
e = &q->entry[index];
skb = e->skb;
+ e->skb = NULL;
dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
@@ -1147,6 +1148,42 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma)
return 0;
}
+static void airoha_qdma_tx_disable(struct airoha_qdma *qdma)
+{
+ struct airoha_eth *eth = qdma->eth;
+ int i;
+
+ /* Protect netdev->reg_state and netif_tx_disable() calls. */
+ rtnl_lock();
+
+ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
+ struct airoha_gdm_port *port = eth->ports[i];
+ int j;
+
+ if (!port)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(port->devs); j++) {
+ struct airoha_gdm_dev *dev = port->devs[j];
+ struct net_device *netdev;
+
+ if (!dev)
+ continue;
+
+ if (dev->qdma != qdma)
+ continue;
+
+ netdev = netdev_from_priv(dev);
+ if (netdev->reg_state != NETREG_REGISTERED)
+ continue;
+
+ netif_tx_disable(netdev);
+ }
+ }
+
+ rtnl_unlock();
+}
+
static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
{
struct airoha_qdma *qdma = q->qdma;
@@ -1158,13 +1195,20 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
for (i = 0; i < q->ndesc; i++) {
struct airoha_queue_entry *e = &q->entry[i];
struct airoha_qdma_desc *desc = &q->desc[i];
+ struct sk_buff *skb = e->skb;
if (!e->dma_addr)
continue;
dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
- dev_kfree_skb_any(e->skb);
+ if (skb) {
+ struct netdev_queue *txq;
+
+ txq = skb_get_tx_queue(skb->dev, skb);
+ netdev_tx_completed_queue(txq, 1, skb->len);
+ dev_kfree_skb_any(skb);
+ }
e->dma_addr = 0;
e->skb = NULL;
list_add_tail(&e->list, &q->tx_list);
@@ -1527,6 +1571,23 @@ static void airoha_qdma_cleanup(struct airoha_qdma *qdma)
{
int i;
+ if (test_bit(DEV_STATE_INITIALIZED, &qdma->eth->state)) {
+ u32 status;
+
+ airoha_qdma_tx_disable(qdma);
+
+ airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
+ GLOBAL_CFG_TX_DMA_EN_MASK |
+ GLOBAL_CFG_RX_DMA_EN_MASK);
+ if (read_poll_timeout(airoha_qdma_rr, status,
+ !(status & (GLOBAL_CFG_TX_DMA_BUSY_MASK |
+ GLOBAL_CFG_RX_DMA_BUSY_MASK)),
+ USEC_PER_MSEC, 50 * USEC_PER_MSEC, true,
+ qdma, REG_QDMA_GLOBAL_CFG))
+ dev_warn(qdma->eth->dev,
+ "QDMA DMA engine busy timeout\n");
+ }
+
for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
if (!qdma->q_rx[i].ndesc)
continue;
@@ -1837,9 +1898,6 @@ static int airoha_dev_open(struct net_device *netdev)
}
port->users++;
- airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG,
- GLOBAL_CFG_TX_DMA_EN_MASK |
- GLOBAL_CFG_RX_DMA_EN_MASK);
qdma->users++;
if (!airoha_is_lan_gdm_dev(dev) &&
@@ -1880,12 +1938,9 @@ static int airoha_dev_stop(struct net_device *netdev)
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
struct airoha_qdma *qdma = dev->qdma;
- int i;
netif_tx_disable(netdev);
airoha_set_vip_for_gdm_port(dev, false);
- for (i = 0; i < netdev->num_tx_queues; i++)
- netdev_tx_reset_subqueue(netdev, i);
if (--port->users)
airoha_set_port_mtu(dev->eth, port);
@@ -1893,19 +1948,7 @@ static int airoha_dev_stop(struct net_device *netdev)
airoha_set_gdm_port_fwd_cfg(qdma->eth,
REG_GDM_FWD_CFG(port->id),
FE_PSE_PORT_DROP);
-
- if (!--qdma->users) {
- airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
- GLOBAL_CFG_TX_DMA_EN_MASK |
- GLOBAL_CFG_RX_DMA_EN_MASK);
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
- if (!qdma->q_tx[i].ndesc)
- continue;
-
- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
- }
- }
+ qdma->users--;
return 0;
}
@@ -3413,8 +3456,12 @@ static int airoha_probe(struct platform_device *pdev)
if (err)
goto error_netdev_free;
- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
airoha_qdma_start_napi(ð->qdma[i]);
+ airoha_qdma_set(ð->qdma[i], REG_QDMA_GLOBAL_CFG,
+ GLOBAL_CFG_TX_DMA_EN_MASK |
+ GLOBAL_CFG_RX_DMA_EN_MASK);
+ }
for_each_child_of_node(pdev->dev.of_node, np) {
if (!of_device_is_compatible(np, "airoha,eth-mac"))
@@ -3440,6 +3487,8 @@ static int airoha_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(ð->qdma[i]);
+ airoha_hw_cleanup(eth);
+
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
int j;
@@ -3461,7 +3510,6 @@ static int airoha_probe(struct platform_device *pdev)
}
airoha_metadata_dst_free(port);
}
- airoha_hw_cleanup(eth);
error_netdev_free:
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
@@ -3477,6 +3525,8 @@ static void airoha_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(ð->qdma[i]);
+ airoha_hw_cleanup(eth);
+
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
int j;
@@ -3497,7 +3547,6 @@ static void airoha_remove(struct platform_device *pdev)
}
airoha_metadata_dst_free(port);
}
- airoha_hw_cleanup(eth);
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
---
base-commit: 7d8297e26b4e20b5d1c3c3fe51fe81a1c7fbc823
change-id: 20260618-airoha-bql-fixes-f57b2d108573
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH v2] arm64: tlbflush: Don't broadcast if mm was only active on local cpu
From: Linu Cherian @ 2026-06-18 6:01 UTC (permalink / raw)
To: Will Deacon
Cc: Ryan Roberts, Catalin Marinas, Kevin Brodsky, Anshuman Khandual,
Yang Shi, Mark Rutland, Huang Ying, linux-arm-kernel,
linux-kernel, shameerali.kolothum.thodi
In-Reply-To: <ajAPnahwTe1OHQDp@willie-the-truck>
Hi,
On Mon, Jun 15, 2026 at 03:43:41PM +0100, Will Deacon wrote:
> On Mon, Jun 15, 2026 at 12:21:19PM +0100, Ryan Roberts wrote:
> > On 14/06/2026 12:04, Will Deacon wrote:
> > > On Sat, May 23, 2026 at 07:17:10PM +0530, Linu Cherian wrote:
> > >> From: Ryan Roberts <ryan.roberts@arm.com>
> > >>
> > >> Testing with 7.1-rc4 :
> > >> +-----------------------+---------------------------------------------------+-------------+
> > >> | Benchmark | Result Class | Improvement|
> > >> +=======================+===================================================+=============+
> > >> | perf/syscall | fork (ops/sec) | (I) 3.25% |
> > >> +-----------------------+---------------------------------------------------+-------------+
> > >> | pts/memtier-benchmark | Protocol: Redis Clients: 100 Ratio: 1:5 (Ops/sec) | (I) 2.70% |
> > >> | | Protocol: Redis Clients: 100 Ratio: 5:1 (Ops/sec) | (I) 2.13% |
> > >> +-----------------------+---------------------------------------------------+-------------+
> > >
> > > I think we need a much more comprehensive set of benchmarks before we can
> > > begin to consider a change like this.
> >
> > I believe that Linu ran a wider set of benchmarks and didn't find any
> > regressions. These are just the ones that show improvement (Linu, please correct
> > me and/or provide details).
>
> I think it's important to show the ones that suffer as well... and also
> look at different configurations (e.g. preemptible settings) and different
> environments (e.g. native vs in a VM).
>
> > Additionally Huang Ying did some testing against the RFC and reported 4.5%
> > improvement with Redis:
> >
> > https://lore.kernel.org/linux-arm-kernel/87segumv6w.fsf@DESKTOP-5N7EMDA
>
> To be clear: I'm not disputing that some benchmarks appear to show a small
> boost from this series. I'm just worried that's not the whole story.
>
> > >> arch/arm64/include/asm/mmu.h | 12 +++
> > >> arch/arm64/include/asm/mmu_context.h | 2 +
> > >> arch/arm64/include/asm/tlbflush.h | 127 +++++++++++++++++++++------
> > >> arch/arm64/mm/context.c | 30 ++++++-
> > >> 4 files changed, 141 insertions(+), 30 deletions(-)
> > >
> > > Doesn't this break BTM/SVM with the SMMU? I think that's a non-starter
> > > even if you can provide some more compelling numbers.
> >
> > AIUI, we don't support BTM upstream - the SMMU uses private ASIDs and implements
> > MMU notifiers to forward the TLBIs via its command queue interface.
> >
> > I was also under the impression that supporting BTM upsteam was not desired;
> > Please correct me if that's not accurate or if you're aware of plans to add
> > support. I've been (coincidentlly) looking at some other stuff that could
> > benefit from BTM but had concluded it wouldn't be an acceptable approach upstream.
> >
> > If we did ever want to add SMMU BTM support though, I think it would be simple
> > enough to add an interface to allow the SMMU to disable the optimization (i.e.
> > force active_cpu to ACTIVE_CPU_MULTIPLE)?
>
> We used to have some initial BTM support in the SMMUv3 driver but the
> main problem was finding an upstream driver/soc that can use it properly
> and so it was ultimately removed in d38c28dbefee ("iommu/arm-smmu-v3: Put
> the SVA mmu notifier in the smmu_domain") because it was getting in the
> way of wider driver rework and we couldn't test it.
>
> However, there *is* work to re-enable it on top of that rework (and other
> changes):
>
> https://lore.kernel.org/linux-iommu/20250319173202.78988-6-shameerali.kolothum.thodi@huawei.com/
>
> although I don't know if Shameer intends to repost that...
>
> > >> +static inline bool flush_tlb_user_pre(struct mm_struct *mm, tlbf_t flags)
> > >> +{
> > >> + unsigned int self, active;
> > >> + bool local;
> > >> +
> > >> + migrate_disable();
> > >> +
> > >> + if (flags & TLBF_NOBROADCAST) {
> > >> + dsb(nshst);
> > >> + return true;
> > >> + }
> > >
> > > Why does the NOBROADCAST case need migration disabled? It didn't before...
> >
> > The existing semantic for TLBF_BOBROADCAST is that it emits a local TLBI on
> > whatever CPU we happen to be executing on. It's used for lazily fixing up
> > spurious faults (i.e. hitting RO TLB entries when the PTE has been relaxed to
> > RW). So it's still functionally correct if the thread migrates CPU between
> > taking the fault and issuing the local TLBI - in the worst case it just leads to
> > another spurious fault.
> >
> > For this new case, we need to ensure we don't get migrated between reading
> > active_cpu and issuing the local TLBI, otherwise we would only issue a local
> > TLBI when a broadcast was required.
>
> Sounds like those two users probably need separating out, then?
>
> > >> + self = smp_processor_id();
> > >> +
> > >> + /*
> > >> + * The load of mm->context.active_cpu must not be reordered before the
> > >> + * store to the pgtable that necessitated this flush. This ensures that
> > >> + * if the value read is our cpu id, then no other cpu can have seen the
> > >> + * old pgtable value and therefore does not need this old value to be
> > >> + * flushed from its tlb. But we don't want to upgrade the dsb(ishst),
> > >> + * needed to make the pgtable updates visible to the walker, to a
> > >> + * dsb(ish) by default. So speculatively load without a barrier and if
> > >> + * it indicates our cpu id, then upgrade the barrier and re-load.
> > >> + */
> > >> + active = READ_ONCE(mm->context.active_cpu);
> > >> + if (active == self) {
> > >> + dsb(ish);
> > >> + active = READ_ONCE(mm->context.active_cpu);
> > >> + } else {
> > >> + dsb(ishst);
> > >> + }
> > >
> > > Why can't you just do:
> > >
> > > dsb(ishst);
> > > active = READ_ONCE(mm->context.active_cpu);
> > >
> > > ?
> >
> > Prior to this optimization, we always issued a dsb(ishst) here. Catalin
> > suggested the same simplification against the RFC. I believe Linu tried it but
> > saw regressions; Hopefully Linu can provide the details.
>
> I don't follow...
>
> The old code always did dsb(ishst). The proposed code here does either
> dsb(ish) or dsb(ishst). How can that possibly be faster?
>
> > >> + local = active == self;
> > >> + if (!local)
> > >> + migrate_enable();
> > >> +
> > >> + return local;
> > >> +}
> > >> +
> > >> +static inline void flush_tlb_user_post(bool local)
> > >> +{
> > >> + if (local)
> > >> + migrate_enable();
> > >> +}
> > >
> > > I was under the impression that disabling/enabling migration was an
> > > expensive thing to do, so I'd really want to see some more numbers to
> > > justify this (including from inside a VM) and allow us to consider the
> > > trade-offs properly. It's also not at all clear to me that it's safe
> > > from such a low-level TLB invalidation helper.
> >
> > I had assumed it wasn't very expensive, but perhaps I'm wrong. I know
> > preempt_enable() can be expensive because it has to test to see if it needs to
> > reschedule. But I assumed for disabling/enabling migration, it would just be a
> > counter and the scheduler would check that it's zero before considing moving the
> > task to another run queue. (But I have practically zero understanding of the
> > scheduler so I'll assume I'm wrong...).
>
> I'm not an expert here either, but reading the code shows that it has
> a preempt guard along with additional book-keeping.
>
> > Instead of disabling migration, perhaps we could re-check active_cpu after
> > issuing the local tlbi - if it's now reporting "multiple" we must have been
> > migrated and we need to upgrade to a braodcast TLBI?
>
> That's an interesting idea, although I suppose it means the
> post-invalidation DSB needs to be ISH for the local case to check the
> active_cpu safely?
I might be wrong about this, so please correct me if i am missing
something here.
So we have two possibilities here,
Case 1: Task not migrated until active_cpu is loaded
In this case, the existing dsb(nsh) would suffice to give necessary
ordering between tlbi and active_cpu_load.
Case 2: Task migrated(scheduled to run on another cpu) before active_cpu is loaded
In this case, active_cpu gets upgraded to ACTIVE_CPU_MULTIPLE as part of context switch in
check_and_switch_context and active_cpu gets loaded correctly.
Also we would end up repeating the tlbi op in broadcast mode for this case.
But then, we will have a problem with the TLBF_NOSYNC | TLBF_NOBRODCAST case, as we need
to introduce a dsb(nsh) unconditionally to ensure ordering between the tlbi and
active_cpu load.
Thanks,
Linu Cherian.
^ permalink raw reply
* [PATCH net 2/2] net: airoha: fix netif_set_real_num_tx_queues for sparse QoS channels
From: Lorenzo Bianconi @ 2026-06-18 6:00 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Wayen Yan, linux-arm-kernel, linux-mediatek, netdev,
Lorenzo Bianconi
In-Reply-To: <20260618-airoha-qos-fixes-v1-0-37192652157f@kernel.org>
airoha_tc_htb_alloc_leaf_queue() assigns queue IDs based on the channel
index (opt->qid = AIROHA_NUM_TX_RING + channel), but updates
real_num_tx_queues with a simple increment (num_tx_queues + 1). When QoS
channels are allocated sparsely (e.g., channels 0 and 3 without 1 and
2), the returned qid can exceed real_num_tx_queues, causing out-of-bounds
accesses in the networking stack.
For example, allocating channel 0 then channel 3 results in
real_num_tx_queues = 34 but qid = 35, which is out of range [0, 34).
Fix this by computing real_num_tx_queues based on the highest active
channel index rather than using a simple counter, in both the allocation
and deletion paths.
Fixes: ef1ca9271313b ("net: airoha: Add sched HTB offload support")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index aa98d1823ab6..e2652cff67c0 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2789,7 +2789,7 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
struct tc_htb_qopt_offload *opt)
{
u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
- int err, num_tx_queues = netdev->real_num_tx_queues;
+ int err, num_tx_queues = AIROHA_NUM_TX_RING + channel + 1;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_qdma *qdma = dev->qdma;
@@ -2806,7 +2806,10 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
if (err)
goto error;
- err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1);
+ if (num_tx_queues <= netdev->real_num_tx_queues)
+ goto set_qos_sq_bmap;
+
+ err = netif_set_real_num_tx_queues(netdev, num_tx_queues);
if (err) {
airoha_qdma_set_tx_rate_limit(netdev, channel, 0,
opt->quantum);
@@ -2815,6 +2818,7 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev,
goto error;
}
+set_qos_sq_bmap:
set_bit(channel, dev->qos_sq_bmap);
opt->qid = AIROHA_NUM_TX_RING + channel;
@@ -3003,13 +3007,18 @@ static int airoha_dev_setup_tc_block(struct net_device *dev,
static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
+ int num_tx_queues = AIROHA_NUM_TX_RING;
struct airoha_qdma *qdma = dev->qdma;
- netif_set_real_num_tx_queues(netdev, netdev->real_num_tx_queues - 1);
airoha_qdma_set_tx_rate_limit(netdev, queue, 0, 0);
clear_bit(queue, qdma->qos_channel_map);
clear_bit(queue, dev->qos_sq_bmap);
+
+ if (!bitmap_empty(dev->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS))
+ num_tx_queues += find_last_bit(dev->qos_sq_bmap,
+ AIROHA_NUM_QOS_CHANNELS) + 1;
+ netif_set_real_num_tx_queues(netdev, num_tx_queues);
}
static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev,
--
2.54.0
^ permalink raw reply related
* [PATCH net 1/2] net: airoha: Fix off-by-one in airoha_tc_remove_htb_queue()
From: Lorenzo Bianconi @ 2026-06-18 6:00 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Wayen Yan, linux-arm-kernel, linux-mediatek, netdev,
Lorenzo Bianconi
In-Reply-To: <20260618-airoha-qos-fixes-v1-0-37192652157f@kernel.org>
airoha_tc_htb_alloc_leaf_queue() computes the HTB QoS channel index
as opt->classid % AIROHA_NUM_QOS_CHANNELS and stores it in qos_sq_bmap.
However, airoha_tc_remove_htb_queue() clears the HTB configuration
using queue + 1 as the channel index, causing an off-by-one error.
Use queue directly as the QoS channel index to match the allocation
logic.
Fixes: ef1ca9271313b ("net: airoha: Add sched HTB offload support")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 64dde6464f3f..aa98d1823ab6 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -3006,7 +3006,7 @@ static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue)
struct airoha_qdma *qdma = dev->qdma;
netif_set_real_num_tx_queues(netdev, netdev->real_num_tx_queues - 1);
- airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0);
+ airoha_qdma_set_tx_rate_limit(netdev, queue, 0, 0);
clear_bit(queue, qdma->qos_channel_map);
clear_bit(queue, dev->qos_sq_bmap);
--
2.54.0
^ permalink raw reply related
* [PATCH net 0/2] airoha: fixes for sched HTB offload support
From: Lorenzo Bianconi @ 2026-06-18 6:00 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Wayen Yan, linux-arm-kernel, linux-mediatek, netdev,
Lorenzo Bianconi
---
Lorenzo Bianconi (2):
net: airoha: Fix off-by-one in airoha_tc_remove_htb_queue()
net: airoha: fix netif_set_real_num_tx_queues for sparse QoS channels
drivers/net/ethernet/airoha/airoha_eth.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
---
base-commit: 7d8297e26b4e20b5d1c3c3fe51fe81a1c7fbc823
change-id: 20260618-airoha-qos-fixes-b6460b085680
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
From: Frieder Schrempf @ 2026-06-18 5:52 UTC (permalink / raw)
To: Frank Li
Cc: Pankaj Gupta, Peng Fan (OSS), Frieder Schrempf,
Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo, devicetree, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <ajL7-OqjYuQHyZOI@SMW015318>
On 17.06.26 21:56, Frank Li wrote:
> On Wed, Jun 17, 2026 at 08:54:35AM +0200, Frieder Schrempf wrote:
>> On 16.06.26 22:05, Frank Li wrote:
>>> On Tue, Jun 16, 2026 at 07:59:54PM +0200, Frieder Schrempf wrote:
>>>> On 16.06.26 17:36, Frank Li wrote:
>>>>> On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
>>>>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>>>
>>>>>> The ELE S400 API provides read and write access to the OCOTP fuse
>>>>>> registers. This adds the necessary API functions imx_se_read_fuse()
>>>>>> and imx_se_write_fuse() to be used by other drivers such as the
>>>>>> OCOTP S400 NVMEM driver.
>>>>>>
>>>>>> This is ported from the downstream vendor kernel.
>>>>>>
>>>>>> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>>> ---
>>>>>> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
>>>>>> drivers/firmware/imx/ele_base_msg.h | 6 ++
>>>>>> include/linux/firmware/imx/se_api.h | 3 +
>>>>>> 3 files changed, 131 insertions(+)
>>>>>>
>>>>> ...
>>>>>> +++ b/include/linux/firmware/imx/se_api.h
>>>>>> @@ -11,4 +11,7 @@
>>>>>> #define SOC_ID_OF_IMX8ULP 0x084d
>>>>>> #define SOC_ID_OF_IMX93 0x9300
>>>>>>
>>>>>> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
>>>>>> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
>>>>>> +
>>>>>
>>>>> This API should implement in fuse drivers. Other consume should use standard
>>>>> fuse API to get value. If put here, it may bypass fuse driver.
>>>>
>>>> The reason this is here, is the downstream implementation in linux-imx
>>>> and the current code organization.
>>>
>>> Downstream may not good enough, sometime, it is quick solution.
>>
>> Ok, but the code structure and API design has been upstreamed like this
>> and the refactoring could have been done before, if downstream is known
>> to not be well organized.
>>
>>>
>>>> I thought there is some good reason
>>>> to have shared functions and it looks like Pankaj structured it like
>>>> this so all API functions live in ele_base_msg.c and the internal
>>>> structs and defines in ele_base_msg.h and se_ctrl.h are not exposed to
>>>> other drivers.
>>>>
>>>> If I would move this into imx-ocotp-ele.c, then I would also need to
>>>> change how the code is organized and make the internal se_api functions
>>>> exposed to other drivers. I don't know if that is really a good idea.
>>>>
>>>> I get your point but it looks like this contradicts the intention of
>>>> having a clean API in the firmware driver.
>>>
>>> You can refer imx-ocotp-scu.c, structure should be similar, only difference
>>> is that lower transfer APIs.
>> Ok, this would mean that I expose the generic SE functions and structs
>> required for fuse handling. In practice, I would remove
>> imx_se_read_fuse() and imx_se_write_fuse() from se_api.h and instead add
>> the following:
>>
>> struct se_msg_hdr { ... };
>> struct se_api_msg { ... };
>> struct se_if_priv;
>> se_fill_cmd_msg_hdr( ... );
>> se_msg_send_rcv( ... );
>> se_val_rsp_hdr_n_status( ... );
>>
>> Then I would export the functions in ele_common.c and put the fuse
>> read/write functions in the NVMEM driver.
>>
>> Is that what you want me to do?
>
> Yes, Idealy, it should be children device under ele, ELE like a bus, which
> previous lower level data transfer, ocotp should be base on top then it.
> like spi/i2c, which provide low level data transfer.
Ok, please also see the discussion with Krzysztof on the bindings patch.
The problem is that this driver uses both, MMIO and firmware interface.
Therefore putting a child node in the ELE device node is probably not
correct, either!?
In general I think it's a good idea as the fuses actually live inside
the ELE block so this would properly describe the hardware, but again
this would create a hard dependency on the closed source ELE firmware
which I don't like that much.
^ permalink raw reply
* Question: pinctrl-backed GPIO set_config and gpio_chip::can_sleep
From: Runyu Xiao @ 2026-06-18 5:36 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski
Cc: Ludovic Desroches, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Antonio Borneo, Maxime Coquelin, Alexandre Torgue,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, linux-arm-kernel,
linux-gpio, linux-stm32, linux-sunxi, linux-kernel, jianhao.xu,
runyu.xiao
Hi,
While auditing pinctrl-backed GPIO chips, our static analysis tool
flagged several controllers that expose gpiochip_generic_config() while
still advertising a non-sleeping gpio_chip. We then manually reviewed
the findings against the current tree.
The path we are concerned about is:
gpiod_set_config()
-> gpio_do_set_config()
-> gpiochip_generic_config()
-> pinctrl_gpio_set_config()
-> pinctrl_get_device_gpio_range()
-> mutex_lock(&pctldev->mutex)
If gpiod_cansleep() returns false, a GPIO forwarder or another consumer
can choose an atomic carrier and call gpiod_set_config() while holding a
spinlock. A minimal Lockdep reproducer preserving this carrier reports:
BUG: sleeping function called from invalid context
#0: ... (&global_shared_desc.spinlock) ...
pinctrl_get_device_gpio_range
gpiochip_generic_config
[ BUG: Invalid wait context ]
This looks similar to the Meson fix that marked the GPIO controller as
sleeping when GPIO configuration is routed through the pinctrl-backed
generic config path.
The local draft I am considering marks only these controllers as
sleeping:
pinctrl: at91-pio4: mark the GPIO controller as sleeping
pinctrl: stm32: mark the GPIO controller as sleeping
pinctrl: sunxi: mark the GPIO controller as sleeping
The reason is that all three expose gpiochip_generic_config() and can
therefore reach the pinctrl mutex from the GPIO set_config path, while
their current gpio_chip registration does not set can_sleep.
Two other candidates from the same audit, bcm2835 and keembay, are not
part of this draft. They use gpio_irq_chip::parent_handler, and gpiolib
rejects chained interrupts on a GPIO chip that may sleep. Setting
can_sleep there would therefore break registration instead of fixing the
contract; those cases need a separate irqchip design review.
Does setting gpio_chip::can_sleep for the at91-pio4, stm32 and sunxi
pinctrl-backed GPIO chips sound like the right fix for this set_config
contract mismatch? Or would you prefer this to be handled elsewhere in
gpiolib/pinctrl so that set_config sleepability can be represented more
narrowly than the whole gpio_chip?
Thanks,
Runyu
^ permalink raw reply
* Re: [PATCH v7 2/4] PCI: Use standard wait times for PCIe link monitoring
From: Aksh Garg @ 2026-06-18 5:19 UTC (permalink / raw)
To: Thierry Reding, Bjorn Helgaas, Lorenzo Pieralisi,
Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Karthikeyan Mitran, Hou Zhiqiang,
Thomas Petazzoni, Pali Rohár, Michal Simek, Kevin Xie
Cc: linux-pci, devicetree, linux-tegra, linux-kernel,
linux-arm-kernel, Thierry Reding
In-Reply-To: <20260617-tegra264-pcie-v7-2-eae7ae964629@nvidia.com>
On 17/06/26 21:31, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> Instead of defining the wait values for each driver, use common values
> defined in the core pci.h header file. Note that while most drivers use
> the usleep_range(), it looks like these were mostly cargo culted and
> msleep() is a better choice given the fixed delay that the specification
> calls for. Convert all drivers to msleep() and use the existing
> definition.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
Reviewed-by: Aksh Garg <a-garg7@ti.com>
> Changes in v7:
> - rebase on top of next-20260615 (resolve pci-aardvark.c conflict)
>
> Changes in v6:
> - convert all drivers to use msleep() (Lukas Wunner)
>
> Changes in v2:
> - fix build for Cadence
> ---
^ permalink raw reply
* [PATCH 11/11] ARM: dts: ux500: Remove DB8500 EPOD regulators
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Delete the obsolete DB8500 EPOD regulator nodes.
Keep the VAPE and VSMPS2 compatibility regulators.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
arch/arm/boot/dts/st/ste-dbx5x0.dtsi | 92 ------------------------------------
1 file changed, 92 deletions(-)
diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
index fd6a075e4c93..18727953a863 100644
--- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
@@ -663,97 +663,17 @@ thermal: thermal@801573c0 {
#thermal-sensor-cells = <0>;
};
- /*
- * TODO: Delete these bogus regulators and replace with power
- * domains.
- */
db8500-prcmu-regulators {
compatible = "stericsson,db8500-prcmu-regulator";
- // DB8500_REGULATOR_VAPE
db8500_vape_reg: db8500_vape {
regulator-always-on;
power-domains = <&pm_domains DOMAIN_VAPE>;
};
- // DB8500_REGULATOR_VARM
- db8500_varm_reg: db8500_varm {
- };
-
- // DB8500_REGULATOR_VMODEM
- db8500_vmodem_reg: db8500_vmodem {
- };
-
- // DB8500_REGULATOR_VPLL
- db8500_vpll_reg: db8500_vpll {
- };
-
- // DB8500_REGULATOR_VSMPS1
- db8500_vsmps1_reg: db8500_vsmps1 {
- };
-
- // DB8500_REGULATOR_VSMPS2
db8500_vsmps2_reg: db8500_vsmps2 {
power-domains = <&pm_domains DOMAIN_VSMPS2>;
};
-
- // DB8500_REGULATOR_VSMPS3
- db8500_vsmps3_reg: db8500_vsmps3 {
- };
-
- // DB8500_REGULATOR_VRF1
- db8500_vrf1_reg: db8500_vrf1 {
- };
-
- // DB8500_REGULATOR_SWITCH_SVAMMDSP
- db8500_sva_mmdsp_reg: db8500_sva_mmdsp {
- };
-
- // DB8500_REGULATOR_SWITCH_SVAMMDSPRET
- db8500_sva_mmdsp_ret_reg: db8500_sva_mmdsp_ret {
- };
-
- // DB8500_REGULATOR_SWITCH_SVAPIPE
- db8500_sva_pipe_reg: db8500_sva_pipe {
- };
-
- // DB8500_REGULATOR_SWITCH_SIAMMDSP
- db8500_sia_mmdsp_reg: db8500_sia_mmdsp {
- };
-
- // DB8500_REGULATOR_SWITCH_SIAMMDSPRET
- db8500_sia_mmdsp_ret_reg: db8500_sia_mmdsp_ret {
- };
-
- // DB8500_REGULATOR_SWITCH_SIAPIPE
- db8500_sia_pipe_reg: db8500_sia_pipe {
- };
-
- // DB8500_REGULATOR_SWITCH_SGA
- db8500_sga_reg: db8500_sga {
- vin-supply = <&db8500_vape_reg>;
- };
-
- // DB8500_REGULATOR_SWITCH_B2R2_MCDE
- db8500_b2r2_mcde_reg: db8500_b2r2_mcde {
- vin-supply = <&db8500_vape_reg>;
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM12
- db8500_esram12_reg: db8500_esram12 {
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM12RET
- db8500_esram12_ret_reg: db8500_esram12_ret {
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM34
- db8500_esram34_reg: db8500_esram34 {
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM34RET
- db8500_esram34_ret_reg: db8500_esram34_ret {
- };
};
};
@@ -1111,8 +1031,6 @@ msp0: msp@80123000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80123000 0x1000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
dmas = <&dma 31 0 0x12>, /* Logical - DevToMem - HighPrio */
@@ -1130,8 +1048,6 @@ msp1: msp@80124000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80124000 0x1000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
/* This DMA channel only exist on DB8500 v1 */
@@ -1150,8 +1066,6 @@ msp2: msp@80117000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80117000 0x1000>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
dmas = <&dma 14 0 0x12>, /* Logical - DevToMem - HighPrio */
@@ -1170,8 +1084,6 @@ msp3: msp@80125000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80125000 0x1000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
/* This DMA channel only exist on DB8500 v2 */
@@ -1215,8 +1127,6 @@ gpu@a0300000 {
clocks = <&prcmu_clk PRCMU_ACLK>, <&prcmu_clk PRCMU_SGACLK>;
clock-names = "bus", "core";
power-domains = <&pm_domains DOMAIN_SGA>;
- /* TODO: delete and replace with power-domain handling */
- mali-supply = <&db8500_sga_reg>;
};
mcde@a0350000 {
@@ -1224,8 +1134,6 @@ mcde@a0350000 {
reg = <0xa0350000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&pm_domains DOMAIN_B2R2_MCDE>;
- /* TODO: delete and replace with power-domain handling */
- epod-supply = <&db8500_b2r2_mcde_reg>;
clocks = <&prcmu_clk PRCMU_MCDECLK>, /* Main MCDE clock */
<&prcmu_clk PRCMU_LCDCLK>, /* LCD clock */
<&prcmu_clk PRCMU_PLLDSI>; /* HDMI clock */
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox