* Re: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe Ethernet
From: Heiner Kallweit @ 2026-06-05 15:48 UTC (permalink / raw)
To: ricardo, nic_swsd, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Heiko Stuebner
Cc: Sebastian Reichel, netdev, devicetree, linux-kernel,
linux-arm-kernel, linux-rockchip
In-Reply-To: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
On 05.06.2026 13:49, Ricardo Pardini via B4 Relay wrote:
> From: Ricardo Pardini <ricardo@pardini.net>
>
> Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
> driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).
>
> The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
> spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
> need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
> compatibles documented in their own bindings (e.g. microchip,lan95xx)
> so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
> these PCI function nodes can be validated.
>
The of node seems to be created by of_pci_make_dev_node(). But this
function is called for bridges only in pci_bus_add_device().
So where is the node created in your case? Did you test node creation?
> Suggested-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> Signed-off-by: Ricardo Pardini <ricardo@pardini.net>
> ---
> .../devicetree/bindings/net/realtek,r8169.yaml | 54 ++++++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 55 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/net/realtek,r8169.yaml b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
> new file mode 100644
> index 0000000000000..6923211ff4c93
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/realtek,r8169.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Realtek r8169 family PCIe Ethernet Controllers
> +
> +maintainers:
> + - Heiner Kallweit <hkallweit1@gmail.com>
> +
> +description:
> + PCI function node properties for fixed/soldered Realtek Ethernet
> + controllers driven by the r8169 driver.
> +
> +allOf:
> + - $ref: ethernet-controller.yaml#
> +
> +properties:
> + compatible:
> + enum:
> + - pci10ec,8125 # RTL8125 2.5GbE
> + - pci10ec,8126 # RTL8126 5GbE
> + - pci10ec,8127 # RTL8127
> + - pci10ec,8161 # RTL8168 variant
> + - pci10ec,8162 # RTL8168 variant
> + - pci10ec,8168 # RTL8168/8111 GbE
This list reflects just some of the PCI id's handled by r8169.
Any specific reason for this exact selection?
> +
> + reg:
> + maxItems: 1
> +
> + local-mac-address: true
> + mac-address: true
> + nvmem-cells: true
> + nvmem-cell-names: true
> +
> +required:
> + - compatible
> + - reg
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + pcie {
> + #address-cells = <3>;
> + #size-cells = <2>;
> +
> + ethernet@0,0 {
> + compatible = "pci10ec,8125";
> + reg = <0x10000 0 0 0 0>;
> + local-mac-address = [00 00 00 00 00 00];
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b539be153f6a4..6341de4fadb6c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -134,6 +134,7 @@ M: Heiner Kallweit <hkallweit1@gmail.com>
> M: nic_swsd@realtek.com
> L: netdev@vger.kernel.org
> S: Maintained
> +F: Documentation/devicetree/bindings/net/realtek,r8169.yaml
> F: drivers/net/ethernet/realtek/r8169*
>
> 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
>
^ permalink raw reply
* Re: [PATCH bpf-next v2 8/8] selftests/bpf: add tests to validate KASAN on JIT programs
From: Yonghong Song @ 2026-06-05 15:47 UTC (permalink / raw)
To: Alexis Lothoré (eBPF Foundation), Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu, Jiri Olsa,
John Fastabend, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Shuah Khan, Maxime Coquelin,
Alexandre Torgue, Ihor Solodrai
Cc: ebpf, Bastien Curutchet, Thomas Petazzoni, bpf, linux-kernel,
linux-kselftest, linux-stm32, linux-arm-kernel
In-Reply-To: <20260604-kasan-v2-8-c066e627fda8@bootlin.com>
On 6/4/26 1:22 PM, Alexis Lothoré (eBPF Foundation) wrote:
> Add a basic KASAN test runner that loads and test-run programs that can
> trigger memory management bugs. The test captures kernel logs and ensure
> that the expected KASAN splat is emitted by searching for the
> corresponding first lines in the report, hence validated that the needed
> instrumentation has been inserted by the JIT compiler before the
> relevant memory accesses.
>
> The runner covers different cases and settings: in the nominal case, it
> validates kasan reports on basic instructions (on all supported accesses
> sizes) but also when report _should not_ be emitted (eg: for accesses on
> program stack). The runner also comes with a few specialized tests that
> are then not executed for all sizes/locations. A few of those tests
> depends on cpuv4 (load_acquire and store_release).
>
> # ./test_progs -a kasan
> #164/1 kasan/st_1_not_on_stack:OK
> #164/2 kasan/st_1_on_stack:OK
> #164/3 kasan/st_2_not_on_stack:OK
> #164/4 kasan/st_2_on_stack:OK
> #164/5 kasan/st_4_not_on_stack:OK
> #164/6 kasan/st_4_on_stack:OK
> #164/7 kasan/st_8_not_on_stack:OK
> #164/8 kasan/st_8_on_stack:OK
> #164/9 kasan/stx_1_not_on_stack:OK
> #164/10 kasan/stx_1_on_stack:OK
> #164/11 kasan/stx_2_not_on_stack:OK
> #164/12 kasan/stx_2_on_stack:OK
> #164/13 kasan/stx_4_not_on_stack:OK
> #164/14 kasan/stx_4_on_stack:OK
> #164/15 kasan/stx_8_not_on_stack:OK
> #164/16 kasan/stx_8_on_stack:OK
> #164/17 kasan/ldx_1_not_on_stack:OK
> #164/18 kasan/ldx_1_on_stack:OK
> #164/19 kasan/ldx_2_not_on_stack:OK
> #164/20 kasan/ldx_2_on_stack:OK
> #164/21 kasan/ldx_4_not_on_stack:OK
> #164/22 kasan/ldx_4_on_stack:OK
> #164/23 kasan/ldx_8_not_on_stack:OK
> #164/24 kasan/ldx_8_on_stack:OK
> #164/25 kasan/simple_atomic_4_not_on_stack:OK
> #164/26 kasan/simple_atomic_4_on_stack:OK
> #164/27 kasan/simple_atomic_8_not_on_stack:OK
> #164/28 kasan/simple_atomic_8_on_stack:OK
> #164/29 kasan/load_acquire_1_not_on_stack:SKIP
> #164/30 kasan/load_acquire_1_on_stack:SKIP
> #164/31 kasan/load_acquire_2_not_on_stack:SKIP
> #164/32 kasan/load_acquire_2_on_stack:SKIP
> #164/33 kasan/load_acquire_4_not_on_stack:SKIP
> #164/34 kasan/load_acquire_4_on_stack:SKIP
> #164/35 kasan/load_acquire_8_not_on_stack:SKIP
> #164/36 kasan/load_acquire_8_on_stack:SKIP
> #164/37 kasan/store_release_1_not_on_stack:SKIP
> #164/38 kasan/store_release_1_on_stack:SKIP
> #164/39 kasan/store_release_2_not_on_stack:SKIP
> #164/40 kasan/store_release_2_on_stack:SKIP
> #164/41 kasan/store_release_4_not_on_stack:SKIP
> #164/42 kasan/store_release_4_on_stack:SKIP
> #164/43 kasan/store_release_8_not_on_stack:SKIP
> #164/44 kasan/store_release_8_on_stack:SKIP
> #164/45 kasan/ldx_patched:OK
> #164/46 kasan/stack_and_non_stack:OK
> #164 kasan:OK (SKIP: 16/46)
> Summary: 1/30 PASSED, 16 SKIPPED, 0 FAILED
On my qemu run, I got a bunch of failures like below:
[root@arch-fb-vm1 bpf]# ./test_progs -n 164
test_kasan:PASS:alloc test ctx 0 nsec
gzopen /boot/config-7.1.0-rc5-gec86c8156bd6: No such file or directory
test_kasan:PASS:open prog 0 nsec
test_kasan:PASS:find rnd_hi32 prog 0 nsec
...
All error logs:
test_kasan:PASS:alloc test ctx 0 nsec
gzopen /boot/config-7.1.0-rc5-gec86c8156bd6: No such file or directory
test_kasan:PASS:open prog 0 nsec
test_kasan:PASS:find rnd_hi32 prog 0 nsec
test_kasan:PASS:load prog 0 nsec
test_kasan:PASS:open kernel logs 0 nsec
test_kasan:PASS:get map 0 nsec
test_kasan:PASS:set map 0 nsec
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/1 kasan/st_1_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/3 kasan/st_2_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/5 kasan/st_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/7 kasan/st_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/9 kasan/stx_1_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/11 kasan/stx_2_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/13 kasan/stx_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/15 kasan/stx_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/17 kasan/ldx_1_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/19 kasan/ldx_2_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/21 kasan/ldx_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/23 kasan/ldx_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/25 kasan/simple_atomic_4_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/27 kasan/simple_atomic_8_not_on_stack:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/45 kasan/ldx_patched:FAIL
run_subtest_with_size_and_location:PASS:find test prog 0 nsec
run_subtest_with_size_and_location:PASS:fetch loaded program info 0 nsec
run_subtest_with_size_and_location:PASS:run prog 0 nsec
run_subtest_with_size_and_location:PASS:read kernel logs 0 nsec
run_subtest_with_size_and_location:FAIL:report should be generated unexpected error: 1 (errno 11)
#164/46 kasan/stack_and_non_stack:FAIL
#164 kasan:FAIL
I checked the subtest 164/1,
For
ret = check_kasan_report_in_kernel_logs(klog_buffer, ctx,
test->is_write, access_size);
if (on_stack || test->expect_no_report)
ASSERT_NEQ(ret, 0, "no report should be generated");
else
ASSERT_OK(ret, "report should be generated");
the ret is equal to 1 as klog_buffer is empty. This caused the failure.
>
> Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
> ---
> Changes in v2:
> - simplify tests by just manually poisoning test areas with a dedicated
> kfunc
> - introduce one prog per covered instruction family
> - make sure that tests do not consume kernel logs (use /dev/kmgs rather
> than klogctl)
> - add tests for stack accesses:
> - marking correctly set when there are diverging verifier states
> leading to different memory types
> - marking kept in sync with prog when it is patched
> ---
> tools/testing/selftests/bpf/prog_tests/kasan.c | 356 +++++++++++++++++++
> tools/testing/selftests/bpf/progs/kasan.c | 382 +++++++++++++++++++++
> .../testing/selftests/bpf/test_kmods/bpf_testmod.c | 22 ++
> 3 files changed, 760 insertions(+)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/kasan.c b/tools/testing/selftests/bpf/prog_tests/kasan.c
> new file mode 100644
> index 000000000000..adf61e230ec9
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/kasan.c
> @@ -0,0 +1,356 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +#include <bpf/bpf.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <linux/if_ether.h>
> +#include <unistd.h>
> +#include <test_progs.h>
> +#include <unpriv_helpers.h>
> +#include "kasan.skel.h"
> +
> +#define SUBTEST_NAME_MAX_LEN 128
> +#define PROG_NAME_MAX_LEN 128
> +
> +#define MAX_LOG_SIZE (8 * 1024)
> +#define READ_CHUNK_SIZE 256
> +
> +#define KASAN_PATTERN_SLAB_UAF "BUG: KASAN: slab-use-after-free " \
> + "in bpf_prog_%02x%02x%02x%02x%02x%02x%02x%02x_%s"
> +#define KASAN_PATTERN_REPORT "%s of size %d at addr"
> +
> +static char klog_buffer[MAX_LOG_SIZE];
> +
> +struct test_spec {
> + char *prog_type;
> + bool is_write;
> + bool only_32_or_64;
> + bool needs_load_acq_store_rel;
> + bool skip_multi_size_testing;
> + bool skip_on_stack_testing;
> + int run_size;
> + bool expect_no_report;
expect_no_report is not set in the code. The only usage is in
if (on_stack || test->expect_no_report)
ASSERT_NEQ(ret, 0, "no report should be generated");
else
ASSERT_OK(ret, "report should be generated");
> + bool rnd_hi32;
> +};
> +
> +struct kasan_write_val {
> + __u8 data_1;
> + __u16 data_2;
> + __u32 data_4;
> + __u64 data_8;
> +};
> +
>
[...]
^ permalink raw reply
* Re: [PATCH net-next v2 03/14] net: pcs: pcs-xpcs-regmap: support XPCS memory-mapped MDIO bus via regmap
From: Maxime Chevallier @ 2026-06-05 15:35 UTC (permalink / raw)
To: Alex Elder, andrew+netdev, davem, edumazet, kuba, pabeni,
rmk+kernel, andersson, konradybcio, robh, krzk+dt, conor+dt,
linusw, brgl, arnd, gregkh
Cc: Daniel Thompson, mohd.anwar, a0987203069, alexandre.torgue, ast,
boon.khai.ng, chenchuangyu, chenhuacai, daniel, hawk, hkallweit1,
inochiama, john.fastabend, julianbraha, livelycarpet87,
mcoquelin.stm32, me, prabhakar.mahadev-lad.rj, richardcochran,
rohan.g.thomas, sdf, siyanteng, weishangjuan, wens, netdev, bpf,
linux-arm-msm, devicetree, linux-gpio, linux-stm32,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260605010022.968612-4-elder@riscstar.com>
Hi Alex,
On 6/5/26 03:00, Alex Elder wrote:
> From: Daniel Thompson <daniel@riscstar.com>
>
> In some DesignWare XPCS implementatons the memory-mapped MDIO bus is
> allocated to a register window that does not align to a page boundary.
> This makes iomapping the registers problematic.
>
> For example the Toshiba TC9564 (a PCIe Ethernet-AVB/TSN bridge) provides
> an "eMAC" subsystem with the XPCS base address cuddled up to XGMAC
> registers.
>
> Let's introduce helpers to allow the driver that owns the eMAC to register
> an XPCS using is regmap for the memory-mapped MDIO bus.
>
> Signed-off-by: Daniel Thompson <daniel@riscstar.com>
> Signed-off-by: Alex Elder <elder@riscstar.com>
> ---
> MAINTAINERS | 2 +
> drivers/net/pcs/Makefile | 4 +-
> drivers/net/pcs/pcs-xpcs-regmap.c | 219 ++++++++++++++++++++++++++++
> include/linux/pcs/pcs-xpcs-regmap.h | 20 +++
> 4 files changed, 243 insertions(+), 2 deletions(-)
> create mode 100644 drivers/net/pcs/pcs-xpcs-regmap.c
> create mode 100644 include/linux/pcs/pcs-xpcs-regmap.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index eb8cdcc76324f..2aa6ea012c848 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25931,8 +25931,10 @@ F: drivers/net/ethernet/synopsys/
> SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
> L: netdev@vger.kernel.org
> S: Orphan
> +F: drivers/net/pcs/pcs-xpcs-regmap.c
> F: drivers/net/pcs/pcs-xpcs.c
> F: drivers/net/pcs/pcs-xpcs.h
> +F include/linux/pcs/pcs-xpcs-regmap.h
> F: include/linux/pcs/pcs-xpcs.h
>
> SYNOPSYS DESIGNWARE HDMI RX CONTROLLER DRIVER
> diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
> index 4f7920618b900..565f1b63fce0b 100644
> --- a/drivers/net/pcs/Makefile
> +++ b/drivers/net/pcs/Makefile
> @@ -1,8 +1,8 @@
> # SPDX-License-Identifier: GPL-2.0
> # Makefile for Linux PCS drivers
>
> -pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-plat.o \
> - pcs-xpcs-nxp.o pcs-xpcs-wx.o
> +pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-regmap.o \
> + pcs-xpcs-plat.o pcs-xpcs-wx.o
>
> obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
> obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
> diff --git a/drivers/net/pcs/pcs-xpcs-regmap.c b/drivers/net/pcs/pcs-xpcs-regmap.c
> new file mode 100644
> index 0000000000000..55cd05d09c7db
> --- /dev/null
> +++ b/drivers/net/pcs/pcs-xpcs-regmap.c
> @@ -0,0 +1,219 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Synopsys DesignWare XPCS regmap helpers
> + *
> + * Copyright (C) 2026 RISCstar Solutions.
> + * Copyright (C) 2024 Serge Semin
> + */
> +
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/mdio.h>
> +#include <linux/pcs/pcs-xpcs.h>
> +#include <linux/pcs/pcs-xpcs-regmap.h>
> +#include <linux/regmap.h>
> +
> +#include "pcs-xpcs.h"
> +
> +/* Page select register for the indirect MMIO CSRs access */
> +#define DW_VR_CSR_VIEWPORT 0xff
> +
> +struct dw_xpcs_regmap {
> + struct device *dev;
> + struct mii_bus *bus;
> + struct regmap *regmap;
> + bool reg_indir;
> +};
> +
> +static ptrdiff_t xpcs_regmap_addr_format(int dev, int reg)
> +{
> + return FIELD_PREP(0x1f0000, dev) | FIELD_PREP(0xffff, reg);
> +}
> +
> +static u16 xpcs_regmap_addr_page(ptrdiff_t csr)
> +{
> + return FIELD_GET(0x1fff00, csr);
> +}
> +
> +static ptrdiff_t xpcs_regmap_addr_offset(ptrdiff_t csr)
> +{
> + return FIELD_GET(0xff, csr);
> +}
> +
> +static int xpcs_regmap_read_reg_indirect(struct dw_xpcs_regmap *pxpcs, int dev,
> + int reg)
> +{
> + ptrdiff_t csr, ofs;
> + unsigned int val;
> + u16 page;
> + int res;
> +
> + csr = xpcs_regmap_addr_format(dev, reg);
> + page = xpcs_regmap_addr_page(csr);
> + ofs = xpcs_regmap_addr_offset(csr);
> +
> + res = regmap_write(pxpcs->regmap, DW_VR_CSR_VIEWPORT, page);
> + if (res < 0)
> + return res;
> +
> + res = regmap_read(pxpcs->regmap, ofs, &val);
> + if (res < 0)
> + return res;
> +
> + return val & 0xffff;
> +}
> +
> +static int xpcs_regmap_write_reg_indirect(struct dw_xpcs_regmap *pxpcs, int dev,
> + int reg, u16 val)
> +{
> + ptrdiff_t csr, ofs;
> + u16 page;
> + int res;
> +
> + csr = xpcs_regmap_addr_format(dev, reg);
> + page = xpcs_regmap_addr_page(csr);
> + ofs = xpcs_regmap_addr_offset(csr);
> +
> + res = regmap_write(pxpcs->regmap, DW_VR_CSR_VIEWPORT, page);
> + if (res < 0)
> + return res;
> +
> + return regmap_write(pxpcs->regmap, ofs, val);
> +}
> +
> +static int xpcs_regmap_read_reg_direct(struct dw_xpcs_regmap *pxpcs, int dev,
> + int reg)
> +{
> + unsigned int val;
> + ptrdiff_t csr;
> + int res;
> +
> + csr = xpcs_regmap_addr_format(dev, reg);
> + res = regmap_read(pxpcs->regmap, csr, &val);
> + if (res < 0)
> + return res;
> +
> + return val & 0xffff;
> +}
> +
> +static int xpcs_regmap_write_reg_direct(struct dw_xpcs_regmap *pxpcs, int dev,
> + int reg, u16 val)
> +{
> + ptrdiff_t csr = xpcs_regmap_addr_format(dev, reg);
> +
> + return regmap_write(pxpcs->regmap, csr, val);
> +}
> +
> +static int xpcs_regmap_read_c22(struct mii_bus *bus, int addr, int reg)
> +{
> + struct dw_xpcs_regmap *pxpcs = bus->priv;
> +
> + if (addr != 0)
> + return -ENODEV;
> +
> + if (pxpcs->reg_indir)
> + return xpcs_regmap_read_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg);
> + else
> + return xpcs_regmap_read_reg_direct(pxpcs, MDIO_MMD_VEND2, reg);
> +}
> +
> +static int xpcs_regmap_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)
> +{
> + struct dw_xpcs_regmap *pxpcs = bus->priv;
> +
> + if (addr != 0)
> + return -ENODEV;
> +
> + if (pxpcs->reg_indir)
> + return xpcs_regmap_write_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg, val);
> + else
> + return xpcs_regmap_write_reg_direct(pxpcs, MDIO_MMD_VEND2, reg, val);
> +}
> +
> +static int xpcs_regmap_read_c45(struct mii_bus *bus, int addr, int dev, int reg)
> +{
> + struct dw_xpcs_regmap *pxpcs = bus->priv;
> +
> + if (addr != 0)
> + return -ENODEV;
> +
> + if (pxpcs->reg_indir)
> + return xpcs_regmap_read_reg_indirect(pxpcs, dev, reg);
> + else
> + return xpcs_regmap_read_reg_direct(pxpcs, dev, reg);
> +}
> +
> +static int xpcs_regmap_write_c45(struct mii_bus *bus, int addr, int dev,
> + int reg, u16 val)
> +{
> + struct dw_xpcs_regmap *pxpcs = bus->priv;
> +
> + if (addr != 0)
> + return -ENODEV;
> +
> + if (pxpcs->reg_indir)
> + return xpcs_regmap_write_reg_indirect(pxpcs, dev, reg, val);
> + else
> + return xpcs_regmap_write_reg_direct(pxpcs, dev, reg, val);
> +}
> +
> +static void devm_xpcs_regmap_destroy(void *data)
> +{
> + struct dw_xpcs *xpcs = data;
> +
> + xpcs_destroy(xpcs);
> +}
> +
> +struct dw_xpcs *devm_xpcs_regmap_register(struct device *dev,
> + const struct xpcs_regmap_config *config)
> +{
> + static atomic_t id = ATOMIC_INIT(-1);
> + struct dw_xpcs_regmap *pxpcs;
> + struct dw_xpcs *xpcs;
> + int ret;
> +
> + pxpcs = devm_kzalloc(dev, sizeof(*pxpcs), GFP_KERNEL);
> + if (!pxpcs)
> + return ERR_PTR(-ENOMEM);
> +
> + pxpcs->dev = dev;
> + pxpcs->regmap = config->regmap;
> + pxpcs->reg_indir = config->reg_indir;
Looking at the overall series, is there any reason for this flag ?
Looks like the reg_indir=false path isn't used at all in this series.
Maybe just drop it and let anyone add it back should the need arise ?
Maxime
^ permalink raw reply
* [PATCH 1/2] KVM: arm64: Replace memslot_is_logging() with kvm_slot_dirty_track_enabled()
From: Wei-Lin Chang @ 2026-06-05 15:32 UTC (permalink / raw)
To: linux-arm-kernel, kvmarm, linux-kernel
Cc: Marc Zyngier, Oliver Upton, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Gavin Shan, Wei-Lin Chang
In-Reply-To: <20260605153248.2412064-1-weilin.chang@arm.com>
When checking whether a memslot has dirty logging enabled, the
KVM_MEM_LOG_DIRTY_PAGES flag is the source of truth. Previously we were
using memslot_is_logging() which only tests dirty bitmap and did not
consider dirty ring. This was not detected because
KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP was introduced together with KVM
arm64 dirty ring, and users need to enable it to ensure dirty
information is not lost for the case of VGIC LPI/ITS table changes.
Fix this by using kvm_slot_dirty_track_enabled() instead which checks
KVM_MEM_LOG_DIRTY_PAGES.
Note that memslot_is_logging() also treats a memslot as not logging if
KVM_MEM_READONLY is set, hence a memslot with both dirty logging and
read only would be seen as not logging for memslot_is_logging(), but
logging for kvm_slot_dirty_track_enabled(). This allows a read only
mapping of size > PAGE_SIZE to be built when memslot_is_logging() is
used, leading to a better read performance compared to
kvm_slot_dirty_track_enabled(). However memslots that have both
KVM_MEM_LOG_DIRTY_PAGES and KVM_MEM_READONLY set do not really make
sense as dirty logging is essentially nop for a read only memslot, so
this shouldn't affect real workloads much.
Fixes: 9cb1096f8590 ("KVM: arm64: Enable ring-based dirty memory tracking")
Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
---
It took me a long investigation to acquire the context needed to
understand this change, however the reason for this problem not being
detected is an educated guess. Please let me know if this is wrong or
if there are other issues, thanks!
arch/arm64/kvm/mmu.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 4da9281312eb..06c46124d3e7 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -161,11 +161,6 @@ static int kvm_mmu_split_huge_pages(struct kvm *kvm, phys_addr_t addr,
return ret;
}
-static bool memslot_is_logging(struct kvm_memory_slot *memslot)
-{
- return memslot->dirty_bitmap && !(memslot->flags & KVM_MEM_READONLY);
-}
-
/**
* kvm_arch_flush_remote_tlbs() - flush all VM TLB entries for v7/8
* @kvm: pointer to kvm structure.
@@ -1748,7 +1743,7 @@ static short kvm_s2_resolve_vma_size(const struct kvm_s2_fault_desc *s2fd,
{
short vma_shift;
- if (memslot_is_logging(s2fd->memslot)) {
+ if (kvm_slot_dirty_track_enabled(s2fd->memslot)) {
s2vi->max_map_size = PAGE_SIZE;
vma_shift = PAGE_SHIFT;
} else {
@@ -1953,7 +1948,7 @@ static int kvm_s2_fault_compute_prot(const struct kvm_s2_fault_desc *s2fd,
*prot = KVM_PGTABLE_PROT_R;
if (s2vi->map_writable && (s2vi->device ||
- !memslot_is_logging(s2fd->memslot) ||
+ !kvm_slot_dirty_track_enabled(s2fd->memslot) ||
kvm_is_write_fault(s2fd->vcpu)))
*prot |= KVM_PGTABLE_PROT_W;
@@ -2084,7 +2079,7 @@ static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd)
* and a write fault needs to collapse a block entry into a table.
*/
memcache = get_mmu_memcache(s2fd->vcpu);
- if (!perm_fault || (memslot_is_logging(s2fd->memslot) &&
+ if (!perm_fault || (kvm_slot_dirty_track_enabled(s2fd->memslot) &&
kvm_is_write_fault(s2fd->vcpu))) {
ret = topup_mmu_memcache(s2fd->vcpu, memcache);
if (ret)
--
2.43.0
^ permalink raw reply related
* [PATCH 2/2] KVM: arm64: Remove superfluous aligning of gfn for dirty logging
From: Wei-Lin Chang @ 2026-06-05 15:32 UTC (permalink / raw)
To: linux-arm-kernel, kvmarm, linux-kernel
Cc: Marc Zyngier, Oliver Upton, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Gavin Shan, Wei-Lin Chang
In-Reply-To: <20260605153248.2412064-1-weilin.chang@arm.com>
Stage-2 mapping size is forced to PAGE_SIZE when dirty logging is
enabled for a memslot, therefore we don't need to align it down to
a possibly larger vma size or THP adjusted size, they won't happen.
Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
---
arch/arm64/kvm/mmu.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 06c46124d3e7..d1f6ff7c2943 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -2050,13 +2050,12 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault_desc *s2fd,
/*
* Mark the page dirty only if the fault is handled successfully,
- * making sure we adjust the canonical IPA if the mapping size has
- * been updated (via a THP upgrade, for example).
+ * mapping size is forced to PAGE_SIZE if dirty logging is enabled,
+ * so we don't have to adjust the canonical IPA here.
*/
if (writable && !ret) {
- phys_addr_t ipa = gfn_to_gpa(get_canonical_gfn(s2fd, s2vi));
- ipa &= ~(mapping_size - 1);
- mark_page_dirty_in_slot(kvm, s2fd->memslot, gpa_to_gfn(ipa));
+ gfn_t canonical_gfn = get_canonical_gfn(s2fd, s2vi);
+ mark_page_dirty_in_slot(kvm, s2fd->memslot, canonical_gfn);
}
if (ret != -EAGAIN)
--
2.43.0
^ permalink raw reply related
* [PATCH 0/2] KVM: arm64: Small dirty logging fixes/cleanups
From: Wei-Lin Chang @ 2026-06-05 15:32 UTC (permalink / raw)
To: linux-arm-kernel, kvmarm, linux-kernel
Cc: Marc Zyngier, Oliver Upton, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Gavin Shan, Wei-Lin Chang
Hi,
These are two minor fixes/cleanups I found when reading the code.
Although the diff are small the first patch has some implications.
Please view the patches for more detail.
Thanks,
Wei-Lin Chang (2):
KVM: arm64: Replace memslot_is_logging() with
kvm_slot_dirty_track_enabled()
KVM: arm64: Remove superfluous aligning of gfn for dirty logging
arch/arm64/kvm/mmu.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
--
2.43.0
^ permalink raw reply
* Re: [PATCH v4 1/3] dt-bindings: dma: fsl-edma: add dma-channel-mask property description
From: Frank Li @ 2026-06-05 15:32 UTC (permalink / raw)
To: Laurentiu Mihalcea
Cc: Joy Zou, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Peng Fan, Ye Li, devicetree, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <cf7b4c03-e1f4-4439-8077-2f8677bb2cea@gmail.com>
On Fri, Jun 05, 2026 at 03:44:23AM -0700, Laurentiu Mihalcea wrote:
>
>
> On 2/11/2026 1:28 AM, Joy Zou wrote:
> > Add documentation for the dma-channel-mask property in the fsl-edma
> > binding. This property uses an inverted bit definition: bit value 0
> > indicates the channel is available, while bit value 1 indicates
> > unavailable.
> >
> > That was already used widely for i.MX8, i.MX9. Correcting the definition
> > will break backward compatibility. This reversal only impacts the eDMA
> > dts node and driver, and doesn't impact DMA consumer. Therefore,
> > keep the inverted definition.
> >
> > Also add a note at the top of the binding to highlight this inverted
> > definition to prevent confusion.
> >
> > Signed-off-by: Joy Zou <joy.zou@nxp.com>
> Hi,
>
> I believe this patch hasn't been picked up yet even though it's been ACK'd by one of the
> DT binding maintainers.
>
> Frank Li, can you please take it into your tree?
I ping vnod in irc yesterday, let wait for few days, if he don't pick, I
will pick it.
Frank
>
>
> Thanks,
> Laurentiu
^ permalink raw reply
* Re: [PATCH v4 5/5] phy: fsl-imx8mq-usb: keep PHY power domain runtime always-on for i.MX8MP
From: Frank Li @ 2026-06-05 15:30 UTC (permalink / raw)
To: Xu Yang
Cc: Vinod Koul, Neil Armstrong, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Jun Li, linux-phy, imx, linux-arm-kernel,
linux-kernel, Xu Yang
In-Reply-To: <20260605-imx8mp-usb-phy-improvement-v4-5-b2ddf2f3862c@nxp.com>
On Fri, Jun 05, 2026 at 07:13:06PM +0800, Xu Yang wrote:
> From: Xu Yang <xu.yang_2@nxp.com>
>
> On i.MX8MP, the USB PHY has a dedicated power domain that was previously
> never powered off at runtime. With the introduction of runtime PM support,
> the power domain will be powered off if the device is runtime suspended,
> which breaks USB wakeup functionality.
Does it need depend on if device enable wakeup?
Frank
>
> To preserve wakeup functionality, mark the PHY power domain as runtime
> always-on for i.MX8MP platform. To limit the behavior to i.MX8MP, add a
> new imx95_usb_phy_ops for i.MX95 and introduce usb_phy_is_imx8mp() helper
> to identify i.MX8MP PHY instance.
>
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
>
> ---
> Changes in v4:
> - no changes
> Changes in v3:
> - new patch
> ---
> drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 18 +++++++++++++++++-
> 1 file changed, 17 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index e24f46d7924b..c8b93ae2035f 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -9,6 +9,7 @@
> #include <linux/of.h>
> #include <linux/phy/phy.h>
> #include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> #include <linux/pm_runtime.h>
> #include <linux/regulator/consumer.h>
> #include <linux/regmap.h>
> @@ -660,13 +661,20 @@ static const struct phy_ops imx8mp_usb_phy_ops = {
> .owner = THIS_MODULE,
> };
>
> +static const struct phy_ops imx95_usb_phy_ops = {
> + .init = imx8mp_usb_phy_init,
> + .power_on = imx8mq_phy_power_on,
> + .power_off = imx8mq_phy_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> static const struct of_device_id imx8mq_usb_phy_of_match[] = {
> {.compatible = "fsl,imx8mq-usb-phy",
> .data = &imx8mq_usb_phy_ops,},
> {.compatible = "fsl,imx8mp-usb-phy",
> .data = &imx8mp_usb_phy_ops,},
> {.compatible = "fsl,imx95-usb-phy",
> - .data = &imx8mp_usb_phy_ops,},
> + .data = &imx95_usb_phy_ops,},
> { }
> };
> MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
> @@ -679,6 +687,11 @@ static const struct regmap_config imx_cr_regmap_config = {
> .max_register = 0x7,
> };
>
> +static bool usb_phy_is_imx8mp(const void *data)
> +{
> + return data == &imx8mp_usb_phy_ops;
> +}
> +
> static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> {
> struct phy_provider *phy_provider;
> @@ -723,6 +736,9 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> if (!phy_ops)
> return -EINVAL;
>
> + if (usb_phy_is_imx8mp(phy_ops))
> + dev_pm_genpd_rpm_always_on(dev, true);
> +
> imx_phy->phy = devm_phy_create(dev, NULL, phy_ops);
> if (IS_ERR(imx_phy->phy))
> return PTR_ERR(imx_phy->phy);
>
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH bpf-next] bpf: Replace scratch PTE atomically when allocating arena pages
From: patchwork-bot+netdevbpf @ 2026-06-05 15:30 UTC (permalink / raw)
To: Tejun Heo
Cc: void, arighi, changwoo, ast, andrii, daniel, martin.lau, memxor,
peterz, catalin.marinas, will, tglx, mingo, bp, dave.hansen, akpm,
david, rppt, emil, sched-ext, bpf, x86, linux-arm-kernel,
linux-mm, linux-kernel
In-Reply-To: <20260601183728.1800490-1-tj@kernel.org>
Hello:
This patch was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Mon, 1 Jun 2026 08:37:28 -1000 you wrote:
> apply_range_set_cb() maps the pages for a new arena allocation and returned
> -EBUSY when the target PTE was already populated. Kernel-fault recovery
> leaves the per-arena scratch page in unallocated arena PTEs, so a later
> bpf_arena_alloc_pages() over such a page hits that -EBUSY, and every
> subsequent allocation of it fails the same way. Allocation must install the
> real page over scratch instead.
>
> [...]
Here is the summary with links:
- [bpf-next] bpf: Replace scratch PTE atomically when allocating arena pages
https://git.kernel.org/bpf/bpf-next/c/f64c723741c9
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v4 4/5] phy: fsl-imx8mq-usb: add control register regmap
From: Frank Li @ 2026-06-05 15:28 UTC (permalink / raw)
To: Xu Yang
Cc: Vinod Koul, Neil Armstrong, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Jun Li, linux-phy, imx, linux-arm-kernel,
linux-kernel, Xu Yang
In-Reply-To: <20260605-imx8mp-usb-phy-improvement-v4-4-b2ddf2f3862c@nxp.com>
On Fri, Jun 05, 2026 at 07:13:05PM +0800, Xu Yang wrote:
> From: Xu Yang <xu.yang_2@nxp.com>
>
> The CR port is a simple 16-bit data/address parallel port that is
> accessed through 32-bit MMIO registers for on-chip access to the
> control registers inside the USB 3.0 femtoPHY. Add control register
> regmap and export these registers by debugfs to help PHY's diagnostic.
>
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> ---
> Changes in v4:
> - improve commit message as Haibo's suggestion
> Changes in v3:
> - drop Frank's tag because it includes other changes
> - new patch
> ---
> drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 27 ++++++++++++++++++++++++++-
> 1 file changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index 27aa696f5dd4..e24f46d7924b 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -1,5 +1,5 @@
> // SPDX-License-Identifier: GPL-2.0+
> -/* Copyright (c) 2017 NXP. */
> +/* Copyright 2017-2026 NXP. */
>
> #include <linux/bitfield.h>
> #include <linux/clk.h>
> @@ -11,6 +11,7 @@
> #include <linux/platform_device.h>
> #include <linux/pm_runtime.h>
> #include <linux/regulator/consumer.h>
> +#include <linux/regmap.h>
> #include <linux/usb/typec_mux.h>
>
> #define PHY_CTRL0 0x0
> @@ -56,6 +57,8 @@
> #define PHY_CTRL6_ALT_CLK_EN BIT(1)
> #define PHY_CTRL6_ALT_CLK_SEL BIT(0)
>
> +#define PHY_CRCTL 0x30
> +
> #define PHY_TUNE_DEFAULT 0xffffffff
>
> #define TCA_CLK_RST 0x00
> @@ -119,6 +122,7 @@ struct imx8mq_usb_phy {
> void __iomem *base;
> struct regulator *vbus;
> struct tca_blk *tca;
> + struct regmap *cr_regmap;
> u32 pcs_tx_swing_full;
> u32 pcs_tx_deemph_3p5db;
> u32 tx_vref_tune;
> @@ -667,6 +671,14 @@ static const struct of_device_id imx8mq_usb_phy_of_match[] = {
> };
> MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
>
> +static const struct regmap_config imx_cr_regmap_config = {
> + .name = "cr",
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x7,
> +};
> +
> static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> {
> struct phy_provider *phy_provider;
> @@ -696,6 +708,13 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> if (IS_ERR(imx_phy->base))
> return PTR_ERR(imx_phy->base);
>
> + imx_phy->cr_regmap = devm_regmap_init_mmio(dev, imx_phy->base + PHY_CRCTL,
> + &imx_cr_regmap_config);
> + if (IS_ERR(imx_phy->cr_regmap)) {
> + dev_warn(dev, "Fail to init debug register regmap\n");
> + imx_phy->cr_regmap = NULL;
> + }
> +
> ret = devm_pm_runtime_set_active_enabled(dev);
> if (ret)
> return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
> @@ -731,6 +750,9 @@ static int imx8mq_usb_phy_runtime_suspend(struct device *dev)
> {
> struct imx8mq_usb_phy *imx_phy = dev_get_drvdata(dev);
>
> + if (imx_phy->cr_regmap)
> + regcache_cache_only(imx_phy->cr_regmap, true);
> +
I think this common problem, is possible to change
regmap_read_debugfs(), let it call runtime_pm_get(), there are already
have runtime_pm in regmap field.
So you debug fs always to get update value, instead cached value?
Frank
> clk_disable_unprepare(imx_phy->alt_clk);
> clk_disable_unprepare(imx_phy->clk);
>
> @@ -752,6 +774,9 @@ static int imx8mq_usb_phy_runtime_resume(struct device *dev)
> return ret;
> }
>
> + if (imx_phy->cr_regmap)
> + regcache_cache_only(imx_phy->cr_regmap, false);
> +
> return 0;
> }
>
>
> --
> 2.34.1
>
^ permalink raw reply
* [GIT PULL] ARM: mvebu: arm for v7.2 (#1)
From: Gregory CLEMENT @ 2026-06-05 15:27 UTC (permalink / raw)
To: Arnd Bergmann, arm, soc
Cc: Andrew Lunn, Sebastian Hesselbarth, linux-arm-kernel
Hi,
Here is the first pull request for arm for mvebu for v7.2.
Gregory
The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git tags/mvebu-arm-7.2-1
for you to fetch changes up to bf4ad3be0679460585ab17dbcf298d085cf23429:
ARM: orion5x: update board check in mss2_pci_init() to use the DT (2026-06-01 10:26:30 +0200)
----------------------------------------------------------------
mvebu arm for 7.2 (part 1)
Orion5x: Replace machine_is_mss2() with of_machine_is_compatible() in mss2_pci_init()
mvebu_v5_defconfig: Remove stale MACH_LINKSTATION_LSCHL reference
Armada 370: Simplify of_node_put calls and drop redundant NULL checks
----------------------------------------------------------------
Ethan Nelson-Moore (2):
arm: mvebu_v5_defconfig: remove stale MACH_LINKSTATION_LSCHL reference
ARM: orion5x: update board check in mss2_pci_init() to use the DT
Martin Kaiser (2):
ARM: mvebu: drop unnecessary NULL check
ARM: mvebu: simplify of_node_put calls
arch/arm/configs/mvebu_v5_defconfig | 1 -
arch/arm/mach-mvebu/coherency.c | 9 ++-------
arch/arm/mach-orion5x/board-mss2.c | 4 ++--
3 files changed, 4 insertions(+), 10 deletions(-)
^ permalink raw reply
* [GIT PULL] ARM: mvebu: dt64 for v7.2 (#1)
From: Gregory CLEMENT @ 2026-06-05 15:20 UTC (permalink / raw)
To: Arnd Bergmann, arm, soc
Cc: Andrew Lunn, Sebastian Hesselbarth, linux-arm-kernel
Hi,
Here is the first pull request for dt64 for mvebu for v7.2.
Gregory
The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git tags/mvebu-dt64-7.2-1
for you to fetch changes up to 5dd98e0389545b302b0c46cef2264b5b09c01677:
arm64: dts: marvell: armada-37xx: mark EIP97 as dma-coherent (2026-06-01 10:04:36 +0200)
----------------------------------------------------------------
mvebu dt64 for 7.2 (part 1)
Mark EIP97 as dma-coherent for Armada 3720
----------------------------------------------------------------
Aleksander Jan Bajkowski (1):
arm64: dts: marvell: armada-37xx: mark EIP97 as dma-coherent
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 1 +
1 file changed, 1 insertion(+)
^ permalink raw reply
* Re: [PATCH v4 3/5] phy: fsl-imx8mq-usb: add runtime PM support
From: Frank Li @ 2026-06-05 15:14 UTC (permalink / raw)
To: Xu Yang
Cc: Vinod Koul, Neil Armstrong, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Jun Li, linux-phy, imx, linux-arm-kernel,
linux-kernel, Xu Yang
In-Reply-To: <20260605-imx8mp-usb-phy-improvement-v4-3-b2ddf2f3862c@nxp.com>
On Fri, Jun 05, 2026 at 07:13:04PM +0800, Xu Yang wrote:
> From: Xu Yang <xu.yang_2@nxp.com>
>
> Add runtime PM to ensure the PHY is properly powered and clocked during
> register access, preventing potential system hangs.
>
> It guards register access in the following scenarios:
> - PHY operations: init() and power_on/off() callbacks are guarded by
> phy core
> - Type-C orientation switching when PHY/Controller are suspended which
> needs explicitly care
> - Future PHY control port register regmap debugfs access
>
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
>
> ---
> Changes in v4:
> - replace guard() with PM_RUNTIME_ACQUIRE()
> Changes in v3:
> - new patch
> ---
> drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 62 +++++++++++++++++++++---------
> 1 file changed, 43 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index 591ddf346061..27aa696f5dd4 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -9,6 +9,7 @@
> #include <linux/of.h>
> #include <linux/phy/phy.h>
> #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> #include <linux/regulator/consumer.h>
> #include <linux/usb/typec_mux.h>
>
> @@ -136,17 +137,15 @@ static int tca_blk_typec_switch_set(struct typec_switch_dev *sw,
> {
> struct imx8mq_usb_phy *imx_phy = typec_switch_get_drvdata(sw);
> struct tca_blk *tca = imx_phy->tca;
> - int ret;
>
> if (tca->orientation == orientation)
> return 0;
>
> - ret = clk_prepare_enable(imx_phy->clk);
> - if (ret)
> - return ret;
> + PM_RUNTIME_ACQUIRE(&imx_phy->phy->dev, pm);
> + if (PM_RUNTIME_ACQUIRE_ERR(&pm))
> + return -ENXIO;
>
> tca_blk_orientation_set(tca, orientation);
> - clk_disable_unprepare(imx_phy->clk);
>
> return 0;
> }
> @@ -620,16 +619,6 @@ static int imx8mq_phy_power_on(struct phy *phy)
> if (ret)
> return ret;
>
> - ret = clk_prepare_enable(imx_phy->clk);
> - if (ret)
> - return ret;
> -
> - ret = clk_prepare_enable(imx_phy->alt_clk);
> - if (ret) {
> - clk_disable_unprepare(imx_phy->clk);
> - return ret;
> - }
> -
> /* Disable rx term override */
> value = readl(imx_phy->base + PHY_CTRL6);
> value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> @@ -648,8 +637,6 @@ static int imx8mq_phy_power_off(struct phy *phy)
> value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
> writel(value, imx_phy->base + PHY_CTRL6);
>
> - clk_disable_unprepare(imx_phy->alt_clk);
> - clk_disable_unprepare(imx_phy->clk);
> regulator_disable(imx_phy->vbus);
>
> return 0;
> @@ -686,6 +673,7 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> struct device *dev = &pdev->dev;
> struct imx8mq_usb_phy *imx_phy;
> const struct phy_ops *phy_ops;
> + int ret;
>
> imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL);
> if (!imx_phy)
> @@ -693,13 +681,13 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
>
> platform_set_drvdata(pdev, imx_phy);
>
> - imx_phy->clk = devm_clk_get(dev, "phy");
> + imx_phy->clk = devm_clk_get_enabled(dev, "phy");
> if (IS_ERR(imx_phy->clk)) {
> dev_err(dev, "failed to get imx8mq usb phy clock\n");
> return PTR_ERR(imx_phy->clk);
> }
>
> - imx_phy->alt_clk = devm_clk_get_optional(dev, "alt");
> + imx_phy->alt_clk = devm_clk_get_optional_enabled(dev, "alt");
when driver remove, devm will disable clock, which may cause refcound
wrong if device already suspend by runtime pm
> if (IS_ERR(imx_phy->alt_clk))
> return dev_err_probe(dev, PTR_ERR(imx_phy->alt_clk),
> "Failed to get alt clk\n");
> @@ -708,6 +696,10 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> if (IS_ERR(imx_phy->base))
> return PTR_ERR(imx_phy->base);
>
> + ret = devm_pm_runtime_set_active_enabled(dev);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
> +
You have not set auto suspend, so runtime_suspend will never entry.
Frank
> phy_ops = of_device_get_match_data(dev);
> if (!phy_ops)
> return -EINVAL;
> @@ -735,11 +727,43 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> return PTR_ERR_OR_ZERO(phy_provider);
> }
>
> +static int imx8mq_usb_phy_runtime_suspend(struct device *dev)
> +{
> + struct imx8mq_usb_phy *imx_phy = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(imx_phy->alt_clk);
> + clk_disable_unprepare(imx_phy->clk);
> +
> + return 0;
> +}
> +
> +static int imx8mq_usb_phy_runtime_resume(struct device *dev)
> +{
> + struct imx8mq_usb_phy *imx_phy = dev_get_drvdata(dev);
> + int ret;
> +
> + ret = clk_prepare_enable(imx_phy->clk);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(imx_phy->alt_clk);
> + if (ret) {
> + clk_disable_unprepare(imx_phy->clk);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static DEFINE_RUNTIME_DEV_PM_OPS(imx8mq_usb_phy_pm_ops, imx8mq_usb_phy_runtime_suspend,
> + imx8mq_usb_phy_runtime_resume, NULL);
> +
> static struct platform_driver imx8mq_usb_phy_driver = {
> .probe = imx8mq_usb_phy_probe,
> .driver = {
> .name = "imx8mq-usb-phy",
> .of_match_table = imx8mq_usb_phy_of_match,
> + .pm = pm_ptr(&imx8mq_usb_phy_pm_ops),
> .suppress_bind_attrs = true,
> }
> };
>
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: remoteproc: imx_rproc: document optional "memory-region-names"
From: Frank Li @ 2026-06-05 15:11 UTC (permalink / raw)
To: Laurentiu Mihalcea
Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer, Peng Fan,
Fabio Estevam, Daniel Baluta, Francesco Dolcini, linux-remoteproc,
devicetree, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20260605113621.1479-2-laurentiumihalcea111@gmail.com>
On Fri, Jun 05, 2026 at 04:36:18AM -0700, Laurentiu Mihalcea wrote:
> From: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
>
> The names of the carveout regions are derived using the names of the
> reserved memory devicetree nodes, which are referenced using the
> "memory-region" property. This adds a restriction on the names of said
> devicetree nodes, often bearing specific names such as: "vdevbuffer",
> "vdev0vring0", "rsc-table", etc... This goes against the devicetree
> specification's recommendation, which states that the devicetree node
> names should be generic.
Addition notes for dt reviever:
binding check can't restrict memory node naming because no specific
compatible string for it. So there are hidden ABI by node name here.
use memory-region-name can eliminate such hidden ABI.
>
> Fix this by documenting an additional, optional property:
> "memory-region-names". This way, the carveout names can use the values
> passed via "memory-region-names", while keeping the devicetree node
> names of the reserved memory regions generic.
>
> There are no restrictions imposed on the values of the strings passed via
> the new property since the software allows any name to be used, with some
> names (e.g. "vdev%dbuffer", "vdev%dvring%d", "rsc-table") bearing a
> special meaning.
>
> Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> .../devicetree/bindings/remoteproc/fsl,imx-rproc.yaml | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> index c18f71b64889..8e3e6676a95e 100644
> --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> @@ -62,6 +62,10 @@ properties:
> minItems: 1
> maxItems: 32
>
> + memory-region-names:
> + minItems: 1
> + maxItems: 32
> +
> power-domains:
> minItems: 2
> maxItems: 8
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v2] phy: freescale: phy-fsl-imx8qm-lvds-phy: Fix missing pm_runtime_disable() on probe error path
From: Frank Li @ 2026-06-05 15:04 UTC (permalink / raw)
To: Felix Gu
Cc: Vinod Koul, Neil Armstrong, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Liu Ying, linux-phy, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260605-lvds-v2-1-3ce7539d1104@gmail.com>
On Fri, Jun 05, 2026 at 07:57:20PM +0800, Felix Gu wrote:
> If mixel_lvds_phy_reset() fails in probe after pm_runtime_enable(),
> the function returns directly without calling pm_runtime_disable(),
> leaving runtime PM permanently enabled for the device.
>
> Fix this by using devm_pm_runtime_enable() so that cleanup is
> automatic on any probe failure or driver unbind. This also allows
> removing the manual err label and the .remove callback.
>
> Fixes: 06ff622d61d2 ("phy: freescale: Add i.MX8qm Mixel LVDS PHY support")
> Acked-by: Liu Ying <victor.liu@nxp.com>
> Signed-off-by: Felix Gu <ustc.gu@gmail.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes in v2:
> - Change the patch's subject prefix requested by Liu Ying.
> - Add Liu Ying's Acked-by.
> - Link to v1: https://patch.msgid.link/20260604-lvds-v1-1-b8e1ff1bdee7@gmail.com
>
> To: Vinod Koul <vkoul@kernel.org>
> To: Neil Armstrong <neil.armstrong@linaro.org>
> To: Frank Li <Frank.Li@nxp.com>
> To: Sascha Hauer <s.hauer@pengutronix.de>
> To: Pengutronix Kernel Team <kernel@pengutronix.de>
> To: Fabio Estevam <festevam@gmail.com>
> To: Liu Ying <victor.liu@nxp.com>
> Cc: linux-phy@lists.infradead.org
> Cc: imx@lists.linux.dev
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> ---
> drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c | 24 +++++++-----------------
> 1 file changed, 7 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
> index ece357443521..c662f91e598c 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
> @@ -345,7 +345,9 @@ static int mixel_lvds_phy_probe(struct platform_device *pdev)
>
> dev_set_drvdata(dev, priv);
>
> - pm_runtime_enable(dev);
> + ret = devm_pm_runtime_enable(dev);
> + if (ret)
> + return ret;
>
> ret = mixel_lvds_phy_reset(dev);
> if (ret) {
> @@ -355,17 +357,15 @@ static int mixel_lvds_phy_probe(struct platform_device *pdev)
>
> for (i = 0; i < PHY_NUM; i++) {
> lvds_phy = devm_kzalloc(dev, sizeof(*lvds_phy), GFP_KERNEL);
> - if (!lvds_phy) {
> - ret = -ENOMEM;
> - goto err;
> - }
> + if (!lvds_phy)
> + return -ENOMEM;
>
> phy = devm_phy_create(dev, NULL, &mixel_lvds_phy_ops);
> if (IS_ERR(phy)) {
> ret = PTR_ERR(phy);
> dev_err(dev, "failed to create PHY for channel%d: %d\n",
> i, ret);
> - goto err;
> + return ret;
> }
>
> lvds_phy->phy = phy;
> @@ -379,19 +379,10 @@ static int mixel_lvds_phy_probe(struct platform_device *pdev)
> if (IS_ERR(phy_provider)) {
> ret = PTR_ERR(phy_provider);
> dev_err(dev, "failed to register PHY provider: %d\n", ret);
> - goto err;
> + return ret;
> }
>
> return 0;
> -err:
> - pm_runtime_disable(dev);
> -
> - return ret;
> -}
> -
> -static void mixel_lvds_phy_remove(struct platform_device *pdev)
> -{
> - pm_runtime_disable(&pdev->dev);
> }
>
> static int __maybe_unused mixel_lvds_phy_runtime_suspend(struct device *dev)
> @@ -432,7 +423,6 @@ MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match);
>
> static struct platform_driver mixel_lvds_phy_driver = {
> .probe = mixel_lvds_phy_probe,
> - .remove = mixel_lvds_phy_remove,
> .driver = {
> .pm = &mixel_lvds_phy_pm_ops,
> .name = "mixel-lvds-phy",
>
> ---
> base-commit: a225caacc36546a09586e3ece36c0313146e7da9
> change-id: 20260604-lvds-d67cb619df17
>
> Best regards,
> --
> Felix Gu <ustc.gu@gmail.com>
>
^ permalink raw reply
* Re: [PATCH v14 23/44] arm64: RMI: Handle RMI_EXIT_RIPAS_CHANGE
From: Steven Price @ 2026-06-05 15:02 UTC (permalink / raw)
To: Aneesh Kumar K.V, kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Gavin Shan,
Shanker Donthineni, Alper Gun, Emi Kisanuki, Vishal Annapurve,
WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <yq5ay0hfspok.fsf@kernel.org>
On 19/05/2026 10:40, Aneesh Kumar K.V wrote:
> Steven Price <steven.price@arm.com> writes:
>
> ...
>
>> +void kvm_realm_unmap_range(struct kvm *kvm, unsigned long start,
>> + unsigned long size, bool unmap_private,
>> + bool may_block)
>> +{
>> + unsigned long end = start + size;
>> + struct realm *realm = &kvm->arch.realm;
>> +
>> + if (!kvm_realm_is_created(kvm))
>> + return;
>> +
>> + end = min(BIT(realm->ia_bits - 1), end);
>> +
>> + realm_unmap_shared_range(kvm, start, end, may_block);
>> + if (unmap_private)
>> + realm_unmap_private_range(kvm, start, end, may_block);
>> +}
>> +
>
> kvm_gmem_invalidate_begin() indicates a private-only invalidation. How
> is that supported?
Because we treat the private and shared spaces are aliasing we don't
really support a "private-only" invalidation. So the shared space will
be invalidated as well. Something has gone wrong if we've ended up with
the 'same' IPA being used in both the private and shared spaces.
Private has to be treated slightly specially because removing a private
mapping is observable by the guest (the page can't be reinserted without
the guest agreeing and the contents being wiped). For shared mappings
the page can simply be refaulted.
That said, I'll look into Wei-Lin's suggestion to use
kvm_gfn_range_filter which would allow all three combinations of
private-only, shared-only and private+shared.
Thanks,
Steve
^ permalink raw reply
* Re: [PATCH v14 22/44] arm64: RMI: Handle realm enter/exit
From: Steven Price @ 2026-06-05 15:02 UTC (permalink / raw)
To: Gavin Shan, kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Shanker Donthineni,
Alper Gun, Aneesh Kumar K . V, Emi Kisanuki, Vishal Annapurve,
WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <e6cb82fc-a8be-49d3-8fa3-0107c8ab97f7@redhat.com>
On 28/05/2026 05:38, Gavin Shan wrote:
> Hi Steve,
>
> On 5/13/26 11:17 PM, Steven Price wrote:
>> Entering a realm is done using a SMC call to the RMM. On exit the
>> exit-codes need to be handled slightly differently to the normal KVM
>> path so define our own functions for realm enter/exit and hook them
>> in if the guest is a realm guest.
>>
>> Signed-off-by: Steven Price <steven.price@arm.com>
>> Reviewed-by: Gavin Shan <gshan@redhat.com>
>> ---
>> Chanegs since v13:
>> * The RMM is now required to provide an ESR value with the correct
>> information to emulate MMIO, so we no longer need to hardcode 0s in
>> rec_exit_sys_reg().
>> * The PSCI changes mean that there is a potential race when turning on
>> a VCPU which can cause a RMI_ERROR_REC return. Exit to user space
>> with -EAGAIN in this case.
>> Changes since v12:
>> * Call guest_state_{enter,exit}_irqoff() around rmi_rec_enter().
>> * Add handling of the IRQ exception case where IRQs need to be briefly
>> enabled before exiting guest timing.
>> Changes since v8:
>> * Introduce kvm_rec_pre_enter() called before entering an atomic
>> section to handle operations that might require memory allocation
>> (specifically completing a RIPAS change introduced in a later patch).
>> * Updates to align with upstream changes to hpfar_el2 which now
>> (ab)uses
>> HPFAR_EL2_NS as a valid flag.
>> * Fix exit reason when racing with PSCI shutdown to return
>> KVM_EXIT_SHUTDOWN rather than KVM_EXIT_UNKNOWN.
>> Changes since v7:
>> * A return of 0 from kvm_handle_sys_reg() doesn't mean the register has
>> been read (although that can never happen in the current code). Tidy
>> up the condition to handle any future refactoring.
>> Changes since v6:
>> * Use vcpu_err() rather than pr_err/kvm_err when there is an associated
>> vcpu to the error.
>> * Return -EFAULT for KVM_EXIT_MEMORY_FAULT as per the documentation for
>> this exit type.
>> * Split code handling a RIPAS change triggered by the guest to the
>> following patch.
>> Changes since v5:
>> * For a RIPAS_CHANGE request from the guest perform the actual RIPAS
>> change on next entry rather than immediately on the exit. This allows
>> the VMM to 'reject' a RIPAS change by refusing to continue
>> scheduling.
>> Changes since v4:
>> * Rename handle_rme_exit() to handle_rec_exit()
>> * Move the loop to copy registers into the REC enter structure from the
>> to rec_exit_handlers callbacks to kvm_rec_enter(). This fixes a bug
>> where the handler exits to user space and user space wants to modify
>> the GPRS.
>> * Some code rearrangement in rec_exit_ripas_change().
>> Changes since v2:
>> * realm_set_ipa_state() now provides an output parameter for the
>> top_iap that was changed. Use this to signal the VMM with the correct
>> range that has been transitioned.
>> * Adapt to previous patch changes.
>> ---
>> arch/arm64/include/asm/kvm_rmi.h | 4 +
>> arch/arm64/kvm/Makefile | 2 +-
>> arch/arm64/kvm/arm.c | 26 ++++-
>> arch/arm64/kvm/rmi-exit.c | 186 +++++++++++++++++++++++++++++++
>> arch/arm64/kvm/rmi.c | 42 +++++++
>> 5 files changed, 254 insertions(+), 6 deletions(-)
>> create mode 100644 arch/arm64/kvm/rmi-exit.c
>>
>> diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/
>> asm/kvm_rmi.h
>> index d99bf4fc3c39..feb534a6678e 100644
>> --- a/arch/arm64/include/asm/kvm_rmi.h
>> +++ b/arch/arm64/include/asm/kvm_rmi.h
>> @@ -84,6 +84,10 @@ void kvm_destroy_realm(struct kvm *kvm);
>> void kvm_realm_destroy_rtts(struct kvm *kvm);
>> void kvm_destroy_rec(struct kvm_vcpu *vcpu);
>> +int kvm_rec_enter(struct kvm_vcpu *vcpu);
>> +int kvm_rec_pre_enter(struct kvm_vcpu *vcpu);
>> +int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_status);
>> +
>> static inline bool kvm_realm_is_private_address(struct realm *realm,
>> unsigned long addr)
>> {
>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>> index ed3cf30eb06e..4a2d52fdb6a2 100644
>> --- a/arch/arm64/kvm/Makefile
>> +++ b/arch/arm64/kvm/Makefile
>> @@ -16,7 +16,7 @@ CFLAGS_handle_exit.o += -Wno-override-init
>> kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
>> inject_fault.o va_layout.o handle_exit.o config.o \
>> guest.o debug.o reset.o sys_regs.o stacktrace.o \
>> - vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o \
>> + vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o rmi-exit.o \
>> arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \
>> vgic/vgic.o vgic/vgic-init.o \
>> vgic/vgic-irqfd.o vgic/vgic-v2.o \
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 21d9dfdb1ea0..ed88a203b892 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -1331,6 +1331,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
>> if (ret > 0)
>> ret = check_vcpu_requests(vcpu);
>> + if (ret > 0 && vcpu_is_rec(vcpu))
>> + ret = kvm_rec_pre_enter(vcpu);
>> +
>> /*
>> * Preparing the interrupts to be injected also
>> * involves poking the GIC, which must be done in a
>> @@ -1378,7 +1381,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
>> trace_kvm_entry(*vcpu_pc(vcpu));
>> guest_timing_enter_irqoff();
>> - ret = kvm_arm_vcpu_enter_exit(vcpu);
>> + if (vcpu_is_rec(vcpu))
>> + ret = kvm_rec_enter(vcpu);
>> + else
>> + ret = kvm_arm_vcpu_enter_exit(vcpu);
>> vcpu->mode = OUTSIDE_GUEST_MODE;
>> vcpu->stat.exits++;
>> @@ -1424,7 +1430,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
>> * context synchronization event) is necessary to ensure that
>> * pending interrupts are taken.
>> */
>> - if (ARM_EXCEPTION_CODE(ret) == ARM_EXCEPTION_IRQ) {
>> + if (ARM_EXCEPTION_CODE(ret) == ARM_EXCEPTION_IRQ ||
>> + (vcpu_is_rec(vcpu) &&
>> + vcpu->arch.rec.run->exit.exit_reason == RMI_EXIT_IRQ)) {
>> local_irq_enable();
>> isb();
>> local_irq_disable();
>
> The condition could be posssibly imprecise because ARM_EXCEPTION_CODE(ret)
> can be ARM_EXCEPTION_IRQ even for a REC. So the precise condition would be:
>
> if ((!vcpu_is_rec(vcpu) && ARM_EXCEPTION_CODE(ret) ==
> ARM_EXCEPTION_IRQ) ||
> (vcpu_is_rec(vcpu) && vcpu->arch.rec.run->exit.exit_reason
> == RMI_EXIT_IRQ)) {
Good point - I guess this wouldn't have shown up in testing because
there's no harm (other than performance) in the ISB.
>> @@ -1436,8 +1444,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
>> trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu),
>> *vcpu_pc(vcpu));
>> - /* Exit types that need handling before we can be preempted */
>> - handle_exit_early(vcpu, ret);
>> + if (!vcpu_is_rec(vcpu)) {
>> + /*
>> + * Exit types that need handling before we can be
>> + * preempted
>> + */
>> + handle_exit_early(vcpu, ret);
>> + }
>> kvm_nested_sync_hwstate(vcpu);
>> @@ -1462,7 +1475,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu
>> *vcpu)
>> ret = ARM_EXCEPTION_IL;
>> }
>> - ret = handle_exit(vcpu, ret);
>> + if (vcpu_is_rec(vcpu))
>> + ret = handle_rec_exit(vcpu, ret);
>> + else
>> + ret = handle_exit(vcpu, ret);
>> }
>> /* Tell userspace about in-kernel device output levels */
>> diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c
>> new file mode 100644
>> index 000000000000..e7c51b6cf6ce
>> --- /dev/null
>> +++ b/arch/arm64/kvm/rmi-exit.c
>> @@ -0,0 +1,186 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (C) 2023 ARM Ltd.
>> + */
>> +
>> +#include <linux/kvm_host.h>
>> +#include <kvm/arm_hypercalls.h>
>> +#include <kvm/arm_psci.h>
>> +
>> +#include <asm/rmi_smc.h>
>> +#include <asm/kvm_emulate.h>
>> +#include <asm/kvm_rmi.h>
>> +#include <asm/kvm_mmu.h>
>> +
>> +typedef int (*exit_handler_fn)(struct kvm_vcpu *vcpu);
>> +
>> +static int rec_exit_reason_notimpl(struct kvm_vcpu *vcpu)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> +
>> + vcpu_err(vcpu, "Unhandled exit reason from realm (ESR: %#llx)\n",
>> + rec->run->exit.esr);
>> + return -ENXIO;
>> +}
>> +
>
> s/rec->run->exit.esr/kvm_vcpu_get_esr(vcpu), rec->run->exit.esr has been
> copied to the storage space pointed by kvm_vcpu_get_esr() in its caller.
Ack
>> +static int rec_exit_sync_dabt(struct kvm_vcpu *vcpu)
>> +{
>> + return kvm_handle_guest_abort(vcpu);
>> +}
>> +
>> +static int rec_exit_sync_iabt(struct kvm_vcpu *vcpu)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> +
>> + vcpu_err(vcpu, "Unhandled instruction abort (ESR: %#llx).\n",
>> + rec->run->exit.esr);
>> + return -ENXIO;
>> +}
>> +
>
> s/rec->run->exit.esr/kvm_vcpu_get_esr(vcpu)
Ack
>> +static int rec_exit_sys_reg(struct kvm_vcpu *vcpu)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> + unsigned long esr = kvm_vcpu_get_esr(vcpu);
>> + int rt = kvm_vcpu_sys_get_rt(vcpu);
>> + bool is_write = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) ==
>> ESR_ELx_SYS64_ISS_DIR_WRITE;
>> + int ret;
>> +
>> + if (is_write)
>> + vcpu_set_reg(vcpu, rt, rec->run->exit.gprs[rt]);
>> +
>> + ret = kvm_handle_sys_reg(vcpu);
>> + if (!is_write)
>> + rec->run->enter.gprs[rt] = vcpu_get_reg(vcpu, rt);
>> +
>> + return ret;
>> +}
>> +
>> +static exit_handler_fn rec_exit_handlers[] = {
>> + [0 ... ESR_ELx_EC_MAX] = rec_exit_reason_notimpl,
>> + [ESR_ELx_EC_SYS64] = rec_exit_sys_reg,
>> + [ESR_ELx_EC_DABT_LOW] = rec_exit_sync_dabt,
>> + [ESR_ELx_EC_IABT_LOW] = rec_exit_sync_iabt
>> +};
>> +
>> +static int rec_exit_psci(struct kvm_vcpu *vcpu)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> + int i;
>> +
>> + for (i = 0; i < REC_RUN_GPRS; i++)
>> + vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]);
>> +
>> + return kvm_smccc_call_handler(vcpu);
>> +}
>> +
>> +static int rec_exit_ripas_change(struct kvm_vcpu *vcpu)
>> +{
>> + struct kvm *kvm = vcpu->kvm;
>> + struct realm *realm = &kvm->arch.realm;
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> + unsigned long base = rec->run->exit.ripas_base;
>> + unsigned long top = rec->run->exit.ripas_top;
>> + unsigned long ripas = rec->run->exit.ripas_value;
>> +
>> + if (!kvm_realm_is_private_address(realm, base) ||
>> + !kvm_realm_is_private_address(realm, top - 1)) {
>> + vcpu_err(vcpu, "Invalid RIPAS_CHANGE for %#lx - %#lx, ripas:
>> %#lx\n",
>> + base, top, ripas);
>> + /* Set RMI_REJECT bit */
>> + rec->run->enter.flags = REC_ENTER_FLAG_RIPAS_RESPONSE;
>> + return -EINVAL;
>> + }
>
> I doubt if the flag (REC_ENTER_FLAG_RIPAS_RESPONSE) will be handed over
> to RMM
> since the negative return value forces we're exiting to VMM like QEMU where
> how this problematic case can be handled is TBD.
It's perhaps a bit non-obvious but enter.flags is cleared on the exit.
So even if we return to the VMM the flags will be kept for the next entry.
I agree it is somewhat TBD exactly how this case should be handled -
there's a bunch of "VM did something stupid" cases like this that are a
bit problematic.
Thanks,
Steve
>> +
>> + /* Exit to VMM, the actual RIPAS change is done on next entry */
>> + kvm_prepare_memory_fault_exit(vcpu, base, top - base, false, false,
>> + ripas == RMI_RAM);
>> +
>> + /*
>> + * KVM_EXIT_MEMORY_FAULT requires an return code of -EFAULT, see the
>> + * API documentation
>> + */
>> + return -EFAULT;
>> +}
>> +
>> +static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> +
>> + __vcpu_assign_sys_reg(vcpu, CNTV_CTL_EL0, rec->run->exit.cntv_ctl);
>> + __vcpu_assign_sys_reg(vcpu, CNTV_CVAL_EL0, rec->run-
>> >exit.cntv_cval);
>> + __vcpu_assign_sys_reg(vcpu, CNTP_CTL_EL0, rec->run->exit.cntp_ctl);
>> + __vcpu_assign_sys_reg(vcpu, CNTP_CVAL_EL0, rec->run-
>> >exit.cntp_cval);
>> +
>> + kvm_realm_timers_update(vcpu);
>> +}
>> +
>> +/*
>> + * Return > 0 to return to guest, < 0 on error, 0 (and set
>> exit_reason) on
>> + * proper exit to userspace.
>> + */
>> +int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> + u8 esr_ec = ESR_ELx_EC(rec->run->exit.esr);
>> + unsigned long status, index;
>> +
>> + status = RMI_RETURN_STATUS(rec_run_ret);
>> + index = RMI_RETURN_INDEX(rec_run_ret);
>> +
>> + /*
>> + * If a PSCI_SYSTEM_OFF request raced with a vcpu executing, we
>> might
>> + * see the following status code and index indicating an attempt
>> to run
>> + * a REC when the RD state is SYSTEM_OFF. In this case, we just
>> need to
>> + * return to user space which can deal with the system event or
>> will try
>> + * to run the KVM VCPU again, at which point we will no longer
>> attempt
>> + * to enter the Realm because we will have a sleep request
>> pending on
>> + * the VCPU as a result of KVM's PSCI handling.
>> + */
>> + if (status == RMI_ERROR_REALM) {
>> + vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
>> + return 0;
>> + }
>> +
>> + /*
>> + * If a VCPU has been turned on, but the REC state hasn't been
>> updated
>> + * we may experience RMI_ERROR_REC. Exit to the userspace with -
>> EAGAIN
>> + * for a retry.
>> + */
>> + if (status == RMI_ERROR_REC)
>> + return -EAGAIN;
>> + if (rec_run_ret)
>> + return -ENXIO;
>> +
>> + vcpu->arch.fault.esr_el2 = rec->run->exit.esr;
>> + vcpu->arch.fault.far_el2 = rec->run->exit.far;
>> + /* HPFAR_EL2 is only valid for RMI_EXIT_SYNC */
>> + vcpu->arch.fault.hpfar_el2 = 0;
>> +
>> + update_arch_timer_irq_lines(vcpu);
>> +
>> + /* Reset the emulation flags for the next run of the REC */
>> + rec->run->enter.flags = 0;
>> +
>> + switch (rec->run->exit.exit_reason) {
>> + case RMI_EXIT_SYNC:
>> + /*
>> + * HPFAR_EL2_NS is hijacked to indicate a valid HPFAR value,
>> + * see __get_fault_info()
>> + */
>> + vcpu->arch.fault.hpfar_el2 = rec->run->exit.hpfar |
>> HPFAR_EL2_NS;
>> + return rec_exit_handlers[esr_ec](vcpu);
>> + case RMI_EXIT_IRQ:
>> + case RMI_EXIT_FIQ:
>> + case RMI_EXIT_SERROR:
>> + return 1;
>> + case RMI_EXIT_PSCI:
>> + return rec_exit_psci(vcpu);
>> + case RMI_EXIT_RIPAS_CHANGE:
>> + return rec_exit_ripas_change(vcpu);
>> + }
>> +
>> + kvm_pr_unimpl("Unsupported exit reason: %u\n",
>> + rec->run->exit.exit_reason);
>> + vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
>> + return 0;
>> +}
>> diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
>> index 353a5ca45e78..d8a5fb12db2d 100644
>> --- a/arch/arm64/kvm/rmi.c
>> +++ b/arch/arm64/kvm/rmi.c
>> @@ -173,6 +173,48 @@ static int realm_ensure_created(struct kvm *kvm)
>> return -ENXIO;
>> }
>> +/*
>> + * kvm_rec_pre_enter - Complete operations before entering a REC
>> + *
>> + * Some operations require work to be completed before entering a
>> realm. That
>> + * work may require memory allocation so cannot be done in the
>> kvm_rec_enter()
>> + * call.
>> + *
>> + * Return: 1 if we should enter the guest
>> + * 0 if we should exit to userspace
>> + * < 0 if we should exit to userspace, where the return value
>> indicates
>> + * an error
>> + */
>> +int kvm_rec_pre_enter(struct kvm_vcpu *vcpu)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> +
>> + if (kvm_realm_state(vcpu->kvm) != REALM_STATE_ACTIVE)
>> + return -EINVAL;
>> +
>> + switch (rec->run->exit.exit_reason) {
>> + case RMI_EXIT_HOST_CALL:
>> + for (int i = 0; i < REC_RUN_GPRS; i++)
>> + rec->run->enter.gprs[i] = vcpu_get_reg(vcpu, i);
>> + break;
>> + }
>> +
>> + return 1;
>> +}
>> +
>> +int noinstr kvm_rec_enter(struct kvm_vcpu *vcpu)
>> +{
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> + int ret;
>> +
>> + guest_state_enter_irqoff();
>> + ret = rmi_rec_enter(virt_to_phys(rec->rec_page),
>> + virt_to_phys(rec->run));
>> + guest_state_exit_irqoff();
>> +
>> + return ret;
>> +}
>> +
>> static int kvm_create_rec(struct kvm_vcpu *vcpu)
>> {
>> struct user_pt_regs *vcpu_regs = vcpu_gp_regs(vcpu);
>
> Thanks,
> Gavin
>
^ permalink raw reply
* Re: [PATCH v14 20/44] arm64: RMI: Support for the VGIC in realms
From: Steven Price @ 2026-06-05 15:02 UTC (permalink / raw)
To: Gavin Shan, kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Shanker Donthineni,
Alper Gun, Aneesh Kumar K . V, Emi Kisanuki, Vishal Annapurve,
WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <5ea74b6a-a51a-415e-b53f-5ece9829dee8@redhat.com>
On 28/05/2026 05:07, Gavin Shan wrote:
> Hi Steve,
>
> On 5/13/26 11:17 PM, Steven Price wrote:
>> The RMM provides emulation of a VGIC to the realm guest. With RMM v2.0
>> the registers are passed in the system registers so this works similar
>> to a normal guest, but kvm_arch_vcpu_put() need reordering to early out,
>> and realm guests don't support GICv2 even if the host does.
>>
>> Signed-off-by: Steven Price <steven.price@arm.com>
>> ---
>> Changes from v12:
>> * GIC registers are now passed in the system registers rather than via
>> rec_entry/rec_exit which removes most of the changes.
>> Changes from v11:
>> * Minor changes to align with the previous patches. Note that the VGIC
>> handling will change with RMM v2.0.
>> Changes from v10:
>> * Make sure we sync the VGIC v4 state, and only populate valid lrs from
>> the list.
>> Changes from v9:
>> * Copy gicv3_vmcr from the RMM at the same time as gicv3_hcr rather
>> than having to handle that as a special case.
>> Changes from v8:
>> * Propagate gicv3_hcr to from the RMM.
>> Changes from v5:
>> * Handle RMM providing fewer GIC LRs than the hardware supports.
>> ---
>> arch/arm64/kvm/arm.c | 11 ++++++++---
>> arch/arm64/kvm/vgic/vgic-init.c | 2 +-
>> 2 files changed, 9 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 93d34762db91..21d9dfdb1ea0 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -786,19 +786,24 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
>> kvm_call_hyp_nvhe(__pkvm_vcpu_put);
>> }
>> + kvm_timer_vcpu_put(vcpu);
>> + kvm_vgic_put(vcpu);
>> +
>> + vcpu->cpu = -1;
>> +
>> + if (vcpu_is_rec(vcpu))
>> + return;
>> +
>
> For a REC, kvm_vcpu_{load, put}_debug() becomes unbalanced in
> kvm_arch_vcpu_{load, put}().
> kvm_vcpu_load_debug() is called in kvm_arch_vcpu_load(), but
> kvm_vcpu_put_debug() won't
> be called in kvm_arch_vcpu_put() after this whole series is applied.
Good catch. Yes that's not quite right.
Thanks,
Steve
>> kvm_vcpu_put_debug(vcpu);
>> kvm_arch_vcpu_put_fp(vcpu);
>> if (has_vhe())
>> kvm_vcpu_put_vhe(vcpu);
>> - kvm_timer_vcpu_put(vcpu);
>> - kvm_vgic_put(vcpu);
>> kvm_vcpu_pmu_restore_host(vcpu);
>> if (vcpu_has_nv(vcpu))
>> kvm_vcpu_put_hw_mmu(vcpu);
>> kvm_arm_vmid_clear_active();
>> vcpu_clear_on_unsupported_cpu(vcpu);
>> - vcpu->cpu = -1;
>> }
>> static void __kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu)
>> diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/
>> vgic-init.c
>> index 933983bb2005..a9db963dfd23 100644
>> --- a/arch/arm64/kvm/vgic/vgic-init.c
>> +++ b/arch/arm64/kvm/vgic/vgic-init.c
>> @@ -81,7 +81,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>> * the proper checks already.
>> */
>> if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
>> - !kvm_vgic_global_state.can_emulate_gicv2)
>> + (!kvm_vgic_global_state.can_emulate_gicv2 || kvm_is_realm(kvm)))
>> return -ENODEV;
>> /*
>
> Thanks,
> Gavin
>
^ permalink raw reply
* Re: [PATCH v14 19/44] arm64: RMI: Allocate/free RECs to match vCPUs
From: Steven Price @ 2026-06-05 15:02 UTC (permalink / raw)
To: Wei-Lin Chang, kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Gavin Shan,
Shanker Donthineni, Alper Gun, Aneesh Kumar K . V, Emi Kisanuki,
Vishal Annapurve, Lorenzo.Pieralisi2
In-Reply-To: <2uvtjhncf57yek5i4fupdefunukmidzw452mcavnmixpr5u3qd@uoaktzpak3nl>
On 26/05/2026 23:39, Wei-Lin Chang wrote:
> Hi,
>
> On Wed, May 13, 2026 at 02:17:27PM +0100, Steven Price wrote:
>> The RMM maintains a data structure known as the Realm Execution Context
>> (or REC). It is similar to struct kvm_vcpu and tracks the state of the
>> virtual CPUs. KVM must delegate memory and request the structures are
>> created when vCPUs are created, and suitably tear down on destruction.
>>
>> RECs may require additional pages (e.g. for storing larger register
>> state for SVE). The RMM can request extra pages for this purpose using
>> the Stateful RMI Operations (SRO) functionality to request pages during
>> REC creation. These pages are then passed back to the host from the RMM
>> ('reclaimed') when the REC is destroyed. The kernel tracking object
>> (struct rmi_sro_state) is stored in the realm_rec structure to avoid
>> memory allocation during the destruction path.
>>
>> Note that only some of register state for the REC can be set by KVM, the
>> rest is defined by the RMM (zeroed). The register state then cannot be
>> changed by KVM after the REC is created (except when the guest
>> explicitly requests this e.g. by performing a PSCI call).
>>
>> Signed-off-by: Steven Price <steven.price@arm.com>
>> ---
>> Changes since v13:
>> * Support SRO for REC creation/destruction instead of auxiliary
>> granules.
>> Changes since v12:
>> * Use the new range-based delegation RMI.
>> Changes since v11:
>> * Remove the KVM_ARM_VCPU_REC feature. User space no longer needs to
>> configure each VCPU separately, RECs are created on the first VCPU
>> run of the guest.
>> Changes since v9:
>> * Size the aux_pages array according to the PAGE_SIZE of the host.
>> Changes since v7:
>> * Add comment explaining the aux_pages array.
>> * Rename "undeleted_failed" variable to "should_free" to avoid a
>> confusing double negative.
>> Changes since v6:
>> * Avoid reporting the KVM_ARM_VCPU_REC feature if the guest isn't a
>> realm guest.
>> * Support host page size being larger than RMM's granule size when
>> allocating/freeing aux granules.
>> Changes since v5:
>> * Separate the concept of vcpu_is_rec() and
>> kvm_arm_vcpu_rec_finalized() by using the KVM_ARM_VCPU_REC feature as
>> the indication that the VCPU is a REC.
>> Changes since v2:
>> * Free rec->run earlier in kvm_destroy_realm() and adapt to previous patches.
>> ---
>> arch/arm64/include/asm/kvm_emulate.h | 2 +-
>> arch/arm64/include/asm/kvm_host.h | 3 +
>> arch/arm64/include/asm/kvm_rmi.h | 17 +++++
>> arch/arm64/kvm/arm.c | 6 ++
>> arch/arm64/kvm/reset.c | 1 +
>> arch/arm64/kvm/rmi.c | 105 +++++++++++++++++++++++++++
>> 6 files changed, 133 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
>> index 82fd777bd9bb..2e69fe494716 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -714,7 +714,7 @@ static inline bool kvm_realm_is_created(struct kvm *kvm)
>>
>> static inline bool vcpu_is_rec(const struct kvm_vcpu *vcpu)
>> {
>> - return false;
>> + return kvm_is_realm(vcpu->kvm);
>> }
>>
>> #endif /* __ARM64_KVM_EMULATE_H__ */
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 3512696ed506..39b5de03d0fe 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -969,6 +969,9 @@ struct kvm_vcpu_arch {
>>
>> /* Hyp-readable copy of kvm_vcpu::pid */
>> pid_t pid;
>> +
>> + /* Realm meta data */
>> + struct realm_rec rec;
>> };
>>
>> /*
>> diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
>> index 8bd743093ccf..d99bf4fc3c39 100644
>> --- a/arch/arm64/include/asm/kvm_rmi.h
>> +++ b/arch/arm64/include/asm/kvm_rmi.h
>> @@ -59,6 +59,22 @@ struct realm {
>> unsigned int ia_bits;
>> };
>>
>> +/**
>> + * struct realm_rec - Additional per VCPU data for a Realm
>> + *
>> + * @mpidr: MPIDR (Multiprocessor Affinity Register) value to identify this VCPU
>> + * @rec_page: Kernel VA of the RMM's private page for this REC
>> + * @aux_pages: Additional pages private to the RMM for this REC
>> + * @run: Kernel VA of the RmiRecRun structure shared with the RMM
>> + * @sro: A preallocated SRO state context
>> + */
>> +struct realm_rec {
>> + unsigned long mpidr;
>> + void *rec_page;
>> + struct rec_run *run;
>> + struct rmi_sro_state *sro;
>> +};
>> +
>> void kvm_init_rmi(void);
>> u32 kvm_realm_ipa_limit(void);
>>
>> @@ -66,6 +82,7 @@ int kvm_init_realm(struct kvm *kvm);
>> int kvm_activate_realm(struct kvm *kvm);
>> void kvm_destroy_realm(struct kvm *kvm);
>> void kvm_realm_destroy_rtts(struct kvm *kvm);
>> +void kvm_destroy_rec(struct kvm_vcpu *vcpu);
>>
>> static inline bool kvm_realm_is_private_address(struct realm *realm,
>> unsigned long addr)
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index eb2b61fe1f0a..93d34762db91 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -586,6 +586,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
>> /* Force users to call KVM_ARM_VCPU_INIT */
>> vcpu_clear_flag(vcpu, VCPU_INITIALIZED);
>>
>> + vcpu->arch.rec.mpidr = INVALID_HWID;
>> +
>> vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO;
>>
>> /* Set up the timer */
>> @@ -1651,6 +1653,10 @@ static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
>> if (test_bit(KVM_ARM_VCPU_HAS_EL2, &features))
>> return -EINVAL;
>>
>> + /* Realms are incompatible with AArch32 */
>> + if (vcpu_is_rec(vcpu))
>> + return -EINVAL;
>> +
>> return 0;
>> }
>>
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index b963fd975aac..c18cdca7d125 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -161,6 +161,7 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
>> free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
>> kfree(vcpu->arch.vncr_tlb);
>> kfree(vcpu->arch.ccsidr);
>> + kvm_destroy_rec(vcpu);
>> }
>>
>> static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
>> diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
>> index 849111817af7..353a5ca45e78 100644
>> --- a/arch/arm64/kvm/rmi.c
>> +++ b/arch/arm64/kvm/rmi.c
>> @@ -173,9 +173,108 @@ static int realm_ensure_created(struct kvm *kvm)
>> return -ENXIO;
>> }
>>
>> +static int kvm_create_rec(struct kvm_vcpu *vcpu)
>> +{
>> + struct user_pt_regs *vcpu_regs = vcpu_gp_regs(vcpu);
>> + unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
>> + struct realm *realm = &vcpu->kvm->arch.realm;
>> + struct realm_rec *rec = &vcpu->arch.rec;
>> + unsigned long rec_page_phys;
>> + struct rec_params *params;
>> + int r, i;
>> +
>> + if (rec->run)
>> + return -EBUSY;
>> +
>> + /*
>> + * The RMM will report PSCI v1.0 to Realms and the KVM_ARM_VCPU_PSCI_0_2
>> + * flag covers v0.2 and onwards.
>> + */
>> + if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_PSCI_0_2))
>> + return -EINVAL;
>> +
>> + BUILD_BUG_ON(sizeof(*params) > PAGE_SIZE);
>> + BUILD_BUG_ON(sizeof(*rec->run) > PAGE_SIZE);
>> +
>> + params = (struct rec_params *)get_zeroed_page(GFP_KERNEL);
>> + rec->rec_page = (void *)__get_free_page(GFP_KERNEL);
>> + rec->run = (void *)get_zeroed_page(GFP_KERNEL);
>
> Should this be cast to (struct rec_run *) ?
Yes it probably should - I'll update. Although IMHO get_zeroed_page()
should really return void * - but I know that would be a contentious change.
Thanks,
Steve
>> + rec->sro = kmalloc_obj(*rec->sro);
>> + if (!params || !rec->rec_page || !rec->run || !rec->sro) {
>> + r = -ENOMEM;
>> + goto out_free_pages;
>> + }
>> +
>> + for (i = 0; i < ARRAY_SIZE(params->gprs); i++)
>> + params->gprs[i] = vcpu_regs->regs[i];
>> +
>> + params->pc = vcpu_regs->pc;
>> +
>> + if (vcpu->vcpu_id == 0)
>> + params->flags |= REC_PARAMS_FLAG_RUNNABLE;
>> +
>> + rec_page_phys = virt_to_phys(rec->rec_page);
>> +
>> + if (rmi_delegate_page(rec_page_phys)) {
>> + r = -ENXIO;
>> + goto out_free_pages;
>> + }
>> +
>> + params->mpidr = mpidr;
>> +
>> + if (rmi_rec_create(virt_to_phys(realm->rd), rec_page_phys,
>> + virt_to_phys(params), rec->sro)) {
>> + r = -ENXIO;
>> + goto out_undelegate_rmm_rec;
>> + }
>> +
>> + rec->mpidr = mpidr;
>> +
>> + free_page((unsigned long)params);
>> + return 0;
>> +
>> +out_undelegate_rmm_rec:
>> + if (WARN_ON(rmi_undelegate_page(rec_page_phys)))
>> + rec->rec_page = NULL;
>> +out_free_pages:
>> + free_page((unsigned long)rec->run);
>> + free_page((unsigned long)rec->rec_page);
>> + free_page((unsigned long)params);
>> + kfree(rec->sro);
>> + rec->run = NULL;
>> + return r;
>> +}
>> +
>
> [...]
>
> Thanks,
> Wei-Lin Chang
^ permalink raw reply
* Re: [PATCH v14 17/44] arm64: RMI: RTT tear down
From: Steven Price @ 2026-06-05 15:01 UTC (permalink / raw)
To: Wei-Lin Chang, kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Gavin Shan,
Shanker Donthineni, Alper Gun, Aneesh Kumar K . V, Emi Kisanuki,
Vishal Annapurve, Lorenzo.Pieralisi2
In-Reply-To: <mpesc2j3czpunbg3pvgwbotvfn7vahaabvoiu77vd2g5uervho@255lwycekmxh>
On 26/05/2026 23:32, Wei-Lin Chang wrote:
> Hi,
>
> On Wed, May 13, 2026 at 02:17:25PM +0100, Steven Price wrote:
>> The RMM owns the stage 2 page tables for a realm, and KVM must request
>> that the RMM creates/destroys entries as necessary. The physical pages
>> to store the page tables are delegated to the realm as required, and can
>> be undelegated when no longer used.
>>
>> Creating new RTTs is the easy part, tearing down is a little more
>> tricky. The result of realm_rtt_destroy() can be used to effectively
>> walk the tree and destroy the entries (undelegating pages that were
>> given to the realm).
>>
>> Signed-off-by: Steven Price <steven.price@arm.com>
>> ---
>> Changes since v13:
>> * Avoid the double call of kvm_free_stage2_pgd() by splitting the work
>> across that and a new function kvm_realm_uninit_stage2() which is
>> only called for realm guests.
>> Changes since v12:
>> * Simplify some functions now we know RMM page size is the same as the
>> host's.
>> Changes since v11:
>> * Moved some code from earlier in the series to this one so that it's
>> added when it's first used.
>> Changes since v10:
>> * RME->RMI rename.
>> * Some code to handle freeing stage 2 PGD moved into this patch where
>> it belongs.
>> Changes since v9:
>> * Add a comment clarifying that root level RTTs are not destroyed until
>> after the RD is destroyed.
>> Changes since v8:
>> * Introduce free_rtt() wrapper which calls free_delegated_granule()
>> followed by kvm_account_pgtable_pages(). This makes it clear where an
>> RTT is being freed rather than just a delegated granule.
>> Changes since v6:
>> * Move rme_rtt_level_mapsize() and supporting defines from kvm_rme.h
>> into rme.c as they are only used in that file.
>> Changes since v5:
>> * Rename some RME_xxx defines to do with page sizes as RMM_xxx - they are
>> a property of the RMM specification not the RME architecture.
>> Changes since v2:
>> * Moved {alloc,free}_delegated_page() and ensure_spare_page() to a
>> later patch when they are actually used.
>> * Some simplifications now rmi_xxx() functions allow NULL as an output
>> parameter.
>> * Improved comments and code layout.
>> ---
>> arch/arm64/include/asm/kvm_rmi.h | 7 ++
>> arch/arm64/kvm/mmu.c | 21 ++++-
>> arch/arm64/kvm/rmi.c | 148 +++++++++++++++++++++++++++++++
>> 3 files changed, 174 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
>> index 9de34983ee52..06ba0d4745c6 100644
>> --- a/arch/arm64/include/asm/kvm_rmi.h
>> +++ b/arch/arm64/include/asm/kvm_rmi.h
>> @@ -64,5 +64,12 @@ u32 kvm_realm_ipa_limit(void);
>>
>> int kvm_init_realm(struct kvm *kvm);
>> void kvm_destroy_realm(struct kvm *kvm);
>> +void kvm_realm_destroy_rtts(struct kvm *kvm);
>> +
>> +static inline bool kvm_realm_is_private_address(struct realm *realm,
>> + unsigned long addr)
>> +{
>> + return !(addr & BIT(realm->ia_bits - 1));
>> +}
>>
>> #endif /* __ASM_KVM_RMI_H */
>> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>> index ba8286472286..eb56d4e7f21a 100644
>> --- a/arch/arm64/kvm/mmu.c
>> +++ b/arch/arm64/kvm/mmu.c
>> @@ -1024,9 +1024,26 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
>> return err;
>> }
>>
>> +static void kvm_realm_uninit_stage2(struct kvm_s2_mmu *mmu)
>> +{
>> + struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
>> + struct realm *realm = &kvm->arch.realm;
>> +
>> + if (kvm_realm_state(kvm) != REALM_STATE_ACTIVE)
>> + return;
>> +
>> + write_lock(&kvm->mmu_lock);
>> + kvm_stage2_unmap_range(mmu, 0, BIT(realm->ia_bits - 1), true);
>> + write_unlock(&kvm->mmu_lock);
>> + kvm_realm_destroy_rtts(kvm);
>> +}
>> +
>> void kvm_uninit_stage2_mmu(struct kvm *kvm)
>> {
>> - kvm_free_stage2_pgd(&kvm->arch.mmu);
>> + if (kvm_is_realm(kvm))
>> + kvm_realm_uninit_stage2(&kvm->arch.mmu);
>> + else
>> + kvm_free_stage2_pgd(&kvm->arch.mmu);
>> kvm_mmu_free_memory_cache(&kvm->arch.mmu.split_page_cache);
>> }
>>
>> @@ -1103,7 +1120,7 @@ void stage2_unmap_vm(struct kvm *kvm)
>> void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
>> {
>> struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
>> - struct kvm_pgtable *pgt = NULL;
>> + struct kvm_pgtable *pgt;
>>
>> write_lock(&kvm->mmu_lock);
>> pgt = mmu->pgt;
>> diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
>> index f51ec667445e..5b00ccca4af3 100644
>> --- a/arch/arm64/kvm/rmi.c
>> +++ b/arch/arm64/kvm/rmi.c
>> @@ -11,6 +11,14 @@
>> #include <asm/rmi_cmds.h>
>> #include <asm/virt.h>
>>
>> +static inline unsigned long rmi_rtt_level_mapsize(int level)
>> +{
>> + if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL))
>> + return PAGE_SIZE;
>> +
>> + return (1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(level));
>> +}
>> +
>> static bool rmi_has_feature(unsigned long feature)
>> {
>> return !!u64_get_bits(rmm_feat_reg0, feature);
>> @@ -21,6 +29,144 @@ u32 kvm_realm_ipa_limit(void)
>> return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_S2SZ);
>> }
>>
>> +static int get_start_level(struct realm *realm)
>> +{
>> + return 4 - stage2_pgtable_levels(realm->ia_bits);
>> +}
>> +
>> +static void free_rtt(phys_addr_t phys)
>> +{
>> + if (free_delegated_page(phys))
>> + return;
>> +
>> + kvm_account_pgtable_pages(phys_to_virt(phys), -1);
>> +}
>> +
>> +/*
>> + * realm_rtt_destroy - Destroy an RTT at @level for @addr.
>> + *
>> + * Returns - Result of the RMI_RTT_DESTROY call, and:
>> + * @rtt_granule: RTT granule, if the RTT was destroyed.
>> + * @next_addr: IPA corresponding to the next possible valid entry we
>> + * can target
>> + */
>> +static int realm_rtt_destroy(struct realm *realm, unsigned long addr,
>> + int level, phys_addr_t *rtt_granule,
>> + unsigned long *next_addr)
>> +{
>> + unsigned long out_rtt;
>> + int ret;
>> +
>> + ret = rmi_rtt_destroy(virt_to_phys(realm->rd), addr, level,
>> + &out_rtt, next_addr);
>> +
>> + *rtt_granule = out_rtt;
>> +
>> + return ret;
>> +}
>
> Looks like out_rtt can be simplified out.
The issue here is there's a type conversion going on. rmi_rtt_destroy()
takes an "unsigned long *" to match the general approach of using
"unsigned long" for the inputs/outputs of SMCCC calls. But rtt_granule
is a "phys_addr_t". While we know these are (currently) the same size,
they are not the same type according to the compiler - phys_addr_t is
"long long unsigned int".
Thanks,
Steve
> [...]
>
> Thanks,
> Wei-Lin Chang
^ permalink raw reply
* Re: [PATCH v14 17/44] arm64: RMI: RTT tear down
From: Steven Price @ 2026-06-05 15:01 UTC (permalink / raw)
To: Wei-Lin Chang, kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Gavin Shan,
Shanker Donthineni, Alper Gun, Aneesh Kumar K . V, Emi Kisanuki,
Vishal Annapurve, Lorenzo.Pieralisi2
In-Reply-To: <7egwow26r6sbbtm53mujbhpwyts2utzv2ddth7554kqwbk7k7d@iptjpvvbsc2n>
On 26/05/2026 23:27, Wei-Lin Chang wrote:
> Hi,
>
> On Wed, May 13, 2026 at 02:17:25PM +0100, Steven Price wrote:
>> The RMM owns the stage 2 page tables for a realm, and KVM must request
>> that the RMM creates/destroys entries as necessary. The physical pages
>> to store the page tables are delegated to the realm as required, and can
>> be undelegated when no longer used.
>>
>> Creating new RTTs is the easy part, tearing down is a little more
>> tricky. The result of realm_rtt_destroy() can be used to effectively
>> walk the tree and destroy the entries (undelegating pages that were
>> given to the realm).
>>
>> Signed-off-by: Steven Price <steven.price@arm.com>
>> ---
>> Changes since v13:
>> * Avoid the double call of kvm_free_stage2_pgd() by splitting the work
>> across that and a new function kvm_realm_uninit_stage2() which is
>> only called for realm guests.
>> Changes since v12:
>> * Simplify some functions now we know RMM page size is the same as the
>> host's.
>> Changes since v11:
>> * Moved some code from earlier in the series to this one so that it's
>> added when it's first used.
>> Changes since v10:
>> * RME->RMI rename.
>> * Some code to handle freeing stage 2 PGD moved into this patch where
>> it belongs.
>> Changes since v9:
>> * Add a comment clarifying that root level RTTs are not destroyed until
>> after the RD is destroyed.
>> Changes since v8:
>> * Introduce free_rtt() wrapper which calls free_delegated_granule()
>> followed by kvm_account_pgtable_pages(). This makes it clear where an
>> RTT is being freed rather than just a delegated granule.
>> Changes since v6:
>> * Move rme_rtt_level_mapsize() and supporting defines from kvm_rme.h
>> into rme.c as they are only used in that file.
>> Changes since v5:
>> * Rename some RME_xxx defines to do with page sizes as RMM_xxx - they are
>> a property of the RMM specification not the RME architecture.
>> Changes since v2:
>> * Moved {alloc,free}_delegated_page() and ensure_spare_page() to a
>> later patch when they are actually used.
>> * Some simplifications now rmi_xxx() functions allow NULL as an output
>> parameter.
>> * Improved comments and code layout.
>> ---
>> arch/arm64/include/asm/kvm_rmi.h | 7 ++
>> arch/arm64/kvm/mmu.c | 21 ++++-
>> arch/arm64/kvm/rmi.c | 148 +++++++++++++++++++++++++++++++
>> 3 files changed, 174 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
>> index 9de34983ee52..06ba0d4745c6 100644
>> --- a/arch/arm64/include/asm/kvm_rmi.h
>> +++ b/arch/arm64/include/asm/kvm_rmi.h
>> @@ -64,5 +64,12 @@ u32 kvm_realm_ipa_limit(void);
>>
>> int kvm_init_realm(struct kvm *kvm);
>> void kvm_destroy_realm(struct kvm *kvm);
>> +void kvm_realm_destroy_rtts(struct kvm *kvm);
>> +
>> +static inline bool kvm_realm_is_private_address(struct realm *realm,
>> + unsigned long addr)
>> +{
>> + return !(addr & BIT(realm->ia_bits - 1));
>> +}
>>
>> #endif /* __ASM_KVM_RMI_H */
>> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>> index ba8286472286..eb56d4e7f21a 100644
>> --- a/arch/arm64/kvm/mmu.c
>> +++ b/arch/arm64/kvm/mmu.c
>> @@ -1024,9 +1024,26 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
>> return err;
>> }
>>
>> +static void kvm_realm_uninit_stage2(struct kvm_s2_mmu *mmu)
>> +{
>> + struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
>> + struct realm *realm = &kvm->arch.realm;
>> +
>> + if (kvm_realm_state(kvm) != REALM_STATE_ACTIVE)
>> + return;
>> +
>> + write_lock(&kvm->mmu_lock);
>> + kvm_stage2_unmap_range(mmu, 0, BIT(realm->ia_bits - 1), true);
>> + write_unlock(&kvm->mmu_lock);
>> + kvm_realm_destroy_rtts(kvm);
>> +}
>> +
>> void kvm_uninit_stage2_mmu(struct kvm *kvm)
>> {
>> - kvm_free_stage2_pgd(&kvm->arch.mmu);
>> + if (kvm_is_realm(kvm))
>> + kvm_realm_uninit_stage2(&kvm->arch.mmu);
>> + else
>> + kvm_free_stage2_pgd(&kvm->arch.mmu);
>> kvm_mmu_free_memory_cache(&kvm->arch.mmu.split_page_cache);
>> }
>>
>> @@ -1103,7 +1120,7 @@ void stage2_unmap_vm(struct kvm *kvm)
>> void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
>> {
>> struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
>> - struct kvm_pgtable *pgt = NULL;
>> + struct kvm_pgtable *pgt;
>
> Is this included by accident?
Thanks for spotting that. Yes that change shouldn't have sneaked in
here. The original code before this series had the redundant assignment
to NULL. But it's unrelated to this patch so I'll drop the change.
Thanks,
Steve
>
>>
>> write_lock(&kvm->mmu_lock);
>> pgt = mmu->pgt;
>
> [...]
>
> Thanks,
> Wei-Lin Chang
^ permalink raw reply
* Re: [PATCH] net: stmmac: xgmac: report L3/L4 filter match count in ethtool stats
From: Maxime Chevallier @ 2026-06-05 14:55 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade, netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
alexandre.torgue, rmk+kernel, linux-stm32, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260604083037.24407-1-muhammad.nazim.amirul.nazle.asmade@altera.com>
Hi,
You're missing the 'net-next' in the Patch subject :(
Besides that,
On 6/4/26 10:30, muhammad.nazim.amirul.nazle.asmade@altera.com wrote:
> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>
> Read the L3FM and L4FM bits from the RX descriptor status word (RDES2)
> and increment the corresponding ethtool statistics counters. This allows
> users to observe L3/L4 filter hit rates via ethtool -S.
>
> Signed-off-by: Rohan G Thomas <rohan.g.thomas@altera.com>
> Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Maxime
> ---
> drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h | 2 ++
> drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c | 6 ++++++
> 2 files changed, 8 insertions(+)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> index 51943705a2b0..95fdf3133208 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> @@ -429,6 +429,8 @@
> #define XGMAC_TDES3_VLTV BIT(16)
> #define XGMAC_TDES3_VT GENMASK(15, 0)
> #define XGMAC_TDES3_FL GENMASK(14, 0)
> +#define XGMAC_RDES2_L4FM BIT(28)
> +#define XGMAC_RDES2_L3FM BIT(27)
> #define XGMAC_RDES2_HL GENMASK(9, 0)
> #define XGMAC_RDES3_OWN BIT(31)
> #define XGMAC_RDES3_CTXT BIT(30)
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
> index b5f200a87484..6719ac6e395b 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
> @@ -27,6 +27,7 @@ static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
> struct dma_desc *p)
> {
> u32 rdes3 = le32_to_cpu(p->des3);
> + u32 rdes2 = le32_to_cpu(p->des2);
>
> if (unlikely(rdes3 & XGMAC_RDES3_OWN))
> return dma_own;
> @@ -37,6 +38,11 @@ static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
> if (unlikely((rdes3 & XGMAC_RDES3_ES) && (rdes3 & XGMAC_RDES3_LD)))
> return discard_frame;
>
> + if (rdes2 & XGMAC_RDES2_L3FM)
> + x->l3_filter_match++;
> + if (rdes2 & XGMAC_RDES2_L4FM)
> + x->l4_filter_match++;
> +
> return good_frame;
> }
>
^ permalink raw reply
* Re: [PATCH bpf-next v2 5/8] bpf, x86: emit KASAN checks into x86 JITed programs
From: Yonghong Song @ 2026-06-05 14:54 UTC (permalink / raw)
To: Alexis Lothoré (eBPF Foundation), Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu, Jiri Olsa,
John Fastabend, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, Shuah Khan, Maxime Coquelin,
Alexandre Torgue, Ihor Solodrai
Cc: ebpf, Bastien Curutchet, Thomas Petazzoni, bpf, linux-kernel,
linux-kselftest, linux-stm32, linux-arm-kernel
In-Reply-To: <20260604-kasan-v2-5-c066e627fda8@bootlin.com>
On 6/4/26 1:22 PM, Alexis Lothoré (eBPF Foundation) wrote:
> Insert KASAN shadow memory checks before memory load and store
> operations in JIT-compiled BPF programs. This helps detect memory safety
> bugs such as use-after-free and out-of-bounds accesses at runtime.
>
> The main instructions being targeted are BPF_ST, BPF_STX and BPF_LDX,
> but not all of them are being instrumented:
> - if the load/store instruction is in fact accessing the program stack,
> emit_kasan_check silently skips the instrumentation, as we already
> have page guards to monitor stack accesses.
> - if the load/store instruction is a BPF_PROBE_MEM or a BPF_PROBE_ATOMIC
> instruction, we do not instrument it, as the passed address can fault
> (hence the custom fault management with BPF_PROBE_XXX instructions),
> and so the corresponding kasan check could fault as well.
>
> Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
> ---
> Changes in v2:
> - support BPF_ATOMICS
> - support BPF_ST
> - make sure to systematically pass correct instruction to kasan check
> ---
> arch/x86/net/bpf_jit_comp.c | 63 ++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 53 insertions(+), 10 deletions(-)
>
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index 943a0f315cf2..cb3c03edc4bd 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -1516,17 +1516,30 @@ static int emit_atomic_rmw_index(u8 **pprog, u32 atomic_op, u32 size,
> return 0;
> }
>
> -static int emit_atomic_ld_st(u8 **pprog, u32 atomic_op, u32 dst_reg,
> - u32 src_reg, s16 off, u8 bpf_size)
> +static int emit_atomic_ld_st(u8 **pprog, struct bpf_insn *insn, u8 *ip,
> + u32 dst_reg, u32 src_reg, bool accesses_stack_only)
> {
> + u32 atomic_op = insn->imm;
> + int err;
> +
> switch (atomic_op) {
> case BPF_LOAD_ACQ:
> + err = emit_kasan_check(pprog, src_reg, insn, ip, false,
> + accesses_stack_only);
> + if (err)
> + return err;
> /* dst_reg = smp_load_acquire(src_reg + off16) */
> - emit_ldx(pprog, bpf_size, dst_reg, src_reg, off);
> + emit_ldx(pprog, BPF_SIZE(insn->code), dst_reg, src_reg,
> + insn->off);
> break;
> case BPF_STORE_REL:
> + err = emit_kasan_check(pprog, dst_reg, insn, ip, true,
> + accesses_stack_only);
> + if (err)
> + return err;
> /* smp_store_release(dst_reg + off16, src_reg) */
> - emit_stx(pprog, bpf_size, dst_reg, src_reg, off);
> + emit_stx(pprog, BPF_SIZE(insn->code), dst_reg, src_reg,
> + insn->off);
> break;
> default:
> pr_err("bpf_jit: unknown atomic load/store opcode %02x\n",
> @@ -1904,6 +1917,7 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> const s32 imm32 = insn->imm;
> u32 dst_reg = insn->dst_reg;
> u32 src_reg = insn->src_reg;
> + bool accesses_stack_only;
> u8 b2 = 0, b3 = 0;
> u8 *start_of_ldx;
> s64 jmp_offset;
> @@ -1924,6 +1938,8 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> EMIT_ENDBR();
>
> ip = image + addrs[i - 1] + (prog - temp);
> + accesses_stack_only =
> + bpf_insn_accesses_stack_only(env, bpf_prog, i - 1);
>
> switch (insn->code) {
> /* ALU */
> @@ -2304,6 +2320,10 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> case BPF_ST | BPF_MEM | BPF_H:
> case BPF_ST | BPF_MEM | BPF_W:
> case BPF_ST | BPF_MEM | BPF_DW:
> + err = emit_kasan_check(&prog, dst_reg, insn, ip, true,
> + accesses_stack_only);
> + if (err)
> + return err;
> switch (BPF_SIZE(insn->code)) {
> case BPF_B:
> if (is_ereg(dst_reg))
> @@ -2369,6 +2389,10 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> insn_off = outgoing_arg_base - outgoing_rsp - insn_off - 16;
> dst_reg = BPF_REG_FP;
> }
> + err = emit_kasan_check(&prog, dst_reg, insn, ip, true,
> + accesses_stack_only);
> + if (err)
> + return err;
> emit_stx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn_off);
> break;
>
> @@ -2530,6 +2554,12 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> /* populate jmp_offset for JAE above to jump to start_of_ldx */
> start_of_ldx = prog;
> end_of_jmp[-1] = start_of_ldx - end_of_jmp;
> + } else {
> + err = emit_kasan_check(&prog, src_reg, insn, ip,
> + false,
> + accesses_stack_only);
> + if (err)
> + return err;
> }
> if (BPF_MODE(insn->code) == BPF_PROBE_MEMSX ||
> BPF_MODE(insn->code) == BPF_MEMSX)
> @@ -2592,13 +2622,13 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> fallthrough;
> case BPF_STX | BPF_ATOMIC | BPF_W:
> case BPF_STX | BPF_ATOMIC | BPF_DW:
> + bool is64 = BPF_SIZE(insn->code) == BPF_DW;
> + u32 real_src_reg = src_reg;
> + u32 real_dst_reg = dst_reg;
With llvm23, I got the following build failure:
/home/yhs/work/bpf-next/arch/x86/net/bpf_jit_comp.c:2625:4: error:
label followed by a declaration is a C23 extension [-Werror,-Wc23-extensions]
2625 | bool is64 = BPF_SIZE(insn->code) == BPF_DW;
| ^
1 error generated.
The below is a fix:
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index cb3c03edc4bd..61faf8d8f157 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -2621,7 +2621,7 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
}
fallthrough;
case BPF_STX | BPF_ATOMIC | BPF_W:
- case BPF_STX | BPF_ATOMIC | BPF_DW:
+ case BPF_STX | BPF_ATOMIC | BPF_DW: {
bool is64 = BPF_SIZE(insn->code) == BPF_DW;
u32 real_src_reg = src_reg;
u32 real_dst_reg = dst_reg;
@@ -2695,6 +2695,7 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
if (err)
return err;
break;
+ }
case BPF_STX | BPF_PROBE_ATOMIC | BPF_B:
case BPF_STX | BPF_PROBE_ATOMIC | BPF_H:
> + u8 *branch_target;
> if (insn->imm == (BPF_AND | BPF_FETCH) ||
> insn->imm == (BPF_OR | BPF_FETCH) ||
> insn->imm == (BPF_XOR | BPF_FETCH)) {
> - bool is64 = BPF_SIZE(insn->code) == BPF_DW;
> - u32 real_src_reg = src_reg;
> - u32 real_dst_reg = dst_reg;
> - u8 *branch_target;
>
> /*
> * Can't be implemented with a single x86 insn.
> @@ -2612,7 +2642,19 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> if (dst_reg == BPF_REG_0)
> real_dst_reg = BPF_REG_AX;
>
> + ip += 3;
> + }
> + if (!bpf_atomic_is_load_store(insn)) {
> + err = emit_kasan_check(&prog, real_dst_reg,
> + insn, ip, false,
> + accesses_stack_only);
> + if (err)
> + return err;
> branch_target = prog;
> + }
> + if (insn->imm == (BPF_AND | BPF_FETCH) ||
> + insn->imm == (BPF_OR | BPF_FETCH) ||
> + insn->imm == (BPF_XOR | BPF_FETCH)) {
> /* Load old value */
> emit_ldx(&prog, BPF_SIZE(insn->code),
> BPF_REG_0, real_dst_reg, insn->off);
> @@ -2644,8 +2686,9 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
> }
>
> if (bpf_atomic_is_load_store(insn))
> - err = emit_atomic_ld_st(&prog, insn->imm, dst_reg, src_reg,
> - insn->off, BPF_SIZE(insn->code));
> + err = emit_atomic_ld_st(&prog, insn, ip,
> + dst_reg, src_reg,
> + accesses_stack_only);
> else
> err = emit_atomic_rmw(&prog, insn->imm, dst_reg, src_reg,
> insn->off, BPF_SIZE(insn->code));
>
^ permalink raw reply related
* Re: [PATCH net-next v2 13/14] net: stmmac: tc956x: add TC956x/QPS615 support
From: Rob Herring @ 2026-06-05 14:47 UTC (permalink / raw)
To: Alex Elder
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, maxime.chevallier,
rmk+kernel, andersson, konradybcio, krzk+dt, conor+dt, linusw,
brgl, arnd, gregkh, Daniel Thompson, mohd.anwar, a0987203069,
alexandre.torgue, ast, boon.khai.ng, chenchuangyu, chenhuacai,
daniel, hawk, hkallweit1, inochiama, john.fastabend, julianbraha,
livelycarpet87, mcoquelin.stm32, me, prabhakar.mahadev-lad.rj,
richardcochran, rohan.g.thomas, sdf, siyanteng, weishangjuan,
wens, netdev, bpf, linux-arm-msm, devicetree, linux-gpio,
linux-stm32, linux-arm-kernel, linux-kernel
In-Reply-To: <20260605010022.968612-14-elder@riscstar.com>
On Thu, Jun 04, 2026 at 08:00:20PM -0500, Alex Elder wrote:
> From: Daniel Thompson <daniel@riscstar.com>
>
> Toshiba TC956x is an Ethernet AVB/TSN bridge and is essentially a
> small and highly-specialized SoC. TC956x includes an "eMAC" subsystem
> that can be accessed, along with several other peripherals, via two
> PCIe endpoint functions. There is a main driver for the endpoint that
> decomposes things and creates auxiliary bus devices to model the SoC.
>
> The eMAC consists of a Designware XGMAC, XPCS and PMA. Each eMAC is
> supported by an MSIGEN that bridges TC956x level interrupts to PCIe
> MSIs.
>
> Add a driver for the eMAC/MSIGEN combination.
>
> Co-developed-by: Alex Elder <elder@riscstar.com>
> Signed-off-by: Alex Elder <elder@riscstar.com>
> Signed-off-by: Daniel Thompson <daniel@riscstar.com>
The order is wrong here unless you worked on it and then Daniel took
over. Tags should be chronological order.
> ---
> MAINTAINERS | 2 +
> drivers/net/ethernet/stmicro/stmmac/Kconfig | 14 +
> drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +
> .../ethernet/stmicro/stmmac/dwmac-tc956x.c | 818 ++++++++++++++++++
> 4 files changed, 836 insertions(+)
> create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0439607d1155f..418537cbefbbb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -27059,6 +27059,8 @@ S: Maintained
> F: Documentation/devicetree/bindings/net/toshiba,tc956x-dwmac.yaml
> F: drivers/gpio/gpio-tc956x.c
> F: drivers/misc/tc956x_pci.c
> +F: drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c
> +F: include/soc/toshiba/tc956x-dwmac.h
>
> TOSHIBA WMI HOTKEYS DRIVER
> M: Azael Avalos <coproscefalo@gmail.com>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> index e3dd5adda5aca..8d247e033e356 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
> +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> @@ -404,6 +404,20 @@ config DWMAC_MOTORCOMM
> This enables glue driver for Motorcomm DWMAC-based PCI Ethernet
> controllers. Currently only YT6801 is supported.
>
> +config DWMAC_TC956X
> + tristate "Toshiba TC956X DWMAC support"
> + depends on PCI
> + depends on COMMON_CLK
> + depends on TOSHIBA_TC956X_PCI
> + default TOSHIBA_TC956X_PCI
> + select GENERIC_IRQ_CHIP
> + help
> + This selects the Toshiba TC956X (and Qualcomm QPS615) support in the
> + stmmac driver.
> +
> + This provides support for the ethernet controllers found on these
> + devices.
> +
> config STMMAC_PCI
> tristate "STMMAC PCI bus support"
> depends on PCI
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index a1cea2f57252e..e8e7f95dbe3e8 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -51,4 +51,6 @@ obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
> obj-$(CONFIG_DWMAC_INTEL) += dwmac-intel.o
> obj-$(CONFIG_DWMAC_LOONGSON) += dwmac-loongson.o
> obj-$(CONFIG_DWMAC_MOTORCOMM) += dwmac-motorcomm.o
> +obj-$(CONFIG_TC956X_PCI) += tc956x-pci.o
> +obj-$(CONFIG_DWMAC_TC956X) += dwmac-tc956x.o
> stmmac-pci-objs:= stmmac_pci.o
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c
> new file mode 100644
> index 0000000000000..c77585e4a50e6
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c
> @@ -0,0 +1,818 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (C) 2026 by RISCstar Solutions Corporation. All rights reserved.
> + *
> + * Derived from code having the following copyrights:
> + * Copyright (C) 2011-2012 Vayavya Labs Pvt Ltd
> + * Copyright (C) 2025 Toshiba Electronic Devices & Storage Corporation
> + */
> +
> +#include <linux/auxiliary_bus.h>
Based on the block diagram, these are PCI devices. Auxiliary bus is the
wrong thing to use here.
Rob
^ permalink raw reply
* [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Shanker Donthineni @ 2026-06-05 14:45 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, linux-arm-kernel, Vladimir Murzin
Cc: Mark Rutland, linux-kernel, linux-doc, Shanker Donthineni,
Vikram Sethi, Jason Sequeira
On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
observed by a peripheral before an older, non-overlapping Device-nGnR*
store to the same peripheral. This breaks the program-order guarantee
that software expects for Device-nGnR* accesses and can leave a
peripheral in an incorrect state, as a load is observed before an
earlier store takes effect.
The erratum can occur only when all of the following apply:
- A PE executes a Device-nGnR* store followed by a younger
Device-nGnR* load.
- The store is not a store-release.
- The accesses target the same peripheral and do not overlap in bytes.
- There is at most one intervening Device-nGnR* store in program
order, and there are no intervening Device-nGnR* loads.
- There is no DSB, and no DMB that orders loads, between the store and
the load.
- Specific micro-architectural and timing conditions occur.
Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
orders loads) between the store and the load, or make the store a
store-release. A load-acquire on the load side would not help, because
acquire semantics do not prevent a load from being observed ahead of an
older store; only the store side (release or a barrier) closes the
window.
Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
to stlr* (Store-Release), which removes the "store is not a
store-release" condition for every device write the kernel issues.
Because writel() and writel_relaxed() are both built on __raw_writel()
in asm-generic/io.h, patching the raw variants covers both the
non-relaxed and relaxed APIs without touching the higher layers. Note
that writel()'s own barrier sits before the store, so it does not order
the store against a subsequent readl(); the store-release promotion is
what provides that ordering.
Like ARM64_ERRATUM_832075 on the load side, the change is gated on a new
ARM64_WORKAROUND_DEVICE_STORE_RELEASE capability and only activated on
parts that match MIDR_NVIDIA_OLYMPUS, so unaffected CPUs continue to use
the plain str* sequence.
Note: stlr* only supports base-register addressing, so the raw accessors
can no longer use the offset addressing introduced by commit d044d6ba6f02
("arm64: io: permit offset addressing"). The str* and stlr* alternates
share a single inline-asm operand and the sequence is selected at boot,
so the operand form is fixed at compile time; unaffected CPUs keep using
str* but also revert to base-register addressing. This keeps the store
side as simple as the existing load-side patching (load-acquire) and
avoids adding complexity to the device write path; retaining offset
addressing only for str* would otherwise require a runtime branch on
every write.
Co-developed-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
---
Changes since v1:
Update commit text based on feedback from Vladimir Murzin
Documentation/arch/arm64/silicon-errata.rst | 2 ++
arch/arm64/Kconfig | 23 ++++++++++++++++++++
arch/arm64/include/asm/io.h | 24 ++++++++++++++-------
arch/arm64/kernel/cpu_errata.c | 8 +++++++
arch/arm64/tools/cpucaps | 1 +
5 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index 211119ce7adc..899bed3908bb 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -256,6 +256,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| NVIDIA | Carmel Core | N/A | NVIDIA_CARMEL_CNP_ERRATUM |
+----------------+-----------------+-----------------+-----------------------------+
+| NVIDIA | Olympus core | T410-OLY-1027 | NVIDIA_OLYMPUS_1027_ERRATUM |
++----------------+-----------------+-----------------+-----------------------------+
| NVIDIA | T241 GICv3/4.x | T241-FABRIC-4 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| NVIDIA | T241 MPAM | T241-MPAM-1 | N/A |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fe60738e5943..a6bac84b05a1 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -564,6 +564,29 @@ config ARM64_ERRATUM_832075
If unsure, say Y.
+config NVIDIA_OLYMPUS_1027_ERRATUM
+ bool "NVIDIA Olympus: device store/load ordering erratum"
+ default y
+ help
+ This option adds an alternative code sequence to work around an
+ NVIDIA Olympus core erratum where a Device-nGnR* store can be
+ observed by a peripheral after a younger Device-nGnR* load to the
+ same peripheral. This breaks the program order that drivers rely
+ on for MMIO and can leave a device in an incorrect state.
+
+ The workaround promotes the raw MMIO store helpers
+ (__raw_writeb/w/l/q) to Store-Release (STLR), which restores the
+ required ordering. Because writel() and writel_relaxed() are built
+ on __raw_writel(), both are covered without changes to the higher
+ layers.
+
+ The fix is applied through the alternatives framework, so enabling
+ this option does not by itself activate the workaround: it is
+ patched in only when an affected CPU is detected, and is a no-op on
+ unaffected CPUs.
+
+ If unsure, say Y.
+
config ARM64_ERRATUM_834220
bool "Cortex-A57: 834220: Stage 2 translation fault might be incorrectly reported in presence of a Stage 1 fault (rare)"
depends on KVM
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 8cbd1e96fd50..b6d7966e9c19 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -25,29 +25,37 @@
#define __raw_writeb __raw_writeb
static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
- volatile u8 __iomem *ptr = addr;
- asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
+ asm volatile(ALTERNATIVE("strb %w0, [%1]",
+ "stlrb %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE)
+ : : "rZ" (val), "r" (addr));
}
#define __raw_writew __raw_writew
static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
- volatile u16 __iomem *ptr = addr;
- asm volatile("strh %w0, %1" : : "rZ" (val), "Qo" (*ptr));
+ asm volatile(ALTERNATIVE("strh %w0, [%1]",
+ "stlrh %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE)
+ : : "rZ" (val), "r" (addr));
}
#define __raw_writel __raw_writel
static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
- volatile u32 __iomem *ptr = addr;
- asm volatile("str %w0, %1" : : "rZ" (val), "Qo" (*ptr));
+ asm volatile(ALTERNATIVE("str %w0, [%1]",
+ "stlr %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE)
+ : : "rZ" (val), "r" (addr));
}
#define __raw_writeq __raw_writeq
static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
{
- volatile u64 __iomem *ptr = addr;
- asm volatile("str %x0, %1" : : "rZ" (val), "Qo" (*ptr));
+ asm volatile(ALTERNATIVE("str %x0, [%1]",
+ "stlr %x0, [%1]",
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE)
+ : : "rZ" (val), "r" (addr));
}
#define __raw_readb __raw_readb
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 5377e4c2eba2..958d7f16bfeb 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -809,6 +809,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
ERRATA_MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL),
},
#endif
+#ifdef CONFIG_NVIDIA_OLYMPUS_1027_ERRATUM
+ {
+ /* NVIDIA Olympus core */
+ .desc = "NVIDIA Olympus device load/store ordering erratum",
+ .capability = ARM64_WORKAROUND_DEVICE_STORE_RELEASE,
+ ERRATA_MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
+ },
+#endif
#ifdef CONFIG_ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE
{
/*
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 811c2479e82d..d367257bf770 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -120,6 +120,7 @@ WORKAROUND_CAVIUM_TX2_219_PRFM
WORKAROUND_CAVIUM_TX2_219_TVM
WORKAROUND_CLEAN_CACHE
WORKAROUND_DEVICE_LOAD_ACQUIRE
+WORKAROUND_DEVICE_STORE_RELEASE
WORKAROUND_NVIDIA_CARMEL_CNP
WORKAROUND_PMUV3_IMPDEF_TRAPS
WORKAROUND_QCOM_FALKOR_E1003
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox