Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 3/8] mfd: khadas-mcu: Add per-variant configuration infrastructure and VIM4 support
From: Ronald Claveau via B4 Relay @ 2026-07-02  9:55 UTC (permalink / raw)
  To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
	Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
	Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
  Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
	linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260702-add-mcu-fan-khadas-vim4-v8-0-244feee91a36@aliel.fr>

From: Ronald Claveau <linux-kernel-dev@aliel.fr>

Some values change per variant, add the structure to manage it.

Add an enum khadas_mcu_type used as value to match.

Also introduce khadas_mcu_fan_pdata to pass fan register address and
maximum level to the fan sub-driver, removing the hardcoded constants.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
 include/linux/mfd/khadas-mcu.h | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/include/linux/mfd/khadas-mcu.h b/include/linux/mfd/khadas-mcu.h
index a99ba2ed0e4e0..471a31787cce2 100644
--- a/include/linux/mfd/khadas-mcu.h
+++ b/include/linux/mfd/khadas-mcu.h
@@ -70,6 +70,13 @@
 #define KHADAS_MCU_WOL_INIT_START_REG		0x87 /* WO */
 #define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG	0x88 /* WO */
 
+/* VIM4 specific registers */
+#define KHADAS_MCU_VIM4_REST_CONF_REG		0x2c /* WO - reset EEPROM */
+#define KHADAS_MCU_VIM4_LED_ON_RAM_REG		0x89 /* WO - LED volatile */
+#define KHADAS_MCU_VIM4_FAN_CTRL_REG		0x8a /* WO */
+#define KHADAS_MCU_VIM4_WDT_EN_REG		0x8b /* WO */
+#define KHADAS_MCU_VIM4_SYS_RST_REG		0x91 /* WO */
+
 enum {
 	KHADAS_BOARD_VIM1 = 0x1,
 	KHADAS_BOARD_VIM2,
@@ -88,4 +95,19 @@ struct khadas_mcu {
 	struct regmap *regmap;
 };
 
+/**
+ * struct khadas_mcu_fan_pdata - fan sub-driver configuration
+ * @fan_reg: register address to write the fan level
+ * @max_level: maximum fan level
+ */
+struct khadas_mcu_fan_pdata {
+	unsigned int fan_reg;
+	unsigned int max_level;
+};
+
+enum khadas_mcu_type {
+	KHADAS_MCU_GENERIC, /* VIM1/2/3, Edge, Edge-V */
+	KHADAS_MCU_VIM4,
+};
+
 #endif /* MFD_KHADAS_MCU_H */

-- 
2.49.0




^ permalink raw reply related

* [PATCH v8 8/8] arm64: dts: amlogic: t7: khadas-vim4: Add i2c MCU fan node
From: Ronald Claveau via B4 Relay @ 2026-07-02  9:56 UTC (permalink / raw)
  To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
	Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
	Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
  Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
	linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260702-add-mcu-fan-khadas-vim4-v8-0-244feee91a36@aliel.fr>

From: Ronald Claveau <linux-kernel-dev@aliel.fr>

Enable and configure i2c MCU node to get fan working on Khadas VIM4.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
 .../boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts      | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index 69d6118ba57e7..5d7f5390f3a66 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -157,6 +157,19 @@ wifi32k: wifi32k {
 	};
 };
 
+&i2c_m_ao_a {
+	status = "okay";
+	pinctrl-0 = <&i2c0_ao_d_pins>;
+	pinctrl-names = "default";
+
+	khadas_mcu: system-controller@18 {
+		compatible = "khadas,vim4-mcu";
+		reg = <0x18>;
+		fan-supply = <&vcc5v>;
+		#cooling-cells = <2>;
+	};
+};
+
 &pwm_ab {
 	status = "okay";
 	pinctrl-0 = <&pwm_a_pins>;

-- 
2.49.0




^ permalink raw reply related

* [PATCH v8 1/8] dt-bindings: mfd: khadas: Add new compatible for Khadas VIM4 MCU
From: Ronald Claveau via B4 Relay @ 2026-07-02  9:55 UTC (permalink / raw)
  To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
	Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
	Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
  Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
	linux-arm-kernel, linux-pm, Ronald Claveau, Conor Dooley
In-Reply-To: <20260702-add-mcu-fan-khadas-vim4-v8-0-244feee91a36@aliel.fr>

From: Ronald Claveau <linux-kernel-dev@aliel.fr>

The Khadas VIM4 MCU register is slightly different
from previous boards' MCU.
This board also features a switchable power source for its fan.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
 Documentation/devicetree/bindings/mfd/khadas,mcu.yaml | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
index 084960fd5a1fd..1f135618e3b6f 100644
--- a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
+++ b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
@@ -18,6 +18,7 @@ properties:
   compatible:
     enum:
       - khadas,mcu # MCU revision is discoverable
+      - khadas,vim4-mcu # Different MCU variant, not discoverable
 
   "#cooling-cells": # Only needed for boards having FAN control feature
     const: 2
@@ -25,10 +26,27 @@ properties:
   reg:
     maxItems: 1
 
+  fan-supply:
+    description: Phandle to the regulator that powers the fan.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
 required:
   - compatible
   - reg
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: khadas,vim4-mcu
+    then:
+      required:
+        - fan-supply
+    else:
+      properties:
+        fan-supply: false
+
 additionalProperties: false
 
 examples:

-- 
2.49.0




^ permalink raw reply related

* [PATCH v8 7/8] arm64: dts: amlogic: t7: Add i2c controller node
From: Ronald Claveau via B4 Relay @ 2026-07-02  9:56 UTC (permalink / raw)
  To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
	Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
	Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
  Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
	linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260702-add-mcu-fan-khadas-vim4-v8-0-244feee91a36@aliel.fr>

From: Ronald Claveau <linux-kernel-dev@aliel.fr>

Add the T7 i2c controller node used by the Khadas VIM4
for MCU communication.

Use amlogic,meson-axg-i2c as fallback compatible.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
 arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index e96fe10b251a0..560c9dce35266 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -711,6 +711,16 @@ pwm_ao_cd: pwm@60000 {
 				status = "disabled";
 			};
 
+			i2c_m_ao_a: i2c@76000 {
+				compatible = "amlogic,t7-i2c", "amlogic,meson-axg-i2c";
+				reg = <0x0 0x76000 0x0 0x48>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				interrupts = <GIC_SPI 330 IRQ_TYPE_EDGE_RISING>;
+				clocks = <&clkc_periphs CLKID_SYS_I2C_AO_A>;
+				status = "disabled";
+			};
+
 			sd_emmc_a: mmc@88000 {
 				compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
 				reg = <0x0 0x88000 0x0 0x800>;

-- 
2.49.0




^ permalink raw reply related

* [PATCH v8 2/8] dt-bindings: i2c: amlogic: Add compatible for T7 SOC
From: Ronald Claveau via B4 Relay @ 2026-07-02  9:55 UTC (permalink / raw)
  To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
	Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
	Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
  Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
	linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260702-add-mcu-fan-khadas-vim4-v8-0-244feee91a36@aliel.fr>

From: Ronald Claveau <linux-kernel-dev@aliel.fr>

Add the T7 SOC compatible which fallback to AXG compatible.

Acked-by: Rob Herring (Arm) <robh@kernel.org>
Acked-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
 .../devicetree/bindings/i2c/amlogic,meson6-i2c.yaml         | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml b/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
index c4cc8af182807..7b59b60b62e5b 100644
--- a/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
@@ -16,10 +16,15 @@ allOf:
 
 properties:
   compatible:
-    enum:
-      - amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
-      - amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
-      - amlogic,meson-axg-i2c # AXG and compatible SoCs
+    oneOf:
+      - items:
+          - enum:
+              - amlogic,t7-i2c
+          - const: amlogic,meson-axg-i2c
+      - enum:
+          - amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
+          - amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
+          - amlogic,meson-axg-i2c # AXG and compatible SoCs
 
   reg:
     maxItems: 1

-- 
2.49.0




^ permalink raw reply related

* [PATCH v8 6/8] arm64: dts: amlogic: t7: Add i2c pinctrl node
From: Ronald Claveau via B4 Relay @ 2026-07-02  9:55 UTC (permalink / raw)
  To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
	Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
	Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
  Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
	linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260702-add-mcu-fan-khadas-vim4-v8-0-244feee91a36@aliel.fr>

From: Ronald Claveau <linux-kernel-dev@aliel.fr>

Add the T7 pinctrl used by the Khadas VIM4 for MCU communication.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
 arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index 7fe72c94ed623..e96fe10b251a0 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -376,6 +376,16 @@ mux {
 					};
 				};
 
+				i2c0_ao_d_pins: i2c0-ao-d {
+					mux {
+						groups = "i2c0_ao_sck_d",
+							 "i2c0_ao_sda_d";
+						function = "i2c0_ao";
+						bias-disable;
+						drive-strength-microamp = <3000>;
+					};
+				};
+
 				pwm_a_pins: pwm-a {
 					mux {
 						groups = "pwm_a";

-- 
2.49.0




^ permalink raw reply related

* Re: [PATCH v3] Subject: [PATCH] net: gro: fix double aggregation of flush-marked skbs
From: Paolo Abeni @ 2026-07-02 10:02 UTC (permalink / raw)
  To: Shiming Cheng, davem, edumazet, kuba, horms, matthias.bgg,
	angelogioacchino.delregno, willemb, daniel.zahka, alice, sd,
	eilaimemedsnaimel, imv4bel, nbd, dsahern, netdev, linux-kernel,
	linux-arm-kernel, linux-mediatek
  Cc: stable, lena.wang
In-Reply-To: <20260630023512.26927-1-shiming.cheng@mediatek.com>

Note: the patch subject is quite uncorrected

On 6/30/26 4:35 AM, Shiming Cheng wrote:
> The new skb_gro_receive_list() function is missing a critical safety check
> present in the legacy skb_gro_receive() path. Specifically, it does not
> validate NAPI_GRO_CB(skb)->flush before allowing packet aggregation.

skb_gro_receive_list() is not very "new" and definitely
skb_gro_receive() is not legacy.

> This allows already-GRO'd packets with existing frag_list to be
> re-aggregated into a new GRO session, corrupting the frag_list chain
> structure. When skb_segment() attempts to unpack these malformed packets,
> it encounters invalid state and triggers a kernel panic.
> 
> Scenario (Tethering/Device forwarding):
>   1. Driver: Generated aggregated packet P1 via LRO with frag_list
>   2. Dev A: Receives aggregated fraglist packet and flush flag set
>   3. Dev A: Re-enters GRO, skb_gro_receive_list() is called
>   4. Missing flush check allows re-aggregation despite flush flag
>   5. Frag_list chain becomes corrupted (loops or dangling refs)
>   6. Dev B: TX path calls skb_segment(), crashes on corrupted frag_list

I can't parse the above. Is this something that can happen with in-tree
drivers or do you need OoT module to trigger it? In any case please
clarify the actual order and the involved driver. Possibly a stack
strace leading to the critical aggregation could help.

> Fix: Add NAPI_GRO_CB(skb)->flush validation to the early-return check in
> skb_gro_receive_list(), matching the defensive programming pattern of
> skb_gro_receive().
> 
> Fixes: 8928756d53d5 ("net: add fraglist GRO/GSO support")

The fix tag is wrong, should be:

Fixes: 3a1296a38d0c ('net: Support GRO/GSO fraglist chaining.')

/P



^ permalink raw reply

* Re: [RFC 0/2] arm64: kprobes: Fix single-step fault and reentry handling
From: Pu Hu @ 2026-07-02 10:07 UTC (permalink / raw)
  To: Masami Hiramatsu (Google), catalin.marinas@arm.com,
	will@kernel.org, naveen@kernel.org, davem@davemloft.net,
	yang@os.amperecomputing.com, Hongyan Xia, Jiazi Li,
	ada.coupriediaz@arm.com, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org
In-Reply-To: <ec11e9ca-ae7c-49c3-ae7b-47a70e9f86af@transsion.com>

On 7/1/2026 9:56 PM, Pu Hu wrote:
> On 7/1/2026 9:43 PM, Masami Hiramatsu wrote:
>> On Wed, 1 Jul 2026 12:14:54 +0000
>> Pu Hu <hupu@transsion.com> wrote:
>>
>>> From: hupu <hupu@transsion.com>
>>>
>>> This series fixes two arm64 kprobes issues observed when running
>>> simpleperf with preemptirq tracepoints and dwarf callchains while a
>>> kprobe is active on a frequently executed kernel function.
>>>
>>> The crash happens in the kprobe debug exception path. While a kprobe is
>>> preparing or executing its XOL single-step instruction, perf/trace code
>>> can run in the same window. That code may either take a fault of its own
>>> or hit another kprobe.
>>>
>>> Patch 1 makes kprobe_fault_handler() handle a fault in
>>> KPROBE_HIT_SS/KPROBE_REENTER only when the faulting PC points at the
>>> current kprobe's XOL instruction. Otherwise the fault is left to the
>>> normal fault handling path.
>>>
>>> Patch 2 allows a kprobe hit in KPROBE_HIT_SS to be handled as a
>>> recoverable one-level reentry. Only a hit while already in
>>> KPROBE_REENTER remains unrecoverable.
>>>
>>> This follows the same logic as the existing x86 fixes:
>>>    6381c24cd6d5 ("kprobes/x86: Fix page-fault handling logic")
>>>    6a5022a56ac3 ("kprobes/x86: Allow to handle reentered kprobe on 
>>> single-stepping")
>>
>> Good catch!!
>> The series looks good to me.
>>
>> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
>>
>> But it should be reviewed by arm64 maintainers too.
>>
>> BTW, if you are "Pu Hu", the Signed-off-by tag should be
>> "Pu Hu <...>" instead of "hupu <...>".
>>
> 
> Hi Masami,
> 
> Thank you for your reply and Acked-by.
> 
> Yes, thanks for pointing this out. I will fix the author name and the
> Signed-off-by tags to use a consistent name in the next version of the
> patchset.
> 
> Thanks,
> hupu
> 


Hi maintainers,

I have reproduced the same issue on the latest mainline kernel available
today. The commit I tested is 665159e24674.

Below are the steps I used to reproduce the issue. I hope this can help
with further debugging. The complete test case used in these steps will 
be provided in a follow-up email.

Reproduction steps:

1. Build the test case

Please use the test case that I will send in the next email. Depending 
on your local environment, the following variables in the Makefile may 
need to be adjusted:

     CROSS_COMPILE ?= aarch64-dumpstack-linux-gnu-
     KERN_DIR      ?= $(PWD)/../../output/build-mainline
     DEST_PATH     ?= $(PWD)/../../output

Then run:

     make all

This builds the userspace test program:

     fault_stress

and the kprobe module:

     kp_folio.ko

2. Boot QEMU

To increase memory pressure, I used only two CPUs and 512 MB of memory 
in the QEMU guest:

     SMP="-smp 2"

     qemu-system-aarch64 -m 512 -cpu cortex-a53 \
         -M virt,gic-version=3,its=on,iommu=smmuv3 \
         -nographic $SMP -kernel $KERNEL_IMAGE \
         -append "nokaslr noinitrd sched_debug root=/dev/vda 
rootfstype=ext4 rw crashkernel=256M loglevel=8" \
         -drive if=none,file=$ROOTFS_IMAGE,id=hd0,format=raw \
         -device virtio-blk-device,drive=hd0 \
         --fsdev local,id=kmod_dev,path=./output/,security_model=none \
         -device virtio-9p-pci,fsdev=kmod_dev,mount_tag=kmod_mount \
         -net nic -net tap,ifname=tap0,script=no,downscript=no \
         $GDB_DEBUG

3. Run the test in the guest

After the guest has booted, run the following commands.

Allow kernel symbols to be shown:

     echo 0 > /proc/sys/kernel/kptr_restrict

Load the kprobe module:

     insmod kp_folio.ko

Start the fault stress program:

     ./fault_stress &

Start stress-ng to add memory pressure:

     ./stress-ng --vm 2 --vm-bytes 70% --page-in &

Run perf against the fault_stress process. In the command below, 171 is 
the PID of fault_stress in my test environment:

     ./perf record -p 171 -c 1 \
         -e preemptirq:preempt_disable \
         -e preemptirq:preempt_enable \
         --call-graph dwarf \
         -o /tmp/perf.data \
         -- sleep 5

With the steps above, I can reproduce the crash reliably in my local 
QEMU setup. After applying my previously submitted fix, I can no longer 
reproduce the issue with the same test.

The crash log is shown below:

[  173.383321] kp_folio: hit=1564 comm=fault_stress tgid=171 tid=173
[  173.402940] kp_folio: hit=1565 comm=fault_stress tgid=171 tid=179
[  173.528342] kp_folio: hit=1566 comm=fault_stress tgid=171 tid=175
[  173.846895] kp_folio: hit=1567 comm=fault_stress tgid=171 tid=172
[  174.223031] kp_folio: hit=1568 comm=fault_stress tgid=171 tid=179
[  174.224419] kp_folio: hit=1569 comm=fault_stress tgid=171 tid=174
[  174.928471] kp_folio: hit=1570 comm=fault_stress tgid=171 tid=175
[  174.930916] Unable to handle kernel paging request at virtual address 
0000ffffa3592000
[  174.931068] Mem abort info:
[  174.931116]   ESR = 0x0000000096000007
[  174.931180]   EC = 0x25: DABT (current EL), IL = 32 bits
[  174.931240]   SET = 0, FnV = 0
[  174.931368]   EA = 0, S1PTW = 0
[  174.931430]   FSC = 0x07: level 3 translation fault
[  174.931490] Data abort info:
[  174.931540]   ISV = 0, ISS = 0x00000007, ISS2 = 0x00000000
[  174.931593]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[  174.931669]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[  174.931762] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000049bf8000
[  174.931829] [0000ffffa3592000] pgd=0800000049a99403, 
p4d=0800000049a99403, pud=0800000049ac0403, pmd=0800000049bed403, 
pte=00000000000047c0
[  174.932328] Internal error: Oops: 0000000096000007 [#1]  SMP
[  174.939042] Modules linked in: kp_folio(O)
[  174.942114] CPU: 1 UID: 0 PID: 175 Comm: fault_stress Tainted: G 
      O        7.2.0-rc1-00010-g7679152d724a-dirty #2 PREEMPT
[  174.945427] Tainted: [O]=OOT_MODULE
[  174.946006] Hardware name: linux,dummy-virt (DT)
[  174.947011] pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS 
BTYPE=--)
[  174.948582] pc : folio_wait_bit_common+0x0/0x320
[  174.949626] lr : perf_output_sample+0x708/0x968
[  174.950041] sp : ffff800084b13540
[  174.950511] x29: ffff800084b13570 x28: ffff000006704260 x27: 
0000ffffa3591d08
[  174.953274] x26: ffff000009a19a80 x25: 0000000000000000 x24: 
ffff800084b13780
[  174.953601] x23: 0000000000000ee8 x22: 000000000000b5ef x21: 
0000000000001000
[  174.954003] x20: 0000000000000ee8 x19: ffff800084b135e0 x18: 
000000000000000a
[  174.954262] x17: ffff8000803d1af4 x16: ffff80008036d01c x15: 
0000ffffa3591d08
[  174.954549] x14: 0000000000000000 x13: 0000000000000000 x12: 
0000000000000000
[  174.954863] x11: 0000000000000000 x10: 0000000000000000 x9 : 
0000000000000000
[  174.955315] x8 : 0000000000000000 x7 : 0000000000000000 x6 : 
ffff0000069ce2c8
[  174.955592] x5 : ffff0000069ceee8 x4 : 0000000000000008 x3 : 
0000000000000000
[  174.956083] x2 : 0000000000000be0 x1 : 0000ffffa3592000 x0 : 
ffff0000069ce000
[  174.956838] Call trace:
[  174.958282]  folio_wait_bit_common+0x0/0x320 (P)
[  174.958618]  perf_event_output_forward+0xc0/0x1a8
[  174.958811]  __perf_event_overflow+0x108/0x518
[  174.959066]  perf_swevent_event+0x238/0x260
[  174.959295]  perf_tp_event+0x34c/0x6a0
[  174.959667]  perf_trace_run_bpf_submit+0x8c/0xd0
[  174.962331]  perf_trace_preemptirq_template+0xc4/0x130
[  174.962644]  trace_preempt_on+0x114/0x1e8
[  174.963019]  preempt_count_sub+0x78/0xe0
[  174.963402]  el1_brk64+0x40/0x60
[  174.963617]  el1h_64_sync_handler+0x68/0xb0
[  174.963817]  el1h_64_sync+0x6c/0x70
[  174.964239]  0xffff8000846c5000 (P)
[  174.964938]  __do_fault+0x44/0x288
[  174.965452]  __handle_mm_fault+0xaf8/0x1a40
[  174.965815]  handle_mm_fault+0xb4/0x420
[  174.966527]  do_page_fault+0x140/0x7b0
[  174.967398]  do_translation_fault+0x4c/0x70
[  174.968057]  do_mem_abort+0x48/0xa0
[  174.969705]  el0_da+0x64/0x290
[  174.969984]  el0t_64_sync_handler+0xd0/0xe8
[  174.970324]  el0t_64_sync+0x198/0x1a0
[  174.970713] Code: d50323bf d65f03c0 12800140 17fffffc (d4200080)
[  174.971338] kp_folio: hit=1571 comm=fault_stress tgid=171 tid=174
[  174.972266] ---[ end trace 0000000000000000 ]---

I will send the complete test case in a follow-up email.

Thanks,
hupu


^ permalink raw reply

* Re: [RFC 0/2] arm64: kprobes: Fix single-step fault and reentry handling
From: Pu Hu @ 2026-07-02 10:09 UTC (permalink / raw)
  To: Masami Hiramatsu (Google), catalin.marinas@arm.com,
	will@kernel.org, naveen@kernel.org, davem@davemloft.net,
	yang@os.amperecomputing.com, Hongyan Xia, Jiazi Li,
	ada.coupriediaz@arm.com, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org
In-Reply-To: <a6504443-8708-4f6b-819f-2052615d37df@transsion.com>

On 7/2/2026 6:07 PM, hupu wrote:
> On 7/1/2026 9:56 PM, Pu Hu wrote:
>> On 7/1/2026 9:43 PM, Masami Hiramatsu wrote:
>>> On Wed, 1 Jul 2026 12:14:54 +0000
>>> Pu Hu <hupu@transsion.com> wrote:
>>>
>>>> From: hupu <hupu@transsion.com>
>>>>
...
...>
> I will send the complete test case in a follow-up email.
> 
> Thanks,
> hupu
> 

Hi maintainers,

As mentioned in my previous email, below is the complete test case I 
used to reproduce the arm64 kprobe crash on mainline.

It contains:

   - a small kprobe module that probes folio_wait_bit_common()
   - a userspace program that repeatedly triggers file-backed page faults
   - a Makefile to build both parts

Depending on the local build environment, the following variables in the
Makefile may need to be adjusted:

     CROSS_COMPILE
     KERN_DIR
     DEST_PATH

Thanks,
Pu Hu

---


diff --git a/misc/kprobe/Makefile b/misc/kprobe/Makefile
new file mode 100755
index 0000000..14c00c0
--- /dev/null
+++ b/misc/kprobe/Makefile
@@ -0,0 +1,36 @@
+PWD                            := $(shell pwd)
+ARCH                   ?= arm64
+CROSS_COMPILE  ?= aarch64-dumpstack-linux-gnu-
+KERN_DIR               ?= $(PWD)/../../output/build-mainline
+DEST_PATH              ?= $(PWD)/../../output
+Q                              := @
+
+UNIT_TEST              := fault_stress
+UNIT_TEST_SRC  := fault_stress.c
+
+KP_MOD                 := kp_folio
+obj-m                  := $(KP_MOD).o
+
+USER_CFLAGS            := -static -g -O0 -fno-omit-frame-pointer 
-fasynchronous-unwind-tables
+USER_LIBS              := -lm -lpthread
+EXTRA_CFLAGS   += -I$(KERN_DIR)
+
+.PHONY: all modules user clean
+
+all: modules user install
+
+modules:
+       $(Q)$(MAKE) -C $(KERN_DIR) M=$(PWD) 
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" ARCH=$(ARCH) 
CROSS_COMPILE=$(CROSS_COMPILE) modules
+
+user:
+       $(Q)$(CROSS_COMPILE)gcc $(USER_CFLAGS) $(UNIT_TEST_SRC) -o 
$(UNIT_TEST) $(USER_LIBS)
+
+install:
+       $(Q)mkdir -p $(DEST_PATH)
+       $(Q)cp -f *.ko $(DEST_PATH)/
+       $(Q)cp -f $(UNIT_TEST) $(DEST_PATH)/
+
+clean:
+       $(Q)$(MAKE) -C $(KERN_DIR) M=$(PWD) clean
+       $(Q)rm -f $(UNIT_TEST)
+       $(Q)rm -f $(DEST_PATH)/$(UNIT_TEST) $(DEST_PATH)/*.ko
diff --git a/misc/kprobe/fault_stress.c b/misc/kprobe/fault_stress.c
new file mode 100755
index 0000000..10150ff
--- /dev/null
+++ b/misc/kprobe/fault_stress.c
@@ -0,0 +1,96 @@
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define FILE_SIZE   (256UL * 1024 * 1024)
+#define NR_THREADS  8
+
+static void deep_call(int n)
+{
+       volatile char buf[4096];
+
+       memset((void *)buf, n, sizeof(buf));
+
+       if (n > 0)
+               deep_call(n - 1);
+       else
+               sched_yield();
+}
+
+static void *worker(void *arg)
+{
+       const char *path = arg;
+       int fd;
+       char *map;
+       unsigned long i;
+       volatile unsigned long sum = 0;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               perror("open");
+               return NULL;
+       }
+
+       map = mmap(NULL, FILE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (map == MAP_FAILED) {
+               perror("mmap");
+               close(fd);
+               return NULL;
+       }
+
+       for (;;) {
+               /*
+                * Drop the pages backing this mapping from the current 
process.
+                * Subsequent accesses are more likely to trigger 
file-backed
+                * page faults again.
+                */
+               madvise(map, FILE_SIZE, MADV_DONTNEED);
+
+               for (i = 0; i < FILE_SIZE; i += 4096 * 17) {
+                       sum += map[i];
+                       deep_call(64);
+               }
+       }
+
+       munmap(map, FILE_SIZE);
+       close(fd);
+       return NULL;
+}
+
+int main(void)
+{
+       pthread_t th[NR_THREADS];
+       const char *path = "/tmp/fault_stress_file";
+       int fd;
+       int i;
+
+       fd = open(path, O_CREAT | O_RDWR, 0644);
+       if (fd < 0) {
+               perror("open file");
+               return 1;
+       }
+
+       if (ftruncate(fd, FILE_SIZE) < 0) {
+               perror("ftruncate");
+               return 1;
+       }
+
+       close(fd);
+
+       for (i = 0; i < NR_THREADS; i++)
+               pthread_create(&th[i], NULL, worker, (void *)path);
+
+       for (i = 0; i < NR_THREADS; i++)
+               pthread_join(th[i], NULL);
+
+       return 0;
+}
+
diff --git a/misc/kprobe/kp_folio.c b/misc/kprobe/kp_folio.c
new file mode 100755
index 0000000..c8f3e1d
--- /dev/null
+++ b/misc/kprobe/kp_folio.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/ratelimit.h>
+
+static atomic64_t kp_hit_count = ATOMIC64_INIT(0);
+
+static int folio_wait_bit_common_handler(
+                       struct kprobe *p,^M
+                       struct pt_regs *regs)
+{
+       unsigned long hit;
+
+       hit = atomic64_inc_return(&kp_hit_count);
+
+       pr_info("kp_folio: hit=%lu comm=%s tgid=%d tid=%d\n",
+               hit, current->comm, current->tgid, current->pid);
+
+       return 0;
+}
+
+static struct kprobe kp_folio_wait_bit_common = {
+       .symbol_name = "folio_wait_bit_common",
+       .pre_handler = folio_wait_bit_common_handler,
+};
+
+static int __init kp_folio_init(void)
+{
+       int ret;
+
+       ret = register_kprobe(&kp_folio_wait_bit_common);
+       if (ret < 0) {
+               pr_err("kp_folio: register_kprobe failed, ret=%d\n", ret);
+               return ret;
+       }
+
+       pr_info("kp_folio: kprobe registered at %pS, addr=%px\n",
+               kp_folio_wait_bit_common.addr,
+               kp_folio_wait_bit_common.addr);
+
+       return 0;
+}
+
+static void __exit kp_folio_exit(void)
+{
+       unregister_kprobe(&kp_folio_wait_bit_common);
+
+       pr_info("kp_folio: kprobe unregistered, total hits=%lld\n",
+               atomic64_read(&kp_hit_count));
+}
+
+module_init(kp_folio_init);
+module_exit(kp_folio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("hupu <hupu@transsion.com>");
+MODULE_DESCRIPTION("simple kprobe reproducer for folio_wait_bit_common");



^ permalink raw reply related

* [RFC net-next] net: sparx5: configure TAS port link speed
From: Robert Marko @ 2026-07-02 10:15 UTC (permalink / raw)
  To: daniel.machon, UNGLinuxDriver, andrew+netdev, davem, edumazet,
	kuba, pabeni, Steen.Hegelund, horms, netdev, linux-arm-kernel,
	linux-kernel
  Cc: luka.perkov, Robert Marko

On the TSN and RED variants of LAN969x and SparX-5i TAS (Time-Aware Shaper)
is present in the silicon.

Currently, the driver does not use configure it at all, which means that
the TAS_PROFILE_CONFIG.LINK_SPEED[1] value is left at the default of 3
which means that its configured for 1 Gbps.

So, running iperf between two 10G switch ports will result in only 940-ish
Mbps while we should be getting around 9.3 Gbps.

Correctly populating the TAS_PROFILE_CONFIG.LINK_SPEED[1] with the current
port speed fixes this issue and we achieve around 9.4 Gbps between two 10G
switch ports.

So, port the TAS port link speed setting from the vendor BSP 6.18 kernel[2]

[1] https://microchip-ung.github.io/lan969x-industrial_reginfo/reginfo_LAN969x-Industrial.html?select=hsch,tas_profile_cfg,tas_profile_config,link_speed
[2] https://github.com/microchip-ung/linux/tree/bsp-6.18-2026

Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
 .../microchip/sparx5/lan969x/lan969x_regs.c   |  3 ++
 .../microchip/sparx5/sparx5_main_regs.h       | 12 +++++
 .../ethernet/microchip/sparx5/sparx5_port.c   |  4 ++
 .../ethernet/microchip/sparx5/sparx5_qos.c    | 49 +++++++++++++++++++
 .../ethernet/microchip/sparx5/sparx5_qos.h    |  1 +
 .../ethernet/microchip/sparx5/sparx5_regs.c   |  3 ++
 .../ethernet/microchip/sparx5/sparx5_regs.h   |  3 ++
 7 files changed, 75 insertions(+)

diff --git a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_regs.c b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_regs.c
index ace4ba21eec4..3fc2c006ba12 100644
--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_regs.c
+++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_regs.c
@@ -95,6 +95,7 @@ const unsigned int lan969x_gaddr[GADDR_LAST] = {
 	[GA_HSCH_SYSTEM] = 37384,
 	[GA_HSCH_MMGT] = 36260,
 	[GA_HSCH_TAS_CONFIG] = 37696,
+	[GA_HSCH_TAS_PROFILE_CFG] = 37712,
 	[GA_PTP_PTP_CFG] = 512,
 	[GA_PTP_PTP_TOD_DOMAINS] = 528,
 	[GA_PTP_PHASE_DETECTOR_CTRL] = 628,
@@ -129,6 +130,7 @@ const unsigned int lan969x_gcnt[GCNT_LAST] = {
 	[GC_GCB_SIO_CTRL] = 1,
 	[GC_HSCH_HSCH_CFG] = 1120,
 	[GC_HSCH_HSCH_DWRR] = 32,
+	[GC_HSCH_TAS_PROFILE_CFG] = 30,
 	[GC_PTP_PTP_PINS] = 8,
 	[GC_PTP_PHASE_DETECTOR_CTRL] = 8,
 	[GC_REW_PORT] = 35,
@@ -144,6 +146,7 @@ const unsigned int lan969x_gsize[GSIZE_LAST] = {
 	[GW_FDMA_FDMA] = 448,
 	[GW_GCB_CHIP_REGS] = 180,
 	[GW_HSCH_TAS_CONFIG] = 16,
+	[GW_HSCH_TAS_PROFILE_CFG] = 68,
 	[GW_PTP_PHASE_DETECTOR_CTRL] = 12,
 	[GW_QSYS_PAUSE_CFG] = 988,
 };
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
index 27d02eea7ce1..15fbfa68bc75 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
@@ -5369,6 +5369,18 @@ extern const struct sparx5_regs *regs;
 #define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_GET(x)\
 	FIELD_GET(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY, x)
 
+/* HSCH:TAS_PROFILE_CFG:TAS_PROFILE_CONFIG */
+#define HSCH_TAS_PROFILE_CONFIG(g)                                             \
+	__REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_TAS_PROFILE_CFG], g,       \
+	      regs->gcnt[GC_HSCH_TAS_PROFILE_CFG],                              \
+	      regs->gsize[GW_HSCH_TAS_PROFILE_CFG], 32, 0, 1, 4)
+
+#define HSCH_TAS_PROFILE_CONFIG_LINK_SPEED       GENMASK(10, 8)
+#define HSCH_TAS_PROFILE_CONFIG_LINK_SPEED_SET(x)\
+	FIELD_PREP(HSCH_TAS_PROFILE_CONFIG_LINK_SPEED, x)
+#define HSCH_TAS_PROFILE_CONFIG_LINK_SPEED_GET(x)\
+	FIELD_GET(HSCH_TAS_PROFILE_CONFIG_LINK_SPEED, x)
+
 /* LAN969X ONLY */
 /* HSIOWRAP:XMII_CFG:XMII_CFG */
 #define HSIO_WRAP_XMII_CFG(g)                                                  \
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
index 62c49893de3c..ef06bed3a9cc 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
@@ -11,6 +11,7 @@
 #include "sparx5_main_regs.h"
 #include "sparx5_main.h"
 #include "sparx5_port.h"
+#include "sparx5_qos.h"
 
 #define SPX5_ETYPE_TAG_C     0x8100
 #define SPX5_ETYPE_TAG_S     0x88a8
@@ -1050,6 +1051,9 @@ int sparx5_port_config(struct sparx5 *sparx5,
 		 sparx5,
 		 QFWD_SWITCH_PORT_MODE(port->portno));
 
+	/* Notify TAS about the speed. */
+	sparx5_tas_speed(port, conf->speed);
+
 	/* Save the new values */
 	port->conf = *conf;
 
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c
index e580670f3992..972da8a71f5a 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c
@@ -9,6 +9,17 @@
 #include "sparx5_main.h"
 #include "sparx5_qos.h"
 
+enum sparx5_tas_link_speed {
+	TAS_SPEED_NO_GB,
+	TAS_SPEED_10,
+	TAS_SPEED_100,
+	TAS_SPEED_1000,
+	TAS_SPEED_2500,
+	TAS_SPEED_5000,
+	TAS_SPEED_10000,
+	TAS_SPEED_25000,
+};
+
 /* Calculate new base_time based on cycle_time.
  *
  * The hardware requires a base_time that is always in the future.
@@ -581,3 +592,41 @@ int sparx5_tc_ets_del(struct sparx5_port *port)
 
 	return sparx5_dwrr_conf_set(port, &dwrr);
 }
+
+void sparx5_tas_speed(struct sparx5_port *port, int speed)
+{
+	struct sparx5 *sparx5 = port->sparx5;
+	u8 spd;
+
+	switch (speed) {
+	case SPEED_10:
+		spd = TAS_SPEED_10;
+		break;
+	case SPEED_100:
+		spd = TAS_SPEED_100;
+		break;
+	case SPEED_1000:
+		spd = TAS_SPEED_1000;
+		break;
+	case SPEED_2500:
+		spd = TAS_SPEED_2500;
+		break;
+	case SPEED_5000:
+		spd = TAS_SPEED_5000;
+		break;
+	case SPEED_10000:
+		spd = TAS_SPEED_10000;
+		break;
+	case SPEED_25000:
+		spd = TAS_SPEED_25000;
+		break;
+	default:
+		netdev_err(port->ndev, "TAS: Unsupported speed: %d\n", speed);
+		return;
+	}
+
+	spx5_rmw(HSCH_TAS_PROFILE_CONFIG_LINK_SPEED_SET(spd),
+		 HSCH_TAS_PROFILE_CONFIG_LINK_SPEED,
+		 sparx5,
+		 HSCH_TAS_PROFILE_CONFIG(port->portno));
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h
index 04f76f1e23f6..a92a699c551f 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h
@@ -60,6 +60,7 @@ struct sparx5_dwrr {
 };
 
 int sparx5_qos_init(struct sparx5 *sparx5);
+void sparx5_tas_speed(struct sparx5_port *port, int speed);
 
 /* Multi-Queue Priority */
 int sparx5_tc_mqprio_add(struct net_device *ndev, u8 num_tc);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c
index 220e81b714d4..3863f954bd83 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c
@@ -95,6 +95,7 @@ const unsigned int sparx5_gaddr[GADDR_LAST] = {
 	[GA_HSCH_SYSTEM] = 184000,
 	[GA_HSCH_MMGT] = 162368,
 	[GA_HSCH_TAS_CONFIG] = 162384,
+	[GA_HSCH_TAS_PROFILE_CFG] = 188416,
 	[GA_PTP_PTP_CFG] = 320,
 	[GA_PTP_PTP_TOD_DOMAINS] = 336,
 	[GA_PTP_PHASE_DETECTOR_CTRL] = 420,
@@ -129,6 +130,7 @@ const unsigned int sparx5_gcnt[GCNT_LAST] = {
 	[GC_GCB_SIO_CTRL] = 3,
 	[GC_HSCH_HSCH_CFG] = 5040,
 	[GC_HSCH_HSCH_DWRR] = 72,
+	[GC_HSCH_TAS_PROFILE_CFG] = 100,
 	[GC_PTP_PTP_PINS] = 5,
 	[GC_PTP_PHASE_DETECTOR_CTRL] = 5,
 	[GC_REW_PORT] = 70,
@@ -144,6 +146,7 @@ const unsigned int sparx5_gsize[GSIZE_LAST] = {
 	[GW_FDMA_FDMA] = 428,
 	[GW_GCB_CHIP_REGS] = 424,
 	[GW_HSCH_TAS_CONFIG] = 12,
+	[GW_HSCH_TAS_PROFILE_CFG] = 64,
 	[GW_PTP_PHASE_DETECTOR_CTRL] = 8,
 	[GW_QSYS_PAUSE_CFG] = 1128,
 };
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h
index ea28130c2341..585589a31e90 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h
@@ -104,6 +104,7 @@ enum sparx5_gaddr_enum {
 	GA_HSCH_SYSTEM,
 	GA_HSCH_MMGT,
 	GA_HSCH_TAS_CONFIG,
+	GA_HSCH_TAS_PROFILE_CFG,
 	GA_PTP_PTP_CFG,
 	GA_PTP_PTP_TOD_DOMAINS,
 	GA_PTP_PHASE_DETECTOR_CTRL,
@@ -139,6 +140,7 @@ enum sparx5_gcnt_enum {
 	GC_GCB_SIO_CTRL,
 	GC_HSCH_HSCH_CFG,
 	GC_HSCH_HSCH_DWRR,
+	GC_HSCH_TAS_PROFILE_CFG,
 	GC_PTP_PTP_PINS,
 	GC_PTP_PHASE_DETECTOR_CTRL,
 	GC_REW_PORT,
@@ -155,6 +157,7 @@ enum sparx5_gsize_enum {
 	GW_FDMA_FDMA,
 	GW_GCB_CHIP_REGS,
 	GW_HSCH_TAS_CONFIG,
+	GW_HSCH_TAS_PROFILE_CFG,
 	GW_PTP_PHASE_DETECTOR_CTRL,
 	GW_QSYS_PAUSE_CFG,
 	GSIZE_LAST,
-- 
2.55.0



^ permalink raw reply related

* [PATCH v9 0/6] arm_ffa, KVM: Fix FF-A emad offset calculations
From: Sebastian Ene @ 2026-07-02 10:38 UTC (permalink / raw)
  To: catalin.marinas, oupton, sudeep.holla, will
  Cc: jens.wiklander, joey.gouly, kvmarm, linux-arm-kernel,
	linux-kernel, android-kvm, maz, mrigendra.chaubey, op-tee,
	perlarsen, sebastianene, seiden, smostafa, sumit.garg,
	suzuki.poulose, vdonnefort, yuzenghui

Hi all,

This series fixes the Endpoint Memory Access Descriptor (EMAD) offset
calculations and adds the necessary bounds checks for both the core
FF-A driver and the pKVM hypervisor.

Prior to FF-A version 1.1, the memory region header didn't specify an
explicit offset for the EMADs, leading to the assumption that they
immediately follow the header.
However, from v1.1 onwards, the specification dictates using the
ep_mem_offset` field to determine the start of the memory access
array.

The patches in this series address this by:
1. Updating the core `arm_ffa` firmware driver to correctly calculate
the descriptor
   offset using `ep_mem_offset` rather than defaulting to `sizeof(struct
ffa_mem_region)`.
   It also introduces bounds checking against `max_fragsize`.
2. Enhancing the pKVM hypervisor validation logic to no longer strictly
enforce that
   the descriptor strictly follows the header, aligning it with the
driver behavior
   and the FF-A specification, while also ensuring the offset falls
within the mailbox
   buffer bounds.

While addressing these bugs, Sashiko uncovered other issues that were
fixed in the same series.

All the patches aside from the first one in optee are urgent fixes as
they either impact the hypervisor security or kernel stability.

Changelog
#########
v8->v9:
- addressed Sashiko double ffa_rx_release in "KVM: arm64: Fix bounds
  checking in do_ffa_mem_reclaim()"

v7->v8:
- dropped the patch "optee: ffa: Add NULL check in
  optee_ffa_lend_protmem" from the series as it was queued by Jens
- rephrased the commit message for "KVM: arm64: Ensure FFA ranges are
  page aligned"
- introduced a helper macro to get the size of the ffa memory region
  based on the used version.

v6->v7:
- taking the patches from Mostafa and sending a new version with the
  collected tags
- Added overflow checks when doing `ep_offset + emad_size` in the arm
  ff-a driver
- Move the length check before the ffa_mem_reclaim
- fix compatibility break with ff-a version 1.0 reported by Sashiko
- add one more patch to fix an issue with the FFA_VERSION call
  that can lead to leaking pKVM stack un-initialized data to
  a host when -ftrivial-auto-var-init=zero is not used.

v5->v6:
- Add fixes tag
- Small clean up make variable declaration reverse christmas tree.

v4->v5:
- Collect Sudeep Rbs
- Add extra patch to check base address alignment.
- Remove WARN_ONs in KVM code
- Use ffa_emad_size_get() instead of hardcoded size in KVM code.

v3 -> v4:
- Address review comments and fix Sashiko bugs

v2 -> v3:
- Fixed typo in nvhe/ffa.c (missing sizeof)

v1 -> v2:
- For pKVM, removed the strict placement enforcement for `ep_mem_offset`
  as it is not
  compliant with the spec, and avoids making assumptions about the
driver's memory
  layout.

Link to:
########

v8: https://lore.kernel.org/all/20260630102058.3219867-2-sebastianene@google.com/
v7: https://lore.kernel.org/all/20260617145130.3729015-1-sebastianene@google.com/
v6: https://lore.kernel.org/all/20260527150236.1978655-1-smostafa@google.com/
v5: https://lore.kernel.org/all/20260526151934.3783707-1-smostafa@google.com/
v4: https://lore.kernel.org/all/20260520204948.2440882-1-smostafa@google.com/
v3: https://lore.kernel.org/all/20260512124442.1899107-1-sebastianene@google.com/
v2: https://lore.kernel.org/all/20260430160241.1934777-1-sebastianene@google.com/
v1: https://lore.kernel.org/all/ae9KN9nkOgDYJcGP@google.com/T/#t

Mostafa Saleh (3):
  firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit()
  KVM: arm64: Fix bounds checking in do_ffa_mem_reclaim()
  KVM: arm64: Ensure FFA ranges are page aligned

Sebastian Ene (3):
  firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset
    calculation
  KVM: arm64: Validate the offset to the mem access descriptor
  KVM: arm64: Zero out the stack initialized data in the FFA handler

 arch/arm64/kvm/hyp/nvhe/ffa.c     | 44 +++++++++++++++++++++----------
 drivers/firmware/arm_ffa/driver.c | 25 ++++++++++++------
 include/linux/arm_ffa.h           |  9 ++++++-
 3 files changed, 55 insertions(+), 23 deletions(-)

-- 
2.55.0.rc0.799.gd6f94ed593-goog



^ permalink raw reply

* [PATCH v9 1/6] firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit()
From: Sebastian Ene @ 2026-07-02 10:38 UTC (permalink / raw)
  To: catalin.marinas, oupton, sudeep.holla, will
  Cc: jens.wiklander, joey.gouly, kvmarm, linux-arm-kernel,
	linux-kernel, android-kvm, maz, mrigendra.chaubey, op-tee,
	perlarsen, sebastianene, seiden, smostafa, sumit.garg,
	suzuki.poulose, vdonnefort, yuzenghui
In-Reply-To: <20260702103848.1647249-1-sebastianene@google.com>

From: Mostafa Saleh <smostafa@google.com>

Sashiko (locally) reports multiple out-of-bound issues in
ffa_setup_and_transmit:
1) Writing ep_mem_access->reserved can write out of bounds for FFA
   versions < 1.2 as ffa_emad_size_get() returns 16 bytes in that case
   while reserved has an offset of 24.
   Instead of zeroing fields, memset the struct to zero first based on
   the FFA version.

2) Make sure there is enough size to write constituents.

While at it, convert the only sizeof() in the driver that uses a
type instead of variable.

Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>
Fixes: 111a833dc5cb ("firmware: arm_ffa: Set reserved/MBZ fields to zero in the memory descriptors")
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 drivers/firmware/arm_ffa/driver.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 0f468362c288..01301213896a 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -725,11 +725,10 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
 	for (idx = 0; idx < args->nattrs; idx++) {
 		ep_mem_access = buffer +
 			ffa_mem_desc_offset(buffer, idx, drv_info->version);
+		memset(ep_mem_access, 0, ffa_emad_size_get(drv_info->version));
 		ep_mem_access->receiver = args->attrs[idx].receiver;
 		ep_mem_access->attrs = args->attrs[idx].attrs;
 		ep_mem_access->composite_off = composite_offset;
-		ep_mem_access->flag = 0;
-		ep_mem_access->reserved = 0;
 		ffa_emad_impdef_value_init(drv_info->version,
 					   ep_mem_access->impdef_val,
 					   args->attrs[idx].impdef_val);
@@ -769,7 +768,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
 			constituents = buffer;
 		}
 
-		if ((void *)constituents - buffer > max_fragsize) {
+		if ((void *)constituents + sizeof(*constituents) - buffer > max_fragsize) {
 			pr_err("Memory Region Fragment > Tx Buffer size\n");
 			return -EFAULT;
 		}
@@ -778,7 +777,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
 		constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE;
 		constituents->reserved = 0;
 		constituents++;
-		frag_len += sizeof(struct ffa_mem_region_addr_range);
+		frag_len += sizeof(*constituents);
 	} while ((args->sg = sg_next(args->sg)));
 
 	return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len,
-- 
2.55.0.rc0.799.gd6f94ed593-goog



^ permalink raw reply related

* [PATCH v9 2/6] firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation
From: Sebastian Ene @ 2026-07-02 10:38 UTC (permalink / raw)
  To: catalin.marinas, oupton, sudeep.holla, will
  Cc: jens.wiklander, joey.gouly, kvmarm, linux-arm-kernel,
	linux-kernel, android-kvm, maz, mrigendra.chaubey, op-tee,
	perlarsen, sebastianene, seiden, smostafa, sumit.garg,
	suzuki.poulose, vdonnefort, yuzenghui
In-Reply-To: <20260702103848.1647249-1-sebastianene@google.com>

Use the descriptor's `ep_mem_offset` to calculate the start of the endpoint
memory access array and to comply with the FF-A spec instead of defaulting
to `sizeof(struct ffa_mem_region)`.
This requires moving `ffa_mem_region_additional_setup()` earlier in the setup
flow.
Also, add sanity checks to ensure the calculated descriptor offsets do not
exceed `max_fragsize`.

Fixes: 113580530ee7 ("firmware: arm_ffa: Update memory descriptor to support v1.1 format")
Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 drivers/firmware/arm_ffa/driver.c | 20 +++++++++++++++-----
 include/linux/arm_ffa.h           |  2 +-
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 01301213896a..7c1b747797b4 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -713,19 +713,30 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
 	struct ffa_composite_mem_region *composite;
 	struct ffa_mem_region_addr_range *constituents;
 	struct ffa_mem_region_attributes *ep_mem_access;
-	u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg);
+	u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg), ep_offset;
+	u32 emad_end, emad_size = ffa_emad_size_get(drv_info->version);
 
 	mem_region->tag = args->tag;
 	mem_region->flags = args->flags;
 	mem_region->sender_id = drv_info->vm_id;
 	mem_region->attributes = ffa_memory_attributes_get(func_id);
+
+	ffa_mem_region_additional_setup(drv_info->version, mem_region);
 	composite_offset = ffa_mem_desc_offset(buffer, args->nattrs,
 					       drv_info->version);
+	if (composite_offset + sizeof(*composite) > max_fragsize)
+		return -ENXIO;
 
 	for (idx = 0; idx < args->nattrs; idx++) {
-		ep_mem_access = buffer +
-			ffa_mem_desc_offset(buffer, idx, drv_info->version);
-		memset(ep_mem_access, 0, ffa_emad_size_get(drv_info->version));
+		ep_offset = ffa_mem_desc_offset(buffer, idx, drv_info->version);
+		if (check_add_overflow(ep_offset, emad_size, &emad_end))
+			return -ENXIO;
+
+		if (emad_end > max_fragsize)
+			return -ENXIO;
+
+		ep_mem_access = buffer + ep_offset;
+		memset(ep_mem_access, 0, emad_size);
 		ep_mem_access->receiver = args->attrs[idx].receiver;
 		ep_mem_access->attrs = args->attrs[idx].attrs;
 		ep_mem_access->composite_off = composite_offset;
@@ -735,7 +746,6 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
 	}
 	mem_region->handle = 0;
 	mem_region->ep_count = args->nattrs;
-	ffa_mem_region_additional_setup(drv_info->version, mem_region);
 
 	composite = buffer + composite_offset;
 	composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg);
diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
index 17eca3dfc59e..033c630b271b 100644
--- a/include/linux/arm_ffa.h
+++ b/include/linux/arm_ffa.h
@@ -445,7 +445,7 @@ ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version)
 	if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(ffa_version))
 		offset += offsetof(struct ffa_mem_region, ep_mem_offset);
 	else
-		offset += sizeof(struct ffa_mem_region);
+		offset += buf->ep_mem_offset;
 
 	return offset;
 }
-- 
2.55.0.rc0.799.gd6f94ed593-goog



^ permalink raw reply related

* [PATCH v9 3/6] KVM: arm64: Fix bounds checking in do_ffa_mem_reclaim()
From: Sebastian Ene @ 2026-07-02 10:38 UTC (permalink / raw)
  To: catalin.marinas, oupton, sudeep.holla, will
  Cc: jens.wiklander, joey.gouly, kvmarm, linux-arm-kernel,
	linux-kernel, android-kvm, maz, mrigendra.chaubey, op-tee,
	perlarsen, sebastianene, seiden, smostafa, sumit.garg,
	suzuki.poulose, vdonnefort, yuzenghui
In-Reply-To: <20260702103848.1647249-1-sebastianene@google.com>

From: Mostafa Saleh <smostafa@google.com>

Sashiko (locally) reports out of bound write possiblity if SPMD
returns an invalid data.

While SPMD is considered trusted, pKVM does some basic checks,
for offset to be less than or equal len.

However, that is incorrect as even if the offset is smaller than
len pKVM can still access out of bound memory in the next
ffa_host_unshare_ranges().

Split this check into 2:
1- Check that the fixed portion of the descriptor fits.
2- After getting reg, check the variable array size addr_range_cnt
   fits.

Also, drop the WARN_ONs as that will panic the kernel and in the
next checks there are no WARNs, so that makes it consistent.

Fixes: 0a9f15fd5674 ("KVM: arm64: pkvm: Add support for fragmented FF-A descriptors")
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/kvm/hyp/nvhe/ffa.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 1af722771178..41cc4c1bafeb 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -607,8 +607,8 @@ static void do_ffa_mem_reclaim(struct arm_smccc_1_2_regs *res,
 	 * check that we end up with something that doesn't look _completely_
 	 * bogus.
 	 */
-	if (WARN_ON(offset > len ||
-		    fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE)) {
+	if (offset + CONSTITUENTS_OFFSET(0) > len ||
+	    fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) {
 		ret = FFA_RET_ABORTED;
 		ffa_rx_release(res);
 		goto out_unlock;
@@ -636,11 +636,16 @@ static void do_ffa_mem_reclaim(struct arm_smccc_1_2_regs *res,
 		ffa_rx_release(res);
 	}
 
+	reg = (void *)buf + offset;
+	if (offset + CONSTITUENTS_OFFSET(reg->addr_range_cnt) > len) {
+		ret = FFA_RET_ABORTED;
+		goto out_unlock;
+	}
+
 	ffa_mem_reclaim(res, handle_lo, handle_hi, flags);
 	if (res->a0 != FFA_SUCCESS)
 		goto out_unlock;
 
-	reg = (void *)buf + offset;
 	/* If the SPMD was happy, then we should be too. */
 	WARN_ON(ffa_host_unshare_ranges(reg->constituents,
 					reg->addr_range_cnt));
-- 
2.55.0.rc0.799.gd6f94ed593-goog



^ permalink raw reply related

* [PATCH v9 4/6] KVM: arm64: Validate the offset to the mem access descriptor
From: Sebastian Ene @ 2026-07-02 10:38 UTC (permalink / raw)
  To: catalin.marinas, oupton, sudeep.holla, will
  Cc: jens.wiklander, joey.gouly, kvmarm, linux-arm-kernel,
	linux-kernel, android-kvm, maz, mrigendra.chaubey, op-tee,
	perlarsen, sebastianene, seiden, smostafa, sumit.garg,
	suzuki.poulose, vdonnefort, yuzenghui
In-Reply-To: <20260702103848.1647249-1-sebastianene@google.com>

Prevent the pKVM hypervisor from making assumptions that the
endpoint memory access descriptor (EMAD) comes right after the
FF-A memory region header.
Prior to FF-A version 1.1 the header of the memory region
didn't contain an offset to the endpoint memory access descriptor.
The layout of a memory transaction looks like this from 1.1 onward:
Type | Field name | Offset
[ Header | ffa_mem_region  | 0
  EMAD 1 | ffa_mem_region_attributes) | ffa_mem_region.ep_mem_offset
]
Verify that the offset to the first endpoint memory access descriptor
is within the mailbox buffer bounds.

Also, fix one hardcoded sizeof(struct ffa_mem_region_attributes) that
should be replaced ffa_emad_size_get() for compatibility with FFA v1.0.

Fixes: 42fb33dde42b ("KVM: arm64: Use FF-A 1.1 with pKVM")
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/kvm/hyp/nvhe/ffa.c | 27 +++++++++++++++++++--------
 include/linux/arm_ffa.h       |  7 +++++++
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 41cc4c1bafeb..2e7ab7e3319d 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -476,11 +476,12 @@ static void __do_ffa_mem_xfer(const u64 func_id,
 	DECLARE_REG(u32, fraglen, ctxt, 2);
 	DECLARE_REG(u64, addr_mbz, ctxt, 3);
 	DECLARE_REG(u32, npages_mbz, ctxt, 4);
+	u32 offset, nr_ranges, checked_offset, em_mem_access_off;
 	struct ffa_mem_region_attributes *ep_mem_access;
 	struct ffa_composite_mem_region *reg;
 	struct ffa_mem_region *buf;
-	u32 offset, nr_ranges, checked_offset;
 	int ret = 0;
+	size_t mem_region_len = FFA_MEM_REGION_SZ(hyp_ffa_version);
 
 	if (addr_mbz || npages_mbz || fraglen > len ||
 	    fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) {
@@ -488,8 +489,7 @@ static void __do_ffa_mem_xfer(const u64 func_id,
 		goto out;
 	}
 
-	if (fraglen < sizeof(struct ffa_mem_region) +
-		      sizeof(struct ffa_mem_region_attributes)) {
+	if (fraglen < mem_region_len + ffa_emad_size_get(hyp_ffa_version)) {
 		ret = FFA_RET_INVALID_PARAMETERS;
 		goto out;
 	}
@@ -508,8 +508,13 @@ static void __do_ffa_mem_xfer(const u64 func_id,
 	buf = hyp_buffers.tx;
 	memcpy(buf, host_buffers.tx, fraglen);
 
-	ep_mem_access = (void *)buf +
-			ffa_mem_desc_offset(buf, 0, hyp_ffa_version);
+	em_mem_access_off = ffa_mem_desc_offset(buf, 0, hyp_ffa_version);
+	if ((u64)em_mem_access_off + ffa_emad_size_get(hyp_ffa_version) > fraglen) {
+		ret = FFA_RET_INVALID_PARAMETERS;
+		goto out_unlock;
+	}
+
+	ep_mem_access = (void *)buf + em_mem_access_off;
 	offset = ep_mem_access->composite_off;
 	if (!offset || buf->ep_count != 1 || buf->sender_id != HOST_FFA_ID) {
 		ret = FFA_RET_INVALID_PARAMETERS;
@@ -574,9 +579,9 @@ static void do_ffa_mem_reclaim(struct arm_smccc_1_2_regs *res,
 	DECLARE_REG(u32, handle_lo, ctxt, 1);
 	DECLARE_REG(u32, handle_hi, ctxt, 2);
 	DECLARE_REG(u32, flags, ctxt, 3);
+	u32 offset, len, fraglen, fragoff, em_mem_access_off;
 	struct ffa_mem_region_attributes *ep_mem_access;
 	struct ffa_composite_mem_region *reg;
-	u32 offset, len, fraglen, fragoff;
 	struct ffa_mem_region *buf;
 	int ret = 0;
 	u64 handle;
@@ -599,8 +604,14 @@ static void do_ffa_mem_reclaim(struct arm_smccc_1_2_regs *res,
 	len = res->a1;
 	fraglen = res->a2;
 
-	ep_mem_access = (void *)buf +
-			ffa_mem_desc_offset(buf, 0, hyp_ffa_version);
+	em_mem_access_off = ffa_mem_desc_offset(buf, 0, hyp_ffa_version);
+	if ((u64)em_mem_access_off + ffa_emad_size_get(hyp_ffa_version) > fraglen) {
+		ret = FFA_RET_INVALID_PARAMETERS;
+		ffa_rx_release(res);
+		goto out_unlock;
+	}
+
+	ep_mem_access = (void *)buf + em_mem_access_off;
 	offset = ep_mem_access->composite_off;
 	/*
 	 * We can trust the SPMD to get this right, but let's at least
diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
index 033c630b271b..e71d83ee0aef 100644
--- a/include/linux/arm_ffa.h
+++ b/include/linux/arm_ffa.h
@@ -421,6 +421,13 @@ struct ffa_mem_region {
 #define FFA_EMAD_HAS_IMPDEF_FIELD(version)	((version) >= FFA_VERSION_1_2)
 #define FFA_MEM_REGION_HAS_EP_MEM_OFFSET(version) ((version) > FFA_VERSION_1_0)
 
+/* The layout changed from FFA_VERSION_1_0 and the region includes an
+ * ep_mem_offset.
+ */
+#define FFA_MEM_REGION_SZ(version)		(!FFA_MEM_REGION_HAS_EP_MEM_OFFSET((version)) ?\
+						 offsetof(struct ffa_mem_region, ep_mem_offset) :\
+						 sizeof(struct ffa_mem_region))
+
 static inline u32 ffa_emad_size_get(u32 ffa_version)
 {
 	u32 sz;
-- 
2.55.0.rc0.799.gd6f94ed593-goog



^ permalink raw reply related

* [PATCH v9 5/6] KVM: arm64: Ensure FFA ranges are page aligned
From: Sebastian Ene @ 2026-07-02 10:38 UTC (permalink / raw)
  To: catalin.marinas, oupton, sudeep.holla, will
  Cc: jens.wiklander, joey.gouly, kvmarm, linux-arm-kernel,
	linux-kernel, android-kvm, maz, mrigendra.chaubey, op-tee,
	perlarsen, sebastianene, seiden, smostafa, sumit.garg,
	suzuki.poulose, vdonnefort, yuzenghui
In-Reply-To: <20260702103848.1647249-1-sebastianene@google.com>

From: Mostafa Saleh <smostafa@google.com>

Harden the check for the constituent memory region page alignment
to prevent over-sharing when the negotiated FFA_PAGE_SIZE size is
smaller than the system PAGE_SIZE.
At the moment we only check that the size of the range is page
aligned, and truncate the address to the page boundary which can
annotate more memory than needed as being used by the FF-A.

Fixes: 436090001776 ("KVM: arm64: Handle FFA_MEM_SHARE calls from the host")
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/kvm/hyp/nvhe/ffa.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 2e7ab7e3319d..9c96e72e522e 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -352,7 +352,7 @@ static u32 __ffa_host_share_ranges(struct ffa_mem_region_addr_range *ranges,
 		u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE;
 		u64 pfn = hyp_phys_to_pfn(range->address);
 
-		if (!PAGE_ALIGNED(sz))
+		if (!PAGE_ALIGNED(sz | range->address))
 			break;
 
 		if (__pkvm_host_share_ffa(pfn, sz / PAGE_SIZE))
@@ -372,7 +372,7 @@ static u32 __ffa_host_unshare_ranges(struct ffa_mem_region_addr_range *ranges,
 		u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE;
 		u64 pfn = hyp_phys_to_pfn(range->address);
 
-		if (!PAGE_ALIGNED(sz))
+		if (!PAGE_ALIGNED(sz | range->address))
 			break;
 
 		if (__pkvm_host_unshare_ffa(pfn, sz / PAGE_SIZE))
-- 
2.55.0.rc0.799.gd6f94ed593-goog



^ permalink raw reply related

* [PATCH v9 6/6] KVM: arm64: Zero out the stack initialized data in the FFA handler
From: Sebastian Ene @ 2026-07-02 10:38 UTC (permalink / raw)
  To: catalin.marinas, oupton, sudeep.holla, will
  Cc: jens.wiklander, joey.gouly, kvmarm, linux-arm-kernel,
	linux-kernel, android-kvm, maz, mrigendra.chaubey, op-tee,
	perlarsen, sebastianene, seiden, smostafa, sumit.garg,
	suzuki.poulose, vdonnefort, yuzenghui, Sashiko AI
In-Reply-To: <20260702103848.1647249-1-sebastianene@google.com>

Don't leak hypervisor stack data when using the FFA_VERSION call.
When the compiler doesn't support -ftrivial-auto-var-init=zero option
we need to zero out the stack initialized variable before returning data
to the host caller.

Closes:
https://lore.kernel.org/all/20260616160016.C62C81F000E9@smtp.kernel.org/

Reported-by: Sashiko AI <sashiko-bot@kernel.org>
Fixes: c9c012625e12 ("KVM: arm64: Trap FFA_VERSION host call in pKVM")
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Link: https://lore.kernel.org/all/20260616160016.C62C81F000E9@smtp.kernel.org/
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/kvm/hyp/nvhe/ffa.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 9c96e72e522e..a327c2bbb6b6 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -880,7 +880,7 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
 
 bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
 {
-	struct arm_smccc_1_2_regs res;
+	struct arm_smccc_1_2_regs res = {0};
 
 	/*
 	 * There's no way we can tell what a non-standard SMC call might
-- 
2.55.0.rc0.799.gd6f94ed593-goog



^ permalink raw reply related

* Re: [PATCH v3 1/3] KVM: arm64: skip pKVM cache flushes for non cacheable mappings
From: Leonardo Bras @ 2026-07-02 10:43 UTC (permalink / raw)
  To: Bradley Morgan
  Cc: Leonardo Bras, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
	Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Catalin Marinas,
	Will Deacon, Quentin Perret, Vincent Donnefort, Gavin Shan,
	Alexandru Elisei, linux-arm-kernel, kvmarm, linux-kernel
In-Reply-To: <BCFEB62C-FA80-474B-A9F5-9CD6CA87E857@grrlz.net>

On Wed, Jul 01, 2026 at 05:57:48PM +0100, Bradley Morgan wrote:
> On July 1, 2026 5:56:37 PM GMT+01:00, Leonardo Bras <leo.bras@arm.com>
> wrote:
> >On Wed, Jul 01, 2026 at 05:54:40PM +0100, Bradley Morgan wrote:
> >> On July 1, 2026 5:53:34 PM GMT+01:00, Leonardo Bras <leo.bras@arm.com>
> >> wrote:
> >> >On Wed, Jul 01, 2026 at 05:40:46PM +0100, Bradley Morgan wrote:
> >> >> On July 1, 2026 5:05:53 PM GMT+01:00, Leonardo Bras
> ><leo.bras@arm.com>
> >> >> wrote:
> >> >> >On Wed, Jun 24, 2026 at 04:00:26PM +0000, Bradley Morgan wrote:
> >> >> >> pKVM keeps its own mapping list for stage 2 operations. Its flush
> >> >path
> >> >> >> uses that list directly, so it lost the PTE attribute check done
> >by
> >> >the
> >> >> >> generic stage 2 walker.
> >> >> >> 
> >> >> >> Record whether a mapping is cacheable and skip cache maintenance
> >for
> >> >> >> mappings that are not cacheable.
> >> >> >> 
> >> >> >> Fixes: e912efed485a ("KVM: arm64: Introduce the EL1 pKVM MMU")
> >> >> >> Signed-off-by: Bradley Morgan <include@grrlz.net>
> >> >> >> ---
> >> >> >>  arch/arm64/kvm/pkvm.c | 51
> >> >++++++++++++++++++++++++++++++++++---------
> >> >> >>  1 file changed, 41 insertions(+), 10 deletions(-)
> >> >> >> 
> >> >> >> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> >> >> >> index 428723b1b0f5..ca6e823028c2 100644
> >> >> >> --- a/arch/arm64/kvm/pkvm.c
> >> >> >> +++ b/arch/arm64/kvm/pkvm.c
> >> >> >> @@ -302,9 +302,32 @@ static u64 __pkvm_mapping_start(struct
> >> >pkvm_mapping
> >> >> >*m)
> >> >> >>  	return m->gfn * PAGE_SIZE;
> >> >> >>  }
> >> >> >>  
> >> >> >> +#define PKVM_MAPPING_NR_PAGES_MASK	GENMASK_ULL(47, 0)
> >> >> >> +#define PKVM_MAPPING_CACHEABLE		BIT_ULL(48)
> >> >> >
> >> >> >Out of curiosity here, why do you choose to use bit 48 here instead
> >of,
> >> >> >let's say, bit 63?
> >> >> >
> >> >> >(I know it makes absolutely no difference to inner working here, as
> >> >there 
> >> >> >should probably not be 2^48 pages in one mapping.)
> >> >> >
> >> >> >Thanks!
> >> >> >Leo
> >> >> 
> >> >> 
> >> >> sup Leo, here's a quote from maz 
> >> >
> >> >Hi Bradley,
> >> >
> >> >> 
> >> >> "This thing is already big enough, let's not add a bool right in the
> >> >> middle (use pahole to find out why this is bad).
> >> >
> >> >I suppose you proposed to add a bool into a struct, maybe?
> >> >It would screw the struct alignment.
> >> 
> >> yep, crappy old me
> >> 
> >
> >Hah, you were probably focused on the big picture.
> >
> >> 
> >> >> Given that nr_pages
> >> >> is for a range, and that the minimum page size uses 12 bits, the
> >> >> largest number of pages you can have here is 56-12=48 bit wide.
> >That's
> >> >> another 16 bits worth of flags you can use."
> >> >
> >> >Humm, makes sense.
> >> >And since he mentions 16 bits worth of flags, you start by using the
> >48th 
> >> >bit. Ok, got your rationale.
> >> >
> >> >(I would possibly start with the 63, though, but that's more on
> >personal 
> >> >taste)
> >> 
> >> 48 won't make the world blow up :)
> >
> >yeap,
> 
> 
> Would you like to be CCed on v4 or nahhhh?

Whatever you feel like :)

Thanks!
Leo

> 
> >> 
> >> >> 
> >> >> this should just clarify things, any questions, feel more than free
> >to
> >> >ask!
> >> >> 
> >> >> (btw V4 is coming soon)
> >> >
> >> >Thanks!
> >> >Leo
> >> >
> >> >> 
> >> >> >> +
> >> >> >> +static u64 pkvm_mapping_nr_pages(struct pkvm_mapping *m)
> >> >> >> +{
> >> >> >> +	return m->nr_pages & PKVM_MAPPING_NR_PAGES_MASK;
> >> >> >> +}
> >> >> >> +
> >> >> >> +static bool pkvm_mapping_is_cacheable(struct pkvm_mapping *m)
> >> >> >> +{
> >> >> >> +	return m->nr_pages & PKVM_MAPPING_CACHEABLE;
> >> >> >> +}
> >> >> >> +
> >> >> >> +static void pkvm_mapping_set_nr_pages(struct pkvm_mapping *m, u64
> >> >> >nr_pages,
> >> >> >> +				      bool cacheable)
> >> >> >> +{
> >> >> >> +	WARN_ON_ONCE(nr_pages & ~PKVM_MAPPING_NR_PAGES_MASK);
> >> >> >> +
> >> >> >> +	m->nr_pages = nr_pages & PKVM_MAPPING_NR_PAGES_MASK;
> >> >> >> +	if (cacheable)
> >> >> >> +		m->nr_pages |= PKVM_MAPPING_CACHEABLE;
> >> >> >> +}
> >> >> >> +
> >> >> >>  static u64 __pkvm_mapping_end(struct pkvm_mapping *m)
> >> >> >>  {
> >> >> >> -	return (m->gfn + m->nr_pages) * PAGE_SIZE - 1;
> >> >> >> +	return (m->gfn + pkvm_mapping_nr_pages(m)) * PAGE_SIZE - 1;
> >> >> >>  }
> >> >> >>  
> >> >> >>  INTERVAL_TREE_DEFINE(struct pkvm_mapping, node, u64,
> >__subtree_last,
> >> >> >> @@ -350,7 +373,7 @@ static int
> >__pkvm_pgtable_stage2_reclaim(struct
> >> >> >kvm_pgtable *pgt, u64 start, u64
> >> >> >>  			continue;
> >> >> >>  
> >> >> >>  		page = pfn_to_page(mapping->pfn);
> >> >> >> -		WARN_ON_ONCE(mapping->nr_pages != 1);
> >> >> >> +		WARN_ON_ONCE(pkvm_mapping_nr_pages(mapping) != 1);
> >> >> >>  		unpin_user_pages_dirty_lock(&page, 1, true);
> >> >> >>  		account_locked_vm(kvm->mm, 1, false);
> >> >> >>  		pkvm_mapping_remove(mapping, &pgt->pkvm_mappings);
> >> >> >> @@ -369,7 +392,7 @@ static int
> >__pkvm_pgtable_stage2_unshare(struct
> >> >> >kvm_pgtable *pgt, u64 start, u64
> >> >> >>  
> >> >> >>  	for_each_mapping_in_range_safe(pgt, start, end, mapping) {
> >> >> >>  		ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_guest, handle, mapping->gfn,
> >> >> >> -					mapping->nr_pages);
> >> >> >> +					pkvm_mapping_nr_pages(mapping));
> >> >> >>  		if (WARN_ON(ret))
> >> >> >>  			return ret;
> >> >> >>  		pkvm_mapping_remove(mapping, &pgt->pkvm_mappings);
> >> >> >> @@ -448,7 +471,7 @@ int pkvm_pgtable_stage2_map(struct kvm_pgtable
> >> >*pgt,
> >> >> >u64 addr, u64 size,
> >> >> >>  		 * permission faults are handled in the relax_perms() path.
> >> >> >>  		 */
> >> >> >>  		if (mapping) {
> >> >> >> -			if (size == (mapping->nr_pages * PAGE_SIZE))
> >> >> >> +			if (size == (pkvm_mapping_nr_pages(mapping) * PAGE_SIZE))
> >> >> >>  				return -EAGAIN;
> >> >> >>  
> >> >> >>  			/*
> >> >> >> @@ -472,7 +495,9 @@ int pkvm_pgtable_stage2_map(struct kvm_pgtable
> >> >*pgt,
> >> >> >u64 addr, u64 size,
> >> >> >>  	swap(mapping, cache->mapping);
> >> >> >>  	mapping->gfn = gfn;
> >> >> >>  	mapping->pfn = pfn;
> >> >> >> -	mapping->nr_pages = size / PAGE_SIZE;
> >> >> >> +	pkvm_mapping_set_nr_pages(mapping, size / PAGE_SIZE,
> >> >> >> +				  !(prot & (KVM_PGTABLE_PROT_DEVICE |
> >> >> >> +					    KVM_PGTABLE_PROT_NORMAL_NC)));
> >> >> >>  	pkvm_mapping_insert(mapping, &pgt->pkvm_mappings);
> >> >> >>  
> >> >> >>  	return ret;
> >> >> >> @@ -503,7 +528,7 @@ int pkvm_pgtable_stage2_wrprotect(struct
> >> >kvm_pgtable
> >> >> >*pgt, u64 addr, u64 size)
> >> >> >>  	lockdep_assert_held(&kvm->mmu_lock);
> >> >> >>  	for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
> >> >> >>  		ret = kvm_call_hyp_nvhe(__pkvm_host_wrprotect_guest, handle, mapping->gfn,
> >> >> >> -					mapping->nr_pages);
> >> >> >> +					pkvm_mapping_nr_pages(mapping));
> >> >> >>  		if (WARN_ON(ret))
> >> >> >>  			break;
> >> >> >>  	}
> >> >> >> @@ -517,9 +542,13 @@ int pkvm_pgtable_stage2_flush(struct
> >kvm_pgtable
> >> >> >*pgt, u64 addr, u64 size)
> >> >> >>  	struct pkvm_mapping *mapping;
> >> >> >>  
> >> >> >>  	lockdep_assert_held(&kvm->mmu_lock);
> >> >> >> -	for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping)
> >> >> >> +	for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
> >> >> >> +		if (!pkvm_mapping_is_cacheable(mapping))
> >> >> >> +			continue;
> >> >> >> +
> >> >> >>  		__clean_dcache_guest_page(pfn_to_kaddr(mapping->pfn),
> >> >> >> -					  PAGE_SIZE * mapping->nr_pages);
> >> >> >> +					  PAGE_SIZE * pkvm_mapping_nr_pages(mapping));
> >> >> >> +	}
> >> >> >>  
> >> >> >>  	return 0;
> >> >> >>  }
> >> >> >> @@ -536,8 +565,10 @@ bool
> >pkvm_pgtable_stage2_test_clear_young(struct
> >> >> >kvm_pgtable *pgt, u64 addr, u64
> >> >> >>  
> >> >> >>  	lockdep_assert_held(&kvm->mmu_lock);
> >> >> >>  	for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping)
> >> >> >> -		young |= kvm_call_hyp_nvhe(__pkvm_host_test_clear_young_guest, handle, mapping->gfn,
> >> >> >> -					   mapping->nr_pages, mkold);
> >> >> >> +		young |= kvm_call_hyp_nvhe(__pkvm_host_test_clear_young_guest,
> >> >> >> +					   handle, mapping->gfn,
> >> >> >> +					   pkvm_mapping_nr_pages(mapping),
> >> >> >> +					   mkold);
> >> >> >>  
> >> >> >>  	return young;
> >> >> >>  }
> >> >> >> -- 
> >> >> >> 2.53.0
> >> >> >> 
> >> >> >
> >> >> 
> >> >> Thanks!
> >> >
> >> 
> >> Thanks!
> >
> >Thanks!
> >
> 
> Thanks!


^ permalink raw reply

* Re: [PATCH net v2] net: airoha: Add retry mechanism to airoha_qdma_set_trtcm_param()
From: Leto Liu (刘涛) @ 2026-07-02 10:44 UTC (permalink / raw)
  To: Lorenzo Bianconi, Simon Horman
  Cc: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, netdev@vger.kernel.org,
	Brown Huang (黃柏翰)
In-Reply-To: <ajrtd5WA2GFzQyV9@lore-desk>

First, let me descript the detailed mechanism of hardware QDMA register read/write is as follows:

CPU register reads do not have a “write-fail” issue; a CPU read operation does not fail to execute.
A CPU register write may not take effect as expected, i.e., the value written by the CPU may not be preserved. This is because QDMA performs non-atomic read-modify-write (RMW) operations, and a hardware write can overwrite a CPU write, causing the CPU write to be lost.
rw_done is cleared to 0 when the CPU issues a write request, and is set to 1 after completion. The interval is only a few hardware clock cycles (less than 10 ns).
Regarding write contention:

      CPU side (driver/software)                 HW side (rate-limiter engine)
             |                                               |
             | write cfg_param register                       | token-bucket refill tick / packet ingress/egress
             | (indirectly writes SRAM)                       | (updates SRAM)
             |                                               |
             v                                               v
+-----------------------------------------------------------------------------------------------------------------------------------------+
|                                  HW SRAM                                         |
|                                                                                   |
|  HW performs Read-Modify-Write (non-atomic)                                           |
|        |                                                                          |
|        | 1. HW reads the old value                                                     |
|        | 2. CPU write happens first     --->  contention point                             |
|        | 3. HW write overwrites with old/mod value  --->  CPU value overwritten             |
|        v                                                                          |
+-----------------------------------------------------------------------------------------------------------------------------------------+
Best Regards, Leto

> > This is an AI-generated review of your patch. The human sending this 
> > email has considered the AI review valid, or at least plausible.
> > Full review at: https://sashiko.dev
> > 
> > Simon says: I'd appreciate it if you could look over the first two issues
> >             flagged below in the context of this patch. While the third
> > 	    and final issue looks like it is in possible separate follow-up
> > 	    territory.
> > 
> > ---
> > net: airoha: Add retry mechanism to airoha_qdma_set_trtcm_param()
> >     
> > This patch introduces a retry loop to airoha_qdma_set_trtcm_param() to 
> > mitigate bus timeouts when configuring QDMA parameters. It attempts to 
> > verify that the configuration is correctly applied to the hardware.
> > 
> > > diff --git a/drivers/net/ethernet/airoha/airoha_eth.c 
> > > b/drivers/net/ethernet/airoha/airoha_eth.c
> > > index 3370c3df7c107..bb5c0599a4eed 100644
> > > --- a/drivers/net/ethernet/airoha/airoha_eth.c
> > > +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> > > @@ -2673,14 +2673,30 @@ static int airoha_qdma_set_trtcm_param(struct airoha_qdma *qdma, int channel,
> > >  		     FIELD_PREP(TRTCM_METER_GROUP_MASK, group) |
> > >  		     FIELD_PREP(TRTCM_PARAM_INDEX_MASK, idx) |
> > >  		     FIELD_PREP(TRTCM_PARAM_RATE_TYPE_MASK, mode);
> > > +	int i;
> > >  
> > > -	airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
> > > -	airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
> > > +	for (i = 0; i < 100; i++) {
> > > +		u32 data;
> > >  
> > > -	return read_poll_timeout(airoha_qdma_rr, val,
> > > -				 val & TRTCM_PARAM_RW_DONE_MASK,
> > > -				 USEC_PER_MSEC, 10 * USEC_PER_MSEC, true,
> > > -				 qdma, REG_TRTCM_CFG_PARAM(addr));
> > > +		airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
> > > +		wmb();
> > > +		airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
> > > +
> > > +		if (read_poll_timeout(airoha_qdma_rr, data,
> > > +				      data & TRTCM_PARAM_RW_DONE_MASK,
> > > +				      USEC_PER_MSEC, 10 * USEC_PER_MSEC,
> > > +				      true, qdma, REG_TRTCM_CFG_PARAM(addr)))
> > > +			return -ETIMEDOUT;
> > 
> > [Severity: High]
> > If a bus timeout causes the write phase's read_poll_timeout() in
> > airoha_qdma_set_trtcm_param() to fail, this immediately returns 
> > -ETIMEDOUT, aborting the 100-iteration retry loop.
> > 
> > Doesn't this defeat the mitigation?

Here we are polling the hardware done bit. Based on the hardware behavior described above, a read operation will not fail. In addition, the hardware register write completes within at most 10 ns, while the poll timeout here is configured more than 1 ms. From these two points, we can conclude that this read_poll_timeout will always succeed (i.e., it will return 0). Therefore, adding a return -ETIMEDOUT path here will not cause any issues.
Best Regards, Leto

>
> I agree we just run 'continue' here instead of returing -ETIMEDOUT
No change is needed here, and even if we modify it, it will not cause any issues. 
Best Regards, Leto

> > 
> > > +
> > > +		if (airoha_qdma_get_trtcm_param(qdma, channel, addr, param,
> > > +						mode, &data, NULL))
> > > +			continue;
> > 
> > [Severity: High]
> > If airoha_qdma_get_trtcm_param() times out during the verification 
> > phase, it indicates the hardware hasn't finished the read command (DONE bit is still 0).
> > 
> > The continue statement then immediately starts the next iteration, 
> > writing new commands to DATA_LOW and CFG_PARAM.
> > 
> > Can writing to command registers while the hardware state machine is 
> > actively busy violate hardware protocols and lead to unrecoverable lockups?
>
> @Brown and @Leto: can you please comment on this case?
>
the hardware register write completes within at most 10 ns, while the poll timeout here is configured more than 1 ms. When airoha_qdma_get_trtcm_param() is called here, the hardware has already completed the previous register write operation. Therefore, the concern mentioned here will definitely not occur, and there will be no issue at this point.
Best Regards, Leto

> > 
> > > +
> > > +		if (data == val)
> > > +			return 0;
> > 
> > [Severity: High]
> > This isn't a bug introduced by this patch, but if the bus drops the 
> > command write to REG_TRTCM_CFG_PARAM, the hardware never executes the 
> > command and the TRTCM_PARAM_RW_DONE_MASK bit remains set from the previous operation.
> > 
> > Consequently, read_poll_timeout() returns an immediate false success.
> > 
> > If both the set and get command writes are dropped by the bus, the get 
> > operation will read back the newly written DATA_LOW register value.
> > 
> > Will the data == val check evaluate to true and falsely report success 
> > without the hardware ever processing the configuration?
>
> This seems quite a 'pathological' scenario, is it really an issue?
>
> Regards,
> Lorenzo
>
As explained above, the concern here does not apply and there will be no issue.
Best Regards, Leto

> > 
> > > +	}
> > > +
> > > +	return -EBUSY;
> > >  }
> > >  
> > 
> > [ ... ]
> > 
> > >  static int airoha_qdma_set_trtcm_config(struct airoha_qdma *qdma, int channel,
> > >  					u32 addr, enum trtcm_mode_type mode,
> > >  					bool enable, u32 enable_mask)
> > >  {
> > >  	u32 val;
> > >  
> > >  	if (airoha_qdma_get_trtcm_param(qdma, channel, addr, TRTCM_MISC_MODE,
> > >  					mode, &val, NULL))
> > >  		return -EINVAL;
> > 
> > [Severity: High]
> > Standalone calls to airoha_qdma_get_trtcm_param(), like this one in 
> > airoha_qdma_set_trtcm_config(), lack a retry loop entirely.
> > 
> > Does this leave read-modify-write cycles fully vulnerable to the same 
> > bus timeouts the patch attempts to mitigate?
> > 
No change is needed here. Even if the write succeeds but the read-back during verification returns an incorrect value, the verification will fail and the code will proceed to the next retry. A failure would only occur if this happened for 100 consecutive attempts, which has an almost zero probability. Therefore, this code does not affect the final outcome.
That said, your suggestion is a good one, and it is still worthwhile to improve/optimize the read function.
Best Regards, Leto

> > [Severity: High]
> > This isn't a bug introduced by this patch, but the patch mitigates bus 
> > timeouts in airoha_qdma_set_trtcm_param() while entirely missing 
> > airoha_qdma_set_rl_param().
> > 
> > The latter performs the exact same write-and-poll sequence on 
> > identical QDMA configuration registers:
> > 
> > drivers/net/ethernet/airoha/airoha_eth.c:airoha_qdma_set_rl_param() {
> >     ...
> >     return read_poll_timeout(..., val & RATE_LIMIT_PARAM_RW_DONE_MASK, 
> > ...); }
> > 
> > If bus timeouts affect QDMA access broadly as stated in the commit 
> > message, are the rate-limiting configuration paths randomly vulnerable to the same failures?
> > 

Yes, you are right. Function airoha_qdma_set_rl_param need readback protecting.
Best Regards, Leto

> > [Severity: High]
> > This isn't a bug introduced by this patch, but in 
> > airoha_tc_remove_htb_queue(), hardware teardown incorrectly uses queue + 1 instead of queue:
> > 
> > drivers/net/ethernet/airoha/airoha_eth.c:airoha_tc_remove_htb_queue() {
> >     ...
> >     airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0);
> >     ...
> > }
> > 
> > Does this leave the removed queue's hardware limits permanently active 
> > (resource leak) and inadvertently disable the rate limits for queue + 
> > 1, corrupting the QoS state of another active channel?
It has already been fixed, refer to https://github.com/LorenzoBianconi/net-next/commit/d775d542504cbfea2b214149405d97eb00a88dc4
Best Regards, Leto

^ permalink raw reply

* Re: [PATCH 2/5] arm64: cpufeature: Detect BBML3 based on MMFR2 ID
From: Mark Rutland @ 2026-07-02 10:45 UTC (permalink / raw)
  To: Linu Cherian
  Cc: Catalin Marinas, Will Deacon, Ryan Roberts, Kevin Brodsky,
	Anshuman Khandual, Suzuki K Poulose, linux-arm-kernel,
	linux-kernel
In-Reply-To: <20260701094131.677636-3-linu.cherian@arm.com>

On Wed, Jul 01, 2026 at 03:11:28PM +0530, Linu Cherian wrote:
> Add MMFR2 ID based BBML3 feature detection, so
> that compliant cpus doesn't need to be added to the
> midr list.
> 
> Signed-off-by: Linu Cherian <linu.cherian@arm.com>
> ---
>  arch/arm64/kernel/cpufeature.c | 14 +++++++-------
>  arch/arm64/tools/sysreg        |  1 +
>  2 files changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 9986eb7b379c..d754b1b7da77 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -2133,6 +2133,7 @@ static bool hvhe_possible(const struct arm64_cpu_capabilities *entry,
>  
>  bool cpu_supports_bbml3(void)
>  {
> +	u64 mmfr2;
>  	/* CPUs that support BBML3 but dont advertise through MMFR2 ID */
>  	static const struct midr_range supports_bbml3_list[] = {
>  		MIDR_REV_RANGE(MIDR_CORTEX_X4, 0, 3, 0xf),
> @@ -2144,15 +2145,14 @@ bool cpu_supports_bbml3(void)
>  		{}
>  	};
>  
> -	if (!is_midr_in_range_list(supports_bbml3_list))
> -		return false;
> +	if (is_midr_in_range_list(supports_bbml3_list))
> +		return true;
>  
> -	/*
> -	 * We currently ignore the ID_AA64MMFR2_EL1 register, and only care
> -	 * about whether the MIDR check passes.
> -	 */
> +	mmfr2 = __read_sysreg_by_encoding(SYS_ID_AA64MMFR2_EL1);
> +	if (SYS_FIELD_GET(ID_AA64MMFR2_EL1, BBM, mmfr2) == ID_AA64MMFR2_EL1_BBM_3)
> +		return true;

This needs to be '>=', so that if there's a future BBML4, we correctly
detect that CPUs with BBML4 also have the BBML3 behaviour.

It would also be better to check the ID field first, before falling back
to the MIDR check. That way a reader can more clearly see that
supports_bbml3_list catches older parts that don't advertised BBML3, and
the comment above supports_bbml3_list would be clearer.

With those changes, this looks sane to me.

Mark.

>  
> -	return true;
> +	return false;
>  }
>  
>  static bool has_bbml3(const struct arm64_cpu_capabilities *caps, int scope)
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index bc1788b1662b..082256ec3bf9 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -2259,6 +2259,7 @@ UnsignedEnum	55:52	BBM
>  	0b0000	0
>  	0b0001	1
>  	0b0010	2
> +	0b0011	3
>  EndEnum
>  UnsignedEnum	51:48	TTL
>  	0b0000	NI
> -- 
> 2.43.0
> 


^ permalink raw reply

* Re: [PATCH 5/5] arm64: cpufeature: Extend bbml3 support list
From: Mark Rutland @ 2026-07-02 10:47 UTC (permalink / raw)
  To: Linu Cherian
  Cc: Catalin Marinas, Will Deacon, Ryan Roberts, Kevin Brodsky,
	Anshuman Khandual, Suzuki K Poulose, linux-arm-kernel,
	linux-kernel
In-Reply-To: <20260701094131.677636-6-linu.cherian@arm.com>

On Wed, Jul 01, 2026 at 03:11:31PM +0530, Linu Cherian wrote:
> Add below cpus to the midr list, which supports
> BBML3 but don't advertise through MMFR2 ID.
> 
> Cortex A520(AE)
> Cortex A715
> Cortex A720(AE)
> Cortex A725
> Neoverse N3
> C1-Nano
> C1-Pro
> C1-Ultra
> C1-Premium
> 
> Signed-off-by: Linu Cherian <linu.cherian@arm.com>
> ---
>  arch/arm64/kernel/cpufeature.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index d754b1b7da77..9b806c1c60aa 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -2142,6 +2142,15 @@ bool cpu_supports_bbml3(void)
>  		MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
>  		MIDR_ALL_VERSIONS(MIDR_AMPERE1),
>  		MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
> +		MIDR_ALL_VERSIONS(MIDR_CORTEX_A520AE),
> +		MIDR_ALL_VERSIONS(MIDR_CORTEX_A715),
> +		MIDR_ALL_VERSIONS(MIDR_CORTEX_A720AE),
> +		MIDR_ALL_VERSIONS(MIDR_CORTEX_A725),
> +		MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N3),
> +		MIDR_ALL_VERSIONS(MIDR_C1_NANO),
> +		MIDR_ALL_VERSIONS(MIDR_C1_PRO),
> +		MIDR_REV_RANGE(MIDR_C1_ULTRA, 1, 1, 0xf),
> +		MIDR_REV_RANGE(MIDR_C1_PREMIUM, 1, 1, 0xf),

Why do these two have a range? The commit message didn't mention this.

Mark.


^ permalink raw reply

* Re: [PATCH 4/4] drm/tidss: Fix sampling edge configuration
From: Leonardo Costa @ 2026-07-02 10:48 UTC (permalink / raw)
  To: louis.chauvet
  Cc: airlied, bparrot, conor+dt, devicetree, dri-devel, jsarha,
	jyri.sarha, kristo, krzk+dt, lee, linux-arm-kernel, linux-kernel,
	maarten.lankhorst, mripard, nm, robh, sam, simona, stable,
	thomas.petazzoni, tomi.valkeinen, tomi.valkeinen, tzimmermann,
	vigneshr
In-Reply-To: <20250730-fix-edge-handling-v1-4-1bdfb3fe7922@bootlin.com>

Hello,

We tested this patch and it introduces a regression on our panel.

On our board, a Toshiba TC358768 DPI-to-DSI bridge is connected to the parallel
RGB output. The bridge requires data to be driven on the negative edge, and
this is also reflected by the `ipc` variable in `dispc_vp_enable()`, which is
set to `1`.

With this patch applied, however, data is driven on the positive edge instead.

According to SPRUIV7C, both `MAIN_CTRL_MMR_CFG0_DPI0_CLK_CTRL[8]` and
`DSS_VP1_POL_FREQ[14] IPC` should be programmed consistently. However, if we
follow the actual bit descriptions, and ignore the sentence saying that the two
programmed values should be the same, the data is driven on the requested edge.

From SPRUIV7C (https://www.ti.com/lit/ug/spruiv7b/spruiv7c.pdf):

MAIN_CTRL_MMR_CFG0_DPI0_CLK_CTRL[8] (DPI0_CLK_CTRL_DATA_CLK_INVDIS):

        Clock edge select for DPI0 data outputs

        Note that this value should be the same as the programmed value of
        DSS_POL_FREQ[14] IPC.

        Reset Source: mod_por_rst_n

        0 DATA and DE are driven on the falling edge of clk
        1 DATA and DE are driven on the rising edge of clk


    DSS_VP1_POL_FREQ[14] (IPC)

        Invert pixel clock

        To set data to pixel clock relationship, CTRL_MMR_DPI0_CLK_CTRL[8]
        DPI0_CLK_CTRL_DATA_CLK_INVDIS setting should be the same as the [14]
        IPC setting.

        0 Data is driven on the LCD data lines on the rising-edge of the pixel clock
        1 Data is driven on the LCD data lines on the falling-edge of the pixel clock

So, the proposed fix to this patch is:

```diff
- regmap_update_bits(dispc->clk_ctrl, 0, 0x100, ipc ? 0x100 : 0x000);
+ regmap_update_bits(dispc->clk_ctrl, 0, 0x100, ipc ? 0x000 : 0x100);
```

Reverting the patch also makes the Toshiba bridge work correctly again.
However, we can confirm that the patch is needed, otherwise only the
positive-edge case (our case) works correctly.

In other words, the two registers need to match semantically, not numerically.


^ permalink raw reply

* [PATCH v3 5/8] clk: sunxi-ng: sun6i-rtc: Add feature bit for IOSC calibration
From: Jerome Brunet @ 2026-07-02  8:10 UTC (permalink / raw)
  To: Junhui Liu, Alexandre Belloni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
	Michael Turquette, Stephen Boyd, Maxime Ripard
  Cc: linux-rtc, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, linux-clk, Jerome Brunet
In-Reply-To: <20260702-a733-rtc-v3-0-eb2580374de6@baylibre.com>

From: Junhui Liu <junhui.liu@pigmoral.tech>

The sun6i-rtc CCU driver currently uses a global static variable to
denote whether calibration is supported, which makes IOSC operations
tightly coupled to this file.

Convert this into a feature bit to decouple the logic. This allows the
IOSC clock code to be moved into a shared module for reuse by other SoCs.

Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 17 +++++++++--------
 drivers/clk/sunxi-ng/ccu_common.h    |  1 +
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
index 0f528bfaed00..b24c8b196e66 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
@@ -52,8 +52,6 @@ struct sun6i_rtc_match_data {
 	u8				osc32k_fanout_nparents;
 };
 
-static bool have_iosc_calibration;
-
 static int ccu_iosc_enable(struct clk_hw *hw)
 {
 	struct ccu_common *cm = hw_to_ccu_common(hw);
@@ -80,7 +78,7 @@ static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
 {
 	struct ccu_common *cm = hw_to_ccu_common(hw);
 
-	if (have_iosc_calibration) {
+	if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
 		u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);
 
 		/*
@@ -119,7 +117,7 @@ static int ccu_iosc_32k_prepare(struct clk_hw *hw)
 	struct ccu_common *cm = hw_to_ccu_common(hw);
 	u32 val;
 
-	if (!have_iosc_calibration)
+	if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
 		return 0;
 
 	val = readl(cm->base + IOSC_CLK_CALI_REG);
@@ -134,7 +132,7 @@ static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
 	struct ccu_common *cm = hw_to_ccu_common(hw);
 	u32 val;
 
-	if (!have_iosc_calibration)
+	if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
 		return;
 
 	val = readl(cm->base + IOSC_CLK_CALI_REG);
@@ -148,7 +146,7 @@ static unsigned long ccu_iosc_32k_recalc_rate(struct clk_hw *hw,
 	struct ccu_common *cm = hw_to_ccu_common(hw);
 	u32 val;
 
-	if (have_iosc_calibration) {
+	if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
 		val = readl(cm->base + IOSC_CLK_CALI_REG);
 
 		/* Assume the calibrated 32k clock is accurate. */
@@ -167,7 +165,7 @@ static unsigned long ccu_iosc_32k_recalc_accuracy(struct clk_hw *hw,
 	struct ccu_common *cm = hw_to_ccu_common(hw);
 	u32 val;
 
-	if (have_iosc_calibration) {
+	if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
 		val = readl(cm->base + IOSC_CLK_CALI_REG);
 
 		/* Assume the calibrated 32k clock is accurate. */
@@ -358,7 +356,10 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
 		return 0;
 
 	data = match->data;
-	have_iosc_calibration = data->have_iosc_calibration;
+	if (data->have_iosc_calibration) {
+		iosc_clk.features |= CCU_FEATURE_IOSC_CALIBRATION;
+		iosc_32k_clk.features |= CCU_FEATURE_IOSC_CALIBRATION;
+	}
 
 	if (!data->have_ext_osc32k) {
 		/* ext-osc32k-gate is an orphan, so do not register it. */
diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h
index bbec283b9d99..d9dc24ad5503 100644
--- a/drivers/clk/sunxi-ng/ccu_common.h
+++ b/drivers/clk/sunxi-ng/ccu_common.h
@@ -21,6 +21,7 @@
 #define CCU_FEATURE_CLOSEST_RATE	BIT(9)
 #define CCU_FEATURE_DUAL_DIV		BIT(10)
 #define CCU_FEATURE_UPDATE_BIT		BIT(11)
+#define CCU_FEATURE_IOSC_CALIBRATION	BIT(12)
 
 /* MMC timing mode switch bit */
 #define CCU_MMC_NEW_TIMING_MODE		BIT(30)

-- 
2.47.3



^ permalink raw reply related

* Re: [PATCH 18/18] arm64: defconfig: Enable DS90UB960 deserializer and DS90UB953 serializer
From: Krzysztof Kozlowski @ 2026-07-02 10:54 UTC (permalink / raw)
  To: Yemike Abhilash Chandra, nm, vigneshr, kristo, robh, krzk+dt,
	conor+dt
  Cc: Frank.Li, s.hauer, kernel, festevam, andersson, geert,
	dmitry.baryshkov, arnd, ebiggers, luca.weiss, michal.simek, sven,
	linux-arm-kernel, devicetree, linux-kernel, imx, r-donadkar,
	devarsht, u-kumar1
In-Reply-To: <20260702093123.1048575-19-y-abhilashchandra@ti.com>

On 02/07/2026 11:31, Yemike Abhilash Chandra wrote:
> Enable building Texas Instruments DS90UB960 deserializer and
> DS90UB953 serializer drivers as modules.

Standard question: why... Use lore.kernel.org for past discussions.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH] futex: Optimise the size check get_futex_key()
From: Sebastian Andrzej Siewior @ 2026-07-02 10:56 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: K Prateek Nayak, Arnd Bergmann, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, x86, Catalin Marinas, Will Deacon,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Heiko Carstens,
	Vasily Gorbik, Alexander Gordeev, Darren Hart, Davidlohr Bueso,
	André Almeida, linux-arch, linux-kernel, Samuel Holland,
	Charlie Jenkins, linux-arm-kernel, linux-riscv, linux-s390,
	H. Peter Anvin, Thomas Huth, Sean Christopherson, Jisheng Zhang,
	Alexandre Ghiti, Christian Borntraeger, Sven Schnelle
In-Reply-To: <20260702085921.GD49951@noisy.programming.kicks-ass.net>

On 2026-07-02 10:59:21 [+0200], Peter Zijlstra wrote:
> > Could someone verify this, please? The 5% look a bit high. This is on
> > top of the series (but not worsen by the series).
> 
> Bah, I tried to reproduce and couldn't. Then I noticed I did a clang
> build and that is in fact clever enough to do this optimization itself.
> 
> /me tries again with a GCC build.
> 
> pre:  [thread  0] futex: 0x561f14430680 [ 9021408 ops/sec ]
> post: [thread  0] futex: 0x55feadbbb680 [ 8977527 ops/sec ]
> 
> (and this seems to be well inside the error threshold of this test).
> 
> So I see the GCC build do the DIV, and no longer with his patch applied,
> but for some reason I cannot get the runtime performance to actually
> improve much of anything on my system.

I did open https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126078 for the
div.

My .config is the debian distro on the 4 node big iron. [ in case it
it has so much overhead elsewhere that this place a bigger role].

"perf top" showed this as 6% or something and red in the function. After
the removal it did not show up.

Sebastian


^ permalink raw reply


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